diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000..72e85029ef654 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 + +[*.py] +indent_style = space + +[*.md] +trim_trailing_whitespace = false + +[Dockerfile] +indent_style = space diff --git a/.github/guides/HARDDELETES.md b/.github/guides/HARDDELETES.md index defc09360af68..6817de0d9b31a 100644 --- a/.github/guides/HARDDELETES.md +++ b/.github/guides/HARDDELETES.md @@ -1,6 +1,6 @@ # Hard Deletes -> Garbage collection is pretty gothic when you think about it. +> Garbage collection is pretty gothic when you think about it. > >An object in code is like a ghost, clinging to its former life, and especially to the people it knew. It can only pass on and truly die when it has dealt with its unfinished business. And only when its been forgotten by everyone who ever knew it. If even one other object remembers it, it has a connection to the living world that lets it keep hanging on > @@ -52,7 +52,7 @@ This of course means they can store that location in memory in another object's /proc/someshit(mem_location) var/datum/some_obj = new() - some_obj.reference = mem_location + some_obj.reference = mem_location ``` But what happens when you get rid of the object we're passing around references to? If we just cleared it out from memory, everything that holds a reference to it would suddenly be pointing to nowhere, or worse, something totally different! @@ -135,13 +135,13 @@ If that fails, search the object's typepath, and look and see if anything is hol BYOND currently doesn't have the capability to give us information about where a hard delete is. Fortunately we can search for most all of then ourselves. The procs to perform this search are hidden behind compile time defines, since they'd be way too risky to expose to admin button pressing -If you're having issues solving a harddel and want to perform this check yourself, go to `_compile_options.dm` and uncomment `TESTING`, `REFERENCE_TRACKING`, and `GC_FAILURE_HARD_LOOKUP` +If you're having issues solving a harddel and want to perform this check yourself, go to `_compile_options.dm` and uncomment `REFERENCE_TRACKING_STANDARD`. -You can read more about what each of these do in that file, but the long and short of it is if something would hard delete our code will search for the reference (This will look like your game crashing, just hold out) and print information about anything it finds to the runtime log, which you can find inside the round folder inside `/data/logs/year/month/day` +You can read more about what each of these do in that file, but the long and short of it is if something would hard delete our code will search for the reference (This will look like your game crashing, just hold out) and print information about anything it finds to [log_dir]/harddels.log, which you can find inside the round folder inside `/data/logs/year/month/day` -It'll tell you what object is holding the ref if it's in an object, or what pattern of list transversal was required to find the ref if it's hiding in a list of some sort +It'll tell you what object is holding the ref if it's in an object, or what pattern of list transversal was required to find the ref if it's hiding in a list of some sort, alongside the references remaining. -## Techniques For Fixing Hard Deletes +## Techniques For Fixing Hard Deletes Once you've found the issue, it becomes a matter of making sure the ref is cleared as a part of Destroy(). I'm gonna walk you through a few patterns and discuss how you might go about fixing them @@ -243,7 +243,7 @@ So then, we want to temporarily remember to clear a reference when it's deleted This is where I might lose you, but we're gonna use signals -`qdel()`, the proc that sets off this whole deletion business, sends a signal called `COMSIG_PARENT_QDELETING` +`qdel()`, the proc that sets off this whole deletion business, sends a signal called `COMSIG_QDELETING` We can listen for that signal, and if we hear it clear whatever reference we may have @@ -255,10 +255,10 @@ Here's an example /somemob/proc/set_target(new_target) if(target) - UnregisterSignal(target, COMSIG_PARENT_QDELETING) //We need to make sure any old signals are cleared + UnregisterSignal(target, COMSIG_QDELETING) //We need to make sure any old signals are cleared target = new_target if(target) - RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clear_target)) //Call clear_target if target is ever qdel()'d + RegisterSignal(target, COMSIG_QDELETING, PROC_REF(clear_target)) //Call clear_target if target is ever qdel()'d /somemob/proc/clear_target(datum/source) SIGNAL_HANDLER diff --git a/.github/guides/VISUALS.md b/.github/guides/VISUALS.md index 1c3cc6360c57b..4d8f7d3b585c8 100644 --- a/.github/guides/VISUALS.md +++ b/.github/guides/VISUALS.md @@ -4,10 +4,10 @@ Welcome to a breakdown of visuals and visual effects in our codebase, and in BYO 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. +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. +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). @@ -53,10 +53,10 @@ You'll find links to the relevant reference entries at the heading of each entry ## Appearances in BYOND - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance) +- [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. +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. @@ -65,25 +65,27 @@ To start off with, appearances are static. You can't directly edit an appearance 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, +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), +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 +// 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) +/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 ``` +> **Note:** More then being static, appearances are unique. Only one copy of each set of appearance vars exists, and when you modify any of those vars, the corrosponding appearance variable changes its value to whatever matches the new hash. That's why appearance vars can induce inconsistent cost on modification. + > **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 @@ -91,7 +93,7 @@ Somewhat like this - [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. +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. @@ -104,67 +106,67 @@ 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. +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), +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()`, +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 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. +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()`, +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) +- [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). +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, +- `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. +- `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. +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. +`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. +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) +- [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. +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. @@ -172,7 +174,7 @@ See [/client/var/images](#client-images) ## Client Images - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/images) +- [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. @@ -180,35 +182,35 @@ The image objects are displayed at their loc variable, and can be shown to more ### 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. +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. +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. +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. +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) +- [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, +`/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. +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 @@ -218,29 +220,29 @@ Clients get some choice in literally how they want the game to be rendered to th 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. +`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, +`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) +- [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. +`/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. +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) +- [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 @@ -256,21 +258,21 @@ The classic `screen_loc` format looks something like this (keeping in mind it co 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, +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. +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) +- [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. @@ -280,7 +282,7 @@ This is how we do lighting effects, since the lighting [plane](#planes) can be u ## Appearance Flags - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance_flags) +- [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. @@ -293,8 +295,8 @@ Flags of interest: ## Gliding - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/gliding) - +- [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. @@ -306,37 +308,37 @@ This is done using `/atom/movable/proc/set_glide_size`, which will inform anythi 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. +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. +> 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. +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 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) +- [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". +- `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. This is in theory very powerful, but not possible with the 'side_map' [map format](https://www.byond.com/docs/ref/#/world/var/map_format) +This allows us to capture it, and say, blur it, or redraw it elsewhere. This is in theory very powerful, but not possible with the 'side_map' [map format](https://www.byond.com/docs/ref/#/world/var/map_format) ## BYOND Lighting @@ -346,14 +348,14 @@ Alongside OUR lighting implementation, which is discussed in with color matrixes 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, +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) +- [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. @@ -363,7 +365,7 @@ You can actually force it to use a particular mob's sight to avoid aspects of th ### See in Dark - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_in_dark) +- [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. @@ -372,9 +374,9 @@ 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) +- [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. +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 @@ -390,16 +392,16 @@ It's also used to hide some more then ghost invisible things, like some timers a ## Layers - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/layer) +- [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. +`/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. +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. @@ -408,7 +410,7 @@ This allows us to keep relative layer differences while not needing to make all ## Planes - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/plane) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/plane) Allllright `/atom/var/plane`s. Let's talk about em. @@ -417,16 +419,16 @@ 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! +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), +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), +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. @@ -434,15 +436,15 @@ We have a system that allows for arbitrary grouping of plane masters for the pur 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. +> 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`. +> 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) +- [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. @@ -477,8 +479,8 @@ 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, +- 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. @@ -493,7 +495,7 @@ 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. +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. @@ -502,18 +504,18 @@ 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) +- [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. +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), +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)) +> 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 @@ -521,10 +523,10 @@ master's effects are applied. ## Filters - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/filters) +- [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. +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 @@ -546,7 +548,7 @@ 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) +- [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. @@ -560,7 +562,7 @@ It'll let you add and tweak the particles attached to that atom. ## Pixel Offsets - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/pixel_x) +- [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. @@ -573,7 +575,7 @@ There are two "types" of each direction offset. There's the "real" offset (x/y) 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` +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. ## Map Formats @@ -587,10 +589,10 @@ There are 4 types currently. Only 2 that are interesting to us, and one that's n Most of them involve changing how layering works, from the standard [layers](#layers) and [planes](#planes) method. There's a bit more detail here, not gonna go into it, stuff like [underlays](https://www.byond.com/docs/ref/#/atom/var/underlays) drawing under things. See [Understanding The Renderer](https://www.byond.com/docs/ref/#/{notes}/renderer) -> There is very technically more nuance here. +> There is very technically more nuance here. > In default rendering modes, byond will conflict break by using the thing that is highest in the contents list of its location. Or lowest. Don't remember. -### [`TOPDOWN_MAP`](https://www.byond.com/docs/ref/#/{notes}/topdown) +### [`TOPDOWN_MAP`](https://www.byond.com/docs/ref/#/{notes}/topdown) This is the default rendering format. What we used to use. It tells byond to render going off [plane](#planes) first, then [layer](#layers). There's a few edgecases involving big icons, but it's small peanuts. @@ -606,7 +608,7 @@ The idea is the closer to the front of the screen something is, the higher its l `pixel_y` + `y` tell the engine where something "is". `/atom/var/bound_width`, `/atom/var/bound_height` and `/atom/var/bound_x/y` describe how big it is, which lets us in theory control what it tries to layer "against". -I'm not bothering with reference links because they are entirely unrelated. +I'm not bothering with reference links because they are entirely unrelated. An issue that will crop up with this map format is needing to manage the "visual" (how/where it renders) and physical (where it is in game) aspects of position and size. Physical position tells the renderer how to layer things. Visual position and a combination of physical bounds (manually set) and visual bounds (inferred from other aspects of it. Sprite width/height, physical bounds, transforms, filters, etc) tell it what the sprite might be rendering OVER. @@ -647,28 +649,28 @@ One more thing. Big icons are fucked From the byond reference >If you use an icon wider than one tile, the "footprint" of the isometric icon (the actual map tiles it takes up) will always be a square. That is, if your normal tile size is 64 and you want to show a 128x128 icon, the icon is two tiles wide and so it will take up a 2×2-tile area on the map. The height of a big icon is irrelevant--any excess height beyond width/2 is used to show vertical features. To draw this icon properly, other tiles on that same ground will be moved behind it in the drawing order. -> One important warning about using big icons in isometric mode is that you should only do this with dense atoms. If part of a big mob icon covers the same tile as a tall building for instance, the tall building is moved back and it could be partially covered by other turfs that are actually behind it. A mob walking onto a very large non-dense turf icon would experience similar irregularities. +> One important warning about using big icons in isometric mode is that you should only do this with dense atoms. If part of a big mob icon covers the same tile as a tall building for instance, the tall building is moved back and it could be partially covered by other turfs that are actually behind it. A mob walking onto a very large non-dense turf icon would experience similar irregularities. These can cause very annoying flickering. In fact, MUCH of how rendering works causes flickering. This is because we don't decide on a pixel by pixel case, the engine groups sprites up into a sort of rendering stack, unable to split them up. -This combined with us being unable to modify bounds means that if one bit of the view is conflicting. +This combined with us being unable to modify bounds means that if one bit of the view is conflicting. If A wants to be above B and below C, but B wants to be below A and above C, we'll be unable to resolve the rendering properly, leading to flickering depending on other aspects of the layering. This can just sort of spread. Very hard to debug. -### [`ISOMETRIC_MAP`](https://www.byond.com/docs/ref/#/{notes}/isometric) - +### [`ISOMETRIC_MAP`](https://www.byond.com/docs/ref/#/{notes}/isometric) + Isometric mode, renders everything well, isometrically, biased to the north east. This gives the possibility for fake 3d, assuming you get things drawn properly. It will render things in the foreground "last", after things in the background. This is the right way of thinking about it, it's not rendering things above or below, but in a layering order. This is interesting mostly in the context of understanding [side map](#side_map-check-the-main-page-too), but we did actually run an isometric station for april fools once. It was really cursed and flickered like crazy (which causes client lag). Fun as hell though. -The mode essentially overrides the layer/plane layering discussed before, and inserts new rules. -I wish I knew what those rules EXACTLY are, but I'm betting they're similar to [side map's](#side_map-check-the-main-page-too), and lummy's actually told me those. +The mode essentially overrides the layer/plane layering discussed before, and inserts new rules. +I wish I knew what those rules EXACTLY are, but I'm betting they're similar to [side map's](#side_map-check-the-main-page-too), and lummy's actually told me those. Yes this is all rather poorly documented. Similar to sidemap, we take physical position into account when deciding layering. In addition to its height positioning, we also account for width. -So both `pixel_y` and `pixel_x` can effect layering. `pixel_z` handles strictly visual y, and `pixel_w` handles x. +So both `pixel_y` and `pixel_x` can effect layering. `pixel_z` handles strictly visual y, and `pixel_w` handles x. This has similar big icon problems to [sidemap](#side_map-check-the-main-page-too). @@ -679,14 +681,14 @@ it would be automatically broken down into smaller icon states, which you would ## Color - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/color) +- [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. +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. @@ -705,7 +707,7 @@ 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) +- [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 @@ -732,17 +734,17 @@ and forget to update this file. ## Animate() - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/proc/animate) +- [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 +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. +Lets you give radiation glow a warm pulse, that sort of thing. ## GAGS - [Table of Contents](#table-of-contents) diff --git a/.github/max_required_byond_client.txt b/.github/max_required_byond_client.txt index faf8058076a2a..bd10125cce940 100644 --- a/.github/max_required_byond_client.txt +++ b/.github/max_required_byond_client.txt @@ -5,4 +5,4 @@ # (Requiring clients update to connect to the game server is not something we like to spring on them with no notice, # especially for beta builds where the pager/updater won't let them update without additional configuration.) -514 +515 diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index f514e52b21fdc..412fda467dd7c 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -13,14 +13,18 @@ on: merge_group: branches: - master + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: run_linters: if: ( !contains(github.event.head_commit.message, '[ci skip]') ) name: Run Linters runs-on: ubuntu-22.04 - concurrency: - group: run_linters-${{ github.head_ref || github.run_id }} - cancel-in-progress: true + timeout-minutes: 5 + steps: - uses: actions/checkout@v4 - name: Restore SpacemanDMM cache @@ -130,9 +134,8 @@ jobs: name: Compile Maps needs: [collect_data] runs-on: ubuntu-22.04 - concurrency: - group: compile_all_maps-${{ github.head_ref || github.run_id }} - cancel-in-progress: true + timeout-minutes: 5 + steps: - uses: actions/checkout@v4 - name: Restore BYOND cache @@ -155,13 +158,12 @@ jobs: if: ( !contains(github.event.head_commit.message, '[ci skip]') ) name: Collect data for other tasks runs-on: ubuntu-22.04 + timeout-minutes: 5 outputs: maps: ${{ steps.map_finder.outputs.maps }} alternate_tests: ${{ steps.alternate_test_finder.outputs.alternate_tests }} max_required_byond_client: ${{ steps.max_required_byond_client.outputs.max_required_byond_client }} - concurrency: - group: find_all_maps-${{ github.head_ref || github.run_id }} - cancel-in-progress: true + steps: - uses: actions/checkout@v4 - name: Find Maps @@ -186,13 +188,12 @@ jobs: if: ( !contains(github.event.head_commit.message, '[ci skip]') ) name: Integration Tests needs: [collect_data] + strategy: fail-fast: false matrix: map: ${{ fromJSON(needs.collect_data.outputs.maps).paths }} - concurrency: - group: run_all_tests-${{ github.head_ref || github.run_id }}-${{ matrix.map }} - cancel-in-progress: true + uses: ./.github/workflows/run_integration_tests.yml with: map: ${{ matrix.map }} @@ -206,9 +207,7 @@ jobs: fail-fast: false matrix: setup: ${{ fromJSON(needs.collect_data.outputs.alternate_tests) }} - concurrency: - group: run_all_tests-${{ github.head_ref || github.run_id }}-${{ matrix.setup.major }}.${{ matrix.setup.minor }}-${{ matrix.setup.map }} - cancel-in-progress: true + uses: ./.github/workflows/run_integration_tests.yml with: map: ${{ matrix.setup.map }} @@ -221,6 +220,7 @@ jobs: name: Check Alternate Tests needs: [run_alternate_tests] runs-on: ubuntu-22.04 + timeout-minutes: 5 steps: - run: echo Alternate tests passed. @@ -228,6 +228,7 @@ jobs: if: ( !contains(github.event.head_commit.message, '[ci skip]') && (always() && (!failure() && !cancelled())) ) needs: [run_all_tests, run_alternate_tests] name: Compare Screenshot Tests + timeout-minutes: 15 runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -266,9 +267,8 @@ jobs: name: Windows Build needs: [collect_data] runs-on: windows-latest - concurrency: - group: test_windows-${{ github.head_ref || github.run_id }} - cancel-in-progress: true + timeout-minutes: 5 + steps: - uses: actions/checkout@v4 - name: Restore Yarn cache diff --git a/.github/workflows/codeowner_reviews.yml b/.github/workflows/codeowner_reviews.yml index cffab706d6100..e6cfb98027901 100644 --- a/.github/workflows/codeowner_reviews.yml +++ b/.github/workflows/codeowner_reviews.yml @@ -9,6 +9,7 @@ jobs: assign-users: runs-on: ubuntu-latest + timeout-minutes: 5 steps: # Checks-out your repository under $GITHUB_WORKSPACE, so the job can access it diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index 42954b571b6cc..7b544fef2a66c 100644 --- a/.github/workflows/run_integration_tests.yml +++ b/.github/workflows/run_integration_tests.yml @@ -16,9 +16,11 @@ on: max_required_byond_client: required: true type: string + jobs: run_integration_tests: runs-on: ubuntu-latest + timeout-minutes: 15 services: mysql: image: mysql:latest @@ -57,7 +59,7 @@ jobs: run: | bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup - tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -WError -NWTG0001 + tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -Werror -ITG0001 -I"loop_checks" - name: Run Tests run: | source $HOME/BYOND/byond/bin/byondsetup diff --git a/.tgs.yml b/.tgs.yml index 76a53577b505b..dd18c3b8a2577 100644 --- a/.tgs.yml +++ b/.tgs.yml @@ -3,7 +3,7 @@ version: 1 # The BYOND version to use (kept in sync with dependencies.sh by the "TGS Test Suite" CI job) # Must be interpreted as a string, keep quoted -byond: "515.1633" +byond: "515.1637" # Folders to create in "/Configuration/GameStaticFiles/" static_files: # Config directory should be static diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 09324eb844fd5..79a1a64683a3b 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,7 @@ { "recommendations": [ "platymuus.dm-langclient", + "EditorConfig.EditorConfig", "arcanis.vscode-zipfs", "dbaeumer.vscode-eslint", "stylemistake.auto-comment-blocks", diff --git a/.vscode/settings.json b/.vscode/settings.json index d7c1bfc1d1e31..0ef2ce67760b5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,8 @@ }, "files.eol": "\n", "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "editor.insertSpaces": false, "git.branchProtection": ["master"], "gitlens.advanced.blame.customArguments": ["-w"], "tgstationTestExplorer.project.resultsType": "json", diff --git a/SQL/database_changelog.md b/SQL/database_changelog.md index a71cf673d3dbc..8ae4c7d42647b 100644 --- a/SQL/database_changelog.md +++ b/SQL/database_changelog.md @@ -2,19 +2,32 @@ Any time you make a change to the schema files, remember to increment the databa Make sure to also update `DB_MAJOR_VERSION` and `DB_MINOR_VERSION`, which can be found in `code/__DEFINES/subsystem.dm`. -The latest database version is 5.26; The query to update the schema revision table is: +The latest database version is 5.27; The query to update the schema revision table is: ```sql -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 26); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 27); ``` or ```sql -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 26); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 27); ``` In any query remember to add a prefix to the table names if you use one. - +----------------------------------------------------- +Version 5.27, 26 April 2024, by zephyrtfa +Add the ip intel whitelist table +```sql +DROP TABLE IF EXISTS `ipintel_whitelist`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `ipintel_whitelist` ( + `ckey` varchar(32) NOT NULL, + `admin_ckey` varchar(32) NOT NULL, + PRIMARY KEY (`ckey`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +``` ----------------------------------------------------- Version 5.26, 03 December 2023, by distributivgesetz Set the default value of cloneloss to 0, as it's obsolete and it won't be set by blackbox anymore. diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index 64bbf4259d931..19739a306b5eb 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -215,6 +215,20 @@ CREATE TABLE `ipintel` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `ipintel_whitelist` +-- + +DROP TABLE IF EXISTS `ipintel_whitelist`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `ipintel_whitelist` ( + `ckey` varchar(32) NOT NULL, + `admin_ckey` varchar(32) NOT NULL, + PRIMARY KEY (`ckey`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `legacy_population` -- diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index 597281f2c2076..fb9a6cbe10fa4 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -214,6 +214,19 @@ CREATE TABLE `SS13_ipintel` ( KEY `idx_ipintel` (`ip`,`intel`,`date`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `ipintel_whitelist` +-- + +DROP TABLE IF EXISTS `SS13_ipintel_whitelist`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `SS13_ipintel_whitelist` ( + `ckey` varchar(32) NOT NULL, + `admin_ckey` varchar(32) NOT NULL, + PRIMARY KEY (`ckey`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `SS13_legacy_population` diff --git a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm index 61311b3f036c8..cddd5a0820659 100644 --- a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm +++ b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm @@ -337,7 +337,7 @@ /area/ruin/powered/golem_ship) "un" = ( /obj/structure/table/wood, -/obj/item/areaeditor/blueprints/golem{ +/obj/item/blueprints/golem{ pixel_y = 3; pixel_x = -2 }, diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_hermit.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_hermit.dmm index df0bf1c088073..d596a823a6a23 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_hermit.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_hermit.dmm @@ -75,7 +75,7 @@ /turf/open/floor/grass/fairy, /area/ruin/powered/hermit) "wf" = ( -/obj/item/gun/ballistic/rifle/boltaction/pipegun/prime, +/obj/item/gun/energy/laser/musket/prime, /obj/structure/table/wood, /obj/item/flashlight/lantern, /turf/open/floor/wood, diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm index ebb62bff3750a..1ecd393cc7d4d 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm @@ -1228,7 +1228,7 @@ /area/lavaland/surface/outdoors) "JD" = ( /obj/effect/mapping_helpers/no_lava, -/obj/structure/ore_container/gutlunch_trough, +/obj/structure/ore_container/food_trough/gutlunch_trough, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "Kg" = ( diff --git a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm index 84a3a2658d3e5..a7eac1fe1a8b1 100644 --- a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm +++ b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm @@ -1192,7 +1192,7 @@ }, /obj/effect/decal/cleanable/blood/gibs, /obj/item/organ/internal/brain, -/obj/item/skillchip/job/research_director, +/obj/item/skillchip/research_director, /obj/effect/turf_decal/tile/neutral/half{ dir = 4 }, diff --git a/_maps/RandomRuins/SpaceRuins/interdyne.dmm b/_maps/RandomRuins/SpaceRuins/interdyne.dmm index cba624ef05f22..cf8c7f8c0d408 100644 --- a/_maps/RandomRuins/SpaceRuins/interdyne.dmm +++ b/_maps/RandomRuins/SpaceRuins/interdyne.dmm @@ -852,7 +852,7 @@ /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/interdyne) "JM" = ( -/obj/machinery/computer/arcade{ +/obj/effect/spawner/random/entertainment/arcade{ dir = 1 }, /turf/open/floor/mineral/plastitanium/red, diff --git a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm index 2c7a240d67969..ad27c03ab9ad9 100644 --- a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm @@ -755,7 +755,7 @@ /turf/open/floor/iron/small, /area/ruin/space/has_grav/listeningstation) "NO" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/effect/turf_decal/stripes/line{ dir = 10 }, diff --git a/_maps/RandomRuins/SpaceRuins/waystation.dmm b/_maps/RandomRuins/SpaceRuins/waystation.dmm index 245473c8faea2..e5262d324259e 100644 --- a/_maps/RandomRuins/SpaceRuins/waystation.dmm +++ b/_maps/RandomRuins/SpaceRuins/waystation.dmm @@ -357,7 +357,7 @@ /area/ruin/space/has_grav/waystation/cargobay) "gE" = ( /obj/structure/sign/poster/contraband/missing_gloves/directional/north, -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -464,7 +464,7 @@ /area/ruin/space) "iT" = ( /obj/machinery/light/dim/directional/north, -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /turf/open/floor/plating, /area/ruin/space/has_grav/waystation/power) diff --git a/_maps/deathmatch/maint_mania.dmm b/_maps/deathmatch/maint_mania.dmm index ec04776ae8325..5b23ac38feb8f 100644 --- a/_maps/deathmatch/maint_mania.dmm +++ b/_maps/deathmatch/maint_mania.dmm @@ -46,11 +46,6 @@ "hB" = ( /turf/closed/indestructible/fakedoor, /area/deathmatch) -"hN" = ( -/obj/structure/lattice, -/obj/effect/decal/cleanable/dirt/dust, -/turf/template_noop, -/area/template_noop) "ih" = ( /obj/item/reagent_containers/pill/maintenance, /turf/open/indestructible, @@ -198,7 +193,7 @@ /turf/open/indestructible, /area/deathmatch) "zF" = ( -/obj/item/ammo_casing/shotgun/improvised, +/obj/effect/spawner/random/junk_shell, /turf/open/indestructible, /area/deathmatch) "AG" = ( @@ -512,7 +507,7 @@ FL FL ur ur -hN +ur ur ur ur diff --git a/_maps/deathmatch/ragin_mages.dmm b/_maps/deathmatch/ragin_mages.dmm new file mode 100644 index 0000000000000..37939643b7275 --- /dev/null +++ b/_maps/deathmatch/ragin_mages.dmm @@ -0,0 +1,1880 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ay" = ( +/obj/structure/railing/corner/end{ + dir = 4 + }, +/obj/machinery/door/airlock/wood, +/obj/structure/railing/corner/end/flip{ + dir = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"aT" = ( +/obj/item/cardboard_cutout/adaptive{ + pixel_y = 14; + pixel_x = 8 + }, +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"bb" = ( +/obj/structure/chair/wood/wings{ + dir = 8 + }, +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"bg" = ( +/obj/effect/spawner/random/entertainment/arcade, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"bv" = ( +/obj/machinery/power/shuttle_engine/propulsion, +/turf/open/floor/plating/airless, +/area/deathmatch/teleport) +"co" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin/carbon{ + pixel_y = 12; + pixel_x = 7 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"ct" = ( +/obj/structure/flora/bush/grassy/style_random, +/mob/living/simple_animal/pet/gondola{ + name = "Jommy"; + faction = list("gondola", "Wizard") + }, +/turf/open/floor/grass, +/area/deathmatch/teleport) +"cU" = ( +/obj/structure/chair/wood/wings{ + dir = 1 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"dj" = ( +/obj/machinery/door/airlock/wood, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"ds" = ( +/turf/open/floor/carpet/purple, +/area/deathmatch/teleport) +"ez" = ( +/obj/structure/closet/crate, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"fH" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/griddle, +/obj/item/food/burger/spell{ + pixel_y = 11; + pixel_x = -3 + }, +/obj/item/stack/medical/ointment{ + pixel_y = -2; + pixel_x = 9 + }, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"fI" = ( +/turf/open/lava, +/area/deathmatch/teleport) +"gn" = ( +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"gr" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/structure/chair/wood, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"hg" = ( +/obj/structure/railing/corner/end/flip{ + dir = 8 + }, +/obj/machinery/door/airlock/wood, +/obj/structure/railing/corner/end{ + dir = 8 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"hk" = ( +/obj/item/kirbyplants/organic/plant10{ + pixel_y = 21; + pixel_x = -7 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"hK" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"ig" = ( +/obj/structure/table/wood, +/obj/item/stack/medical/bruise_pack{ + pixel_x = -12 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"iz" = ( +/obj/structure/chair/comfy/brown{ + dir = 1 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"iL" = ( +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/carpet/red, +/area/deathmatch/teleport) +"iQ" = ( +/obj/structure/table, +/obj/structure/bedsheetbin{ + pixel_y = 4; + pixel_x = 3 + }, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"iZ" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/structure/sink/directional/west, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"jb" = ( +/obj/machinery/door/airlock/wood, +/obj/structure/railing/corner/end/flip, +/obj/structure/railing/corner/end, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"jg" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"jm" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/mystery_box/wands, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"js" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"jM" = ( +/obj/structure/table/reinforced, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"jV" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/door/airlock/wood, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"kl" = ( +/obj/structure/flora/bush/grassy/style_random, +/obj/machinery/light/floor, +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/grass, +/area/deathmatch/teleport) +"li" = ( +/obj/structure/table, +/obj/item/extinguisher{ + pixel_x = 7; + pixel_y = -6 + }, +/obj/item/clothing/suit/wizrobe/red{ + pixel_y = 3; + pixel_x = -6 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"lM" = ( +/obj/structure/bed{ + dir = 1 + }, +/obj/item/bedsheet/wiz{ + dir = 1 + }, +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"lO" = ( +/obj/structure/closet/crate, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"mu" = ( +/obj/effect/turf_decal/stripes, +/obj/structure/railing{ + dir = 4 + }, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"mV" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/structure/railing{ + dir = 8 + }, +/obj/structure/mystery_box/tdome, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"nk" = ( +/obj/item/gun/magic/wand/death, +/obj/structure/window/reinforced/plasma/spawner/directional/east, +/obj/structure/window/reinforced/plasma/spawner/directional/north, +/obj/structure/window/reinforced/plasma/spawner/directional/west, +/turf/open/floor/grass, +/area/deathmatch/teleport) +"nx" = ( +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/floor/carpet/red, +/area/deathmatch/teleport) +"nQ" = ( +/obj/machinery/door/airlock/wood, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"on" = ( +/obj/structure/table/wood, +/turf/open/floor/carpet/red, +/area/deathmatch/teleport) +"oP" = ( +/obj/structure/destructible/cult/item_dispenser/archives/library, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"pe" = ( +/obj/item/kirbyplants/organic/plant10{ + pixel_y = 21; + pixel_x = -7 + }, +/turf/open/floor/carpet/red, +/area/deathmatch/teleport) +"ph" = ( +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"pv" = ( +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"pL" = ( +/obj/effect/turf_decal/stripes{ + dir = 1 + }, +/obj/structure/mystery_box/wands, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"pV" = ( +/obj/structure/flora/bush/flowers_br/style_random, +/turf/open/floor/grass, +/area/deathmatch/teleport) +"qx" = ( +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/carpet/purple, +/area/deathmatch/teleport) +"qY" = ( +/obj/structure/closet/crate/bin, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"rj" = ( +/obj/machinery/door/window/right/directional/east, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"rD" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/structure/railing{ + dir = 8 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"sf" = ( +/obj/structure/mirror/directional/east, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"tL" = ( +/obj/structure/flora/bush/fullgrass/style_random, +/mob/living/simple_animal/hostile/ooze/gelatinous{ + name = "Jimmy"; + faction = list("slime", "Wizard") + }, +/turf/open/floor/grass, +/area/deathmatch/teleport) +"ue" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/item/food/burger/yellow{ + pixel_x = -11; + pixel_y = 8 + }, +/obj/item/food/burger/red{ + pixel_y = 13; + pixel_x = 6 + }, +/obj/item/food/burger/purple{ + pixel_y = 3 + }, +/obj/structure/table/reinforced, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"ui" = ( +/obj/effect/turf_decal/stripes, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"uz" = ( +/turf/open/floor/iron, +/area/deathmatch/teleport) +"uR" = ( +/obj/item/clothing/shoes/sandal/magic{ + pixel_y = 16 + }, +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"vh" = ( +/obj/structure/mystery_box/wands, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"vv" = ( +/obj/vehicle/ridden/scooter/skateboard{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"vR" = ( +/obj/structure/bookcase/random, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"wd" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/structure/mystery_box/wands, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"wl" = ( +/obj/item/kirbyplants/organic/plant10{ + pixel_y = 1; + pixel_x = -6 + }, +/turf/open/floor/carpet/purple, +/area/deathmatch/teleport) +"wL" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/gibber/autogibber, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"xk" = ( +/obj/structure/sink/directional/south, +/obj/structure/mirror/directional/north{ + pixel_y = 36 + }, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"xs" = ( +/obj/structure/flora/bush/grassy/style_random, +/turf/open/floor/grass, +/area/deathmatch/teleport) +"yA" = ( +/obj/structure/chair/wood/wings, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"zN" = ( +/obj/structure/mystery_box/wands, +/obj/structure/sign/poster/contraband/the_big_gas_giant_truth/directional/north, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"zO" = ( +/obj/structure/closet, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Au" = ( +/obj/structure/railing{ + dir = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"AD" = ( +/obj/structure/sign/departments/restroom/directional/west, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Bm" = ( +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"Cb" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/structure/table/wood, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"Cj" = ( +/obj/structure/table, +/obj/item/clothing/ears/earmuffs{ + pixel_y = 14; + pixel_x = 4 + }, +/obj/item/toy/gun{ + pixel_y = 2; + pixel_x = -3 + }, +/obj/item/clothing/head/wizard/red{ + pixel_x = 6; + pixel_y = -10 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Cq" = ( +/turf/open/floor/carpet/red, +/area/deathmatch/teleport) +"CM" = ( +/obj/structure/railing/corner, +/obj/structure/railing/corner{ + dir = 8 + }, +/obj/structure/railing/corner{ + dir = 4 + }, +/obj/structure/railing/corner{ + dir = 1 + }, +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"DK" = ( +/obj/structure/railing{ + dir = 8 + }, +/obj/structure/railing{ + dir = 8 + }, +/obj/structure/railing{ + dir = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"DW" = ( +/obj/machinery/computer, +/turf/open/floor/carpet/red, +/area/deathmatch/teleport) +"Eh" = ( +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Fb" = ( +/obj/effect/turf_decal/stripes{ + dir = 1 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Fm" = ( +/obj/structure/chair/comfy/black{ + dir = 1 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Fv" = ( +/obj/structure/chair/wood/wings{ + dir = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Fx" = ( +/obj/item/target, +/obj/structure/sign/flag/nanotrasen/directional/north, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"FL" = ( +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"Ge" = ( +/obj/item/flashlight/flare{ + pixel_x = -5; + pixel_y = -12 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Gv" = ( +/obj/item/kirbyplants/organic/plant10{ + pixel_y = 2; + pixel_x = 5 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"GC" = ( +/obj/effect/spawner/structure/window, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"GZ" = ( +/obj/structure/curtain, +/obj/machinery/shower/directional/north, +/obj/item/soap/syndie, +/turf/open/floor/noslip, +/area/deathmatch/teleport) +"Hf" = ( +/obj/item/kirbyplants/organic/plant10{ + pixel_y = 1; + pixel_x = -6 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Hs" = ( +/turf/template_noop, +/area/template_noop) +"HM" = ( +/obj/structure/rack, +/obj/item/knife/ritual{ + pixel_y = 5 + }, +/obj/item/staff{ + pixel_x = -4; + pixel_y = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"HP" = ( +/obj/structure/chair/comfy/black{ + dir = 1 + }, +/turf/open/floor/carpet/red, +/area/deathmatch/teleport) +"HS" = ( +/obj/structure/table/wood/fancy, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"IE" = ( +/obj/structure/table/wood, +/obj/item/clothing/suit/wizrobe/black{ + pixel_y = 3; + pixel_x = -1 + }, +/obj/item/clothing/head/wizard/black{ + pixel_y = 13; + pixel_x = 6 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"IM" = ( +/obj/item/kirbyplants/organic/plant10{ + pixel_y = 2; + pixel_x = 5 + }, +/turf/open/floor/carpet/purple, +/area/deathmatch/teleport) +"Jm" = ( +/turf/closed/wall/mineral/wood, +/area/deathmatch/teleport) +"Jo" = ( +/obj/structure/toilet{ + dir = 4 + }, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"Kr" = ( +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"KW" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Le" = ( +/obj/structure/filingcabinet, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Mg" = ( +/obj/machinery/computer, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Nl" = ( +/obj/machinery/power/shuttle_engine/heater{ + resistance_flags = 3 + }, +/obj/structure/window/reinforced/spawner/directional/north{ + resistance_flags = 3 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Nm" = ( +/obj/item/kirbyplants/organic/plant10{ + pixel_y = 21; + pixel_x = 6 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Nt" = ( +/obj/item/target{ + pixel_y = 11 + }, +/obj/effect/turf_decal/stripes, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"NW" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/turf_decal/stripes{ + dir = 1 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Ok" = ( +/obj/machinery/vending/cigarette, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"OD" = ( +/obj/structure/filingcabinet, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"OK" = ( +/obj/item/kirbyplants/organic/plant10{ + pixel_y = 21; + pixel_x = 6 + }, +/turf/open/floor/carpet/red, +/area/deathmatch/teleport) +"PD" = ( +/obj/structure/table/wood, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Qj" = ( +/obj/structure/dresser, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"QH" = ( +/obj/structure/table, +/obj/item/clothing/head/wizard{ + pixel_y = 14; + pixel_x = 4 + }, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"QT" = ( +/obj/structure/mystery_box/wands, +/turf/open/floor/plastic, +/area/deathmatch/teleport) +"RB" = ( +/obj/machinery/vending/snack, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"RI" = ( +/obj/effect/decal/cleanable/cobweb, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"RT" = ( +/obj/machinery/power/shuttle_engine/heater{ + resistance_flags = 3 + }, +/obj/structure/window/reinforced/spawner/directional/north{ + resistance_flags = 3 + }, +/turf/open/lava, +/area/deathmatch/teleport) +"Sa" = ( +/turf/open/floor/grass, +/area/deathmatch/teleport) +"SK" = ( +/obj/structure/flora/bush/fullgrass/style_random, +/turf/open/floor/grass, +/area/deathmatch/teleport) +"Th" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/structure/table/reinforced, +/obj/item/food/burger/rat{ + pixel_y = 9; + pixel_x = -2 + }, +/obj/item/food/bun{ + pixel_x = 8; + pixel_y = 2 + }, +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/iron, +/area/deathmatch/teleport) +"Vk" = ( +/obj/machinery/door/window/left/directional/east, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"VM" = ( +/obj/structure/table/wood/poker, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Wl" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/light_emitter{ + set_cap = 2; + light_color = "#DEEFFF"; + set_luminosity = 4 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"WX" = ( +/obj/machinery/vending/magivend, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Xv" = ( +/obj/structure/railing{ + layer = 3.1 + }, +/obj/structure/railing{ + layer = 3.1; + dir = 1 + }, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"YP" = ( +/obj/structure/closet/crate/coffin, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"YS" = ( +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/engine/cult, +/area/deathmatch/teleport) +"Zo" = ( +/obj/structure/flora/bush/flowers_pp/style_random, +/turf/open/floor/grass, +/area/deathmatch/teleport) +"ZS" = ( +/obj/structure/railing/corner/end/flip, +/turf/open/floor/iron, +/area/deathmatch/teleport) + +(1,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(2,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(3,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(4,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(5,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Jm +Jm +Jm +Jm +Jm +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(6,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Jm +Jm +vR +lM +Qj +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Hs +Hs +Hs +Hs +"} +(7,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Jm +Jm +vR +ph +ph +ph +Jm +QT +Jo +HS +iQ +GZ +Jm +Fx +uz +ui +Fb +ph +ph +ph +ph +RT +bv +Hs +Hs +Hs +"} +(8,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +gn +PD +iz +ph +ph +ph +dj +FL +FL +Bm +QH +uR +Jm +Fx +pv +Nt +Fb +Kr +ph +Eh +ph +RT +bv +Hs +Hs +Hs +"} +(9,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +gn +ig +ph +Kr +qY +Jm +Jm +Jm +Jm +xk +FL +FL +Jm +Fx +ZS +mu +NW +Wl +Au +Vk +rj +RT +bv +Hs +Hs +Hs +"} +(10,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Jm +HM +ph +Eh +Jm +Jm +qx +wl +Jm +Jm +nQ +Jm +Jm +dj +Jm +Jm +pL +ph +ph +ph +Gv +Jm +Hs +Hs +Hs +Hs +"} +(11,1,1) = {" +Hs +Hs +Hs +gn +gn +gn +Jm +zN +ph +ph +Jm +WX +ds +ds +Hf +Jm +ph +AD +Eh +ph +vR +Jm +Jm +Cj +li +ph +Jm +Jm +Hs +Hs +Hs +Hs +"} +(12,1,1) = {" +Hs +Hs +gn +gn +IE +PD +Jm +oP +ph +ph +dj +ph +ds +ds +ph +dj +ph +ph +ph +ph +ph +vR +Jm +Jm +Jm +ay +Jm +Hs +Hs +Hs +Hs +Hs +"} +(13,1,1) = {" +Hs +Hs +gn +Mg +Fm +Hf +Jm +Jm +sf +Gv +Jm +vR +ds +ds +ph +Jm +Jm +Jm +Jm +Nm +ph +ph +vR +Jm +fI +Xv +Jm +Jm +Hs +Hs +Hs +Hs +"} +(14,1,1) = {" +Hs +Hs +gn +Mg +ph +ph +vh +Jm +Jm +Jm +Jm +vR +ds +ds +ph +Jm +xs +tL +Jm +Jm +ph +ph +vR +Jm +fI +Xv +fI +Jm +Jm +Hs +Hs +Hs +"} +(15,1,1) = {" +Hs +Hs +gn +on +Cq +Cq +Cq +Cq +Cq +Cq +Cq +Cq +ds +ds +Cq +GC +Zo +Sa +xs +Jm +OK +Cq +Cq +Jm +fI +Xv +fI +fI +RT +bv +Hs +Hs +"} +(16,1,1) = {" +Hs +Hs +gn +DW +HP +iL +nx +Cq +Cq +Cq +iL +Cq +ds +ds +Cq +GC +Sa +kl +nk +Jm +nx +iL +Cq +jb +DK +CM +rD +mV +Nl +bv +Hs +Hs +"} +(17,1,1) = {" +Hs +Hs +gn +on +Cq +Cq +Cq +Cq +Cq +Cq +Cq +Cq +ds +ds +Cq +GC +Sa +pV +SK +Jm +pe +Cq +Cq +Jm +fI +Xv +fI +fI +RT +bv +Hs +Hs +"} +(18,1,1) = {" +Hs +Hs +gn +Mg +ph +ph +Ok +Jm +Jm +Jm +Jm +vR +ds +ds +ph +Jm +SK +ct +Jm +Jm +ph +ph +vR +Jm +fI +Xv +fI +Jm +Jm +Hs +Hs +Hs +"} +(19,1,1) = {" +Hs +Hs +gn +Mg +Fm +Gv +Jm +Jm +PD +vh +Jm +vR +ds +ds +ph +Jm +Jm +Jm +Jm +hk +ph +ph +vR +Jm +fI +Xv +Jm +Jm +Hs +Hs +Hs +Hs +"} +(20,1,1) = {" +Hs +Hs +gn +gn +PD +PD +Jm +PD +ph +ph +dj +ph +ds +ds +ph +dj +ph +ph +ph +ph +ph +vR +Jm +Jm +Jm +hg +Jm +Hs +Hs +Hs +Hs +Hs +"} +(21,1,1) = {" +Hs +Hs +Hs +gn +gn +gn +Jm +PD +ph +ph +Jm +RB +ds +ds +Gv +Jm +ph +ph +Eh +ph +vh +Jm +Jm +YS +KW +Ge +Jm +Jm +Hs +Hs +Hs +Hs +"} +(22,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Jm +PD +ph +Eh +Jm +Jm +qx +IM +Jm +Jm +jV +Jm +Jm +dj +Jm +Jm +RI +ph +vR +ph +lO +Jm +Hs +Hs +Hs +Hs +"} +(23,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +gn +zO +ph +Kr +ph +Jm +Jm +Jm +Jm +wL +js +fH +Jm +aT +ph +KW +ph +hK +vR +KW +ez +RT +bv +Hs +Hs +Hs +"} +(24,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +gn +bg +ph +ph +Fv +ph +dj +js +js +jg +js +Th +Jm +jm +Eh +vR +KW +Kr +KW +Eh +vv +RT +bv +Hs +Hs +Hs +"} +(25,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Jm +Jm +ph +yA +VM +cU +Jm +wd +gr +Cb +iZ +ue +Jm +YP +KW +KW +ph +Le +OD +co +jM +RT +bv +Hs +Hs +Hs +"} +(26,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Jm +Jm +ph +bb +Gv +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Jm +Hs +Hs +Hs +Hs +"} +(27,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Jm +Jm +Jm +Jm +Jm +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(28,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(29,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(30,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(31,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} +(32,1,1) = {" +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +Hs +"} diff --git a/_maps/deathmatch/train.dmm b/_maps/deathmatch/train.dmm new file mode 100644 index 0000000000000..3f0619d1ab4b8 --- /dev/null +++ b/_maps/deathmatch/train.dmm @@ -0,0 +1,2421 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ai" = ( +/obj/structure/table_frame/wood, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/wood/tile, +/area/deathmatch) +"as" = ( +/obj/effect/particle_effect/ion_trails/flight{ + icon_state = "shieldwall" + }, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"at" = ( +/turf/open/floor/wood/tile, +/area/deathmatch) +"be" = ( +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/plating, +/area/deathmatch) +"bR" = ( +/obj/effect/landmark/deathmatch_player_spawn, +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"bY" = ( +/obj/structure/railing{ + dir = 6 + }, +/obj/structure/closet/crate/secure/weapon{ + locked = 0 + }, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/item/ammo_box/c38, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 6 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"ca" = ( +/obj/effect/decal/cleanable/glass, +/obj/effect/mapping_helpers/broken_floor, +/obj/structure/girder/displaced, +/turf/open/indestructible/plating, +/area/deathmatch) +"ci" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"cr" = ( +/obj/item/chair/wood, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/wood/tile, +/area/deathmatch) +"cv" = ( +/obj/structure/safe, +/obj/item/gun/energy/laser/instakill, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"cy" = ( +/obj/effect/spawner/structure/window/hollow/middle{ + dir = 4 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"cU" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/item/grenade/syndieminibomb/concussion, +/turf/open/indestructible/plating, +/area/deathmatch) +"dB" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 4 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"dU" = ( +/obj/structure/grille/broken, +/obj/effect/decal/cleanable/glass, +/turf/open/indestructible/plating, +/area/deathmatch) +"ec" = ( +/obj/item/ammo_casing/shotgun/breacher, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"eA" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/structure/girder/displaced, +/turf/open/indestructible/plating, +/area/deathmatch) +"fa" = ( +/obj/structure/chair/wood{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood, +/area/deathmatch) +"fJ" = ( +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"gL" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 4 + }, +/obj/effect/decal/fakelattice{ + density = 0 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"gN" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"hR" = ( +/obj/structure/chair/wood, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/wood/tile, +/area/deathmatch) +"hZ" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood/tile, +/area/deathmatch) +"ii" = ( +/obj/structure/closet/crate/critter{ + mob_storage_capacity = 33 + }, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/mob/living/basic/mothroach, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"il" = ( +/obj/effect/light_emitter/fake_outdoors, +/obj/effect/particle_effect/ion_trails/flight{ + icon_state = "shieldwall" + }, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"jj" = ( +/obj/machinery/power/shuttle_engine/heater, +/obj/structure/window/spawner/directional/north, +/turf/open/indestructible/plating, +/area/deathmatch) +"jq" = ( +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/item/storage/toolbox/mechanical, +/turf/open/indestructible/plating, +/area/deathmatch) +"kd" = ( +/obj/structure/closet/crate/bin, +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"ke" = ( +/obj/effect/spawner/structure/window/hollow/middle, +/turf/open/indestructible/plating, +/area/deathmatch) +"kt" = ( +/obj/structure/table/reinforced, +/obj/item/gun/ballistic/automatic/pistol/m1911, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood, +/area/deathmatch) +"kR" = ( +/obj/effect/decal/fakelattice{ + density = 0 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/wood, +/area/deathmatch) +"lJ" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 8 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"mi" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/machinery/computer/old{ + dir = 8 + }, +/turf/open/floor/wood, +/area/deathmatch) +"mr" = ( +/obj/structure/chair/wood, +/turf/open/floor/wood/tile, +/area/deathmatch) +"mS" = ( +/obj/structure/barricade/wooden, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"mW" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/structure/closet/crate/secure/weapon{ + locked = 0 + }, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/item/ammo_box/c38, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"nj" = ( +/obj/effect/decal/fakelattice{ + density = 0 + }, +/obj/effect/decal/cleanable/glass, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"oo" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood, +/area/deathmatch) +"pm" = ( +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"pO" = ( +/obj/structure/railing{ + dir = 8 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/structure/closet/crate, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 8 + }, +/obj/item/storage/medkit/brute, +/obj/item/reagent_containers/hypospray/medipen, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"qJ" = ( +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/closet/crate, +/obj/item/extinguisher, +/obj/item/extinguisher/anti, +/turf/open/indestructible/plating, +/area/deathmatch) +"qY" = ( +/obj/effect/landmark/deathmatch_player_spawn, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"rd" = ( +/obj/structure/chair/comfy/shuttle/tactical{ + dir = 1 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"ru" = ( +/obj/structure/table/wood, +/obj/item/food/spaghetti/pastatomato, +/obj/item/knife/kitchen, +/turf/open/floor/wood/tile, +/area/deathmatch) +"ry" = ( +/obj/item/stack/rods/ten, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/fakelattice{ + density = 0 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"rM" = ( +/obj/structure/shipping_container/deforest, +/obj/structure/railing{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"rZ" = ( +/obj/structure/girder, +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"sp" = ( +/obj/structure/girder/displaced, +/turf/open/indestructible/plating, +/area/deathmatch) +"ty" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/decal/fakelattice{ + density = 0 + }, +/turf/open/floor/wood, +/area/deathmatch) +"tQ" = ( +/obj/machinery/oven/range, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"uM" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 4 + }, +/obj/item/spear, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"vl" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 8 + }, +/obj/effect/decal/fakelattice{ + density = 0 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"vV" = ( +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/effect/decal/cleanable/dirt, +/obj/item/storage/bag/money, +/turf/open/indestructible/plating, +/area/deathmatch) +"vW" = ( +/obj/structure/lattice/catwalk, +/obj/structure/door_assembly/door_assembly_wood, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"wf" = ( +/turf/open/floor/wood, +/area/deathmatch) +"wm" = ( +/obj/structure/door_assembly/door_assembly_wood, +/obj/effect/decal/fakelattice{ + density = 0 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/wood, +/area/deathmatch) +"wv" = ( +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/item/reagent_containers/cup/bucket/wooden, +/obj/item/flashlight/flare/torch, +/turf/open/indestructible/plating, +/area/deathmatch) +"wy" = ( +/obj/structure/chair/wood{ + dir = 1 + }, +/obj/effect/decal/cleanable/glass, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"wE" = ( +/obj/effect/spawner/structure/window, +/turf/open/indestructible/plating, +/area/deathmatch) +"wR" = ( +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/fermenting_barrel/gunpowder, +/obj/item/stack/cannonball/the_big_one, +/turf/open/indestructible/plating, +/area/deathmatch) +"xd" = ( +/obj/machinery/computer/old, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood, +/area/deathmatch) +"xn" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood, +/area/deathmatch) +"xp" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/fakelattice{ + density = 0 + }, +/turf/open/floor/wood, +/area/deathmatch) +"xN" = ( +/obj/structure/railing, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/structure/reagent_dispensers/fueltank/large, +/obj/effect/turf_decal/stripes/asteroid/line, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"xV" = ( +/obj/effect/decal/cleanable/glass, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"yi" = ( +/obj/structure/barricade/wooden/crude, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"yr" = ( +/obj/effect/light_emitter/fake_outdoors, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"yR" = ( +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"ze" = ( +/obj/machinery/door/airlock/wood/glass, +/obj/effect/turf_decal/siding/wood/corner, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 8 + }, +/turf/open/floor/wood, +/area/deathmatch) +"zg" = ( +/obj/machinery/power/shuttle_engine/propulsion, +/turf/open/indestructible/plating, +/area/deathmatch) +"zP" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"An" = ( +/obj/structure/grille/broken, +/obj/item/shard, +/obj/effect/decal/cleanable/glass, +/turf/open/indestructible/plating, +/area/deathmatch) +"AR" = ( +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Bx" = ( +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/cannon{ + anchorable_cannon = 0; + anchored = 0 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"BC" = ( +/obj/item/ammo_casing/shotgun/scatterlaser, +/obj/structure/kitchenspike, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"BN" = ( +/obj/structure/table_frame/wood, +/turf/open/floor/wood/tile, +/area/deathmatch) +"CN" = ( +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/wood/tile, +/area/deathmatch) +"CO" = ( +/obj/structure/chair/wood{ + dir = 1 + }, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/wood/tile, +/area/deathmatch) +"CX" = ( +/obj/structure/girder, +/obj/structure/railing{ + dir = 8 + }, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Da" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/open/floor/wood, +/area/deathmatch) +"Du" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood/tile, +/area/deathmatch) +"Dy" = ( +/obj/machinery/door/airlock/wood/glass, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 1 + }, +/turf/open/floor/wood, +/area/deathmatch) +"Ej" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/end, +/turf/open/indestructible/plating, +/area/deathmatch) +"ED" = ( +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"EH" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/item/storage/toolbox/mechanical, +/turf/open/indestructible/plating, +/area/deathmatch) +"EU" = ( +/obj/item/stack/rods/ten, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"EX" = ( +/obj/structure/lattice/catwalk, +/obj/item/ammo_box/c38/match, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"Fa" = ( +/obj/structure/girder, +/obj/structure/railing{ + dir = 9 + }, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 9 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Fh" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/storage/bag/money, +/turf/open/indestructible/plating, +/area/deathmatch) +"Fs" = ( +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"FB" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/end{ + dir = 1 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"Ge" = ( +/obj/structure/lattice/catwalk, +/obj/item/storage/medkit/ancient, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"Gl" = ( +/obj/structure/barricade/wooden/crude, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 8 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"Gx" = ( +/obj/effect/turf_decal/siding/wood, +/obj/machinery/door/airlock/wood/glass, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"GQ" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"Ht" = ( +/obj/structure/girder, +/obj/structure/railing{ + dir = 10 + }, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 10 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Hx" = ( +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/wood, +/area/deathmatch) +"HH" = ( +/obj/machinery/door/airlock/wood/glass, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/wood, +/area/deathmatch) +"HV" = ( +/obj/item/stack/rods/ten, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"HZ" = ( +/obj/structure/girder, +/obj/structure/railing{ + dir = 5 + }, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 5 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"ID" = ( +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/floor/wood, +/area/deathmatch) +"IJ" = ( +/obj/structure/kitchenspike, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"IR" = ( +/obj/structure/lattice/catwalk, +/obj/item/shield/improvised, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"Je" = ( +/obj/structure/lattice/catwalk, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"Js" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/effect/turf_decal/stripes/asteroid/line, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Kv" = ( +/obj/structure/table/reinforced, +/obj/item/gun/ballistic/shotgun/doublebarrel, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"KT" = ( +/turf/closed/wall/r_wall, +/area/deathmatch) +"LX" = ( +/obj/effect/decal/cleanable/glass, +/obj/structure/girder/displaced, +/turf/open/indestructible/plating, +/area/deathmatch) +"Mq" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Mt" = ( +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"Mz" = ( +/obj/machinery/door/airlock/wood/glass, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"MV" = ( +/obj/effect/decal/fakelattice{ + density = 0 + }, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"Ow" = ( +/obj/item/ammo_casing/shotgun/pulverizer, +/obj/structure/kitchenspike, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"Pa" = ( +/obj/effect/landmark/deathmatch_player_spawn, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"Pc" = ( +/obj/structure/table/reinforced, +/obj/item/storage/fancy/cigarettes/cigars/cohiba, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood, +/area/deathmatch) +"PD" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/machinery/vending/dinnerware, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"QL" = ( +/obj/machinery/computer/old, +/obj/effect/mapping_helpers/broken_machine, +/turf/open/indestructible/plating, +/area/deathmatch) +"Rg" = ( +/obj/item/chair/wood, +/turf/open/floor/wood/tile, +/area/deathmatch) +"Rn" = ( +/obj/effect/decal/cleanable/glass, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Se" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/wood, +/area/deathmatch) +"Sm" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Sy" = ( +/obj/structure/lattice, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"Tg" = ( +/obj/structure/table/reinforced, +/obj/item/food/meat/slab/pig, +/obj/item/food/meat/slab/pig, +/obj/item/food/meat/slab/pig, +/obj/item/food/meat/slab/pig, +/obj/item/food/meat/slab/pig, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"TA" = ( +/obj/machinery/griddle, +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"Uq" = ( +/obj/structure/lattice/catwalk, +/obj/item/ammo_casing/shotgun/executioner, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"Vc" = ( +/obj/effect/decal/cleanable/glass, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"Vu" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/structure/girder, +/turf/open/indestructible/plating, +/area/deathmatch) +"VS" = ( +/obj/structure/closet/secure_closet/freezer/kitchen{ + req_access = null + }, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"VT" = ( +/obj/structure/table/reinforced, +/obj/item/knife/kitchen, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"Wa" = ( +/turf/closed/wall/mineral/wood/nonmetal, +/area/deathmatch) +"Ww" = ( +/obj/machinery/computer/old, +/obj/effect/decal/cleanable/blood/old, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/indestructible/plating, +/area/deathmatch) +"Xr" = ( +/obj/structure/barricade/wooden/crude, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 4 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"Xw" = ( +/obj/structure/chair/wood, +/obj/effect/landmark/deathmatch_player_spawn, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/wood/tile, +/area/deathmatch) +"XD" = ( +/obj/structure/table/reinforced, +/obj/item/storage/fancy/egg_box, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"Yg" = ( +/obj/item/stack/rods/ten, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/fakelattice{ + density = 0 + }, +/turf/open/indestructible/plating, +/area/deathmatch) +"Yi" = ( +/obj/effect/turf_decal/siding/thinplating_new{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/closet/crate, +/obj/item/clothing/suit/armor/bulletproof, +/turf/open/indestructible/plating, +/area/deathmatch) +"Ys" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/structure/closet/crate/secure/weapon{ + locked = 0 + }, +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/item/ammo_box/c38, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 4 + }, +/obj/item/gun/energy/laser, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"Yt" = ( +/obj/effect/decal/cleanable/fuel_pool/hivis, +/obj/structure/closet/crate/secure/freezer{ + locked = 0 + }, +/obj/item/food/pizza/flatbread/zmorgast, +/obj/item/food/pizza/flatbread/stinging, +/obj/item/food/pizza/flatbread/rustic, +/obj/item/food/pizza/flatbread/nutty, +/obj/item/food/pizza/flatbread/mushroom, +/obj/item/food/pizza/flatbread/italic, +/obj/item/food/pizza/flatbread/imperial, +/obj/item/food/pizza/flatbread/fish, +/obj/effect/decal/cleanable/dirt, +/turf/open/indestructible/plating, +/area/deathmatch) +"YP" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/door/airlock/wood/glass, +/turf/open/floor/iron/kitchen, +/area/deathmatch) +"YR" = ( +/obj/structure/railing{ + dir = 1 + }, +/obj/effect/mapping_helpers/broken_floor, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/plating, +/area/deathmatch) +"Zc" = ( +/obj/structure/lattice/catwalk, +/obj/structure/girder/displaced, +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast, +/area/deathmatch) +"ZR" = ( +/turf/open/floor/iron/kitchen, +/area/deathmatch) + +(1,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(2,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +"} +(3,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(4,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(5,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(6,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +"} +(7,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +Je +Je +Ge +Mt +Mt +Mt +Mt +Mt +Je +Je +Je +Je +Je +EX +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(8,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Wa +cy +cy +Wa +HH +HH +Wa +Wa +Sy +Sy +Sy +Wa +Wa +An +Wa +Wa +wE +Wa +Wa +Sy +Sy +Sy +Wa +Wa +zg +as +as +as +as +as +as +as +"} +(9,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +ke +kt +xn +xn +xn +Hx +Da +Wa +Mt +Mt +Mt +Wa +hR +BN +Rg +mr +ru +CO +Wa +Mt +Mt +Mt +Yi +jj +zg +as +as +as +as +as +as +as +"} +(10,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +ke +xd +fa +Fs +ID +Hx +xn +ze +Se +oo +oo +Dy +at +at +CN +at +Du +hZ +ze +Se +xp +oo +be +jj +zg +as +as +as +as +il +as +as +"} +(11,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +ke +Pc +Fs +Fs +wf +xn +mi +Wa +Mt +Mt +Mt +Wa +Xw +ai +CN +at +BN +cr +Wa +Mt +Je +Mt +jq +jj +zg +as +as +as +as +as +as +as +"} +(12,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Wa +cy +cy +Wa +wm +kR +yi +Wa +Sy +Sy +Sy +Wa +Wa +dB +gL +dB +Xr +Wa +Wa +Sy +Je +Sy +Wa +Wa +zg +as +as +as +as +as +as +as +"} +(13,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +Je +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +Mt +Mt +Mt +Mt +Mt +Je +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(14,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Je +Je +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Je +Mt +Mt +yr +Mt +Mt +Je +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +"} +(15,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Zc +Je +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +Mt +Mt +Mt +Mt +Mt +Je +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(16,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Fs +cU +ca +eA +MV +MV +xV +KT +Sy +Sy +Sy +Fa +rM +EH +ry +gN +pO +CX +Ht +Sy +Je +Sy +KT +KT +zg +as +as +as +as +as +as +as +"} +(17,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +zP +ca +xV +xV +Fs +LX +Rn +Fs +Se +Se +Se +yR +Sm +HV +Sm +EU +vV +Mq +Js +Se +ty +Se +wR +jj +zg +as +as +as +as +as +as +as +"} +(18,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +Fs +xV +rd +xV +Pa +zP +xV +Vu +Mt +Mt +Mt +YR +Sm +ii +Sm +Mq +Yt +AR +xN +Mt +Je +Mt +wv +jj +zg +as +as +as +as +il +as +as +"} +(19,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Fs +QL +Fs +Fs +eA +sp +xV +zP +Se +Se +Se +yR +Fh +zP +Fh +Sm +AR +Mq +Js +Se +ty +Se +Bx +jj +zg +as +as +as +as +as +as +as +"} +(20,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +eA +Fs +KT +Ej +nj +nj +FB +KT +Sy +Sy +Sy +HZ +rZ +uM +Yg +ci +Ys +mW +bY +Sy +Je +Sy +KT +KT +zg +as +as +as +as +as +as +as +"} +(21,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +Je +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +Mt +Mt +Mt +Mt +Mt +Je +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(22,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Je +Je +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Je +Mt +Mt +yr +Mt +Mt +Je +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +"} +(23,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +vW +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +Mt +Mt +Mt +Mt +Mt +Je +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(24,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Wa +cy +dU +mS +MV +MV +Wa +Wa +Sy +Sy +Sy +Wa +Gl +lJ +vl +lJ +lJ +Wa +Wa +Sy +Je +Sy +Wa +Wa +zg +as +as +as +as +as +as +as +"} +(25,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +ke +cv +Vc +Vc +Vc +ec +Ow +Wa +Mt +Mt +Mt +Wa +tQ +ED +ED +ED +ED +PD +Wa +Mt +Je +Mt +fJ +jj +zg +as +as +as +as +as +as +as +"} +(26,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +ke +Ww +wy +Vc +qY +GQ +GQ +ze +Se +Se +Se +YP +ZR +ZR +bR +ZR +pm +ZR +Gx +Se +ty +Se +be +jj +zg +as +as +as +as +il +as +as +"} +(27,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +ke +Kv +GQ +BC +GQ +GQ +IJ +Wa +Mt +Mt +Mt +Wa +TA +VT +Tg +XD +VS +kd +Wa +Mt +Mt +Mt +qJ +jj +zg +as +as +as +as +as +as +as +"} +(28,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Wa +cy +cy +Wa +Mz +Mz +Wa +Wa +Sy +Sy +Sy +Wa +Wa +wE +Wa +Wa +wE +Wa +Wa +Sy +Sy +Sy +Wa +Wa +zg +as +as +as +as +as +as +as +"} +(29,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Je +Je +Je +Uq +Mt +Mt +Mt +Mt +Mt +Je +Je +Je +IR +Je +Je +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(30,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +"} +(31,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(32,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(33,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} +(34,1,1) = {" +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +Mt +Mt +Mt +yr +Mt +Mt +"} +(35,1,1) = {" +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +Mt +"} diff --git a/_maps/gateway_test.json b/_maps/gateway_test.json index 0b3923162f62c..df38ec4c5b866 100644 --- a/_maps/gateway_test.json +++ b/_maps/gateway_test.json @@ -7,6 +7,7 @@ "load_all_away_missions": true, "ignored_unit_tests": [ "/datum/unit_test/antag_moodlets", + "/datum/unit_test/cargo_dep_order_locations", "/datum/unit_test/job_roundstart_spawnpoints", "/datum/unit_test/required_map_items", "/datum/unit_test/space_dragon_expiration", diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index d9fb22def8fb1..811ea64f9b4c1 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -264,7 +264,6 @@ /obj/structure/chair/office/light{ dir = 8 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/virology) "agy" = ( @@ -633,8 +632,8 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/yellow/visible, /obj/machinery/meter, +/obj/machinery/atmospherics/pipe/smart/manifold/yellow/visible, /turf/open/floor/iron, /area/station/engineering/atmos) "api" = ( @@ -648,17 +647,11 @@ /area/station/science/server) "apj" = ( /obj/effect/turf_decal/sand/plating, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ dir = 4 }, /turf/open/floor/plating/airless, -/area/space/nearstation) +/area/space) "apk" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/tile/dark_red{ @@ -1721,6 +1714,7 @@ dir = 4 }, /obj/machinery/light/cold/directional/north, +/obj/machinery/portable_atmospherics/canister, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "aOx" = ( @@ -2567,10 +2561,10 @@ /turf/open/floor/iron/small, /area/station/security/office) "bkI" = ( +/obj/machinery/status_display/evac/directional/south, /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible{ - dir = 5 + dir = 4 }, -/obj/machinery/status_display/evac/directional/south, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "bkO" = ( @@ -2988,13 +2982,7 @@ /area/station/maintenance/starboard/greater) "brC" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ +/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible{ dir = 4 }, /turf/open/floor/plating, @@ -3515,8 +3503,9 @@ /turf/open/floor/iron, /area/station/cargo/sorting) "bDO" = ( -/obj/machinery/atmospherics/pipe/smart/simple/cyan/visible{ - dir = 10 +/obj/machinery/atmospherics/components/binary/pump{ + dir = 4; + name = "N2 to Pure" }, /turf/open/floor/iron/dark, /area/station/engineering/atmos) @@ -3734,6 +3723,7 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/item/radio/intercom/directional/west, /obj/machinery/status_display/evac/directional/south, +/obj/item/kirbyplants/random, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "bJZ" = ( @@ -4847,7 +4837,7 @@ "chb" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 5 + dir = 8 }, /turf/open/floor/iron, /area/station/engineering/atmos) @@ -7530,12 +7520,12 @@ /turf/open/floor/iron/dark/small, /area/station/security/checkpoint/customs/auxiliary) "dqV" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 9 +/obj/effect/turf_decal/sand/plating, +/obj/machinery/atmospherics/pipe/smart/simple/cyan/visible/layer4{ + dir = 5 }, -/obj/machinery/portable_atmospherics/canister, -/turf/open/floor/iron, -/area/station/engineering/atmos) +/turf/open/floor/plating/airless, +/area/space/nearstation) "dqX" = ( /obj/structure/reagent_dispensers/wall/peppertank/directional/north, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, @@ -9089,6 +9079,7 @@ /area/station/medical/medbay/aft) "dYY" = ( /obj/machinery/light/cold/dim/directional/north, +/obj/machinery/portable_atmospherics/canister, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "dZa" = ( @@ -9160,6 +9151,10 @@ /area/station/maintenance/department/medical/central) "dZX" = ( /obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/components/binary/pump/off/general/visible{ + dir = 4; + name = "Air to Pure" + }, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "dZZ" = ( @@ -10017,6 +10012,10 @@ pixel_y = 4 }, /obj/item/clothing/glasses/meson, +/obj/item/grenade/chem_grenade/smart_metal_foam{ + pixel_x = -8; + pixel_y = 14 + }, /turf/open/floor/iron/grimy, /area/station/engineering/main) "erK" = ( @@ -10260,6 +10259,10 @@ /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, /obj/structure/cable, /obj/effect/decal/cleanable/dirt/dust, +/obj/item/clothing/head/cone{ + pixel_x = -7; + pixel_y = 9 + }, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "exE" = ( @@ -11518,6 +11521,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 }, +/obj/item/airlock_painter, /turf/open/floor/iron/grimy, /area/station/engineering/main) "eWj" = ( @@ -12001,12 +12005,12 @@ /area/station/service/cafeteria) "fhX" = ( /obj/structure/table/greyscale, -/obj/item/folder/yellow{ - pixel_x = 2; - pixel_y = 4 +/obj/item/lightreplacer{ + pixel_y = 7 }, -/obj/item/pen{ - pixel_x = -4 +/obj/item/lightreplacer{ + pixel_y = 2; + pixel_x = -2 }, /turf/open/floor/iron/grimy, /area/station/engineering/main) @@ -13346,8 +13350,9 @@ /turf/open/floor/catwalk_floor/iron_smooth, /area/station/ai_monitored/turret_protected/aisat/teleporter) "fJt" = ( -/obj/machinery/atmospherics/pipe/smart/manifold/yellow/visible{ - dir = 4 +/obj/machinery/atmospherics/components/unary/thermomachine/heater/on{ + dir = 8; + initialize_directions = 8 }, /turf/open/floor/iron, /area/station/engineering/atmos) @@ -15799,7 +15804,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 10 }, -/obj/item/kirbyplants/random, +/obj/machinery/atmospherics/pipe/smart/manifold/yellow/visible, /turf/open/floor/iron, /area/station/engineering/atmos) "gCR" = ( @@ -18455,18 +18460,12 @@ /turf/open/floor/plating, /area/station/cargo/miningoffice) "hsL" = ( -/obj/structure/lattice/catwalk, -/obj/structure/railing{ - dir = 8 - }, -/obj/structure/railing{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/simple/cyan/visible/layer4{ +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ dir = 6 }, /turf/open/space/basic, -/area/station/engineering/atmos/space_catwalk) +/area/space/nearstation) "hsO" = ( /obj/structure/cable, /obj/effect/spawner/structure/window, @@ -19326,7 +19325,6 @@ /obj/effect/turf_decal/tile/blue{ dir = 1 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) "hGE" = ( @@ -20271,14 +20269,12 @@ /turf/open/floor/iron, /area/station/cargo/miningfoundry) "hZf" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible{ +/obj/effect/turf_decal/sand/plating, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ dir = 4 }, -/turf/open/floor/iron, -/area/station/engineering/atmos) +/turf/open/floor/plating/airless, +/area/space/nearstation) "hZP" = ( /obj/structure/cable, /obj/structure/sign/poster/official/random/directional/north, @@ -20846,8 +20842,8 @@ /obj/effect/turf_decal/stripes/line{ dir = 9 }, -/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/manifold/yellow/visible{ + dir = 1 }, /turf/open/floor/iron, /area/station/engineering/atmos) @@ -21657,7 +21653,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 8 }, -/obj/machinery/atmospherics/components/unary/thermomachine/heater{ +/obj/machinery/atmospherics/pipe/smart/manifold/yellow/visible{ dir = 4 }, /turf/open/floor/iron, @@ -24481,14 +24477,14 @@ /area/station/commons/storage/tools) "jul" = ( /obj/structure/lattice, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ dir = 4 }, /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 4 + dir = 10 }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ + dir = 10 }, /turf/open/space/basic, /area/space/nearstation) @@ -24946,7 +24942,7 @@ /area/station/ai_monitored/security/armory) "jBA" = ( /obj/structure/cable, -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/machinery/camera/directional/north{ c_tag = "AI Chamber - SMES"; network = list("aicore") @@ -25662,10 +25658,6 @@ "jKU" = ( /turf/closed/wall, /area/station/engineering/atmos/storage/gas) -"jLi" = ( -/obj/effect/landmark/start/virologist, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/virology) "jLl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -27015,7 +27007,7 @@ /area/station/hallway/primary/central/fore) "kiQ" = ( /obj/structure/cable, -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/machinery/status_display/ai/directional/north, /turf/open/floor/iron/smooth, /area/station/ai_monitored/turret_protected/aisat/equipment) @@ -27412,7 +27404,7 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible/layer4{ - dir = 9 + dir = 8 }, /turf/open/space/basic, /area/station/engineering/atmos/space_catwalk) @@ -27931,7 +27923,7 @@ /area/station/science/robotics/augments) "kwH" = ( /obj/effect/turf_decal/sand/plating, -/obj/machinery/atmospherics/pipe/smart/simple/cyan/visible/layer4{ +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ dir = 4 }, /turf/open/floor/plating/airless, @@ -29477,10 +29469,8 @@ /turf/open/floor/iron/small, /area/station/engineering/engine_smes) "kXf" = ( -/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ - dir = 4 - }, /obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/visible, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "kXj" = ( @@ -31847,10 +31837,10 @@ /turf/open/misc/sandy_dirt, /area/station/hallway/primary/central/fore) "lGq" = ( +/obj/structure/fluff/broken_canister_frame, /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 8 }, -/obj/structure/fluff/broken_canister_frame, /turf/open/floor/iron, /area/station/engineering/atmos) "lGr" = ( @@ -32221,15 +32211,12 @@ /area/station/hallway/primary/fore) "lLE" = ( /obj/effect/turf_decal/sand/plating, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ dir = 4 }, +/obj/machinery/atmospherics/pipe/smart/simple/cyan/visible/layer4{ + dir = 10 + }, /turf/open/floor/plating/airless, /area/space/nearstation) "lLH" = ( @@ -33668,7 +33655,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/machinery/space_heater, +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 8 + }, /turf/open/floor/iron, /area/station/engineering/atmos) "mgt" = ( @@ -35118,14 +35107,7 @@ dir = 6 }, /obj/effect/decal/cleanable/dirt/dust, -/obj/item/clothing/head/cone{ - pixel_x = -7; - pixel_y = 9 - }, -/obj/item/clothing/head/cone{ - pixel_x = -7; - pixel_y = 11 - }, +/obj/structure/tank_holder/extinguisher/advanced, /turf/open/floor/iron, /area/station/engineering/atmos) "mFG" = ( @@ -35266,13 +35248,6 @@ /obj/machinery/atmospherics/pipe/smart/simple/dark/hidden, /turf/open/floor/iron/grimy, /area/station/tcommsat/server) -"mIa" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/start/virologist, -/turf/open/floor/iron/white/small, -/area/station/medical/virology) "mIg" = ( /obj/machinery/light/small/directional/west, /turf/open/floor/catwalk_floor/iron_dark, @@ -35453,17 +35428,10 @@ /turf/open/floor/iron/cafeteria, /area/station/service/cafeteria) "mKK" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ - dir = 4 +/obj/effect/turf_decal/stripes/line{ + dir = 6 }, -/turf/open/floor/plating, +/turf/open/floor/iron, /area/station/engineering/atmos) "mKV" = ( /obj/effect/turf_decal/siding/blue{ @@ -36154,16 +36122,7 @@ /turf/open/floor/plating, /area/station/maintenance/starboard/aft) "mXm" = ( -/obj/machinery/atmospherics/components/binary/pump{ - dir = 4; - name = "N2O to Pure" - }, -/obj/machinery/atmospherics/components/binary/pump/off/general/visible/layer1{ - dir = 4; - name = "Plasma to Pure"; - color = "#BF40BF" - }, -/obj/machinery/atmospherics/components/binary/pump/off/general/visible/layer5{ +/obj/machinery/atmospherics/components/binary/pump/off/general/visible{ dir = 4; name = "CO2 to Pure" }, @@ -36176,13 +36135,11 @@ /turf/open/floor/iron/dark/small, /area/station/medical/storage) "mXx" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 6 +/obj/machinery/atmospherics/components/binary/pump{ + dir = 4; + name = "N2O to Pure" }, -/turf/open/floor/iron, +/turf/open/floor/iron/dark, /area/station/engineering/atmos) "mXD" = ( /obj/effect/turf_decal/stripes/white/line{ @@ -36960,28 +36917,9 @@ /turf/open/floor/iron/textured_half, /area/station/security) "nki" = ( -/obj/structure/rack, -/obj/item/airlock_painter, -/obj/item/lightreplacer{ - pixel_y = 7 - }, -/obj/item/clothing/head/utility/hardhat/welding{ - pixel_x = -4; - pixel_y = -3 - }, -/obj/item/clothing/head/utility/hardhat/welding{ - pixel_x = -4 - }, -/obj/item/clothing/head/utility/hardhat/welding{ - pixel_x = -4; - pixel_y = 3 - }, /obj/effect/turf_decal/bot, /obj/machinery/light/cold/dim/directional/west, -/obj/item/grenade/chem_grenade/smart_metal_foam{ - pixel_x = 9; - pixel_y = 5 - }, +/obj/machinery/vending/wardrobe/engi_wardrobe, /turf/open/floor/iron, /area/station/engineering/main) "nkl" = ( @@ -38538,6 +38476,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/white/corner, /area/station/science/xenobiology) +"nID" = ( +/obj/effect/turf_decal/sand/plating, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ + dir = 4 + }, +/turf/open/floor/plating/airless, +/area/space/nearstation) "nIJ" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -39629,6 +39574,7 @@ }, /obj/structure/cable, /obj/machinery/firealarm/directional/north, +/obj/machinery/space_heater, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "obe" = ( @@ -42319,10 +42265,15 @@ /turf/open/floor/iron/dark, /area/station/science/genetics) "oTY" = ( -/obj/effect/turf_decal/stripes/line, -/obj/structure/tank_holder/extinguisher/advanced, -/turf/open/floor/iron, -/area/station/engineering/atmos) +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ + dir = 5 + }, +/turf/open/space/basic, +/area/space/nearstation) "oTZ" = ( /obj/structure/table, /turf/open/floor/plating, @@ -43310,6 +43261,9 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/tram, /area/station/maintenance/department/medical/central) +"pjk" = ( +/turf/open/floor/iron, +/area/station/engineering/atmos) "pjn" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/machinery/dna_scannernew, @@ -45244,8 +45198,9 @@ /area/station/maintenance/port/fore) "pJT" = ( /obj/structure/lattice, -/obj/machinery/atmospherics/pipe/smart/simple/cyan/visible/layer4{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ + dir = 6 }, /turf/open/space/basic, /area/space/nearstation) @@ -45700,10 +45655,6 @@ }, /turf/open/floor/iron/dark/side, /area/station/science/xenobiology) -"pRb" = ( -/obj/item/computer_disk/virus/mime, -/turf/closed/mineral/random/stationside, -/area/space/nearstation) "pRe" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/table/wood, @@ -47612,18 +47563,9 @@ /turf/open/floor/iron/diagonal, /area/station/hallway/primary/central/aft) "qqr" = ( -/obj/machinery/atmospherics/components/binary/pump/off/general/visible/layer5{ +/obj/machinery/atmospherics/components/binary/pump/off/general/visible{ dir = 4; - name = "Air to Pure" - }, -/obj/machinery/atmospherics/pipe/smart/simple/cyan/hidden, -/obj/machinery/atmospherics/components/binary/pump{ - dir = 4; - name = "N2 to Pure" - }, -/obj/machinery/atmospherics/components/binary/pump/off/general/visible/layer1{ - dir = 4; - name = "O2 to Pure" + name = "O2 to pure" }, /turf/open/floor/iron/dark, /area/station/engineering/atmos) @@ -48395,7 +48337,8 @@ "qAQ" = ( /obj/machinery/light/small/directional/east, /obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/helium_output{ - dir = 8 + dir = 8; + name = "N2O tank output inlet" }, /turf/open/floor/engine/n2o, /area/station/ai_monitored/turret_protected/ai) @@ -49240,6 +49183,13 @@ /obj/structure/cable, /turf/open/floor/iron/smooth, /area/station/engineering/engine_smes) +"qME" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ + dir = 5 + }, +/turf/open/space/basic, +/area/space/nearstation) "qMG" = ( /obj/effect/decal/cleanable/dirt/dust, /obj/structure/cable, @@ -49369,7 +49319,7 @@ /obj/machinery/atmospherics/pipe/smart/simple/supply/visible/layer2{ dir = 6 }, -/obj/machinery/meter, +/obj/machinery/meter/layer2, /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) "qQg" = ( @@ -50970,7 +50920,6 @@ /obj/effect/turf_decal/stripes/line{ dir = 5 }, -/obj/item/kirbyplants/random, /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ dir = 10 }, @@ -51372,14 +51321,17 @@ /area/station/maintenance/starboard/fore) "rqV" = ( /obj/structure/lattice, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ dir = 4 }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/simple/cyan/visible/layer4{ + dir = 8 }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer1{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible/layer5{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ + dir = 9 }, /turf/open/space/basic, /area/space/nearstation) @@ -51839,10 +51791,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 6 }, -/obj/machinery/atmospherics/components/unary/thermomachine/heater/on{ - dir = 8; - initialize_directions = 8 - }, +/obj/item/kirbyplants/random, /turf/open/floor/iron, /area/station/engineering/atmos) "rxu" = ( @@ -53642,8 +53591,8 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ + dir = 1 }, /turf/open/floor/iron, /area/station/engineering/atmos) @@ -55102,8 +55051,9 @@ /area/station/security/checkpoint/customs/auxiliary) "sqB" = ( /obj/effect/turf_decal/stripes/line, -/obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ - dir = 4 +/obj/machinery/atmospherics/components/unary/thermomachine/heater/on{ + dir = 8; + initialize_directions = 8 }, /turf/open/floor/iron, /area/station/engineering/atmos) @@ -58280,7 +58230,10 @@ /turf/open/floor/iron, /area/station/maintenance/department/engine/atmos) "tnH" = ( -/obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/visible, +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ + dir = 4 + }, +/obj/effect/landmark/start/atmospheric_technician, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "tnO" = ( @@ -60287,6 +60240,10 @@ "tSg" = ( /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, /obj/machinery/light_switch/directional/east, +/obj/item/clothing/head/cone{ + pixel_x = -7; + pixel_y = 11 + }, /turf/open/floor/iron/dark, /area/station/engineering/atmos) "tSh" = ( @@ -60450,7 +60407,7 @@ desc = "A cold, hard place for your final rest."; name = "Morgue Slab" }, -/mob/living/carbon/human/species/monkey/humand_legged{ +/mob/living/carbon/human/species/monkey{ name = "Charles"; real_name = "Charles" }, @@ -61722,6 +61679,13 @@ /obj/effect/mapping_helpers/airlock/access/all/medical/general, /turf/open/floor/iron/white/small, /area/station/medical/cryo) +"ulf" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/yellow/visible, +/turf/open/floor/iron, +/area/station/engineering/atmos) "ull" = ( /obj/machinery/light/cold/directional/west, /turf/open/floor/iron, @@ -61761,13 +61725,13 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ + dir = 4 + }, /obj/machinery/atmospherics/components/binary/pump{ dir = 1; name = "South Ports to Wastes" }, -/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ - dir = 4 - }, /turf/open/floor/iron, /area/station/engineering/atmos) "umr" = ( @@ -66319,7 +66283,8 @@ "vzK" = ( /obj/machinery/light/small/directional/west, /obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/helium_output{ - dir = 4 + dir = 4; + chamber_id = "helium" }, /turf/open/floor/engine/helium, /area/station/ai_monitored/turret_protected/ai) @@ -67463,7 +67428,9 @@ /area/station/maintenance/starboard/central) "vPY" = ( /obj/effect/turf_decal/stripes/line, -/obj/machinery/atmospherics/pipe/smart/manifold/yellow/visible, +/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ + dir = 4 + }, /turf/open/floor/iron, /area/station/engineering/atmos) "vQk" = ( @@ -67738,11 +67705,14 @@ /turf/open/floor/iron, /area/station/security/prison) "vUh" = ( -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 8 +/obj/machinery/atmospherics/components/binary/pump/off/general/visible/layer1{ + dir = 4; + name = "Plasma to Pure"; + color = "#BF40BF"; + piping_layer = 3; + icon_state = "pump_map-3" }, -/obj/machinery/portable_atmospherics/canister, -/turf/open/floor/iron, +/turf/open/floor/iron/dark, /area/station/engineering/atmos) "vUq" = ( /obj/machinery/restaurant_portal/bar, @@ -68911,7 +68881,9 @@ /area/station/service/chapel) "wlS" = ( /obj/effect/turf_decal/stripes/line, -/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible, +/obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ + dir = 9 + }, /turf/open/floor/iron, /area/station/engineering/atmos) "wlU" = ( @@ -70351,8 +70323,8 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/central) "wHO" = ( -/obj/structure/dresser, /obj/structure/sign/poster/official/random/directional/north, +/obj/structure/closet/crate/wooden/toy, /turf/open/floor/wood/parquet, /area/station/service/greenroom) "wHP" = ( @@ -70752,10 +70724,10 @@ dir = 1 }, /obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ - dir = 1 - }, /obj/machinery/meter, +/obj/machinery/atmospherics/pipe/smart/simple/general/visible{ + dir = 4 + }, /turf/open/floor/iron, /area/station/engineering/atmos) "wNv" = ( @@ -71467,7 +71439,6 @@ dir = 10 }, /obj/effect/decal/cleanable/dirt/dust, -/obj/effect/landmark/start/atmospheric_technician, /turf/open/floor/iron, /area/station/engineering/atmos) "wWR" = ( @@ -75811,10 +75782,10 @@ /area/station/maintenance/starboard/aft) "xXl" = ( /obj/structure/table/reinforced, -/obj/structure/showcase/machinery/microwave{ - pixel_y = 7 - }, /obj/effect/turf_decal/bot, +/obj/machinery/microwave{ + pixel_y = 5 + }, /turf/open/floor/iron/small, /area/station/engineering/break_room) "xXr" = ( @@ -85598,7 +85569,7 @@ dDB dDB dDB jhz -hsL +xQZ kpe dDB dDB @@ -85835,8 +85806,8 @@ tYT dDB dDB jul -blb -blb +oTY +qME dDB dDB tYT @@ -85854,7 +85825,7 @@ tYT tYT dDB dDB -blb +hsL pJT rqV dDB @@ -86092,8 +86063,8 @@ giq wBo vmL apj -vmL -vmL +kwH +nID vmL ybO tYT @@ -86111,10 +86082,10 @@ aJq tYT ybO vmL -vmL +hZf kwH lLE -vmL +dqV ybO aJq aJq @@ -86348,9 +86319,9 @@ drw gvB wBo ybO -mKK -cwf -cwf +brC +brC +brC ybO ybO aJq @@ -86368,10 +86339,10 @@ aJq aJq ybO ybO -cwf -pfx brC -ybO +brC +brC +pfx ybO akZ akZ @@ -86606,8 +86577,8 @@ qBD gKs hXt mXm -hXt -hXt +mXx +vUh bJN hYC pwv @@ -86882,9 +86853,9 @@ tSi vnz hYC dYY -dqV -ivT -hZf +ijP +ulf +gCP nkp kvb gBh @@ -87139,7 +87110,7 @@ bSm qxz mRA hvZ -mXx +xHT fJt vPY wPt @@ -87377,7 +87348,7 @@ vtw gKs mFZ exE -tFB +pjk wWP dlk qUN @@ -87634,8 +87605,8 @@ ihj gKs pIB wNi -bPU -yii +tFB +mKK tnH vcR fxV @@ -87891,8 +87862,8 @@ fEr pUK vjK rVA -vUh -oTY +bPU +yii kXf hvo kQr @@ -88018,7 +87989,7 @@ aJq aJq aJq aJq -pRb +aJq dDB dDB dDB @@ -88275,7 +88246,7 @@ aJq aJq aJq aJq -pRb +aJq aJq aJq aJq @@ -88532,7 +88503,7 @@ aJq aJq aJq aJq -pRb +aJq aJq aJq aJq @@ -107040,7 +107011,7 @@ bUv cSk gLb nlS -mIa +eRX gpM sSQ hrF @@ -108578,7 +108549,7 @@ jrk gIF wYA bpS -jLi +hOp nYk vVP xAA diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 2b35348f40794..bf4f4d9464f2b 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -38677,7 +38677,6 @@ /obj/machinery/power/terminal{ dir = 4 }, -/obj/structure/cable, /obj/structure/sign/warning/electric_shock/directional/north, /turf/open/floor/plating, /area/station/maintenance/department/electrical) @@ -43947,6 +43946,9 @@ pixel_x = 5 }, /obj/machinery/camera/autoname/directional/south, +/obj/item/toy/figure/bitrunner{ + pixel_x = -6 + }, /turf/open/floor/iron/dark/smooth_large, /area/station/cargo/bitrunning/den) "kUn" = ( @@ -51032,7 +51034,6 @@ /obj/effect/turf_decal/trimline/green/filled/line{ dir = 10 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/virology) "mIs" = ( @@ -58192,7 +58193,6 @@ "oDw" = ( /obj/structure/table/glass, /obj/machinery/computer/records/medical/laptop, -/obj/item/toy/figure/virologist, /obj/effect/turf_decal/trimline/green/filled/line{ dir = 1 }, @@ -62743,7 +62743,7 @@ /turf/open/floor/iron, /area/station/science/breakroom) "pKa" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/sign/warning/electric_shock/directional/north, /obj/machinery/camera/directional/north{ c_tag = "AI Chamber - Fore"; @@ -70718,7 +70718,6 @@ /obj/structure/chair/office/light{ dir = 8 }, -/obj/effect/landmark/start/virologist, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 }, @@ -77771,7 +77770,6 @@ /obj/machinery/power/terminal{ dir = 4 }, -/obj/structure/cable, /obj/structure/sign/warning/electric_shock/directional/south, /turf/open/floor/plating, /area/station/maintenance/department/electrical) @@ -91414,7 +91412,6 @@ /area/station/hallway/secondary/entry) "wOz" = ( /obj/structure/chair/office/light, -/obj/effect/landmark/start/virologist, /obj/effect/turf_decal/trimline/green/filled/warning, /turf/open/floor/iron/white, /area/station/medical/virology) diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 8d915ad910e60..e08e300a61a47 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -1,11 +1,4 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aak" = ( -/obj/structure/stairs/south, -/obj/structure/railing{ - dir = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "aap" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /turf/open/floor/iron, @@ -56,6 +49,13 @@ "abe" = ( /turf/open/floor/engine, /area/station/science/xenobiology) +"abm" = ( +/obj/structure/table, +/obj/item/trash/can/food/beans, +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "abv" = ( /obj/effect/turf_decal/loading_area{ dir = 1 @@ -105,33 +105,24 @@ /obj/structure/table/wood, /turf/open/floor/wood, /area/station/maintenance/port/aft) -"acr" = ( -/obj/structure/table/wood, -/obj/effect/spawner/random/entertainment/gambling, -/obj/machinery/newscaster/directional/south, -/obj/machinery/status_display/evac/directional/west, -/turf/open/floor/iron/grimy, -/area/station/commons/lounge) -"acw" = ( -/obj/machinery/camera{ - c_tag = "Starboard Primary Hallway Center East" - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) -"acx" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/structure/chair{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) +"acg" = ( +/obj/effect/mapping_helpers/burnt_floor, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/fore) +"acm" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "acE" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/solars/starboard/fore) +"acG" = ( +/obj/effect/spawner/random/trash/moisture_trap, +/obj/item/reagent_containers/cup/bucket, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "ade" = ( /obj/structure/table/glass, /obj/structure/extinguisher_cabinet/directional/north, @@ -231,6 +222,15 @@ /obj/item/clothing/mask/gas, /turf/open/floor/iron/smooth, /area/mine/living_quarters) +"aeF" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/machinery/light/directional/west, +/obj/structure/sign/poster/official/random/directional/west, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "aeQ" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -266,15 +266,10 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/mining, /turf/open/floor/iron/large, /area/mine/mechbay) -"afv" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/obj/structure/chair{ - dir = 1 - }, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) +"aft" = ( +/obj/machinery/vending/boozeomat, +/turf/open/floor/iron, +/area/station/service/bar) "afz" = ( /obj/effect/spawner/random/structure/crate, /turf/open/floor/plating, @@ -300,15 +295,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/maintenance/starboard/upper) -"aga" = ( -/obj/structure/mirror/directional/west, -/obj/item/toy/mecha/honk{ - pixel_y = 12 - }, -/obj/machinery/light/small/directional/west, -/obj/structure/table/wood, -/turf/open/floor/wood/tile, -/area/station/service/theater) "agk" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -331,13 +317,6 @@ }, /turf/open/floor/iron, /area/station/commons/dorms) -"agt" = ( -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "agF" = ( /obj/structure/rack, /obj/item/storage/box/teargas{ @@ -386,6 +365,12 @@ /obj/machinery/door/firedoor/heavy, /turf/open/floor/iron/dark, /area/station/engineering/atmos/project) +"ahh" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/structure/window/reinforced/spawner/directional/west, +/turf/open/floor/iron, +/area/station/service/bar) "ahm" = ( /obj/machinery/newscaster/directional/west, /obj/machinery/firealarm/directional/south, @@ -404,16 +389,6 @@ /obj/machinery/newscaster/directional/west, /turf/open/floor/iron/smooth, /area/station/security/holding_cell) -"ahI" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "ahK" = ( /obj/effect/landmark/blobstart, /turf/open/floor/plating, @@ -520,6 +495,27 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark/textured, /area/station/security/prison/workout) +"akb" = ( +/obj/structure/closet/crate, +/obj/item/food/canned/beans, +/obj/item/food/canned/beans, +/obj/item/food/canned/beans, +/obj/item/reagent_containers/cup/glass/waterbottle{ + pixel_x = 7; + pixel_y = 6 + }, +/obj/item/reagent_containers/cup/glass/waterbottle{ + pixel_x = 7; + pixel_y = 6 + }, +/obj/item/reagent_containers/cup/glass/waterbottle{ + pixel_x = 7; + pixel_y = 6 + }, +/mob/living/basic/mouse/white, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "akk" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/junction/layer2{ dir = 4 @@ -773,6 +769,22 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/solars/starboard/aft) +"any" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/decal/cleanable/oil, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) +"anI" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/middle{ + dir = 1 + }, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "botany_chasm_and_wolf_shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) "anK" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 4 @@ -806,6 +818,13 @@ /obj/machinery/light/floor, /turf/open/floor/iron, /area/station/command/bridge) +"aoi" = ( +/obj/structure/closet/emcloset, +/obj/machinery/power/apc/auto_name/directional/west, +/obj/structure/cable, +/obj/machinery/light/cold/directional/west, +/turf/open/floor/plating, +/area/station/service/kitchen/coldroom) "aoo" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -834,15 +853,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/commons/dorms) -"aoP" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Canteen" - }, -/turf/open/floor/iron/textured_half{ - dir = 1 - }, -/area/station/service/kitchen/diner) "apb" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -906,6 +916,12 @@ }, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) +"apC" = ( +/obj/effect/turf_decal/tile/neutral/half/contrasted, +/obj/machinery/light/small/directional/south, +/obj/structure/sign/calendar/directional/south, +/turf/open/floor/iron, +/area/station/commons/dorms) "apD" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -968,6 +984,16 @@ }, /turf/open/floor/iron/white, /area/station/medical/virology) +"aqq" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/structure/window/reinforced/spawner/directional/east, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "botany_chasm_and_wolf_shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) "aqB" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -1047,6 +1073,18 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/security/processing) +"arW" = ( +/obj/effect/turf_decal/tile/neutral/diagonal_edge, +/obj/effect/landmark/start/cook, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/holopad, +/turf/open/floor/iron/kitchen/diagonal, +/area/station/service/kitchen) +"arZ" = ( +/obj/effect/turf_decal/tile/blue, +/obj/structure/extinguisher_cabinet/directional/south, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "asa" = ( /obj/structure/table/wood, /obj/item/storage/crayons, @@ -1095,17 +1133,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"asJ" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 4 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/hydroponics) "asM" = ( /obj/machinery/light/directional/east, /obj/effect/turf_decal/tile/yellow/opposingcorners, @@ -1192,11 +1219,6 @@ /obj/effect/landmark/start/depsec/medical, /turf/open/floor/iron/dark/smooth_large, /area/station/security/checkpoint/medical) -"atM" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "atN" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -1245,23 +1267,6 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"aut" = ( -/obj/structure/rack, -/obj/item/clothing/suit/utility/fire/firefighter, -/obj/item/tank/internals/oxygen, -/obj/item/clothing/mask/gas, -/obj/item/extinguisher, -/obj/item/clothing/head/utility/hardhat/red, -/obj/item/clothing/glasses/meson, -/obj/effect/turf_decal/stripes/line{ - dir = 10 - }, -/obj/machinery/atmospherics/components/binary/pump/on/general/visible/layer4{ - dir = 4; - name = "Air In" - }, -/turf/open/floor/plating, -/area/station/maintenance/fore) "auw" = ( /obj/machinery/atmospherics/components/binary/pump/on{ dir = 8; @@ -1294,16 +1299,41 @@ /obj/machinery/portable_atmospherics/scrubber, /turf/open/floor/iron/dark, /area/station/science/ordnance/office) -"auN" = ( -/obj/structure/chair/sofa/corp/right{ - dir = 1 - }, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "avb" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"avd" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Central Access" + }, +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) +"ave" = ( +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "avh" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, @@ -1369,6 +1399,11 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) +"awF" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/grille_or_waste, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "awK" = ( /obj/structure/table, /obj/item/hemostat, @@ -1526,17 +1561,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/engineering/lobby) -"ayk" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/duct, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "ayq" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ cycle_id = "atmos-entrance" @@ -1567,6 +1591,10 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) +"ayJ" = ( +/obj/effect/spawner/random/lavaland_mob/raptor, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "ayR" = ( /obj/machinery/airalarm/directional/east, /obj/structure/extinguisher_cabinet/directional/north, @@ -1577,6 +1605,12 @@ /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/cmo) +"ayY" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 1 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "azf" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -1591,6 +1625,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"azt" = ( +/obj/machinery/door/airlock{ + name = "Unit B" + }, +/turf/open/floor/iron/textured, +/area/station/commons/toilet) "azw" = ( /turf/closed/wall, /area/station/medical/pharmacy) @@ -1616,6 +1656,12 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/engine_equipment, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"azI" = ( +/obj/machinery/vending/autodrobe, +/obj/machinery/airalarm/directional/north, +/obj/machinery/light/small/directional/north, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "azN" = ( /obj/structure/rack, /obj/item/tank/internals/emergency_oxygen{ @@ -1650,16 +1696,6 @@ }, /turf/open/floor/plating, /area/station/science/robotics/lab) -"aAa" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/landmark/event_spawn, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "aAf" = ( /obj/machinery/incident_display/delam, /turf/closed/wall/r_wall, @@ -1680,6 +1716,10 @@ }, /turf/open/floor/circuit/red, /area/station/ai_monitored/turret_protected/ai_upload) +"aAk" = ( +/obj/structure/table/wood, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "aAl" = ( /obj/machinery/computer/mech_bay_power_console{ dir = 1 @@ -1694,6 +1734,28 @@ /obj/effect/turf_decal/tile/blue/half/contrasted, /turf/open/floor/iron, /area/station/command/bridge) +"aAy" = ( +/obj/structure/table/wood/poker, +/obj/effect/spawner/random/entertainment/dice{ + pixel_y = 5; + pixel_x = -4 + }, +/obj/effect/spawner/random/entertainment/money_small, +/turf/open/floor/wood/large, +/area/station/commons/lounge) +"aBb" = ( +/obj/structure/closet/emcloset, +/obj/item/pickaxe, +/obj/machinery/light/small/directional/east, +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/turf/open/floor/iron, +/area/station/service/hydroponics) "aBf" = ( /obj/effect/landmark/start/hangover, /turf/open/floor/engine{ @@ -1714,6 +1776,12 @@ /obj/machinery/light/cold/directional/south, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/cmo) +"aBj" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 9 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "aBR" = ( /turf/open/genturf/blue, /area/icemoon/surface/outdoors/noruins) @@ -1834,6 +1902,15 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/command/bridge) +"aEx" = ( +/obj/structure/closet/lasertag/blue, +/obj/effect/landmark/start/hangover/closet, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/obj/machinery/status_display/ai/directional/north, +/turf/open/floor/iron, +/area/station/commons/fitness) "aEA" = ( /obj/structure/rack, /obj/item/clothing/mask/gas, @@ -1853,6 +1930,16 @@ /obj/structure/extinguisher_cabinet/directional/south, /turf/open/floor/iron/white, /area/station/science/robotics/lab) +"aEK" = ( +/obj/machinery/atmospherics/components/binary/pump/off, +/obj/machinery/airlock_sensor/incinerator_ordmix{ + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden{ + dir = 4 + }, +/turf/open/floor/engine, +/area/station/science/ordnance) "aEM" = ( /obj/structure/sign/departments/cargo, /turf/closed/wall/r_wall, @@ -1874,15 +1961,6 @@ }, /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/ai_upload) -"aEU" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "aFg" = ( /obj/machinery/button/door/directional/east{ id = "lawyer_blast"; @@ -1952,6 +2030,26 @@ }, /turf/open/floor/iron/white, /area/station/science/xenobiology) +"aGf" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) +"aGk" = ( +/obj/structure/rack, +/obj/item/wrench, +/obj/item/crowbar, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/spawner/random/engineering/flashlight, +/turf/open/floor/iron/smooth, +/area/station/maintenance/starboard/lesser) "aGr" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/camera/directional/east{ @@ -1987,6 +2085,13 @@ /obj/effect/mapping_helpers/airlock/access/all/security/brig, /turf/open/floor/iron, /area/mine/laborcamp) +"aHh" = ( +/obj/machinery/light/small/directional/west, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 5 + }, +/turf/open/floor/plating/snowed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "aHz" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/reinforced, @@ -2040,6 +2145,21 @@ dir = 9 }, /area/station/science/explab) +"aIA" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 9 + }, +/obj/effect/turf_decal/trimline/green/filled/corner, +/obj/effect/turf_decal/trimline/blue/filled/warning/corner, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "aIB" = ( /obj/effect/turf_decal/weather/snow/corner{ dir = 4 @@ -2078,10 +2198,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, /area/station/medical/morgue) -"aJh" = ( -/obj/item/kirbyplants/random, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "aJm" = ( /obj/structure/cable, /obj/machinery/door/window/left/directional/east{ @@ -2192,10 +2308,6 @@ /obj/structure/cable, /turf/open/floor/iron/white/textured, /area/station/security/medical) -"aKG" = ( -/obj/structure/table, -/turf/open/floor/iron/smooth, -/area/station/maintenance/starboard/fore) "aKI" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -2204,6 +2316,11 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/hallway/primary/fore) +"aLh" = ( +/obj/structure/fireplace, +/obj/effect/mapping_helpers/burnt_floor, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "aLy" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -2318,6 +2435,12 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"aMI" = ( +/obj/machinery/oven/range, +/obj/effect/turf_decal/siding/white, +/obj/machinery/computer/security/telescreen/entertainment/directional/north, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "aML" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -2328,12 +2451,6 @@ /obj/effect/turf_decal/tile/yellow, /turf/open/floor/iron/white, /area/station/medical/pharmacy) -"aMX" = ( -/obj/machinery/light/small/directional/south, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "aNc" = ( /obj/structure/fence{ dir = 4 @@ -2341,6 +2458,14 @@ /obj/structure/sign/nanotrasen, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) +"aNj" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/commons/fitness) "aNq" = ( /obj/effect/turf_decal/caution/stand_clear, /obj/effect/turf_decal/siding/dark_blue, @@ -2370,11 +2495,6 @@ /obj/machinery/portable_atmospherics/canister/oxygen, /turf/open/floor/plating, /area/mine/eva/lower) -"aNR" = ( -/obj/machinery/smartfridge, -/obj/machinery/door/firedoor, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "aOa" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -2420,20 +2540,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white/textured, /area/station/security/medical) -"aOV" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2{ - color = "#ff0000"; - dir = 8; - name = "Scrubbers multi deck pipe adapter" - }, -/obj/structure/disposalpipe/trunk/multiz/down{ - dir = 8 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "aOX" = ( /turf/open/floor/engine/co2, /area/station/engineering/atmos) @@ -2466,15 +2572,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/engineering/atmos) -"aPo" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/green, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "aPD" = ( /turf/closed/wall/r_wall, /area/station/engineering/storage_shared) @@ -2494,6 +2591,11 @@ /obj/machinery/light/floor, /turf/open/floor/iron/dark/textured, /area/station/security/warden) +"aPP" = ( +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "aPV" = ( /obj/effect/spawner/random/trash/mess, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -2734,14 +2836,22 @@ }, /turf/open/floor/iron, /area/station/engineering/main) -"aTm" = ( -/obj/effect/turf_decal/siding/wood{ +"aTk" = ( +/obj/machinery/door/airlock/hydroponics/glass{ + name = "Apiary" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, +/turf/open/floor/iron/dark/textured_half{ dir = 1 }, -/obj/structure/table/wood, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) +/area/station/service/hydroponics) "aTp" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -2791,16 +2901,6 @@ /obj/effect/turf_decal/tile/yellow/half/contrasted, /turf/open/floor/iron, /area/station/commons/storage/tools) -"aTV" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/light/directional/west, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "aTZ" = ( /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 4 @@ -2841,6 +2941,11 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"aUq" = ( +/obj/structure/flora/bush/fullgrass/style_random, +/obj/structure/flora/bush/generic/style_random, +/turf/open/floor/grass, +/area/station/service/hydroponics) "aUA" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -2885,19 +2990,6 @@ /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible, /turf/closed/wall/r_wall, /area/station/engineering/atmos) -"aUY" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 6 - }, -/obj/structure/chair/sofa/corp/right{ - dir = 4; - pixel_x = -4; - pixel_y = 8 - }, -/obj/machinery/newscaster/directional/west, -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron/grimy, -/area/station/service/bar/atrium) "aVb" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -2966,6 +3058,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/tcommsat/computer) +"aVJ" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/stone, +/area/station/commons/lounge) "aVU" = ( /obj/effect/mapping_helpers/airlock/locked, /obj/machinery/door/airlock/virology{ @@ -3032,10 +3131,6 @@ /obj/machinery/status_display/evac/directional/north, /turf/open/floor/iron/dark, /area/station/tcommsat/computer) -"aWI" = ( -/obj/machinery/light/small/directional/south, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "aWN" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/turf_decal/siding/thinplating_new/corner{ @@ -3043,11 +3138,6 @@ }, /turf/open/floor/iron/large, /area/station/hallway/secondary/entry) -"aWS" = ( -/obj/structure/table, -/obj/item/storage/box/donkpockets/donkpocketberry, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "aWV" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -3074,6 +3164,22 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"aXu" = ( +/obj/structure/chair/sofa/right/brown, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 1 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) +"aXv" = ( +/obj/structure/sign/warning/gas_mask/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) +"aXx" = ( +/obj/item/bedsheet/red, +/mob/living/simple_animal/bot/secbot/beepsky, +/turf/open/floor/plating, +/area/station/maintenance/fore) "aXY" = ( /obj/structure/rack, /obj/item/circuitboard/machine/monkey_recycler, @@ -3104,6 +3210,13 @@ /obj/item/radio/intercom/directional/north, /turf/open/floor/iron, /area/mine/production) +"aYO" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/turf/open/floor/plating, +/area/station/maintenance/fore) "aYQ" = ( /obj/machinery/shower/directional/south, /obj/item/soap/nanotrasen, @@ -3220,18 +3333,6 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"baj" = ( -/obj/machinery/door/airlock/external{ - glass = 1; - name = "Chapel Maintenance External Airlock"; - opacity = 0 - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, -/turf/open/floor/plating, -/area/station/maintenance/department/chapel) "bam" = ( /turf/open/floor/carpet/red, /area/station/commons/vacant_room/office) @@ -3242,14 +3343,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/orange/visible, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"baq" = ( -/obj/machinery/modular_computer/preset/civilian{ - dir = 1 +"bao" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/sign/poster/contraband/random/directional/south, +/obj/structure/closet/emcloset, /turf/open/floor/iron, -/area/station/maintenance/starboard/fore) +/area/station/hallway/primary/starboard) "bar" = ( /obj/effect/turf_decal/tile/blue/opposingcorners{ dir = 1 @@ -3348,6 +3448,12 @@ /obj/effect/turf_decal/tile/red, /turf/open/floor/iron/textured, /area/station/security/brig) +"bcf" = ( +/obj/effect/spawner/random/entertainment/arcade, +/obj/structure/sign/poster/contraband/random/directional/east, +/obj/item/radio/intercom/directional/north, +/turf/open/floor/eighties, +/area/station/commons/lounge) "bcm" = ( /obj/machinery/camera/directional/east{ c_tag = "Security - Lower Brig Cells"; @@ -3360,6 +3466,14 @@ /obj/effect/turf_decal/tile/red, /turf/open/floor/iron/textured, /area/station/security/brig) +"bcu" = ( +/obj/effect/turf_decal/siding/wideplating/dark{ + dir = 1 + }, +/obj/item/seeds/watermelon, +/obj/machinery/hydroponics/soil, +/turf/open/floor/grass, +/area/station/maintenance/starboard/fore) "bcx" = ( /obj/machinery/door/airlock/maintenance{ name = "Quartermaster Office Maintenance" @@ -3474,6 +3588,14 @@ /obj/machinery/status_display/evac/directional/west, /turf/open/floor/wood, /area/station/service/library) +"bdX" = ( +/obj/item/toy/snowball{ + pixel_y = 3; + pixel_x = 3 + }, +/obj/item/toy/snowball, +/turf/open/misc/asteroid/snow/coldroom, +/area/icemoon/underground/explored) "bea" = ( /obj/effect/spawner/structure/window/reinforced/plasma, /turf/open/floor/plating/icemoon, @@ -3491,6 +3613,14 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron, /area/station/hallway/primary/central) +"beF" = ( +/obj/machinery/door/airlock{ + name = "Unisex Showers" + }, +/obj/structure/cable, +/obj/machinery/duct, +/turf/open/floor/iron/textured, +/area/station/commons/toilet) "beO" = ( /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, @@ -3503,11 +3633,6 @@ /obj/structure/sign/painting/large, /turf/open/floor/wood, /area/station/security/prison/rec) -"beT" = ( -/obj/structure/table/glass, -/obj/item/cultivator, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "beZ" = ( /turf/closed/indestructible/riveted{ desc = "A wall impregnated with Fixium, able to withstand massive explosions with ease"; @@ -3533,6 +3658,11 @@ /obj/effect/spawner/structure/window/hollow/reinforced/end, /turf/open/floor/plating, /area/mine/eva/lower) +"bfy" = ( +/obj/effect/spawner/random/trash/bin, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "bfL" = ( /obj/effect/turf_decal/stripes/line{ dir = 5 @@ -3572,20 +3702,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden, /turf/open/floor/iron, /area/station/engineering/atmos/storage/gas) -"bfZ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/red/half{ - dir = 4 - }, -/obj/machinery/light/small/directional/south, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/hallway/secondary/service) -"bgd" = ( -/obj/structure/reagent_dispensers/plumbed, -/turf/open/floor/plating, -/area/station/maintenance/department/medical/morgue) "bgs" = ( /obj/structure/sign/poster/random/directional/east, /obj/structure/cable, @@ -3630,10 +3746,6 @@ }, /turf/open/floor/iron/large, /area/station/command/gateway) -"bgG" = ( -/obj/effect/decal/cleanable/cobweb, -/turf/open/floor/iron, -/area/station/maintenance/starboard/fore) "bgK" = ( /obj/structure/table, /obj/item/toner, @@ -3704,6 +3816,18 @@ }, /turf/open/floor/iron, /area/station/commons/vacant_room/commissary) +"bid" = ( +/obj/effect/turf_decal/siding/wood, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/obj/effect/landmark/navigate_destination/bar, +/obj/machinery/door/airlock/multi_tile/public/glass{ + name = "Atrium" + }, +/turf/open/floor/iron/dark/textured_half, +/area/station/service/bar/atrium) "bie" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle{ dir = 4 @@ -3719,6 +3843,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"bil" = ( +/obj/structure/railing/wooden_fence, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "bin" = ( /obj/effect/turf_decal/stripes/asteroid/line{ dir = 4 @@ -3859,14 +3987,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/chemistry) -"bjZ" = ( -/obj/structure/sink/kitchen/directional/south, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "bkg" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/north, @@ -3904,6 +4024,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/science/explab) +"bkM" = ( +/obj/structure/sign/warning/gas_mask/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/fore) "bkS" = ( /obj/machinery/bci_implanter, /turf/open/floor/iron/white/side{ @@ -4013,13 +4137,10 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/wood, /area/station/service/library) -"bmf" = ( -/obj/effect/turf_decal/tile/blue/diagonal_edge, -/obj/machinery/computer/order_console/cook{ - dir = 1 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +"blX" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/fore) "bml" = ( /obj/structure/table, /obj/item/storage/medkit/regular, @@ -4032,21 +4153,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/central) -"bmw" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) -"bmz" = ( -/obj/machinery/door/firedoor, -/obj/structure/sign/warning/electric_shock/directional/south, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "bmM" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, @@ -4156,16 +4262,42 @@ "bol" = ( /turf/open/floor/iron/dark/textured, /area/station/security/prison) +"bon" = ( +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"bor" = ( +/obj/structure/minecart_rail{ + dir = 4 + }, +/obj/structure/cable, +/obj/structure/holosign/barrier/atmos/sturdy, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/door/poddoor/shutters{ + dir = 4; + id = "minecraft_shutter"; + name = "Cart Shutters" + }, +/turf/open/floor/iron/textured, +/area/station/service/hydroponics) "bos" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/visible{ dir = 5 }, /turf/open/floor/iron/dark, /area/station/engineering/atmos/project) -"boK" = ( -/obj/structure/closet/firecloset, -/turf/open/floor/plating, -/area/station/service/kitchen/coldroom) "boO" = ( /obj/structure/chair/sofa/left/brown{ dir = 8 @@ -4190,16 +4322,23 @@ }, /turf/open/floor/plating, /area/station/maintenance/disposal) -"boV" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 10 +"bpa" = ( +/obj/structure/minecart_rail{ + dir = 4 }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 10 +/obj/structure/cable, +/obj/effect/turf_decal/weather/snow/corner, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 1 }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) +/obj/machinery/light/small/red/directional/north, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) +"bpc" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/grimy, +/area/station/service/theater) "bpd" = ( /obj/machinery/power/smes/engineering, /obj/effect/turf_decal/delivery, @@ -4234,6 +4373,16 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) +"bpv" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "bpD" = ( /obj/machinery/newscaster/directional/south, /obj/structure/closet/firecloset, @@ -4241,11 +4390,6 @@ dir = 8 }, /area/station/science/research) -"bpG" = ( -/obj/effect/turf_decal/tile/blue/diagonal_edge, -/obj/machinery/chem_master/condimaster, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "bpK" = ( /obj/machinery/door/airlock/maintenance, /obj/effect/mapping_helpers/airlock/unres, @@ -4324,18 +4468,10 @@ /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron, /area/station/security/brig/upper) -"bqH" = ( -/obj/effect/turf_decal/trimline/green/filled/corner{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/blue/corner{ - dir = 8 - }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) +"bqX" = ( +/obj/machinery/air_sensor/ordnance_burn_chamber, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "bqY" = ( /obj/structure/closet, /obj/effect/spawner/random/maintenance/two, @@ -4376,6 +4512,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/security/checkpoint/engineering) +"brC" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/structure/chair_flipped{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "brJ" = ( /obj/structure/chair/stool/directional/south, /obj/effect/landmark/event_spawn, @@ -4447,6 +4592,14 @@ }, /turf/open/floor/iron/white, /area/station/medical/break_room) +"bsn" = ( +/obj/machinery/door/airlock{ + name = "Unisex Restrooms" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/textured, +/area/station/commons/toilet) "bst" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 6 @@ -4516,19 +4669,6 @@ dir = 4 }, /area/station/hallway/secondary/entry) -"btp" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/structure/chair{ - dir = 4 - }, -/obj/machinery/camera/directional/north{ - c_tag = "Service Diner North" - }, -/obj/machinery/light/directional/north, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "bts" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, @@ -4613,6 +4753,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/department/electrical) +"bvc" = ( +/obj/structure/minecart_rail{ + dir = 1 + }, +/obj/item/radio/intercom/directional/west{ + frequency = 1453; + name = "Kitchen Intercom" + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "bvd" = ( /obj/machinery/power/terminal, /obj/machinery/light/small/directional/east, @@ -4658,6 +4808,11 @@ /obj/machinery/autolathe, /turf/open/floor/iron, /area/station/cargo/office) +"bvu" = ( +/obj/machinery/light/directional/north, +/obj/structure/extinguisher_cabinet/directional/north, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "bvE" = ( /obj/machinery/computer/monitor{ name = "bridge power monitoring console" @@ -4715,6 +4870,12 @@ /obj/effect/turf_decal/tile/green/full, /turf/open/floor/iron/white/smooth_large, /area/station/medical/virology) +"bwh" = ( +/obj/effect/turf_decal/siding/white/corner{ + dir = 8 + }, +/turf/closed/wall, +/area/station/service/hydroponics) "bwi" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -4739,15 +4900,6 @@ dir = 8 }, /area/station/hallway/secondary/entry) -"bwr" = ( -/obj/machinery/light_switch/directional/east, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) -"bws" = ( -/obj/machinery/light/small/directional/north, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "bwt" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/yellow, @@ -4757,11 +4909,6 @@ /obj/structure/bookcase/random/religion, /turf/open/floor/wood, /area/station/service/library) -"bwL" = ( -/obj/structure/rack, -/obj/effect/spawner/random/maintenance/two, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "bwM" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -4786,10 +4933,6 @@ "bxe" = ( /turf/closed/wall/r_wall, /area/station/maintenance/solars/starboard/fore) -"bxv" = ( -/obj/effect/landmark/blobstart, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "bxJ" = ( /obj/structure/closet/crate, /turf/open/floor/plating, @@ -4838,15 +4981,6 @@ }, /turf/open/floor/iron/dark, /area/station/security/checkpoint/customs/auxiliary) -"byk" = ( -/obj/structure/sign/painting/library{ - pixel_y = 32 - }, -/obj/structure/table, -/obj/machinery/microwave, -/obj/structure/sign/poster/official/random/directional/east, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "byl" = ( /obj/machinery/conveyor{ dir = 4; @@ -4897,6 +5031,11 @@ }, /turf/open/floor/carpet, /area/station/command/heads_quarters/captain) +"byy" = ( +/obj/machinery/newscaster/directional/east, +/obj/machinery/duct, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "byB" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /turf/open/floor/plating/icemoon, @@ -4916,6 +5055,14 @@ /obj/effect/mapping_helpers/mail_sorting/science/robotics, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"byO" = ( +/obj/effect/turf_decal/siding/wood/end{ + dir = 1 + }, +/mob/living/carbon/human/species/monkey/punpun, +/obj/item/kirbyplants/organic/plant11, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "byP" = ( /obj/structure/girder, /turf/open/floor/plating, @@ -4933,22 +5080,6 @@ dir = 4 }, /area/station/hallway/secondary/entry) -"bzn" = ( -/obj/machinery/door/airlock{ - name = "Kitchen Access" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 1; - id = "kitchencounter"; - name = "Kitchen Shutters" - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "bzA" = ( /obj/machinery/vending/coffee, /obj/effect/turf_decal/siding/wood/corner{ @@ -4977,6 +5108,14 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos/storage) +"bzF" = ( +/obj/machinery/status_display/ai/directional/north, +/obj/item/aquarium_kit, +/obj/structure/rack, +/obj/effect/turf_decal/bot, +/obj/effect/turf_decal/siding/dark, +/turf/open/floor/iron/checker, +/area/station/hallway/secondary/service) "bzI" = ( /obj/machinery/bluespace_vendor/directional/west, /obj/effect/turf_decal/tile/blue{ @@ -5005,6 +5144,15 @@ "bzW" = ( /turf/open/floor/engine/plasma, /area/station/engineering/atmos) +"bzX" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "bAa" = ( /obj/structure/disposalpipe/segment{ dir = 10 @@ -5073,6 +5221,18 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) +"bBa" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 9 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 9 + }, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/service/hydroponics) "bBb" = ( /obj/structure/railing{ dir = 4 @@ -5088,6 +5248,24 @@ /obj/machinery/light/floor, /turf/open/floor/iron, /area/station/engineering/lobby) +"bBn" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/multiz/supply/visible/layer4{ + color = "#0000ff"; + dir = 8; + name = "Supply multi deck pipe adapter" + }, +/obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2{ + color = "#ff0000"; + dir = 8; + name = "Scrubbers multi deck pipe adapter" + }, +/obj/structure/cable/multilayer/multiz, +/obj/machinery/airalarm/directional/east, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "bBw" = ( /obj/item/trash/sosjerky, /turf/open/floor/plating, @@ -5354,25 +5532,6 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/iron/white, /area/station/maintenance/aft/greater) -"bEp" = ( -/obj/machinery/camera/directional/north{ - c_tag = "Service Hallway - Lower East" - }, -/obj/machinery/firealarm/directional/north, -/obj/machinery/photocopier, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) -"bEq" = ( -/obj/machinery/door/window/right/directional/north{ - name = "Terrarium"; - req_access = list("hydroponics") - }, -/obj/structure/flora/bush/flowers_yw/style_random, -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/turf/open/floor/grass, -/area/station/service/hydroponics) "bEz" = ( /obj/machinery/door/airlock/command/glass{ name = "Secure EVA Storage" @@ -5448,17 +5607,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) -"bFw" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/structure/table, -/obj/item/pen{ - pixel_x = -5 - }, -/obj/item/paper_bin, -/turf/open/floor/plating, -/area/station/hallway/secondary/service) "bFS" = ( /obj/item/crowbar/red, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -5542,17 +5690,6 @@ /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"bHG" = ( -/obj/structure/railing{ - dir = 4 - }, -/obj/machinery/door/firedoor/border_only{ - dir = 4 - }, -/obj/machinery/airalarm/directional/north, -/obj/machinery/light/small/directional/north, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "bHI" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ @@ -5570,10 +5707,6 @@ /obj/effect/turf_decal/tile/yellow/half/contrasted, /turf/open/floor/iron/white, /area/station/medical/pharmacy) -"bHS" = ( -/obj/structure/chair/stool/directional/north, -/turf/open/floor/plating, -/area/station/maintenance/solars/starboard/fore) "bHZ" = ( /obj/effect/spawner/random/trash/mess, /obj/effect/mapping_helpers/burnt_floor, @@ -5633,6 +5766,15 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/disposal) +"bIq" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/disposalpipe/trunk/multiz/down{ + dir = 8 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "bIt" = ( /obj/structure/rack, /obj/effect/decal/cleanable/cobweb/cobweb2, @@ -5642,17 +5784,6 @@ "bID" = ( /turf/closed/wall/r_wall, /area/station/engineering/lobby) -"bIH" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/chair/sofa/right/brown{ - dir = 1 - }, -/obj/machinery/computer/security/telescreen/entertainment/directional/south, -/obj/machinery/airalarm/directional/east, -/turf/open/floor/iron/grimy, -/area/station/commons/lounge) "bIL" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -5695,11 +5826,6 @@ /obj/machinery/light/small/red/directional/north, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) -"bIW" = ( -/obj/machinery/holopad, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "bJa" = ( /obj/structure/railing{ dir = 4 @@ -5781,17 +5907,6 @@ /obj/item/paper/fluff/ids_for_dummies, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) -"bJA" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/effect/turf_decal/siding/wood, -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/multi_tile/public/glass{ - name = "The Girly Boar" - }, -/turf/open/floor/iron/dark/textured_half, -/area/station/service/bar/atrium) "bJD" = ( /obj/machinery/atmospherics/components/trinary/filter/atmos/n2{ dir = 4 @@ -5885,6 +6000,12 @@ /obj/machinery/power/apc/auto_name/directional/west, /turf/open/floor/iron/dark/textured, /area/station/security/interrogation) +"bLf" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "bLn" = ( /obj/machinery/light/directional/west, /obj/item/radio/intercom/directional/west, @@ -5964,17 +6085,6 @@ }, /turf/open/floor/iron/dark, /area/station/service/chapel) -"bMu" = ( -/obj/machinery/door/airlock{ - name = "Service Hall" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 1 - }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/dark/textured_half, -/area/station/hallway/secondary/service) "bMz" = ( /obj/docking_port/stationary{ dir = 8; @@ -6068,6 +6178,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/showroomfloor, /area/station/security/processing) +"bOh" = ( +/obj/machinery/airalarm/directional/north, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "bOj" = ( /obj/machinery/door/airlock/maintenance, /obj/structure/disposalpipe/segment, @@ -6081,6 +6197,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/construction) +"bOn" = ( +/obj/machinery/camera/directional/east{ + c_tag = "Service - Gambling Lounge" + }, +/obj/machinery/computer/slot_machine{ + name = "two-armed bandit" + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "bOo" = ( /obj/effect/turf_decal/arrows/white{ dir = 4 @@ -6132,21 +6257,24 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/port/fore) +"bOZ" = ( +/obj/effect/spawner/random/structure/musician/piano/random_piano, +/obj/machinery/button/curtain{ + id = "cantena_curtains"; + pixel_x = -30 + }, +/turf/open/floor/wood, +/area/station/commons/lounge) "bPc" = ( /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/maint) -"bPg" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 10 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 10 +"bPk" = ( +/obj/structure/reagent_dispensers/plumbed{ + dir = 4 }, -/obj/machinery/firealarm/directional/west, -/obj/structure/sink/directional/east, -/turf/open/floor/iron, -/area/station/service/hydroponics) +/turf/open/floor/plating, +/area/station/maintenance/department/medical/morgue) "bPn" = ( /obj/structure/girder, /turf/open/floor/plating, @@ -6210,6 +6338,12 @@ /obj/effect/turf_decal/tile/green/full, /turf/open/floor/iron/dark/smooth_large, /area/station/medical/virology) +"bPR" = ( +/obj/structure/railing/wooden_fence{ + dir = 1 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "bPV" = ( /obj/item/kirbyplants/random/dead, /turf/open/floor/plating/snowed/icemoon, @@ -6240,16 +6374,6 @@ dir = 1 }, /area/station/hallway/primary/starboard) -"bQr" = ( -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/machinery/duct, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "bQA" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, @@ -6260,16 +6384,6 @@ }, /turf/open/floor/plating, /area/mine/eva/lower) -"bQP" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/red/full, -/obj/machinery/light/small/directional/east, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "bQS" = ( /obj/machinery/power/apc/auto_name/directional/south, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -6318,6 +6432,19 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/cargo) +"bRx" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/engineering/tracking_beacon, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/landmark/generic_maintenance_landmark, +/obj/effect/landmark/blobstart, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "bRz" = ( /obj/machinery/hydroponics/soil{ pixel_y = 8 @@ -6350,6 +6477,18 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) +"bRO" = ( +/obj/item/reagent_containers/cup/soda_cans/beer{ + pixel_x = -7; + pixel_y = 2 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) +"bSi" = ( +/obj/structure/sign/warning/cold_temp/directional/south, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "bSk" = ( /obj/machinery/door/poddoor/preopen{ id = "Prison Gate"; @@ -6377,6 +6516,15 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"bSC" = ( +/obj/machinery/camera{ + c_tag = "Starboard Primary Hallway Center" + }, +/obj/structure/cable, +/obj/effect/landmark/start/hangover, +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "bSG" = ( /obj/effect/turf_decal/stripes/red/line{ dir = 8 @@ -6393,20 +6541,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) -"bSU" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark/side{ - dir = 1 - }, -/area/station/service/hydroponics) "bSX" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/structure/chair/sofa/right/brown, @@ -6622,6 +6756,13 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/service/chapel) +"bXb" = ( +/obj/effect/decal/cleanable/greenglow, +/obj/effect/decal/cleanable/plastic, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/confetti, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "bXf" = ( /obj/structure/closet/emcloset, /turf/open/floor/plating, @@ -6638,17 +6779,6 @@ }, /turf/open/floor/plating/elevatorshaft, /area/mine/storage) -"bXj" = ( -/obj/machinery/airalarm/directional/west, -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "bXl" = ( /obj/machinery/air_sensor/nitrous_tank, /turf/open/floor/engine/n2o, @@ -6728,6 +6858,10 @@ dir = 8 }, /area/station/service/chapel) +"bYr" = ( +/obj/structure/fence, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "bYu" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -6741,6 +6875,12 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter) +"bYx" = ( +/obj/structure/fence/post{ + dir = 1 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "bYz" = ( /obj/machinery/conveyor{ dir = 8; @@ -6873,11 +7013,34 @@ "bZQ" = ( /turf/closed/wall/r_wall, /area/station/hallway/primary/starboard) +"bZU" = ( +/obj/structure/disposalpipe/sorting/mail/flip{ + dir = 2 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/power/apc/auto_name/directional/west, +/obj/effect/mapping_helpers/mail_sorting/service/dormitories, +/obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ + dir = 1 + }, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/commons/fitness) "bZV" = ( /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"cag" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "caC" = ( /obj/machinery/door/window/right/directional/west{ name = "Monkey Pen"; @@ -6968,15 +7131,6 @@ /obj/machinery/light/floor, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"cbS" = ( -/obj/structure/rack, -/obj/item/wrench, -/obj/item/crowbar, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/iron/smooth, -/area/station/maintenance/starboard/lesser) "ccg" = ( /obj/machinery/light/directional/west, /obj/effect/turf_decal/tile/yellow/opposingcorners, @@ -7117,16 +7271,28 @@ }, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"cdM" = ( -/obj/structure/disposalpipe/segment, +"cdO" = ( +/obj/structure/disposalpipe/sorting/mail/flip{ + dir = 4 + }, +/obj/effect/mapping_helpers/mail_sorting/service/theater, /obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/mapping_helpers/burnt_floor, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) +"cdX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 +/obj/machinery/duct, +/obj/structure/disposalpipe/segment{ + dir = 5 }, -/turf/open/floor/iron, -/area/station/commons/fitness) +/obj/effect/turf_decal/siding/white, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "cef" = ( /obj/machinery/biogenerator, /obj/effect/turf_decal/trimline/green/filled/line{ @@ -7138,6 +7304,10 @@ /obj/structure/grille, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"cem" = ( +/obj/structure/flora/rock/pile/icy/style_random, +/turf/open/misc/asteroid/snow/coldroom, +/area/icemoon/underground/explored) "ceo" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7186,6 +7356,21 @@ /obj/effect/turf_decal/siding/white, /turf/open/floor/iron/smooth, /area/mine/mechbay) +"ceU" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Fitness Maintenance" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/any/security/maintenance, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 1 + }, +/obj/machinery/duct, +/turf/open/floor/plating, +/area/station/maintenance/fore) "ceY" = ( /obj/machinery/door/poddoor/preopen{ id = "Disposal Exit"; @@ -7292,6 +7477,15 @@ }, /turf/open/floor/iron, /area/station/security/prison/mess) +"cgd" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "cge" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/effect/decal/cleanable/dirt, @@ -7318,13 +7512,6 @@ }, /turf/open/floor/iron/dark, /area/station/service/hydroponics/garden) -"cgz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "cgC" = ( /obj/structure/cable, /turf/open/floor/iron, @@ -7354,22 +7541,11 @@ /obj/structure/fence/door, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"chj" = ( -/obj/effect/landmark/event_spawn, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "cht" = ( /obj/machinery/vending/engivend, /obj/machinery/light/small/directional/north, /turf/open/floor/iron/dark, /area/station/engineering/storage_shared) -"chB" = ( -/obj/machinery/door/airlock{ - id_tag = "Toilet1"; - name = "Unit 1" - }, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "chC" = ( /obj/machinery/door/airlock/external{ glass = 1; @@ -7493,20 +7669,15 @@ /obj/effect/spawner/random/trash/cigbutt, /turf/open/floor/iron/dark, /area/station/science/breakroom) -"cjj" = ( -/obj/machinery/holopad, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) -"cjl" = ( +"cjh" = ( +/obj/structure/cable, /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/door/firedoor, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "cjz" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/rack, @@ -7532,13 +7703,6 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/medical/chemistry) -"cjK" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "cjL" = ( /obj/structure/chair/office{ dir = 1 @@ -7570,6 +7734,11 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) +"cki" = ( +/obj/effect/turf_decal/tile/neutral/diagonal_edge, +/obj/structure/cable, +/turf/open/floor/iron/kitchen/diagonal, +/area/station/service/kitchen) "cks" = ( /obj/item/wrench, /obj/effect/turf_decal/delivery, @@ -7698,6 +7867,14 @@ /obj/structure/closet/firecloset, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) +"cmg" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/structure/sink/kitchen/directional/south, +/turf/open/floor/iron, +/area/station/service/hydroponics) "cmq" = ( /obj/machinery/door/airlock/external{ name = "External Access" @@ -7755,6 +7932,17 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) +"cmK" = ( +/obj/structure/table/wood, +/obj/machinery/newscaster/directional/west, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap{ + pixel_y = 3 + }, +/obj/item/storage/photo_album/bar, +/obj/item/toy/figure/bartender, +/turf/open/floor/iron/grimy, +/area/station/service/bar/backroom) "cmL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -7823,11 +8011,6 @@ /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible, /turf/open/floor/plating, /area/station/engineering/atmos) -"cnr" = ( -/obj/machinery/vending/autodrobe, -/obj/structure/sign/poster/contraband/random/directional/west, -/turf/open/floor/wood/tile, -/area/station/service/theater) "cnx" = ( /obj/machinery/power/tracker, /obj/structure/cable, @@ -7853,6 +8036,15 @@ }, /turf/open/floor/iron, /area/station/cargo/office) +"cnS" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/chair/stool/directional/east, +/obj/machinery/light/small/directional/south, +/turf/open/floor/plating, +/area/station/maintenance/fore) "cnU" = ( /obj/machinery/modular_computer/preset/id, /obj/machinery/computer/security/telescreen/vault{ @@ -7863,14 +8055,6 @@ }, /turf/open/floor/iron, /area/station/command/heads_quarters/qm) -"coL" = ( -/obj/structure/reagent_dispensers/water_cooler, -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "coT" = ( /obj/structure/table, /obj/item/storage/wallet, @@ -7955,6 +8139,10 @@ }, /turf/open/floor/plating, /area/station/engineering/engine_smes) +"cpO" = ( +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "cpT" = ( /obj/item/kirbyplants/random, /obj/machinery/status_display/evac/directional/south, @@ -7978,6 +8166,13 @@ }, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"cql" = ( +/obj/effect/turf_decal/tile/bar{ + dir = 4 + }, +/obj/structure/chair/stool/directional/north, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "cqo" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7988,6 +8183,13 @@ }, /turf/open/floor/iron, /area/station/engineering/main) +"cqs" = ( +/obj/item/toy/snowball{ + pixel_y = -7; + pixel_x = 5 + }, +/turf/open/misc/asteroid/snow/coldroom, +/area/station/service/kitchen/coldroom) "cqv" = ( /obj/effect/landmark/blobstart, /obj/machinery/camera{ @@ -8054,6 +8256,13 @@ /obj/effect/mapping_helpers/requests_console/information, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) +"crO" = ( +/obj/effect/turf_decal/siding/wood, +/obj/structure/railing/corner/end/flip{ + dir = 1 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "crS" = ( /obj/machinery/vending/wardrobe/law_wardrobe, /turf/open/floor/wood, @@ -8079,13 +8288,6 @@ /obj/effect/spawner/random/clothing/bowler_or_that, /turf/open/floor/iron/white, /area/station/maintenance/port/fore) -"csg" = ( -/obj/structure/table/wood/poker, -/obj/item/toy/cards/deck{ - pixel_y = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "csm" = ( /obj/machinery/door/airlock/external{ name = "External Access" @@ -8094,6 +8296,13 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/external, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"css" = ( +/obj/structure/table/wood, +/obj/structure/reagent_dispensers/beerkeg, +/obj/machinery/power/apc/auto_name/directional/west, +/obj/structure/cable, +/turf/open/floor/iron/grimy, +/area/station/service/bar/backroom) "csB" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -8104,13 +8313,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/port/aft) -"csR" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/hydroponics) "csT" = ( /turf/open/floor/circuit/telecomms/mainframe, /area/station/tcommsat/server) @@ -8123,6 +8325,17 @@ }, /turf/open/floor/iron/dark, /area/station/medical/morgue) +"csZ" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/machinery/light/small/directional/north, +/obj/structure/extinguisher_cabinet/directional/north, +/turf/open/floor/iron/grimy, +/area/station/service/bar/backroom) "ctk" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -8226,6 +8439,10 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/wood, /area/station/commons/vacant_room/office) +"cuB" = ( +/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/ordnance_burn_chamber_input, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "cuJ" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -8279,14 +8496,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"cvz" = ( -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/effect/landmark/event_spawn, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "cvB" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/firealarm/directional/west, @@ -8332,12 +8541,6 @@ "cvS" = ( /turf/closed/wall, /area/station/maintenance/department/medical/central) -"cwd" = ( -/obj/machinery/disposal/bin, -/obj/machinery/light/small/directional/west, -/obj/structure/disposalpipe/trunk, -/turf/open/floor/iron, -/area/station/service/theater) "cwe" = ( /obj/effect/turf_decal/tile/yellow, /turf/open/floor/iron, @@ -8437,6 +8640,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"cxD" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "cxO" = ( /turf/open/floor/iron/dark/textured, /area/station/ai_monitored/security/armory) @@ -8461,6 +8675,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply, /turf/open/floor/iron/white, /area/station/medical/virology) +"cxT" = ( +/obj/structure/table/wood, +/obj/item/plate, +/obj/effect/spawner/random/trash/bacteria, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "cyh" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/reinforced, @@ -8564,15 +8784,16 @@ /obj/machinery/modular_computer/preset/cargochat/engineering, /turf/open/floor/iron/dark, /area/station/engineering/lobby) -"czm" = ( -/obj/structure/cable, +"czo" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ + dir = 8 + }, +/obj/structure/sign/poster/official/help_others/directional/south, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) +/turf/open/floor/iron, +/area/station/commons/fitness) "czq" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 @@ -8782,21 +9003,11 @@ /obj/machinery/status_display/evac/directional/north, /turf/open/floor/iron/dark, /area/station/medical/chemistry) -"cBj" = ( -/obj/structure/closet/emcloset, -/obj/item/clothing/head/costume/festive, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) "cBn" = ( /obj/structure/sign/poster/random/directional/north, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"cBC" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) "cBD" = ( /obj/effect/turf_decal/siding/wood/corner{ dir = 4 @@ -8813,15 +9024,10 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/station/security/prison/workout) -"cBL" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/machinery/vending/coffee, -/obj/machinery/computer/security/telescreen/entertainment/directional/south, -/obj/machinery/status_display/evac/directional/west, -/turf/open/floor/stone, -/area/station/commons/lounge) +"cBJ" = ( +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "cBP" = ( /obj/structure/table/wood, /obj/item/flashlight/lamp{ @@ -8853,6 +9059,14 @@ /obj/structure/flora/tree/pine/style_random, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"cCe" = ( +/obj/structure/window/reinforced/spawner/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/commons/fitness) "cCt" = ( /obj/structure/rack, /obj/effect/spawner/random/techstorage/rnd_all, @@ -8892,6 +9106,22 @@ }, /turf/open/floor/iron/dark, /area/mine/laborcamp) +"cCR" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) +"cCT" = ( +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning/corner{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "cCW" = ( /obj/machinery/conveyor/inverted{ dir = 6; @@ -9113,6 +9343,22 @@ "cGA" = ( /turf/open/floor/plating, /area/station/maintenance/department/medical/central) +"cGI" = ( +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/obj/machinery/door/airlock{ + name = "Kitchen" + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/service/kitchen) "cGQ" = ( /obj/structure/sign/poster/official/random/directional/west, /obj/effect/turf_decal/tile/green/anticorner/contrasted{ @@ -9120,11 +9366,6 @@ }, /turf/open/floor/iron, /area/station/security/prison/garden) -"cGZ" = ( -/obj/machinery/airalarm/directional/north, -/obj/machinery/light/small/directional/east, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "cHb" = ( /obj/structure/cable, /turf/open/floor/iron, @@ -9158,17 +9399,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/port/greater) -"cHy" = ( -/obj/structure/cable, -/obj/structure/railing, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "cHB" = ( /obj/machinery/vending/autodrobe, /turf/open/floor/plating, @@ -9189,20 +9419,6 @@ }, /turf/open/floor/iron/white, /area/station/science/robotics/lab) -"cHR" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2{ - color = "#ff0000"; - dir = 8; - name = "Scrubbers multi deck pipe adapter" - }, -/obj/structure/disposalpipe/trunk/multiz{ - dir = 8 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "cHY" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -9222,15 +9438,6 @@ "cIc" = ( /turf/closed/wall, /area/station/security/prison/work) -"cId" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/structure/sign/painting/library{ - pixel_y = 32 - }, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "cIq" = ( /obj/machinery/computer/slot_machine{ balance = 15; @@ -9332,11 +9539,14 @@ dir = 6 }, /area/station/science/research) -"cKn" = ( -/obj/effect/mapping_helpers/broken_floor, -/mob/living/simple_animal/bot/secbot/beepsky, -/turf/open/floor/plating, -/area/station/maintenance/fore) +"cKp" = ( +/obj/effect/turf_decal/siding/wood, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/dark/textured_half, +/area/station/service/bar/atrium) "cKq" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -9378,6 +9588,16 @@ /obj/structure/bookcase/random/reference, /turf/open/floor/carpet/blue, /area/station/medical/psychology) +"cKJ" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/obj/effect/turf_decal/siding/dark{ + dir = 9 + }, +/turf/open/floor/iron/checker, +/area/station/hallway/secondary/service) "cLf" = ( /obj/effect/decal/cleanable/blood/bubblegum, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -9485,16 +9705,6 @@ "cMk" = ( /turf/closed/wall/r_wall, /area/mine/production) -"cMs" = ( -/obj/effect/turf_decal/tile/blue/diagonal_edge, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/machinery/light/directional/south, -/obj/structure/disposalpipe/trunk{ - dir = 1 - }, -/obj/machinery/disposal/bin, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "cMv" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/public/glass{ @@ -9565,16 +9775,6 @@ /obj/effect/spawner/structure/window/hollow/reinforced/middle, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) -"cNd" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Central Access" - }, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "cNh" = ( /obj/structure/fence/corner{ dir = 10 @@ -9596,15 +9796,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/wood, /area/station/service/lawoffice) -"cND" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "cNI" = ( /obj/machinery/door/poddoor/preopen{ id = "xenobio7"; @@ -9617,6 +9808,26 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/engine, /area/station/science/xenobiology) +"cNL" = ( +/obj/machinery/airalarm/directional/south, +/obj/effect/turf_decal/siding/thinplating/dark/corner{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 6 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "cNS" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/public/glass{ @@ -9668,6 +9879,17 @@ }, /turf/open/floor/iron, /area/station/command/bridge) +"cOQ" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/door/airlock/engineering{ + name = "Utilities Room" + }, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/unres, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "cPd" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -9755,6 +9977,13 @@ }, /turf/open/floor/plating, /area/station/maintenance/disposal) +"cQp" = ( +/obj/machinery/status_display/evac/directional/north, +/obj/machinery/rnd/production/techfab/department/service, +/obj/effect/turf_decal/bot, +/obj/effect/turf_decal/siding/dark, +/turf/open/floor/iron/checker, +/area/station/hallway/secondary/service) "cQs" = ( /obj/structure/table, /obj/item/computer_disk{ @@ -9766,11 +9995,6 @@ }, /turf/open/floor/iron/dark, /area/station/science/ordnance/office) -"cQv" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "cQw" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/brown{ @@ -9803,6 +10027,13 @@ dir = 8 }, /area/station/ai_monitored/command/storage/eva) +"cQE" = ( +/obj/structure/fence, +/obj/structure/sign/nanotrasen{ + pixel_y = -32 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/nospawn) "cQH" = ( /obj/structure/sign/warning/no_smoking/directional/south, /turf/open/floor/circuit/telecomms/mainframe, @@ -9814,6 +10045,17 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/atmos) +"cQV" = ( +/obj/structure/barricade/wooden/snowed, +/obj/machinery/light/small/red/directional/north, +/obj/machinery/door/poddoor/shutters{ + dir = 4; + id = "minecraft_shutter"; + name = "Cart Shutters"; + pixel_y = 0 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) "cRg" = ( /obj/structure/cable, /turf/open/floor/iron/dark/textured, @@ -9860,22 +10102,6 @@ /obj/machinery/processor, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"cSc" = ( -/obj/structure/flora/bush/flowers_pp/style_random, -/obj/structure/closet/crate{ - name = "Le Caisee D'abeille" - }, -/obj/item/honey_frame, -/obj/item/honey_frame, -/obj/item/honey_frame, -/obj/item/clothing/suit/utility/beekeeper_suit, -/obj/item/clothing/suit/hooded/bee_costume, -/obj/item/clothing/head/utility/beekeeper_head, -/obj/item/clothing/head/hooded/bee_hood, -/obj/item/melee/flyswatter, -/obj/item/queen_bee/bought, -/turf/open/floor/grass, -/area/station/service/hydroponics) "cSe" = ( /obj/structure/table, /obj/item/flashlight{ @@ -9893,13 +10119,6 @@ initial_gas_mix = "ICEMOON_ATMOS" }, /area/icemoon/underground/explored) -"cSu" = ( -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/effect/landmark/start/hangover, -/turf/open/floor/carpet, -/area/station/service/theater) "cSw" = ( /obj/structure/cable, /turf/open/floor/iron, @@ -9922,6 +10141,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"cSO" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "cSP" = ( /obj/machinery/camera/directional/east{ c_tag = "Aft Primary Hallway South"; @@ -9931,13 +10157,6 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron, /area/station/hallway/primary/aft) -"cSQ" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "cTh" = ( /obj/structure/table/wood, /obj/item/paper_bin, @@ -10003,18 +10222,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/port/greater) -"cUt" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/obj/machinery/door/airlock/maintenance, -/obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 8 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "cUF" = ( /obj/machinery/camera/directional/west{ c_tag = "Aft Primary Hallway North" @@ -10025,6 +10232,11 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron, /area/station/hallway/primary/aft) +"cUH" = ( +/obj/structure/cable, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/commons/dorms) "cVa" = ( /obj/machinery/camera/directional/north{ c_tag = "Fitness Room North" @@ -10065,6 +10277,14 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/laborcamp) +"cVW" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/light_switch/directional/south{ + pixel_x = 5 + }, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "cWq" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/turf_decal/tile/green/half/contrasted{ @@ -10072,6 +10292,15 @@ }, /turf/open/floor/iron, /area/station/security/prison/garden) +"cWz" = ( +/obj/structure/window/reinforced/spawner/directional/east, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/effect/turf_decal/siding/white{ + dir = 5 + }, +/turf/open/floor/iron/dark, +/area/station/commons/fitness) "cWG" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -10138,15 +10367,6 @@ dir = 1 }, /area/station/security/prison/garden) -"cXN" = ( -/obj/machinery/camera/directional/south{ - c_tag = "Fitness Room South" - }, -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "cXV" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/trimline/dark_red/filled/line{ @@ -10174,6 +10394,13 @@ /obj/machinery/newscaster/directional/north, /turf/open/floor/iron/grimy, /area/station/security/detectives_office) +"cYe" = ( +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "cYf" = ( /obj/machinery/shower/directional/west, /obj/effect/turf_decal/stripes/red/line{ @@ -10378,6 +10605,13 @@ /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"day" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/commons/fitness) "daE" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/cafeteria, @@ -10417,10 +10651,6 @@ /obj/structure/marker_beacon/jade, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"dbb" = ( -/obj/structure/reagent_dispensers/cooking_oil, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "dbi" = ( /obj/structure/table, /obj/item/flashlight, @@ -10457,10 +10687,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/science/robotics/mechbay) -"dby" = ( -/obj/item/radio/intercom/directional/east, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "dbH" = ( /turf/closed/wall/r_wall, /area/station/security/prison/mess) @@ -10626,6 +10852,13 @@ }, /turf/open/floor/iron/white, /area/station/medical/treatment_center) +"ddv" = ( +/obj/machinery/light/small/directional/east, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 10 + }, +/turf/open/floor/plating/snowed/icemoon, +/area/icemoon/underground/explored) "ddz" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -10638,6 +10871,25 @@ }, /turf/open/floor/plating, /area/station/maintenance/aft/greater) +"ddJ" = ( +/obj/structure/reagent_dispensers/plumbed{ + name = "service reservoir" + }, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/effect/turf_decal/delivery/white{ + color = "#307db9" + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/iron/textured, +/area/station/maintenance/starboard/fore) +"ddR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "ddZ" = ( /obj/structure/cable, /obj/effect/turf_decal/siding/green{ @@ -10749,6 +11001,12 @@ }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) +"dge" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/railing/corner/end/flip, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "dgl" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 8 @@ -10843,6 +11101,11 @@ }, /turf/open/floor/iron, /area/station/cargo/miningdock) +"dig" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/duct, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "dip" = ( /obj/machinery/holopad, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -10883,20 +11146,21 @@ "diC" = ( /turf/open/floor/iron/dark/textured, /area/station/ai_monitored/security/armory/upper) -"diH" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "diI" = ( /obj/machinery/mech_bay_recharge_port, /obj/item/radio/intercom/directional/south, /turf/open/floor/iron/textured, /area/mine/mechbay) +"diK" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "diL" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -10916,6 +11180,12 @@ dir = 1 }, /area/mine/living_quarters) +"djl" = ( +/obj/structure/chair/sofa/left/brown{ + dir = 1 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "djr" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -11023,11 +11293,6 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"dkO" = ( -/obj/effect/landmark/start/hangover, -/obj/structure/chair/stool/directional/north, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "dkT" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle{ dir = 1 @@ -11047,6 +11312,19 @@ dir = 8 }, /area/station/security/brig/entrance) +"dla" = ( +/obj/machinery/door/airlock/external{ + glass = 1; + name = "Service External Airlock"; + opacity = 0 + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "dlt" = ( /obj/effect/turf_decal/weather/snow/corner{ dir = 8 @@ -11054,6 +11332,9 @@ /obj/structure/marker_beacon/burgundy, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"dlu" = ( +/turf/closed/wall/mineral/wood/nonmetal, +/area/icemoon/surface) "dlB" = ( /obj/structure/table/wood, /obj/item/storage/photo_album/chapel, @@ -11113,12 +11394,6 @@ /obj/structure/ladder, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"dmD" = ( -/obj/structure/closet/secure_closet/bar, -/obj/machinery/firealarm/directional/north, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "dmG" = ( /obj/structure/table/wood, /obj/item/camera, @@ -11130,9 +11405,8 @@ /turf/open/floor/iron/white/smooth_large, /area/station/medical/pharmacy) "dmL" = ( -/obj/structure/cable, -/obj/effect/decal/cleanable/dirt, /obj/machinery/light_switch/directional/south, +/obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/maintenance/department/electrical) "dmR" = ( @@ -11241,9 +11515,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) -"doJ" = ( -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "doK" = ( /obj/machinery/button/door/directional/east{ id = "xenobio8"; @@ -11273,6 +11544,23 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) +"dpa" = ( +/obj/structure/table, +/obj/effect/turf_decal/siding/white{ + dir = 5 + }, +/obj/item/reagent_containers/condiment/enzyme{ + pixel_x = -7; + pixel_y = 6 + }, +/obj/item/reagent_containers/condiment/saltshaker{ + pixel_x = -3 + }, +/obj/item/reagent_containers/condiment/peppermill{ + pixel_x = 3 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "dpc" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/command/glass{ @@ -11286,10 +11574,22 @@ /obj/structure/cable, /turf/open/floor/iron/dark/textured, /area/station/ai_monitored/command/storage/eva) +"dpj" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "dpq" = ( /obj/structure/tank_holder/extinguisher, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"dpw" = ( +/obj/structure/table/wood, +/obj/effect/spawner/random/food_or_drink/snack, +/obj/effect/spawner/random/trash/food_packaging, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "dpx" = ( /obj/effect/spawner/random/maintenance, /obj/structure/disposalpipe/segment, @@ -11338,18 +11638,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/port/greater) -"dqd" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/red/half{ - dir = 4 - }, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/hallway/secondary/service) "dqg" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/warning/secure_area/directional/south, @@ -11361,10 +11649,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/hallway/primary/central) -"dqv" = ( -/obj/item/bedsheet/red, -/turf/open/floor/plating, -/area/station/maintenance/fore) "dqw" = ( /obj/machinery/holopad, /turf/open/floor/iron, @@ -11373,6 +11657,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/laborcamp) +"dqA" = ( +/obj/structure/fence/corner{ + dir = 5 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "dqL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, @@ -11422,11 +11712,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/cargo/lobby) -"dre" = ( -/obj/structure/closet, -/obj/effect/spawner/random/maintenance/two, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "drh" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 @@ -11452,6 +11737,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/commons/dorms) +"drw" = ( +/turf/closed/wall/ice, +/area/station/service/kitchen/coldroom) "dry" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -11572,12 +11860,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"dsO" = ( -/obj/structure/railing/corner{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "dsR" = ( /obj/machinery/conveyor/inverted{ dir = 10; @@ -11630,6 +11912,11 @@ /obj/structure/bookcase/random/reference, /turf/open/floor/wood, /area/station/service/library) +"dtc" = ( +/obj/structure/table/wood/poker, +/obj/item/storage/dice, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "dth" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/engineering/glass{ @@ -11670,14 +11957,6 @@ "duh" = ( /turf/closed/wall/r_wall, /area/station/engineering/transit_tube) -"duq" = ( -/obj/structure/chair/sofa/bench/left{ - dir = 4 - }, -/obj/structure/sign/warning/electric_shock/directional/west, -/obj/machinery/light/small/directional/north, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) "duE" = ( /obj/machinery/atmospherics/components/binary/tank_compressor{ dir = 4 @@ -11707,15 +11986,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/mine/laborcamp) -"duV" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 9 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 9 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "duZ" = ( /obj/machinery/door/airlock/engineering{ name = "Utilities Closet" @@ -11786,6 +12056,22 @@ /obj/structure/flora/tree/dead/style_random, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"dvZ" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/machinery/door/airlock/maintenance{ + name = "Bar Maintenance" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/commons/lounge) "dwb" = ( /obj/effect/turf_decal/tile/blue{ dir = 1 @@ -11801,6 +12087,12 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/openspace/icemoon/keep_below, /area/station/maintenance/port/lesser) +"dwq" = ( +/obj/structure/grille/broken, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "dww" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -11941,15 +12233,11 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/security/courtroom) -"dyw" = ( +"dym" = ( /obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, +/obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) +/area/station/maintenance/fore) "dyE" = ( /obj/structure/chair/pew/right{ dir = 1 @@ -12013,16 +12301,21 @@ }, /turf/open/floor/iron/smooth, /area/station/security/execution/transfer) -"dzx" = ( -/obj/structure/closet/emcloset, -/turf/open/floor/plating, -/area/station/maintenance/fore) "dzy" = ( /obj/effect/turf_decal/tile/neutral{ dir = 4 }, /turf/open/floor/iron/dark, /area/station/service/chapel) +"dzD" = ( +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 1 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "dzJ" = ( /obj/effect/turf_decal/stripes/line{ dir = 6 @@ -12136,6 +12429,26 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/mine/laborcamp/security) +"dBA" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Central Access" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/starboard) "dBB" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/effect/turf_decal/bot_white, @@ -12178,19 +12491,6 @@ "dBZ" = ( /turf/open/floor/iron, /area/station/cargo/sorting) -"dCk" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/duct, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "dCs" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -12204,19 +12504,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/engineering/supermatter/room) -"dCA" = ( -/obj/structure/closet/crate, -/obj/effect/spawner/random/maintenance/two, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "dCF" = ( /obj/effect/landmark/start/hangover, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/commons/fitness) +"dCV" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/wood/parquet, +/area/station/service/bar/backroom) "dDm" = ( /obj/machinery/atmospherics/components/unary/outlet_injector/on{ dir = 1 @@ -12284,6 +12582,18 @@ /obj/effect/spawner/random/structure/girder, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"dEc" = ( +/obj/structure/table/wood, +/obj/item/soap/nanotrasen, +/obj/item/clothing/head/costume/sombrero/green, +/obj/machinery/camera{ + c_tag = "Service - Theater"; + dir = 9 + }, +/obj/machinery/status_display/ai/directional/north, +/obj/effect/turf_decal/siding/wood, +/turf/open/floor/iron/grimy, +/area/station/commons/lounge) "dEf" = ( /obj/effect/turf_decal/trimline/blue/corner{ dir = 1 @@ -12318,15 +12628,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet, /area/station/security/prison/rec) -"dEB" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "dEC" = ( /obj/machinery/door/firedoor/heavy, /obj/machinery/door/poddoor/shutters/preopen{ @@ -12461,10 +12762,6 @@ /obj/machinery/light/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"dFP" = ( -/obj/structure/sink/directional/east, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "dFW" = ( /turf/open/floor/iron/white/side, /area/station/science/research) @@ -12508,6 +12805,19 @@ /obj/effect/mapping_helpers/airlock/access/all/command/captain, /turf/open/floor/plating, /area/station/maintenance/central/lesser) +"dGZ" = ( +/obj/machinery/door/airlock/external{ + glass = 1; + name = "Chapel Maintenance External Airlock"; + opacity = 0 + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/maintenance/department/chapel) "dHa" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 8 @@ -12561,30 +12871,6 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"dIc" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 10 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 10 - }, -/obj/machinery/hydroponics/constructable, -/obj/machinery/light/directional/south, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) -"dIe" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/door/airlock{ - name = "Service Hall" - }, -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/obj/effect/mapping_helpers/airlock/unres, -/turf/open/floor/plastic, -/area/station/hallway/secondary/service) "dIl" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 4 @@ -12592,14 +12878,6 @@ /obj/effect/turf_decal/bot_red, /turf/open/floor/iron/dark, /area/station/engineering/atmos/project) -"dIn" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/segment, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "dIx" = ( /obj/effect/spawner/random/structure/grille, /turf/open/floor/plating, @@ -12640,12 +12918,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply, /turf/open/floor/iron/dark, /area/station/medical/virology) -"dJk" = ( -/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_ordmix{ - dir = 8 - }, -/turf/open/floor/engine, -/area/station/science/ordnance/burnchamber) "dJx" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/reinforced, @@ -12662,6 +12934,18 @@ /obj/machinery/air_sensor/ordnance_freezer_chamber, /turf/open/floor/iron/dark/airless, /area/station/science/ordnance/freezerchamber) +"dJF" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "dJY" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -12688,6 +12972,16 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/plating, /area/station/cargo/sorting) +"dKf" = ( +/obj/machinery/camera/directional/south{ + c_tag = "Starboard Primary Hallway Center West" + }, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/item/radio/intercom/directional/south, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "dKh" = ( /obj/machinery/light_switch/directional/east, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -12696,17 +12990,6 @@ /obj/effect/turf_decal/tile/yellow, /turf/open/floor/iron, /area/station/tcommsat/computer) -"dKt" = ( -/obj/machinery/door/airlock/external, -/obj/effect/turf_decal/weather/snow/corner{ - dir = 8 - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "chem-morgue-airlock" - }, -/obj/effect/mapping_helpers/airlock/access/any/medical/maintenance, -/turf/open/floor/plating, -/area/station/medical/morgue) "dKy" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -12818,13 +13101,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) -"dMq" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "dMv" = ( /obj/item/clothing/gloves/color/rainbow, /obj/item/clothing/head/soft/rainbow, @@ -12861,9 +13137,6 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"dMS" = ( -/turf/closed/wall, -/area/station/maintenance/department/crew_quarters/bar) "dMX" = ( /obj/structure/chair{ dir = 1; @@ -12871,6 +13144,10 @@ }, /turf/open/floor/iron, /area/station/command/bridge) +"dNk" = ( +/obj/effect/landmark/event_spawn, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "dNl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/siding/thinplating{ @@ -12936,22 +13213,6 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) -"dNZ" = ( -/obj/structure/training_machine, -/obj/item/target, -/obj/effect/turf_decal/tile/red/half/contrasted{ - dir = 4 - }, -/obj/machinery/light/directional/south, -/turf/open/floor/iron, -/area/station/commons/fitness) -"dOc" = ( -/obj/machinery/door/airlock/external, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/turf/open/floor/plating, -/area/station/maintenance/fore) "dOq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -12978,15 +13239,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"dOQ" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/structure/table/wood, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/mob/living/carbon/human/species/monkey/punpun, -/turf/open/floor/iron, -/area/station/service/bar) "dOY" = ( /obj/effect/spawner/random/vending/snackvend, /obj/effect/turf_decal/tile/red/half, @@ -13051,6 +13303,13 @@ }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) +"dQp" = ( +/obj/structure/table/wood, +/obj/item/food/pie/cream, +/obj/item/bikehorn, +/obj/machinery/status_display/evac/directional/west, +/turf/open/floor/iron/grimy, +/area/station/service/theater) "dQI" = ( /obj/effect/landmark/start/assistant, /obj/effect/turf_decal/tile/neutral/half/contrasted{ @@ -13141,6 +13400,14 @@ }, /turf/open/floor/iron/white, /area/station/security/prison/safe) +"dSs" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/structure/chair/stool/bar/directional/east, +/obj/structure/disposalpipe/segment, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "dSJ" = ( /obj/machinery/flasher/directional/north{ id = "visitorflash" @@ -13165,6 +13432,14 @@ /obj/effect/spawner/random/structure/crate, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) +"dSY" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "dTm" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/effect/mob_spawn/corpse/human/skeleton, @@ -13185,21 +13460,13 @@ "dTs" = ( /turf/open/floor/iron/smooth, /area/mine/eva) -"dTv" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/external{ - glass = 1; - name = "Chapel External Airlock"; - opacity = 0 - }, -/obj/structure/sign/warning/cold_temp/directional/north, -/obj/structure/sign/warning/gas_mask/directional/south{ - desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." +"dTx" = ( +/obj/machinery/status_display/ai/directional/south, +/obj/structure/chair/sofa/right/brown{ + dir = 4 }, -/turf/open/floor/iron, -/area/station/service/chapel) +/turf/open/floor/wood/large, +/area/station/commons/lounge) "dTD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment, @@ -13307,6 +13574,16 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) +"dVj" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 10 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 10 + }, +/obj/machinery/hydroponics/constructable, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "dVq" = ( /obj/machinery/space_heater, /obj/structure/sign/poster/random/directional/east, @@ -13427,14 +13704,6 @@ /obj/machinery/light/directional/north, /turf/open/floor/iron/dark, /area/station/command/gateway) -"dXA" = ( -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark/side{ - dir = 1 - }, -/area/station/service/hydroponics) "dXF" = ( /obj/structure/disposalpipe/segment{ dir = 10 @@ -13451,6 +13720,13 @@ /obj/item/radio/intercom/directional/east, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"dXR" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "dXU" = ( /obj/effect/decal/cleanable/generic, /obj/machinery/light/small/directional/south, @@ -13499,10 +13775,6 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos/storage) -"dYO" = ( -/obj/structure/rack, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "dYP" = ( /obj/item/toy/snowball{ pixel_x = -11; @@ -13532,17 +13804,36 @@ dir = 8 }, /area/mine/eva) -"dZB" = ( +"dZC" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/commons/fitness) +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "dZJ" = ( /obj/machinery/seed_extractor, /obj/machinery/status_display/evac/directional/north, /turf/open/floor/iron/dark, /area/station/service/hydroponics/garden) +"dZL" = ( +/obj/item/radio/intercom/directional/south, +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/green/filled/line, +/obj/effect/turf_decal/trimline/blue/filled/warning, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "dZN" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -13624,6 +13915,20 @@ /obj/structure/cable, /turf/open/floor/carpet/red, /area/station/security/prison/work) +"eav" = ( +/obj/machinery/door/airlock/hydroponics/glass{ + name = "Hydroponics" + }, +/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wood, +/turf/open/floor/iron/dark/textured_half, +/area/station/service/hydroponics) "eaw" = ( /obj/effect/spawner/random/contraband/prison, /obj/structure/closet/crate, @@ -13634,15 +13939,9 @@ /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/iron/dark/smooth_half, /area/station/security/prison/work) -"eaB" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +"eaM" = ( +/turf/open/misc/asteroid/snow/coldroom, +/area/station/service/kitchen/coldroom) "ebb" = ( /obj/structure/extinguisher_cabinet/directional/north, /turf/open/floor/iron, @@ -13651,11 +13950,6 @@ /obj/structure/flora/rock/pile/icy/style_random, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"ebq" = ( -/obj/effect/landmark/start/clown, -/obj/structure/disposalpipe/segment, -/turf/open/floor/carpet, -/area/station/service/theater) "ebr" = ( /turf/open/openspace, /area/station/engineering/atmos/storage) @@ -13691,15 +13985,6 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"ece" = ( -/obj/machinery/airalarm/directional/east, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark/side{ - dir = 1 - }, -/area/station/service/hydroponics) "ecs" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -13735,11 +14020,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"ecZ" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/closet/secure_closet/freezer/kitchen, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "edd" = ( /obj/machinery/door/airlock/maintenance, /obj/structure/cable, @@ -13773,25 +14053,41 @@ }, /turf/open/floor/iron, /area/station/science/robotics/mechbay) -"edD" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 +"edt" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible/layer4, +/obj/effect/turf_decal/stripes/line{ + dir = 5 }, -/obj/machinery/vending/cigarette, -/obj/machinery/camera{ - c_tag = "Service Bar South"; - dir = 9 +/obj/structure/rack, +/obj/item/tank/internals/oxygen, +/obj/item/extinguisher, +/obj/item/clothing/suit/utility/fire/firefighter, +/obj/item/clothing/head/utility/hardhat/red, +/obj/item/clothing/mask/gas, +/obj/item/clothing/glasses/meson, +/obj/machinery/light/small/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/fore) +"edM" = ( +/obj/item/toy/snowball{ + pixel_x = -6; + pixel_y = -4 }, -/obj/machinery/computer/security/telescreen/entertainment/directional/north, -/obj/machinery/light/directional/west, -/turf/open/floor/iron/grimy, -/area/station/commons/lounge) +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "edN" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"edO" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/airalarm/directional/west, +/turf/open/floor/wood/large, +/area/station/service/bar) "edT" = ( /obj/structure/grille/broken, /turf/open/floor/plating, @@ -13817,6 +14113,10 @@ }, /turf/open/floor/iron, /area/station/command/teleporter) +"eet" = ( +/obj/effect/spawner/random/trash/bin, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "eeD" = ( /obj/machinery/light/directional/west, /turf/open/floor/iron/dark/textured, @@ -13836,14 +14136,22 @@ /obj/effect/mapping_helpers/mail_sorting/engineering/atmospherics, /turf/open/floor/iron, /area/station/engineering/lobby) -"efh" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/machinery/computer/slot_machine{ - pixel_y = -6 +"eeY" = ( +/obj/structure/railing{ + dir = 4 }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood/parquet, +/obj/structure/curtain/cloth/fancy/mechanical/start_closed{ + id = "cantena_curtains" + }, +/turf/open/floor/wood, /area/station/commons/lounge) "efi" = ( /obj/structure/bed/dogbed, @@ -13917,6 +14225,41 @@ initial_gas_mix = "ICEMOON_ATMOS" }, /area/icemoon/underground/explored) +"efN" = ( +/obj/machinery/door/airlock/external{ + glass = 1; + name = "Chapel External Airlock"; + opacity = 0 + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/effect/mapping_helpers/airlock/access/any/service/chapel_office, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/service/chapel) +"efS" = ( +/obj/item/kirbyplants/random, +/obj/effect/turf_decal/siding/wood{ + dir = 9 + }, +/obj/machinery/power/apc/auto_name/directional/east, +/obj/structure/cable, +/obj/machinery/light/warm/directional/east, +/turf/open/floor/wood/large, +/area/station/commons/lounge) +"efU" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 8 + }, +/obj/machinery/duct, +/obj/structure/sign/flag/nanotrasen/directional/west, +/turf/open/floor/iron, +/area/station/commons/fitness) "efV" = ( /obj/effect/turf_decal/delivery, /obj/structure/cable, @@ -13929,9 +14272,6 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"egf" = ( -/turf/closed/wall/r_wall, -/area/station/science/ordnance/burnchamber) "egj" = ( /obj/structure/rack, /obj/machinery/light/small/directional/north, @@ -14028,12 +14368,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"ehm" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "ehp" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -14046,14 +14380,6 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/command/heads_quarters/hos) -"ehA" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Canteen" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/textured_half, -/area/station/hallway/primary/starboard) "ehD" = ( /obj/effect/turf_decal/stripes/line{ dir = 6 @@ -14159,14 +14485,6 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/medical/medbay/central) -"ejg" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible/layer4, -/obj/machinery/meter/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) "ejn" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -14212,15 +14530,22 @@ "ejX" = ( /turf/open/floor/plating, /area/station/security/prison/safe) -"eke" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/closet/mini_fridge{ - name = "mini-fridge" +"ejY" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/oil, +/turf/open/floor/plating, +/area/station/maintenance/fore) +"ekc" = ( +/obj/effect/landmark/event_spawn, +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 }, -/obj/item/reagent_containers/condiment/milk, -/obj/structure/table, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "ekh" = ( /obj/machinery/camera/directional/west{ c_tag = "Atmospherics - Central" @@ -14321,6 +14646,30 @@ dir = 1 }, /area/station/hallway/primary/starboard) +"emw" = ( +/obj/item/radio/intercom/directional/west, +/turf/open/floor/wood, +/area/station/commons/lounge) +"emx" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) +"emF" = ( +/obj/structure/reagent_dispensers/plumbed{ + name = "service reservoir" + }, +/obj/machinery/light/small/dim/directional/north, +/obj/effect/turf_decal/delivery/white{ + color = "#307db9" + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/iron/textured, +/area/station/maintenance/starboard/fore) "emK" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white/side{ @@ -14355,14 +14704,6 @@ /obj/effect/turf_decal/stripes/box, /turf/open/floor/plating, /area/station/engineering/lobby) -"enG" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "enI" = ( /obj/machinery/door/airlock/maintenance{ name = "Tool Storage Maintenance" @@ -14391,16 +14732,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/service/chapel) -"eoq" = ( -/obj/structure/stairs/south{ - dir = 1 - }, -/obj/structure/railing{ - dir = 4 - }, -/obj/machinery/firealarm/directional/east, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "eos" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -14454,6 +14785,18 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"eoV" = ( +/obj/item/trash/popcorn, +/obj/structure/reagent_dispensers/plumbed{ + name = "dormitory reservoir" + }, +/obj/machinery/light/small/dim/directional/north, +/obj/effect/turf_decal/delivery/white{ + color = "#307db9" + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/iron/textured, +/area/station/maintenance/fore) "eoY" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -14472,6 +14815,15 @@ /obj/item/stock_parts/cell/high, /turf/open/floor/iron, /area/station/maintenance/department/electrical) +"eph" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "epB" = ( /obj/structure/chair/pew/left{ dir = 1 @@ -14503,6 +14855,15 @@ dir = 8 }, /area/station/science/ordnance/office) +"eqk" = ( +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "eqn" = ( /obj/structure/sign/warning/docking/directional/east, /turf/open/misc/asteroid/snow/icemoon, @@ -14618,6 +14979,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/science/genetics) +"erq" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "erw" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt/dust, @@ -14630,6 +14998,12 @@ /obj/machinery/light_switch/directional/east, /turf/open/floor/iron, /area/station/construction) +"erE" = ( +/obj/machinery/requests_console/auto_name/directional/east, +/obj/machinery/duct, +/obj/effect/mapping_helpers/requests_console/supplies, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "erH" = ( /obj/structure/disposalpipe/trunk{ dir = 8 @@ -14688,23 +15062,10 @@ }, /turf/open/floor/iron/dark, /area/station/cargo/miningdock) -"esn" = ( -/obj/effect/landmark/start/bartender, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "eso" = ( /obj/machinery/telecomms/receiver/preset_left, /turf/open/floor/iron/dark/telecomms, /area/station/tcommsat/server) -"esu" = ( -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "esv" = ( /obj/structure/cable, /obj/effect/turf_decal/siding/green{ @@ -14752,19 +15113,19 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) +"etr" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "etw" = ( /obj/effect/turf_decal/stripes/white/line, /obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm/directional/west, /turf/open/floor/iron, /area/station/security/prison/workout) -"etA" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "etB" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/simple/brown/visible{ @@ -14792,18 +15153,6 @@ /obj/effect/mapping_helpers/airlock/access/any/engineering/general, /turf/open/floor/iron/dark, /area/station/engineering/main) -"etV" = ( -/obj/machinery/door/airlock{ - name = "Service Hall" - }, -/obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 1 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "etY" = ( /obj/machinery/light_switch/directional/north, /turf/open/floor/iron, @@ -14906,6 +15255,10 @@ "evb" = ( /turf/open/floor/iron, /area/station/service/janitor) +"evc" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "evk" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -14929,11 +15282,6 @@ "evT" = ( /turf/open/floor/plating/icemoon, /area/station/science/ordnance/bomb) -"ewd" = ( -/obj/machinery/airalarm/directional/north, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "ewi" = ( /obj/machinery/navbeacon{ codes_txt = "delivery;dir=8"; @@ -14943,12 +15291,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/maintenance/department/medical/central) -"ewz" = ( -/obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) "ewC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, @@ -15029,12 +15371,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/prison/work) -"exY" = ( -/obj/effect/turf_decal/siding/white, -/obj/effect/spawner/random/vending/colavend, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "eyb" = ( /turf/closed/wall, /area/station/security/processing) @@ -15088,6 +15424,16 @@ /obj/machinery/light/small/red/directional/south, /turf/open/floor/iron/dark/smooth_half, /area/station/service/chapel) +"ezd" = ( +/obj/structure/table/wood, +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/storage/wallet{ + pixel_y = 5; + pixel_x = 3 + }, +/obj/item/newspaper, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "ezf" = ( /obj/machinery/door/airlock{ name = "Private Restroom" @@ -15095,6 +15441,13 @@ /obj/effect/mapping_helpers/airlock/access/all/medical/general, /turf/open/floor/iron/freezer, /area/station/medical/break_room) +"ezk" = ( +/obj/effect/turf_decal/siding/wood/end{ + dir = 1 + }, +/obj/item/kirbyplants/organic/plant11, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "ezl" = ( /obj/effect/turf_decal/siding/wood, /obj/effect/decal/cleanable/dirt, @@ -15195,22 +15548,6 @@ /obj/machinery/firealarm/directional/south, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) -"eAS" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/door/airlock/engineering{ - name = "Utilities Room" - }, -/obj/structure/disposalpipe/segment, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, -/obj/effect/mapping_helpers/airlock/unres, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) -"eBa" = ( -/obj/effect/turf_decal/siding/white, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "eBd" = ( /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, @@ -15228,25 +15565,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) -"eBi" = ( -/obj/machinery/door/airlock{ - name = "Hydroponics Backroom" - }, -/obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, -/turf/open/floor/iron/textured_half, -/area/station/service/hydroponics) -"eBk" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/light/directional/south, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral/half/contrasted, -/turf/open/floor/iron, -/area/station/commons/fitness) "eBz" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -15373,12 +15691,6 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) -"eDi" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "eDj" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 8 @@ -15391,13 +15703,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/security/prison/visit) -"eDx" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/start/cook, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "eDy" = ( /obj/structure/closet/boxinggloves, /obj/machinery/light/directional/north, @@ -15414,6 +15719,12 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"eDD" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/segment, +/obj/structure/railing/corner/end, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "eDH" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -15438,13 +15749,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron/smooth_large, /area/station/command/heads_quarters/hos) -"eDP" = ( -/obj/effect/turf_decal/siding/wood/end{ - dir = 1 - }, -/obj/structure/bookcase/random/fiction, -/turf/open/floor/iron/dark, -/area/station/commons/lounge) "eEh" = ( /obj/structure/table/reinforced, /obj/item/storage/toolbox/mechanical, @@ -15456,10 +15760,11 @@ /obj/item/flashlight, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"eEz" = ( -/obj/effect/spawner/structure/window/reinforced, +"eEr" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/sign/warning/directional/south, /turf/open/floor/plating, -/area/station/service/bar/atrium) +/area/station/maintenance/starboard/fore) "eEC" = ( /obj/structure/table/wood, /obj/machinery/fax{ @@ -15502,6 +15807,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden, /turf/open/floor/plating, /area/station/engineering/atmos/storage/gas) +"eFf" = ( +/obj/structure/fireplace{ + pixel_x = 0 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/stone, +/area/station/commons/lounge) "eFh" = ( /obj/structure/table, /obj/effect/spawner/random/entertainment/cigarette_pack, @@ -15560,6 +15873,11 @@ /obj/structure/chair/stool/directional/south, /turf/open/floor/wood, /area/station/commons/dorms) +"eGg" = ( +/obj/machinery/icecream_vat, +/obj/structure/sign/clock/directional/north, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "eGl" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/effect/landmark/event_spawn, @@ -15646,16 +15964,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"eHW" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +"eHX" = ( /obj/structure/disposalpipe/segment{ - dir = 4 + dir = 6 }, -/obj/structure/sign/warning/gas_mask/directional/south, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, /turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) +/area/station/maintenance/fore) "eHZ" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 4 @@ -15663,13 +15981,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/treatment_center) -"eIa" = ( -/obj/effect/turf_decal/siding/wood/corner{ - dir = 1 - }, -/obj/machinery/restaurant_portal/bar, -/turf/open/floor/stone, -/area/station/commons/lounge) "eId" = ( /obj/structure/railing/corner{ dir = 8 @@ -15708,16 +16019,6 @@ }, /turf/open/floor/iron, /area/station/cargo/storage) -"eIY" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 4 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 4 - }, -/obj/machinery/light/floor, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "eJe" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -15731,18 +16032,6 @@ /obj/structure/lattice, /turf/open/openspace/icemoon/keep_below, /area/icemoon/underground/explored) -"eJq" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/hydroponics/glass{ - name = "Hydroponics" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, -/turf/open/floor/iron/textured_half{ - dir = 1 - }, -/area/station/service/hydroponics) "eJx" = ( /obj/machinery/newscaster/directional/east, /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -15838,15 +16127,19 @@ dir = 5 }, /area/station/science/research) -"eLx" = ( -/obj/effect/landmark/start/bartender, -/obj/machinery/duct, -/obj/structure/disposalpipe/segment{ - dir = 9 +"eLv" = ( +/obj/machinery/light_switch/directional/east, +/obj/effect/turf_decal/siding/white{ + dir = 8 }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) +/obj/structure/closet/secure_closet/freezer/kitchen, +/obj/item/food/grown/tomato, +/obj/item/food/grown/tomato{ + pixel_y = 2; + pixel_x = 2 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "eLS" = ( /obj/structure/window/reinforced/spawner/directional/north, /obj/structure/window/reinforced/spawner/directional/east, @@ -15947,20 +16240,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"eNz" = ( -/obj/machinery/door/airlock/maintenance{ - name = "Fitness Maintenance" - }, -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/mapping_helpers/airlock/access/any/security/maintenance, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 1 - }, -/turf/open/floor/plating, -/area/station/maintenance/fore) "eNC" = ( /obj/machinery/status_display/evac/directional/west, /obj/item/kirbyplants/random, @@ -16050,6 +16329,11 @@ /obj/structure/table, /turf/open/floor/engine, /area/station/science/xenobiology) +"ePd" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/grille/broken, +/turf/open/floor/plating, +/area/station/maintenance/fore) "ePi" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/trimline/blue/filled/corner{ @@ -16060,17 +16344,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/storage) -"ePl" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/obj/machinery/duct, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "ePm" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -16104,6 +16377,16 @@ /obj/item/kirbyplants/random, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"ePZ" = ( +/obj/structure/chair/stool/directional/west, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/stone, +/area/station/commons/lounge) "eQz" = ( /obj/structure/grille, /turf/open/floor/plating, @@ -16118,15 +16401,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/laborcamp) -"eQN" = ( -/obj/machinery/door/airlock{ - name = "Unisex Showers" - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "eQQ" = ( /obj/structure/sign/warning/biohazard, /turf/closed/wall, @@ -16195,6 +16469,15 @@ dir = 4 }, /area/station/cargo/bitrunning/den) +"eSm" = ( +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/structure/sign/warning/electric_shock/directional/west, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/hallway/primary/fore) "eSn" = ( /obj/structure/chair/office, /obj/effect/landmark/start/assistant, @@ -16222,13 +16505,6 @@ }, /turf/open/floor/iron/cafeteria, /area/station/security/prison/work) -"eSF" = ( -/obj/machinery/light/small/directional/east, -/obj/structure/dresser, -/obj/machinery/firealarm/directional/east, -/obj/structure/sign/poster/contraband/random/directional/north, -/turf/open/floor/iron, -/area/station/service/theater) "eSJ" = ( /obj/effect/turf_decal/stripes/corner{ dir = 8 @@ -16297,6 +16573,15 @@ /obj/structure/cable, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/starboard/fore) +"eTT" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/requests_console/auto_name/directional/north, +/obj/effect/turf_decal/siding/wood, +/obj/machinery/duct, +/obj/machinery/light/small/directional/north, +/obj/effect/mapping_helpers/requests_console/supplies, +/turf/open/floor/iron, +/area/station/service/bar) "eUe" = ( /obj/effect/turf_decal/trimline/yellow/filled/corner, /turf/open/floor/iron/white, @@ -16319,15 +16604,6 @@ /obj/item/seeds/tower, /turf/open/floor/iron/dark, /area/station/service/hydroponics/garden) -"eUw" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/table, -/obj/item/storage/bag/tray, -/obj/item/knife/kitchen{ - pixel_y = 2 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "eUA" = ( /obj/structure/cable, /obj/effect/turf_decal/siding/green/corner{ @@ -16360,6 +16636,17 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/iron/dark, /area/station/security/execution/education) +"eUC" = ( +/obj/machinery/firealarm/directional/west{ + pixel_y = -4 + }, +/obj/machinery/light_switch/directional/west{ + pixel_y = 5 + }, +/obj/machinery/photocopier, +/obj/machinery/airalarm/directional/north, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "eUI" = ( /obj/machinery/space_heater, /turf/open/floor/plating, @@ -16425,6 +16712,11 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/eva/lower) +"eVi" = ( +/obj/effect/turf_decal/siding/wood/corner, +/obj/machinery/newscaster/directional/south, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "eVl" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/mining/glass{ @@ -16536,19 +16828,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/plating, /area/station/hallway/secondary/entry) -"eWI" = ( -/obj/machinery/door/airlock{ - name = "Hydroponics Maintenance" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "eWP" = ( /obj/machinery/computer/security/mining, /obj/effect/turf_decal/tile/brown/anticorner/contrasted, @@ -16574,21 +16853,6 @@ "eXH" = ( /turf/closed/wall/r_wall, /area/station/medical/chemistry) -"eXU" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/closed/wall, -/area/station/maintenance/starboard/lesser) -"eXY" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) "eYe" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -16603,7 +16867,7 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/central) "eYz" = ( -/obj/machinery/mineral/processing_unit{ +/obj/machinery/mineral/processing_unit/gulag{ dir = 1 }, /obj/effect/decal/cleanable/dirt, @@ -16613,14 +16877,10 @@ /turf/open/floor/iron/smooth, /area/mine/laborcamp/security) "eYH" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/ai) -"eYL" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/closed/wall, -/area/station/maintenance/fore) "eYP" = ( /obj/structure/cable, /obj/machinery/door/firedoor, @@ -16672,17 +16932,6 @@ /obj/machinery/drone_dispenser, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"eZj" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "eZp" = ( /obj/machinery/space_heater, /obj/effect/decal/cleanable/dirt, @@ -16768,6 +17017,26 @@ /obj/structure/tank_holder/extinguisher, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"far" = ( +/obj/structure/railing/corner/end{ + dir = 4 + }, +/turf/open/floor/iron/stairs/old{ + dir = 4 + }, +/area/station/hallway/primary/starboard) +"fat" = ( +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/blue/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "faG" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -16784,6 +17053,25 @@ }, /turf/open/floor/iron, /area/station/command/heads_quarters/rd) +"fbg" = ( +/obj/machinery/door/airlock/wood{ + name = "Backstage" + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/all/service/theatre, +/obj/effect/landmark/navigate_destination, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/service/theater) "fbh" = ( /obj/machinery/power/tracker, /obj/structure/cable, @@ -16792,20 +17080,6 @@ "fbl" = ( /turf/open/floor/iron/dark, /area/station/science/breakroom) -"fbm" = ( -/obj/effect/turf_decal/siding/white{ - dir = 5 - }, -/obj/machinery/duct, -/obj/machinery/power/apc/auto_name/directional/east, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) -"fbt" = ( -/obj/effect/turf_decal/tile/green, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "fbw" = ( /obj/machinery/camera/directional/north{ c_tag = "Bridge Conference Room" @@ -16813,6 +17087,14 @@ /obj/machinery/newscaster/directional/north, /turf/open/floor/wood, /area/station/command/meeting_room) +"fbW" = ( +/obj/machinery/newscaster/directional/west, +/obj/machinery/vending/cigarette, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/commons/lounge) "fbY" = ( /obj/effect/spawner/random/trash/hobo_squat, /turf/open/floor/plating, @@ -16823,6 +17105,14 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/dark, /area/station/security/checkpoint/science) +"fce" = ( +/obj/structure/table/glass, +/obj/structure/sign/poster/contraband/little_fruits/directional/east, +/obj/item/storage/bag/plants/portaseeder, +/obj/item/plant_analyzer, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "fcg" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -16840,6 +17130,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/science/ordnance) +"fco" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/service/bar) "fcu" = ( /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/chair, @@ -16974,6 +17271,11 @@ }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) +"feV" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/spawner/structure/window/reinforced/tinted, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "ffe" = ( /turf/closed/wall/r_wall, /area/station/maintenance/aft/lesser) @@ -16984,6 +17286,16 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/service/chapel) +"ffr" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/railing{ + dir = 1 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "ffz" = ( /obj/machinery/processor/slime, /turf/open/floor/iron, @@ -17025,16 +17337,12 @@ }, /turf/open/floor/iron, /area/station/science/ordnance) -"fgE" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 +"fgz" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 }, -/obj/machinery/duct, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) +/turf/open/floor/plating, +/area/station/maintenance/fore) "fgJ" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -17084,6 +17392,14 @@ /obj/structure/chair/sofa/bench/left, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"fhS" = ( +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/obj/structure/sink/kitchen/directional/west, +/obj/machinery/newscaster/directional/east, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "fhU" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -17213,10 +17529,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) -"fjm" = ( -/obj/machinery/firealarm/directional/north, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "fjt" = ( /obj/machinery/door/window/left/directional/east{ name = "Containment Pen 9"; @@ -17229,15 +17541,21 @@ /obj/structure/cable, /turf/open/floor/engine, /area/station/science/xenobiology) +"fju" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 1 + }, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/hydroponics) "fjz" = ( /obj/effect/decal/cleanable/generic, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"fjC" = ( -/obj/structure/disposalpipe/segment, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "fjD" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /obj/effect/turf_decal/bot, @@ -17259,6 +17577,13 @@ }, /turf/open/floor/iron/grimy, /area/station/service/chapel/office) +"fjO" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/components/binary/valve/digital/on/layer4, +/turf/open/floor/plating, +/area/station/maintenance/fore) "fjQ" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/white, @@ -17267,10 +17592,17 @@ /obj/machinery/power/terminal{ dir = 8 }, -/obj/structure/cable, /obj/structure/sign/poster/contraband/missing_gloves/directional/east, /turf/open/floor/plating, /area/station/maintenance/department/electrical) +"fkd" = ( +/obj/machinery/vending/coffee, +/obj/effect/turf_decal/siding/wood{ + dir = 5 + }, +/obj/machinery/airalarm/directional/west, +/turf/open/floor/iron/dark, +/area/station/commons/lounge) "fkj" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -17286,6 +17618,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/kitchen/diagonal, /area/station/service/kitchen) +"fkq" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "fkt" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/plating/icemoon, @@ -17294,12 +17635,6 @@ /obj/item/weldingtool, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) -"fkJ" = ( -/obj/machinery/computer/slot_machine{ - pixel_y = 2 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "fkN" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, /turf/open/floor/iron/dark, @@ -17452,9 +17787,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/mix) -"fmD" = ( -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "fmU" = ( /obj/structure/railing/corner{ dir = 4 @@ -17543,9 +17875,15 @@ /obj/effect/turf_decal/tile/neutral/anticorner/contrasted, /turf/open/floor/iron, /area/station/commons/dorms) -"fpb" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plating/snowed/coldroom, +"fpm" = ( +/obj/structure/railing/corner/end{ + dir = 1 + }, +/obj/structure/cable, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/turf/open/floor/plating, /area/station/service/kitchen/coldroom) "fpp" = ( /obj/effect/turf_decal/trimline/green/filled/line{ @@ -17569,6 +17907,11 @@ dir = 9 }, /area/station/security/prison/safe) +"fpt" = ( +/obj/structure/kitchenspike, +/obj/machinery/status_display/evac/directional/west, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "fpA" = ( /obj/machinery/hydroponics/soil, /obj/effect/turf_decal/siding/wideplating/dark{ @@ -17590,28 +17933,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"fpF" = ( +/obj/machinery/space_heater, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/turf/open/floor/plating, +/area/station/maintenance/fore) "fpJ" = ( /obj/structure/fireaxecabinet/directional/west, /obj/machinery/suit_storage_unit/atmos, /turf/open/floor/iron/dark/textured, /area/station/engineering/atmos) -"fpP" = ( -/obj/machinery/camera/directional/north{ - c_tag = "Central Hallway North-East" - }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/central) -"fpW" = ( -/obj/structure/sign/poster/official/random/directional/north, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) -"fqc" = ( -/obj/structure/table, -/obj/item/clothing/mask/cigarette/cigar, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "fqv" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -17640,14 +17971,6 @@ /obj/effect/turf_decal/trimline/white/filled/warning, /turf/open/genturf, /area/icemoon/underground/unexplored/rivers/deep) -"fqK" = ( -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 10 - }, -/turf/open/floor/carpet, -/area/station/service/theater) "fqQ" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -17676,6 +17999,11 @@ dir = 8 }, /area/station/medical/chem_storage) +"fqX" = ( +/obj/structure/chair/stool/directional/north, +/obj/effect/landmark/event_spawn, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "frd" = ( /obj/structure/railing/corner{ dir = 1 @@ -17762,11 +18090,6 @@ }, /turf/open/floor/iron/dark/textured, /area/station/security/range) -"fsr" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "fsv" = ( /turf/open/floor/iron, /area/station/hallway/secondary/entry) @@ -17782,6 +18105,14 @@ }, /turf/open/floor/plating, /area/station/security/execution/education) +"fsO" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/landmark/start/hangover, +/obj/effect/turf_decal/tile/neutral/half/contrasted, +/obj/machinery/firealarm/directional/south, +/turf/open/floor/iron, +/area/station/commons/fitness) "fsQ" = ( /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible, /obj/effect/turf_decal/tile/blue{ @@ -17808,6 +18139,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"fte" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/structure/closet/secure_closet/hydroponics, +/obj/structure/sign/clock/directional/east, +/turf/open/floor/iron, +/area/station/service/hydroponics) "ftt" = ( /obj/structure/sign/warning/secure_area/directional/south{ desc = "A warning sign which reads 'SERVER ROOM'."; @@ -17835,16 +18175,6 @@ }, /turf/open/floor/plating, /area/station/science/genetics) -"ftM" = ( -/obj/machinery/button/door/directional/north{ - id = "kitchencounter"; - name = "Kitchen Lockdown"; - pixel_x = -25; - req_access = list("kitchen") - }, -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "ftN" = ( /obj/machinery/light_switch/directional/west, /obj/machinery/rnd/destructive_analyzer, @@ -17916,15 +18246,16 @@ "fvk" = ( /turf/open/floor/glass/reinforced, /area/station/science/xenobiology) -"fvs" = ( -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/north, +"fvm" = ( +/obj/machinery/door/airlock/maintenance, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/unres{ dir = 4 }, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "fvx" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -17967,14 +18298,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/closed/wall/r_wall, /area/station/maintenance/aft/greater) -"fwf" = ( -/obj/machinery/door/airlock/maintenance, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "fwh" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -17985,6 +18308,13 @@ }, /turf/open/floor/iron, /area/station/security/brig/upper) +"fwi" = ( +/obj/effect/turf_decal/siding/wood/corner, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 8 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "fwm" = ( /obj/effect/turf_decal/plaque{ icon_state = "L14" @@ -18120,14 +18450,6 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) -"fyh" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/airalarm/directional/east, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/light/directional/east, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "fyr" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/command/glass{ @@ -18147,6 +18469,14 @@ /obj/machinery/telecomms/server/presets/service, /turf/open/floor/iron/dark/telecomms, /area/station/tcommsat/server) +"fyL" = ( +/obj/structure/table, +/obj/item/storage/medkit/regular, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/commons/fitness) "fyQ" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/meter, @@ -18303,6 +18633,15 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/hallway/primary/fore) +"fBJ" = ( +/obj/structure/closet/secure_closet/hydroponics, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/machinery/light/small/directional/east, +/turf/open/floor/iron, +/area/station/service/hydroponics) "fBM" = ( /obj/structure/chair{ dir = 4 @@ -18369,15 +18708,14 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/medical/medbay/lobby) +"fCS" = ( +/obj/machinery/door/poddoor/incinerator_ordmix, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "fCW" = ( /obj/structure/extinguisher_cabinet/directional/east, /turf/open/floor/iron/dark/textured, /area/station/security/processing) -"fCY" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/sink/directional/south, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "fDc" = ( /obj/structure/chair/office, /obj/effect/landmark/start/warden, @@ -18411,14 +18749,6 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/dark, /area/station/medical/morgue) -"fDt" = ( -/obj/structure/table/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 10 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "fDI" = ( /obj/structure/table/wood, /obj/machinery/computer/records/medical/laptop{ @@ -18455,17 +18785,6 @@ }, /turf/open/floor/iron, /area/station/maintenance/port/fore) -"fEj" = ( -/obj/machinery/door/airlock/maintenance, -/obj/effect/mapping_helpers/airlock/abandoned, -/obj/structure/cable, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "fEA" = ( /obj/structure/cable, /obj/machinery/door/airlock/maintenance{ @@ -18521,6 +18840,11 @@ }, /turf/open/floor/iron, /area/mine/laborcamp/security) +"fEY" = ( +/obj/item/stack/rods/two, +/obj/item/stack/sheet/iron, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "fEZ" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -18605,6 +18929,13 @@ }, /turf/open/floor/iron/smooth, /area/station/security/holding_cell) +"fGr" = ( +/obj/structure/chair/sofa/bench{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/hallway/primary/fore) "fGI" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, @@ -18808,16 +19139,6 @@ }, /turf/open/floor/engine/n2, /area/station/engineering/atmos) -"fKd" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 8 - }, -/obj/item/food/grown/pumpkin{ - pixel_y = 5 - }, -/turf/open/floor/grass, -/area/station/service/hydroponics) "fKe" = ( /obj/machinery/camera/directional/west{ c_tag = "Engineering West" @@ -18844,6 +19165,11 @@ /obj/machinery/iv_drip, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"fKk" = ( +/obj/item/kirbyplants/fern, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "fKr" = ( /obj/machinery/airalarm/directional/north, /obj/effect/turf_decal/tile/yellow/opposingcorners, @@ -18856,26 +19182,6 @@ /obj/structure/fluff/tram_rail, /turf/open/openspace/icemoon/keep_below, /area/icemoon/underground/explored) -"fKw" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/obj/effect/turf_decal/trimline/green/filled/corner{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/blue/corner{ - dir = 1 - }, -/obj/effect/landmark/start/botanist, -/turf/open/floor/iron, -/area/station/service/hydroponics) -"fKy" = ( -/obj/effect/turf_decal/trimline/green/filled/corner{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/blue/corner{ - dir = 1 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "fKF" = ( /obj/effect/turf_decal/plaque{ icon_state = "L7" @@ -18915,7 +19221,7 @@ /turf/open/floor/iron/dark/textured_edge, /area/station/security/prison) "fLa" = ( -/obj/machinery/gibber, +/obj/effect/turf_decal/weather/snow/corner, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "fLb" = ( @@ -18955,6 +19261,17 @@ /obj/machinery/newscaster/directional/east, /turf/open/floor/wood/large, /area/mine/eva/lower) +"fLG" = ( +/obj/structure/railing/corner/end/flip{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/hydroponics) "fLK" = ( /obj/structure/railing/corner{ dir = 8 @@ -19055,13 +19372,11 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, /area/station/maintenance/starboard/upper) -"fMP" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +"fMu" = ( +/obj/structure/table/wood, +/obj/effect/spawner/random/trash/crushed_can, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "fNa" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/closet/emcloset, @@ -19106,6 +19421,12 @@ }, /turf/open/floor/iron/textured, /area/station/hallway/secondary/entry) +"fNz" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/structure/crate, +/obj/effect/spawner/random/maintenance/two, +/turf/open/floor/plating, +/area/station/maintenance/fore) "fNA" = ( /turf/open/openspace, /area/station/medical/medbay/central) @@ -19124,6 +19445,13 @@ /obj/structure/cable, /turf/open/floor/engine, /area/station/engineering/supermatter) +"fOg" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "fOl" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -19202,6 +19530,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/maint) +"fQa" = ( +/obj/structure/railing/wooden_fence{ + dir = 6 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "fQc" = ( /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ dir = 1 @@ -19213,6 +19547,11 @@ /obj/structure/chair/stool/directional/east, /turf/open/floor/iron, /area/station/maintenance/starboard/fore) +"fQs" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "fQu" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -19258,32 +19597,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply, /turf/open/floor/iron/dark, /area/station/medical/virology) -"fRG" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) -"fRJ" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/structure/table, -/obj/item/clothing/head/fedora, -/obj/machinery/airalarm/directional/north, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) -"fRP" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/machinery/camera/directional/south{ - c_tag = "Service - Electrical Maintenace Upper" - }, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/starboard/fore) "fSd" = ( /obj/structure/railing/corner{ dir = 4 @@ -19322,10 +19635,6 @@ /obj/structure/sign/warning/electric_shock/directional/east, /turf/open/floor/iron, /area/station/hallway/primary/central) -"fSG" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/closed/wall/r_wall, -/area/station/science/ordnance/burnchamber) "fTb" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -19335,6 +19644,11 @@ }, /turf/open/floor/iron, /area/station/security/prison/mess) +"fTn" = ( +/obj/effect/spawner/random/structure/grille, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "fTo" = ( /obj/item/reagent_containers/condiment/saltshaker{ pixel_x = -3 @@ -19428,20 +19742,6 @@ /obj/structure/bed/medical/emergency, /turf/open/floor/iron/white/textured, /area/station/security/medical) -"fUn" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/rack, -/obj/item/pickaxe, -/obj/item/toy/figure/chef, -/obj/machinery/camera/directional/north{ - c_tag = "Service Kitchen - Cold Room" - }, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "fUr" = ( /obj/machinery/airalarm/directional/south, /obj/structure/closet/emcloset, @@ -19477,6 +19777,11 @@ "fUR" = ( /turf/closed/wall, /area/station/hallway/secondary/entry) +"fVh" = ( +/obj/structure/table/wood, +/obj/effect/spawner/random/trash/food_packaging, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "fVm" = ( /obj/machinery/door/airlock/maintenance{ name = "Chemical Storage" @@ -19551,6 +19856,20 @@ }, /turf/open/floor/wood, /area/station/security/prison/rec) +"fWd" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Hydroponics Maintenance" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, +/turf/open/floor/plating, +/area/station/service/hydroponics) "fWe" = ( /obj/machinery/hydroponics/soil, /obj/item/plant_analyzer, @@ -19587,6 +19906,16 @@ /obj/structure/railing/corner, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"fWE" = ( +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "fWL" = ( /obj/structure/table, /obj/item/paper_bin{ @@ -19613,6 +19942,13 @@ /obj/structure/barricade/wooden/crude/snow, /turf/open/floor/wood, /area/station/maintenance/space_hut/cabin) +"fWW" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/chair/wood{ + dir = 1 + }, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "fWX" = ( /obj/structure/cable/multilayer/multiz, /turf/open/floor/plating/snowed/icemoon, @@ -19652,6 +19988,11 @@ /obj/effect/turf_decal/tile/red/opposingcorners, /turf/open/floor/iron, /area/mine/laborcamp/security) +"fXF" = ( +/obj/structure/table/wood, +/obj/item/pai_card, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "fXO" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -19668,35 +20009,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/mine/laborcamp) -"fYe" = ( -/obj/structure/closet/crate, -/obj/item/reagent_containers/cup/glass/waterbottle{ - pixel_x = 7; - pixel_y = 6 - }, -/obj/item/reagent_containers/cup/glass/waterbottle{ - pixel_x = 7; - pixel_y = 6 - }, -/obj/item/reagent_containers/cup/glass/waterbottle{ - pixel_x = 7; - pixel_y = 6 - }, -/obj/item/food/canned/beans, -/obj/item/food/canned/beans, -/obj/item/food/canned/beans, -/obj/effect/decal/cleanable/dirt, -/mob/living/basic/mouse/white, -/turf/open/floor/iron, -/area/station/maintenance/starboard/fore) -"fYh" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "fYi" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -19734,6 +20046,13 @@ }, /turf/open/floor/iron/large, /area/station/hallway/secondary/entry) +"fYX" = ( +/obj/structure/chair/stool/directional/north, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/commons/fitness) "fZb" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ cycle_id = "miner-passthrough" @@ -19753,19 +20072,15 @@ }, /turf/open/floor/plating, /area/station/command/teleporter) -"fZo" = ( -/obj/structure/railing/corner{ - dir = 4 - }, -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "fZq" = ( /obj/structure/curtain/cloth, /turf/open/floor/iron/showroomfloor, /area/station/security/prison/toilet) +"fZO" = ( +/obj/effect/spawner/random/vending/snackvend, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/hallway/primary/central) "fZT" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -19924,6 +20239,11 @@ /obj/structure/sign/warning/secure_area/directional/west, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) +"gbC" = ( +/obj/machinery/vending/dinnerware, +/obj/effect/turf_decal/siding/white, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "gbJ" = ( /obj/machinery/door/airlock/security/glass{ name = "Armory" @@ -19948,6 +20268,10 @@ /obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) +"gbM" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/middle, +/turf/open/floor/plating, +/area/station/maintenance/fore) "gbP" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -19955,14 +20279,17 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/medical/storage) -"gca" = ( +"gcf" = ( /obj/structure/table, -/obj/machinery/cell_charger, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 +/obj/item/storage/bag/tray, +/obj/item/knife/kitchen{ + pixel_y = 2 }, -/turf/open/floor/iron/white, -/area/station/medical/medbay/lobby) +/obj/effect/turf_decal/siding/white{ + dir = 10 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "gck" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -19973,11 +20300,6 @@ /obj/effect/mapping_helpers/airlock/access/all/security/general, /turf/open/floor/plating, /area/station/security/processing) -"gcm" = ( -/obj/structure/flora/bush/flowers_yw/style_random, -/obj/machinery/light/small/directional/east, -/turf/open/floor/grass, -/area/station/service/hydroponics) "gcu" = ( /obj/effect/mapping_helpers/burnt_floor, /obj/structure/cable, @@ -19993,6 +20315,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/science/ordnance) +"gcB" = ( +/obj/item/pickaxe/improvised{ + pixel_x = 7 + }, +/turf/open/misc/asteroid/snow/coldroom, +/area/icemoon/underground/explored) "gcV" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 8 @@ -20045,6 +20373,13 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"gdK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "gdN" = ( /obj/structure/railing/corner{ dir = 1 @@ -20054,6 +20389,13 @@ }, /turf/open/floor/iron, /area/station/cargo/storage) +"gdO" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/machinery/vending/cigarette, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "gdP" = ( /obj/structure/cable, /turf/open/floor/plating, @@ -20172,18 +20514,6 @@ /obj/structure/light_construct/directional/south, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"gfE" = ( -/obj/machinery/light/small/directional/west, -/obj/structure/chair/stool/directional/south, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/obj/machinery/atmospherics/components/binary/pump/on/general/visible/layer4{ - dir = 8; - name = "Air Out" - }, -/turf/open/floor/plating, -/area/station/maintenance/fore) "gfF" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -20224,13 +20554,6 @@ /obj/machinery/shower/directional/north, /turf/open/floor/iron/smooth, /area/mine/eva) -"ggD" = ( -/obj/structure/chair{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "ggG" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, @@ -20275,6 +20598,12 @@ /obj/structure/closet/crate, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) +"ghA" = ( +/obj/structure/railing/wooden_fence{ + dir = 5 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "ghE" = ( /obj/structure/disposalpipe/segment, /obj/machinery/camera/directional/west{ @@ -20305,6 +20634,18 @@ /obj/effect/turf_decal/tile/brown/half/contrasted, /turf/open/floor/iron/dark/side, /area/mine/eva) +"ghT" = ( +/obj/machinery/newscaster/directional/north, +/obj/structure/table/wood, +/obj/machinery/light/small/directional/north, +/obj/item/toy/figure/mime{ + pixel_x = -6 + }, +/obj/item/toy/figure/clown{ + pixel_x = 4 + }, +/turf/open/floor/iron/grimy, +/area/station/service/theater) "ghY" = ( /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/atmos) @@ -20316,14 +20657,15 @@ /obj/structure/sign/warning/directional/north, /turf/open/floor/plating, /area/station/maintenance/port/lesser) -"giD" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/siding/wideplating/dark{ - dir = 1 +"giH" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/barsign/all_access/directional/north, +/obj/effect/turf_decal/siding/wood, +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/obj/item/seeds/watermelon, -/turf/open/floor/grass, -/area/station/maintenance/starboard/fore) +/turf/open/floor/iron, +/area/station/service/bar) "giN" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/trimline/yellow/line, @@ -20429,6 +20771,13 @@ /obj/machinery/newscaster/directional/east, /turf/open/floor/wood, /area/station/security/courtroom) +"gjT" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "gjW" = ( /obj/structure/chair, /turf/open/floor/iron/cafeteria, @@ -20465,6 +20814,12 @@ /obj/effect/spawner/random/engineering/tracking_beacon, /turf/open/floor/iron, /area/station/science/robotics/mechbay) +"gkH" = ( +/obj/structure/table/wood, +/obj/effect/spawner/random/entertainment/cigarette, +/obj/effect/spawner/random/entertainment/lighter, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "gkK" = ( /obj/machinery/atmospherics/pipe/multiz/supply/visible/layer4{ color = "#0000ff"; @@ -20581,11 +20936,6 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) -"glQ" = ( -/obj/machinery/door/firedoor, -/obj/machinery/smartfridge, -/turf/open/floor/iron, -/area/station/service/hydroponics) "glS" = ( /obj/machinery/camera/directional/south{ c_tag = "MiniSat Pod Access"; @@ -20622,18 +20972,11 @@ /obj/structure/extinguisher_cabinet/directional/south, /turf/open/floor/iron/white, /area/station/medical/virology) -"gmB" = ( -/obj/structure/stairs/south{ - dir = 1 - }, -/obj/structure/railing{ - dir = 8 - }, -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) +"gmt" = ( +/obj/structure/extinguisher_cabinet/directional/north, +/obj/machinery/food_cart, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "gmJ" = ( /obj/machinery/atmospherics/components/binary/pump{ name = "Port to Infiltrate/Filter" @@ -20706,6 +21049,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold/yellow/visible, /turf/open/floor/iron, /area/station/engineering/atmos) +"gnE" = ( +/obj/machinery/hydroponics/constructable, +/turf/open/floor/grass, +/area/station/service/hydroponics) "gnL" = ( /obj/structure/closet/bombcloset/security, /turf/open/floor/iron/smooth, @@ -20895,6 +21242,13 @@ }, /turf/open/floor/iron/textured, /area/station/security/brig) +"grg" = ( +/obj/item/toy/snowball{ + pixel_x = 6; + pixel_y = 5 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "grk" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -20955,6 +21309,16 @@ }, /turf/open/floor/iron, /area/station/cargo/lobby) +"grO" = ( +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/corner{ + dir = 8 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "grT" = ( /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 1 @@ -20981,14 +21345,6 @@ "gst" = ( /turf/closed/wall, /area/station/commons/vacant_room/commissary) -"gsD" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/item/radio/intercom/directional/north, -/obj/item/kirbyplants/random, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "gsF" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 @@ -21022,18 +21378,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) -"gsW" = ( -/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, -/obj/machinery/door/airlock/freezer{ - desc = "The freezer where the chef keeps all the stuff that needs to be kept cold. Ice cold."; - name = "The Ice Box" - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating, -/area/station/service/kitchen/coldroom) "gta" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/structure/table, @@ -21041,16 +21385,6 @@ /obj/item/pen, /turf/open/floor/iron, /area/station/commons/locker) -"gtc" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/machinery/duct, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "gtg" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/visible/layer1{ dir = 8 @@ -21060,11 +21394,6 @@ "gti" = ( /turf/open/openspace, /area/station/maintenance/starboard/aft) -"gtj" = ( -/obj/structure/closet, -/obj/effect/spawner/random/maintenance/three, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "gtw" = ( /obj/effect/turf_decal/tile/neutral/diagonal_edge, /turf/open/floor/iron/kitchen/diagonal, @@ -21081,6 +21410,17 @@ /obj/effect/spawner/random/vending/colavend, /turf/open/floor/iron, /area/station/commons/locker) +"gua" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/bar) "guS" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -21138,6 +21478,10 @@ /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/iron, /area/station/science/xenobiology) +"gwb" = ( +/obj/machinery/airalarm/directional/east, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "gwm" = ( /obj/machinery/door/firedoor/heavy, /turf/open/floor/iron/white/side{ @@ -21223,6 +21567,10 @@ /obj/item/radio/intercom/prison/directional/south, /turf/open/floor/iron/dark, /area/station/security/prison/rec) +"gxz" = ( +/obj/structure/closet/secure_closet/freezer/meat, +/turf/open/misc/asteroid/snow/coldroom, +/area/station/service/kitchen/coldroom) "gxO" = ( /obj/structure/table/reinforced, /obj/item/hand_labeler{ @@ -21255,6 +21603,22 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/mine/eva) +"gxT" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Fitness" + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/commons/fitness) "gxU" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -21262,19 +21626,6 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/command/bridge) -"gxY" = ( -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) -"gxZ" = ( -/obj/structure/sign/painting/library{ - pixel_y = 32 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "gya" = ( /obj/structure/table/wood, /obj/item/storage/medkit/regular, @@ -21289,24 +21640,6 @@ }, /turf/open/floor/iron/dark, /area/station/service/chapel) -"gyr" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/structure/chair/stool/bar/directional/east, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) -"gyw" = ( -/obj/machinery/door/window/right/directional/west{ - name = "Apiary"; - req_access = list("hydroponics") - }, -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 8 - }, -/turf/open/floor/grass, -/area/station/service/hydroponics) "gyH" = ( /obj/machinery/light/directional/north, /obj/machinery/vending/coffee, @@ -21314,6 +21647,14 @@ /obj/machinery/newscaster/directional/north, /turf/open/floor/iron/dark, /area/station/hallway/secondary/entry) +"gyP" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/landmark/event_spawn, +/obj/machinery/holopad, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/wood/parquet, +/area/station/service/bar/backroom) "gyR" = ( /turf/closed/wall/r_wall, /area/station/engineering/main) @@ -21322,9 +21663,6 @@ /obj/effect/turf_decal/tile/green/full, /turf/open/floor/iron/dark/smooth_large, /area/station/medical/virology) -"gzw" = ( -/turf/open/openspace, -/area/station/hallway/secondary/service) "gzz" = ( /obj/machinery/computer/security/telescreen/entertainment/directional/west, /obj/machinery/computer/monitor{ @@ -21378,9 +21716,23 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/security/prison/visit) -"gAy" = ( +"gAw" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 5 + }, +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning/corner{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/service/hydroponics) "gAB" = ( @@ -21395,31 +21747,10 @@ }, /turf/open/floor/iron/grimy, /area/station/service/chapel/office) -"gAM" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/machinery/door/airlock/engineering{ - name = "Utilities Room" - }, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, -/obj/effect/mapping_helpers/airlock/unres, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) -"gAN" = ( -/obj/structure/reagent_dispensers/watertank/high, -/obj/effect/turf_decal/stripes/line, -/obj/item/reagent_containers/cup/watering_can, -/obj/effect/turf_decal/tile/blue/half{ - dir = 4 - }, -/obj/effect/turf_decal/tile/green/half{ - dir = 8 - }, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/service/hydroponics) +"gAG" = ( +/obj/machinery/modular_computer/preset/civilian, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "gAR" = ( /obj/structure/falsewall, /turf/open/floor/plating, @@ -21455,13 +21786,10 @@ /obj/structure/sign/warning/electric_shock, /turf/closed/wall/r_wall, /area/icemoon/underground/explored) -"gBq" = ( -/obj/machinery/door/firedoor, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) +"gBs" = ( +/obj/structure/falsewall, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "gBv" = ( /obj/machinery/door/window/left/directional/south{ name = "Engineering Delivery"; @@ -21572,6 +21900,13 @@ /obj/structure/cable, /turf/open/floor/wood, /area/station/security/courtroom) +"gDh" = ( +/obj/structure/flora/grass/brown/style_random, +/obj/structure/sign/nanotrasen{ + pixel_y = -32 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/nospawn) "gDp" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -21595,6 +21930,22 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/station/maintenance/fore) +"gDB" = ( +/obj/machinery/oven/range, +/obj/effect/turf_decal/siding/white/corner, +/obj/machinery/light/directional/north, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) +"gDL" = ( +/obj/structure/chair/wood{ + dir = 4 + }, +/obj/item/toy/plush/moth{ + name = "Theseus" + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "gDN" = ( /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 1 @@ -21613,6 +21964,15 @@ /obj/effect/turf_decal/tile/yellow, /turf/open/floor/iron, /area/station/hallway/primary/aft) +"gDY" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/structure/railing{ + dir = 8 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "gDZ" = ( /turf/open/floor/wood, /area/station/maintenance/port/fore) @@ -21639,6 +21999,14 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"gEl" = ( +/obj/machinery/door/airlock/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "gEn" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -21672,28 +22040,14 @@ /obj/effect/mapping_helpers/airlock/access/any/engineering/general, /turf/open/floor/plating, /area/station/engineering/storage_shared) -"gEz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/space_heater, +"gEt" = ( +/obj/machinery/power/apc/auto_name/directional/east, +/obj/structure/cable, /turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) +/area/station/maintenance/starboard/lesser) "gEE" = ( /turf/open/openspace, /area/station/service/chapel) -"gEL" = ( -/obj/structure/table/glass, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 6 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 6 - }, -/obj/machinery/camera/directional/east{ - c_tag = "Service Botany - Upper North" - }, -/obj/item/hand_labeler, -/turf/open/floor/iron, -/area/station/service/hydroponics) "gER" = ( /turf/open/floor/iron, /area/station/command/bridge) @@ -21718,6 +22072,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/medical/morgue) +"gEZ" = ( +/obj/structure/railing, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "gFj" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -21725,6 +22086,10 @@ /obj/structure/cable, /turf/open/floor/carpet, /area/station/security/detectives_office) +"gFt" = ( +/obj/effect/spawner/random/engineering/canister, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "gFx" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/warning/gas_mask, @@ -21753,6 +22118,13 @@ /obj/item/clothing/glasses/meson, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"gFW" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/machinery/computer/security/telescreen/entertainment/directional/north, +/turf/open/floor/wood/large, +/area/station/service/bar) "gFX" = ( /turf/closed/wall, /area/icemoon/underground/explored) @@ -21840,6 +22212,14 @@ }, /turf/open/floor/iron/white, /area/station/medical/chemistry) +"gGS" = ( +/obj/structure/railing, +/obj/effect/turf_decal/siding/white, +/obj/structure/curtain/cloth/fancy/mechanical/start_closed{ + id = "cantena_curtains" + }, +/turf/open/floor/wood, +/area/station/commons/lounge) "gGZ" = ( /obj/machinery/computer/bank_machine, /obj/effect/turf_decal/bot_white, @@ -21869,14 +22249,6 @@ /obj/effect/turf_decal/tile/yellow/anticorner/contrasted, /turf/open/floor/iron, /area/station/engineering/atmos) -"gHm" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment, -/obj/effect/spawner/random/structure/steam_vent, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "gHq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -21907,6 +22279,9 @@ /obj/effect/turf_decal/trimline/red/line, /turf/open/floor/iron/dark/textured, /area/station/security/range) +"gHL" = ( +/turf/open/floor/catwalk_floor/iron_dark, +/area/station/maintenance/starboard/fore) "gHN" = ( /obj/effect/turf_decal/trimline/green/filled/corner{ dir = 1 @@ -21921,17 +22296,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"gHR" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/structure/table, -/obj/effect/spawner/random/food_or_drink/donkpockets{ - pixel_y = 8 - }, -/obj/structure/sign/poster/random/directional/north, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "gHS" = ( /obj/structure/chair/stool/directional/north, /obj/effect/turf_decal/tile/neutral/half/contrasted, @@ -21942,6 +22306,20 @@ /obj/structure/chair/stool/directional/west, /turf/open/floor/iron/checker, /area/station/science/lab) +"gIf" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Central Access" + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/starboard) "gIl" = ( /obj/structure/fence/corner{ dir = 6 @@ -22070,10 +22448,6 @@ /obj/structure/extinguisher_cabinet/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/central) -"gLo" = ( -/obj/structure/disposalpipe/segment, -/turf/open/floor/wood/tile, -/area/station/service/theater) "gLu" = ( /obj/effect/turf_decal/delivery, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -22107,10 +22481,17 @@ /obj/item/flashlight/lamp, /turf/open/floor/wood, /area/station/maintenance/port/fore) -"gMp" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) +"gMi" = ( +/obj/structure/table, +/obj/item/paper_bin, +/obj/item/pen{ + pixel_x = -5 + }, +/obj/item/hand_labeler/borg{ + pixel_y = -3 + }, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "gMt" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt/dust, @@ -22129,6 +22510,17 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/iron/smooth, /area/mine/eva) +"gMx" = ( +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "gMK" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -22172,6 +22564,13 @@ }, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"gNc" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/service/bar) "gNg" = ( /obj/machinery/camera/directional/north{ c_tag = "MiniSat External South"; @@ -22197,6 +22596,21 @@ /obj/item/reagent_containers/dropper, /turf/open/floor/iron/cafeteria, /area/station/science/lab) +"gNu" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/middle{ + dir = 4 + }, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "botany_chasm_and_wolf_shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) +"gNw" = ( +/obj/structure/flora/bush/grassy/style_random, +/obj/structure/flora/bush/flowers_br/style_random, +/turf/open/floor/grass, +/area/station/service/hydroponics) "gNH" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -22234,6 +22648,15 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/command/heads_quarters/cmo) +"gOd" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/station/maintenance/starboard/lesser) "gOg" = ( /obj/machinery/light/small/directional/west, /obj/machinery/camera/directional/west{ @@ -22330,6 +22753,13 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/ai_monitored/security/armory/upper) +"gPo" = ( +/obj/effect/spawner/random/structure/chair_flipped{ + dir = 8 + }, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "gPp" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 @@ -22337,6 +22767,11 @@ /obj/machinery/light_switch/directional/south, /turf/open/floor/iron/showroomfloor, /area/station/security/warden) +"gPB" = ( +/obj/structure/table/wood/poker, +/obj/effect/spawner/random/food_or_drink/refreshing_beverage, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "gPE" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -22369,17 +22804,6 @@ }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) -"gQj" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 6 - }, -/obj/machinery/disposal/bin, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/trunk{ - dir = 1 - }, -/turf/open/floor/stone, -/area/station/service/bar) "gQp" = ( /obj/machinery/door/airlock/external{ name = "External Access" @@ -22435,19 +22859,6 @@ /obj/effect/mapping_helpers/airlock/access/all/service/chapel_office, /turf/open/floor/iron/dark, /area/station/service/chapel/office) -"gQZ" = ( -/obj/machinery/light/directional/north, -/turf/open/floor/iron, -/area/station/hallway/primary/central) -"gRl" = ( -/obj/effect/landmark/start/hangover, -/obj/structure/chair/wood{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/light/small/directional/north, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "gRm" = ( /obj/structure/grille/broken, /obj/effect/decal/cleanable/dirt, @@ -22476,11 +22887,30 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) +"gRE" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/window/reinforced/spawner/directional/east, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "botany_chasm_and_wolf_shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) "gRI" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) +"gRL" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "gRZ" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -22541,6 +22971,17 @@ /obj/effect/turf_decal/tile/brown/half/contrasted, /turf/open/floor/iron/dark/side, /area/mine/eva/lower) +"gSU" = ( +/obj/item/popsicle_stick{ + pixel_y = 1; + pixel_x = -9 + }, +/obj/item/popsicle_stick{ + pixel_y = 3; + pixel_x = -2 + }, +/turf/open/misc/asteroid/snow/coldroom, +/area/icemoon/underground/explored) "gSV" = ( /obj/machinery/light/directional/south, /obj/structure/bodycontainer/morgue{ @@ -22629,21 +23070,18 @@ dir = 1 }, /area/station/security/processing) +"gUw" = ( +/obj/machinery/light/small/directional/south, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "gUx" = ( /obj/effect/turf_decal/bot, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/laborcamp) -"gUB" = ( -/obj/structure/chair/stool/directional/south, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) -"gUF" = ( -/obj/effect/turf_decal/siding/thinplating/corner{ - dir = 4 - }, -/turf/open/misc/asteroid/snow/icemoon, -/area/icemoon/underground/explored) "gUQ" = ( /obj/structure/fence/door{ dir = 4 @@ -22668,6 +23106,10 @@ /obj/item/radio/intercom/directional/east, /turf/open/floor/iron/dark, /area/station/science/breakroom) +"gVh" = ( +/obj/structure/chair/stool/directional/north, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "gVm" = ( /obj/item/coin/silver{ pixel_x = -5; @@ -22680,12 +23122,12 @@ }, /turf/open/floor/plating, /area/station/commons/dorms/laundry) -"gVn" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +"gVs" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/hobo_squat, +/obj/structure/sign/poster/contraband/random/directional/west, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "gVt" = ( /obj/item/radio/intercom/directional/west, /obj/effect/turf_decal/tile/red{ @@ -22746,6 +23188,13 @@ /obj/machinery/firealarm/directional/north, /turf/open/floor/iron/dark, /area/station/security/courtroom) +"gVX" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 5 + }, +/obj/structure/disposalpipe/segment, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "gWf" = ( /obj/item/storage/box/lights/mixed, /obj/structure/table, @@ -22754,6 +23203,28 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron/dark, /area/station/maintenance/department/medical/morgue) +"gWl" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 10 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 10 + }, +/obj/structure/table/glass, +/obj/machinery/reagentgrinder{ + pixel_y = 8; + pixel_x = 6 + }, +/obj/item/storage/box/syringes{ + pixel_y = 8; + pixel_x = -5 + }, +/obj/item/storage/box/beakers{ + pixel_y = 5; + pixel_x = -9 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "gWr" = ( /obj/structure/tank_dispenser, /turf/open/floor/iron/dark, @@ -22770,17 +23241,6 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/security/interrogation) -"gWZ" = ( -/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/ordnance_burn_chamber_input, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance/burnchamber) -"gXe" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/structure/disposalpipe/segment, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "gXh" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -22866,6 +23326,14 @@ /obj/effect/spawner/structure/window/hollow/reinforced, /turf/open/floor/plating, /area/mine/living_quarters) +"gYk" = ( +/obj/machinery/computer/security/telescreen/entertainment/directional/east, +/obj/machinery/status_display/evac/directional/south, +/obj/structure/chair/sofa/left/brown{ + dir = 8 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "gYp" = ( /obj/effect/turf_decal/tile/red{ dir = 8 @@ -22906,6 +23374,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"gYN" = ( +/obj/effect/turf_decal/loading_area/white{ + dir = 8 + }, +/turf/open/floor/wood/large, +/area/station/service/bar/atrium) "gZa" = ( /obj/structure/sign/nanotrasen{ pixel_x = -32 @@ -22932,27 +23406,6 @@ /obj/structure/sign/poster/random/directional/north, /turf/open/floor/plating, /area/station/construction) -"gZl" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/space_heater, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) -"gZq" = ( -/obj/machinery/firealarm/directional/south, -/obj/structure/table, -/obj/item/paper_bin{ - pixel_x = -3; - pixel_y = 7 - }, -/obj/item/pen, -/obj/effect/turf_decal/tile/blue/anticorner/contrasted, -/turf/open/floor/iron, -/area/station/command/bridge) "gZt" = ( /obj/effect/turf_decal/weather/snow/corner{ dir = 6 @@ -22980,6 +23433,10 @@ dir = 1 }, /area/station/security/prison) +"gZR" = ( +/obj/machinery/power/smes/engineering, +/turf/open/floor/plating, +/area/station/maintenance/department/electrical) "gZT" = ( /obj/structure/cable, /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -22991,6 +23448,11 @@ /obj/machinery/power/apc/auto_name/directional/north, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"gZV" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/grille_or_waste, +/turf/open/floor/plating, +/area/station/maintenance/fore) "hac" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple/layer2{ dir = 9 @@ -23021,13 +23483,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/mine/laborcamp) -"hao" = ( -/obj/structure/frame/computer{ - dir = 1 - }, -/obj/item/radio/intercom/directional/south, -/turf/open/floor/iron/smooth, -/area/station/maintenance/starboard/fore) "hap" = ( /turf/open/floor/vault, /area/station/security/prison/rec) @@ -23060,15 +23515,6 @@ /obj/effect/landmark/start/bitrunner, /turf/open/floor/iron, /area/station/cargo/storage) -"haN" = ( -/obj/machinery/deepfryer, -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/sign/poster/contraband/moffuchis_pizza/directional/east, -/obj/machinery/camera/directional/east{ - c_tag = "Service Kitchen" - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "haQ" = ( /obj/effect/turf_decal/tile/purple/half/contrasted{ dir = 8 @@ -23100,6 +23546,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/maintenance/starboard/fore) +"hbL" = ( +/obj/machinery/light/small/directional/east, +/turf/open/openspace, +/area/station/service/hydroponics) "hbR" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -23110,15 +23560,6 @@ /obj/machinery/holopad, /turf/open/floor/iron/grimy, /area/station/service/chapel/office) -"hbT" = ( -/obj/machinery/vending/hydronutrients, -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark/side{ - dir = 1 - }, -/area/station/service/hydroponics) "hbY" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -23142,13 +23583,15 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"hcv" = ( -/obj/machinery/newscaster/directional/north, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 +"hcj" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 4 }, -/turf/open/floor/iron, -/area/station/hallway/primary/central) +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "hcw" = ( /obj/docking_port/stationary/random/icemoon{ dir = 8; @@ -23330,16 +23773,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/wood, /area/station/service/library) -"hfh" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/machinery/duct, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "hfm" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -23361,6 +23794,14 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/station/security/holding_cell) +"hfG" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "hfI" = ( /obj/machinery/light/directional/north, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -23371,6 +23812,26 @@ /obj/structure/closet/l3closet/scientist, /turf/open/floor/iron, /area/station/science/xenobiology) +"hfY" = ( +/obj/effect/turf_decal/siding/thinplating/dark/corner{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 6 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/sign/poster/official/the_owl/directional/south, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "hgc" = ( /obj/structure/table, /turf/open/floor/plating, @@ -23471,17 +23932,6 @@ /obj/effect/landmark/start/chemist, /turf/open/floor/iron/textured, /area/station/medical/chem_storage) -"hid" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red/half{ - dir = 4 - }, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/hallway/secondary/service) "hil" = ( /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, @@ -23512,6 +23962,16 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/service/hydroponics/garden) +"hjw" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "hjE" = ( /turf/closed/wall/r_wall, /area/station/science/explab) @@ -23531,6 +23991,14 @@ "hjM" = ( /turf/closed/wall/r_wall, /area/station/maintenance/department/medical/morgue) +"hjO" = ( +/obj/machinery/power/apc/auto_name/directional/south, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/wood/large, +/area/station/service/bar) "hjQ" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -23575,23 +24043,9 @@ }, /area/station/security/office) "hkd" = ( -/obj/structure/cable, /obj/machinery/light/small/directional/west, /turf/open/floor/plating, /area/station/maintenance/department/electrical) -"hkl" = ( -/obj/structure/table/wood, -/obj/effect/turf_decal/siding/wood/corner{ - dir = 8 - }, -/obj/structure/desk_bell{ - desc = "Why, I'm always here! I should get absolute service. Pronto, garcon!"; - name = "The Regular's Bell"; - pixel_x = -6 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "hkp" = ( /obj/effect/turf_decal/trimline/dark_blue/line{ dir = 8 @@ -23636,6 +24090,12 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) +"hlt" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/poster/contraband/random/directional/south, +/obj/structure/reagent_dispensers/water_cooler, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "hlv" = ( /obj/machinery/airalarm/directional/south, /obj/machinery/shower/directional/west, @@ -23649,16 +24109,6 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/iron, /area/mine/laborcamp) -"hlP" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 9 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 9 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "hlS" = ( /obj/structure/table, /obj/item/clothing/under/misc/burial, @@ -23689,15 +24139,6 @@ dir = 6 }, /area/station/security/prison) -"hml" = ( -/obj/effect/turf_decal/trimline/green/filled/corner{ - dir = 4 - }, -/obj/effect/turf_decal/trimline/blue/corner{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "hmt" = ( /obj/machinery/door/firedoor, /obj/structure/table/reinforced, @@ -23728,12 +24169,6 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) -"hnf" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "hno" = ( /obj/structure/sign/painting/library{ pixel_y = 32 @@ -23747,11 +24182,6 @@ }, /turf/open/floor/iron/dark/textured, /area/station/security/prison) -"hnB" = ( -/obj/structure/closet/secure_closet/hydroponics, -/obj/effect/turf_decal/siding/thinplating/dark, -/turf/open/floor/plating, -/area/station/service/hydroponics) "hnC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -23760,6 +24190,14 @@ }, /turf/open/floor/iron, /area/station/cargo/lobby) +"hnK" = ( +/obj/structure/table/wood, +/obj/item/wallframe/camera{ + pixel_y = -2; + pixel_x = 1 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "hnN" = ( /obj/machinery/camera/directional/west{ c_tag = "Xenobiology Pens Observation - Port Aft"; @@ -23791,6 +24229,16 @@ /obj/structure/extinguisher_cabinet/directional/north, /turf/open/floor/iron/white, /area/station/medical/pharmacy) +"hog" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 8 + }, +/obj/machinery/hydroponics/constructable, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "hos" = ( /obj/structure/disposalpipe/trunk/multiz/down{ dir = 1 @@ -23925,6 +24373,25 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/engineering/atmos) +"hpK" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "hpM" = ( /obj/machinery/door/airlock/external{ glass = 1; @@ -23986,6 +24453,16 @@ dir = 1 }, /area/station/commons/storage/art) +"hqv" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/atmospherics/components/binary/pump/off/supply/visible/layer4{ + dir = 1; + name = "Can In" + }, +/turf/open/floor/plating, +/area/station/maintenance/fore) "hqx" = ( /obj/effect/landmark/start/assistant, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -24014,6 +24491,14 @@ /obj/structure/sign/warning/radiation/rad_area, /turf/closed/wall/r_wall, /area/station/engineering/main) +"hrd" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible/layer4, +/obj/machinery/meter/layer4, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating, +/area/station/maintenance/fore) "hrh" = ( /obj/structure/chair/comfy/beige{ dir = 1 @@ -24029,9 +24514,14 @@ /obj/effect/turf_decal/tile/red/anticorner/contrasted, /turf/open/floor/iron/dark, /area/station/security/checkpoint/engineering) -"hrt" = ( -/obj/structure/table/glass, -/obj/item/shovel/spade, +"hrA" = ( +/obj/machinery/space_heater, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/structure/railing{ + dir = 6 + }, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) "hrJ" = ( @@ -24057,7 +24547,6 @@ /obj/structure/chair/office/light{ dir = 4 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/virology) "hsh" = ( @@ -24210,13 +24699,6 @@ /obj/machinery/vending/autodrobe/all_access, /turf/open/floor/iron, /area/station/commons/locker) -"hun" = ( -/obj/structure/disposalpipe/trunk{ - dir = 1 - }, -/obj/machinery/disposal/bin, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "huB" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -24304,34 +24786,22 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"hvl" = ( -/obj/effect/turf_decal/siding/white, -/obj/effect/spawner/random/entertainment/arcade, -/obj/structure/sign/poster/random/directional/north, -/obj/effect/turf_decal/siding/white{ - dir = 6 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +"hvi" = ( +/obj/structure/closet/crate/freezer/food{ + name = "cooler" + }, +/obj/item/reagent_containers/cup/glass/ice, +/obj/item/reagent_containers/cup/glass/ice, +/obj/item/reagent_containers/cup/glass/ice, +/obj/item/reagent_containers/cup/glass/ice, +/turf/open/misc/asteroid/snow/coldroom, +/area/icemoon/underground/explored) "hvm" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"hvr" = ( -/obj/machinery/door/airlock{ - name = "Hydroponics Backroom" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/firedoor, -/obj/machinery/duct, -/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, -/turf/open/floor/iron/textured_half{ - dir = 1 - }, -/area/station/service/hydroponics) "hvS" = ( /obj/effect/landmark/start/depsec/engineering, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -24390,21 +24860,6 @@ }, /turf/open/floor/iron, /area/station/cargo/office) -"hwM" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/structure/chair/sofa/corp/left{ - dir = 4; - pixel_x = -4; - pixel_y = 8 - }, -/obj/effect/landmark/start/hangover, -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/north, -/obj/structure/sign/poster/random/directional/west, -/turf/open/floor/iron/grimy, -/area/station/service/bar/atrium) "hwR" = ( /obj/machinery/camera/directional/west{ c_tag = "Security - Equipment Room" @@ -24434,6 +24889,13 @@ /obj/effect/turf_decal/tile/blue/full, /turf/open/floor/iron/large, /area/station/medical/treatment_center) +"hxB" = ( +/obj/machinery/door/airlock{ + id_tag = "Toilet2"; + name = "Unit 2" + }, +/turf/open/floor/iron/textured, +/area/station/commons/toilet) "hxE" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -24445,6 +24907,12 @@ dir = 5 }, /area/station/service/chapel) +"hxY" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/kitchen/coldroom) "hyd" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -24460,22 +24928,6 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/station/maintenance/disposal) -"hyt" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/airlock/maintenance{ - name = "Bar Maintenance" - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 8 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "hyC" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle, /obj/structure/cable, @@ -24487,6 +24939,16 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/aft/greater) +"hyQ" = ( +/obj/effect/turf_decal/tile/blue{ + dir = 1 + }, +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, +/obj/effect/landmark/navigate_destination/hydro, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "hyV" = ( /turf/closed/wall/r_wall, /area/station/science/ordnance/testlab) @@ -24500,6 +24962,12 @@ /obj/structure/stairs/north, /turf/open/floor/iron, /area/station/service/chapel) +"hzw" = ( +/obj/structure/fence/cut/large{ + dir = 1 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "hzz" = ( /obj/structure/table/glass, /obj/item/clothing/gloves/latex, @@ -24551,13 +25019,6 @@ }, /turf/open/openspace, /area/station/ai_monitored/security/armory/upper) -"hzQ" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/structure/chair/stool/bar/directional/east, -/turf/open/floor/stone, -/area/station/commons/lounge) "hzY" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ @@ -24589,6 +25050,12 @@ }, /turf/open/floor/iron/large, /area/station/hallway/secondary/entry) +"hAK" = ( +/obj/machinery/holopad, +/obj/effect/spawner/random/engineering/tracking_beacon, +/obj/effect/turf_decal/bot, +/turf/open/floor/iron/dark/smooth_half, +/area/station/service/hydroponics) "hAO" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -24608,6 +25075,10 @@ }, /turf/open/floor/iron, /area/station/security/brig/upper) +"hAS" = ( +/obj/machinery/light/cold/directional/east, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "hAT" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -24619,17 +25090,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/science/genetics) -"hBc" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/structure/chair{ - dir = 8 - }, -/obj/structure/sign/poster/random/directional/north, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) +"hAW" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "hBd" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, @@ -24678,17 +25142,6 @@ }, /turf/open/floor/iron, /area/station/service/hydroponics/garden) -"hBR" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/duct, -/obj/effect/landmark/event_spawn, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "hBZ" = ( /obj/structure/table/wood, /obj/item/radio/intercom/command, @@ -24736,15 +25189,6 @@ /obj/machinery/newscaster/directional/north, /turf/open/floor/iron/white, /area/station/medical/chemistry) -"hCN" = ( -/obj/structure/chair/sofa/right/brown{ - desc = "Hey, did you know you can get a pineapple on your burger here?"; - dir = 1; - name = "The Regular's Sofa" - }, -/obj/effect/landmark/start/hangover, -/turf/open/floor/stone, -/area/station/commons/lounge) "hCV" = ( /obj/structure/table/wood, /obj/item/hand_tele{ @@ -24793,6 +25237,20 @@ "hDp" = ( /turf/open/floor/engine, /area/station/science/genetics) +"hDu" = ( +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/obj/machinery/power/apc/auto_name/directional/east, +/obj/structure/cable, +/obj/item/stack/package_wrap{ + pixel_y = 2 + }, +/obj/item/book/manual/chef_recipes, +/obj/item/holosign_creator/robot_seat/restaurant, +/obj/structure/rack, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "hDA" = ( /obj/effect/turf_decal/stripes/line, /turf/open/floor/plating/icemoon, @@ -24832,10 +25290,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/fore) -"hEl" = ( -/obj/machinery/portable_atmospherics/canister/air, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "hEm" = ( /obj/structure/closet/emcloset, /turf/open/floor/iron/dark, @@ -24855,6 +25309,12 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"hEV" = ( +/obj/structure/table/wood/poker, +/obj/effect/spawner/random/bureaucracy/briefcase, +/obj/item/taperecorder/empty, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "hEW" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk{ @@ -24882,6 +25342,14 @@ /obj/structure/frame/machine, /turf/open/floor/plating, /area/station/construction) +"hFj" = ( +/obj/machinery/computer/security/telescreen/entertainment/directional/south, +/obj/machinery/status_display/evac/directional/east, +/obj/structure/chair/sofa/right/brown{ + dir = 1 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "hFr" = ( /obj/structure/flora/grass/both/style_2, /turf/open/misc/asteroid/snow/icemoon, @@ -24922,17 +25390,22 @@ /obj/machinery/vending/wardrobe/det_wardrobe, /turf/open/floor/iron/grimy, /area/station/security/detectives_office) -"hGf" = ( -/obj/item/clothing/suit/hooded/wintercoat, -/obj/effect/decal/remains/human, -/obj/item/clothing/head/beanie/orange{ - pixel_y = 8 +"hFX" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 }, -/obj/item/clothing/shoes/wheelys/skishoes{ - pixel_y = -8 +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"hGg" = ( +/obj/structure/sign/warning/directional/west{ + desc = "A sign warning to watch for moving minecarts beyond this point." }, -/turf/open/misc/asteroid/snow/icemoon, -/area/icemoon/surface/outdoors/nospawn) +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/light/small/directional/west, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "hGh" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -24951,12 +25424,6 @@ "hGH" = ( /turf/closed/wall, /area/station/security/lockers) -"hGI" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/hydroponics) "hGZ" = ( /obj/structure/table, /obj/item/analyzer, @@ -25025,9 +25492,6 @@ "hHN" = ( /turf/open/floor/iron, /area/station/engineering/atmos) -"hHU" = ( -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "hHV" = ( /obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/nitrogen_output{ dir = 1 @@ -25053,6 +25517,15 @@ }, /turf/open/floor/plating, /area/station/engineering/atmos/pumproom) +"hIE" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/camera/directional/south{ + c_tag = "Service - Electrical Maintenace Lower" + }, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/station/maintenance/starboard/lesser) "hIH" = ( /obj/machinery/door/airlock/maintenance, /obj/structure/cable, @@ -25095,12 +25568,6 @@ /obj/structure/cable, /turf/open/floor/engine, /area/station/science/xenobiology) -"hJm" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 8 - }, -/turf/open/floor/wood/tile, -/area/station/service/theater) "hJp" = ( /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 1 @@ -25132,6 +25599,11 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron, /area/station/hallway/primary/central) +"hJF" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/sign/warning/directional/south, +/turf/open/floor/plating, +/area/station/maintenance/fore) "hJG" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/effect/decal/cleanable/dirt, @@ -25140,21 +25612,33 @@ }, /turf/open/floor/iron, /area/station/commons/locker) +"hJS" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 1 + }, +/obj/machinery/duct, +/obj/effect/turf_decal/siding/dark{ + dir = 10 + }, +/turf/open/floor/iron/checker, +/area/station/hallway/secondary/service) "hJY" = ( /obj/structure/closet/l3closet/janitor, /obj/machinery/airalarm/directional/north, /turf/open/floor/iron, /area/station/service/janitor) -"hKj" = ( -/obj/machinery/atmospherics/components/binary/pump/off, -/obj/machinery/airlock_sensor/incinerator_ordmix{ - pixel_x = 24 +"hKn" = ( +/obj/machinery/biogenerator, +/obj/machinery/door/window/left/directional/south{ + name = "Biogenerator Access"; + req_access = list("hydroponics") }, -/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden{ - dir = 4 +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 }, -/turf/open/floor/engine, -/area/station/science/ordnance/burnchamber) +/obj/effect/turf_decal/tile/blue/opposingcorners, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "hKr" = ( /obj/structure/table/glass, /obj/item/book/manual/wiki/infections{ @@ -25191,6 +25675,12 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron, /area/station/tcommsat/computer) +"hKL" = ( +/obj/effect/turf_decal/tile/bar{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "hKT" = ( /obj/machinery/light/floor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -25223,11 +25713,17 @@ }, /turf/open/floor/iron, /area/mine/laborcamp) -"hLw" = ( -/obj/item/radio/intercom/directional/north, -/obj/structure/table/wood, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) +"hLy" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "hLO" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -25272,16 +25768,18 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/primary/port) -"hMk" = ( -/obj/machinery/light/directional/west, -/turf/open/floor/iron, -/area/station/service/hydroponics) "hMr" = ( /obj/effect/landmark/start/chaplain, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/carpet, /area/station/service/chapel) +"hMs" = ( +/obj/effect/landmark/start/hangover, +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "hMw" = ( /obj/structure/bookcase/random/fiction, /turf/open/floor/plating, @@ -25325,6 +25823,21 @@ }, /turf/open/floor/iron/smooth, /area/mine/laborcamp/security) +"hMM" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/hallway/secondary/service) "hMS" = ( /obj/machinery/light/small/directional/south, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -25347,13 +25860,6 @@ /obj/item/radio/intercom/directional/south, /turf/open/floor/wood, /area/station/service/lawoffice) -"hNi" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "hNx" = ( /obj/machinery/camera/directional/south{ c_tag = "Holodeck - South"; @@ -25383,6 +25889,11 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/supermatter/room) +"hNK" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "hNM" = ( /obj/structure/sign/warning/no_smoking/directional/north, /obj/structure/cable, @@ -25496,6 +26007,19 @@ /obj/effect/turf_decal/trimline/yellow/filled/line, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"hPS" = ( +/obj/effect/landmark/start/botanist, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/structure/sign/calendar/directional/north, +/obj/machinery/camera{ + c_tag = "Service - Botany Equipment"; + dir = 9 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "hPT" = ( /obj/effect/turf_decal/stripes/line{ dir = 6 @@ -25659,14 +26183,6 @@ /obj/effect/decal/cleanable/generic, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"hSb" = ( -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 8 - }, -/obj/effect/spawner/random/structure/musician/piano/random_piano, -/obj/structure/sign/poster/random/directional/north, -/turf/open/floor/carpet, -/area/station/service/theater) "hSl" = ( /obj/effect/turf_decal/trimline/neutral/mid_joiner{ dir = 8 @@ -25891,20 +26407,18 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/white, /area/station/maintenance/port/fore) -"hWh" = ( -/obj/structure/sink/directional/west, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "hWi" = ( /obj/machinery/teleport/hub, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat_interior) +"hWv" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/middle, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 2; + id = "botany_chasm_and_wolf_shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) "hWI" = ( /obj/effect/turf_decal/box, /obj/effect/spawner/random/structure/closet_empty/crate/with_loot, @@ -25912,19 +26426,6 @@ /obj/structure/sign/poster/official/wtf_is_co2/directional/north, /turf/open/floor/iron/dark, /area/station/maintenance/starboard/aft) -"hWP" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Central Access" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "hWV" = ( /obj/machinery/light/small/directional/north, /obj/machinery/space_heater, @@ -25945,6 +26446,18 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/medical/morgue) +"hXm" = ( +/obj/effect/spawner/random/vending/colavend, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/hallway/primary/central) +"hXt" = ( +/obj/machinery/camera{ + c_tag = "Starboard Primary Hallway Center East" + }, +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "hXC" = ( /obj/structure/chair{ dir = 8 @@ -25956,6 +26469,15 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"hXD" = ( +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/effect/turf_decal/bot_red, +/obj/effect/turf_decal/siding/white, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "hXU" = ( /obj/machinery/newscaster/directional/east, /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, @@ -25975,19 +26497,12 @@ /obj/effect/landmark/navigate_destination/disposals, /turf/open/floor/plating, /area/station/maintenance/port/lesser) -"hYs" = ( -/obj/machinery/chem_master/condimaster{ - desc = "Looks like a knock-off chem-master. Perhaps useful for separating liquids when mixing drinks precisely. Also dispenses condiments."; - name = "HoochMaster Deluxe" - }, -/obj/effect/turf_decal/siding/white/end{ - dir = 4 +"hYt" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/obj/machinery/power/apc/auto_name/directional/east, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/service/bar) +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "hYy" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -25996,14 +26511,6 @@ /obj/item/kirbyplants/random, /turf/open/floor/wood, /area/station/security/prison/rec) -"hYC" = ( -/obj/structure/closet/athletic_mixed, -/obj/effect/landmark/start/hangover/closet, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "hYP" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -26039,10 +26546,6 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"iao" = ( -/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, -/turf/closed/wall/r_wall, -/area/station/science/ordnance/burnchamber) "iar" = ( /obj/structure/cable, /obj/machinery/door/poddoor/preopen{ @@ -26115,13 +26618,6 @@ }, /turf/open/floor/iron/white, /area/station/science/ordnance/office) -"ibi" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/duct, -/turf/open/floor/wood/tile, -/area/station/service/theater) "ibj" = ( /obj/structure/closet/firecloset, /turf/open/floor/plating, @@ -26185,13 +26681,6 @@ }, /turf/open/floor/wood, /area/station/security/prison/rec) -"ibI" = ( -/obj/structure/chair/stool/directional/south, -/obj/machinery/camera/directional/north{ - c_tag = "Starboard Primary Hallway West" - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "ibM" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle{ dir = 4 @@ -26374,22 +26863,12 @@ }, /turf/open/floor/iron/smooth, /area/station/security/holding_cell) -"idw" = ( -/obj/structure/table/glass, -/obj/item/clothing/accessory/armband/hydro, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 9 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 9 +"idH" = ( +/obj/structure/railing/wooden_fence{ + dir = 6 }, -/obj/item/paper/guides/jobs/hydroponics, -/turf/open/floor/iron, -/area/station/service/hydroponics) -"idE" = ( -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "idN" = ( /obj/structure/window/reinforced/spawner/directional/north, /obj/machinery/door/window/brigdoor/left/directional/south{ @@ -26407,17 +26886,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/hallway/primary/port) -"ieq" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) +"iew" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/turf/open/floor/iron, +/area/station/service/bar) "ieG" = ( /obj/effect/turf_decal/stripes/corner{ dir = 4 @@ -26432,32 +26904,20 @@ /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron, /area/mine/laborcamp/security) +"ifd" = ( +/obj/item/radio/intercom/directional/north, +/obj/machinery/light/directional/north, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "ife" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/atmos) -"ifg" = ( -/obj/effect/turf_decal/siding/white, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) -"ifw" = ( -/obj/structure/table/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 8; - id = "kitchencounter"; - name = "Kitchen Counter Shutters" - }, -/obj/machinery/door/firedoor, -/obj/structure/desk_bell{ - pixel_x = 7 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "ifA" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/warning/cold_temp, @@ -26481,14 +26941,6 @@ /obj/item/soap/nanotrasen, /turf/open/floor/iron/showroomfloor, /area/station/security/prison/toilet) -"igi" = ( -/obj/item/kirbyplants/organic/plant10, -/obj/machinery/camera/directional/west{ - c_tag = "Service Bar Staircase" - }, -/obj/item/radio/intercom/directional/west, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "igm" = ( /turf/closed/wall/ice, /area/mine/living_quarters) @@ -26501,6 +26953,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/eva/lower) +"igu" = ( +/obj/effect/spawner/random/engineering/atmospherics_portable, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "igx" = ( /obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ dir = 5 @@ -26511,6 +26967,15 @@ /obj/machinery/firealarm/directional/west, /turf/open/floor/glass, /area/station/security/lockers) +"igH" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/effect/decal/cleanable/cobweb, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "igL" = ( /obj/structure/cable/multilayer/multiz, /obj/effect/turf_decal/stripes/box, @@ -26545,14 +27010,6 @@ /obj/effect/spawner/random/trash/mess, /turf/open/floor/wood/large, /area/station/commons/vacant_room/office) -"ihf" = ( -/obj/effect/turf_decal/siding/white{ - dir = 10 - }, -/obj/machinery/firealarm/directional/west, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "ihk" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -26577,12 +27034,6 @@ /obj/structure/cable, /turf/open/floor/iron/dark/textured, /area/station/security/execution/transfer) -"ihG" = ( -/obj/structure/chair/sofa/corp/left{ - dir = 1 - }, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "ihN" = ( /obj/machinery/button/door/directional/west{ id = "xenobio4"; @@ -26592,6 +27043,17 @@ }, /turf/open/floor/iron/white, /area/station/science/xenobiology) +"iif" = ( +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/obj/machinery/biogenerator, +/turf/open/floor/iron, +/area/station/service/hydroponics) "iih" = ( /obj/effect/spawner/xmastree, /obj/effect/turf_decal/tile/neutral{ @@ -26618,6 +27080,17 @@ }, /turf/open/floor/iron, /area/station/cargo/lobby) +"iiB" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/service/hydroponics) "iiH" = ( /obj/machinery/door/airlock/security/glass{ id_tag = "innerbrig"; @@ -26696,6 +27169,14 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"ijw" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/confetti, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "ijC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -26745,6 +27226,10 @@ /obj/effect/turf_decal/tile/brown/opposingcorners, /turf/open/floor/iron, /area/station/cargo/storage) +"ike" = ( +/obj/structure/fence/cut/medium, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/nospawn) "ikk" = ( /obj/structure/disposalpipe/sorting/mail/flip{ dir = 4 @@ -26771,10 +27256,6 @@ /obj/machinery/computer/security/telescreen/entertainment/directional/north, /turf/open/floor/wood, /area/station/service/library) -"iko" = ( -/obj/machinery/airalarm/directional/north, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "iku" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -26800,14 +27281,6 @@ /obj/machinery/light/directional/east, /turf/open/floor/iron, /area/station/hallway/primary/central) -"ikH" = ( -/obj/machinery/camera{ - c_tag = "Starboard Primary Hallway Center" - }, -/obj/structure/cable, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "ikI" = ( /obj/item/gun/energy/laser/carbine/practice{ pixel_y = 5 @@ -26828,17 +27301,6 @@ }, /turf/open/floor/plating, /area/station/command/heads_quarters/qm) -"ikT" = ( -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/sorting/mail{ - dir = 4 - }, -/obj/effect/mapping_helpers/mail_sorting/service/bar, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "ikW" = ( /obj/structure/railing/corner{ dir = 8 @@ -26896,6 +27358,14 @@ /obj/effect/spawner/random/structure/steam_vent, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"imk" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment, +/obj/item/rack_parts, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "imy" = ( /obj/machinery/airalarm/directional/east, /turf/open/floor/iron/dark, @@ -26907,6 +27377,15 @@ /obj/item/clothing/mask/breath, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"imI" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 9 + }, +/obj/item/kirbyplants/random, +/obj/machinery/light/warm/directional/south, +/obj/machinery/digital_clock/directional/south, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "imO" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -26926,10 +27405,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/chemistry) -"inb" = ( -/obj/machinery/door/poddoor/incinerator_ordmix, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance/burnchamber) "inh" = ( /obj/structure/stairs/west, /obj/structure/railing, @@ -26940,6 +27415,14 @@ /obj/structure/falsewall, /turf/open/floor/plating, /area/station/maintenance/port/lesser) +"int" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/structure/sign/departments/botany/directional/west, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "inE" = ( /turf/open/floor/iron/corner, /area/station/engineering/lobby) @@ -26951,6 +27434,31 @@ /obj/machinery/light/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/central) +"inN" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/structure/cable, +/obj/machinery/button/door/directional/south{ + id = "minecraft_shutter"; + req_one_access = list("hydroponics", "kitchen"); + name = "Cart Access"; + desc = "Opens the railway leading into the Kitchen Coldroom." + }, +/obj/structure/minecart_rail/railbreak{ + dir = 4 + }, +/obj/structure/closet/crate/miningcar{ + name = "delivery cart"; + desc = "Used for quick transit of fresh produce to the kitchen. Just give it a shove." + }, +/obj/item/storage/bag/plants, +/turf/open/floor/iron, +/area/station/service/hydroponics) "inQ" = ( /obj/structure/table/wood, /obj/item/paper_bin/carbon{ @@ -26999,6 +27507,10 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) +"ion" = ( +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "ior" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -27069,6 +27581,18 @@ "ipf" = ( /turf/open/genturf, /area/icemoon/underground/unexplored/rivers/deep/shoreline) +"ipg" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/obj/structure/curtain/cloth/fancy/mechanical/start_closed{ + id = "cantena_curtains" + }, +/turf/open/floor/wood, +/area/station/commons/lounge) "ipw" = ( /obj/structure/rack, /obj/effect/spawner/random/maintenance/two, @@ -27153,18 +27677,15 @@ /obj/structure/lattice/catwalk, /turf/open/openspace, /area/station/science/ordnance/office) +"iqA" = ( +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "iqC" = ( /obj/structure/table, /obj/item/flashlight/lamp, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"iqL" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "irp" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -27183,22 +27704,6 @@ /obj/structure/grille, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) -"irz" = ( -/obj/machinery/door/airlock/external{ - glass = 1; - name = "Service External Airlock"; - opacity = 0 - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/structure/sign/warning/cold_temp/directional/north, -/obj/structure/sign/warning/gas_mask/directional/south{ - desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." - }, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "irA" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/iron/white, @@ -27294,6 +27799,10 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/central) +"isj" = ( +/obj/effect/decal/cleanable/oil, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "isl" = ( /obj/structure/fence/door{ name = "graveyard" @@ -27421,6 +27930,10 @@ /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 8 }, +/obj/machinery/chem_master/condimaster{ + desc = "Used to separate out liquids - useful for purifying botanical extracts. Also dispenses condiments."; + name = "SapMaster XP" + }, /turf/open/floor/iron, /area/station/service/hydroponics) "iuH" = ( @@ -27449,6 +27962,11 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron, /area/station/hallway/primary/central) +"ivp" = ( +/obj/structure/flora/bush/flowers_yw/style_random, +/obj/structure/flora/bush/sparsegrass/style_random, +/turf/open/floor/grass, +/area/station/service/hydroponics) "ivq" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/red{ @@ -27456,13 +27974,22 @@ }, /turf/open/floor/iron, /area/mine/laborcamp/security) -"ivr" = ( -/turf/open/floor/grass, -/area/station/service/hydroponics) "ivB" = ( /obj/structure/closet/emcloset, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"ivC" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 4 + }, +/obj/structure/railing{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "ivF" = ( /turf/closed/wall, /area/station/maintenance/disposal) @@ -27477,6 +28004,11 @@ }, /turf/open/floor/wood, /area/station/service/library) +"ivJ" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/structure/sign/poster/official/random/directional/north, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "iwf" = ( /turf/closed/wall/r_wall, /area/mine/mechbay) @@ -27487,6 +28019,9 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"iwq" = ( +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "iwx" = ( /obj/machinery/door/airlock/maintenance{ name = "Xenobiology Maintenance" @@ -27537,6 +28072,21 @@ }, /turf/open/floor/iron/grimy, /area/station/commons/vacant_room/office) +"ixp" = ( +/obj/machinery/door/airlock/wood{ + name = "Bar Backroom" + }, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wood, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/access/all/service/bar, +/turf/open/floor/iron/dark/textured_half, +/area/station/service/bar/backroom) "ixu" = ( /obj/machinery/camera/directional/north{ c_tag = "Teleporter" @@ -27569,15 +28119,6 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/dark, /area/station/engineering/engine_smes) -"ixH" = ( -/obj/structure/railing/corner{ - dir = 1 - }, -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "ixZ" = ( /obj/machinery/door/airlock/command/glass{ name = "Chief Engineer" @@ -27591,13 +28132,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) -"iyb" = ( -/obj/structure/chair/wood{ - dir = 4 - }, -/obj/machinery/barsign/all_access/directional/north, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "iyd" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 9 @@ -27660,15 +28194,6 @@ /obj/effect/spawner/structure/window/reinforced/tinted, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) -"izc" = ( -/obj/machinery/atmospherics/components/binary/pump/on{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/layer_manifold/scrubbers/hidden{ - dir = 8 - }, -/turf/open/floor/engine, -/area/station/science/ordnance/burnchamber) "izn" = ( /obj/effect/spawner/random/decoration/generic, /turf/open/floor/plating, @@ -27743,16 +28268,18 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/medical/chemistry) +"izU" = ( +/obj/structure/table/wood, +/obj/item/instrument/saxophone, +/obj/item/instrument/piano_synth, +/obj/effect/turf_decal/siding/wood, +/turf/open/floor/iron/grimy, +/area/station/commons/lounge) "izY" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/prison/visit) -"iAa" = ( -/obj/effect/turf_decal/caution/stand_clear, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron/dark/textured, -/area/station/hallway/secondary/service) "iAf" = ( /turf/closed/wall/mineral/wood, /area/station/maintenance/space_hut/cabin) @@ -27797,20 +28324,6 @@ }, /turf/open/floor/iron/dark, /area/mine/laborcamp) -"iAJ" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/obj/structure/table, -/obj/item/reagent_containers/condiment/saltshaker{ - pixel_x = -3 - }, -/obj/item/reagent_containers/condiment/peppermill{ - pixel_x = 3 - }, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "iAO" = ( /obj/effect/turf_decal/trimline/blue/filled/corner{ dir = 1 @@ -27894,6 +28407,10 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/cargo/sorting) +"iBM" = ( +/obj/structure/chair/wood, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "iBO" = ( /obj/machinery/modular_computer/preset/civilian{ dir = 4 @@ -27902,6 +28419,10 @@ dir = 4 }, /area/station/science/explab) +"iCe" = ( +/obj/machinery/atmospherics/pipe/smart/simple/dark/visible, +/turf/closed/wall/r_wall, +/area/station/science/ordnance) "iCg" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -27941,15 +28462,6 @@ }, /turf/open/floor/plating, /area/station/science/robotics/lab) -"iCC" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "iCD" = ( /obj/machinery/door/airlock/external{ name = "External Access" @@ -27968,13 +28480,16 @@ }, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"iCQ" = ( -/obj/structure/closet/lasertag/red, -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ +"iCS" = ( +/obj/effect/turf_decal/siding/wood{ dir = 4 }, -/turf/open/floor/iron, -/area/station/commons/fitness) +/obj/structure/chair/stool/bar/directional/east, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "iCX" = ( /obj/machinery/power/solar_control{ dir = 4; @@ -27984,11 +28499,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/solars/port/aft) -"iDg" = ( -/obj/machinery/duct, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "iDp" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/closed/wall, @@ -28008,6 +28518,25 @@ /obj/item/kirbyplants/random, /turf/open/floor/wood, /area/station/security/prison/rec) +"iDv" = ( +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"iDx" = ( +/obj/structure/railing/wooden_fence{ + dir = 4 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) +"iDB" = ( +/obj/structure/table/wood, +/obj/item/circuitboard/machine/fax, +/obj/structure/frame/machine, +/obj/item/stack/cable_coil/five, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "iDG" = ( /obj/machinery/door/window/left/directional/east{ name = "Containment Pen 3"; @@ -28019,6 +28548,16 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/science/xenobiology) +"iDK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/turf/open/floor/wood, +/area/station/commons/lounge) "iDQ" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/simple/dark/visible, @@ -28077,14 +28616,11 @@ dir = 4 }, /area/station/hallway/secondary/entry) -"iFc" = ( -/obj/effect/turf_decal/tile/red/half{ - dir = 4 - }, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/hallway/secondary/service) +"iEY" = ( +/obj/machinery/restaurant_portal/bar, +/obj/effect/turf_decal/delivery/red, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "iFe" = ( /obj/structure/cable, /turf/open/floor/iron/dark/smooth_half, @@ -28117,11 +28653,29 @@ }, /turf/open/floor/iron, /area/station/command/bridge) +"iFz" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/obj/machinery/holopad, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "iFL" = ( /obj/structure/bed/dogbed/renault, /mob/living/basic/pet/fox/renault, /turf/open/floor/wood, /area/station/command/heads_quarters/captain) +"iFQ" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "iFX" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -28175,19 +28729,6 @@ "iHp" = ( /turf/closed/wall/r_wall, /area/station/ai_monitored/turret_protected/ai) -"iHy" = ( -/obj/structure/chair/wood{ - dir = 4 - }, -/obj/effect/landmark/start/bartender, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) -"iHz" = ( -/obj/machinery/power/apc/auto_name/directional/north, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/fore) "iHV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -28213,22 +28754,29 @@ /obj/machinery/light/cold/directional/west, /turf/open/floor/iron/dark/smooth_large, /area/station/medical/storage) -"iIa" = ( -/obj/structure/cable, -/obj/structure/railing, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "iIe" = ( /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/disposalpipe/segment, /obj/structure/cable, /turf/open/floor/iron/white, /area/station/science/robotics/lab) +"iIk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/starboard) "iIs" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/simple/dark/visible, @@ -28237,6 +28785,15 @@ }, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) +"iIv" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/reagent_containers/cup/bucket{ + pixel_y = 10; + pixel_x = -4 + }, +/obj/machinery/duct, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "iIA" = ( /obj/effect/turf_decal/bot, /turf/open/floor/iron, @@ -28456,29 +29013,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/mix) -"iMg" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/light/small/directional/east, -/obj/machinery/duct, -/turf/open/floor/wood/tile, -/area/station/service/theater) -"iMj" = ( -/obj/structure/closet/lasertag/blue, -/obj/effect/landmark/start/hangover/closet, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) -"iMo" = ( -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "iMp" = ( /obj/machinery/status_display/ai/directional/east, /turf/open/floor/circuit, @@ -28542,19 +29076,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/science/genetics) -"iNt" = ( -/obj/machinery/vending/hydroseeds{ - slogan_delay = 700 - }, -/obj/effect/turf_decal/trimline/green/filled/line, -/obj/effect/turf_decal/trimline/blue/filled/warning, -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark/side{ - dir = 1 - }, -/area/station/service/hydroponics) "iNy" = ( /obj/structure/chair{ dir = 4 @@ -28667,6 +29188,17 @@ }, /turf/open/floor/iron/dark, /area/station/commons/storage/mining) +"iPP" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/landmark/start/bartender, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/landmark/event_spawn, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/bar) "iPR" = ( /obj/structure/closet/emcloset, /turf/open/floor/plating, @@ -28677,20 +29209,6 @@ dir = 4 }, /area/station/security/brig/entrance) -"iQf" = ( -/obj/machinery/door/airlock/external{ - name = "Service Hall Exit" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "service-hall-external" - }, -/obj/structure/sign/warning/cold_temp/directional/north, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/turf/open/floor/iron/dark/textured, -/area/station/hallway/secondary/service) "iQj" = ( /obj/item/radio/intercom/directional/north, /obj/structure/table/glass, @@ -28764,6 +29282,9 @@ }, /turf/open/floor/iron/white/corner, /area/station/hallway/secondary/entry) +"iRa" = ( +/turf/open/floor/catwalk_floor/iron_dark, +/area/station/maintenance/fore) "iRc" = ( /obj/structure/table, /obj/item/stack/cable_coil{ @@ -28843,6 +29364,20 @@ /obj/structure/sign/warning/radiation/directional/west, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"iRS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/door/airlock/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "iRV" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -28855,12 +29390,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/mine/laborcamp/security) -"iSi" = ( -/obj/effect/landmark/generic_maintenance_landmark, -/obj/structure/cable, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "iSk" = ( /obj/structure/lattice/catwalk, /obj/structure/railing{ @@ -28975,6 +29504,13 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/engine/plasma, /area/station/engineering/atmos) +"iUi" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/duct, +/turf/open/floor/wood/large, +/area/station/service/bar) "iUm" = ( /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, @@ -29034,10 +29570,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/engineering/supermatter) -"iUO" = ( -/obj/structure/flora/bush/flowers_pp/style_random, -/turf/open/floor/grass, -/area/station/service/hydroponics) "iUT" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -29076,6 +29608,13 @@ }, /turf/open/floor/iron, /area/mine/eva/lower) +"iVu" = ( +/obj/effect/turf_decal/tile/red{ + dir = 4 + }, +/obj/machinery/airalarm/directional/north, +/turf/open/floor/iron/textured, +/area/station/security/brig) "iVA" = ( /obj/effect/landmark/start/shaft_miner, /turf/open/floor/iron, @@ -29112,9 +29651,6 @@ /obj/machinery/light/small/dim/directional/south, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"iWr" = ( -/turf/closed/wall, -/area/station/service/kitchen/diner) "iWI" = ( /obj/structure/lattice/catwalk, /obj/structure/window/reinforced/spawner/directional/south, @@ -29201,6 +29737,13 @@ }, /turf/open/floor/iron/white, /area/station/science/xenobiology) +"iXB" = ( +/obj/effect/turf_decal/siding/wideplating/dark{ + dir = 1 + }, +/obj/machinery/hydroponics/soil, +/turf/open/floor/grass, +/area/station/maintenance/starboard/fore) "iXC" = ( /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, @@ -29211,20 +29754,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"iXF" = ( -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 6 - }, -/turf/open/floor/carpet, -/area/station/service/theater) -"iXH" = ( -/obj/effect/turf_decal/siding/white, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "iXP" = ( /obj/machinery/holopad, /obj/effect/turf_decal/box/white{ @@ -29235,16 +29764,6 @@ "iYb" = ( /turf/closed/wall, /area/station/maintenance/central/greater) -"iYi" = ( -/obj/structure/table/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 8; - id = "kitchencounter"; - name = "Kitchen Counter Shutters" - }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "iYs" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -29287,6 +29806,12 @@ }, /turf/open/floor/iron/textured, /area/station/security/brig) +"iYY" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/sink/directional/south, +/obj/structure/mirror/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "iZl" = ( /obj/effect/spawner/structure/window, /obj/machinery/door/poddoor/shutters/preopen{ @@ -29308,16 +29833,6 @@ /obj/effect/turf_decal/trimline/yellow/line, /turf/open/floor/iron/dark/side, /area/station/security/prison/workout) -"iZp" = ( -/obj/structure/chair/sofa/right/brown{ - dir = 4 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "iZq" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -29336,16 +29851,16 @@ /obj/machinery/airalarm/directional/south, /turf/open/floor/iron/white, /area/station/medical/cryo) -"iZy" = ( -/obj/effect/turf_decal/siding/wideplating/dark{ - dir = 1 - }, -/obj/machinery/hydroponics/constructable, -/turf/open/floor/grass, -/area/station/maintenance/starboard/fore) "iZz" = ( /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/labor_camp) +"iZD" = ( +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/machinery/griddle, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "iZO" = ( /obj/machinery/status_display/ai/directional/west, /obj/effect/turf_decal/tile/yellow/opposingcorners, @@ -29381,6 +29896,12 @@ }, /turf/open/floor/iron/freezer, /area/station/commons/toilet/locker) +"jae" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "jag" = ( /obj/machinery/ai_slipper{ uses = 10 @@ -29400,6 +29921,10 @@ /obj/effect/landmark/start/head_of_personnel, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) +"jas" = ( +/obj/structure/fence, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/nospawn) "jaw" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -29489,6 +30014,23 @@ /obj/effect/turf_decal/tile/blue/full, /turf/open/floor/iron/white/smooth_large, /area/station/medical/storage) +"jbB" = ( +/obj/structure/beebox, +/obj/machinery/status_display/ai/directional/north, +/obj/effect/turf_decal/siding/thinplating/dark/corner, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 9 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/camera{ + c_tag = "Service - Botany Apiary"; + dir = 9 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "jbC" = ( /obj/machinery/door/firedoor, /obj/effect/turf_decal/stripes/line{ @@ -29544,6 +30086,17 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) +"jcy" = ( +/obj/machinery/camera/directional/north{ + c_tag = "Central Hallway North-East" + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/obj/structure/sign/poster/official/random/directional/north, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "jcC" = ( /obj/machinery/requests_console/directional/north{ department = "Ordnance"; @@ -29606,6 +30159,22 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"jed" = ( +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/starboard) +"jee" = ( +/obj/structure/girder, +/obj/effect/spawner/random/structure/grille, +/turf/open/floor/plating, +/area/station/maintenance/fore) "jeh" = ( /obj/machinery/atmospherics/components/unary/outlet_injector/monitored/oxygen_input{ dir = 1 @@ -29667,35 +30236,19 @@ "jfc" = ( /turf/closed/wall, /area/station/command/heads_quarters/hop) -"jfN" = ( -/obj/structure/stairs/south, -/obj/structure/railing{ - dir = 8 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "jfR" = ( /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron, /area/station/command/gateway) -"jfZ" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) -"jgh" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Canteen" - }, -/obj/structure/disposalpipe/segment{ - dir = 4 +"jgd" = ( +/obj/machinery/camera/directional/north{ + c_tag = "Starboard Primary Hallway West" }, -/turf/open/floor/iron/textured_half{ - dir = 1 +/obj/structure/sign/nanotrasen{ + pixel_y = 32 }, -/area/station/service/kitchen/diner) +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "jgl" = ( /obj/effect/turf_decal/trimline/dark_blue/corner{ dir = 1 @@ -29739,6 +30292,12 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/white, /area/station/maintenance/port/fore) +"jhu" = ( +/obj/effect/spawner/random/maintenance/three, +/obj/structure/closet/crate/wooden, +/obj/effect/spawner/random/clothing/twentyfive_percent_cyborg_mask, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "jhy" = ( /obj/effect/turf_decal/tile/brown, /turf/open/floor/iron, @@ -29783,6 +30342,54 @@ /obj/effect/landmark/blobstart, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"jik" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 6 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 6 + }, +/obj/structure/table/glass, +/obj/machinery/light/small/directional/east, +/obj/machinery/firealarm/directional/east, +/obj/item/food/grown/poppy{ + pixel_y = -1; + pixel_x = 3 + }, +/obj/item/food/grown/poppy/geranium{ + pixel_y = 5; + pixel_x = 2 + }, +/obj/item/food/grown/poppy/lily{ + pixel_x = -2 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) +"jiD" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/structure/table/glass, +/obj/item/book/manual/hydroponics_pod_people, +/obj/structure/extinguisher_cabinet/directional/west, +/obj/structure/sign/poster/contraband/kudzu/directional/north, +/obj/machinery/light/small/directional/west, +/obj/item/plant_analyzer, +/obj/item/watertank{ + pixel_y = -3; + pixel_x = -5 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) +"jiU" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/turf/open/floor/iron, +/area/station/commons/fitness) "jjk" = ( /obj/structure/lattice/catwalk, /obj/structure/railing{ @@ -29823,14 +30430,6 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/medical/chemistry) -"jjG" = ( -/obj/item/instrument/harmonica, -/obj/item/instrument/guitar, -/obj/machinery/airalarm/directional/north, -/obj/machinery/firealarm/directional/west, -/obj/structure/table/wood, -/turf/open/floor/wood/tile, -/area/station/service/theater) "jjJ" = ( /obj/machinery/camera/directional/west{ c_tag = "Labor Camp External West"; @@ -29845,12 +30444,6 @@ /obj/structure/mirror/directional/east, /turf/open/floor/iron/freezer, /area/station/commons/toilet/locker) -"jjW" = ( -/obj/machinery/vending/wardrobe/bar_wardrobe, -/obj/item/radio/intercom/directional/east, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "jkn" = ( /obj/effect/turf_decal/tile/dark/fourcorners, /turf/open/floor/iron, @@ -29886,6 +30479,17 @@ /obj/effect/landmark/blobstart, /turf/open/floor/engine, /area/station/science/explab) +"jkK" = ( +/obj/structure/railing/wooden_fence{ + dir = 9 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) +"jkN" = ( +/obj/effect/spawner/random/entertainment/arcade, +/obj/machinery/status_display/ai/directional/north, +/turf/open/floor/eighties, +/area/station/commons/lounge) "jkS" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, @@ -29929,6 +30533,13 @@ /obj/structure/railing/corner, /turf/open/lava/plasma/ice_moon, /area/icemoon/underground/explored) +"jlv" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/siding/wood, +/obj/effect/spawner/random/entertainment/musical_instrument, +/obj/item/instrument/harmonica, +/turf/open/floor/iron/grimy, +/area/station/commons/lounge) "jly" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -29960,6 +30571,17 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/freezer, /area/station/commons/toilet) +"jlT" = ( +/obj/structure/chair{ + desc = "Aw geez, I wonder what the chef's cooking up in there!"; + dir = 1; + name = "The Peanut's Gallery" + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "jlV" = ( /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible{ dir = 4 @@ -29981,6 +30603,13 @@ }, /turf/open/floor/iron/cafeteria, /area/mine/laborcamp) +"jmo" = ( +/obj/effect/turf_decal/weather/snow/corner{ + dir = 9 + }, +/obj/machinery/light/small/directional/east, +/turf/open/floor/plating/snowed/icemoon, +/area/icemoon/underground/explored) "jms" = ( /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/west, @@ -30003,6 +30632,18 @@ "jmI" = ( /turf/closed/wall/r_wall, /area/station/security/prison/workout) +"jmJ" = ( +/obj/machinery/door/airlock/external, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 8 + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "chem-morgue-airlock" + }, +/obj/effect/mapping_helpers/airlock/access/any/medical/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/medical/morgue) "jmR" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -30012,6 +30653,16 @@ }, /turf/open/floor/iron/grimy, /area/station/service/chapel/office) +"jnh" = ( +/obj/machinery/door/airlock{ + name = "Unisex Showers" + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/textured, +/area/station/commons/toilet) "jnR" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle{ dir = 4 @@ -30031,6 +30682,14 @@ }, /turf/open/floor/iron/white, /area/station/medical/storage) +"jnU" = ( +/obj/structure/sign/departments/botany/directional/east, +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "jnV" = ( /obj/structure/closet/firecloset, /turf/open/floor/plating, @@ -30086,13 +30745,16 @@ /obj/machinery/power/apc/auto_name/directional/south, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"joG" = ( -/obj/effect/landmark/event_spawn, -/obj/effect/turf_decal/siding/wideplating/dark{ - dir = 1 +"joW" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 10 + }, +/obj/structure/reagent_dispensers/watertank/high, +/obj/item/reagent_containers/cup/watering_can, +/turf/open/floor/iron/dark, /area/station/service/hydroponics) "jpd" = ( /obj/machinery/vending/coffee, @@ -30214,23 +30876,14 @@ }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) -"jqJ" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/landmark/start/botanist, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark/side{ - dir = 1 - }, -/area/station/service/hydroponics) "jqT" = ( /turf/closed/wall/r_wall, /area/station/engineering/storage/tech) +"jqZ" = ( +/obj/effect/landmark/start/hangover, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "jrc" = ( /obj/machinery/button/door/directional/east{ id = "xenobio6"; @@ -30248,6 +30901,22 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) +"jrv" = ( +/obj/item/book/manual/wiki/barman_recipes{ + pixel_x = 5; + pixel_y = 6 + }, +/obj/item/reagent_containers/cup/rag, +/obj/structure/table/wood, +/obj/item/holosign_creator/robot_seat/bar{ + pixel_y = 6 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/box/white/corners{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/service/bar) "jrI" = ( /obj/structure/transit_tube/curved/flipped, /obj/structure/cable, @@ -30329,6 +30998,23 @@ dir = 1 }, /area/station/hallway/primary/port) +"jsR" = ( +/obj/machinery/door/airlock{ + name = "Bar" + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/machinery/duct, +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/access/all/service/bar, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/service/bar) "jth" = ( /obj/structure/table, /obj/item/assembly/prox_sensor{ @@ -30608,6 +31294,12 @@ /obj/machinery/atmospherics/pipe/smart/simple/purple/visible, /turf/open/floor/iron, /area/station/engineering/atmos) +"jwf" = ( +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "jwj" = ( /obj/machinery/atmospherics/components/binary/pump{ dir = 8 @@ -30639,14 +31331,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron, /area/station/hallway/primary/central) -"jwv" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/table, -/obj/machinery/processor{ - pixel_y = 6 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "jwx" = ( /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 8 @@ -30701,20 +31385,16 @@ /obj/structure/cable, /turf/open/floor/circuit, /area/station/ai_monitored/command/nuke_storage) +"jxr" = ( +/obj/machinery/restaurant_portal/restaurant, +/obj/effect/turf_decal/delivery/red, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "jxv" = ( /obj/effect/landmark/start/paramedic, /obj/structure/cable, /turf/open/floor/iron/white, /area/station/medical/storage) -"jyh" = ( -/obj/structure/table/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/obj/machinery/digital_clock/directional/south, -/turf/open/floor/iron, -/area/station/service/bar) "jyl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -30745,6 +31425,14 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/white, /area/station/medical/virology) +"jyE" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/fore) "jyL" = ( /obj/structure/cable, /obj/machinery/power/terminal{ @@ -30755,6 +31443,11 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron/smooth, /area/mine/laborcamp/security) +"jyN" = ( +/obj/effect/spawner/random/structure/crate, +/obj/effect/spawner/random/maintenance/three, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "jyR" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -30787,6 +31480,16 @@ /obj/effect/mapping_helpers/airlock/access/all/security/entrance, /turf/open/floor/iron, /area/station/security/brig/upper) +"jzR" = ( +/obj/structure/table/glass, +/obj/item/shovel/spade, +/obj/item/cultivator{ + pixel_x = 1; + pixel_y = 6 + }, +/obj/machinery/airalarm/directional/east, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "jzY" = ( /obj/machinery/airalarm/directional/west, /obj/effect/turf_decal/trimline/blue/filled/corner{ @@ -30846,13 +31549,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/space_hut/cabin) -"jBb" = ( -/obj/structure/chair/wood{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "jBc" = ( /obj/machinery/dna_infuser, /obj/item/infuser_book, @@ -30888,11 +31584,6 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"jBq" = ( -/obj/structure/flora/tree/jungle/style_random, -/obj/structure/flora/bush/jungle/a/style_random, -/turf/open/floor/grass, -/area/station/service/hydroponics) "jBB" = ( /obj/structure/kitchenspike, /turf/open/floor/plating/snowed/coldroom, @@ -30914,15 +31605,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/engineering/atmos) -"jBU" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "jCl" = ( /turf/open/floor/plating, /area/station/maintenance/starboard/aft) @@ -30966,17 +31648,6 @@ /obj/machinery/smartfridge/petri/preloaded, /turf/open/openspace, /area/station/science/xenobiology) -"jCF" = ( -/obj/effect/turf_decal/siding/wood, -/obj/structure/chair/wood{ - dir = 4 - }, -/obj/item/radio/intercom/directional/west{ - pixel_y = -9 - }, -/obj/effect/decal/cleanable/ash, -/turf/open/floor/stone, -/area/station/commons/lounge) "jCL" = ( /obj/structure/disposalpipe/trunk{ dir = 4 @@ -31087,16 +31758,6 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/iron/dark, /area/station/medical/virology) -"jEr" = ( -/obj/structure/table/wood, -/obj/item/camera, -/obj/item/taperecorder, -/obj/item/radio/intercom/directional/east, -/obj/structure/sign/painting/library_private{ - pixel_y = 32 - }, -/turf/open/floor/engine/cult, -/area/station/service/library) "jEs" = ( /obj/machinery/conveyor_switch/oneway{ id = "gulag"; @@ -31104,6 +31765,12 @@ }, /turf/open/floor/iron, /area/mine/laborcamp) +"jEA" = ( +/obj/machinery/light/small/directional/east, +/obj/item/pickaxe, +/obj/structure/closet/emcloset, +/turf/open/floor/plating, +/area/station/medical/morgue) "jEB" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/newscaster/directional/north, @@ -31124,22 +31791,14 @@ /obj/structure/rack, /turf/open/floor/iron, /area/station/command/gateway) -"jFA" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/obj/machinery/firealarm/directional/east, -/obj/machinery/door/airlock{ - name = "Service Hall" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/obj/effect/mapping_helpers/airlock/unres{ +"jFu" = ( +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ dir = 1 }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/dark/textured_half, -/area/station/hallway/secondary/service) +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/service/bar) "jFJ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -31169,6 +31828,11 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"jFY" = ( +/obj/effect/spawner/random/entertainment/arcade, +/obj/machinery/digital_clock/directional/north, +/turf/open/floor/eighties, +/area/station/commons/lounge) "jFZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -31228,12 +31892,6 @@ /obj/item/clothing/suit/hazardvest, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"jHE" = ( -/obj/effect/turf_decal/siding/white/corner, -/obj/machinery/firealarm/directional/south, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "jHF" = ( /obj/item/trash/boritos/red, /obj/structure/cable, @@ -31245,17 +31903,13 @@ /obj/machinery/light/directional/north, /turf/open/floor/iron/freezer, /area/station/commons/toilet) -"jHK" = ( -/obj/machinery/seed_extractor, -/obj/effect/turf_decal/siding/white{ - dir = 9 - }, -/obj/effect/turf_decal/tile/green/opposingcorners{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners, -/turf/open/floor/iron, -/area/station/service/hydroponics) +"jHL" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "jHQ" = ( /obj/machinery/atmospherics/components/trinary/filter/atmos/co2{ dir = 1 @@ -31366,6 +32020,12 @@ }, /turf/open/floor/iron, /area/station/cargo/drone_bay) +"jIY" = ( +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "jIZ" = ( /obj/machinery/power/terminal{ dir = 1 @@ -31395,17 +32055,18 @@ }, /turf/open/floor/plating, /area/station/cargo/sorting) -"jJf" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/duct, -/obj/machinery/holopad, -/obj/structure/disposalpipe/junction{ +"jJr" = ( +/obj/machinery/door/firedoor, +/obj/structure/sign/warning/electric_shock/directional/south, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line{ dir = 4 }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "jJF" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/effect/turf_decal/stripes/line{ @@ -31423,6 +32084,18 @@ "jJM" = ( /turf/open/floor/glass, /area/station/security/lockers) +"jJR" = ( +/obj/machinery/firealarm/directional/south, +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/effect/turf_decal/tile/blue/anticorner/contrasted, +/obj/machinery/door/airlock, +/turf/open/floor/iron, +/area/station/command/bridge) "jJV" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -31501,6 +32174,24 @@ /obj/effect/turf_decal/tile/green, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai_upload) +"jKL" = ( +/obj/structure/cable, +/obj/structure/holosign/barrier/atmos/sturdy, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/door/poddoor/shutters{ + dir = 1; + id = "minecraft_shutter"; + name = "Cart Shutters"; + pixel_y = 0 + }, +/obj/structure/minecart_rail{ + dir = 1 + }, +/turf/open/floor/iron/textured, +/area/station/service/kitchen/coldroom) "jKN" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -31516,19 +32207,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/port/greater) -"jKV" = ( -/obj/item/training_toolbox{ - pixel_y = 5 - }, -/obj/structure/table, -/obj/item/training_toolbox{ - pixel_y = -2 - }, -/obj/effect/turf_decal/tile/red/half/contrasted{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "jKY" = ( /turf/closed/mineral/random/snow/high_chance, /area/icemoon/underground/unexplored/rivers/deep/shoreline) @@ -31557,10 +32235,6 @@ }, /turf/open/floor/iron/dark/corner, /area/station/engineering/atmos/storage/gas) -"jLn" = ( -/obj/machinery/firealarm/directional/west, -/turf/open/floor/iron, -/area/station/service/hydroponics) "jLo" = ( /obj/structure/table, /obj/effect/decal/cleanable/dirt, @@ -31657,6 +32331,16 @@ }, /turf/open/floor/plating, /area/station/hallway/secondary/entry) +"jMD" = ( +/obj/effect/turf_decal/siding/white/corner{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"jMJ" = ( +/obj/machinery/duct, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "jMY" = ( /obj/structure/cable, /obj/effect/turf_decal/trimline/dark_blue/line{ @@ -31666,6 +32350,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/mix) +"jNe" = ( +/obj/effect/spawner/structure/window/reinforced/tinted, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "jNf" = ( /turf/closed/wall, /area/station/security/prison/garden) @@ -31696,22 +32384,6 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) -"jOc" = ( -/obj/structure/sink/kitchen/directional/west, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 8 - }, -/obj/item/radio/intercom/directional/east{ - pixel_x = 31 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "jOi" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -31778,21 +32450,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark/textured, /area/station/security/office) -"jOY" = ( -/obj/effect/turf_decal/stripes/line, -/obj/structure/reagent_dispensers/plumbed{ - dir = 8 - }, -/turf/open/floor/plating, -/area/station/hallway/secondary/service) -"jPa" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/structure/table, -/obj/item/aquarium_kit, -/turf/open/floor/plating, -/area/station/hallway/secondary/service) "jPc" = ( /obj/machinery/conveyor_switch/oneway{ id = "QMLoad2" @@ -31879,13 +32536,6 @@ /obj/machinery/space_heater, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) -"jQo" = ( -/obj/effect/turf_decal/siding/white{ - dir = 10 - }, -/obj/effect/spawner/random/entertainment/arcade, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "jQt" = ( /obj/machinery/navbeacon{ codes_txt = "delivery;dir=1"; @@ -31950,6 +32600,12 @@ /obj/item/gps/mining, /turf/open/floor/iron, /area/station/commons/storage/mining) +"jQM" = ( +/obj/machinery/power/apc/auto_name/directional/north, +/obj/structure/cable, +/obj/machinery/light/warm/directional/north, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "jQS" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, @@ -31986,6 +32642,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, /area/station/medical/morgue) +"jRt" = ( +/obj/effect/spawner/random/structure/grille, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "jRu" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -32054,14 +32714,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/engineering/storage/tech) -"jSm" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, +"jSp" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt/dust, /obj/structure/disposalpipe/segment{ - dir = 6 + dir = 5 }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "jSt" = ( /obj/machinery/door/airlock/external{ name = "Security Yard"; @@ -32088,12 +32750,6 @@ /obj/structure/stairs/east, /turf/open/floor/plating, /area/station/hallway/primary/central/fore) -"jSM" = ( -/obj/effect/turf_decal/siding/thinplating/corner{ - dir = 1 - }, -/turf/open/misc/asteroid/snow/icemoon, -/area/icemoon/underground/explored) "jSQ" = ( /obj/structure/sign/poster/official/here_for_your_safety/directional/east, /turf/open/misc/asteroid/snow/icemoon, @@ -32149,13 +32805,6 @@ dir = 1 }, /area/station/engineering/atmos) -"jTV" = ( -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "jTZ" = ( /obj/machinery/door/airlock/command/glass{ name = "Server Room" @@ -32180,6 +32829,14 @@ /obj/item/radio/intercom/directional/north, /turf/open/floor/iron/showroomfloor, /area/station/security/warden) +"jUv" = ( +/obj/machinery/hydroponics/constructable, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "jUB" = ( /turf/closed/wall, /area/station/medical/virology) @@ -32228,15 +32885,12 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/fore) -"jVq" = ( -/obj/structure/railing/corner, -/obj/machinery/door/firedoor/border_only, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/green{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) +"jVm" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/light/small/directional/west, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "jVx" = ( /obj/machinery/light/small/directional/south, /obj/structure/sign/warning/cold_temp/directional/south, @@ -32272,15 +32926,6 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/plating, /area/station/maintenance/solars/port/aft) -"jWp" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "jWt" = ( /obj/structure/cable, /obj/structure/closet/radiation, @@ -32293,13 +32938,6 @@ /obj/structure/sign/warning/gas_mask/directional/west, /turf/open/floor/plating, /area/station/engineering/main) -"jWO" = ( -/obj/item/soap/nanotrasen, -/obj/item/clothing/head/costume/sombrero/green, -/obj/structure/table/wood, -/obj/structure/sign/poster/random/directional/north, -/turf/open/floor/wood/tile, -/area/station/service/theater) "jWP" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -32344,10 +32982,6 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/plating, /area/station/maintenance/port/greater) -"jXD" = ( -/obj/machinery/light/directional/north, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "jXH" = ( /obj/machinery/conveyor{ dir = 8; @@ -32418,6 +33052,12 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/engineering/atmos) +"jYI" = ( +/obj/effect/spawner/random/trash/mess, +/obj/structure/disposalpipe/segment, +/obj/structure/railing/corner/end, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "jYL" = ( /obj/structure/light_construct/directional/south, /obj/structure/sign/poster/contraband/random/directional/south, @@ -32438,6 +33078,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/nuke_storage) +"jZc" = ( +/obj/machinery/light/small/dim/directional/east, +/turf/open/floor/stone, +/area/station/commons/lounge) "jZe" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -32460,14 +33104,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/eva) -"jZt" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/table, -/obj/machinery/reagentgrinder{ - pixel_y = 9 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "jZB" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/public/glass{ @@ -32490,6 +33126,14 @@ dir = 10 }, /area/station/security/prison) +"jZJ" = ( +/obj/machinery/vending/wardrobe/bar_wardrobe, +/obj/machinery/camera/directional/north{ + c_tag = "Service - Backroom" + }, +/obj/machinery/status_display/ai/directional/north, +/turf/open/floor/wood/parquet, +/area/station/service/bar/backroom) "jZM" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -32512,6 +33156,14 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"kav" = ( +/obj/effect/spawner/random/trash/moisture_trap, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "kaw" = ( /obj/machinery/photocopier, /obj/item/radio/intercom/directional/north, @@ -32528,6 +33180,11 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/white, /area/station/medical/virology) +"kaI" = ( +/obj/effect/spawner/random/maintenance/two, +/obj/structure/closet/crate, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "kaK" = ( /obj/effect/landmark/generic_maintenance_landmark, /turf/open/floor/iron, @@ -32576,6 +33233,12 @@ }, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"kbu" = ( +/obj/structure/reagent_dispensers/plumbed{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "kbx" = ( /obj/structure/table, /obj/effect/decal/cleanable/dirt, @@ -32609,20 +33272,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/fore) -"kbU" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/door/airlock, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "kcc" = ( /obj/machinery/camera/directional/west{ c_tag = "Security - Infirmary" @@ -32659,6 +33308,16 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron, /area/station/engineering/storage/tech) +"kcs" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/neutral/half/contrasted, +/turf/open/floor/iron, +/area/station/commons/fitness) +"kcw" = ( +/obj/structure/flora/bush/fullgrass/style_random, +/turf/open/floor/grass, +/area/station/service/hydroponics) "kcC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, @@ -32693,6 +33352,12 @@ /obj/structure/sign/warning/directional/south, /turf/open/genturf/blue, /area/icemoon/underground/unexplored/rivers/deep/shoreline) +"kda" = ( +/obj/structure/closet/crate, +/obj/effect/spawner/random/maintenance/two, +/obj/item/sign, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "kdc" = ( /obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/visible{ dir = 8 @@ -32706,6 +33371,12 @@ /obj/structure/sign/warning/test_chamber/directional/south, /turf/open/floor/iron, /area/station/science/ordnance/testlab) +"kdw" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/station/maintenance/starboard/fore) "kdy" = ( /obj/machinery/door/poddoor/shutters{ id = "secmechbay"; @@ -32716,13 +33387,6 @@ /obj/effect/turf_decal/box, /turf/open/floor/iron/dark, /area/station/security/mechbay) -"kdD" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/light/small/directional/south, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "kdF" = ( /obj/effect/spawner/random/vending/snackvend, /turf/open/floor/iron, @@ -32753,22 +33417,18 @@ }, /turf/open/floor/engine/vacuum, /area/station/engineering/atmos) +"kea" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/structure/desk_bell{ + pixel_x = -3 + }, +/turf/open/floor/iron, +/area/station/service/bar) "kei" = ( /obj/docking_port/stationary/escape_pod, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) -"keq" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 5 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 5 - }, -/obj/item/radio/intercom/directional/east, -/obj/machinery/duct, -/obj/machinery/light/directional/east, -/turf/open/floor/iron, -/area/station/service/hydroponics) "keu" = ( /obj/structure/lattice/catwalk, /obj/structure/marker_beacon/burgundy{ @@ -32799,6 +33459,13 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron, /area/station/commons/dorms) +"keM" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/turf/open/floor/stone, +/area/station/commons/lounge) "keP" = ( /turf/closed/wall, /area/station/engineering/atmos/storage/gas) @@ -32829,9 +33496,6 @@ dir = 4 }, /area/station/maintenance/port/fore) -"keV" = ( -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance/burnchamber) "keX" = ( /obj/structure/table, /obj/item/stack/cable_coil{ @@ -32870,6 +33534,13 @@ /obj/item/trash/energybar, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"kfk" = ( +/obj/structure/table/wood, +/obj/item/paper, +/obj/item/pen, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "kfl" = ( /obj/structure/table/wood, /obj/item/radio/intercom/directional/south, @@ -32919,22 +33590,6 @@ /obj/structure/sign/poster/random/directional/west, /turf/open/floor/iron, /area/station/engineering/atmos) -"kfX" = ( -/obj/structure/table/wood, -/obj/item/toy/cards/deck{ - pixel_y = 4 - }, -/obj/item/radio/intercom/directional/west, -/turf/open/floor/carpet, -/area/station/service/theater) -"kfY" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/structure/chair, -/obj/structure/extinguisher_cabinet/directional/north, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "kfZ" = ( /obj/machinery/door/firedoor/heavy, /obj/structure/sign/warning/test_chamber/directional/east, @@ -32976,10 +33631,6 @@ }, /turf/open/floor/iron/dark, /area/station/science/ordnance/office) -"kgs" = ( -/obj/machinery/airalarm/directional/north, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "kgy" = ( /obj/structure/cable, /obj/effect/spawner/random/structure/steam_vent, @@ -33075,11 +33726,6 @@ /obj/structure/marker_beacon/cerulean, /turf/open/genturf, /area/icemoon/surface/outdoors/unexplored/rivers/no_monsters) -"khA" = ( -/obj/machinery/firealarm/directional/west, -/obj/item/kirbyplants/random, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "khF" = ( /obj/machinery/light/small/directional/north, /obj/structure/sign/warning/gas_mask/directional/north{ @@ -33148,21 +33794,17 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/mining_station, /turf/open/floor/iron/dark/textured_half, /area/station/cargo/storage) -"kiB" = ( -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/obj/structure/railing{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "kiE" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) +"kiI" = ( +/obj/machinery/light/small/directional/east, +/obj/effect/spawner/random/engineering/atmospherics_portable, +/turf/open/floor/plating, +/area/station/maintenance/fore) "kiL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet, @@ -33272,6 +33914,18 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) +"kkb" = ( +/obj/machinery/door/window/left/directional/east{ + name = "Fitness Ring" + }, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/siding/white{ + dir = 6 + }, +/turf/open/floor/iron/dark, +/area/station/commons/fitness) "kke" = ( /obj/machinery/door/airlock/maintenance, /obj/structure/cable, @@ -33294,6 +33948,21 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/solars/port/aft) +"kkr" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Central Access" + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "kkA" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/newscaster/directional/west, @@ -33375,6 +34044,12 @@ /obj/effect/spawner/random/contraband/prison, /turf/open/floor/carpet/blue, /area/station/security/prison/work) +"klJ" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "klP" = ( /obj/structure/dresser, /turf/open/floor/carpet, @@ -33390,19 +34065,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/mine/laborcamp) -"klY" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) -"kme" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/medical/morgue) "kmf" = ( /obj/machinery/status_display/evac/directional/west, /turf/open/openspace, @@ -33466,27 +34128,6 @@ /obj/structure/sign/poster/official/random/directional/north, /turf/open/floor/iron/textured, /area/mine/mechbay) -"kmQ" = ( -/obj/structure/railing/corner{ - dir = 8 - }, -/obj/machinery/door/firedoor/border_only, -/obj/machinery/camera{ - c_tag = "Service Botany - Upper South"; - dir = 10 - }, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/green{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) -"kmW" = ( -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "knd" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, @@ -33513,13 +34154,6 @@ /obj/machinery/light/directional/east, /turf/open/floor/wood, /area/station/command/meeting_room) -"knW" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "knX" = ( /obj/machinery/status_display/evac/directional/east, /obj/effect/turf_decal/tile/yellow/opposingcorners, @@ -33536,6 +34170,11 @@ dir = 8 }, /area/station/hallway/secondary/entry) +"koj" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/light/small/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/fore) "koH" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -33565,11 +34204,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/maint) -"kpf" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/oven/range, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "kpj" = ( /obj/structure/window/reinforced/spawner/directional/north{ pixel_y = 2 @@ -33654,6 +34288,16 @@ }, /turf/open/floor/iron/dark/textured_edge, /area/station/security/prison) +"kqo" = ( +/obj/structure/table/wood, +/obj/machinery/duct, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/box/white/corners, +/obj/item/storage/fancy/cigarettes/cigars{ + pixel_y = 4 + }, +/turf/open/floor/iron/dark, +/area/station/service/bar) "kqq" = ( /obj/machinery/atmospherics/components/binary/pump/on{ dir = 1; @@ -33686,12 +34330,6 @@ dir = 4 }, /area/station/command/gateway) -"kqA" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/east, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "kqG" = ( /obj/structure/table/reinforced, /obj/machinery/light/small/directional/east, @@ -33718,6 +34356,14 @@ /obj/structure/disposalpipe/trunk/multiz/down, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) +"kqP" = ( +/obj/effect/turf_decal/siding/white/corner{ + dir = 4 + }, +/obj/machinery/light/directional/south, +/obj/machinery/firealarm/directional/south, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "kqR" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -33790,6 +34436,22 @@ }, /turf/open/floor/plating, /area/mine/laborcamp/security) +"krE" = ( +/obj/structure/table, +/obj/item/flashlight/flare/candle{ + pixel_y = 1; + pixel_x = -16 + }, +/obj/item/paper/crumpled{ + pixel_y = 3; + pixel_x = 1; + name = "used napkin" + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "krN" = ( /obj/structure/sign/poster/official/random/directional/south, /obj/structure/window/reinforced/spawner/directional/west, @@ -33873,30 +34535,13 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron/white, /area/station/medical/virology) -"ksK" = ( -/turf/closed/wall, -/area/station/service/kitchen/coldroom) -"ksL" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/sign/poster/official/random/directional/south, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) -"ksO" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 1 +"ksR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) +/obj/effect/decal/cleanable/confetti, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "ksU" = ( /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, @@ -33931,6 +34576,27 @@ }, /turf/open/floor/iron, /area/station/commons/dorms/laundry) +"ktq" = ( +/obj/effect/turf_decal/siding/thinplating/dark/corner{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 10 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 10 + }, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/light/warm/directional/south, +/obj/structure/sign/poster/contraband/lizard/directional/south, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "ktt" = ( /obj/structure/sign/warning/electric_shock, /turf/closed/wall/r_wall, @@ -33980,6 +34646,20 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) +"ktJ" = ( +/obj/structure/chair/stool/directional/north, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/solars/starboard/fore) +"ktK" = ( +/obj/structure/chair/sofa/bench/left{ + dir = 4 + }, +/obj/structure/sign/warning/electric_shock/directional/west, +/obj/machinery/light/small/directional/north, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/hallway/primary/fore) "ktU" = ( /turf/open/floor/carpet, /area/station/command/meeting_room) @@ -33992,16 +34672,16 @@ /obj/machinery/disposal/bin, /turf/open/floor/iron/dark, /area/station/hallway/secondary/entry) +"ktY" = ( +/obj/item/radio/intercom/directional/east, +/obj/structure/table, +/obj/machinery/fax/auto_name, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "kub" = ( /obj/machinery/newscaster/directional/east, /turf/open/floor/iron/dark, /area/station/service/chapel) -"kum" = ( -/obj/structure/table, -/obj/item/trash/can/food/beans, -/obj/item/reagent_containers/cup/glass/waterbottle/empty, -/turf/open/floor/iron, -/area/station/maintenance/starboard/fore) "kuy" = ( /obj/machinery/computer/pod/old/mass_driver_controller/ordnancedriver{ pixel_x = 28 @@ -34060,18 +34740,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/general/visible, /turf/open/floor/iron/dark, /area/station/engineering/supermatter/room) -"kvs" = ( -/obj/machinery/door/firedoor, -/obj/structure/table/reinforced, -/obj/machinery/door/window/left/directional/west{ - name = "Hydroponics Desk"; - req_access = list("hydroponics") - }, -/obj/structure/desk_bell{ - pixel_x = 7 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "kvu" = ( /obj/machinery/door/airlock/security{ id_tag = "IsolationCell"; @@ -34111,6 +34779,15 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/white, /area/station/science/ordnance/office) +"kvT" = ( +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "kvX" = ( /turf/open/floor/iron/dark/smooth_edge{ dir = 4 @@ -34133,13 +34810,6 @@ /obj/item/wrench, /turf/open/floor/iron, /area/station/engineering/atmos) -"kwu" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/machinery/computer/slot_machine{ - pixel_y = -6 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "kwz" = ( /obj/structure/table/wood, /obj/item/folder/blue, @@ -34207,14 +34877,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/solars/starboard/fore) -"kxN" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "kxY" = ( /obj/effect/turf_decal/stripes/corner, /turf/open/floor/iron, @@ -34295,13 +34957,6 @@ /obj/effect/turf_decal/tile/red/full, /turf/open/floor/iron/dark/smooth_large, /area/station/security/checkpoint/medical) -"kyZ" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "kzv" = ( /obj/structure/bed, /obj/effect/spawner/random/bedsheet/any, @@ -34366,15 +35021,17 @@ /obj/item/multitool, /turf/open/floor/plating, /area/station/engineering/storage/tech) -"kzW" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 +"kzU" = ( +/obj/structure/dresser, +/obj/structure/mirror/directional/north, +/obj/effect/turf_decal/siding/wood{ + dir = 8 }, -/obj/machinery/duct, -/turf/open/floor/wood/tile, +/obj/machinery/camera{ + c_tag = "Service - Backstage"; + dir = 9 + }, +/turf/open/floor/wood/parquet, /area/station/service/theater) "kzZ" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ @@ -34398,12 +35055,6 @@ /obj/effect/decal/cleanable/cobweb/cobweb2, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"kAD" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/turf/open/floor/plating, -/area/station/service/kitchen/coldroom) "kAG" = ( /obj/structure/table, /obj/item/cigbutt, @@ -34466,6 +35117,14 @@ /obj/structure/sink/directional/south, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"kBO" = ( +/obj/structure/window/reinforced/spawner/directional/south, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/obj/effect/turf_decal/siding/white, +/turf/open/floor/plating, +/area/station/service/kitchen/coldroom) "kBU" = ( /obj/structure/table/wood, /obj/item/flashlight/lamp/green{ @@ -34668,26 +35327,6 @@ dir = 4 }, /area/mine/eva) -"kDJ" = ( -/obj/item/wrench, -/obj/item/clothing/glasses/monocle, -/obj/structure/table/wood, -/obj/structure/sign/poster/contraband/random/directional/north, -/turf/open/floor/iron, -/area/station/service/theater) -"kDP" = ( -/obj/effect/turf_decal/siding/wideplating/dark{ - dir = 1 - }, -/obj/machinery/firealarm/directional/west, -/turf/open/floor/iron, -/area/station/service/hydroponics) -"kDU" = ( -/obj/effect/turf_decal/siding/thinplating{ - dir = 1 - }, -/turf/open/misc/asteroid/snow/icemoon, -/area/icemoon/underground/explored) "kEj" = ( /obj/machinery/computer/libraryconsole/bookmanagement, /obj/structure/table, @@ -34708,6 +35347,16 @@ /obj/effect/spawner/random/structure/crate, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"kEr" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "kEs" = ( /obj/structure/tank_holder/extinguisher, /turf/open/floor/plating, @@ -34752,6 +35401,15 @@ /obj/machinery/firealarm/directional/south, /turf/open/floor/iron/cafeteria, /area/station/security/prison/mess) +"kFF" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Cart Maintenance" + }, +/obj/effect/mapping_helpers/airlock/access/any/service/kitchen, +/obj/effect/mapping_helpers/airlock/access/any/service/hydroponics, +/obj/structure/barricade/wooden/snowed, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "kFH" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/visible{ dir = 10 @@ -34794,6 +35452,13 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/cargo/lobby) +"kGD" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/bar{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "kGF" = ( /obj/structure/table, /obj/item/camera_film, @@ -34839,12 +35504,6 @@ /obj/structure/sign/poster/official/random/directional/west, /turf/open/floor/stone, /area/mine/eva/lower) -"kHk" = ( -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 8 - }, -/turf/open/floor/carpet, -/area/station/service/theater) "kHl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/stripes/line{ @@ -34920,10 +35579,6 @@ }, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/service) -"kHV" = ( -/obj/structure/flora/bush/jungle/a/style_random, -/turf/open/floor/grass, -/area/station/service/hydroponics) "kIh" = ( /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -34978,6 +35633,11 @@ /obj/machinery/space_heater, /turf/open/floor/iron/smooth_large, /area/station/cargo/warehouse) +"kIK" = ( +/obj/effect/turf_decal/tile/blue, +/obj/item/radio/intercom/directional/south, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "kIU" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/corner, @@ -35027,6 +35687,22 @@ /obj/structure/sign/poster/official/random/directional/north, /turf/open/floor/iron/smooth, /area/mine/laborcamp/security) +"kJx" = ( +/obj/structure/railing/wooden_fence, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) +"kJG" = ( +/obj/structure/curtain/cloth/fancy/mechanical/start_closed{ + id = "cantena_curtains" + }, +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/turf/open/floor/wood, +/area/station/commons/lounge) "kJI" = ( /obj/structure/transit_tube/station/reverse, /turf/open/floor/plating, @@ -35073,11 +35749,11 @@ }, /turf/open/floor/iron/dark, /area/station/medical/morgue) -"kKl" = ( -/obj/structure/table/glass, -/obj/item/plant_analyzer, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) +"kKn" = ( +/obj/machinery/light/cold/directional/east, +/obj/machinery/status_display/ai/directional/east, +/turf/open/openspace, +/area/station/service/kitchen/coldroom) "kKv" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/disposalpipe/sorting/mail{ @@ -35183,14 +35859,6 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) -"kMD" = ( -/obj/machinery/door/airlock{ - name = "Unisex Restrooms" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "kMN" = ( /obj/machinery/space_heater, /turf/open/floor/plating, @@ -35291,23 +35959,6 @@ }, /turf/open/floor/iron, /area/station/security/brig/upper) -"kOB" = ( -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral/half/contrasted, -/obj/machinery/firealarm/directional/south, -/turf/open/floor/iron, -/area/station/commons/fitness) -"kOF" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/door/firedoor, -/obj/effect/turf_decal/tile/blue, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) "kON" = ( /obj/structure/rack, /obj/effect/decal/cleanable/dirt, @@ -35368,6 +36019,11 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/station/hallway/primary/aft) +"kPh" = ( +/obj/structure/flora/bush/sunny/style_random, +/obj/structure/flora/bush/fullgrass/style_random, +/turf/open/floor/grass, +/area/station/service/hydroponics) "kPo" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -35399,6 +36055,9 @@ }, /turf/open/floor/iron, /area/station/service/hydroponics/garden) +"kPz" = ( +/turf/closed/mineral/random/snow, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "kPL" = ( /obj/machinery/power/apc/auto_name/directional/south, /obj/structure/cable, @@ -35418,6 +36077,19 @@ /obj/structure/marker_beacon/cerulean, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"kPY" = ( +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/machinery/vending/hydroseeds{ + slogan_delay = 700 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "kQc" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -35448,6 +36120,14 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"kQx" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/item/radio/intercom/directional/north, +/obj/machinery/holopad, +/obj/machinery/light/warm/directional/north, +/obj/effect/turf_decal/bot, +/turf/open/floor/iron, +/area/station/service/bar) "kQz" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -35466,6 +36146,14 @@ /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating, /area/station/maintenance/fore) +"kQH" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "kQJ" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 @@ -35495,32 +36183,6 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/plating, /area/station/maintenance/port/greater) -"kQW" = ( -/obj/structure/closet/crate/hydroponics, -/obj/item/shovel/spade, -/obj/item/wrench, -/obj/item/reagent_containers/cup/watering_can, -/obj/item/wirecutters, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/obj/machinery/camera{ - c_tag = "Service Botany - Lower North"; - dir = 9 - }, -/obj/machinery/newscaster/directional/north, -/turf/open/floor/plating, -/area/station/service/hydroponics) -"kQX" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "kQY" = ( /obj/effect/turf_decal/arrows/red{ dir = 4; @@ -35542,6 +36204,12 @@ /obj/structure/bookcase, /turf/open/floor/iron, /area/mine/laborcamp) +"kRj" = ( +/obj/structure/table/wood, +/obj/item/c_tube, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "kRw" = ( /obj/machinery/portable_atmospherics/scrubber, /obj/effect/turf_decal/stripes/line{ @@ -35557,6 +36225,15 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"kRD" = ( +/obj/machinery/door/airlock/hydroponics/glass{ + name = "Garden" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/turf/open/floor/iron/textured, +/area/station/service/hydroponics) "kRE" = ( /obj/machinery/computer/mech_bay_power_console{ dir = 8 @@ -35618,21 +36295,19 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/cargo/office) +"kSj" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/structure/cable, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "kSn" = ( /obj/structure/cable/multilayer/multiz, /obj/effect/turf_decal/stripes/line, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) -"kSo" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "kSv" = ( /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron, @@ -35692,14 +36367,6 @@ /obj/effect/spawner/random/structure/steam_vent, /turf/open/floor/plating, /area/mine/eva/lower) -"kTO" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "kTQ" = ( /obj/effect/turf_decal/siding/yellow{ dir = 6 @@ -35779,11 +36446,55 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/iron/smooth, /area/station/maintenance/port/lesser) +"kUW" = ( +/obj/machinery/door/airlock/external{ + glass = 1; + name = "Service External Airlock"; + opacity = 0 + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/structure/sign/warning/cold_temp/directional/north, +/obj/structure/sign/warning/gas_mask/directional/south{ + desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." + }, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) +"kVj" = ( +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "kVl" = ( /obj/effect/landmark/event_spawn, /obj/machinery/light/floor, /turf/open/floor/iron, /area/station/cargo/storage) +"kVo" = ( +/obj/structure/table/wood, +/obj/machinery/reagentgrinder{ + pixel_x = 6; + pixel_y = 6 + }, +/obj/item/reagent_containers/cup/glass/shaker{ + pixel_x = -6 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/box/white/corners{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/service/bar) +"kVq" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/light/warm/directional/north, +/obj/machinery/digital_clock/directional/north, +/turf/open/floor/iron, +/area/station/service/bar) "kVx" = ( /obj/structure/cable/multilayer/multiz, /obj/effect/turf_decal/stripes/line, @@ -35824,10 +36535,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) -"kWa" = ( -/obj/structure/fireplace, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "kWh" = ( /obj/machinery/holopad/secure, /turf/open/floor/iron/dark/smooth_large, @@ -35846,21 +36553,6 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/white, /area/station/maintenance/port/fore) -"kWs" = ( -/obj/effect/turf_decal/siding/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/machinery/door/airlock{ - name = "Bar" - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/access/all/service/bar, -/turf/open/floor/iron/dark/textured_half, -/area/station/service/bar/backroom) "kWw" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -35870,6 +36562,16 @@ }, /turf/open/floor/iron, /area/station/tcommsat/computer) +"kWG" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "kWH" = ( /obj/structure/rack, /obj/item/hand_labeler, @@ -35877,13 +36579,6 @@ /obj/effect/turf_decal/tile/red, /turf/open/floor/iron/textured, /area/station/security/brig) -"kWK" = ( -/obj/machinery/door/firedoor, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) "kWL" = ( /obj/structure/rack, /obj/item/reagent_containers/cup/bottle/nitrogen{ @@ -35909,12 +36604,6 @@ /obj/effect/mapping_helpers/mail_sorting/service/janitor_closet, /turf/open/floor/iron, /area/station/hallway/primary/central) -"kWR" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/holopad, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "kWW" = ( /obj/machinery/door/airlock/atmos, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -35951,14 +36640,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/cargo/storage) -"kXu" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/red/half/contrasted{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "kXx" = ( /obj/structure/table, /obj/item/food/spaghetti/meatballspaghetti{ @@ -35993,15 +36674,6 @@ }, /turf/open/floor/iron/large, /area/station/hallway/secondary/entry) -"kXE" = ( -/obj/machinery/door/firedoor, -/obj/structure/disposalpipe/segment, -/obj/machinery/status_display/evac/directional/west, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "kXI" = ( /obj/effect/turf_decal/weather/snow/corner{ dir = 1 @@ -36022,6 +36694,22 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/showroomfloor, /area/station/security/prison/toilet) +"kXS" = ( +/obj/machinery/door/airlock/hydroponics/glass{ + name = "Hydroponics" + }, +/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/service/hydroponics) "kXY" = ( /turf/open/floor/iron/dark, /area/station/security/prison/rec) @@ -36038,6 +36726,9 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) +"kYo" = ( +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "kYq" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -36052,11 +36743,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/mine/laborcamp) -"kYz" = ( -/obj/effect/landmark/start/hangover, -/obj/structure/disposalpipe/segment, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "kYF" = ( /obj/structure/light_construct/directional/west, /mob/living/simple_animal/hostile/retaliate/goose/vomit, @@ -36072,6 +36758,11 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/large, /area/station/engineering/engine_smes) +"kYN" = ( +/obj/structure/table/wood, +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "kZa" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -36091,11 +36782,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) -"kZc" = ( -/obj/machinery/holopad, -/obj/effect/landmark/start/clown, -/turf/open/floor/wood/tile, -/area/station/service/theater) "kZh" = ( /obj/structure/cable, /obj/structure/sign/poster/contraband/random/directional/west, @@ -36105,6 +36791,16 @@ /obj/machinery/space_heater, /turf/open/floor/iron/dark/textured, /area/station/security/prison) +"kZm" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "kZn" = ( /obj/structure/cable, /obj/machinery/light/floor, @@ -36192,13 +36888,6 @@ }, /turf/open/floor/iron, /area/station/service/janitor) -"laP" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Canteen" - }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/textured_half, -/area/station/hallway/primary/starboard) "laV" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 8 @@ -36265,6 +36954,15 @@ /obj/machinery/gateway/centerstation, /turf/open/floor/iron/dark/smooth_large, /area/station/command/gateway) +"lcm" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/decal/cleanable/ash, +/obj/item/rack_parts, +/obj/effect/mapping_helpers/burnt_floor, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "lcu" = ( /turf/open/floor/iron/white, /area/station/science/explab) @@ -36294,7 +36992,6 @@ pixel_x = -8; pixel_y = 4 }, -/obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/department/electrical) "ldn" = ( @@ -36369,6 +37066,16 @@ /obj/machinery/shower/directional/south, /turf/open/floor/iron, /area/station/science/xenobiology) +"leg" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "lei" = ( /obj/effect/turf_decal/trimline/blue/filled/line, /obj/structure/bed/medical/emergency, @@ -36388,13 +37095,6 @@ }, /turf/open/floor/iron, /area/station/cargo/sorting) -"let" = ( -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "leE" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -36412,6 +37112,12 @@ }, /turf/open/floor/glass/reinforced, /area/station/hallway/primary/starboard) +"leP" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "leW" = ( /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, @@ -36461,13 +37167,11 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/medical/storage) -"lfR" = ( -/obj/machinery/light/small/directional/north, -/obj/effect/turf_decal/siding/thinplating{ - dir = 8 - }, -/turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/underground/explored) +"lgb" = ( +/obj/effect/landmark/start/botanist, +/obj/structure/chair/office/light, +/turf/open/floor/glass, +/area/station/service/hydroponics) "lgg" = ( /obj/machinery/air_sensor/engine_chamber, /turf/open/floor/engine, @@ -36485,17 +37189,6 @@ /obj/effect/turf_decal/tile/red/full, /turf/open/floor/iron/dark/textured_large, /area/station/security/brig/entrance) -"lgA" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 1 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "lgD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -36519,6 +37212,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/port/fore) +"lgP" = ( +/obj/machinery/atmospherics/components/binary/pump/on{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/layer_manifold/scrubbers/hidden{ + dir = 8 + }, +/turf/open/floor/engine, +/area/station/science/ordnance) "lgW" = ( /obj/machinery/meter/monitored/distro_loop, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible, @@ -36590,6 +37292,19 @@ }, /turf/open/floor/iron, /area/station/command/heads_quarters/qm) +"liv" = ( +/obj/structure/cable, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 8 + }, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 4 + }, +/obj/structure/minecart_rail{ + dir = 1 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "lix" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -36805,6 +37520,19 @@ "lli" = ( /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"llm" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/item/gun/ballistic/shotgun/doublebarrel, +/obj/structure/rack, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/turf_decal/box/red, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/iron/grimy, +/area/station/service/bar/backroom) "llw" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -36819,17 +37547,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/psychology) -"llG" = ( -/obj/effect/turf_decal/siding/white{ - dir = 6 - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/start/hangover, -/obj/machinery/firealarm/directional/east, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "llT" = ( /obj/effect/turf_decal/weather/snow/corner{ dir = 1 @@ -36862,15 +37579,6 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron/dark/textured, /area/station/security/range) -"lmm" = ( -/obj/effect/turf_decal/trimline/green/filled/corner{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/blue/corner{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "lms" = ( /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating, @@ -36903,10 +37611,6 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/dark, /area/station/engineering/atmos/storage) -"lmB" = ( -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron/smooth, -/area/station/maintenance/starboard/lesser) "lmK" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -36951,16 +37655,6 @@ /obj/machinery/firealarm/directional/west, /turf/open/floor/iron/grimy, /area/station/hallway/secondary/entry) -"lnq" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "lnr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, @@ -37155,13 +37849,6 @@ }, /turf/open/floor/iron, /area/station/security/prison/mess) -"lqh" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "lqj" = ( /obj/structure/chair/pew/right{ dir = 1 @@ -37170,15 +37857,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/dark, /area/station/service/chapel) -"lqs" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "lqz" = ( /obj/structure/cable, /turf/closed/wall, @@ -37190,19 +37868,6 @@ }, /turf/open/floor/iron/textured, /area/mine/mechbay) -"lqB" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/duct, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "lqE" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple{ dir = 10 @@ -37261,12 +37926,14 @@ /obj/structure/curtain, /turf/open/floor/iron/freezer, /area/station/command/heads_quarters/captain) -"lrN" = ( +"lrE" = ( +/obj/effect/landmark/generic_maintenance_landmark, +/obj/item/bikehorn/rubberducky, +/obj/structure/cable, /obj/effect/landmark/start/hangover, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/obj/structure/chair/stool/directional/north, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "lsa" = ( /obj/machinery/door/poddoor/shutters/preopen{ dir = 4; @@ -37276,6 +37943,11 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/science/robotics/lab) +"lsh" = ( +/obj/structure/closet/emcloset, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/fore) "lsi" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -37288,6 +37960,23 @@ "lso" = ( /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"lsH" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "lsN" = ( /obj/effect/turf_decal/trimline/red/filled/corner{ dir = 8 @@ -37363,17 +38052,17 @@ }, /turf/open/floor/iron/white/side, /area/station/science/ordnance/office) +"luR" = ( +/obj/item/toy/snowball{ + pixel_x = 9; + pixel_y = 1 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "lva" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/science/xenobiology) -"lvc" = ( -/obj/item/clothing/mask/fakemoustache, -/obj/item/clothing/mask/cigarette/pipe, -/obj/structure/table/wood, -/obj/structure/sign/poster/contraband/random/directional/south, -/turf/open/floor/wood/tile, -/area/station/service/theater) "lvh" = ( /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/iron, @@ -37397,21 +38086,15 @@ "lvt" = ( /turf/open/openspace/icemoon, /area/icemoon/underground/explored) -"lvu" = ( -/obj/machinery/door/airlock/highsecurity{ - name = "Service Hall Exit" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "service-hall-external" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/turf/open/floor/iron/textured_half{ - dir = 1 - }, -/area/station/hallway/secondary/service) +"lvv" = ( +/obj/machinery/newscaster/directional/east, +/turf/open/floor/stone, +/area/station/commons/lounge) +"lvy" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/hydroponics) "lvB" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -37433,13 +38116,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) -"lvO" = ( -/obj/item/clothing/mask/animal/pig, -/obj/item/bikehorn, -/obj/structure/table/wood, -/obj/structure/sign/poster/contraband/random/directional/west, -/turf/open/floor/wood/tile, -/area/station/service/theater) "lvQ" = ( /obj/machinery/light/small/directional/east, /obj/effect/decal/cleanable/dirt, @@ -37538,17 +38214,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/commons/storage/tools) -"lxf" = ( -/obj/structure/table, -/obj/item/reagent_containers/condiment/saltshaker{ - pixel_x = -3 - }, -/obj/item/reagent_containers/condiment/peppermill{ - pixel_x = 3 - }, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "lxn" = ( /obj/machinery/biogenerator, /obj/structure/window/reinforced/spawner/directional/north, @@ -37590,6 +38255,14 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/nuke_storage) +"lyf" = ( +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/structure/extinguisher_cabinet/directional/south, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "lyg" = ( /turf/closed/wall/r_wall, /area/station/security/brig) @@ -37626,6 +38299,13 @@ /obj/machinery/airalarm/directional/south, /turf/open/floor/stone, /area/mine/eva/lower) +"lyv" = ( +/obj/structure/table/wood/poker, +/obj/item/trash/candle{ + pixel_y = 3 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "lyG" = ( /turf/open/floor/glass/reinforced, /area/station/ai_monitored/security/armory/upper) @@ -37634,11 +38314,26 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/brown/visible/layer2, /turf/closed/wall/r_wall, /area/station/maintenance/disposal/incinerator) -"lyW" = ( -/obj/structure/chair/sofa/corp/left, -/obj/item/radio/intercom/directional/north, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) +"lyP" = ( +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/obj/machinery/airalarm/directional/north, +/obj/machinery/camera{ + c_tag = "Service - Botany Lower Entrance"; + dir = 9 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"lyU" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 1 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "lyX" = ( /obj/structure/chair{ dir = 4 @@ -37646,6 +38341,10 @@ /obj/structure/sign/poster/contraband/random/directional/north, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"lzc" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/plating, +/area/station/maintenance/fore) "lzq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -37739,12 +38438,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"lAB" = ( -/obj/structure/rack, -/obj/item/crowbar, -/obj/item/pickaxe, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "lAC" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/machinery/door/airlock/external{ @@ -37753,15 +38446,6 @@ }, /turf/open/floor/plating, /area/station/hallway/secondary/entry) -"lAG" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "lAL" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -37771,15 +38455,6 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/security/warden) -"lBb" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "lBo" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /turf/open/floor/carpet, @@ -37791,11 +38466,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"lBy" = ( -/obj/effect/turf_decal/siding/white, -/obj/machinery/digital_clock/directional/south, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "lBD" = ( /obj/structure/flora/grass/green/style_random, /turf/open/misc/asteroid/snow/icemoon, @@ -37836,6 +38506,11 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"lCv" = ( +/obj/machinery/firealarm/directional/west, +/obj/structure/closet/crate/wooden/toy, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "lCz" = ( /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/bot, @@ -37870,6 +38545,11 @@ dir = 1 }, /area/station/engineering/lobby) +"lCO" = ( +/obj/machinery/duct, +/obj/structure/disposalpipe/segment, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "lCV" = ( /obj/machinery/door/airlock/maintenance, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -37891,11 +38571,6 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/station/hallway/primary/aft) -"lDg" = ( -/obj/structure/window/reinforced/spawner/directional/east, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) "lDh" = ( /obj/structure/table, /obj/effect/turf_decal/stripes/red/line{ @@ -37922,12 +38597,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) -"lDp" = ( -/obj/machinery/duct, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "lDq" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -37993,6 +38662,25 @@ /obj/structure/cable, /turf/open/floor/carpet/blue, /area/station/security/prison/work) +"lEb" = ( +/obj/machinery/door/airlock/multi_tile/public/glass{ + dir = 4; + name = "Service Hall" + }, +/obj/effect/turf_decal/siding/dark/corner, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/mapping_helpers/airlock/access/all/service/general, +/obj/effect/landmark/navigate_destination, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/hallway/secondary/service) "lEg" = ( /obj/machinery/door/window/left/directional/north{ name = "AI Core Door"; @@ -38004,6 +38692,17 @@ "lEj" = ( /turf/open/floor/iron/dark/textured, /area/station/security/processing) +"lEn" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table, +/obj/item/stack/sheet/mineral/coal{ + pixel_x = 6; + pixel_y = 3 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "lEo" = ( /obj/effect/turf_decal/trimline/blue/filled/line, /obj/structure/disposalpipe/segment{ @@ -38050,27 +38749,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/hallway/primary/port) -"lEH" = ( -/obj/structure/table/glass, -/obj/item/grenade/chem_grenade/antiweed, -/obj/item/reagent_containers/spray/plantbgone{ - pixel_y = 3 - }, -/obj/item/reagent_containers/spray/plantbgone{ - pixel_x = 8; - pixel_y = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/siding/white{ - dir = 6 - }, -/obj/effect/turf_decal/tile/green/opposingcorners{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners, -/turf/open/floor/iron, -/area/station/service/hydroponics) "lEK" = ( /obj/machinery/door/firedoor, /obj/structure/cable, @@ -38222,11 +38900,19 @@ dir = 1 }, /area/station/hallway/secondary/entry) -"lGY" = ( -/obj/structure/chair/stool/directional/south, -/obj/effect/landmark/start/hangover, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) +"lHi" = ( +/obj/effect/turf_decal/tile/blue{ + dir = 1 + }, +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) +"lHr" = ( +/obj/structure/stairs/north, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "lHu" = ( /obj/structure/closet/secure_closet/brig, /obj/structure/cable, @@ -38266,6 +38952,17 @@ }, /turf/open/floor/iron/dark/corner, /area/station/engineering/atmos/storage/gas) +"lHI" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/siding/white/corner{ + dir = 8 + }, +/obj/structure/window/reinforced/spawner/directional/west, +/turf/open/floor/iron, +/area/station/service/hydroponics) "lHL" = ( /obj/structure/cable, /obj/effect/turf_decal/stripes/corner{ @@ -38382,6 +39079,12 @@ "lIW" = ( /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat_interior) +"lJc" = ( +/obj/item/food/chococoin, +/obj/structure/closet/secure_closet/freezer/fridge, +/obj/effect/turf_decal/weather/snow/corner, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "lJO" = ( /turf/closed/wall, /area/station/maintenance/port/fore) @@ -38392,6 +39095,18 @@ }, /turf/open/floor/iron/dark/textured, /area/station/security/prison) +"lJW" = ( +/obj/machinery/smartfridge, +/obj/machinery/door/window/right/directional/south{ + name = "Produce Access"; + req_access = list("hydroponics") + }, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "lKc" = ( /obj/effect/turf_decal/stripes/corner{ dir = 4 @@ -38474,6 +39189,16 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/laborcamp) +"lLR" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 9 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 9 + }, +/obj/machinery/hydroponics/constructable, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "lLY" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/recharge_floor, @@ -38488,6 +39213,10 @@ /obj/item/food/cheesiehonkers, /turf/open/floor/iron, /area/station/cargo/office) +"lMe" = ( +/obj/effect/spawner/structure/window, +/turf/open/floor/plating, +/area/station/service/kitchen) "lMg" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -38630,12 +39359,6 @@ /obj/machinery/light/small/dim/directional/east, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"lOt" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/door/window/left/directional/east, -/obj/structure/sign/warning/gas_mask/directional/north, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "lOz" = ( /obj/machinery/door/airlock{ id_tag = "Dorm2"; @@ -38693,13 +39416,6 @@ }, /turf/open/floor/iron/sepia, /area/station/service/library) -"lPm" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "lPr" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -38749,15 +39465,12 @@ }, /turf/open/floor/iron/dark/textured_large, /area/station/cargo/bitrunning/den) -"lPN" = ( -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/south, -/obj/effect/turf_decal/siding/white{ - dir = 1 +"lPQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, -/area/station/hallway/secondary/service) +/area/station/commons/fitness) "lQc" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -38831,13 +39544,6 @@ /obj/structure/mineral_door/wood, /turf/open/floor/wood, /area/station/maintenance/space_hut/cabin) -"lQV" = ( -/obj/effect/turf_decal/tile/red/half/contrasted{ - dir = 4 - }, -/obj/machinery/light/small/directional/east, -/turf/open/floor/iron, -/area/station/commons/fitness) "lRc" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -38949,14 +39655,6 @@ }, /turf/open/floor/iron, /area/station/commons/storage/tools) -"lSl" = ( -/obj/structure/chair/stool/bar/directional/south, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/machinery/light/directional/east, -/turf/open/floor/stone, -/area/station/commons/lounge) "lSu" = ( /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors/nospawn) @@ -39015,13 +39713,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/space_hut/cabin) -"lTJ" = ( -/obj/structure/railing, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "lUa" = ( /obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ dir = 1 @@ -39057,12 +39748,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/brig/upper) -"lUy" = ( -/obj/item/food/pie/cream, -/obj/machinery/newscaster/directional/north, -/obj/structure/table/wood, -/turf/open/floor/iron, -/area/station/service/theater) "lUC" = ( /turf/closed/wall, /area/station/maintenance/department/electrical) @@ -39148,6 +39833,15 @@ }, /turf/open/floor/wood, /area/station/service/library) +"lVN" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/disposalpipe/trunk/multiz/down{ + dir = 1 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "lVY" = ( /obj/effect/turf_decal/siding/thinplating_new/corner{ dir = 4 @@ -39224,11 +39918,12 @@ }, /turf/open/floor/iron/smooth, /area/station/maintenance/port/fore) -"lXo" = ( -/obj/structure/table/wood/poker, -/obj/item/storage/dice, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) +"lXC" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/solars/starboard/fore) "lXJ" = ( /obj/structure/railing{ dir = 1 @@ -39260,16 +39955,6 @@ }, /turf/open/floor/grass, /area/station/medical/virology) -"lYY" = ( -/obj/item/clothing/suit/hooded/wintercoat, -/obj/item/clothing/suit/hooded/wintercoat, -/obj/item/clothing/suit/hooded/wintercoat, -/obj/effect/turf_decal/stripes/white/corner{ - dir = 1 - }, -/obj/structure/closet/chefcloset, -/turf/open/floor/plating, -/area/station/service/kitchen/coldroom) "lZe" = ( /obj/effect/turf_decal/tile/blue/opposingcorners{ dir = 1 @@ -39281,22 +39966,11 @@ /obj/structure/railing, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"lZv" = ( -/obj/structure/table/glass, -/obj/item/seeds/bamboo, +"lZP" = ( +/obj/effect/turf_decal/stripes/line, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible/layer4, /turf/open/floor/plating, -/area/station/maintenance/starboard/fore) -"lZG" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/table/wood, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) +/area/station/maintenance/fore) "lZQ" = ( /obj/machinery/airalarm/directional/west, /obj/machinery/computer/cargo{ @@ -39329,11 +40003,26 @@ }, /turf/open/floor/plating, /area/station/medical/pharmacy) +"maw" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "maB" = ( /obj/structure/chair/stool/directional/north, /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, /area/station/commons/dorms) +"maM" = ( +/obj/item/paper/fluff/jobs/security/beepsky_mom, +/obj/machinery/light/small/dim/directional/east, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/turf/open/floor/plating, +/area/station/maintenance/fore) "maO" = ( /obj/machinery/disposal/bin, /obj/structure/window/reinforced/spawner/directional/south, @@ -39362,6 +40051,18 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/cargo/storage) +"maX" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "maY" = ( /obj/item/wrench, /obj/item/weldingtool, @@ -39503,6 +40204,23 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/smooth_large, /area/station/command/heads_quarters/hos) +"mcQ" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/status_display/evac/directional/north, +/obj/effect/turf_decal/siding/wood/corner, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/service/bar) +"mcT" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/commons/fitness) "mcW" = ( /turf/open/floor/iron/white, /area/station/medical/medbay/central) @@ -39519,15 +40237,6 @@ /obj/effect/landmark/start/prisoner, /turf/open/floor/iron, /area/station/security/prison/work) -"mdy" = ( -/obj/structure/railing/corner{ - dir = 4 - }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 8 - }, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "mdE" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -39585,22 +40294,10 @@ "mdZ" = ( /turf/closed/wall, /area/station/hallway/secondary/service) -"men" = ( -/obj/machinery/duct, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "mep" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"meB" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "meG" = ( /obj/item/kirbyplants/random, /obj/structure/cable, @@ -39646,12 +40343,6 @@ /obj/machinery/power/apc/auto_name/directional/east, /turf/open/floor/iron/dark, /area/mine/eva/lower) -"mfz" = ( -/obj/machinery/door/airlock{ - name = "Unit B" - }, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "mfD" = ( /turf/closed/wall/r_wall, /area/station/ai_monitored/turret_protected/aisat/atmos) @@ -39702,46 +40393,15 @@ }, /turf/open/floor/iron, /area/station/science/robotics/lab) -"mgw" = ( -/obj/structure/cable, -/obj/effect/mapping_helpers/broken_floor, -/obj/effect/landmark/generic_maintenance_landmark, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) +"mgy" = ( +/obj/effect/turf_decal/stripes/line, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/textured, +/area/station/service/hydroponics) "mgD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, /turf/open/floor/engine, /area/station/maintenance/disposal/incinerator) -"mgN" = ( -/obj/machinery/door/airlock{ - name = "Kitchen" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 4; - id = "kitchencounter"; - name = "Kitchen Shutters" - }, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) -"mgR" = ( -/obj/effect/turf_decal/siding/wood, -/obj/machinery/reagentgrinder{ - pixel_x = 6; - pixel_y = 6 - }, -/obj/item/reagent_containers/cup/glass/shaker{ - pixel_x = -6 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/table/wood, -/turf/open/floor/stone, -/area/station/service/bar) "mgU" = ( /turf/closed/wall/r_wall, /area/station/command/heads_quarters/hos) @@ -39770,6 +40430,12 @@ }, /turf/open/floor/iron, /area/station/ai_monitored/command/storage/eva) +"mhj" = ( +/obj/structure/railing/wooden_fence{ + dir = 10 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "mhq" = ( /obj/structure/closet, /obj/effect/spawner/random/maintenance, @@ -39797,19 +40463,6 @@ }, /turf/open/floor/iron, /area/station/engineering/lobby) -"miR" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 10 - }, -/obj/item/book/manual/wiki/barman_recipes{ - pixel_x = 5; - pixel_y = 6 - }, -/obj/item/reagent_containers/cup/rag, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/table/wood, -/turf/open/floor/stone, -/area/station/service/bar) "miS" = ( /obj/structure/table, /obj/item/stack/cable_coil{ @@ -39899,6 +40552,16 @@ }, /turf/open/floor/iron, /area/station/science/explab) +"mkr" = ( +/obj/structure/closet/secure_closet/hydroponics, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/machinery/newscaster/directional/south, +/obj/machinery/light/small/directional/east, +/turf/open/floor/iron, +/area/station/service/hydroponics) "mku" = ( /obj/effect/spawner/random/structure/grille, /obj/effect/decal/cleanable/glass, @@ -39917,6 +40580,14 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"mkM" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/fore) "mld" = ( /obj/effect/turf_decal/tile/yellow{ dir = 1 @@ -39949,6 +40620,18 @@ /obj/structure/cable/layer3, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) +"mlN" = ( +/obj/structure/railing{ + dir = 6 + }, +/obj/effect/turf_decal/siding/white{ + dir = 6 + }, +/obj/structure/curtain/cloth/fancy/mechanical/start_closed{ + id = "cantena_curtains" + }, +/turf/open/floor/wood, +/area/station/commons/lounge) "mlO" = ( /obj/structure/disposalpipe/segment, /obj/machinery/airalarm/directional/east, @@ -39977,6 +40660,15 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"mmf" = ( +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/structure/railing{ + dir = 10 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "mmh" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -40048,18 +40740,12 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) -"mnj" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/red/half{ - dir = 4 - }, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/hallway/secondary/service) +"mnn" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible/layer4, +/obj/effect/turf_decal/stripes/line, +/obj/structure/chair/stool/directional/west, +/turf/open/floor/plating, +/area/station/maintenance/fore) "mnu" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -40080,13 +40766,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) -"mnE" = ( -/obj/item/vending_refill/cigarette, -/obj/structure/table/wood, -/obj/machinery/airalarm/directional/east, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "mnF" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -40116,13 +40795,6 @@ /obj/machinery/firealarm/directional/east, /turf/open/floor/iron, /area/station/cargo/storage) -"mow" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/landmark/event_spawn, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "moB" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -40241,10 +40913,6 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/service/hydroponics) -"mpZ" = ( -/obj/machinery/light/directional/south, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "mqe" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk{ @@ -40260,12 +40928,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"mqr" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "mqs" = ( /obj/effect/turf_decal/bot, /obj/structure/sign/warning/cold_temp/directional/north, @@ -40323,15 +40985,6 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/white, /area/station/maintenance/port/fore) -"mru" = ( -/obj/structure/sign/warning/directional/north, -/obj/machinery/light/small/directional/north, -/obj/effect/turf_decal/caution/stand_clear, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron/dark/textured, -/area/station/hallway/secondary/service) "mrw" = ( /obj/effect/turf_decal/tile/purple/half/contrasted{ dir = 4 @@ -40374,15 +41027,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/surgery/aft) -"mrF" = ( -/obj/effect/landmark/start/hangover, -/obj/effect/turf_decal/tile/red/half{ - dir = 4 - }, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/hallway/secondary/service) "mrI" = ( /obj/structure/railing{ dir = 1 @@ -40400,13 +41044,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/virology) -"mrX" = ( -/obj/effect/turf_decal/stripes/white/line{ - dir = 8 - }, -/obj/structure/closet/emcloset, -/turf/open/floor/plating, -/area/station/service/kitchen/coldroom) "msb" = ( /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, @@ -40549,12 +41186,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/engineering/atmos/storage) -"mui" = ( -/obj/structure/chair/wood{ - dir = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "mut" = ( /obj/machinery/hydroponics/soil, /obj/machinery/light/directional/east, @@ -40656,12 +41287,6 @@ }, /turf/open/floor/plating, /area/station/medical/pharmacy) -"mwH" = ( -/obj/item/trash/popcorn, -/obj/effect/landmark/generic_maintenance_landmark, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) "mwQ" = ( /obj/structure/tank_holder/extinguisher, /turf/open/floor/plating, @@ -40675,6 +41300,10 @@ }, /turf/open/floor/iron, /area/station/science/ordnance) +"mxh" = ( +/obj/structure/cable, +/turf/open/floor/stone, +/area/station/commons/lounge) "mxj" = ( /obj/machinery/atmospherics/components/binary/pump{ name = "Port Mix to East Ports" @@ -40714,6 +41343,13 @@ /obj/machinery/computer/security/telescreen/entertainment/directional/east, /turf/open/floor/iron/grimy, /area/station/hallway/secondary/entry) +"mxY" = ( +/obj/structure/minecart_rail{ + dir = 9 + }, +/obj/structure/cable, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) "mye" = ( /obj/machinery/door/airlock/maintenance, /obj/structure/disposalpipe/segment, @@ -40770,6 +41406,22 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/department/cargo) +"myS" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/machinery/camera/directional/south{ + c_tag = "Service - Botany Garden Access" + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "myU" = ( /obj/structure/table/glass, /obj/item/assembly/signaler{ @@ -40812,6 +41464,11 @@ /obj/structure/lattice/catwalk, /turf/open/openspace/icemoon/keep_below, /area/icemoon/underground/explored) +"mza" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "mzb" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron, @@ -40823,15 +41480,6 @@ }, /turf/open/floor/iron/dark, /area/station/cargo/drone_bay) -"mzs" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/light_switch/directional/east, -/obj/structure/sink/kitchen/directional/west, -/obj/structure/table, -/obj/item/book/manual/chef_recipes, -/obj/item/holosign_creator/robot_seat/restaurant, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "mzu" = ( /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 8 @@ -40892,15 +41540,6 @@ "mAe" = ( /turf/open/floor/glass/reinforced, /area/station/security/lockers) -"mAz" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Fitness" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/commons/fitness) "mAM" = ( /obj/structure/ladder, /obj/machinery/light/small/red/directional/west, @@ -40995,15 +41634,6 @@ }, /turf/open/floor/wood, /area/station/command/heads_quarters/captain) -"mCb" = ( -/mob/living/basic/goat/pete{ - desc = "Not known for their pleasant disposition. This one seems a bit more hardy to the cold."; - habitable_atmos = list("min_oxy"=1,"max_oxy"=0,"min_plas"=0,"max_plas"=1,"min_co2"=0,"max_co2"=5,"min_n2"=0,"max_n2"=0); - minimum_survivable_temperature = 150; - name = "Snowy Pete" - }, -/turf/open/misc/asteroid/snow/coldroom, -/area/station/service/kitchen/coldroom) "mCw" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/hatch{ @@ -41027,13 +41657,6 @@ /obj/machinery/hydroponics/soil, /turf/open/floor/grass, /area/station/service/hydroponics/garden) -"mCX" = ( -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "mDf" = ( /obj/machinery/telecomms/server/presets/common, /turf/open/floor/iron/dark/telecomms, @@ -41147,18 +41770,6 @@ }, /turf/open/floor/iron, /area/station/science/ordnance/testlab) -"mEZ" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/obj/machinery/camera/directional/south{ - c_tag = "Service Hallway - Upper West" - }, -/obj/machinery/modular_computer/preset/cargochat/service{ - dir = 1 - }, -/turf/open/floor/plating, -/area/station/hallway/secondary/service) "mFj" = ( /obj/effect/spawner/random/structure/crate, /turf/open/floor/plating, @@ -41254,6 +41865,13 @@ /obj/structure/lattice/catwalk, /turf/open/openspace/icemoon, /area/station/science/server) +"mGF" = ( +/obj/effect/decal/cleanable/confetti, +/obj/structure/closet/crate/cardboard, +/obj/item/storage/cans/sixbeer, +/obj/effect/spawner/random/food_or_drink/cups, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "mGJ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -41327,18 +41945,6 @@ }, /turf/open/floor/plating, /area/station/medical/pharmacy) -"mIB" = ( -/obj/structure/cable, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) -"mIC" = ( -/obj/machinery/door/airlock/research/glass/incinerator/ordmix_exterior{ - name = "Burn Chamber Exterior Airlock" - }, -/obj/effect/mapping_helpers/airlock/locked, -/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance/burnchamber) "mIE" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -41385,24 +41991,12 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/solars/starboard/aft) -"mJr" = ( -/obj/effect/spawner/random/trash/mess, -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "mJu" = ( /obj/structure/table/glass, /turf/open/floor/iron/chapel{ dir = 4 }, /area/station/service/chapel) -"mJD" = ( -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "mJM" = ( /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 1 @@ -41441,20 +42035,6 @@ dir = 8 }, /area/station/hallway/secondary/entry) -"mKh" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/airlock/maintenance{ - name = "Service Hall Maintenance" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/obj/machinery/duct, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "mKq" = ( /obj/structure/closet/secure_closet/evidence, /obj/machinery/light/small/directional/north, @@ -41518,6 +42098,12 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"mMi" = ( +/obj/effect/turf_decal/tile/neutral/diagonal_edge, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/kitchen/diagonal, +/area/station/service/kitchen) "mMk" = ( /obj/machinery/telecomms/message_server/preset, /turf/open/floor/iron/dark/telecomms, @@ -41537,6 +42123,10 @@ /obj/machinery/firealarm/directional/west, /turf/open/floor/carpet, /area/station/service/library) +"mMI" = ( +/obj/structure/secure_safe/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "mMM" = ( /turf/closed/wall/r_wall, /area/station/security/prison) @@ -41565,6 +42155,13 @@ }, /turf/open/floor/plating/icemoon, /area/station/science/ordnance/bomb) +"mMZ" = ( +/obj/structure/cable, +/obj/effect/turf_decal/box/red/corners{ + dir = 1 + }, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "mNj" = ( /obj/machinery/computer/security{ dir = 4 @@ -41635,6 +42232,16 @@ }, /turf/open/floor/iron, /area/station/cargo/office) +"mOH" = ( +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/item/kirbyplants/random, +/turf/open/floor/iron, +/area/station/commons/fitness) "mOL" = ( /obj/machinery/airalarm/directional/south, /obj/structure/disposalpipe/segment{ @@ -41709,6 +42316,11 @@ /obj/structure/sign/warning/radiation/rad_area/directional/south, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"mPQ" = ( +/obj/structure/table/wood, +/obj/effect/spawner/random/decoration/ornament, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "mQb" = ( /obj/structure/flora/grass/both/style_random, /turf/open/misc/asteroid/snow/icemoon, @@ -41761,24 +42373,17 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"mRa" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/start/mime, -/turf/open/floor/wood/tile, -/area/station/service/theater) "mRr" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) -"mRs" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) +"mRv" = ( +/obj/structure/chair/stool/directional/west, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/stone, +/area/station/commons/lounge) "mRG" = ( /obj/structure/table, /obj/item/book/manual/wiki/atmospherics, @@ -41800,6 +42405,15 @@ /obj/structure/cable/layer3, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/hallway) +"mRN" = ( +/obj/structure/railing, +/obj/structure/closet, +/obj/effect/spawner/random/maintenance/four, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "mRU" = ( /obj/effect/decal/cleanable/insectguts, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, @@ -41867,6 +42481,15 @@ }, /turf/open/floor/engine/air, /area/station/engineering/atmos) +"mTA" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/turf/open/floor/iron, +/area/station/service/kitchen/coldroom) "mTI" = ( /obj/structure/sink/kitchen/directional/south{ desc = "A sink used for washing one's hands and face. It looks rusty and home-made"; @@ -41875,6 +42498,19 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/freezer, /area/mine/laborcamp) +"mTL" = ( +/obj/structure/closet/secure_closet/bar, +/obj/machinery/firealarm/directional/north{ + pixel_x = 4 + }, +/obj/machinery/light/small/directional/north, +/obj/machinery/light_switch/directional/north{ + pixel_x = -5; + pixel_y = 28 + }, +/obj/item/vending_refill/cigarette, +/turf/open/floor/wood/parquet, +/area/station/service/bar/backroom) "mTS" = ( /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 4 @@ -41931,30 +42567,16 @@ /obj/effect/landmark/generic_maintenance_landmark, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"mUR" = ( -/obj/machinery/firealarm/directional/north{ - pixel_x = -26 - }, -/obj/structure/chair, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/white, -/area/station/medical/medbay/lobby) -"mUU" = ( -/obj/effect/landmark/event_spawn, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) +"mUW" = ( +/obj/effect/spawner/random/structure/crate, +/obj/effect/spawner/random/trash/botanical_waste, +/obj/effect/spawner/random/food_or_drink/donkpockets, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "mVe" = ( /obj/machinery/button/ignition/incinerator/atmos, /turf/closed/wall/r_wall, /area/station/maintenance/disposal/incinerator) -"mVh" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "mVm" = ( /obj/structure/grille/broken, /turf/open/misc/asteroid/snow/icemoon, @@ -41998,13 +42620,20 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"mVY" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 +"mVW" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Dormitory" }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured, +/area/station/commons/dorms) "mWf" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -42027,16 +42656,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/station/engineering/lobby) -"mWp" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/hydroponics/glass{ - name = "Hydroponics" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, -/turf/open/floor/iron/textured_half{ - dir = 1 - }, -/area/station/service/hydroponics) "mWs" = ( /obj/structure/table, /obj/item/storage/toolbox/emergency, @@ -42144,14 +42763,6 @@ }, /turf/open/floor/iron, /area/mine/laborcamp) -"mXt" = ( -/obj/item/radio/intercom/directional/east, -/obj/effect/turf_decal/siding/white{ - dir = 6 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "mXA" = ( /obj/effect/landmark/blobstart, /obj/effect/mapping_helpers/burnt_floor, @@ -42190,10 +42801,11 @@ }, /turf/open/floor/plating, /area/station/hallway/secondary/entry) -"mYd" = ( -/obj/machinery/air_sensor/ordnance_burn_chamber, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance/burnchamber) +"mXW" = ( +/obj/structure/flora/bush/flowers_pp/style_random, +/obj/structure/flora/bush/flowers_br/style_random, +/turf/open/floor/grass, +/area/station/service/hydroponics) "mYh" = ( /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) @@ -42208,6 +42820,10 @@ }, /turf/open/floor/iron/white, /area/mine/laborcamp) +"mYn" = ( +/obj/machinery/duct, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "mYq" = ( /obj/machinery/requests_console/directional/north{ department = "Research Director's Desk"; @@ -42220,16 +42836,6 @@ /obj/machinery/pdapainter/research, /turf/open/floor/iron/white, /area/station/command/heads_quarters/rd) -"mYr" = ( -/obj/structure/table/wood, -/obj/effect/spawner/random/entertainment/gambling{ - pixel_y = 9 - }, -/obj/item/storage/fancy/donut_box{ - pixel_x = -6 - }, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "mYs" = ( /obj/machinery/computer/records/security{ dir = 8 @@ -42246,16 +42852,6 @@ }, /turf/open/floor/iron, /area/station/security/checkpoint/supply) -"mYG" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/obj/effect/landmark/start/mime, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/tile, -/area/station/service/theater) "mYJ" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -42415,6 +43011,13 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/external, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"nbl" = ( +/obj/structure/minecart_rail{ + dir = 4 + }, +/obj/structure/cable, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) "nbm" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 6 @@ -42468,6 +43071,13 @@ /obj/machinery/door/firedoor, /turf/open/floor/plating, /area/station/medical/treatment_center) +"nbI" = ( +/obj/structure/cable, +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "nbJ" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -42482,12 +43092,30 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/mining, /turf/open/floor/iron/smooth, /area/mine/eva/lower) +"nbL" = ( +/obj/structure/table/wood, +/obj/item/camera, +/obj/item/taperecorder, +/obj/item/radio/intercom/directional/east, +/obj/structure/sign/painting/library_private{ + pixel_y = 32 + }, +/obj/item/storage/photo_album/library, +/turf/open/floor/engine/cult, +/area/station/service/library) "nbM" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple/layer2{ dir = 5 }, /turf/open/floor/iron/dark/airless, /area/station/science/ordnance/freezerchamber) +"nbO" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/kitchen/coldroom) "nbP" = ( /obj/structure/bonfire/prelit, /turf/open/misc/asteroid/snow/icemoon, @@ -42536,6 +43164,29 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) +"ncc" = ( +/obj/effect/turf_decal/tile/bar{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/table, +/obj/item/paper{ + pixel_y = 4 + }, +/obj/item/pen{ + pixel_x = -5 + }, +/turf/open/floor/iron, +/area/station/service/kitchen/coldroom) +"ncd" = ( +/obj/effect/turf_decal/siding/white, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/hydroponics) "nci" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -42555,6 +43206,17 @@ /obj/item/kirbyplants/random, /turf/open/floor/iron, /area/station/commons/locker) +"ncx" = ( +/obj/structure/table/wood, +/obj/item/soap/deluxe{ + pixel_y = 11 + }, +/obj/item/soap/deluxe{ + pixel_y = 6 + }, +/obj/item/soap/deluxe, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "ncB" = ( /obj/machinery/door/airlock/security/glass{ name = "Brig Walkway" @@ -42693,14 +43355,6 @@ }, /turf/open/floor/iron/smooth, /area/station/security/brig) -"nep" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/machinery/door/window/right/directional/east, -/obj/structure/sign/warning/cold_temp/directional/south, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "neq" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/blue/half/contrasted, @@ -42751,6 +43405,20 @@ /obj/machinery/hydroponics/soil, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"neQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/door/airlock/maintenance, +/obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "neR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/orange/visible, /obj/machinery/meter, @@ -42806,6 +43474,14 @@ }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) +"nfK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/light/floor, +/turf/open/floor/wood, +/area/station/commons/lounge) "nfU" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -42828,6 +43504,12 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron, /area/station/command/heads_quarters/rd) +"ngh" = ( +/obj/structure/fence{ + dir = 4 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/nospawn) "ngj" = ( /obj/effect/turf_decal/stripes/asteroid/line{ dir = 9 @@ -42846,17 +43528,6 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/mine/production) -"ngH" = ( -/obj/machinery/portable_atmospherics/canister/air, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible/layer4, -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 1 - }, -/turf/open/floor/plating, -/area/station/maintenance/fore) "ngM" = ( /obj/structure/lattice/catwalk, /obj/structure/fence/door{ @@ -42894,6 +43565,16 @@ /obj/structure/mirror/directional/west, /turf/open/floor/iron/showroomfloor, /area/station/security/prison/toilet) +"nhv" = ( +/obj/effect/spawner/random/structure/closet_maintenance, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/structure/railing{ + dir = 10 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "nhw" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -43014,20 +43695,12 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/engineering/transit_tube) -"njn" = ( -/obj/machinery/holopad, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/hydroponics) -"njx" = ( -/obj/machinery/door/window/left/directional/east{ - name = "Fitness Ring" - }, -/obj/structure/window/reinforced/spawner/directional/south, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +"njz" = ( +/obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "njA" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, @@ -43036,6 +43709,14 @@ "njJ" = ( /turf/closed/wall, /area/mine/laborcamp) +"njM" = ( +/obj/item/radio/intercom/directional/east, +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "njO" = ( /obj/effect/spawner/random/trash/mess, /turf/open/floor/plating, @@ -43083,13 +43764,6 @@ /obj/structure/tank_holder/oxygen, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"nkM" = ( -/obj/machinery/door/airlock{ - name = "Unisex Showers" - }, -/obj/structure/cable, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "nkO" = ( /obj/structure/table, /obj/item/storage/box/matches, @@ -43102,10 +43776,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/vault, /area/station/security/prison/rec) -"nkQ" = ( -/obj/structure/cable, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) +"nla" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "nll" = ( /obj/structure/table, /obj/item/stack/sheet/iron/fifty{ @@ -43133,11 +43807,17 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/construction) -"nlI" = ( -/obj/effect/landmark/start/hangover, -/obj/effect/turf_decal/tile/neutral/half/contrasted, -/turf/open/floor/iron, -/area/station/commons/dorms) +"nlA" = ( +/obj/item/clothing/head/beanie/orange{ + pixel_y = 8 + }, +/obj/item/clothing/suit/hooded/wintercoat, +/obj/item/clothing/shoes/wheelys/skishoes{ + pixel_y = -8 + }, +/obj/effect/decal/remains/human, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "nlJ" = ( /obj/structure/railing{ dir = 5 @@ -43195,18 +43875,16 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/central) -"nmg" = ( -/obj/machinery/door/airlock/external{ - glass = 1; - name = "Service External Airlock"; - opacity = 0 - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +"nmi" = ( +/obj/structure/closet/chefcloset, +/obj/item/clothing/suit/hooded/wintercoat, +/obj/item/clothing/suit/hooded/wintercoat, +/obj/item/clothing/suit/hooded/wintercoat, +/obj/machinery/airalarm/directional/north, +/obj/effect/mapping_helpers/airalarm/tlv_cold_room, +/obj/structure/sign/poster/official/cleanliness/directional/west, /turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) +/area/station/service/kitchen/coldroom) "nmj" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -43316,14 +43994,15 @@ /obj/effect/landmark/navigate_destination/library, /turf/open/floor/wood, /area/station/service/library) -"nmS" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 +"nmO" = ( +/obj/structure/marker_beacon/burgundy{ + name = "landing marker" }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "nnl" = ( /obj/machinery/atmospherics/pipe/layer_manifold/scrubbers/hidden, /obj/effect/spawner/structure/window/reinforced/plasma, @@ -43359,18 +44038,6 @@ /obj/machinery/holopad, /turf/open/floor/carpet, /area/station/command/heads_quarters/hop) -"nnW" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/red/half{ - dir = 4 - }, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/hallway/secondary/service) "noi" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/airalarm/directional/east, @@ -43561,6 +44228,10 @@ }, /turf/open/floor/iron/white, /area/station/science/explab) +"npZ" = ( +/obj/machinery/duct, +/turf/open/floor/plating, +/area/station/maintenance/fore) "nqb" = ( /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible, /turf/open/floor/plating/snowed/icemoon, @@ -43606,12 +44277,13 @@ dir = 4 }, /area/station/hallway/secondary/entry) -"nqL" = ( -/obj/machinery/food_cart, -/obj/effect/turf_decal/tile/brown/diagonal_edge, -/obj/structure/window/reinforced/spawner/directional/east, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +"nqI" = ( +/obj/effect/landmark/event_spawn, +/obj/machinery/requests_console/auto_name/directional/south, +/obj/machinery/holopad, +/obj/effect/turf_decal/bot_white, +/turf/open/floor/iron/grimy, +/area/station/service/theater) "nqP" = ( /obj/machinery/camera/directional/north{ c_tag = "Research Division West"; @@ -43638,39 +44310,23 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/mix) +"nrh" = ( +/obj/effect/turf_decal/weather/snow/corner{ + dir = 10 + }, +/turf/open/floor/plating/snowed/icemoon, +/area/icemoon/underground/explored) "nrm" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/tile/brown/anticorner/contrasted, /turf/open/floor/iron/dark, /area/station/cargo/miningdock) -"nro" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/chair/stool/bar/directional/east, -/obj/effect/landmark/start/hangover, -/turf/open/floor/stone, -/area/station/commons/lounge) "nrq" = ( /obj/effect/turf_decal/tile/red, /obj/structure/extinguisher_cabinet/directional/south, /turf/open/floor/iron/textured, /area/station/security/brig) -"nrt" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/sorting/mail/flip{ - dir = 4 - }, -/obj/effect/mapping_helpers/mail_sorting/service/theater, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "nrA" = ( /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ dir = 4 @@ -43720,16 +44376,6 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/supermatter/room) -"nsf" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/structure/railing/corner{ - dir = 1 - }, -/obj/structure/sign/poster/official/random/directional/north, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "nsp" = ( /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, @@ -43761,12 +44407,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"nsz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/light/small/directional/south, -/obj/structure/rack, -/turf/open/floor/iron/smooth, -/area/station/maintenance/department/chapel) "nsK" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, @@ -43909,6 +44549,20 @@ /obj/structure/flora/bush/snow/style_random, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"nvc" = ( +/obj/machinery/smartfridge, +/turf/open/floor/iron/dark, +/area/station/service/kitchen) +"nvh" = ( +/obj/machinery/vending/wardrobe/chef_wardrobe, +/obj/effect/turf_decal/siding/white/corner{ + dir = 8 + }, +/obj/machinery/light/directional/north, +/obj/structure/sign/poster/contraband/moffuchis_pizza/directional/east, +/obj/machinery/status_display/evac/directional/north, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "nvr" = ( /obj/effect/turf_decal/weather/snow/corner, /obj/machinery/light/small/directional/north, @@ -43920,10 +44574,12 @@ }, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) -"nvt" = ( -/obj/item/kirbyplants/organic/plant10, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) +"nvw" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "nvx" = ( /obj/machinery/airalarm/directional/east, /obj/effect/landmark/event_spawn, @@ -43987,17 +44643,23 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/security/checkpoint/customs/auxiliary) +"nwC" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 1 + }, +/obj/machinery/hydroponics/constructable, +/obj/machinery/status_display/evac/directional/north, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "nwF" = ( /obj/structure/chair/sofa/bench{ dir = 4 }, /turf/open/floor/iron, /area/station/security/prison/mess) -"nwI" = ( -/obj/item/reagent_containers/cup/bucket, -/obj/structure/sink/directional/east, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "nwT" = ( /turf/closed/wall, /area/station/commons/vacant_room/office) @@ -44009,15 +44671,37 @@ dir = 9 }, /area/station/science/research) +"nxc" = ( +/turf/open/floor/glass, +/area/station/service/hydroponics) "nxe" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/pink, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"nxj" = ( +/obj/structure/railing{ + dir = 8 + }, +/obj/effect/turf_decal/loading_area/white, +/turf/open/floor/wood/large, +/area/station/service/bar/atrium) "nxm" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/solars/port/aft) +"nxw" = ( +/obj/machinery/door/morgue{ + req_access = list("bar") + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/iron/grimy, +/area/station/service/bar/backroom) "nxD" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -44053,16 +44737,25 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) -"nxY" = ( -/obj/structure/chair/stool/directional/north, -/turf/open/floor/iron, -/area/station/commons/fitness) "nyg" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/random/directional/south, /turf/open/floor/plating, /area/station/construction) +"nyj" = ( +/obj/machinery/door/airlock/hydroponics/glass{ + name = "Hydroponics" + }, +/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, +/obj/machinery/duct, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wood, +/turf/open/floor/iron/dark/textured_half, +/area/station/service/hydroponics) "nyl" = ( /obj/machinery/door/morgue{ name = "Private Study"; @@ -44187,6 +44880,12 @@ /obj/effect/turf_decal/tile/blue/full, /turf/open/floor/iron/large, /area/station/medical/treatment_center) +"nzt" = ( +/obj/effect/turf_decal/tile/bar{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "nzy" = ( /obj/machinery/computer/atmos_control/mix_tank{ dir = 8 @@ -44283,17 +44982,6 @@ "nAH" = ( /turf/open/openspace/icemoon/keep_below, /area/station/hallway/secondary/entry) -"nAM" = ( -/obj/structure/railing/corner{ - dir = 8 - }, -/obj/effect/landmark/start/botanist, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/green{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "nAN" = ( /obj/effect/landmark/start/paramedic, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -44382,6 +45070,14 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/station/maintenance/starboard/aft) +"nBO" = ( +/obj/structure/disposalpipe/sorting/mail, +/obj/effect/mapping_helpers/mail_sorting/service/bar, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "nBQ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/components/tank/air{ @@ -44389,10 +45085,10 @@ }, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"nBV" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance/burnchamber) +"nBZ" = ( +/obj/structure/stairs/south, +/turf/open/floor/stone, +/area/station/commons/lounge) "nCa" = ( /obj/structure/rack, /obj/item/pickaxe, @@ -44447,6 +45143,14 @@ }, /turf/open/floor/iron, /area/station/commons/fitness) +"nCz" = ( +/obj/structure/extinguisher_cabinet/directional/south, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/machinery/light/directional/south, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "nCD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -44458,15 +45162,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) -"nCJ" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "nCP" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -44509,6 +45204,11 @@ /obj/effect/turf_decal/tile/dark/half/contrasted, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) +"nDm" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/structure/crate, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "nDp" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -44632,6 +45332,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/hallway/secondary/entry) +"nEI" = ( +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "nEV" = ( /obj/machinery/vending/wardrobe/sec_wardrobe, /obj/structure/cable, @@ -44666,15 +45370,6 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/grimy, /area/station/ai_monitored/turret_protected/aisat_interior) -"nFm" = ( -/obj/machinery/camera/directional/south{ - c_tag = "Starboard Primary Hallway Center West" - }, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "nFn" = ( /obj/effect/turf_decal/tile/red{ dir = 1 @@ -44716,6 +45411,14 @@ /obj/structure/cable, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"nFQ" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/chair/wood{ + dir = 1 + }, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "nFU" = ( /obj/structure/chair/stool/directional/west, /obj/item/trash/energybar, @@ -44723,22 +45426,12 @@ /obj/structure/sign/poster/official/work_for_a_future/directional/south, /turf/open/floor/iron, /area/station/security/prison/work) -"nGb" = ( -/obj/effect/spawner/random/engineering/tracking_beacon, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "nGk" = ( /obj/effect/decal/cleanable/cobweb/cobweb2, /obj/structure/rack, /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"nGz" = ( -/obj/effect/landmark/start/hangover, -/obj/structure/extinguisher_cabinet/directional/east, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "nGA" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -44786,16 +45479,6 @@ dir = 1 }, /area/station/security/lockers) -"nHa" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/turf_decal/tile/green/opposingcorners{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "nHc" = ( /obj/structure/bodycontainer/morgue, /turf/open/floor/iron/dark, @@ -44856,6 +45539,13 @@ /obj/structure/barricade/wooden, /turf/open/floor/eighties/red, /area/station/security/prison/safe) +"nIe" = ( +/obj/item/stack/cable_coil, +/obj/structure/fence/corner{ + dir = 1 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "nIl" = ( /obj/structure/chair/stool/directional/north, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -44863,10 +45553,6 @@ }, /turf/open/floor/iron/white, /area/station/science/robotics/lab) -"nIr" = ( -/obj/structure/sign/poster/official/random/directional/east, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "nIt" = ( /obj/structure/stairs/west, /turf/open/floor/iron/white, @@ -44874,13 +45560,10 @@ "nIx" = ( /turf/closed/wall/r_wall, /area/station/maintenance/solars/starboard/aft) -"nIL" = ( -/obj/machinery/camera{ - c_tag = "Service Hallway - Lower West"; - dir = 9 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +"nIY" = ( +/obj/effect/spawner/random/structure/girder, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "nJd" = ( /obj/structure/grille, /turf/open/floor/plating, @@ -44914,6 +45597,15 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/engine_equipment, /turf/open/floor/iron, /area/station/engineering/storage) +"nJq" = ( +/obj/structure/closet/athletic_mixed, +/obj/effect/landmark/start/hangover/closet, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/obj/machinery/status_display/evac/directional/north, +/turf/open/floor/iron, +/area/station/commons/fitness) "nJy" = ( /obj/structure/chair/pew{ dir = 1 @@ -44922,10 +45614,6 @@ dir = 8 }, /area/station/service/chapel) -"nJC" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "nJI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible, /obj/effect/turf_decal/siding/wideplating/corner{ @@ -44987,15 +45675,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron, /area/station/cargo/lobby) -"nKG" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Central Access" - }, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/blue, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "nKK" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 10 @@ -45053,23 +45732,41 @@ /obj/structure/mirror/broken/directional/north, /turf/open/floor/iron, /area/station/maintenance/port/fore) +"nLa" = ( +/obj/structure/flora/bush/lavendergrass/style_random, +/obj/structure/flora/bush/style_random, +/turf/open/floor/grass, +/area/station/service/hydroponics) "nLb" = ( /obj/machinery/blackbox_recorder, /turf/open/floor/iron/dark/telecomms, /area/station/tcommsat/server) +"nLd" = ( +/obj/effect/turf_decal/siding/thinplating/dark, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "nLe" = ( /obj/effect/turf_decal/tile/dark/half/contrasted, /obj/machinery/light/floor, /turf/open/floor/iron/white, /area/station/medical/virology) -"nLg" = ( -/obj/item/wrench, -/obj/effect/turf_decal/stripes/line{ - dir = 4 +"nLs" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 10 }, -/obj/machinery/atmospherics/pipe/layer_manifold/supply/visible, -/turf/open/floor/plating, -/area/station/maintenance/fore) +/obj/structure/sign/poster/official/random/directional/north, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "nLH" = ( /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron, @@ -45129,6 +45826,28 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/science/research) +"nMC" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/item/radio/intercom/directional/north, +/obj/structure/rack, +/obj/item/pickaxe, +/obj/item/toy/figure/chef, +/obj/machinery/camera/directional/north{ + c_tag = "Service - Coldroom" + }, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/service/kitchen/coldroom) +"nMD" = ( +/obj/structure/fence/door{ + dir = 4 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "nME" = ( /obj/item/clothing/head/utility/hardhat, /turf/open/floor/plating/snowed/icemoon, @@ -45192,13 +45911,6 @@ /obj/item/clothing/glasses/meson/engine, /turf/open/floor/iron/dark, /area/station/engineering/storage) -"nNv" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/starboard/fore) "nNy" = ( /obj/structure/sign/warning/xeno_mining{ pixel_x = 29 @@ -45214,10 +45926,18 @@ /obj/effect/turf_decal/trimline/green/filled/line{ dir = 9 }, -/obj/effect/landmark/start/virologist, /obj/structure/chair/stool/directional/east, /turf/open/floor/iron/dark, /area/station/medical/virology) +"nNI" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "nNM" = ( /obj/machinery/door/airlock/maintenance, /obj/effect/mapping_helpers/airlock/abandoned, @@ -45226,11 +45946,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"nNQ" = ( -/obj/machinery/duct, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "nNU" = ( /obj/machinery/chem_dispenser, /obj/structure/window/reinforced/spawner/directional/west, @@ -45287,6 +46002,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/command/bridge) +"nOI" = ( +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 4 + }, +/obj/effect/landmark/start/assistant, +/obj/structure/chair/office{ + dir = 8 + }, +/obj/machinery/status_display/ai/directional/east, +/turf/open/floor/iron, +/area/station/commons/fitness) "nOQ" = ( /obj/machinery/suit_storage_unit/security, /obj/machinery/camera/directional/north{ @@ -45311,6 +46037,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) +"nPS" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/power/apc/auto_name/directional/west, +/obj/structure/cable, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "nQd" = ( /obj/effect/turf_decal/trimline/green/filled/corner, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -45330,6 +46063,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/engineering/storage/tech) +"nQm" = ( +/obj/machinery/newscaster/directional/east, +/obj/machinery/duct, +/obj/machinery/light/directional/east, +/obj/machinery/camera/directional/east{ + c_tag = "Service - Hall" + }, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "nQu" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -45453,6 +46195,15 @@ /obj/structure/sign/poster/official/nanotrasen_logo/directional/east, /turf/open/floor/iron, /area/station/commons/dorms/laundry) +"nRy" = ( +/mob/living/basic/goat/pete{ + desc = "Not known for their pleasant disposition. This one seems a bit more hardy to the cold."; + habitable_atmos = list("min_oxy"=1,"max_oxy"=0,"min_plas"=0,"max_plas"=1,"min_co2"=0,"max_co2"=5,"min_n2"=0,"max_n2"=0); + minimum_survivable_temperature = 150; + name = "Snowy Pete" + }, +/turf/open/misc/ice/coldroom, +/area/station/service/kitchen/coldroom) "nRO" = ( /obj/structure/cable/multilayer/multiz, /obj/structure/sign/poster/contraband/random/directional/north, @@ -45546,6 +46297,14 @@ /obj/machinery/atmospherics/pipe/smart/simple/orange/visible, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"nSX" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/light/small/broken/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/fore) "nTp" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -45600,6 +46359,14 @@ "nTO" = ( /turf/closed/wall/r_wall, /area/mine/laborcamp/security) +"nTP" = ( +/obj/item/food/grown/potato{ + pixel_y = 4 + }, +/obj/structure/rack, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "nTV" = ( /obj/structure/table/reinforced, /obj/item/screwdriver{ @@ -45674,16 +46441,6 @@ }, /turf/open/floor/carpet, /area/station/service/library) -"nVz" = ( -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/east, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark/side{ - dir = 1 - }, -/area/station/service/hydroponics) "nVB" = ( /obj/effect/turf_decal/trimline/dark/warning{ dir = 4 @@ -45694,18 +46451,19 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/white, /area/station/science/robotics/lab) +"nVO" = ( +/obj/structure/table, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/turf/open/floor/iron/smooth, +/area/station/maintenance/starboard/fore) "nVR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/cafeteria{ dir = 5 }, /area/station/maintenance/port/aft) -"nVX" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "nVZ" = ( /obj/machinery/door/airlock/command{ name = "Captain's Office" @@ -45734,13 +46492,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/port/lesser) -"nWw" = ( -/obj/structure/chair/wood{ - dir = 4 - }, -/obj/machinery/newscaster/directional/north, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "nWH" = ( /turf/closed/wall, /area/station/maintenance/department/cargo) @@ -45771,17 +46522,20 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/supermatter/room) -"nXn" = ( -/obj/structure/table, -/obj/item/storage/medkit/regular, -/turf/open/floor/iron, -/area/station/commons/fitness) "nXp" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/table/glass, /obj/item/storage/box/monkeycubes, /turf/open/floor/iron, /area/station/science/xenobiology) +"nXs" = ( +/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/obj/structure/cable, +/obj/machinery/door/airlock/maintenance{ + name = "Kitchen Maintenance" + }, +/turf/open/floor/plating, +/area/station/service/kitchen) "nXH" = ( /obj/structure/bodycontainer/crematorium{ id = "crematoriumChapel" @@ -45819,13 +46573,25 @@ }, /turf/open/floor/iron, /area/station/command/bridge) -"nYQ" = ( -/obj/machinery/rnd/production/techfab/department/service, -/obj/effect/turf_decal/stripes/line{ - dir = 1 +"nYN" = ( +/turf/open/floor/wood, +/area/station/commons/lounge) +"nYR" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 9 }, -/turf/open/floor/plating, -/area/station/hallway/secondary/service) +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 9 + }, +/obj/structure/reagent_dispensers/watertank/high, +/obj/item/reagent_containers/cup/watering_can, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"nYY" = ( +/obj/machinery/light/directional/south, +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "nYZ" = ( /obj/item/storage/bag/trash, /turf/open/floor/plating, @@ -45898,14 +46664,38 @@ }, /turf/open/floor/iron/freezer, /area/station/commons/toilet/locker) -"oaa" = ( +"oac" = ( +/obj/effect/turf_decal/siding/thinplating/dark/corner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 5 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/button/door/directional/north{ + id = "botany_apiary"; + name = "Bee Protection Shutters" + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"oas" = ( +/obj/machinery/door/firedoor, /obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 10 +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 }, -/obj/structure/sign/poster/official/random/directional/north, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "oaG" = ( /obj/effect/turf_decal/stripes/asteroid/line{ dir = 9 @@ -45924,6 +46714,18 @@ }, /turf/open/floor/iron/white/corner, /area/mine/living_quarters) +"oaJ" = ( +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/obj/machinery/requests_console/auto_name/directional/east, +/obj/structure/table, +/obj/machinery/microwave{ + pixel_y = 5 + }, +/obj/effect/mapping_helpers/requests_console/supplies, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "oaP" = ( /obj/machinery/door/airlock/research{ name = "Crater Observation Room" @@ -46000,6 +46802,15 @@ dir = 1 }, /area/station/engineering/atmos/storage/gas) +"obT" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "obZ" = ( /obj/machinery/camera/directional/east{ c_tag = "Xenobiology Test Chamber Access"; @@ -46007,25 +46818,16 @@ }, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"ocf" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +"ocd" = ( +/obj/machinery/igniter/incinerator_ordmix, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) +"ocp" = ( +/obj/effect/landmark/start/hangover, +/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) -"ocj" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Central Access" - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) +/turf/open/floor/iron/dark, +/area/station/medical/morgue) "ocu" = ( /obj/effect/turf_decal/bot_white, /obj/structure/cable, @@ -46110,6 +46912,11 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) +"odZ" = ( +/obj/machinery/door/airlock/hatch, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "oed" = ( /obj/machinery/door/window/right/directional/east{ name = "Robotics Surgery"; @@ -46216,15 +47023,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"ofT" = ( -/obj/structure/closet/secure_closet/hydroponics, -/obj/effect/turf_decal/siding/thinplating/dark, -/obj/machinery/camera{ - c_tag = "Service Botany - Backroom"; - dir = 9 - }, -/turf/open/floor/plating, -/area/station/service/hydroponics) "ogd" = ( /obj/structure/chair/office{ dir = 8 @@ -46238,6 +47036,9 @@ /obj/effect/landmark/start/scientist, /turf/open/floor/iron, /area/station/science/xenobiology) +"ogu" = ( +/turf/open/floor/iron/dark/smooth_half, +/area/station/service/hydroponics) "ogy" = ( /obj/machinery/door/airlock/maintenance{ name = "EVA Maintenance" @@ -46273,6 +47074,11 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/cargo) +"ohk" = ( +/obj/machinery/light/small/directional/west, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "ohp" = ( /turf/open/floor/glass, /area/station/maintenance/department/medical/central) @@ -46292,6 +47098,15 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"ohP" = ( +/obj/structure/table/wood, +/obj/machinery/duct, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/box/white/corners{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/service/bar) "ohS" = ( /obj/structure/railing{ dir = 8 @@ -46466,13 +47281,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) -"ojD" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/hydroponics) "ojF" = ( /obj/machinery/rnd/production/protolathe/department/science, /turf/open/floor/iron/checker, @@ -46484,13 +47292,6 @@ dir = 4 }, /area/station/science/research) -"ojV" = ( -/obj/item/flashlight, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/maintenance/starboard/fore) "ojW" = ( /obj/machinery/light/small/directional/east, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, @@ -46528,11 +47329,6 @@ /obj/structure/sign/poster/official/random/directional/north, /turf/open/floor/iron, /area/mine/laborcamp/security) -"oko" = ( -/obj/effect/turf_decal/siding/wood/end, -/obj/structure/bookcase/random/fiction, -/turf/open/floor/iron/dark, -/area/station/commons/lounge) "okx" = ( /obj/structure/table/reinforced, /obj/machinery/door/window/brigdoor/left/directional/south{ @@ -46577,6 +47373,13 @@ "olf" = ( /turf/open/floor/carpet, /area/station/commons/dorms) +"olt" = ( +/obj/structure/chair/sofa/bench/right{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/hallway/primary/fore) "olH" = ( /obj/machinery/door/airlock/command{ name = "Captain's Quarters" @@ -46651,13 +47454,6 @@ "omk" = ( /turf/open/floor/glass/reinforced, /area/station/security/office) -"omt" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "omG" = ( /obj/structure/table, /obj/item/flashlight/lamp, @@ -46687,6 +47483,15 @@ }, /turf/open/floor/plating, /area/station/security/prison/safe) +"omS" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Kitchen Maintenance" + }, +/obj/machinery/duct, +/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/obj/structure/disposalpipe/segment, +/turf/open/floor/plating, +/area/station/service/kitchen/coldroom) "ond" = ( /obj/effect/landmark/event_spawn, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -46762,16 +47567,6 @@ /obj/machinery/processor/slime, /turf/open/floor/iron, /area/station/science/xenobiology) -"oop" = ( -/obj/machinery/door/airlock/external{ - name = "External Access" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 - }, -/obj/effect/mapping_helpers/airlock/access/all/engineering/external, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "oor" = ( /obj/machinery/door/firedoor, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -46846,21 +47641,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/maintenance/starboard/upper) -"ops" = ( -/obj/structure/table/glass, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/siding/white{ - dir = 5 - }, -/obj/item/cultivator, -/obj/item/plant_analyzer, -/obj/effect/turf_decal/tile/green/opposingcorners{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners, -/turf/open/floor/iron, -/area/station/service/hydroponics) "opu" = ( /obj/structure/extinguisher_cabinet/directional/south, /obj/structure/disposalpipe/segment{ @@ -46894,6 +47674,20 @@ /obj/machinery/door/firedoor/border_only, /turf/open/floor/iron/white, /area/station/science/ordnance) +"opH" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/starboard) "opI" = ( /obj/machinery/microwave{ pixel_y = 7 @@ -46967,6 +47761,13 @@ /obj/effect/turf_decal/tile/dark_green, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai_upload) +"oqB" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/box/red/corners{ + dir = 1 + }, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "oqC" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -47004,15 +47805,6 @@ /obj/effect/turf_decal/tile/brown/anticorner/contrasted, /turf/open/floor/iron/white, /area/station/medical/break_room) -"orf" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "ork" = ( /obj/structure/fence/door{ dir = 4 @@ -47045,6 +47837,12 @@ /obj/machinery/recharge_station, /turf/open/floor/iron/freezer, /area/station/commons/toilet/locker) +"oru" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "orv" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -47093,6 +47891,16 @@ /obj/effect/landmark/start/hangover/closet, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) +"orZ" = ( +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk, +/obj/item/radio/intercom/directional/east, +/obj/machinery/camera/directional/north{ + c_tag = "Service - Atrium" + }, +/obj/effect/turf_decal/bot_white, +/turf/open/floor/wood/large, +/area/station/service/bar/atrium) "osd" = ( /obj/structure/chair/comfy/black{ dir = 8 @@ -47137,6 +47945,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/maintenance/port/aft) +"osN" = ( +/obj/effect/spawner/structure/window/reinforced/tinted, +/turf/open/floor/plating, +/area/station/maintenance/fore) "osO" = ( /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -47153,16 +47965,6 @@ }, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat_interior) -"otj" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/spawner/random/structure/steam_vent, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "ots" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/hollow/reinforced/middle, @@ -47205,10 +48007,6 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron/white, /area/station/science/robotics/lab) -"otQ" = ( -/obj/structure/sign/poster/official/random/directional/east, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "oua" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -47306,6 +48104,11 @@ /obj/structure/cable, /turf/open/floor/iron/smooth, /area/station/security/lockers) +"ovZ" = ( +/obj/structure/table/wood, +/obj/item/paper/crumpled, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "owf" = ( /obj/effect/turf_decal/stripes/white/line, /obj/effect/decal/cleanable/dirt, @@ -47342,10 +48145,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"owU" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) "oxe" = ( /obj/machinery/computer/cargo/request, /obj/effect/turf_decal/tile/brown/half/contrasted, @@ -47491,16 +48290,6 @@ }, /turf/open/floor/iron/dark, /area/station/security/mechbay) -"oyV" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/start/cook, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "oyW" = ( /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/aisat/hallway) @@ -47527,6 +48316,23 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) +"ozx" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/structure/minecart_rail{ + dir = 4 + }, +/obj/item/radio/intercom/directional/south{ + frequency = 1453; + name = "Kitchen Intercom" + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "ozA" = ( /obj/structure/closet/secure_closet/research_director, /obj/effect/turf_decal/stripes/line{ @@ -47578,6 +48384,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/chapel) +"ozW" = ( +/obj/structure/railing/wooden_fence{ + dir = 10 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "ozX" = ( /obj/machinery/hydroponics/soil, /turf/open/floor/grass, @@ -47675,17 +48487,6 @@ /obj/item/book/bible, /turf/open/floor/iron/dark, /area/station/service/chapel/office) -"oBl" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark/side{ - dir = 1 - }, -/area/station/service/hydroponics) "oBm" = ( /obj/structure/chair/comfy/beige{ dir = 1; @@ -47720,11 +48521,16 @@ /obj/machinery/light/floor, /turf/open/floor/carpet, /area/station/service/library) -"oBP" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/commons/fitness) +"oBJ" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/effect/mapping_helpers/burnt_floor, +/obj/structure/railing{ + dir = 6 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "oBQ" = ( /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, @@ -47732,10 +48538,6 @@ /area/station/maintenance/solars/starboard/fore) "oCs" = ( /obj/structure/table, -/obj/item/toy/figure/virologist{ - pixel_x = -8; - pixel_y = 7 - }, /obj/item/radio/headset/headset_med{ pixel_x = -3; pixel_y = -2 @@ -47762,6 +48564,10 @@ /obj/item/stack/cable_coil/five, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"oCw" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/fore) "oCA" = ( /obj/structure/closet/secure_closet/cytology, /obj/machinery/button/door/directional/north{ @@ -47836,11 +48642,6 @@ /obj/structure/grille/broken, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) -"oDm" = ( -/obj/effect/turf_decal/siding/white, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "oDn" = ( /obj/machinery/door/airlock/atmos/glass, /obj/structure/cable, @@ -47877,13 +48678,6 @@ dir = 8 }, /area/station/maintenance/port/fore) -"oDJ" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "oDQ" = ( /obj/effect/turf_decal/stripes/corner{ dir = 8 @@ -47901,13 +48695,12 @@ }, /turf/open/floor/iron/cafeteria, /area/station/commons/dorms/laundry) -"oEh" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +"oEe" = ( +/obj/machinery/duct, +/obj/effect/decal/cleanable/dirt, +/obj/structure/disposalpipe/segment, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "oEj" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -47932,6 +48725,10 @@ /obj/machinery/airalarm/directional/south, /turf/open/floor/iron, /area/station/engineering/main) +"oEC" = ( +/obj/machinery/light/small/directional/north, +/turf/open/floor/catwalk_floor/iron_dark, +/area/station/maintenance/starboard/fore) "oEF" = ( /obj/structure/cable/multilayer/multiz, /obj/effect/turf_decal/stripes/end, @@ -47965,6 +48762,17 @@ /obj/machinery/holopad/secure, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) +"oFB" = ( +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/starboard) "oFI" = ( /obj/effect/turf_decal/weather/snow/corner{ dir = 6 @@ -48019,21 +48827,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/solars/starboard/aft) -"oGn" = ( -/obj/structure/reagent_dispensers/watertank/high, -/obj/effect/turf_decal/stripes/line, -/obj/item/reagent_containers/cup/watering_can, -/obj/effect/turf_decal/tile/blue/half{ - dir = 4 - }, -/obj/effect/turf_decal/tile/green/half{ - dir = 8 - }, -/obj/machinery/light/directional/north, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/service/hydroponics) "oGs" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/trimline/blue/filled/corner{ @@ -48186,6 +48979,17 @@ }, /turf/open/floor/engine, /area/station/engineering/atmos/hfr_room) +"oIQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/machinery/duct, +/obj/machinery/newscaster/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "oIR" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/maintenance/four, @@ -48201,6 +49005,9 @@ /obj/structure/flora/bush/snow/style_random, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"oJD" = ( +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "oJH" = ( /obj/structure/marker_beacon/burgundy, /obj/effect/turf_decal/weather/snow/corner{ @@ -48223,15 +49030,6 @@ dir = 1 }, /area/station/command/gateway) -"oKb" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 1; - id = "pharmacy_shutters3"; - name = "Pharmacy Shutters" - }, -/turf/open/floor/plating, -/area/station/service/kitchen) "oKu" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -48368,12 +49166,6 @@ /obj/structure/sign/warning/gas_mask, /turf/open/floor/plating, /area/station/maintenance/solars/port/fore) -"oLV" = ( -/obj/machinery/vending/wardrobe/chef_wardrobe{ - pixel_x = -2 - }, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "oLW" = ( /obj/machinery/computer/security/telescreen{ desc = "Used to access the various cameras on the station."; @@ -48423,17 +49215,6 @@ /obj/effect/spawner/random/trash/mess, /turf/open/floor/iron/grimy, /area/station/maintenance/aft/greater) -"oMG" = ( -/obj/effect/turf_decal/trimline/green/filled/line, -/obj/effect/turf_decal/trimline/blue/filled/warning, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/machinery/camera/directional/south{ - c_tag = "Service Botany - Lower South" - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "oMO" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -48466,6 +49247,14 @@ "oMT" = ( /turf/open/floor/iron, /area/station/command/heads_quarters/rd) +"oNy" = ( +/obj/effect/spawner/random/structure/crate_abandoned, +/obj/machinery/light/small/directional/south, +/obj/machinery/camera/directional/south{ + c_tag = "Chapel Electrical Maintenace Upper" + }, +/turf/open/floor/iron/smooth, +/area/station/maintenance/starboard/fore) "oNA" = ( /obj/effect/turf_decal/bot, /turf/open/floor/plating/snowed/smoothed/icemoon, @@ -48485,6 +49274,19 @@ /obj/structure/sign/poster/official/random/directional/south, /turf/open/floor/iron, /area/station/science/explab) +"oNN" = ( +/obj/effect/turf_decal/siding/wood, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/multi_tile/public/glass{ + name = "Atrium" + }, +/obj/structure/disposalpipe/segment, +/obj/effect/landmark/navigate_destination/kitchen, +/turf/open/floor/iron/dark/textured_half, +/area/station/service/bar/atrium) "oNO" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/meter, @@ -48514,6 +49316,15 @@ /obj/machinery/status_display/evac/directional/west, /turf/open/floor/iron/white, /area/station/science/research) +"oOt" = ( +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/fore) "oOx" = ( /obj/machinery/door/airlock/public/glass/incinerator/atmos_interior, /obj/effect/mapping_helpers/airlock/cyclelink_helper, @@ -48556,6 +49367,18 @@ /obj/structure/sign/warning/secure_area, /turf/closed/wall/r_wall, /area/station/security/prison/work) +"oPd" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/bar) "oPl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -48580,6 +49403,13 @@ dir = 9 }, /area/station/science/lab) +"oPr" = ( +/obj/effect/landmark/start/bartender, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/iron/grimy, +/area/station/service/bar/backroom) "oPv" = ( /obj/machinery/turretid{ control_area = "/area/station/ai_monitored/turret_protected/aisat/service"; @@ -48592,6 +49422,13 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) +"oPw" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "oPI" = ( /turf/open/floor/circuit, /area/station/ai_monitored/command/nuke_storage) @@ -48668,6 +49505,10 @@ "oQY" = ( /turf/open/floor/iron/white, /area/station/medical/virology) +"oRf" = ( +/obj/structure/flora/rock/pile/icy/style_random, +/turf/open/misc/asteroid/snow/coldroom, +/area/station/service/kitchen/coldroom) "oRk" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -48685,17 +49526,6 @@ /obj/machinery/light/cold/directional/east, /turf/open/floor/iron/white, /area/station/medical/cryo) -"oRw" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/sign/poster/official/random/directional/south, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "oRy" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -48731,14 +49561,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/mine/laborcamp) -"oSk" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Fitness" - }, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/commons/fitness) "oSm" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -48765,10 +49587,6 @@ /obj/structure/stairs/south, /turf/open/floor/iron/dark/textured, /area/station/security/prison) -"oSI" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "oSQ" = ( /obj/machinery/camera{ c_tag = "Medbay Stasis Center North"; @@ -48872,17 +49690,6 @@ "oTA" = ( /turf/open/floor/iron/dark, /area/station/service/chapel) -"oTB" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/multiz/supply/visible/layer4{ - color = "#0000ff"; - dir = 8; - name = "Supply multi deck pipe adapter" - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "oTM" = ( /obj/item/flashlight/lantern, /obj/structure/table/wood, @@ -48903,22 +49710,6 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) -"oUG" = ( -/obj/machinery/door/airlock{ - id_tag = "Toilet2"; - name = "Unit 2" - }, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) -"oUK" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 4 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "oUL" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -48947,6 +49738,21 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/freezer, /area/station/commons/toilet) +"oVn" = ( +/obj/effect/turf_decal/box/red/corners{ + dir = 4 + }, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) +"oVr" = ( +/obj/structure/table/wood/poker, +/obj/effect/spawner/random/entertainment/coin{ + pixel_x = -7; + pixel_y = 0 + }, +/obj/effect/spawner/random/clothing/bowler_or_that, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "oVt" = ( /obj/machinery/power/apc/auto_name/directional/south, /obj/structure/cable, @@ -49040,6 +49846,10 @@ /obj/item/stack/sheet/iron/fifty, /turf/open/floor/iron/dark, /area/station/engineering/supermatter/room) +"oWV" = ( +/obj/structure/sign/warning/cold_temp/directional/south, +/turf/open/floor/plating, +/area/station/maintenance/fore) "oXc" = ( /obj/machinery/door/firedoor, /obj/effect/turf_decal/tile/yellow/half/contrasted{ @@ -49058,16 +49868,6 @@ }, /turf/open/floor/iron/dark/textured, /area/station/security/range) -"oXe" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 9 - }, -/obj/item/holosign_creator/robot_seat/bar, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/duct, -/obj/structure/table/wood, -/turf/open/floor/stone, -/area/station/service/bar) "oXf" = ( /obj/structure/closet/secure_closet/medical1, /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -49087,9 +49887,6 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai_upload) -"oXk" = ( -/turf/open/floor/carpet, -/area/station/service/theater) "oXm" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/mapping_helpers/burnt_floor, @@ -49144,10 +49941,6 @@ dir = 1 }, /area/station/hallway/primary/starboard) -"oXS" = ( -/obj/structure/chair/stool/directional/north, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "oXT" = ( /obj/structure/table/glass, /obj/item/storage/box/beakers{ @@ -49179,15 +49972,6 @@ /obj/machinery/status_display/evac/directional/south, /turf/open/floor/iron, /area/station/commons/locker) -"oYc" = ( -/obj/structure/chair/wood/wings{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/wood/tile, -/area/station/service/theater) "oYi" = ( /obj/machinery/firealarm/directional/south, /obj/structure/table, @@ -49209,11 +49993,24 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai_upload) -"oYH" = ( -/obj/effect/turf_decal/siding/wideplating/dark, -/obj/effect/landmark/start/botanist, +"oYw" = ( +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/stripes/line, /turf/open/floor/iron, /area/station/service/hydroponics) +"oYC" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "oYI" = ( /obj/effect/spawner/random/vending/colavend, /turf/open/floor/wood, @@ -49224,6 +50021,16 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"oZk" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "botany_chasm_and_wolf_shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) "oZn" = ( /obj/structure/cable, /obj/effect/turf_decal/stripes/line{ @@ -49242,6 +50049,13 @@ dir = 4 }, /area/station/security/prison) +"oZD" = ( +/obj/machinery/door/window/left/directional/west{ + req_access = list("hydroponics"); + name = "Hydroponics Equipment" + }, +/turf/open/floor/iron/half, +/area/station/service/hydroponics) "oZL" = ( /obj/machinery/atmospherics/components/binary/pump{ dir = 4; @@ -49305,6 +50119,9 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/commons/locker) +"pba" = ( +/turf/open/floor/stone, +/area/station/service/bar/atrium) "pbk" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -49334,19 +50151,20 @@ }, /turf/open/floor/iron, /area/station/security/prison/garden) -"pbD" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/obj/machinery/duct, -/obj/machinery/light/small/directional/west, -/turf/open/floor/plating, -/area/station/hallway/secondary/service) "pbE" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/station/construction) +"pbF" = ( +/obj/effect/turf_decal/siding/wideplating/dark{ + dir = 1 + }, +/obj/item/seeds/berry, +/obj/machinery/light/small/dim/directional/south, +/obj/machinery/hydroponics/soil, +/turf/open/floor/grass, +/area/station/maintenance/starboard/fore) "pbH" = ( /obj/item/radio/intercom/directional/north, /turf/open/floor/iron, @@ -49407,6 +50225,13 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/general, /turf/open/floor/iron, /area/station/cargo/drone_bay) +"pco" = ( +/obj/effect/decal/cleanable/blood/tracks, +/obj/structure/fence/cut/large{ + dir = 8 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "pcr" = ( /obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/nitrous_output{ dir = 8 @@ -49474,6 +50299,15 @@ /obj/machinery/firealarm/directional/east, /turf/open/floor/iron/dark/textured, /area/station/security/execution/transfer) +"pdC" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/effect/turf_decal/tile/bar{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "pdK" = ( /obj/effect/turf_decal/tile/red/anticorner/contrasted, /turf/open/floor/iron/dark/textured, @@ -49594,13 +50428,16 @@ /obj/structure/flora/grass/green/style_random, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"pfB" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/door/firedoor, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) +"pfy" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/atmospherics/components/binary/pump/off/supply/visible/layer4{ + dir = 8; + name = "Air Out" + }, +/turf/open/floor/plating, +/area/station/maintenance/fore) "pfD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/light/small/directional/east, @@ -49644,6 +50481,11 @@ /obj/effect/turf_decal/box, /turf/open/floor/iron/dark/smooth_large, /area/station/cargo/bitrunning/den) +"pgv" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/bar) "pgw" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/requests_console/directional/south{ @@ -49705,6 +50547,28 @@ }, /turf/open/floor/iron/white, /area/station/medical/break_room) +"phl" = ( +/obj/structure/minecart_rail{ + dir = 4 + }, +/obj/structure/cable, +/obj/effect/turf_decal/weather/snow/corner, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 1 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) +"phr" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, +/obj/machinery/door/airlock/hydroponics/glass{ + name = "Apiary" + }, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/service/hydroponics) "phu" = ( /obj/structure/chair/sofa/bench/left{ dir = 1 @@ -49743,14 +50607,6 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) -"phU" = ( -/obj/effect/turf_decal/siding/thinplating/dark, -/obj/machinery/door/window/right/directional/south{ - name = "Theater Stage" - }, -/obj/structure/disposalpipe/segment, -/turf/open/floor/carpet, -/area/station/service/theater) "pib" = ( /obj/machinery/camera/motion/directional/south{ c_tag = "Vault"; @@ -49790,12 +50646,6 @@ /obj/effect/spawner/random/engineering/tracking_beacon, /turf/open/floor/iron, /area/station/security/brig/upper) -"pix" = ( -/obj/effect/turf_decal/trimline/green/filled/line, -/obj/effect/turf_decal/trimline/blue/filled/warning, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/hydroponics) "piB" = ( /obj/structure/sign/warning/electric_shock/directional/north, /obj/effect/turf_decal/stripes/corner{ @@ -49898,17 +50748,6 @@ /obj/effect/mapping_helpers/airlock/access/all/science/ordnance, /turf/open/floor/iron/dark, /area/station/science/ordnance/freezerchamber) -"pjg" = ( -/obj/item/instrument/saxophone, -/obj/machinery/computer/security/telescreen/entertainment/directional/north, -/obj/item/instrument/piano_synth, -/obj/structure/table/wood, -/obj/machinery/camera{ - c_tag = "Service Theater"; - dir = 9 - }, -/turf/open/floor/wood/tile, -/area/station/service/theater) "pji" = ( /obj/structure/cable, /obj/machinery/camera/directional/east{ @@ -49922,6 +50761,16 @@ /obj/structure/chair, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) +"pjk" = ( +/obj/structure/disposalpipe/sorting/mail/flip{ + dir = 1 + }, +/obj/effect/mapping_helpers/mail_sorting/service/hydroponics, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "pjl" = ( /obj/structure/rack, /obj/effect/spawner/random/techstorage/engineering_all, @@ -49970,6 +50819,13 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) +"pjM" = ( +/obj/structure/closet, +/obj/effect/spawner/random/clothing/costume, +/obj/structure/sign/poster/contraband/random/directional/east, +/obj/effect/spawner/random/clothing/gloves, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "pjZ" = ( /obj/structure/closet/crate/freezer/blood, /turf/open/floor/iron/white, @@ -50016,6 +50872,11 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/station/maintenance/port/greater) +"ply" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/caution_sign, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "plN" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/effect/turf_decal/tile/neutral/opposingcorners, @@ -50046,13 +50907,6 @@ /obj/machinery/door/firedoor/heavy, /turf/open/floor/iron/dark, /area/station/science/ordnance) -"pmg" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "pmn" = ( /obj/effect/spawner/random/trash/caution_sign, /turf/open/floor/plating, @@ -50098,6 +50952,16 @@ /obj/structure/flora/grass/brown/style_random, /turf/open/misc/asteroid/snow/standard_air, /area/station/science/research) +"pns" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/item/flashlight{ + pixel_y = 3; + pixel_x = -4 + }, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "pnz" = ( /obj/item/radio/intercom/directional/west, /turf/open/floor/iron, @@ -50192,6 +51056,13 @@ /obj/machinery/airalarm/directional/east, /turf/open/floor/iron, /area/station/commons/locker) +"poV" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/bar) "poY" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -50316,28 +51187,20 @@ /obj/effect/turf_decal/tile/purple/fourcorners, /turf/open/floor/iron, /area/mine/living_quarters) -"pqx" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 4 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 4 - }, -/obj/effect/spawner/random/engineering/tracking_beacon, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "pqK" = ( /obj/structure/sign/warning/secure_area/directional/east, /turf/open/floor/plating, /area/station/maintenance/aft/greater) +"pqZ" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/item/storage/box/matches, +/obj/effect/spawner/random/entertainment/cigar, +/turf/open/floor/iron, +/area/station/service/bar) "pra" = ( /turf/open/floor/iron/dark, /area/station/science/robotics/lab) -"prf" = ( -/obj/structure/closet/crate, -/obj/effect/spawner/random/maintenance/two, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "prg" = ( /turf/open/floor/wood, /area/station/service/library) @@ -50461,17 +51324,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/hallway/primary/port) -"ptp" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/structure/chair{ - dir = 4 - }, -/obj/machinery/newscaster/directional/north, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) +"ptv" = ( +/obj/effect/turf_decal/siding/wood, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "ptx" = ( /obj/structure/closet/crate, /obj/item/stack/sheet/iron/fifty, @@ -50511,13 +51367,6 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/central) -"pub" = ( -/obj/effect/spawner/random/maintenance, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "puc" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, @@ -50728,21 +51577,11 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"pwx" = ( -/obj/machinery/portable_atmospherics/canister/nitrous_oxide, -/obj/effect/mapping_helpers/broken_floor, +"pwz" = ( +/obj/machinery/duct, +/obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/plating, -/area/station/maintenance/fore) -"pwB" = ( -/obj/structure/stairs/west, -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/structure/railing{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +/area/station/maintenance/starboard/fore) "pwC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -50804,32 +51643,10 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"pxs" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/obj/structure/chair, -/obj/machinery/airalarm/directional/west, -/obj/machinery/camera/directional/west{ - c_tag = "Service Diner South" - }, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "pxu" = ( /obj/structure/sign/warning/secure_area/directional/east, /turf/open/floor/engine, /area/station/science/explab) -"pxF" = ( -/obj/structure/table/reinforced, -/obj/machinery/door/firedoor, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 8; - id = "kitchencounter"; - name = "Kitchen Counter Shutters" - }, -/obj/structure/displaycase/forsale/kitchen, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "pxL" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -50871,13 +51688,6 @@ /obj/item/radio/intercom/directional/south, /turf/open/floor/iron, /area/station/security/checkpoint/supply) -"pyj" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/obj/structure/disposalpipe/segment, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "pyr" = ( /obj/machinery/griddle, /turf/open/floor/iron/cafeteria, @@ -50936,12 +51746,6 @@ /obj/effect/landmark/start/station_engineer, /turf/open/floor/iron, /area/station/engineering/storage_shared) -"pyW" = ( -/obj/structure/chair/sofa/bench{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) "pyY" = ( /obj/machinery/status_display/evac/directional/south, /turf/open/openspace, @@ -51045,16 +51849,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/science/ordnance) -"pAp" = ( -/obj/machinery/deepfryer, -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/firealarm/directional/east, -/turf/open/floor/iron/kitchen/diagonal, +"pAn" = ( +/obj/effect/turf_decal/siding/white/corner{ + dir = 1 + }, +/obj/machinery/light/directional/south, +/obj/machinery/status_display/ai/directional/south, +/obj/structure/extinguisher_cabinet/directional/east, +/obj/machinery/chem_master/condimaster, +/turf/open/floor/iron/white/smooth_large, /area/station/service/kitchen) -"pAM" = ( -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "pAN" = ( /obj/structure/ladder, /obj/effect/decal/cleanable/dirt, @@ -51069,6 +51873,16 @@ dir = 4 }, /area/mine/production) +"pAW" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/railing/corner/end{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "pAZ" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -51082,21 +51896,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/hallway/primary/port) -"pBr" = ( -/obj/structure/window/reinforced/spawner/directional/east, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 1 - }, -/obj/machinery/chem_master/condimaster{ - desc = "Used to separate out liquids - useful for purifying botanical extracts. Also dispenses condiments."; - name = "SapMaster XP" - }, -/obj/machinery/requests_console/auto_name/directional/north, -/turf/open/floor/iron, -/area/station/service/hydroponics) "pBA" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -51126,6 +51925,14 @@ /obj/structure/flora/tree/jungle/small/style_random, /turf/open/floor/grass, /area/station/security/warden) +"pBS" = ( +/obj/structure/window/reinforced/spawner/directional/east, +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/item/kirbyplants/organic/applebush, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "pBV" = ( /obj/structure/chair/office/light, /turf/open/floor/iron/dark, @@ -51381,6 +52188,12 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) +"pGg" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "pGo" = ( /obj/structure/cable, /obj/effect/turf_decal/stripes/line{ @@ -51566,6 +52379,12 @@ dir = 4 }, /area/station/science/explab) +"pJq" = ( +/obj/structure/statue/snow/snowman{ + name = "Steve" + }, +/turf/open/misc/asteroid/snow/coldroom, +/area/icemoon/underground/explored) "pJu" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -51634,11 +52453,16 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) -"pKe" = ( -/obj/machinery/light/cold/directional/west, -/obj/item/radio/intercom/directional/west, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) +"pKo" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/item/radio/intercom/directional/south, +/turf/open/floor/wood/parquet, +/area/station/service/bar/backroom) "pKu" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -51706,6 +52530,17 @@ dir = 8 }, /area/station/hallway/secondary/entry) +"pLo" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "kitchencounter"; + name = "Kitchen Counter Shutters" + }, +/obj/machinery/door/firedoor, +/obj/structure/window/reinforced/spawner/directional/south, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "pLr" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -51723,6 +52558,18 @@ /obj/item/radio/intercom/directional/north, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"pLu" = ( +/obj/structure/sink/kitchen/directional/south, +/obj/effect/turf_decal/siding/thinplating/dark/corner, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "pLv" = ( /obj/structure/chair/stool/directional/south, /turf/open/floor/iron, @@ -51764,6 +52611,11 @@ /obj/effect/mapping_helpers/airlock/access/all/security/brig, /turf/open/floor/iron/dark/smooth_large, /area/station/security/processing) +"pMh" = ( +/obj/structure/table/wood/poker, +/obj/item/storage/wallet/random, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "pMq" = ( /obj/machinery/camera/directional/south{ c_tag = "Atmospherics Storage Room - South" @@ -51808,19 +52660,15 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/science/xenobiology) +"pNi" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "pNm" = ( /turf/closed/wall/r_wall, /area/station/security/execution/education) -"pNp" = ( -/obj/item/stack/package_wrap{ - pixel_x = -4; - pixel_y = 6 - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "pNq" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, @@ -51831,12 +52679,6 @@ }, /turf/open/floor/carpet, /area/station/command/meeting_room) -"pNx" = ( -/obj/effect/turf_decal/tile/blue, -/obj/machinery/light/directional/south, -/obj/structure/extinguisher_cabinet/directional/south, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "pNy" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 4 @@ -51916,6 +52758,12 @@ /obj/structure/cable, /turf/closed/wall/r_wall, /area/station/security/prison/safe) +"pOl" = ( +/obj/structure/flora/tree/pine/style_random{ + pixel_x = -15 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "pOo" = ( /obj/machinery/airalarm/directional/north, /obj/structure/closet/secure_closet/personal/cabinet, @@ -51932,17 +52780,26 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/atmos/storage) -"pOJ" = ( -/obj/structure/displaycase/forsale/kitchen{ - pixel_y = 8 +"pOC" = ( +/obj/machinery/computer/order_console/cook{ + dir = 4 }, -/obj/effect/turf_decal/siding/wood/corner{ +/obj/item/radio/intercom/directional/north, +/obj/effect/turf_decal/tile/bar{ dir = 1 }, -/obj/structure/table/wood, -/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/newscaster/directional/west, /turf/open/floor/iron, -/area/station/service/bar) +/area/station/service/kitchen/coldroom) +"pOK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark/smooth_half, +/area/station/service/hydroponics) "pOL" = ( /turf/open/floor/iron/white, /area/station/science/ordnance) @@ -52192,16 +53049,48 @@ "pSz" = ( /turf/open/openspace, /area/station/maintenance/starboard/upper) -"pSQ" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ +"pSP" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, +/obj/machinery/door/airlock/external{ + glass = 1; + name = "Chapel External Airlock"; + opacity = 0 + }, +/obj/structure/sign/warning/cold_temp/directional/north, +/obj/structure/sign/warning/gas_mask/directional/south{ + desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." + }, +/obj/effect/mapping_helpers/airlock/access/any/service/chapel_office, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, /turf/open/floor/iron, -/area/station/commons/fitness) +/area/station/service/chapel) +"pSX" = ( +/obj/structure/closet/crate{ + name = "Le Caisee D'abeille" + }, +/obj/item/honey_frame, +/obj/item/honey_frame, +/obj/item/honey_frame, +/obj/item/queen_bee/bought, +/obj/item/clothing/suit/hooded/bee_costume, +/obj/machinery/status_display/evac/directional/north, +/obj/effect/turf_decal/siding/thinplating/dark/corner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 5 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/light/warm/directional/north, +/obj/item/seeds/sunflower, +/obj/effect/spawner/random/food_or_drink/seed, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "pTd" = ( /obj/structure/table/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ @@ -52223,12 +53112,6 @@ }, /turf/open/floor/iron/dark, /area/station/security/brig/entrance) -"pTf" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plating, -/area/station/maintenance/fore) "pTB" = ( /obj/effect/turf_decal/tile/brown{ dir = 8 @@ -52426,11 +53309,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"pXz" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/machinery/hydroponics/soil, -/turf/open/floor/grass, -/area/station/service/hydroponics) +"pXy" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/turf/open/floor/iron/grimy, +/area/station/service/theater) "pXB" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -52495,19 +53379,18 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, /turf/open/floor/plating, /area/station/maintenance/central/greater) +"pYD" = ( +/obj/machinery/light/directional/south, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/neutral/half/contrasted, +/turf/open/floor/iron, +/area/station/commons/fitness) "pYF" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/service/janitor) -"pYI" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/table, -/obj/machinery/microwave{ - pixel_y = 5 - }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "pYT" = ( /obj/machinery/light/small/directional/east, /turf/open/floor/iron, @@ -52543,6 +53426,15 @@ /obj/structure/extinguisher_cabinet/directional/west, /turf/open/floor/iron, /area/station/engineering/storage) +"pZO" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/structure/steam_vent, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "pZY" = ( /mob/living/simple_animal/hostile/asteroid/polarbear{ move_force = 999; @@ -52556,14 +53448,19 @@ }, /turf/open/floor/engine/plasma, /area/station/engineering/atmos) -"qaf" = ( -/obj/machinery/light/directional/south, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "qai" = ( /obj/structure/window/reinforced/spawner/directional/north, /turf/open/floor/plating/snowed/icemoon, /area/station/maintenance/port/aft) +"qal" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/engineering/tracking_beacon, +/obj/effect/landmark/event_spawn, +/obj/machinery/holopad, +/obj/effect/turf_decal/bot_white, +/turf/open/floor/stone, +/area/station/commons/lounge) "qam" = ( /obj/structure/cable/multilayer/multiz, /obj/effect/turf_decal/stripes/box, @@ -52682,6 +53579,25 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/wood, /area/station/commons/dorms) +"qbG" = ( +/obj/machinery/door/airlock/external, +/obj/structure/sign/warning/gas_mask/directional/south{ + desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." + }, +/obj/structure/sign/warning/cold_temp/directional/north, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "chem-morgue-airlock" + }, +/obj/effect/mapping_helpers/airlock/access/any/medical/maintenance, +/obj/effect/mapping_helpers/broken_floor, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/medical/morgue) +"qbM" = ( +/obj/structure/ore_container/food_trough/raptor_trough, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "qbO" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -52698,6 +53614,19 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/plating, /area/station/maintenance/starboard/upper) +"qbY" = ( +/obj/item/clothing/accessory/pocketprotector, +/obj/structure/closet/secure_closet/personal/cabinet, +/obj/item/camera{ + pixel_y = 4; + pixel_x = -3 + }, +/obj/effect/spawner/random/clothing/mafia_outfit, +/obj/effect/spawner/random/clothing/mafia_outfit, +/obj/effect/spawner/random/clothing/backpack, +/obj/machinery/light/small/directional/west, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "qca" = ( /obj/structure/chair/office{ dir = 8 @@ -52868,21 +53797,17 @@ dir = 8 }, /area/station/service/chapel) -"qfe" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/table, -/obj/item/reagent_containers/condiment/enzyme{ - pixel_x = -7; - pixel_y = 6 - }, -/obj/item/reagent_containers/condiment/saltshaker{ - pixel_x = -3 - }, -/obj/item/reagent_containers/condiment/peppermill{ - pixel_x = 3 +"qeW" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +/obj/effect/turf_decal/siding/wood, +/obj/structure/chair/stool/bar/directional/north, +/obj/structure/cable, +/turf/open/floor/eighties, +/area/station/commons/lounge) "qfh" = ( /turf/open/floor/iron/recharge_floor, /area/station/science/robotics/mechbay) @@ -52903,19 +53828,17 @@ }, /turf/open/floor/iron/dark, /area/station/service/chapel) +"qfr" = ( +/obj/structure/table/wood/poker, +/obj/effect/spawner/random/entertainment/cigarette_pack, +/obj/effect/spawner/random/entertainment/lighter, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "qfs" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/structure/cable, /turf/open/floor/plating, /area/station/security/prison/safe) -"qfu" = ( -/obj/structure/closet/crate/wooden/toy, -/obj/machinery/camera/directional/south{ - c_tag = "Service Theater - Backstage" - }, -/obj/item/staff/broom, -/turf/open/floor/wood/tile, -/area/station/service/theater) "qfE" = ( /obj/effect/turf_decal/trimline/yellow/filled/warning{ dir = 4 @@ -52925,6 +53848,31 @@ }, /turf/open/floor/iron/white, /area/station/medical/treatment_center) +"qfI" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 6 + }, +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"qfJ" = ( +/obj/machinery/airalarm/directional/west, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 8 + }, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/commons/fitness) "qgm" = ( /obj/machinery/meter/monitored/waste_loop, /obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/visible{ @@ -52958,6 +53906,16 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/security/processing) +"qgQ" = ( +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) +"qgT" = ( +/obj/effect/spawner/random/structure/closet_private, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "qhd" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 @@ -52974,6 +53932,19 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"qhF" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Dormitory" + }, +/obj/effect/landmark/navigate_destination, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured, +/area/station/commons/dorms) "qhL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, @@ -52996,6 +53967,11 @@ /obj/machinery/light/floor, /turf/open/floor/iron/dark/side, /area/station/security/processing) +"qhQ" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/tile/bar/opposingcorners, +/turf/open/floor/iron, +/area/station/service/bar) "qhS" = ( /obj/machinery/door/firedoor, /obj/structure/cable, @@ -53003,6 +53979,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/catwalk_floor/iron_dark, /area/station/security/prison) +"qhV" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "qig" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -53011,16 +53993,39 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"qis" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) +"qit" = ( +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/effect/turf_decal/tile/blue/half/contrasted{ + dir = 1 + }, +/obj/machinery/firealarm/directional/north, +/turf/open/floor/iron/white, +/area/station/medical/medbay/lobby) +"qiA" = ( +/obj/machinery/chem_master/condimaster{ + desc = "Looks like a knock-off chem-master. Perhaps useful for separating liquids when mixing drinks precisely. Also dispenses condiments."; + name = "HoochMaster Deluxe" + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/service/bar) "qiF" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/brown/half/contrasted, /turf/open/floor/iron/dark/side, /area/mine/eva/lower) +"qiG" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/commons/fitness) "qiJ" = ( /obj/structure/closet/secure_closet/freezer/kitchen/maintenance, /obj/effect/spawner/random/contraband/prison, @@ -53034,6 +54039,11 @@ /obj/machinery/airalarm/directional/east, /turf/open/floor/iron, /area/station/command/heads_quarters/qm) +"qiL" = ( +/obj/machinery/door/airlock/hatch, +/obj/effect/mapping_helpers/airlock/access/any/security/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/fore) "qiN" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, /turf/open/floor/iron/dark, @@ -53063,6 +54073,9 @@ /obj/machinery/power/apc/auto_name/directional/north, /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) +"qjd" = ( +/turf/open/misc/ice/coldroom, +/area/station/service/kitchen/coldroom) "qjg" = ( /obj/effect/landmark/observer_start, /obj/effect/turf_decal/plaque{ @@ -53093,6 +54106,10 @@ /obj/effect/turf_decal/tile/blue/half/contrasted, /turf/open/floor/iron, /area/station/hallway/primary/central) +"qjn" = ( +/obj/machinery/light/small/directional/north, +/turf/open/floor/catwalk_floor/iron_dark, +/area/station/maintenance/fore) "qjp" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/effect/turf_decal/siding/thinplating_new, @@ -53124,11 +54141,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) -"qjK" = ( -/obj/effect/turf_decal/siding/white, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "qjO" = ( /obj/effect/turf_decal/stripes/line{ dir = 10 @@ -53261,6 +54273,14 @@ /obj/structure/cable, /turf/open/floor/iron/textured, /area/station/hallway/secondary/entry) +"qlS" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/chair/wood{ + dir = 1 + }, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "qlU" = ( /obj/structure/closet/crate, /turf/open/floor/plating/snowed/icemoon, @@ -53286,14 +54306,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"qmN" = ( -/obj/item/radio/intercom/directional/north, -/obj/structure/reagent_dispensers/plumbed, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/hallway/secondary/service) "qmT" = ( /obj/structure/bed{ dir = 4 @@ -53331,13 +54343,6 @@ }, /turf/open/floor/carpet, /area/station/security/prison/rec) -"qnf" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/green, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "qnj" = ( /turf/closed/wall, /area/station/commons/locker) @@ -53387,13 +54392,6 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) -"qnU" = ( -/obj/structure/extinguisher_cabinet/directional/south, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "qnV" = ( /obj/structure/table/reinforced, /obj/item/storage/toolbox/emergency{ @@ -53417,6 +54415,20 @@ /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"qod" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "kitchencounter"; + name = "Kitchen Counter Shutters" + }, +/obj/machinery/door/firedoor, +/obj/structure/desk_bell{ + pixel_x = -4; + pixel_y = 3 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "qoi" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -53428,16 +54440,26 @@ /obj/effect/turf_decal/stripes/box, /turf/open/floor/wood/parquet, /area/station/service/library) -"qoz" = ( -/obj/machinery/door/airlock/maintenance, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, -/obj/effect/mapping_helpers/airlock/unres{ +"qon" = ( +/obj/machinery/door/airlock/wood{ + name = "Backstage" + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/turf_decal/siding/wood{ dir = 4 }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/access/all/service/theatre, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/commons/lounge) "qoK" = ( /obj/structure/flora/rock/style_random, /obj/structure/window/reinforced/spawner/directional/south, @@ -53569,6 +54591,15 @@ /obj/effect/landmark/start/assistant, /turf/open/floor/wood, /area/station/service/library) +"qpQ" = ( +/obj/machinery/camera/directional/south{ + c_tag = "Service - Electrical Maintenace Upper" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/station/maintenance/starboard/fore) "qpR" = ( /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, @@ -53578,6 +54609,19 @@ /obj/machinery/recharge_station, /turf/open/floor/wood, /area/station/command/meeting_room) +"qpU" = ( +/obj/machinery/power/apc/auto_name/directional/north, +/obj/structure/cable, +/obj/structure/reagent_dispensers/plumbed{ + name = "dormitory reservoir" + }, +/obj/effect/decal/cleanable/cobweb, +/obj/effect/turf_decal/delivery/white{ + color = "#307db9" + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/iron/textured, +/area/station/maintenance/fore) "qpZ" = ( /obj/structure/table, /obj/item/folder/blue{ @@ -53616,13 +54660,6 @@ /obj/item/storage/toolbox/emergency, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) -"qqx" = ( -/obj/structure/sign/painting/library{ - pixel_y = 32 - }, -/obj/item/kirbyplants/organic/applebush, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "qqB" = ( /obj/machinery/button/door/directional/north{ id = "maint3"; @@ -53647,6 +54684,15 @@ dir = 1 }, /area/station/security/office) +"qre" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/machinery/vending/wardrobe/hydro_wardrobe, +/turf/open/floor/iron, +/area/station/service/hydroponics) "qrg" = ( /obj/item/bodypart/head, /obj/effect/decal/cleanable/blood, @@ -53688,11 +54734,29 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron/showroomfloor, /area/station/security/prison/toilet) +"qrF" = ( +/obj/machinery/duct, +/obj/effect/turf_decal/tile/blue{ + dir = 1 + }, +/obj/effect/turf_decal/tile/green{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "qrJ" = ( /obj/machinery/ticket_machine/directional/east, /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/hallway/primary/central) +"qrM" = ( +/obj/structure/window/reinforced/spawner/directional/north, +/obj/effect/landmark/start/hangover, +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/commons/fitness) "qrQ" = ( /obj/structure/railing{ dir = 8 @@ -53754,6 +54818,12 @@ /obj/item/clothing/gloves/latex, /turf/open/floor/plating, /area/station/security/prison/safe) +"qsY" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "qtj" = ( /turf/closed/wall, /area/station/engineering/storage) @@ -53777,6 +54847,22 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron/dark, /area/station/security/prison/garden) +"qtG" = ( +/obj/machinery/camera/directional/south{ + c_tag = "Fitness Room South" + }, +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/light_switch/directional/south{ + pixel_x = -7 + }, +/obj/item/kirbyplants/random, +/turf/open/floor/iron, +/area/station/commons/fitness) "qtH" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -53817,6 +54903,33 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron/dark, /area/station/service/chapel) +"quw" = ( +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/structure/closet/crate/hydroponics, +/obj/item/wrench, +/obj/item/wrench, +/obj/item/grenade/chem_grenade/antiweed{ + pixel_x = 3; + pixel_y = 1 + }, +/obj/item/grenade/chem_grenade/antiweed, +/obj/item/shovel/spade, +/obj/item/reagent_containers/spray/plantbgone{ + pixel_x = 8; + pixel_y = 8 + }, +/obj/item/reagent_containers/spray/plantbgone{ + pixel_y = 3 + }, +/obj/item/cultivator, +/obj/item/shovel/spade, +/obj/item/reagent_containers/cup/watering_can, +/obj/machinery/airalarm/directional/north, +/turf/open/floor/iron, +/area/station/service/hydroponics) "quB" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment{ @@ -53827,6 +54940,9 @@ }, /turf/open/floor/iron/grimy, /area/station/service/chapel/office) +"quJ" = ( +/turf/open/floor/stone, +/area/station/commons/lounge) "quK" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -54003,14 +55119,6 @@ /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"qwP" = ( -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/commons/fitness) "qwX" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/effect/decal/cleanable/dirt, @@ -54147,6 +55255,19 @@ }, /turf/open/floor/iron/dark, /area/station/cargo/miningdock) +"qyZ" = ( +/obj/structure/table, +/obj/machinery/light/small/dim/directional/west, +/obj/item/camera{ + pixel_y = 9; + pixel_x = -2 + }, +/obj/item/reagent_containers/cup/glass/waterbottle/empty{ + pixel_y = 5; + pixel_x = 4 + }, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "qzq" = ( /obj/structure/sign/departments/cargo, /turf/closed/wall/r_wall, @@ -54182,17 +55303,23 @@ }, /turf/open/floor/wood, /area/station/maintenance/port/aft) -"qzN" = ( -/obj/structure/closet, -/obj/effect/spawner/random/clothing/costume, -/obj/effect/decal/cleanable/cobweb, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "qzT" = ( /obj/structure/closet/firecloset, /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"qzU" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Central Access" + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "qzV" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle{ dir = 4 @@ -54288,20 +55415,6 @@ /obj/machinery/portable_atmospherics/canister/air, /turf/open/floor/engine/air, /area/station/engineering/atmos) -"qCz" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 5 - }, -/obj/machinery/chem_dispenser/drinks/beer{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/duct, -/obj/structure/table/wood, -/obj/structure/disposalpipe/segment, -/turf/open/floor/stone, -/area/station/service/bar) "qCA" = ( /obj/structure/table/wood, /turf/open/floor/wood, @@ -54375,6 +55488,11 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter) +"qDk" = ( +/obj/machinery/door/airlock/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "qDD" = ( /obj/machinery/washing_machine, /obj/effect/decal/cleanable/dirt, @@ -54396,18 +55514,15 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"qDZ" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/table, -/obj/item/plate, -/obj/item/food/piedough, -/obj/effect/spawner/random/food_or_drink/cake_ingredients, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "qEa" = ( /obj/structure/cable/layer3, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) +"qEh" = ( +/obj/structure/girder, +/obj/structure/grille, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) "qEj" = ( /obj/structure/table/glass, /obj/item/assembly/igniter, @@ -54551,17 +55666,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) -"qFC" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/siding/wideplating/dark{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) +"qFD" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "qFJ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/holopad, @@ -54608,6 +55719,17 @@ /obj/item/gps/mining, /turf/open/floor/iron/smooth, /area/mine/eva) +"qGh" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/machinery/light/small/directional/south, +/obj/structure/cable, +/turf/open/floor/iron/grimy, +/area/station/service/bar/backroom) "qGi" = ( /obj/effect/turf_decal/trimline/purple/filled/warning{ dir = 8 @@ -54692,6 +55814,11 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron/dark, /area/station/science/breakroom) +"qHs" = ( +/obj/structure/flora/bush/flowers_yw/style_random, +/obj/structure/flora/bush/fullgrass/style_random, +/turf/open/floor/grass, +/area/station/service/hydroponics) "qHz" = ( /obj/machinery/light_switch/directional/west, /obj/machinery/disposal/bin{ @@ -54749,12 +55876,6 @@ }, /turf/open/floor/iron, /area/station/security/prison/garden) -"qIv" = ( -/obj/machinery/icecream_vat, -/obj/effect/turf_decal/tile/brown/diagonal_edge, -/obj/structure/window/reinforced/spawner/directional/west, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "qIB" = ( /obj/effect/turf_decal/caution/stand_clear, /obj/machinery/door/poddoor/shutters/window{ @@ -54783,15 +55904,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) -"qIP" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/effect/turf_decal/tile/red/half/contrasted{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "qIU" = ( /turf/open/floor/iron, /area/station/commons/dorms) @@ -54810,6 +55922,15 @@ /obj/item/cigbutt, /turf/open/floor/wood/large, /area/mine/eva/lower) +"qJy" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/bar) "qJT" = ( /obj/machinery/light/small/directional/south, /turf/open/floor/plating/snowed/icemoon, @@ -54875,6 +55996,22 @@ /obj/machinery/atmospherics/components/tank, /turf/open/floor/iron/dark, /area/station/science/ordnance) +"qKw" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table, +/obj/item/grown/log/tree, +/obj/item/grown/log/tree{ + pixel_y = 5; + pixel_x = 7 + }, +/obj/item/grown/log/tree{ + pixel_y = 0; + pixel_x = 7 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "qKx" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/effect/turf_decal/bot, @@ -54921,13 +56058,6 @@ /obj/structure/cable, /turf/open/floor/iron/smooth, /area/station/security/brig) -"qKX" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "qLf" = ( /obj/structure/sign/painting/library{ pixel_y = 32 @@ -55012,25 +56142,6 @@ "qLY" = ( /turf/closed/wall/r_wall, /area/station/science/xenobiology) -"qMe" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/machinery/door/airlock{ - name = "Theater Stage" - }, -/obj/machinery/door/firedoor, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/all/service/theatre, -/turf/open/floor/iron/dark/textured_half{ - dir = 1 - }, -/area/station/service/theater) "qMm" = ( /obj/structure/bookcase/random/adult, /turf/open/floor/wood, @@ -55045,10 +56156,26 @@ /obj/effect/turf_decal/trimline/yellow/filled/line, /turf/open/floor/iron/white, /area/station/medical/chemistry) +"qMD" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/spawner/structure/window/reinforced/tinted, +/turf/open/floor/plating, +/area/station/maintenance/fore) "qMH" = ( /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/maint) +"qMI" = ( +/obj/effect/turf_decal/siding/wood/corner{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "qMN" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ @@ -55061,6 +56188,26 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/engineering/supermatter) +"qMO" = ( +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/corner{ + dir = 8 + }, +/obj/effect/landmark/start/botanist, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"qMS" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/chair/wood{ + dir = 1 + }, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "qMT" = ( /turf/closed/wall, /area/station/commons/lounge) @@ -55075,21 +56222,6 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/plating, /area/station/engineering/storage_shared) -"qNc" = ( -/obj/machinery/door/airlock/highsecurity{ - name = "Service Hall Exit" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "service-hall-external" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 5 - }, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/turf/open/floor/iron/textured_half{ - dir = 1 - }, -/area/station/hallway/secondary/service) "qNl" = ( /obj/structure/plasticflaps/opaque, /obj/effect/turf_decal/delivery, @@ -55174,6 +56306,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/service) +"qOB" = ( +/obj/machinery/status_display/ai/directional/east, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "qOD" = ( /obj/effect/turf_decal/caution/stand_clear, /obj/effect/turf_decal/siding/dark_blue, @@ -55263,10 +56399,15 @@ }, /turf/open/floor/wood, /area/station/maintenance/port/aft) -"qPE" = ( -/obj/structure/closet/secure_closet/freezer/meat, -/turf/open/misc/asteroid/snow/coldroom, -/area/station/service/kitchen/coldroom) +"qPD" = ( +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "qPI" = ( /obj/effect/turf_decal/trimline/blue/filled/corner{ dir = 4 @@ -55283,6 +56424,13 @@ "qPL" = ( /turf/closed/wall/r_wall, /area/station/hallway/secondary/exit/departure_lounge) +"qPQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/effect/spawner/random/structure/crate, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "qPX" = ( /obj/structure/sink/directional/west, /obj/structure/mirror/directional/east, @@ -55349,6 +56497,12 @@ /obj/effect/turf_decal/tile/red, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"qQV" = ( +/obj/structure/cable, +/obj/effect/mapping_helpers/broken_floor, +/obj/machinery/duct, +/turf/open/floor/plating, +/area/station/maintenance/fore) "qRk" = ( /obj/item/chair/wood, /turf/open/floor/carpet, @@ -55379,6 +56533,12 @@ /obj/structure/flora/tree/pine/style_random, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"qRF" = ( +/obj/structure/table/wood, +/obj/machinery/chem_dispenser/drinks/beer, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/service/bar) "qRO" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -55411,6 +56571,11 @@ /obj/effect/landmark/start/assistant, /turf/open/floor/iron/freezer, /area/station/commons/toilet) +"qSi" = ( +/obj/structure/railing/wooden_fence, +/obj/item/flashlight/lantern/on, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "qSj" = ( /obj/structure/table/wood, /obj/item/folder/blue, @@ -55461,14 +56626,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/sepia, /area/station/security/prison/rec) -"qSB" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "External Access" - }, -/obj/effect/mapping_helpers/airlock/access/all/engineering/external, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "qSC" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ @@ -55499,6 +56656,11 @@ /obj/machinery/firealarm/directional/north, /turf/open/floor/iron/white, /area/station/medical/virology) +"qSP" = ( +/obj/item/kirbyplants/random, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/hallway/primary/fore) "qST" = ( /obj/structure/table/reinforced, /obj/item/pipe_dispenser, @@ -55506,6 +56668,15 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"qSU" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/box/red/corners{ + dir = 4 + }, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "qSY" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -55534,6 +56705,14 @@ }, /turf/open/floor/iron, /area/station/service/hydroponics/garden) +"qTp" = ( +/obj/structure/table/wood, +/obj/item/clothing/mask/fakemoustache, +/obj/item/clothing/mask/cigarette/pipe, +/obj/item/clothing/glasses/monocle, +/obj/item/radio/intercom/directional/north, +/turf/open/floor/iron/grimy, +/area/station/service/theater) "qTs" = ( /turf/open/floor/iron/showroomfloor, /area/station/security/prison/mess) @@ -55573,6 +56752,12 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"qUo" = ( +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/structure/closet, +/obj/effect/spawner/random/maintenance/two, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "qUr" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -55668,6 +56853,13 @@ }, /turf/open/floor/iron/smooth, /area/station/maintenance/port/lesser) +"qVG" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/neutral/half/contrasted, +/turf/open/floor/iron, +/area/station/commons/fitness) "qVJ" = ( /obj/machinery/disposal/bin, /obj/machinery/light_switch/directional/south, @@ -55682,6 +56874,14 @@ /obj/effect/spawner/random/food_or_drink/booze, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"qWf" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/machinery/deepfryer, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "qWh" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -55785,13 +56985,6 @@ }, /turf/open/floor/iron/white, /area/station/science/research) -"qXz" = ( -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "qXF" = ( /obj/machinery/computer/station_alert, /obj/effect/turf_decal/tile/yellow/half/contrasted, @@ -55819,11 +57012,6 @@ }, /turf/open/floor/iron/chapel, /area/station/service/chapel) -"qYo" = ( -/obj/effect/turf_decal/siding/white/corner, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "qYw" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -55851,19 +57039,18 @@ }, /turf/open/floor/iron/dark, /area/station/security/checkpoint/customs/auxiliary) -"qYD" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 4 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 4 +"qYC" = ( +/obj/machinery/door/window/right/directional/south{ + req_access = list("kitchen"); + name = "The Ice Box" }, -/obj/machinery/duct, -/obj/structure/chair/office{ - dir = 4 +/obj/structure/sign/warning/cold_temp/directional/east, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 1 }, -/turf/open/floor/iron, -/area/station/service/hydroponics) +/obj/effect/turf_decal/siding/white, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "qYP" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/machinery/door/airlock/external{ @@ -55915,16 +57102,6 @@ }, /turf/open/floor/iron/dark, /area/station/medical/treatment_center) -"qZB" = ( -/obj/structure/table/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 1; - id = "kitchencounter"; - name = "Kitchen Counter Shutters" - }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "qZN" = ( /turf/closed/wall/r_wall, /area/station/science/ordnance/freezerchamber) @@ -55977,6 +57154,10 @@ /obj/machinery/newscaster/directional/north, /turf/open/floor/iron/showroomfloor, /area/station/security/warden) +"raq" = ( +/obj/structure/fence/corner, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "ras" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/engineering/glass{ @@ -56011,10 +57192,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) -"raL" = ( -/obj/item/kirbyplants/random, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) "raN" = ( /obj/machinery/firealarm/directional/north, /obj/machinery/light/directional/north, @@ -56046,6 +57223,13 @@ /obj/structure/closet, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) +"rbh" = ( +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/green{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "rbm" = ( /obj/machinery/camera/directional/east{ c_tag = "MiniSat External NorthWest"; @@ -56054,6 +57238,10 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"rbp" = ( +/obj/machinery/duct, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "rbs" = ( /obj/effect/turf_decal/tile/yellow, /obj/machinery/light/directional/east, @@ -56062,11 +57250,24 @@ "rbC" = ( /turf/closed/wall, /area/station/command/heads_quarters/qm) +"rbE" = ( +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "rbT" = ( /obj/structure/ore_box, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/mine/laborcamp) +"rbU" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 1; + id = "botany_apiary"; + name = "Apiary Shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) "rbY" = ( /obj/structure/table/reinforced, /obj/item/pipe_dispenser, @@ -56143,15 +57344,6 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"rdd" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 1 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "rdl" = ( /obj/machinery/button/door/directional/east{ id = "misclab"; @@ -56171,34 +57363,38 @@ /obj/item/radio/intercom/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/port) +"rdq" = ( +/obj/machinery/light/small/directional/east, +/obj/effect/spawner/random/trash/mopbucket, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) +"rdv" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 10 + }, +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "rdw" = ( /obj/structure/bookcase, /obj/machinery/light/small/directional/north, /turf/open/floor/carpet, /area/station/security/processing) -"rdB" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/structure/chair/sofa/corp/right{ - dir = 4; - pixel_x = -4 - }, -/obj/machinery/firealarm/directional/west, -/turf/open/floor/iron/grimy, -/area/station/service/bar/atrium) "rdG" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 8 }, /turf/open/floor/iron/white, /area/station/medical/storage) -"rdR" = ( -/obj/effect/turf_decal/tile/red{ - dir = 4 - }, -/turf/open/floor/iron/textured, -/area/station/security/brig) "rea" = ( /obj/structure/table, /obj/effect/turf_decal/tile/brown/half/contrasted{ @@ -56216,9 +57412,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) -"reh" = ( -/turf/open/floor/iron/textured_half, -/area/station/service/hydroponics) "rej" = ( /obj/machinery/oven/range, /turf/open/floor/plating, @@ -56231,6 +57424,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"reu" = ( +/obj/structure/fence/corner{ + dir = 8 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "rex" = ( /obj/effect/turf_decal/stripes/asteroid/corner{ dir = 8 @@ -56245,16 +57444,6 @@ dir = 5 }, /area/mine/living_quarters) -"reA" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/chair/sofa/left/brown{ - dir = 1 - }, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/grimy, -/area/station/commons/lounge) "reJ" = ( /obj/machinery/navbeacon{ codes_txt = "delivery;dir=8"; @@ -56267,11 +57456,6 @@ }, /turf/open/floor/iron, /area/station/commons/storage/primary) -"reM" = ( -/obj/structure/table, -/obj/item/flashlight/flare/candle, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "reT" = ( /obj/machinery/door/window/left/directional/east{ name = "Containment Pen 8"; @@ -56284,6 +57468,13 @@ /obj/structure/cable, /turf/open/floor/engine, /area/station/science/xenobiology) +"reX" = ( +/obj/structure/cable, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "rfh" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -56293,6 +57484,16 @@ /obj/structure/cable/layer3, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/hallway) +"rfj" = ( +/obj/structure/frame/computer{ + dir = 1 + }, +/obj/item/radio/intercom/directional/south, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron/smooth, +/area/station/maintenance/starboard/fore) "rfo" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -56320,19 +57521,12 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) -"rga" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/obj/structure/table, -/obj/item/reagent_containers/condiment/saltshaker{ - pixel_x = -3 - }, -/obj/item/reagent_containers/condiment/peppermill{ - pixel_x = 3 - }, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) +"rfW" = ( +/obj/structure/cable, +/obj/effect/turf_decal/tile/neutral/anticorner/contrasted, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/commons/dorms) "rgi" = ( /obj/structure/sign/poster/contraband/random/directional/west, /turf/open/floor/plating, @@ -56395,6 +57589,12 @@ "rgE" = ( /turf/closed/wall/r_wall, /area/station/engineering/atmos/hfr_room) +"rgM" = ( +/obj/effect/landmark/start/hangover, +/obj/effect/turf_decal/tile/neutral/half/contrasted, +/obj/machinery/computer/security/telescreen/entertainment/directional/south, +/turf/open/floor/iron, +/area/station/commons/dorms) "rhf" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -56404,17 +57604,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/command/heads_quarters/hos) -"rhh" = ( -/obj/machinery/biogenerator, -/obj/effect/turf_decal/siding/white{ - dir = 10 - }, -/obj/effect/turf_decal/tile/green/opposingcorners{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners, -/turf/open/floor/iron, -/area/station/service/hydroponics) "rhi" = ( /obj/machinery/door/firedoor/heavy, /obj/machinery/door/airlock/research{ @@ -56445,13 +57634,14 @@ }, /turf/open/floor/iron/smooth, /area/station/security/brig) -"rhR" = ( +"rhS" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/trimline/green/filled/line, -/obj/effect/turf_decal/trimline/blue/filled/warning, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "rhY" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible, /obj/effect/turf_decal/box/red, @@ -56490,10 +57680,36 @@ /obj/effect/mapping_helpers/mail_sorting/security/general, /turf/open/floor/iron, /area/station/security/brig/upper) +"riB" = ( +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/access/all/service/bar, +/obj/machinery/door/airlock{ + name = "Bar" + }, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wood, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/service/bar) "riL" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/mine/living_quarters) +"riM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table, +/obj/item/food/grown/carrot, +/obj/item/food/grown/carrot{ + pixel_y = 4; + pixel_x = -2 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "riT" = ( /obj/machinery/atmospherics/components/unary/outlet_injector/on, /turf/open/floor/plating/snowed/icemoon, @@ -56508,24 +57724,20 @@ /obj/structure/closet/firecloset, /turf/open/floor/iron/dark, /area/station/engineering/main) -"rjr" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply, -/turf/open/floor/plating, -/area/station/medical/virology) -"rjs" = ( -/obj/structure/disposalpipe/sorting/mail/flip{ - dir = 2 +"rji" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/power/apc/auto_name/directional/west, -/obj/effect/mapping_helpers/mail_sorting/service/dormitories, -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ +/obj/structure/chair/wood{ dir = 1 }, -/turf/open/floor/iron, -/area/station/commons/fitness) +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) +"rjr" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply, +/turf/open/floor/plating, +/area/station/medical/virology) "rjt" = ( /obj/structure/table/glass, /obj/item/computer_disk/medical, @@ -56607,16 +57819,6 @@ }, /turf/open/floor/iron/checker, /area/station/maintenance/port/fore) -"rki" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Central Access" - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "rkl" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -56626,6 +57828,10 @@ }, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) +"rkm" = ( +/obj/structure/chair/stool, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "rkt" = ( /obj/structure/cable, /obj/machinery/light/directional/east, @@ -56671,6 +57877,25 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"rlA" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/medical/morgue) +"rlE" = ( +/obj/item/radio/intercom/directional/east, +/obj/machinery/computer/slot_machine{ + name = "two-armed bandit" + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) +"rlH" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "rlS" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -56729,6 +57954,14 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/mining, /turf/open/floor/iron/dark/textured_half, /area/mine/mechbay) +"rmG" = ( +/obj/machinery/door/airlock/research/glass/incinerator/ordmix_exterior{ + name = "Burn Chamber Exterior Airlock" + }, +/obj/effect/mapping_helpers/airlock/locked, +/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "rmM" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk{ @@ -56736,6 +57969,11 @@ }, /turf/open/floor/wood, /area/station/command/meeting_room) +"rmR" = ( +/obj/effect/spawner/random/trash/mess, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "rmU" = ( /obj/effect/spawner/random/trash/graffiti, /obj/structure/sign/poster/contraband/free_drone/directional/east, @@ -56750,6 +57988,10 @@ /obj/effect/turf_decal/tile/red, /turf/open/floor/iron/textured, /area/station/security/brig) +"rng" = ( +/obj/machinery/light/cold/directional/west, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "rnh" = ( /obj/machinery/door/airlock{ name = "Observatory Access" @@ -56872,6 +58114,10 @@ /obj/machinery/newscaster/directional/south, /turf/open/floor/iron, /area/station/science/explab) +"roW" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/closed/wall/r_wall, +/area/station/science/ordnance) "roX" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -56918,6 +58164,15 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/central) +"rpJ" = ( +/obj/structure/minecart_rail{ + dir = 10 + }, +/obj/structure/cable, +/obj/structure/sign/warning/directional/south, +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) "rpK" = ( /obj/structure/chair/pew/left{ dir = 1 @@ -56986,6 +58241,15 @@ }, /turf/open/floor/iron/dark, /area/station/security/checkpoint/customs/auxiliary) +"rqn" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/light/small/directional/south, +/obj/structure/rack, +/obj/machinery/camera/directional/south{ + c_tag = "Chapel Electrical Maintenace Lower" + }, +/turf/open/floor/iron/smooth, +/area/station/maintenance/department/chapel) "rqD" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -56999,6 +58263,13 @@ }, /turf/open/floor/plating, /area/station/engineering/engine_smes) +"rqG" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/turf/open/floor/wood, +/area/station/commons/lounge) "rqH" = ( /obj/structure/closet/crate, /obj/item/stack/sheet/leather, @@ -57018,10 +58289,20 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/cargo/lobby) -"rqT" = ( -/obj/machinery/door/firedoor, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) +"rqQ" = ( +/obj/machinery/camera/directional/east{ + c_tag = "Service - Kitchen" + }, +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/obj/machinery/airalarm/directional/east, +/obj/structure/table, +/obj/machinery/processor{ + pixel_y = 6 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "rqY" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 9 @@ -57029,10 +58310,22 @@ /obj/machinery/light_switch/directional/west, /turf/open/floor/iron/dark, /area/station/medical/virology) +"rra" = ( +/obj/machinery/modular_computer/preset/cargochat/service, +/obj/machinery/requests_console/auto_name/directional/north, +/obj/effect/turf_decal/bot, +/obj/effect/turf_decal/siding/dark, +/turf/open/floor/iron/checker, +/area/station/hallway/secondary/service) "rrf" = ( /obj/structure/table/wood, /turf/open/floor/iron/dark, /area/station/service/chapel/office) +"rrl" = ( +/obj/item/stack/sheet/mineral/wood, +/obj/effect/decal/cleanable/generic, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "rrn" = ( /obj/structure/closet/emcloset, /obj/structure/sign/poster/contraband/random/directional/north, @@ -57047,29 +58340,19 @@ }, /turf/open/floor/glass/reinforced, /area/station/hallway/primary/starboard) -"rrx" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/duct, -/obj/structure/disposalpipe/segment{ +"rrL" = ( +/obj/effect/turf_decal/siding/wood{ dir = 4 }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/duct, +/turf/open/floor/wood/large, +/area/station/service/bar) "rrV" = ( /obj/effect/spawner/structure/window/hollow/reinforced/end, /turf/open/floor/plating, /area/mine/eva) -"rrX" = ( -/obj/effect/turf_decal/siding/wood, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/airalarm/directional/east, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/theater) "rsw" = ( /obj/effect/turf_decal/stripes/corner{ dir = 8 @@ -57114,17 +58397,6 @@ "rsY" = ( /turf/closed/wall/r_wall, /area/mine/eva) -"rtc" = ( -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) -"rth" = ( -/obj/effect/turf_decal/siding/white, -/obj/effect/turf_decal/siding/white, -/obj/effect/spawner/random/entertainment/arcade, -/obj/structure/sign/poster/random/directional/north, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "rtn" = ( /obj/structure/chair/comfy/black, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -57225,6 +58497,23 @@ }, /turf/open/floor/iron, /area/station/engineering/main) +"ruQ" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) +"ruX" = ( +/obj/structure/closet/lasertag/red, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/obj/machinery/newscaster/directional/north, +/turf/open/floor/iron, +/area/station/commons/fitness) "ruZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable/layer3, @@ -57249,6 +58538,13 @@ /obj/machinery/light/directional/east, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) +"rvO" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/item/kirbyplants/organic/plant2, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "rvS" = ( /obj/structure/rack, /obj/item/poster/random_contraband, @@ -57356,14 +58652,6 @@ /obj/structure/girder, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) -"rxA" = ( -/obj/machinery/disposal/bin, -/obj/structure/disposalpipe/trunk{ - dir = 4 - }, -/obj/structure/sign/warning/electric_shock/directional/west, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) "rxG" = ( /obj/structure/ore_vent/starter_resources{ icon_state = "ore_vent_ice_active"; @@ -57371,11 +58659,6 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"rxK" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "rxM" = ( /obj/machinery/door/poddoor/preopen{ id = "xenobio8"; @@ -57389,6 +58672,11 @@ /obj/structure/sign/warning/electric_shock, /turf/open/floor/plating, /area/station/science/xenobiology) +"rxV" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "rxW" = ( /turf/closed/mineral/random/snow, /area/icemoon/underground/unexplored/rivers) @@ -57444,17 +58732,12 @@ /obj/effect/turf_decal/delivery/red, /turf/open/floor/iron/textured, /area/station/hallway/secondary/entry) -"ryO" = ( -/obj/item/kirbyplants/random, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) -"rza" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/commons/fitness) +"ryX" = ( +/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_ordmix{ + dir = 8 + }, +/turf/open/floor/engine, +/area/station/science/ordnance) "rzj" = ( /obj/structure/table, /obj/item/stack/sheet/iron/fifty{ @@ -57464,22 +58747,25 @@ /obj/item/stack/sheet/iron/fifty, /turf/open/floor/iron/dark, /area/station/engineering/atmos) -"rzk" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Dormitory" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/commons/dorms) "rzm" = ( /obj/structure/sign/departments/cargo, /turf/closed/wall, /area/station/cargo/lobby) +"rzq" = ( +/obj/machinery/firealarm/directional/south, +/obj/effect/turf_decal/siding/thinplating/dark/corner{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/green/filled/line, +/obj/effect/turf_decal/trimline/blue/filled/warning, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "rzz" = ( /obj/machinery/door/airlock/command{ name = "Server Room" @@ -57491,20 +58777,6 @@ /obj/effect/mapping_helpers/airlock/access/all/science/rd, /turf/open/floor/iron/dark, /area/station/science/server) -"rzA" = ( -/obj/machinery/door/airlock{ - name = "Theater Backstage" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/door/firedoor, -/obj/machinery/duct, -/obj/effect/mapping_helpers/airlock/access/all/service/theatre, -/turf/open/floor/iron/textured_half{ - dir = 1 - }, -/area/station/service/theater) "rzD" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/manifold/layer2{ dir = 1 @@ -57540,6 +58812,17 @@ /obj/machinery/digital_clock/directional/south, /turf/open/openspace, /area/station/medical/medbay/lobby) +"rzY" = ( +/obj/structure/table/wood, +/obj/item/raptor_dex{ + pixel_y = 13 + }, +/obj/item/raptor_dex{ + pixel_y = 7 + }, +/obj/item/raptor_dex, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "rAr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -57553,6 +58836,23 @@ }, /turf/open/floor/iron, /area/mine/laborcamp/security) +"rAx" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/obj/machinery/duct, +/obj/effect/turf_decal/tile/bar{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/station/service/kitchen/coldroom) "rAA" = ( /obj/machinery/pdapainter, /turf/open/floor/iron, @@ -57601,10 +58901,6 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron/dark/smooth_large, /area/station/ai_monitored/command/storage/eva) -"rBn" = ( -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/commons/dorms) "rBo" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/smart/simple/dark/visible/layer1{ @@ -57616,6 +58912,12 @@ }, /turf/open/floor/plating, /area/station/engineering/atmos) +"rBp" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/closed/wall, +/area/station/service/library) "rBv" = ( /obj/structure/chair/stool/directional/north, /obj/item/storage/toolbox/artistic{ @@ -57662,16 +58964,6 @@ "rCf" = ( /turf/open/floor/iron, /area/station/maintenance/starboard/fore) -"rCh" = ( -/obj/machinery/door/airlock/medical/glass{ - name = "Icemoon Exterior Garden" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "hydroponics-external" - }, -/turf/open/floor/iron/textured_half, -/area/station/service/hydroponics) "rCj" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -57834,9 +59126,6 @@ /obj/structure/sign/poster/official/safety_internals/directional/east, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) -"rDF" = ( -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "rDH" = ( /obj/structure/flora/grass/green/style_random, /mob/living/basic/pet/penguin/emperor{ @@ -57844,6 +59133,16 @@ }, /turf/open/misc/asteroid/snow/standard_air, /area/station/science/research) +"rDI" = ( +/obj/item/toy/plush/lizard_plushie{ + name = "Wines-And-Dines"; + pixel_x = 4 + }, +/obj/item/reagent_containers/cup/glass/bottle{ + pixel_x = -9 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "rDJ" = ( /obj/structure/ladder{ name = "upper dispenser access" @@ -57851,6 +59150,10 @@ /obj/effect/turf_decal/stripes/box, /turf/open/floor/iron/dark/textured_large, /area/station/medical/treatment_center) +"rDN" = ( +/obj/structure/signpost, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "rDO" = ( /obj/structure/table, /obj/item/storage/box/lights/mixed, @@ -57903,6 +59206,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/science/ordnance) +"rEn" = ( +/obj/structure/railing/wooden_fence{ + dir = 4 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "rEp" = ( /obj/structure/table, /obj/item/hand_labeler, @@ -57912,6 +59221,17 @@ }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) +"rEt" = ( +/obj/machinery/seed_extractor, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "rEx" = ( /obj/effect/turf_decal/bot_white, /turf/open/floor/iron/dark, @@ -57923,6 +59243,15 @@ }, /turf/open/floor/iron/white, /area/station/medical/treatment_center) +"rEH" = ( +/obj/item/chair/stool/bar{ + dir = 2; + pixel_y = -2 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "rEP" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -57934,6 +59263,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"rEY" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "kitchencounter"; + name = "Kitchen Counter Shutters" + }, +/obj/structure/displaycase/forsale/kitchen, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "rFb" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 @@ -57946,13 +59286,6 @@ }, /turf/open/floor/iron/dark, /area/station/commons/storage/mining) -"rFr" = ( -/obj/effect/turf_decal/siding/wideplating/dark{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/service/hydroponics) "rFD" = ( /obj/machinery/firealarm/directional/east, /turf/open/floor/iron, @@ -58092,6 +59425,23 @@ }, /turf/open/floor/iron/dark, /area/station/tcommsat/computer) +"rHR" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/machinery/door/airlock/external{ + glass = 1; + name = "Chapel Maintenance External Airlock"; + opacity = 0 + }, +/obj/structure/sign/warning/cold_temp/directional/north, +/obj/structure/sign/warning/gas_mask/directional/south{ + desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." + }, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/maintenance/department/chapel) "rHZ" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -58128,6 +59478,10 @@ /obj/machinery/light/directional/north, /turf/open/floor/iron/showroomfloor, /area/station/engineering/atmos) +"rIS" = ( +/obj/structure/flora/rock/icy/style_random, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "rIU" = ( /turf/open/floor/iron/white, /area/station/science/robotics/lab) @@ -58173,33 +59527,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/smooth, /area/station/maintenance/fore/lesser) -"rJL" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) -"rKd" = ( -/obj/effect/landmark/start/hangover, -/obj/effect/spawner/random/entertainment/gambling, -/obj/structure/table/wood, -/obj/machinery/camera{ - c_tag = "Service Bar North"; - dir = 9 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) -"rKe" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Dormitory" - }, -/obj/effect/landmark/navigate_destination, -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/commons/dorms) +"rJX" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/textured, +/area/station/service/hydroponics) "rKs" = ( /obj/structure/chair/stool/directional/south, /obj/structure/sign/poster/official/work_for_a_future/directional/north, @@ -58268,13 +59599,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/cargo/office) -"rLV" = ( -/obj/structure/window/reinforced/spawner/directional/east, -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 4 - }, -/turf/open/floor/carpet, -/area/station/service/theater) "rLX" = ( /obj/item/target, /obj/item/target/syndicate, @@ -58288,11 +59612,10 @@ }, /turf/open/floor/iron/dark/textured, /area/station/security/range) -"rMa" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/sign/warning/cold_temp, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) +"rMm" = ( +/obj/machinery/airalarm/directional/west, +/turf/open/openspace, +/area/station/service/bar/atrium) "rMr" = ( /obj/structure/chair{ dir = 8 @@ -58402,6 +59725,12 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"rNV" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/segment, +/obj/structure/railing/corner/end/flip, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "rOb" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -58468,11 +59797,6 @@ /obj/structure/closet/toolcloset, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"rPf" = ( -/obj/structure/table/wood/poker, -/obj/item/clothing/mask/cigarette/pipe, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "rPn" = ( /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible, /obj/machinery/camera{ @@ -58491,11 +59815,6 @@ /obj/structure/fake_stairs/wood/directional/north, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) -"rPu" = ( -/obj/machinery/power/smes, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/department/electrical) "rPL" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/rack, @@ -58520,10 +59839,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron, /area/station/hallway/primary/central) -"rQt" = ( -/obj/machinery/airalarm/directional/west, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "rQw" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 8 @@ -58604,15 +59919,29 @@ }, /turf/open/floor/iron, /area/station/science/ordnance) -"rRy" = ( -/obj/structure/railing{ +"rRs" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ dir = 4 }, -/obj/machinery/door/firedoor/border_only{ +/obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 4 }, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) +/obj/machinery/camera/directional/east{ + c_tag = "Service - Botany Upper Entrance" + }, +/obj/structure/table/glass, +/obj/machinery/fax/auto_name, +/turf/open/floor/iron, +/area/station/service/hydroponics) +"rRu" = ( +/obj/structure/table/wood, +/obj/item/toy/mecha/honk{ + pixel_y = 12 + }, +/obj/structure/sign/poster/contraband/random/directional/west, +/obj/machinery/light/small/directional/west, +/turf/open/floor/iron/grimy, +/area/station/service/theater) "rRM" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -58657,12 +59986,6 @@ "rSC" = ( /turf/open/floor/glass/reinforced, /area/station/engineering/lobby) -"rSK" = ( -/obj/effect/turf_decal/siding/white/corner, -/obj/machinery/holopad, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "rSN" = ( /obj/machinery/computer/upload/borg{ dir = 1 @@ -58685,6 +60008,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) +"rSQ" = ( +/obj/item/toy/snowball{ + pixel_x = -11; + pixel_y = -2 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "rST" = ( /obj/structure/marker_beacon/cerulean, /turf/open/misc/asteroid/snow/icemoon, @@ -58884,15 +60214,6 @@ /obj/item/storage/backpack, /turf/open/floor/plastic, /area/station/commons/dorms/laundry) -"rVO" = ( -/obj/structure/reagent_dispensers/beerkeg, -/obj/item/stack/package_wrap{ - pixel_x = 2; - pixel_y = 3 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "rVV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -58917,6 +60238,15 @@ }, /turf/open/floor/engine/plasma, /area/station/engineering/atmos) +"rWA" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock/access/any/security/general, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/maintenance/fore) "rWO" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -59011,6 +60341,14 @@ }, /turf/open/floor/iron/large, /area/station/commons/storage/primary) +"rXB" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/structure/minecart_rail/railbreak, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "rXD" = ( /obj/machinery/button/door/directional/east{ id = "xenobio7"; @@ -59042,6 +60380,11 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/security/processing) +"rXY" = ( +/obj/item/kirbyplants/random/dead, +/obj/machinery/light/small/broken/directional/east, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "rYq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -59115,42 +60458,16 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmos/project) -"rZK" = ( -/obj/structure/flora/bush/snow/style_random, -/obj/effect/mapping_helpers/airalarm/tlv_cold_room, -/obj/machinery/airalarm/directional/west, -/turf/open/misc/asteroid/snow/coldroom, -/area/station/service/kitchen/coldroom) -"rZN" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +"rZP" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/stone, +/area/station/commons/lounge) "rZR" = ( /obj/effect/turf_decal/trimline/blue/filled/line, /obj/effect/landmark/start/chief_medical_officer, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/cmo) -"rZT" = ( -/obj/structure/fireplace{ - dir = 4; - pixel_y = -15 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/turf/open/floor/stone, -/area/station/commons/lounge) -"rZX" = ( -/obj/machinery/light/small/directional/east, -/obj/structure/rack, -/obj/item/pickaxe, -/turf/open/floor/plating, -/area/station/medical/morgue) "rZZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/trimline/blue/filled/warning{ @@ -59251,14 +60568,6 @@ /obj/effect/turf_decal/tile/green/anticorner/contrasted, /turf/open/floor/iron/dark, /area/mine/laborcamp) -"sbT" = ( -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/machinery/light/directional/west, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "sbU" = ( /obj/machinery/vending/cigarette, /turf/open/floor/iron/dark, @@ -59301,6 +60610,14 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"scr" = ( +/obj/machinery/hydroponics/constructable, +/obj/effect/turf_decal/trimline/green/filled/line, +/obj/effect/turf_decal/trimline/blue/filled/warning, +/obj/structure/sign/warning/gas_mask/directional/south, +/obj/machinery/light/warm/directional/south, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "scu" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -59321,6 +60638,14 @@ /obj/machinery/airalarm/directional/south, /turf/open/floor/iron, /area/station/tcommsat/computer) +"scG" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/sink/directional/south, +/obj/structure/mirror/directional/north, +/obj/structure/cable, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "scQ" = ( /obj/structure/tank_holder/oxygen, /obj/effect/decal/cleanable/wrapping, @@ -59390,6 +60715,10 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) +"sed" = ( +/obj/structure/flora/rock/icy/style_random, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/explored) "sen" = ( /obj/structure/cable, /turf/open/floor/iron, @@ -59399,6 +60728,17 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/security/courtroom) +"seB" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 8 + }, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/commons/fitness) "seH" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -59443,6 +60783,12 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron/large, /area/station/hallway/secondary/entry) +"sft" = ( +/obj/machinery/holopad, +/obj/effect/spawner/random/engineering/tracking_beacon, +/obj/effect/turf_decal/bot_white, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "sfv" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/general/visible, @@ -59479,17 +60825,12 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) -"sfA" = ( -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/start/hangover, -/obj/effect/turf_decal/tile/neutral/half/contrasted, -/turf/open/floor/iron, -/area/station/commons/fitness) +"sfD" = ( +/obj/machinery/airalarm/directional/north, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "sfY" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -59501,6 +60842,12 @@ dir = 5 }, /area/station/science/research) +"sgz" = ( +/obj/effect/turf_decal/siding/wood/corner{ + dir = 1 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "sgA" = ( /obj/effect/turf_decal/box, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -59588,12 +60935,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"shD" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/turf/open/floor/stone, -/area/station/commons/lounge) "shG" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -59615,17 +60956,6 @@ dir = 8 }, /area/station/hallway/secondary/entry) -"sib" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/multiz/supply/visible/layer4{ - color = "#0000ff"; - dir = 8; - name = "Supply multi deck pipe adapter" - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "sil" = ( /obj/machinery/door/airlock/public/glass{ name = "Art Gallery" @@ -59705,13 +61035,6 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron/smooth_large, /area/station/cargo/drone_bay) -"sjL" = ( -/obj/effect/landmark/generic_maintenance_landmark, -/obj/item/bikehorn/rubberducky, -/obj/structure/cable, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "sjU" = ( /obj/structure/sign/warning/docking/directional/east, /turf/open/floor/plating/snowed/smoothed/icemoon, @@ -59737,12 +61060,6 @@ /obj/effect/mapping_helpers/airlock/cyclelink_helper, /turf/open/floor/plating, /area/station/hallway/secondary/entry) -"skf" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "skj" = ( /obj/structure/table, /obj/machinery/light/directional/east, @@ -59766,16 +61083,6 @@ }, /turf/open/floor/iron/dark/corner, /area/station/engineering/atmos/storage/gas) -"skp" = ( -/obj/machinery/smartfridge/food, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 1; - id = "kitchencounter"; - name = "Kitchen Counter Shutters" - }, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "skw" = ( /obj/machinery/computer/security/qm, /obj/machinery/requests_console/directional/west{ @@ -59797,11 +61104,32 @@ /obj/machinery/atmospherics/pipe/bridge_pipe/yellow/visible, /turf/open/floor/iron, /area/station/engineering/atmos) +"skH" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/siding/white/corner{ + dir = 4 + }, +/obj/machinery/duct, +/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/obj/machinery/door/airlock{ + name = "Kitchen" + }, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/white/textured_half, +/area/station/service/kitchen) "skJ" = ( /obj/structure/grille/broken, /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"skQ" = ( +/obj/structure/window/reinforced/spawner/directional/south, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/siding/white, +/turf/open/floor/iron/dark, +/area/station/commons/fitness) "skU" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -59812,13 +61140,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/virology) -"skV" = ( -/obj/structure/chair/stool/bar/directional/south, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/turf/open/floor/stone, -/area/station/commons/lounge) "skW" = ( /obj/machinery/door/airlock/maintenance, /obj/effect/mapping_helpers/airlock/abandoned, @@ -60050,6 +61371,15 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"snR" = ( +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "snW" = ( /obj/machinery/computer/atmos_control/oxygen_tank{ dir = 1 @@ -60067,11 +61397,6 @@ /obj/effect/mapping_helpers/airlock/access/all/security/general, /turf/open/floor/iron/dark, /area/station/security/checkpoint/engineering) -"son" = ( -/obj/effect/turf_decal/siding/white, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "sou" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -60154,6 +61479,14 @@ }, /turf/open/floor/iron/dark, /area/station/science/genetics) +"spj" = ( +/obj/effect/turf_decal/tile/neutral/diagonal_edge, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 1 + }, +/obj/effect/landmark/start/cook, +/turf/open/floor/iron/kitchen/diagonal, +/area/station/service/kitchen) "spv" = ( /obj/structure/window/reinforced/plasma/spawner/directional/east, /obj/structure/cable, @@ -60231,6 +61564,17 @@ dir = 8 }, /area/station/service/chapel) +"sqH" = ( +/obj/machinery/door/airlock/research/glass/incinerator/ordmix_interior{ + name = "Burn Chamber Interior Airlock" + }, +/obj/effect/mapping_helpers/airlock/locked, +/obj/machinery/airlock_controller/incinerator_ordmix{ + pixel_x = 24 + }, +/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, +/turf/open/floor/engine, +/area/station/science/ordnance) "sqN" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -60325,6 +61669,15 @@ "srP" = ( /turf/closed/wall, /area/station/science/breakroom) +"srU" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/junction{ + dir = 2 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "srW" = ( /obj/structure/table, /obj/item/assembly/prox_sensor{ @@ -60374,6 +61727,13 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) +"ssm" = ( +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/closet/firecloset, +/obj/structure/sign/warning/gas_mask/directional/west, +/obj/effect/turf_decal/siding/white, +/turf/open/floor/plating, +/area/station/service/kitchen/coldroom) "ssq" = ( /obj/structure/table/wood, /obj/item/camera_film, @@ -60384,6 +61744,10 @@ /obj/structure/sign/warning/secure_area, /turf/closed/wall/r_wall, /area/station/engineering/storage/tech) +"ssu" = ( +/obj/structure/gulag_vent/ice, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "ssv" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/effect/turf_decal/siding/thinplating_new/corner, @@ -60441,12 +61805,6 @@ }, /turf/open/floor/iron, /area/station/commons/vacant_room/commissary) -"stp" = ( -/obj/structure/chair/sofa/bench/right{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) "stt" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -60456,15 +61814,6 @@ dir = 1 }, /area/station/security/lockers) -"stw" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/machinery/disposal/bin, -/obj/structure/disposalpipe/trunk, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "stA" = ( /obj/structure/lattice/catwalk, /obj/structure/railing{ @@ -60472,6 +61821,16 @@ }, /turf/open/lava/plasma/ice_moon, /area/icemoon/underground/explored) +"stB" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/fore) "stD" = ( /obj/machinery/door/poddoor/preopen{ id = "atmos"; @@ -60545,6 +61904,12 @@ /obj/structure/sign/warning/gas_mask, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"sus" = ( +/obj/structure/table, +/obj/effect/spawner/random/maintenance/two, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron/smooth, +/area/station/maintenance/starboard/fore) "suA" = ( /obj/structure/closet/crate/coffin, /obj/effect/decal/cleanable/dirt, @@ -60552,11 +61917,6 @@ /obj/machinery/light/small/dim/directional/north, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"suE" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) "suL" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -60613,6 +61973,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth_large, /area/station/cargo/warehouse) +"svz" = ( +/obj/machinery/light/small/directional/east, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 9 + }, +/turf/open/floor/plating/snowed/icemoon, +/area/icemoon/underground/explored) "svF" = ( /turf/open/floor/iron/smooth, /area/station/security/execution/transfer) @@ -60788,15 +62155,6 @@ /obj/structure/cable, /turf/open/floor/wood, /area/station/security/prison/rec) -"sxW" = ( -/obj/structure/chair/wood{ - dir = 8 - }, -/obj/machinery/light/small/directional/east, -/obj/machinery/computer/security/telescreen/entertainment/directional/north, -/obj/structure/sign/poster/random/directional/east, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "sxY" = ( /obj/structure/cable/multilayer/multiz, /obj/structure/window/reinforced/spawner/directional/south, @@ -60810,6 +62168,14 @@ /obj/machinery/firealarm/directional/west, /turf/open/floor/iron/white, /area/station/science/research) +"syd" = ( +/obj/machinery/duct, +/obj/machinery/firealarm/directional/south, +/obj/effect/turf_decal/tile/bar{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/service/kitchen/coldroom) "syh" = ( /obj/structure/chair/pew/right{ dir = 1 @@ -60876,6 +62242,14 @@ /obj/effect/spawner/structure/window/hollow/reinforced/end, /turf/open/floor/plating, /area/station/medical/morgue) +"szj" = ( +/obj/structure/railing/corner/end/flip{ + dir = 8 + }, +/turf/open/floor/iron/stairs/old{ + dir = 8 + }, +/area/station/hallway/primary/starboard) "szo" = ( /obj/machinery/door/firedoor, /obj/structure/cable, @@ -60885,6 +62259,13 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"szt" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/neutral/half/contrasted, +/obj/structure/sign/clock/directional/south, +/turf/open/floor/iron, +/area/station/commons/fitness) "szu" = ( /obj/structure/sign/poster/official/obey/directional/north, /obj/effect/decal/cleanable/dirt, @@ -60909,6 +62290,14 @@ /obj/structure/sign/warning/cold_temp/directional/north, /turf/open/floor/iron/smooth, /area/station/cargo/warehouse) +"szK" = ( +/obj/machinery/power/apc/auto_name/directional/east, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "szR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -60933,15 +62322,6 @@ }, /turf/open/floor/iron, /area/mine/eva/lower) -"sAc" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "sAj" = ( /obj/machinery/photocopier, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -61036,6 +62416,14 @@ }, /turf/open/floor/iron/white/corner, /area/station/hallway/secondary/exit/departure_lounge) +"sBY" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/spawner/random/trash/crushed_can{ + pixel_y = 10 + }, +/turf/open/floor/iron, +/area/station/service/bar) "sCa" = ( /obj/effect/turf_decal/siding/wideplating/dark{ dir = 5 @@ -61094,6 +62482,11 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"sCX" = ( +/obj/effect/turf_decal/siding/wood/corner, +/obj/machinery/newscaster/directional/west, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "sCZ" = ( /turf/open/floor/iron/dark, /area/station/service/hydroponics) @@ -61118,17 +62511,14 @@ /obj/machinery/light/small/dim/directional/north, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"sDs" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 +"sDM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/obj/structure/cable/multilayer/multiz, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/grille_or_waste, /turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) -"sDA" = ( -/obj/machinery/igniter/incinerator_ordmix, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance/burnchamber) +/area/station/maintenance/starboard/fore) "sDQ" = ( /obj/item/radio/intercom/prison/directional/north, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -61168,19 +62558,16 @@ }, /turf/open/floor/wood, /area/station/command/meeting_room) -"sEp" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "sEq" = ( /obj/effect/spawner/structure/window/hollow/reinforced/end{ dir = 8 }, /turf/open/floor/plating, /area/mine/living_quarters) +"sEv" = ( +/obj/item/flashlight/lantern/on, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "sEz" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -61210,13 +62597,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/starboard/upper) -"sEE" = ( -/obj/structure/cable, -/obj/structure/disposalpipe/junction{ - dir = 2 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "sEF" = ( /obj/machinery/computer/atmos_control/plasma_tank{ dir = 8 @@ -61338,17 +62718,25 @@ }, /turf/open/floor/iron/dark, /area/station/medical/morgue) -"sGi" = ( -/obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/table/wood, -/obj/item/food/pie/cream, -/turf/open/floor/carpet, -/area/station/service/theater) "sGk" = ( /obj/effect/turf_decal/trimline/yellow/filled/line, /obj/structure/sign/poster/random/directional/south, /turf/open/floor/iron/white, /area/station/medical/chemistry) +"sGn" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "sGp" = ( /obj/effect/turf_decal/tile/red{ dir = 4 @@ -61438,15 +62826,24 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/carpet, /area/station/service/chapel) +"sHi" = ( +/obj/effect/turf_decal/siding/dark{ + dir = 6 + }, +/turf/open/floor/iron/checker, +/area/station/hallway/secondary/service) "sHl" = ( /obj/machinery/vending/coffee, /obj/item/radio/intercom/directional/south, /turf/open/floor/stone, /area/mine/eva/lower) -"sHB" = ( -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) +"sHs" = ( +/obj/effect/turf_decal/tile/neutral/diagonal_edge, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/kitchen/diagonal, +/area/station/service/kitchen) "sHC" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -61499,18 +62896,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) -"sIh" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 8 - }, -/obj/structure/flora/bush/flowers_yw/style_random, -/turf/open/floor/grass, -/area/station/service/hydroponics) -"sIm" = ( -/obj/machinery/hydroponics/soil, -/turf/open/floor/grass, -/area/station/service/hydroponics) "sIp" = ( /obj/structure/closet/radiation, /obj/effect/turf_decal/tile/yellow/half/contrasted{ @@ -61560,26 +62945,31 @@ /obj/structure/cable, /turf/open/floor/plating, /area/mine/storage) +"sIX" = ( +/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, +/obj/machinery/door/airlock/hydroponics/glass{ + name = "Garden" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/turf/open/floor/iron/textured, +/area/station/service/hydroponics) "sJe" = ( /obj/machinery/deepfryer, /obj/machinery/light/warm/directional/north, /turf/open/floor/iron/cafeteria, /area/station/security/prison/mess) +"sJg" = ( +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "sJi" = ( /obj/machinery/vending/donksofttoyvendor, /turf/open/floor/iron/dark/textured, /area/station/security/prison/safe) -"sJk" = ( -/obj/structure/cable, -/obj/machinery/camera/directional/west{ - c_tag = "Dormitory South" - }, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 - }, -/obj/machinery/light/directional/west, -/turf/open/floor/iron, -/area/station/commons/dorms) "sJn" = ( /obj/structure/closet/emcloset, /obj/structure/sign/warning/gas_mask/directional/west, @@ -61613,6 +63003,21 @@ }, /turf/open/floor/plating/icemoon, /area/station/security/execution/education) +"sJu" = ( +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/graffiti{ + pixel_y = 32 + }, +/obj/effect/mapping_helpers/burnt_floor, +/obj/machinery/light/small/dim/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "sJA" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -61719,6 +63124,25 @@ }, /turf/open/floor/iron/dark/corner, /area/station/security/processing) +"sLm" = ( +/obj/structure/chair/sofa/left/brown{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 1 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) +"sLy" = ( +/obj/structure/table, +/obj/item/reagent_containers/cup/bowl{ + pixel_y = 5 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "sLD" = ( /obj/structure/table/reinforced, /obj/item/stack/sheet/iron/fifty, @@ -61897,6 +63321,11 @@ }, /turf/open/floor/iron, /area/station/cargo/office) +"sON" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "sOO" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, @@ -61907,6 +63336,12 @@ /obj/item/kitchen/fork/plastic, /turf/open/floor/iron, /area/station/security/prison/mess) +"sOX" = ( +/obj/machinery/light/small/directional/west, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/power/port_gen/pacman, +/turf/open/floor/iron/smooth, +/area/station/maintenance/starboard/lesser) "sOY" = ( /obj/structure/table/glass, /obj/item/hemostat, @@ -61945,6 +63380,13 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/security/warden) +"sPS" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/machinery/firealarm/directional/west, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "sPV" = ( /obj/machinery/door/airlock/atmos/glass, /obj/machinery/door/firedoor/heavy, @@ -61993,6 +63435,25 @@ /obj/item/radio/intercom/directional/west, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"sRc" = ( +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/obj/effect/turf_decal/siding/white{ + dir = 10 + }, +/turf/open/floor/iron/dark, +/area/station/commons/fitness) +"sRf" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/power/apc/auto_name/directional/south, +/obj/structure/cable, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "sRp" = ( /obj/structure/fence, /obj/effect/turf_decal/weather/snow/corner{ @@ -62024,14 +63485,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/central) -"sSh" = ( -/obj/effect/turf_decal/siding/white{ - dir = 6 - }, -/obj/item/kirbyplants/random, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "sSj" = ( /obj/machinery/light/small/directional/south, /obj/structure/chair/sofa/left/brown{ @@ -62211,13 +63664,6 @@ /obj/structure/cable, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) -"sUO" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/junction/flip, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "sUS" = ( /obj/structure/table/wood, /obj/effect/mapping_helpers/broken_floor, @@ -62306,13 +63752,15 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/mining_station, /turf/open/floor/iron/textured_half, /area/mine/production) -"sWC" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +"sWS" = ( +/obj/structure/railing, +/obj/effect/turf_decal/siding/white, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/theater) +/obj/structure/curtain/cloth/fancy/mechanical/start_closed{ + id = "cantena_curtains" + }, +/turf/open/floor/wood, +/area/station/commons/lounge) "sWU" = ( /obj/structure/chair/stool/directional/south, /turf/open/floor/iron, @@ -62405,11 +63853,15 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/mix) -"sYb" = ( -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted, -/turf/open/floor/iron, -/area/station/commons/dorms) +"sXU" = ( +/obj/structure/table/wood/poker, +/obj/item/toy/cards/deck{ + pixel_y = 13; + pixel_x = 6 + }, +/obj/effect/spawner/random/entertainment/cigarette, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "sYe" = ( /obj/structure/table/wood, /obj/item/clothing/under/suit/red, @@ -62569,16 +64021,35 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) +"tbd" = ( +/obj/item/radio/intercom/directional/south, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark/smooth_half, +/area/station/service/hydroponics) "tbh" = ( /turf/open/floor/iron/half{ dir = 1 }, /area/station/engineering/atmos) -"tbv" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/flora/bush/sunny/style_random, -/turf/open/floor/grass, -/area/station/service/hydroponics) +"tbE" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/effect/landmark/start/bartender, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/service/bar) +"tbK" = ( +/obj/effect/spawner/random/trash/grille_or_waste, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "tbN" = ( /obj/effect/mapping_helpers/airlock/access/any/supply/maintenance, /obj/machinery/door/airlock/engineering{ @@ -62693,6 +64164,15 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/service/chapel) +"tec" = ( +/obj/effect/spawner/structure/window, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "botany_apiary"; + name = "Apiary Shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) "ted" = ( /obj/machinery/holopad, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -62702,10 +64182,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/central) -"tef" = ( -/obj/machinery/space_heater, -/turf/open/floor/plating, -/area/station/maintenance/fore) "tei" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/carpet/red, @@ -62714,6 +64190,13 @@ /obj/structure/fence, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) +"tes" = ( +/obj/effect/spawner/random/trash/graffiti{ + pixel_y = -30 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "teE" = ( /obj/effect/spawner/structure/window, /obj/machinery/door/poddoor/shutters{ @@ -62734,12 +64217,6 @@ dir = 4 }, /area/station/security/brig/entrance) -"teR" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/service/theater) "teZ" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -62910,6 +64387,20 @@ dir = 10 }, /area/station/science/lab) +"tie" = ( +/obj/structure/rack, +/obj/item/clothing/suit/utility/beekeeper_suit, +/obj/item/clothing/head/utility/beekeeper_head, +/obj/item/melee/flyswatter, +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning/corner{ + dir = 4 + }, +/obj/machinery/firealarm/directional/north, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "til" = ( /obj/item/radio/intercom/directional/west, /obj/effect/decal/cleanable/dirt, @@ -62920,6 +64411,22 @@ dir = 8 }, /area/mine/eva) +"tip" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Fitness" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/stripes/white/line{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/white/line{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/commons/fitness) "tis" = ( /obj/structure/window/reinforced/fulltile, /obj/structure/transit_tube/horizontal, @@ -62929,22 +64436,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"tiF" = ( -/obj/structure/chair/stool/directional/west, -/turf/open/floor/carpet, -/area/station/service/theater) "tiV" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 }, /turf/open/floor/iron, /area/station/service/chapel) -"tiX" = ( -/obj/effect/turf_decal/siding/wood, -/obj/structure/cable, -/obj/effect/landmark/event_spawn, -/turf/open/floor/iron, -/area/station/service/theater) "tiY" = ( /obj/machinery/light/small/directional/west, /obj/effect/turf_decal/weather/snow/corner{ @@ -62984,6 +64481,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) +"tjA" = ( +/obj/machinery/smartfridge, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "tjC" = ( /obj/machinery/airalarm/directional/south, /obj/effect/turf_decal/tile/red/half/contrasted, @@ -63027,10 +64528,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/treatment_center) -"tki" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "tku" = ( /obj/machinery/door/firedoor, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -63061,14 +64558,16 @@ "tkU" = ( /turf/open/lava/plasma/ice_moon, /area/icemoon/surface/outdoors/nospawn) -"tkV" = ( -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ +"tkY" = ( +/obj/structure/cable, +/obj/effect/turf_decal/weather/snow/corner{ dir = 4 }, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) +/obj/structure/minecart_rail{ + dir = 1 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "tlh" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -63091,12 +64590,6 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/ai_monitored/command/storage/eva) -"tlr" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "tlA" = ( /obj/machinery/light/small/directional/south, /obj/item/radio/intercom/directional/south, @@ -63106,15 +64599,6 @@ "tlE" = ( /turf/open/floor/glass/reinforced/icemoon, /area/icemoon/surface/outdoors/nospawn) -"tlF" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "tlH" = ( /turf/open/openspace/icemoon, /area/icemoon/surface/outdoors/nospawn) @@ -63158,6 +64642,10 @@ }, /turf/open/floor/iron/dark/textured, /area/station/hallway/secondary/entry) +"tmb" = ( +/obj/structure/stairs/west, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "tml" = ( /obj/structure/grille, /turf/open/floor/plating, @@ -63238,17 +64726,17 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"tnB" = ( -/obj/machinery/door/airlock{ - name = "Theater Backstage" +"tnz" = ( +/obj/structure/table, +/obj/item/plate, +/obj/item/food/piedough, +/obj/effect/spawner/random/food_or_drink/cake_ingredients, +/obj/effect/turf_decal/siding/white{ + dir = 9 }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/duct, -/obj/effect/mapping_helpers/airlock/access/all/service/theatre, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) +/obj/item/kitchen/rollingpin, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "tnI" = ( /obj/effect/turf_decal/trimline/dark_blue/line{ dir = 10 @@ -63256,6 +64744,14 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/mix) +"tnJ" = ( +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 4 + }, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "tnO" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, @@ -63291,21 +64787,17 @@ /obj/machinery/shower/directional/west, /turf/open/floor/iron/white, /area/station/medical/virology) -"toH" = ( -/obj/structure/railing{ - dir = 8 - }, -/obj/machinery/door/firedoor/border_only{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue{ +"toT" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/machinery/status_display/evac/directional/west, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/stripes/white/line{ dir = 1 }, -/obj/effect/turf_decal/tile/green{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/central) "toV" = ( /obj/structure/table, /obj/item/stock_parts/subspace/ansible, @@ -63372,6 +64864,14 @@ /obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/iron/white/textured, /area/station/security/medical) +"tpZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/poster/contraband/random/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "tqk" = ( /obj/structure/table, /obj/item/paper_bin{ @@ -63382,6 +64882,13 @@ /obj/item/key/janitor, /turf/open/floor/iron, /area/station/service/janitor) +"tqr" = ( +/obj/effect/turf_decal/trimline/green/filled/line, +/obj/effect/turf_decal/trimline/blue/filled/warning, +/obj/machinery/hydroponics/constructable, +/obj/machinery/status_display/ai/directional/south, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "tqQ" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -63394,11 +64901,6 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) -"tqZ" = ( -/obj/machinery/door/firedoor, -/obj/machinery/biogenerator, -/turf/open/floor/iron, -/area/station/service/hydroponics) "trb" = ( /obj/structure/table, /obj/machinery/computer/security/telescreen{ @@ -63417,10 +64919,6 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, /area/station/maintenance/disposal) -"trl" = ( -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "trm" = ( /turf/open/floor/plating, /area/station/science/ordnance/testlab) @@ -63474,6 +64972,16 @@ /obj/machinery/rnd/server/master, /turf/open/openspace/icemoon, /area/station/science/server) +"tsu" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/light/floor, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "tsH" = ( /obj/machinery/door/airlock/security/glass{ name = "Interrogation" @@ -63510,7 +65018,6 @@ /turf/open/floor/iron/dark, /area/station/commons/storage/mining) "tsR" = ( -/obj/structure/cable, /obj/structure/chair/stool/directional/south, /obj/effect/decal/cleanable/oil/slippery, /turf/open/floor/plating, @@ -63526,6 +65033,14 @@ /obj/machinery/door/airlock/freezer, /turf/open/floor/iron/showroomfloor, /area/station/security/prison/mess) +"tts" = ( +/obj/item/chair/wood, +/obj/item/toy/plush/moth{ + name = "Ariadne" + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "ttv" = ( /obj/structure/sign/painting/library{ pixel_y = 32 @@ -63604,13 +65119,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"tux" = ( -/obj/structure/railing/corner, -/obj/machinery/door/firedoor/border_only{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "tuz" = ( /obj/structure/cable, /obj/structure/table, @@ -63685,11 +65193,6 @@ dir = 1 }, /area/station/engineering/engine_smes) -"tvI" = ( -/obj/structure/chair/sofa/corp/right, -/obj/machinery/light/directional/north, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "tvJ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -63768,6 +65271,17 @@ /obj/structure/cable, /turf/open/floor/iron/showroomfloor, /area/station/security/warden) +"twS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/freezer{ + desc = "The freezer where the chef keeps all the stuff that needs to be kept cold. Ice cold."; + name = "The Ice Box" + }, +/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/turf/open/floor/plating, +/area/station/service/kitchen/coldroom) "twU" = ( /obj/effect/landmark/start/hangover, /turf/open/floor/iron/freezer, @@ -63779,16 +65293,6 @@ }, /turf/open/floor/iron/dark, /area/mine/laborcamp) -"twX" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/sorting/mail/flip{ - dir = 8 - }, -/obj/effect/mapping_helpers/mail_sorting/service/kitchen, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "twZ" = ( /obj/structure/table, /obj/effect/spawner/random/maintenance, @@ -63836,6 +65340,17 @@ /obj/machinery/firealarm/directional/south, /turf/open/floor/plating, /area/station/medical/treatment_center) +"txv" = ( +/obj/effect/turf_decal/siding/white{ + dir = 1 + }, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/machinery/vending/hydronutrients, +/turf/open/floor/iron, +/area/station/service/hydroponics) "txE" = ( /obj/item/cigbutt, /obj/effect/decal/cleanable/dirt, @@ -63867,18 +65382,6 @@ /obj/machinery/light/floor, /turf/open/floor/carpet, /area/station/service/chapel) -"tyj" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/structure/chair/sofa/left/brown{ - desc = "Hey, did you know you can get a pineapple on your burger here?"; - dir = 1; - name = "The Regular's Sofa" - }, -/obj/machinery/barsign/all_access/directional/south, -/turf/open/floor/stone, -/area/station/commons/lounge) "tyl" = ( /obj/structure/ladder, /obj/machinery/light/small/directional/north, @@ -63906,10 +65409,6 @@ }, /turf/open/floor/glass/reinforced, /area/station/engineering/atmos/pumproom) -"tza" = ( -/obj/structure/sink/directional/east, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "tzf" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -63944,18 +65443,6 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/wood, /area/station/commons/vacant_room/office) -"tAe" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/machinery/chem_dispenser/drinks{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/duct, -/obj/structure/table/wood, -/turf/open/floor/stone, -/area/station/service/bar) "tAg" = ( /obj/effect/turf_decal/trimline/green/filled/corner{ dir = 1 @@ -63972,6 +65459,11 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, /turf/open/floor/plating, /area/station/commons/storage/mining) +"tAt" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/fore) "tAx" = ( /obj/effect/turf_decal/trimline/blue/filled/warning, /obj/structure/disposalpipe/segment, @@ -64017,11 +65509,6 @@ /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron, /area/station/engineering/atmos) -"tBN" = ( -/obj/structure/table, -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron/smooth, -/area/station/maintenance/starboard/fore) "tBP" = ( /obj/machinery/light/small/directional/west, /obj/structure/sign/warning/secure_area/directional/west, @@ -64067,12 +65554,6 @@ /obj/structure/grille, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) -"tCs" = ( -/obj/structure/table, -/obj/item/book/manual/hydroponics_pod_people, -/obj/item/watertank, -/turf/open/floor/iron, -/area/station/service/hydroponics) "tCu" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, @@ -64101,6 +65582,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/mix) +"tCG" = ( +/obj/effect/turf_decal/loading_area{ + dir = 1 + }, +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "tCL" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -64121,14 +65609,6 @@ }, /turf/open/floor/plating, /area/station/security/interrogation) -"tCT" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 9 - }, -/obj/structure/table/wood, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "tCV" = ( /obj/machinery/camera/directional/west{ c_tag = "Security - Permabrig Observation Prep"; @@ -64176,13 +65656,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/security/brig/upper) -"tDv" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/structure/sign/poster/official/random/directional/north, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "tDw" = ( /obj/machinery/suit_storage_unit/hos, /obj/structure/reagent_dispensers/wall/peppertank/directional/west, @@ -64240,16 +65713,6 @@ /obj/effect/turf_decal/tile/blue/half/contrasted, /turf/open/floor/iron, /area/station/hallway/primary/central) -"tEf" = ( -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/landmark/event_spawn, -/turf/open/floor/carpet, -/area/station/service/theater) "tEi" = ( /obj/structure/sink/directional/south, /turf/open/floor/iron, @@ -64264,6 +65727,22 @@ }, /turf/open/floor/plating, /area/station/cargo/storage) +"tEs" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/public/glass{ + name = "Holodeck Door" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "holodeck" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/iron/textured, +/area/station/commons/fitness) "tEu" = ( /obj/structure/table, /obj/item/hand_labeler, @@ -64325,13 +65804,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) -"tFf" = ( -/obj/structure/chair/plastic{ - dir = 0 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/maintenance/starboard/fore) "tFs" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -64427,9 +65899,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/laborcamp) -"tGZ" = ( -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "tHe" = ( /obj/structure/bodycontainer/morgue{ dir = 8 @@ -64468,6 +65937,13 @@ dir = 8 }, /area/station/hallway/secondary/entry) +"tHF" = ( +/obj/structure/sign/nanotrasen, +/obj/structure/fence/post{ + dir = 8 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "tHK" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/structure/railing{ @@ -64558,6 +66034,13 @@ /obj/machinery/status_display/evac/directional/south, /turf/open/floor/iron/dark, /area/station/service/chapel) +"tIL" = ( +/obj/structure/table, +/obj/machinery/light/small/directional/west, +/obj/structure/disposalpipe/segment, +/obj/effect/spawner/random/engineering/material_cheap, +/turf/open/floor/iron/smooth, +/area/station/maintenance/starboard/fore) "tIS" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 6 @@ -64575,13 +66058,6 @@ /obj/effect/spawner/random/structure/steam_vent, /turf/open/floor/plating, /area/station/maintenance/starboard/upper) -"tJb" = ( -/obj/effect/turf_decal/siding/thinplating{ - dir = 4 - }, -/obj/machinery/light/small/directional/north, -/turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/underground/explored) "tJi" = ( /obj/structure/bookcase{ name = "Holy Bookcase" @@ -64649,11 +66125,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark/smooth_half, /area/station/security/office) -"tJP" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/solars/starboard/fore) "tJR" = ( /obj/structure/rack, /obj/item/tank/internals/oxygen, @@ -64672,6 +66143,19 @@ dir = 4 }, /area/station/medical/chem_storage) +"tJZ" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/machinery/door/firedoor, +/obj/effect/landmark/event_spawn, +/obj/effect/turf_decal/stripes/white/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/white/line, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured, +/area/station/hallway/primary/fore) "tKf" = ( /obj/structure/closet, /obj/machinery/light/small/directional/north, @@ -64853,6 +66337,15 @@ /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"tNb" = ( +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/structure/railing/corner/end/flip{ + dir = 8 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "tNd" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /obj/effect/turf_decal/siding/green{ @@ -64885,22 +66378,6 @@ /obj/machinery/light/floor, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"tNA" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/external{ - glass = 1; - name = "Chapel Maintenance External Airlock"; - opacity = 0 - }, -/obj/structure/sign/warning/cold_temp/directional/north, -/obj/structure/sign/warning/gas_mask/directional/south{ - desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." - }, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, -/turf/open/floor/plating, -/area/station/maintenance/department/chapel) "tND" = ( /obj/effect/turf_decal/stripes/asteroid/corner{ dir = 4 @@ -64912,6 +66389,13 @@ dir = 10 }, /area/mine/living_quarters) +"tNH" = ( +/obj/structure/railing, +/obj/effect/turf_decal/siding/thinplating_new/light{ + dir = 6 + }, +/turf/open/floor/wood/large, +/area/station/hallway/primary/starboard) "tNJ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -64921,6 +66405,10 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/cargo/lobby) +"tOe" = ( +/obj/effect/spawner/random/structure/closet_maintenance, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "tOf" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -64959,6 +66447,11 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/mix) +"tOC" = ( +/obj/effect/spawner/random/trash/hobo_squat, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "tOF" = ( /obj/structure/chair/comfy/black{ dir = 8 @@ -65077,19 +66570,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/aft/lesser) -"tRA" = ( -/obj/machinery/door/airlock{ - name = "Bar" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/all/service/bar, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "tRX" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 8 @@ -65103,6 +66583,15 @@ /obj/effect/turf_decal/siding/yellow, /turf/open/floor/iron, /area/station/engineering/atmos/storage/gas) +"tSd" = ( +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/obj/effect/mapping_helpers/airlock/access/any/security/general, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/turf/open/floor/plating, +/area/station/maintenance/fore) "tSi" = ( /obj/machinery/suit_storage_unit/security, /turf/open/floor/iron/smooth, @@ -65135,6 +66624,13 @@ /obj/structure/sign/warning/no_smoking/directional/west, /turf/open/floor/iron/white, /area/station/medical/pharmacy) +"tSO" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/spawner/structure/window/reinforced/tinted, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "tTc" = ( /obj/item/storage/bag/plants/portaseeder, /obj/structure/table/glass, @@ -65176,6 +66672,24 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/space_hut/cabin) +"tUm" = ( +/obj/machinery/door/window/left/directional/west{ + req_one_access = list("bar", "kitchen"); + name = "Deliveries" + }, +/obj/effect/turf_decal/loading_area{ + dir = 8 + }, +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/textured, +/area/station/service/kitchen/coldroom) "tUn" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -65246,27 +66760,6 @@ /obj/effect/mapping_helpers/airlock/access/all/command/general, /turf/open/floor/iron, /area/station/command/bridge) -"tUS" = ( -/obj/structure/ladder{ - name = "Cold Room Access" - }, -/obj/machinery/door/window/left/directional/north{ - desc = "Get down to the Ice Box using this."; - name = "Freezer Access"; - req_access = list("kitchen") - }, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/stripes{ - dir = 1 - }, -/obj/effect/turf_decal/tile/dark_blue/diagonal_edge, -/obj/effect/turf_decal/stripes/white/line{ - dir = 1 - }, -/obj/structure/sign/warning/cold_temp/directional/south, -/obj/structure/sign/warning/gas_mask/directional/east, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "tUV" = ( /obj/structure/railing{ dir = 8 @@ -65353,15 +66846,6 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/dark, /area/mine/mechbay) -"tWD" = ( -/obj/machinery/microwave{ - desc = "Turn it on and you'll immediately get warmer! Warranty void if left in weather conditions."; - name = "Emergency Heating Appliance"; - pixel_y = 5 - }, -/obj/structure/table, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "tWK" = ( /obj/structure/cable, /turf/open/floor/plating/snowed/icemoon, @@ -65377,6 +66861,16 @@ /obj/machinery/firealarm/directional/south, /turf/open/floor/iron, /area/station/security/prison/work) +"tWY" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/obj/machinery/door/airlock/maintenance{ + name = "Kitchen Maintenance" + }, +/turf/open/floor/plating, +/area/station/service/kitchen/coldroom) "tWZ" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 1 @@ -65400,6 +66894,11 @@ }, /turf/open/floor/iron, /area/station/security/prison/garden) +"tXg" = ( +/obj/machinery/airalarm/directional/north, +/obj/machinery/light/directional/north, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "tXh" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -65505,6 +67004,16 @@ /obj/effect/turf_decal/trimline/blue/filled/line, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"tZo" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "tZp" = ( /obj/structure/ladder, /turf/open/floor/plating/snowed/icemoon, @@ -65551,16 +67060,6 @@ /obj/effect/mapping_helpers/airlock/access/all/command/ai_upload, /turf/open/floor/iron/dark/textured_large, /area/station/ai_monitored/turret_protected/ai_upload) -"uac" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 5 - }, -/obj/machinery/disposal/bin, -/obj/structure/disposalpipe/trunk{ - dir = 1 - }, -/turf/open/floor/stone, -/area/station/commons/lounge) "uah" = ( /obj/machinery/light_switch/directional/west, /obj/structure/cable, @@ -65624,9 +67123,8 @@ }, /turf/open/floor/iron/dark, /area/station/security/checkpoint/science) -"ubd" = ( -/obj/machinery/light/small/directional/east, -/turf/open/floor/plating/snowed/smoothed/icemoon, +"ubi" = ( +/turf/open/misc/asteroid/snow/coldroom, /area/icemoon/underground/explored) "ubk" = ( /obj/structure/cable, @@ -65650,6 +67148,10 @@ }, /turf/open/floor/iron/textured, /area/station/security/brig) +"ubp" = ( +/obj/effect/spawner/random/structure/grille, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "ubq" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/white, @@ -65690,6 +67192,15 @@ /obj/effect/turf_decal/stripes/box, /turf/open/floor/iron/dark/textured_large, /area/station/medical/chemistry) +"ubK" = ( +/obj/machinery/computer/holodeck{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/commons/fitness) "ubY" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -65734,6 +67245,20 @@ /obj/structure/sign/warning/electric_shock, /turf/closed/wall/r_wall, /area/station/engineering/supermatter) +"udf" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/door/airlock/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "udj" = ( /obj/effect/turf_decal/stripes/asteroid/line, /obj/structure/cable, @@ -65750,6 +67275,16 @@ /obj/effect/landmark/start/hangover/closet, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) +"udA" = ( +/obj/structure/training_machine, +/obj/item/target, +/obj/machinery/light/directional/south, +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 4 + }, +/obj/item/radio/intercom/directional/south, +/turf/open/floor/iron, +/area/station/commons/fitness) "udK" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 1 @@ -65779,6 +67314,13 @@ dir = 1 }, /area/station/command/heads_quarters/rd) +"udR" = ( +/obj/structure/cable, +/obj/structure/minecart_rail{ + dir = 1 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "uee" = ( /obj/structure/cable, /turf/open/floor/iron, @@ -65959,10 +67501,6 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/maintenance/disposal) -"uhk" = ( -/obj/structure/beebox, -/turf/open/floor/grass, -/area/station/service/hydroponics) "uhs" = ( /obj/structure/railing/corner, /obj/machinery/camera/directional/south{ @@ -66041,6 +67579,17 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/cargo/drone_bay) +"uil" = ( +/obj/effect/landmark/event_spawn, +/obj/machinery/duct, +/obj/effect/turf_decal/siding/dark{ + dir = 5 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/turf/open/floor/iron/checker, +/area/station/hallway/secondary/service) "uin" = ( /obj/structure/sign/warning/fire/directional/south, /obj/effect/turf_decal/stripes/corner{ @@ -66052,6 +67601,12 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos/storage) +"uiq" = ( +/obj/structure/table/wood, +/obj/machinery/chem_dispenser/drinks, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/service/bar) "uiv" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -66059,11 +67614,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) -"uiw" = ( -/obj/machinery/vending/wardrobe/hydro_wardrobe, -/obj/effect/turf_decal/siding/thinplating/dark, -/turf/open/floor/plating, -/area/station/service/hydroponics) "uiF" = ( /obj/structure/cable, /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -66085,6 +67635,15 @@ /obj/structure/sign/warning/secure_area, /turf/closed/wall/r_wall, /area/station/ai_monitored/command/nuke_storage) +"uiV" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/wood/parquet, +/area/station/service/bar/backroom) "uja" = ( /turf/closed/wall, /area/station/commons/toilet) @@ -66149,6 +67708,13 @@ /obj/machinery/door/firedoor, /turf/open/floor/wood, /area/station/command/meeting_room) +"ukt" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "ukv" = ( /obj/machinery/computer/exoscanner_control{ dir = 1 @@ -66159,19 +67725,6 @@ }, /turf/open/floor/iron/dark, /area/station/cargo/drone_bay) -"ukw" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/structure/cable, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "ukz" = ( /obj/machinery/duct, /obj/structure/disposalpipe/segment{ @@ -66268,6 +67821,13 @@ /obj/structure/sign/warning/docking/directional/south, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"umc" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "uml" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -66281,15 +67841,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) -"umv" = ( -/obj/effect/turf_decal/siding/white{ - dir = 9 - }, -/obj/machinery/disposal/bin, -/obj/structure/disposalpipe/trunk, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "umz" = ( /obj/effect/turf_decal/siding/yellow{ dir = 1 @@ -66321,17 +67872,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/cargo/lobby) -"umS" = ( -/obj/structure/extinguisher_cabinet/directional/east, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/structure/cable, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/obj/machinery/light/small/directional/east, -/turf/open/floor/iron, -/area/station/service/bar) "una" = ( /obj/machinery/door/window/left/directional/west, /obj/structure/cable, @@ -66438,13 +67978,6 @@ }, /turf/open/floor/iron/textured, /area/station/engineering/atmos) -"uoz" = ( -/obj/machinery/door/airlock/multi_tile/public/glass{ - name = "Hydroponics" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, -/turf/open/floor/iron/textured_half, -/area/station/service/hydroponics) "uoB" = ( /obj/structure/disposalpipe/junction/yjunction{ dir = 1 @@ -66539,6 +68072,12 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/security/prison) +"upx" = ( +/obj/machinery/light_switch/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "upH" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -66587,13 +68126,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/eva/lower) -"uqB" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/effect/turf_decal/tile/blue/diagonal_edge, -/obj/item/radio/intercom/directional/west, -/obj/machinery/vending/dinnerware, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "uqG" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -66688,11 +68220,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) -"usI" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "usP" = ( /turf/open/misc/asteroid/snow/standard_air, /area/station/science/research) @@ -66710,6 +68237,37 @@ dir = 10 }, /area/station/security/prison/safe) +"utn" = ( +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/structure/table/glass, +/obj/item/seeds/tower, +/obj/item/seeds/chanter{ + pixel_y = 3; + pixel_x = 3 + }, +/obj/item/seeds/watermelon{ + pixel_y = -6; + pixel_x = 3 + }, +/obj/item/seeds/apple{ + pixel_y = 4; + pixel_x = 2 + }, +/obj/item/seeds/banana, +/obj/item/seeds/rose{ + pixel_y = -3; + pixel_x = -4 + }, +/obj/structure/noticeboard/directional/west, +/obj/item/paper/guides/jobs/hydroponics{ + pixel_y = 3; + pixel_x = -27 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "utr" = ( /obj/structure/table, /obj/item/storage/toolbox/mechanical{ @@ -66733,12 +68291,27 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"utG" = ( +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/wood/parquet, +/area/station/service/bar/backroom) "utR" = ( /obj/effect/turf_decal/tile/blue{ dir = 8 }, /turf/open/floor/iron, /area/station/hallway/primary/central) +"utW" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/turf/open/floor/plating, +/area/station/maintenance/fore) "uub" = ( /obj/machinery/atmospherics/components/binary/pump{ name = "Port to Fuel Pipe" @@ -66750,6 +68323,10 @@ /obj/effect/spawner/random/techstorage/tcomms_all, /turf/open/floor/plating, /area/station/engineering/storage/tech) +"uuh" = ( +/obj/structure/noticeboard/directional/north, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "uum" = ( /obj/machinery/door/airlock/public/glass{ name = "Chapel" @@ -66936,6 +68513,10 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/engine/vacuum, /area/station/engineering/atmos) +"uxU" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "uxZ" = ( /obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2, /obj/machinery/atmospherics/pipe/multiz/supply/visible/layer4, @@ -66944,6 +68525,10 @@ }, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) +"uye" = ( +/obj/item/kirbyplants/random/dead, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "uyq" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -66994,11 +68579,6 @@ }, /turf/open/floor/iron, /area/station/commons/dorms/laundry) -"uzc" = ( -/obj/effect/decal/cleanable/food/flour, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "uzd" = ( /obj/structure/rack, /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp{ @@ -67095,31 +68675,12 @@ "uBi" = ( /turf/closed/wall, /area/station/ai_monitored/turret_protected/ai) -"uBn" = ( -/obj/effect/landmark/blobstart, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/turf/open/floor/plating, -/area/station/maintenance/fore) "uBs" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, /turf/open/floor/iron/dark/textured, /area/station/ai_monitored/security/armory) -"uBt" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "uBy" = ( /obj/structure/flora/grass/brown/style_random, /obj/structure/railing{ @@ -67130,6 +68691,17 @@ "uBA" = ( /turf/closed/wall, /area/station/engineering/atmos/project) +"uBD" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/trash/food_packaging, +/obj/effect/spawner/random/trash/cigbutt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "uBL" = ( /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -67334,13 +68906,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on, /turf/open/floor/iron/white, /area/station/medical/virology) -"uDV" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/duct, -/obj/effect/landmark/event_spawn, -/turf/open/floor/iron, -/area/station/service/hydroponics) "uDW" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -67370,12 +68935,6 @@ /obj/structure/closet/crate, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"uEE" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "uEI" = ( /obj/structure/railing/corner{ dir = 4 @@ -67432,27 +68991,17 @@ /obj/machinery/holopad, /turf/open/floor/iron/dark, /area/station/engineering/atmos/storage) -"uFW" = ( -/obj/item/stack/package_wrap{ - pixel_x = 10; - pixel_y = -6 - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/west, +"uGe" = ( +/obj/structure/table/wood, /obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) -"uGa" = ( -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 +/obj/structure/sign/picture_frame/portrait/bar{ + pixel_x = 32 + }, +/obj/structure/displaycase/forsale/kitchen{ + pixel_y = 8 }, /turf/open/floor/iron, -/area/station/commons/dorms) +/area/station/service/bar) "uGl" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -67497,13 +69046,10 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/engineering/main) -"uHa" = ( -/obj/effect/turf_decal/siding/wood, -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/west, -/obj/structure/disposalpipe/segment, -/turf/open/floor/iron, -/area/station/service/theater) +"uGY" = ( +/obj/structure/bookcase, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "uHc" = ( /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 8 @@ -67597,6 +69143,10 @@ /obj/effect/decal/cleanable/glass, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) +"uIS" = ( +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "uIV" = ( /obj/machinery/meter, /obj/effect/turf_decal/delivery, @@ -67648,11 +69198,6 @@ /obj/structure/extinguisher_cabinet/directional/east, /turf/open/floor/iron/white, /area/station/medical/cryo) -"uKr" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "uKx" = ( /obj/structure/closet, /obj/item/clothing/suit/hooded/wintercoat{ @@ -67741,15 +69286,24 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"uLU" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/junction{ +"uLJ" = ( +/obj/machinery/power/apc/auto_name/directional/east, +/obj/structure/cable, +/obj/effect/turf_decal/tile/bar{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) +"uLR" = ( +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "uLX" = ( /obj/machinery/door/airlock{ name = "Port Emergency Storage" @@ -67760,6 +69314,21 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark/textured, /area/station/commons/storage/emergency/port) +"uLZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light/small/dim/directional/north, +/obj/effect/decal/cleanable/vomit/old, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) +"uMj" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/kirbyplants/random/dead, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "uMm" = ( /turf/open/floor/iron/white/corner{ dir = 4 @@ -67775,10 +69344,6 @@ }, /turf/open/floor/iron/dark, /area/mine/storage) -"uMu" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/station/hallway/primary/starboard) "uMx" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk, @@ -67824,6 +69389,15 @@ "uMN" = ( /turf/open/openspace, /area/station/commons/storage/mining) +"uNp" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "uNq" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 1 @@ -67847,21 +69421,18 @@ /obj/item/trash/raisins, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"uNA" = ( -/obj/structure/chair/office{ - dir = 1 - }, -/obj/effect/landmark/start/assistant, -/obj/effect/turf_decal/tile/red/half/contrasted{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) "uNE" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/aisat/hallway) +"uNG" = ( +/obj/machinery/light/small/directional/west, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 5 + }, +/turf/open/floor/plating/snowed/icemoon, +/area/icemoon/underground/explored) "uNV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/siding/wideplating/dark{ @@ -67883,6 +69454,16 @@ "uOb" = ( /turf/closed/wall/r_wall, /area/station/security/prison/toilet) +"uOe" = ( +/obj/machinery/door/window/left/directional/west{ + name = "Fitness Ring" + }, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/effect/turf_decal/siding/white{ + dir = 9 + }, +/turf/open/floor/iron/dark, +/area/station/commons/fitness) "uOf" = ( /obj/machinery/door/airlock{ id_tag = "miningdorm_A"; @@ -67938,20 +69519,20 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/white, /area/station/medical/virology) +"uOy" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/obj/effect/landmark/start/hangover, +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "uOE" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple{ dir = 5 }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) -"uOH" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/machinery/restaurant_portal/restaurant, -/obj/effect/turf_decal/tile/red/full, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "uOL" = ( /obj/effect/turf_decal/tile/yellow{ dir = 4 @@ -67963,16 +69544,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/commons/vacant_room/commissary) -"uOS" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/power/apc/auto_name/directional/north, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "uOW" = ( /obj/effect/turf_decal/trimline/blue/filled/line, /obj/effect/landmark/start/paramedic, @@ -68081,10 +69652,6 @@ }, /turf/open/floor/plating, /area/station/engineering/storage/tech) -"uQY" = ( -/obj/structure/window/reinforced/spawner/directional/east, -/turf/open/floor/carpet, -/area/station/service/theater) "uRi" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -68126,14 +69693,6 @@ dir = 4 }, /area/station/hallway/secondary/entry) -"uRz" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/effect/landmark/start/hangover, -/obj/machinery/light/small/directional/east, -/turf/open/floor/stone, -/area/station/commons/lounge) "uRL" = ( /obj/machinery/airalarm/directional/north, /obj/machinery/light/directional/north, @@ -68183,6 +69742,23 @@ /obj/machinery/meter, /turf/open/floor/iron/dark, /area/station/science/ordnance) +"uSE" = ( +/obj/structure/table/glass, +/obj/machinery/door/window/right/directional/north{ + name = "Hydroponics Desk"; + req_access = list("hydroponics") + }, +/obj/structure/window/reinforced/spawner/directional/east, +/obj/structure/desk_bell{ + pixel_x = 1; + pixel_y = 3 + }, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "uSS" = ( /obj/machinery/recharge_station, /obj/effect/turf_decal/stripes/box, @@ -68197,6 +69773,14 @@ /obj/effect/turf_decal/tile/yellow/full, /turf/open/floor/iron/white/smooth_large, /area/station/medical/pharmacy) +"uTf" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/medical/morgue) "uTk" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -68250,11 +69834,6 @@ /obj/structure/sign/poster/official/random/directional/south, /turf/open/floor/iron/white, /area/station/science/robotics/lab) -"uTN" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/flora/bush/jungle/a/style_random, -/turf/open/floor/grass, -/area/station/service/hydroponics) "uTX" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/item/kirbyplants/random, @@ -68267,6 +69846,10 @@ /obj/effect/decal/cleanable/blood/old, /turf/open/floor/engine, /area/station/science/xenobiology) +"uUq" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/middle, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "uUu" = ( /obj/structure/sign/nanotrasen{ pixel_x = -32 @@ -68278,6 +69861,12 @@ dir = 1 }, /area/station/hallway/secondary/entry) +"uUw" = ( +/obj/structure/table/wood, +/obj/machinery/airalarm/directional/west, +/obj/machinery/fax/auto_name, +/turf/open/floor/iron/grimy, +/area/station/service/bar/backroom) "uUH" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/visible/layer1{ dir = 10 @@ -68287,12 +69876,6 @@ "uUT" = ( /turf/closed/wall, /area/mine/mechbay) -"uUV" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "uVj" = ( /obj/effect/turf_decal/arrows/white, /obj/effect/turf_decal/stripes/line{ @@ -68300,20 +69883,6 @@ }, /turf/open/floor/engine, /area/station/engineering/atmos/hfr_room) -"uVn" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/effect/turf_decal/tile/red/half{ - dir = 4 - }, -/turf/open/floor/iron/half{ - dir = 1 - }, -/area/station/hallway/secondary/service) "uVp" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "MiniSat Maintenance" @@ -68342,17 +69911,20 @@ dir = 1 }, /area/station/security/lockers) +"uWf" = ( +/obj/structure/railing/corner/end{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "uWp" = ( /obj/structure/sign/warning/secure_area, /turf/closed/wall, /area/station/maintenance/aft/greater) -"uWv" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "uWw" = ( /obj/structure/railing/corner{ dir = 1 @@ -68383,19 +69955,10 @@ initial_gas_mix = "ICEMOON_ATMOS" }, /area/icemoon/underground/explored) -"uXm" = ( -/obj/structure/chair{ - desc = "Aw geez, I wonder what the chef's cooking up in there!"; - dir = 1; - name = "The Peanut's Gallery" - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "uXu" = ( /obj/machinery/power/terminal{ dir = 4 }, -/obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/department/electrical) "uXy" = ( @@ -68509,11 +70072,6 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/service) -"uZL" = ( -/obj/structure/table, -/obj/effect/spawner/random/maintenance/two, -/turf/open/floor/iron/smooth, -/area/station/maintenance/starboard/fore) "uZT" = ( /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -68627,17 +70185,6 @@ dir = 1 }, /area/station/medical/chemistry) -"vbb" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/obj/structure/chair{ - dir = 1 - }, -/obj/effect/turf_decal/tile/red/full, -/obj/machinery/light/directional/west, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) "vbd" = ( /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/arrows/white{ @@ -68660,15 +70207,6 @@ /obj/structure/cable, /turf/open/floor/circuit/telecomms/mainframe, /area/station/tcommsat/server) -"vbz" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "vbC" = ( /obj/structure/chair{ dir = 4 @@ -68697,6 +70235,13 @@ /obj/structure/railing, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"vbI" = ( +/obj/effect/turf_decal/tile/bar{ + dir = 1 + }, +/obj/structure/chair/stool/directional/north, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "vbO" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden, /obj/item/kirbyplants/random, @@ -68729,13 +70274,6 @@ "vcj" = ( /turf/closed/wall/r_wall, /area/mine/storage) -"vco" = ( -/obj/machinery/door/window/left/directional/west{ - name = "Fitness Ring" - }, -/obj/structure/window/reinforced/spawner/directional/north, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) "vcH" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/visible{ dir = 9 @@ -68811,16 +70349,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/service) -"vdI" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "vdM" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -68835,6 +70363,13 @@ /obj/effect/mapping_helpers/airlock/access/all/science/ordnance, /turf/open/floor/iron/white, /area/station/science/ordnance/office) +"vdO" = ( +/obj/machinery/newscaster/directional/north, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/central) "vdW" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/effect/decal/cleanable/dirt, @@ -68859,6 +70394,11 @@ "vep" = ( /turf/closed/wall, /area/station/maintenance/disposal/incinerator) +"veq" = ( +/obj/structure/cable, +/obj/effect/turf_decal/tile/purple, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "ver" = ( /obj/structure/lattice/catwalk, /obj/structure/marker_beacon/burgundy{ @@ -68877,12 +70417,6 @@ "veK" = ( /turf/open/floor/iron/white, /area/mine/living_quarters) -"veL" = ( -/obj/structure/sign/painting/library{ - pixel_y = 32 - }, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "veN" = ( /obj/machinery/vending/modularpc, /obj/effect/turf_decal/bot, @@ -68945,6 +70479,27 @@ }, /turf/open/floor/iron, /area/station/science/xenobiology) +"vfw" = ( +/obj/structure/railing/corner/end/flip, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/obj/structure/sink/kitchen/directional/south, +/obj/structure/mirror/directional/north, +/obj/machinery/camera/directional/north{ + c_tag = "Service - Coldroom Access" + }, +/obj/effect/turf_decal/tile/bar{ + dir = 4 + }, +/obj/structure/disposalpipe/sorting/mail{ + dir = 4 + }, +/obj/effect/mapping_helpers/mail_sorting/service/kitchen, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/service/kitchen/coldroom) "vfI" = ( /obj/machinery/door/window/right/directional/south{ name = "Ordnance Freezer Chamber Access"; @@ -69021,11 +70576,26 @@ /obj/effect/mapping_helpers/airlock/abandoned, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"vgU" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/station/maintenance/starboard/fore) "vhm" = ( /obj/structure/sign/poster/random/directional/west, /obj/machinery/firealarm/directional/north, /turf/open/floor/iron/dark, /area/station/service/chapel) +"vhA" = ( +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning/corner{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "vhB" = ( /obj/structure/chair/plastic, /obj/effect/turf_decal/bot_red, @@ -69134,12 +70704,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"vkg" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/trimline/green/filled/line, -/obj/effect/turf_decal/trimline/blue/filled/warning, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "vkz" = ( /obj/machinery/suit_storage_unit/ce, /obj/effect/turf_decal/stripes/line{ @@ -69183,6 +70747,15 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/plating, /area/station/construction) +"vkO" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "vkW" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -69214,26 +70787,9 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) -"vlq" = ( -/obj/effect/turf_decal/siding/white{ - dir = 8 - }, -/obj/structure/chair, -/obj/effect/turf_decal/tile/red/full, -/obj/structure/sign/poster/random/directional/west, -/turf/open/floor/iron/large, -/area/station/service/kitchen/diner) -"vlI" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/turf_decal/tile/green/opposingcorners{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners, -/obj/machinery/light/small/directional/north, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +"vlz" = ( +/turf/open/openspace, +/area/station/service/kitchen/coldroom) "vlL" = ( /obj/machinery/computer/cargo/request, /turf/open/floor/iron, @@ -69242,12 +70798,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/cargo/storage) -"vlP" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/tile, -/area/station/service/theater) "vlS" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/door/airlock/external{ @@ -69264,6 +70814,17 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/mining, /turf/open/floor/iron/smooth, /area/mine/mechbay) +"vlU" = ( +/obj/structure/table, +/obj/effect/turf_decal/siding/white{ + dir = 6 + }, +/obj/machinery/reagentgrinder{ + pixel_y = 9; + pixel_x = 4 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "vlZ" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 8 @@ -69272,6 +70833,11 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/mine/storage) +"vme" = ( +/obj/structure/cable, +/obj/machinery/duct, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "vmj" = ( /obj/structure/chair{ dir = 1; @@ -69407,6 +70973,20 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmos/storage/gas) +"vnK" = ( +/obj/effect/turf_decal/siding/white, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/structure/table/glass, +/obj/machinery/light/small/directional/west, +/obj/item/stack/package_wrap{ + pixel_y = 3 + }, +/obj/item/hand_labeler, +/turf/open/floor/iron, +/area/station/service/hydroponics) "vnN" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -69417,6 +70997,12 @@ }, /turf/open/floor/iron/textured, /area/station/medical/chem_storage) +"vnS" = ( +/obj/structure/fence/cut/large{ + dir = 8 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "vnY" = ( /obj/structure/closet/crate/critter, /turf/open/floor/plating, @@ -69466,14 +71052,6 @@ "voK" = ( /turf/closed/wall/r_wall, /area/station/tcommsat/computer) -"voM" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "voY" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -69528,6 +71106,18 @@ /obj/structure/cable, /turf/open/floor/iron/recharge_floor, /area/station/security/mechbay) +"vpJ" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/machinery/door/airlock/engineering{ + name = "Utilities Room" + }, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/unres, +/obj/structure/disposalpipe/segment, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "vpR" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, @@ -69567,15 +71157,6 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron, /area/station/science/ordnance) -"vqD" = ( -/obj/machinery/door/airlock{ - name = "Hydroponics Backroom" - }, -/obj/machinery/door/firedoor, -/obj/machinery/duct, -/obj/effect/mapping_helpers/airlock/access/all/service/hydroponics, -/turf/open/floor/iron/textured_half, -/area/station/service/hydroponics) "vqH" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 6 @@ -69619,6 +71200,15 @@ /obj/item/kirbyplants/random, /turf/open/floor/iron, /area/station/security/courtroom) +"vrw" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 2; + id = "pharmacy_shutters3"; + name = "Pharmacy Shutters" + }, +/turf/open/floor/plating, +/area/station/service/kitchen) "vrC" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -69709,6 +71299,19 @@ /obj/machinery/air_sensor/carbon_tank, /turf/open/floor/engine/co2, /area/station/engineering/atmos) +"vto" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/newscaster/directional/north, +/obj/effect/turf_decal/siding/wood, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light/small/directional/north, +/obj/machinery/camera/directional/north{ + c_tag = "Service - Bar" + }, +/turf/open/floor/iron, +/area/station/service/bar) "vtr" = ( /obj/effect/decal/cleanable/cobweb/cobweb2, /obj/item/kirbyplants/random, @@ -69735,6 +71338,11 @@ dir = 10 }, /area/station/science/research) +"vtW" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/machinery/space_heater, +/turf/open/floor/plating, +/area/station/medical/morgue) "vtZ" = ( /obj/structure/table/wood, /obj/item/reagent_containers/cup/glass/bottle/vodka/badminka{ @@ -69799,10 +71407,6 @@ /obj/structure/sign/warning/fire, /turf/closed/wall/r_wall, /area/station/engineering/supermatter) -"vuN" = ( -/obj/machinery/light/small/directional/west, -/turf/open/floor/wood/tile, -/area/station/service/theater) "vuR" = ( /obj/structure/extinguisher_cabinet/directional/south, /obj/effect/turf_decal/trimline/yellow/filled/warning{ @@ -69838,6 +71442,17 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) +"vvn" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/obj/item/radio/intercom/directional/west, +/obj/machinery/camera/directional/west{ + c_tag = "Service - Atrium Entrance" + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "vvu" = ( /obj/structure/railing, /obj/effect/turf_decal/trimline/neutral/warning{ @@ -69930,6 +71545,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/smooth, /area/station/security/holding_cell) +"vww" = ( +/obj/structure/sign/warning/directional/west, +/turf/open/openspace/icemoon, +/area/icemoon/surface/outdoors/nospawn) "vwC" = ( /obj/effect/turf_decal/weather/snow/corner{ dir = 9 @@ -70020,19 +71639,6 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/white, /area/station/maintenance/port/fore) -"vxx" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/structure/sign/directions/engineering{ - desc = "A sign that shows there are doors here. There are doors everywhere!"; - icon_state = "doors"; - name = "WARNING: EXTERNAL AIRLOCK"; - pixel_y = 32 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "vxO" = ( /obj/effect/decal/cleanable/dirt/dust, /obj/effect/turf_decal/siding/wood, @@ -70049,6 +71655,14 @@ /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, /turf/open/floor/iron/large, /area/station/engineering/atmos) +"vxY" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/structure/cable, +/obj/effect/landmark/start/mime, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "vyb" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -70072,16 +71686,6 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/security/processing) -"vyj" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/camera/directional/south{ - c_tag = "Service - Electrical Maintenace Lower" - }, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/starboard/lesser) "vym" = ( /turf/closed/wall, /area/station/construction) @@ -70099,6 +71703,10 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/engine, /area/station/science/explab) +"vyy" = ( +/obj/structure/reagent_dispensers/cooking_oil, +/turf/open/misc/asteroid/snow/coldroom, +/area/station/service/kitchen/coldroom) "vyI" = ( /obj/structure/railing{ dir = 1 @@ -70107,6 +71715,12 @@ /obj/machinery/light/small/dim/directional/east, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"vyN" = ( +/obj/structure/closet/crate/miningcar, +/obj/effect/spawner/random/exotic/snow_gear, +/obj/effect/spawner/random/exotic/snow_gear, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "vyO" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -70283,6 +71897,15 @@ }, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/service) +"vAW" = ( +/obj/effect/turf_decal/tile/neutral/diagonal_edge, +/obj/effect/landmark/start/cook, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 8 + }, +/obj/structure/cable, +/turf/open/floor/iron/kitchen/diagonal, +/area/station/service/kitchen) "vAY" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -70330,6 +71953,18 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/engineering/supermatter/room) +"vBt" = ( +/obj/machinery/door/airlock/freezer{ + desc = "The freezer where the chef keeps all the stuff that needs to be kept cold. Ice cold."; + name = "The Ice Box" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/service/kitchen/coldroom) "vBu" = ( /obj/machinery/space_heater, /obj/machinery/camera/directional/south{ @@ -70458,16 +72093,16 @@ }, /turf/open/floor/iron, /area/mine/laborcamp) -"vEi" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/public/glass{ - name = "Holodeck Door" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "holodeck" - }, -/turf/open/floor/iron, -/area/station/commons/fitness) +"vDQ" = ( +/obj/effect/spawner/random/decoration/flower, +/obj/structure/flora/rock/pile/icy/style_random, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) +"vEh" = ( +/obj/structure/frame/machine, +/obj/item/stack/cable_coil/five, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "vEw" = ( /obj/machinery/camera/directional/west{ c_tag = "Atmospherics Access" @@ -70484,6 +72119,17 @@ /obj/machinery/status_display/evac/directional/east, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"vEC" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/siding/wood, +/obj/structure/chair/stool/bar/directional/north, +/turf/open/floor/eighties, +/area/station/commons/lounge) "vEJ" = ( /obj/effect/turf_decal/tile/green{ dir = 8 @@ -70616,6 +72262,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/tcommsat/computer) +"vHe" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/spawner/random/trash/botanical_waste, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "vHf" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -70673,6 +72327,13 @@ }, /turf/open/floor/iron/white/smooth_large, /area/station/medical/chemistry) +"vHT" = ( +/obj/structure/fence/post{ + dir = 8 + }, +/obj/structure/sign/nanotrasen, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "vHU" = ( /obj/item/radio/intercom/prison/directional/south, /obj/effect/turf_decal/tile/red/half/contrasted, @@ -70715,6 +72376,13 @@ /obj/item/radio/intercom/directional/north, /turf/open/floor/iron/dark/textured_edge, /area/station/security/evidence) +"vIL" = ( +/obj/structure/cable, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "vIZ" = ( /obj/machinery/duct, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -70744,11 +72412,6 @@ }, /turf/open/floor/plating, /area/station/engineering/storage/tech) -"vJL" = ( -/obj/machinery/power/apc/auto_name/directional/north, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "vJS" = ( /obj/structure/chair/sofa/corp/right{ dir = 4; @@ -70777,53 +72440,19 @@ /obj/machinery/vending/security, /turf/open/floor/iron/smooth_edge, /area/station/security/lockers) -"vKn" = ( -/obj/item/radio/intercom/directional/north, -/obj/structure/table/wood, -/obj/machinery/fax{ - fax_name = "Service Hallway"; - name = "Service Fax Machine" - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "vKq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, /turf/open/floor/iron, /area/station/commons/locker) -"vKC" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/wood{ - name = "Bar" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/bar, -/turf/open/floor/iron/dark/textured_half{ - dir = 1 - }, -/area/station/service/bar/backroom) -"vKE" = ( -/obj/machinery/computer/holodeck, -/obj/effect/turf_decal/tile/red/half/contrasted{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/commons/fitness) -"vKG" = ( -/obj/machinery/camera/directional/east{ - c_tag = "Holodeck Control" - }, -/obj/effect/turf_decal/tile/red/half/contrasted{ +"vKT" = ( +/obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/open/floor/iron, -/area/station/commons/fitness) +/obj/structure/cable, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "vLj" = ( /obj/machinery/suit_storage_unit/rd, /obj/effect/turf_decal/stripes/line{ @@ -70832,29 +72461,11 @@ /obj/machinery/light/directional/north, /turf/open/floor/iron/smooth_half, /area/station/command/heads_quarters/rd) -"vLk" = ( -/obj/structure/sign/warning/gas_mask, -/turf/closed/wall, -/area/station/maintenance/starboard/fore) -"vLn" = ( -/obj/machinery/camera/directional/south{ - c_tag = "Service Hallway - Upper East" - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "vLo" = ( /obj/effect/landmark/generic_maintenance_landmark, /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"vLx" = ( -/obj/effect/landmark/event_spawn, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "vMa" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm/directional/south, @@ -70904,11 +72515,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/service/chapel/office) -"vMq" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/holopad, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "vMA" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -70923,11 +72529,6 @@ }, /turf/open/floor/wood, /area/station/maintenance/aft/greater) -"vMR" = ( -/obj/structure/table/glass, -/obj/item/seeds/glowshroom, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "vMY" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -70978,6 +72579,16 @@ }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) +"vOd" = ( +/obj/item/wrench, +/obj/machinery/atmospherics/components/binary/pump/off/supply/visible/layer4{ + dir = 1; + name = "Air In" + }, +/obj/effect/landmark/generic_maintenance_landmark, +/obj/effect/landmark/blobstart, +/turf/open/floor/plating, +/area/station/maintenance/fore) "vOw" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/red{ @@ -71069,20 +72680,19 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron, /area/mine/production) +"vQz" = ( +/obj/effect/turf_decal/weather/snow/corner{ + dir = 10 + }, +/obj/machinery/light/small/directional/east, +/turf/open/floor/plating/snowed/icemoon, +/area/icemoon/underground/explored) "vQG" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 10 }, /turf/open/floor/iron/dark, /area/station/commons/storage/mining) -"vQN" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, -/obj/machinery/firealarm/directional/south, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "vQO" = ( /obj/machinery/camera/directional/east{ c_tag = "Locker Room Toilets" @@ -71119,12 +72729,6 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) -"vRE" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "vRN" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -71182,20 +72786,19 @@ "vSi" = ( /turf/closed/wall, /area/mine/eva) -"vSr" = ( -/obj/machinery/door/airlock/maintenance{ - name = "Service Hall Maintenance" +"vSu" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 }, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/obj/machinery/duct, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 1 +/obj/machinery/firealarm/directional/north{ + pixel_x = -4 }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) +/obj/machinery/light_switch/directional/north{ + pixel_x = 5; + pixel_y = 28 + }, +/turf/open/floor/wood/large, +/area/station/service/bar) "vSw" = ( /obj/structure/table, /obj/machinery/firealarm/directional/north, @@ -71294,11 +72897,6 @@ /obj/structure/closet/firecloset, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) -"vTA" = ( -/obj/effect/turf_decal/tile/neutral/half/contrasted, -/obj/machinery/light/small/directional/south, -/turf/open/floor/iron, -/area/station/commons/dorms) "vTJ" = ( /obj/structure/table, /obj/item/toy/plush/slimeplushie{ @@ -71326,14 +72924,24 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) -"vUi" = ( -/obj/structure/sign/picture_frame/portrait/bar{ - pixel_y = -32 +"vUn" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 }, -/obj/effect/turf_decal/siding/white, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) +/obj/machinery/atmospherics/pipe/multiz/supply/visible/layer4{ + color = "#0000ff"; + dir = 8; + name = "Supply multi deck pipe adapter" + }, +/obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2{ + color = "#ff0000"; + dir = 8; + name = "Scrubbers multi deck pipe adapter" + }, +/obj/structure/cable/multilayer/multiz, +/obj/machinery/airalarm/directional/east, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "vUr" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/visible{ dir = 4 @@ -71366,15 +72974,6 @@ }, /turf/open/floor/iron, /area/station/science/ordnance) -"vVh" = ( -/obj/effect/turf_decal/siding/white/corner{ - dir = 4 - }, -/obj/effect/turf_decal/siding/white/corner, -/obj/structure/cable, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "vVj" = ( /obj/effect/turf_decal/bot_white/left, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -71386,6 +72985,12 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/freezer, /area/station/commons/toilet) +"vVA" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 6 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "vVH" = ( /turf/closed/wall, /area/station/security/prison/safe) @@ -71453,10 +73058,6 @@ "vWz" = ( /turf/closed/wall, /area/mine/storage) -"vWB" = ( -/obj/effect/spawner/random/vending/colavend, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/central) "vWL" = ( /obj/structure/chair{ dir = 1; @@ -71505,6 +73106,11 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) +"vXm" = ( +/obj/structure/grille/broken, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "vXn" = ( /obj/structure/table, /obj/item/food/pie/cream, @@ -71545,6 +73151,12 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/mine/living_quarters) +"vXM" = ( +/obj/structure/chair/sofa/right/brown{ + dir = 8 + }, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "vXO" = ( /obj/structure/fluff/tram_rail, /obj/structure/lattice/catwalk, @@ -71563,13 +73175,6 @@ /obj/item/toy/snowball, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) -"vXY" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/door/airlock/external, -/turf/open/floor/plating, -/area/station/maintenance/fore) "vYa" = ( /obj/structure/reagent_dispensers/fueltank, /obj/effect/turf_decal/delivery, @@ -71609,6 +73214,10 @@ }, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) +"vYp" = ( +/obj/structure/table/wood, +/turf/open/floor/wood/parquet, +/area/station/service/bar/atrium) "vYq" = ( /obj/structure/barricade/wooden/snowed, /turf/open/misc/asteroid/snow/icemoon, @@ -71656,6 +73265,17 @@ /obj/effect/spawner/random/structure/crate, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"vYY" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/sorting/mail{ + dir = 4 + }, +/obj/effect/mapping_helpers/mail_sorting/service/hydroponics, +/obj/effect/mapping_helpers/mail_sorting/service/theater, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "vZa" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, @@ -71720,10 +73340,6 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/station/maintenance/port/aft) -"vZY" = ( -/obj/machinery/light/directional/south, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "wab" = ( /obj/structure/cable, /obj/machinery/holopad, @@ -71862,13 +73478,6 @@ }, /turf/open/floor/iron/freezer, /area/station/commons/toilet/locker) -"wbZ" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/structure/cable/multilayer/multiz, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "wck" = ( /obj/structure/chair{ dir = 8 @@ -71879,6 +73488,12 @@ /obj/machinery/bluespace_vendor/directional/east, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"wco" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "wcx" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -71994,16 +73609,6 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) -"weY" = ( -/obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/table/glass, -/obj/effect/turf_decal/trimline/green/filled/line, -/obj/effect/turf_decal/trimline/blue/filled/warning, -/obj/machinery/reagentgrinder{ - pixel_y = 4 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "wfc" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/catwalk_floor/iron_dark, @@ -72179,6 +73784,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold/purple/visible, /turf/open/floor/glass/reinforced, /area/station/engineering/atmos/pumproom) +"whg" = ( +/obj/effect/turf_decal/tile/blue, +/obj/machinery/light/directional/south, +/obj/machinery/firealarm/directional/south, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "whh" = ( /obj/effect/turf_decal/trimline/yellow/filled/line, /obj/effect/turf_decal/trimline/yellow/filled/warning{ @@ -72195,35 +73806,11 @@ /obj/effect/turf_decal/stripes/corner, /turf/open/floor/iron/white, /area/station/medical/treatment_center) -"whl" = ( -/obj/machinery/door/airlock/external, -/obj/structure/sign/warning/gas_mask/directional/south{ - desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." - }, -/obj/structure/sign/warning/cold_temp/directional/north, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "chem-morgue-airlock" - }, -/obj/effect/mapping_helpers/airlock/access/any/medical/maintenance, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/medical/morgue) "whr" = ( /obj/machinery/hydroponics/soil, /obj/item/cultivator, /turf/open/floor/grass, /area/station/security/prison/garden) -"whu" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 10 - }, -/obj/machinery/duct, -/obj/structure/disposalpipe/trunk{ - dir = 8 - }, -/obj/machinery/disposal/bin, -/turf/open/floor/plating, -/area/station/hallway/secondary/service) "whz" = ( /obj/machinery/hydroponics/constructable, /obj/effect/decal/cleanable/dirt, @@ -72297,6 +73884,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/engine_smes) +"wiO" = ( +/obj/structure/chair, +/obj/effect/turf_decal/tile/blue/half/contrasted{ + dir = 1 + }, +/turf/open/floor/iron/white, +/area/station/medical/medbay/lobby) "wjv" = ( /obj/machinery/computer/cargo{ dir = 4 @@ -72332,6 +73926,17 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"wjR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/item/chair, +/obj/effect/decal/cleanable/glass, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "wjS" = ( /obj/effect/landmark/start/assistant, /obj/structure/chair/pew{ @@ -72353,11 +73958,6 @@ }, /turf/open/floor/iron/dark/telecomms, /area/station/tcommsat/server) -"wkq" = ( -/obj/machinery/airalarm/directional/east, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "wkr" = ( /turf/open/floor/iron/showroomfloor, /area/station/security/warden) @@ -72425,6 +74025,18 @@ }, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) +"wla" = ( +/obj/effect/decal/cleanable/garbage, +/obj/item/reagent_containers/spray/chemsprayer/party{ + pixel_x = 1 + }, +/obj/item/clothing/head/costume/festive{ + pixel_y = -3; + pixel_x = -5 + }, +/obj/effect/decal/cleanable/generic, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "wlr" = ( /obj/structure/table, /obj/item/stack/spacecash/c10, @@ -72560,11 +74172,6 @@ /mob/living/basic/pet/penguin/baby/permanent, /turf/open/misc/asteroid/snow/standard_air, /area/station/science/research) -"wnq" = ( -/obj/item/paper/fluff/jobs/security/beepsky_mom, -/obj/machinery/light/small/dim/directional/east, -/turf/open/floor/plating, -/area/station/maintenance/fore) "wnv" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -72679,6 +74286,15 @@ }, /turf/open/floor/plating, /area/station/hallway/secondary/exit/departure_lounge) +"woX" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/structure/disposalpipe/junction/flip{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "wpc" = ( /obj/machinery/door/airlock{ name = "Unisex Restrooms" @@ -72688,6 +74304,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/freezer, /area/station/commons/toilet/locker) +"wph" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/effect/landmark/generic_maintenance_landmark, +/turf/open/floor/plating, +/area/station/maintenance/fore) "wpi" = ( /obj/structure/table, /obj/item/holosign_creator/atmos{ @@ -72699,6 +74321,17 @@ }, /turf/open/floor/iron/dark, /area/station/science/ordnance/office) +"wpm" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/maintenance{ + name = "Fitness Maintenance" + }, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/unres, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "wpp" = ( /obj/machinery/airalarm/directional/north, /obj/machinery/pipedispenser/disposal, @@ -72749,17 +74382,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/commons/locker) -"wpV" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/light_switch/directional/south, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral/half/contrasted, -/turf/open/floor/iron, -/area/station/commons/fitness) "wpY" = ( /obj/effect/mapping_helpers/airlock/abandoned, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -72810,6 +74432,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/commons/storage/mining) +"wqt" = ( +/obj/effect/turf_decal/tile/bar{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/machinery/airalarm/directional/west, +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "wqx" = ( /turf/closed/wall/r_wall, /area/station/hallway/primary/fore) @@ -72972,13 +74605,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"wtb" = ( -/obj/machinery/door/firedoor, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/central) "wtg" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/structure/cable, @@ -73026,21 +74652,28 @@ /obj/structure/sign/warning/cold_temp, /turf/open/floor/plating, /area/station/maintenance/solars/starboard/fore) +"wuc" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "kitchencounter"; + name = "Kitchen Counter Shutters" + }, +/obj/machinery/door/firedoor, +/obj/item/reagent_containers/condiment/peppermill{ + pixel_x = 3 + }, +/obj/item/reagent_containers/condiment/saltshaker{ + pixel_x = -3 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "wug" = ( /obj/machinery/gulag_item_reclaimer{ pixel_y = 24 }, /turf/open/floor/carpet, /area/station/security/processing) -"wun" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 9 - }, -/obj/item/pai_card, -/obj/structure/table/wood, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "wuo" = ( /turf/closed/wall/r_wall, /area/station/engineering/supermatter) @@ -73089,26 +74722,6 @@ /obj/effect/spawner/random/trash/cigbutt, /turf/open/floor/iron, /area/station/engineering/lobby) -"wvb" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/effect/turf_decal/siding/wood, -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron/dark/textured_half, -/area/station/service/bar/atrium) -"wvc" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/machinery/light/directional/east, -/turf/open/floor/iron, -/area/station/service/hydroponics) "wve" = ( /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron/white, @@ -73117,6 +74730,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet, /area/station/service/chapel) +"wvu" = ( +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "wvv" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -73159,6 +74775,10 @@ "wvI" = ( /turf/closed/wall/r_wall, /area/station/maintenance/disposal/incinerator) +"wvJ" = ( +/obj/effect/spawner/random/engineering/atmospherics_portable, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "wvK" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -73187,6 +74807,22 @@ /mob/living/basic/pet/cat/runtime, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/cmo) +"wwg" = ( +/obj/machinery/camera{ + c_tag = "Service - Botany"; + dir = 9 + }, +/obj/machinery/hydroponics/constructable, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 1 + }, +/obj/item/radio/intercom/directional/north, +/obj/machinery/light/warm/directional/north, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "wwn" = ( /obj/structure/table/reinforced, /obj/machinery/door/window/left/directional/west{ @@ -73269,14 +74905,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/cargo/warehouse) -"wxr" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/door/firedoor, -/obj/effect/landmark/event_spawn, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) "wxw" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -73363,17 +74991,6 @@ }, /turf/open/floor/iron/cafeteria, /area/station/security/prison/mess) -"wyQ" = ( -/obj/effect/turf_decal/siding/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/multi_tile/public/glass{ - name = "The Girly Boar" - }, -/turf/open/floor/iron/dark/textured_half, -/area/station/service/bar/atrium) "wzc" = ( /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, @@ -73486,6 +75103,13 @@ }, /turf/open/floor/plating, /area/station/maintenance/fore) +"wBa" = ( +/obj/structure/railing, +/obj/effect/turf_decal/siding/thinplating_new/light{ + dir = 10 + }, +/turf/open/floor/wood/large, +/area/station/hallway/primary/starboard) "wBb" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -73523,6 +75147,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/prison/workout) +"wBr" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/power/apc/auto_name/directional/west, +/obj/item/kirbyplants/organic/plant2, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "wBy" = ( /obj/machinery/netpod, /obj/item/radio/intercom/directional/south, @@ -73540,12 +75173,6 @@ }, /turf/closed/wall, /area/station/cargo/sorting) -"wBR" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "wBT" = ( /obj/machinery/camera/directional/south{ c_tag = "Port Hallway Center" @@ -73683,11 +75310,6 @@ }, /turf/open/floor/iron/dark, /area/mine/laborcamp) -"wDB" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/starboard/lesser) "wDG" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -73718,17 +75340,20 @@ /obj/structure/disposalpipe/trunk, /turf/open/floor/iron, /area/station/command/heads_quarters/rd) -"wEa" = ( -/obj/structure/sign/painting/library{ - pixel_y = 32 - }, -/obj/structure/table, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "wEh" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/cargo/sorting) +"wEq" = ( +/obj/structure/chair/office{ + dir = 8 + }, +/obj/machinery/newscaster/directional/north, +/obj/machinery/light/small/directional/north, +/obj/effect/decal/remains/human, +/obj/effect/mapping_helpers/broken_floor, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "wEG" = ( /obj/structure/extinguisher_cabinet/directional/south{ pixel_x = 4 @@ -73826,6 +75451,13 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/engine, /area/station/science/explab) +"wGm" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/structure/chair/stool/bar/directional/north, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "wGv" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, @@ -73876,6 +75508,10 @@ }, /turf/open/floor/iron/dark/diagonal, /area/station/engineering/atmos/storage) +"wGQ" = ( +/obj/machinery/light/small/dim/directional/west, +/turf/open/floor/stone, +/area/station/commons/lounge) "wGW" = ( /obj/structure/table, /obj/item/book/manual/wiki/security_space_law, @@ -73903,10 +75539,6 @@ "wHc" = ( /turf/closed/wall/r_wall, /area/station/command/heads_quarters/rd) -"wHd" = ( -/obj/machinery/atmospherics/pipe/smart/simple/dark/visible, -/turf/closed/wall/r_wall, -/area/station/science/ordnance/burnchamber) "wHe" = ( /obj/structure/cable, /turf/open/floor/iron/dark/textured, @@ -73930,6 +75562,12 @@ }, /turf/open/floor/iron, /area/station/engineering/lobby) +"wHr" = ( +/obj/structure/fence/post{ + dir = 8 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors/nospawn) "wHH" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/red{ @@ -73937,6 +75575,17 @@ }, /turf/open/floor/iron, /area/mine/laborcamp/security) +"wHK" = ( +/obj/machinery/portable_atmospherics/canister/air, +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/obj/machinery/atmospherics/components/unary/portables_connector/visible/layer4{ + dir = 1 + }, +/obj/machinery/light/small/directional/south, +/turf/open/floor/plating, +/area/station/maintenance/fore) "wIg" = ( /obj/machinery/mech_bay_recharge_port{ dir = 2 @@ -73949,18 +75598,28 @@ /obj/effect/turf_decal/tile/blue/half/contrasted, /turf/open/floor/iron, /area/station/hallway/primary/central) +"wIx" = ( +/obj/machinery/newscaster/directional/south, +/obj/effect/turf_decal/siding/thinplating/dark{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/green/filled/line, +/obj/effect/turf_decal/trimline/blue/filled/warning, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "wIz" = ( /obj/machinery/light/small/directional/west, /obj/structure/table/wood, /obj/effect/landmark/start/hangover, /turf/open/floor/carpet, /area/station/commons/dorms) -"wIF" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/chair/stool/directional/west, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "wIR" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -73976,18 +75635,6 @@ /obj/effect/decal/remains/plasma, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) -"wJe" = ( -/obj/effect/turf_decal/siding/thinplating/dark{ - dir = 4 - }, -/obj/structure/window/reinforced/spawner/directional/east, -/turf/open/floor/carpet, -/area/station/service/theater) -"wJf" = ( -/obj/structure/table/wood, -/obj/item/flashlight/lamp, -/turf/open/floor/wood, -/area/station/hallway/secondary/service) "wJi" = ( /obj/structure/railing{ dir = 4 @@ -74038,14 +75685,10 @@ /obj/effect/landmark/start/depsec/medical, /turf/open/floor/iron/dark/smooth_large, /area/station/security/checkpoint/medical) -"wKm" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) +"wKh" = ( +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, +/turf/closed/wall/r_wall, +/area/station/science/ordnance) "wKv" = ( /obj/structure/table, /obj/item/radio/off, @@ -74206,11 +75849,19 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/commons/storage/mining) -"wMP" = ( -/obj/item/food/chococoin, -/obj/structure/closet/secure_closet/freezer/fridge, -/turf/open/misc/ice/coldroom, -/area/station/service/kitchen/coldroom) +"wME" = ( +/obj/machinery/light_switch/directional/north{ + pixel_x = 6; + pixel_y = 28 + }, +/obj/machinery/button/door/directional/north{ + id = "botany_chasm_and_wolf_shutters"; + name = "Exterior Shutters"; + pixel_y = 28; + pixel_x = -4 + }, +/turf/open/floor/iron/dark/smooth_half, +/area/station/service/hydroponics) "wMT" = ( /obj/structure/sign/poster/random/directional/south, /turf/open/floor/iron, @@ -74250,17 +75901,6 @@ "wNO" = ( /turf/open/genturf, /area/icemoon/surface/outdoors/unexplored/rivers/no_monsters) -"wNQ" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/table/wood, -/obj/structure/desk_bell{ - pixel_y = 10 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) "wNR" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -74283,16 +75923,6 @@ /obj/structure/cable, /turf/open/floor/iron/dark/textured, /area/station/security/processing) -"wOh" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 8 - }, -/obj/machinery/light/floor, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "wOn" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -74307,6 +75937,12 @@ /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"wOC" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "wOF" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/official/random/directional/north, @@ -74343,6 +75979,26 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/science/xenobiology) +"wPe" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/access/all/service/bar, +/obj/machinery/door/airlock{ + name = "Bar" + }, +/turf/open/floor/iron/dark/textured_half{ + dir = 1 + }, +/area/station/service/bar) "wPf" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -74373,17 +76029,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"wPC" = ( -/obj/machinery/door/airlock/research/glass/incinerator/ordmix_interior{ - name = "Burn Chamber Interior Airlock" - }, -/obj/effect/mapping_helpers/airlock/locked, -/obj/machinery/airlock_controller/incinerator_ordmix{ - pixel_x = 24 - }, -/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, -/turf/open/floor/engine, -/area/station/science/ordnance/burnchamber) "wPD" = ( /obj/machinery/door/airlock/security/glass{ name = "Evidence Storage" @@ -74408,6 +76053,16 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"wPR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/duct, +/obj/structure/sign/warning/cold_temp/directional/south, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "wPX" = ( /obj/structure/table, /obj/item/storage/belt/medical{ @@ -74425,12 +76080,6 @@ /obj/item/radio/intercom/directional/south, /turf/open/floor/iron/white, /area/station/medical/storage) -"wPZ" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/starboard/fore) "wQh" = ( /obj/structure/railing{ dir = 4 @@ -74459,6 +76108,14 @@ /obj/item/assembly/flash, /turf/open/floor/plating/icemoon, /area/station/security/execution/education) +"wQx" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "wQC" = ( /obj/item/flashlight/lantern, /obj/structure/table/wood, @@ -74472,11 +76129,12 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) -"wQI" = ( -/obj/structure/closet, -/obj/effect/spawner/random/maintenance/four, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) +"wQN" = ( +/obj/structure/fence/cut/large{ + dir = 1 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/nospawn) "wQR" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -74569,6 +76227,10 @@ /obj/effect/spawner/structure/window/hollow/reinforced/middle, /turf/open/floor/plating, /area/station/medical/chemistry) +"wSc" = ( +/obj/machinery/power/port_gen/pacman, +/turf/open/floor/plating, +/area/station/maintenance/fore) "wSd" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -74615,6 +76277,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/security/prison/work) +"wSL" = ( +/obj/effect/landmark/start/botanist, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/item/radio/intercom/directional/south, +/turf/open/floor/iron, +/area/station/service/hydroponics) "wSM" = ( /obj/machinery/conveyor{ dir = 4; @@ -74648,6 +76319,11 @@ "wTg" = ( /turf/closed/wall, /area/station/engineering/main) +"wTl" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/effect/landmark/start/mime, +/turf/open/floor/wood, +/area/station/commons/lounge) "wTw" = ( /obj/effect/turf_decal/trimline/neutral/warning{ dir = 10 @@ -74809,16 +76485,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/maintenance/central/greater) -"wUY" = ( -/obj/structure/chair/sofa/left/brown{ - dir = 4 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "wVe" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -74870,6 +76536,17 @@ }, /turf/open/floor/iron, /area/station/cargo/sorting) +"wVI" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/effect/turf_decal/siding/wood, +/obj/structure/chair/stool/bar/directional/north, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/turf/open/floor/eighties, +/area/station/commons/lounge) "wVR" = ( /obj/structure/disposalpipe/segment{ dir = 10 @@ -74891,6 +76568,13 @@ /obj/effect/spawner/random/structure/tank_holder, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"wWB" = ( +/obj/structure/chair/plastic{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron, +/area/station/maintenance/starboard/fore) "wWM" = ( /obj/machinery/atmospherics/pipe/smart/simple/orange/visible{ dir = 4 @@ -74960,12 +76644,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/science/xenobiology) -"wYf" = ( -/obj/effect/turf_decal/loading_area{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "wYh" = ( /obj/structure/disposalpipe/segment, /obj/machinery/firealarm/directional/west, @@ -74990,9 +76668,6 @@ }, /turf/open/floor/vault, /area/station/security/prison/rec) -"wYs" = ( -/turf/open/floor/plating, -/area/station/service/kitchen/coldroom) "wYw" = ( /obj/effect/turf_decal/stripes/asteroid/line{ dir = 8 @@ -75057,17 +76732,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) -"wZq" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/power/apc/auto_name/directional/south, -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "wZr" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 8 @@ -75099,39 +76763,16 @@ /obj/structure/cable, /turf/open/floor/iron/showroomfloor, /area/station/security/warden) -"wZK" = ( -/obj/structure/chair/stool/bar/directional/south, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/effect/landmark/start/hangover, -/turf/open/floor/stone, -/area/station/commons/lounge) "wZV" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/machinery/portable_atmospherics/canister/oxygen, /turf/open/floor/iron/dark, /area/station/science/ordnance) -"wZZ" = ( -/obj/structure/tank_holder/oxygen/red, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "xad" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle, /obj/structure/cable, /turf/open/floor/plating, /area/station/security/range) -"xak" = ( -/obj/machinery/door/airlock/external{ - glass = 1; - name = "Chapel External Airlock"; - opacity = 0 - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/service/chapel) "xal" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -75220,33 +76861,6 @@ /obj/item/kirbyplants/random, /turf/open/floor/iron/white, /area/mine/living_quarters) -"xbc" = ( -/obj/structure/window/reinforced/spawner/directional/south, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/commons/fitness) -"xbf" = ( -/obj/machinery/hydroponics/constructable, -/obj/effect/turf_decal/siding/wideplating/dark{ - dir = 1 - }, -/obj/item/seeds/berry, -/obj/machinery/light/small/dim/directional/south, -/turf/open/floor/grass, -/area/station/maintenance/starboard/fore) -"xbj" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 5 - }, -/obj/structure/chair/sofa/corp/left{ - dir = 4; - pixel_x = -4 - }, -/obj/effect/landmark/start/hangover, -/obj/machinery/computer/security/telescreen/entertainment/directional/west, -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron/grimy, -/area/station/service/bar/atrium) "xbn" = ( /obj/effect/turf_decal/tile/neutral/diagonal_edge, /obj/effect/landmark/event_spawn, @@ -75281,6 +76895,10 @@ }, /turf/open/floor/iron/freezer, /area/mine/eva/lower) +"xbB" = ( +/obj/machinery/gibber, +/turf/open/misc/asteroid/snow/coldroom, +/area/station/service/kitchen/coldroom) "xbC" = ( /obj/effect/turf_decal/trimline/dark_green/arrow_ccw, /obj/machinery/meter, @@ -75330,6 +76948,16 @@ }, /turf/open/lava/plasma/ice_moon, /area/icemoon/underground/explored) +"xcO" = ( +/obj/effect/turf_decal/tile/bar/opposingcorners, +/obj/machinery/status_display/ai/directional/north, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 8 + }, +/obj/structure/sink/kitchen/directional/west, +/obj/structure/extinguisher_cabinet/directional/east, +/turf/open/floor/iron, +/area/station/service/bar) "xcW" = ( /obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2{ dir = 1 @@ -75353,21 +76981,10 @@ /obj/effect/mapping_helpers/airlock/access/any/command/ai_upload, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat_interior) -"xdf" = ( -/obj/structure/sign/poster/official/random/directional/north, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "xdl" = ( /obj/structure/cable, /turf/open/floor/iron/white, /area/station/medical/storage) -"xdA" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/structure/chair/stool/bar/directional/east, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "xdH" = ( /obj/effect/turf_decal/stripes/line, /obj/structure/chair{ @@ -75405,28 +77022,15 @@ }, /turf/open/floor/iron/dark/textured, /area/station/security/prison/rec) +"xea" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/light/small/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "xeg" = ( /obj/effect/turf_decal/weather/snow/corner, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) -"xei" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/machinery/light/cold/directional/north, -/obj/structure/table, -/obj/item/food/grown/carrot{ - pixel_x = 6; - pixel_y = 7 - }, -/obj/item/food/grown/carrot{ - pixel_x = -6; - pixel_y = 10 - }, -/obj/item/food/meat/slab/synthmeat, -/turf/open/floor/plating/snowed/coldroom, -/area/station/service/kitchen/coldroom) "xem" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/power/apc/auto_name/directional/west, @@ -75715,13 +77319,6 @@ /obj/structure/extinguisher_cabinet/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/port) -"xhz" = ( -/obj/structure/ladder{ - name = "Kitchen Access" - }, -/obj/effect/turf_decal/tile/dark_blue/diagonal_edge, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen/coldroom) "xhD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -75795,15 +77392,6 @@ /obj/structure/sign/departments/medbay/alt, /turf/closed/wall, /area/station/medical/medbay/lobby) -"xjj" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/starboard/lesser) "xjm" = ( /obj/machinery/light_switch/directional/north, /obj/machinery/camera/directional/north{ @@ -75893,17 +77481,18 @@ /obj/effect/turf_decal/tile/yellow/full, /turf/open/floor/iron/large, /area/station/medical/storage) +"xlp" = ( +/obj/structure/sign/nanotrasen, +/obj/structure/fence/post{ + dir = 8 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/explored) "xlq" = ( /obj/structure/lattice/catwalk, /obj/structure/railing, /turf/open/lava/plasma/ice_moon, /area/icemoon/underground/explored) -"xlv" = ( -/obj/structure/chair{ - dir = 8 - }, -/turf/open/floor/iron/white/smooth_large, -/area/station/service/kitchen/diner) "xlx" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -76040,6 +77629,20 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"xnc" = ( +/obj/effect/turf_decal/siding/white/end{ + dir = 4 + }, +/obj/structure/table, +/obj/effect/spawner/random/food_or_drink/donkpockets{ + pixel_y = 6 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) +"xnf" = ( +/obj/item/kirbyplants/fern, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "xni" = ( /obj/effect/turf_decal/tile/yellow/half/contrasted{ dir = 1 @@ -76091,35 +77694,18 @@ }, /turf/open/lava/plasma/ice_moon, /area/icemoon/underground/explored) -"xoq" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/airalarm/directional/south, -/obj/effect/turf_decal/siding/white, -/obj/machinery/camera/directional/south{ - c_tag = "Service Bar" +"xog" = ( +/obj/structure/fence{ + dir = 1 }, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar) +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/nospawn) "xow" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/machinery/firealarm/directional/west, /obj/effect/turf_decal/stripes/corner, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/atmos) -"xpo" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted, -/turf/open/floor/iron, -/area/station/commons/fitness) -"xpp" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/machinery/duct, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "xpw" = ( /obj/machinery/power/apc/auto_name/directional/south, /obj/structure/cable, @@ -76156,6 +77742,16 @@ /obj/machinery/camera/autoname/directional/east, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) +"xpO" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "botany_chasm_and_wolf_shutters" + }, +/turf/open/floor/plating, +/area/station/service/hydroponics) "xpP" = ( /obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, @@ -76164,6 +77760,20 @@ /obj/effect/spawner/random/trash/mess, /turf/open/floor/plating, /area/station/maintenance/aft/greater) +"xqa" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/obj/machinery/duct, +/obj/effect/turf_decal/tile/bar{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/station/service/kitchen/coldroom) "xqj" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -76182,31 +77792,19 @@ /obj/structure/cable, /turf/open/floor/engine, /area/station/science/xenobiology) -"xqv" = ( -/obj/effect/spawner/random/entertainment/gambling, -/obj/structure/table/wood, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "xqy" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/cargo/office) -"xqA" = ( -/obj/machinery/door/airlock/external{ - name = "Service Hall Exit" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "service-hall-external" - }, -/obj/structure/sign/warning/gas_mask/directional/south{ - desc = "A sign that warns of dangerous gasses in the air, instructing you to wear internals." +"xqP" = ( +/obj/structure/window/reinforced/spawner/directional/north, +/obj/effect/turf_decal/siding/white{ + dir = 1 }, -/obj/effect/turf_decal/stripes/line, -/obj/effect/mapping_helpers/airlock/access/all/service/general, -/turf/open/floor/iron/dark/textured, -/area/station/hallway/secondary/service) +/turf/open/floor/iron/dark, +/area/station/commons/fitness) "xqX" = ( /obj/structure/sign/poster/contraband/random/directional/north, /obj/structure/cable, @@ -76224,6 +77822,25 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) +"xre" = ( +/obj/structure/table/glass, +/obj/machinery/door/window/left/directional/north{ + name = "Hydroponics Desk"; + req_access = list("hydroponics") + }, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/item/paper_bin{ + pixel_y = 4 + }, +/obj/item/pen{ + pixel_x = -5 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "xrf" = ( /obj/structure/railing, /obj/structure/cable, @@ -76288,6 +77905,12 @@ /obj/machinery/light/blacklight/directional/east, /turf/open/floor/wood, /area/station/service/library) +"xsm" = ( +/obj/structure/cable, +/obj/machinery/duct, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/fore) "xss" = ( /obj/machinery/light/directional/south, /obj/effect/turf_decal/tile/yellow/half/contrasted, @@ -76304,6 +77927,13 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/tech_storage, /turf/open/floor/plating, /area/station/engineering/storage/tech) +"xsy" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "xsA" = ( /obj/structure/rack, /obj/machinery/light/small/dim/directional/north, @@ -76345,6 +77975,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/prison/workout) +"xtH" = ( +/obj/effect/turf_decal/siding/wood/corner{ + dir = 8 + }, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "xtQ" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -76588,6 +78224,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/general/visible, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"xwL" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/duct, +/turf/open/floor/iron, +/area/station/commons/fitness) "xwM" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -76598,6 +78240,10 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) +"xxo" = ( +/obj/effect/turf_decal/weather/snow/corner, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) "xxs" = ( /obj/effect/turf_decal/bot_white, /obj/structure/reagent_dispensers/plumbed, @@ -76633,6 +78279,12 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"xxH" = ( +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "xxI" = ( /obj/machinery/airalarm/directional/north, /obj/item/kirbyplants/random, @@ -76815,11 +78467,6 @@ }, /turf/open/floor/circuit/red, /area/station/ai_monitored/turret_protected/ai_upload) -"xAb" = ( -/obj/structure/reagent_dispensers/watertank, -/obj/structure/sign/poster/contraband/random/directional/east, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "xAk" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/turf_decal/stripes/line{ @@ -76898,6 +78545,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/general/visible, /turf/closed/wall/r_wall, /area/station/engineering/supermatter) +"xBs" = ( +/obj/machinery/status_display/ai/directional/west, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/turf/open/floor/wood/parquet, +/area/station/service/theater) "xBt" = ( /obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ dir = 4 @@ -76925,6 +78579,24 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron/dark/textured, /area/station/engineering/atmos/storage/gas) +"xBS" = ( +/obj/item/training_toolbox{ + pixel_y = 5 + }, +/obj/structure/table, +/obj/item/training_toolbox{ + pixel_y = -2 + }, +/obj/machinery/camera/directional/east{ + c_tag = "Holodeck Control" + }, +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 4 + }, +/obj/machinery/status_display/evac/directional/east, +/obj/machinery/newscaster/directional/south, +/turf/open/floor/iron, +/area/station/commons/fitness) "xBU" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -77034,12 +78706,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/commons/locker) -"xDr" = ( -/obj/effect/turf_decal/siding/white, -/obj/effect/spawner/random/vending/snackvend, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "xDw" = ( /obj/structure/grille/broken, /obj/effect/decal/cleanable/dirt, @@ -77105,16 +78771,6 @@ /obj/structure/closet/bombcloset, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"xEx" = ( -/obj/item/gun/ballistic/shotgun/doublebarrel, -/obj/structure/table/wood, -/obj/machinery/camera/directional/east{ - c_tag = "Service Bar - Backroom" - }, -/obj/machinery/requests_console/auto_name/directional/east, -/obj/effect/turf_decal/tile/bar/opposingcorners, -/turf/open/floor/iron, -/area/station/service/bar/backroom) "xEE" = ( /obj/machinery/firealarm/directional/south, /turf/open/floor/iron, @@ -77157,6 +78813,19 @@ /obj/structure/disposalpipe/trunk, /turf/open/floor/iron/dark, /area/station/maintenance/disposal/incinerator) +"xEP" = ( +/obj/structure/reagent_dispensers/plumbed{ + dir = 1; + name = "hydroponics reservoir" + }, +/obj/effect/turf_decal/delivery/white{ + color = "#307db9" + }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/light/small/dim/directional/south, +/turf/open/floor/iron/dark/textured, +/area/station/maintenance/starboard/lesser) "xEQ" = ( /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -77169,21 +78838,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron, /area/mine/living_quarters) -"xFi" = ( -/obj/structure/sign/warning/cold_temp/directional/south, -/obj/structure/sign/warning/gas_mask/directional/north, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"xFj" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/obj/structure/cable, -/obj/structure/disposalpipe/trunk/multiz/down{ - dir = 1 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "xFm" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -77205,22 +78859,14 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"xFv" = ( -/obj/effect/turf_decal/siding/white{ - dir = 6 - }, +"xFz" = ( /obj/effect/turf_decal/tile/bar/opposingcorners, -/obj/structure/extinguisher_cabinet/directional/south, +/obj/effect/turf_decal/siding/wood, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, /turf/open/floor/iron, /area/station/service/bar) -"xFA" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) "xFB" = ( /obj/structure/table, /obj/item/tank/internals/emergency_oxygen/engi, @@ -77246,6 +78892,24 @@ /obj/machinery/incident_display/delam, /turf/closed/wall/r_wall, /area/station/engineering/supermatter/room) +"xFT" = ( +/obj/effect/turf_decal/trimline/green/filled/corner, +/obj/effect/turf_decal/trimline/blue/filled/warning/corner, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/machinery/duct, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/rack, +/obj/item/clothing/accessory/armband/hydro{ + pixel_y = 4; + pixel_x = 2 + }, +/obj/item/clothing/accessory/armband/hydro, +/obj/item/toy/figure/botanist, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "xFU" = ( /obj/structure/barricade/wooden, /obj/structure/sign/warning/gas_mask/directional/south{ @@ -77269,6 +78933,16 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) +"xGi" = ( +/obj/structure/table/glass, +/obj/item/seeds/glowshroom, +/obj/item/seeds/bamboo{ + pixel_y = 3; + pixel_x = 4 + }, +/obj/machinery/newscaster/directional/east, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "xGp" = ( /obj/structure/table/reinforced, /obj/machinery/door/window/left/directional/east{ @@ -77333,10 +79007,6 @@ /obj/structure/cable, /turf/open/floor/iron/textured, /area/station/security/courtroom) -"xGZ" = ( -/obj/machinery/vending/boozeomat, -/turf/closed/wall, -/area/station/service/bar) "xHe" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -77350,11 +79020,6 @@ /obj/machinery/status_display/evac/directional/south, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"xHi" = ( -/obj/effect/turf_decal/tile/neutral/diagonal_edge, -/obj/machinery/griddle, -/turf/open/floor/iron/kitchen/diagonal, -/area/station/service/kitchen) "xHq" = ( /obj/machinery/door/airlock/security/glass{ name = "Brig Entrance" @@ -77368,6 +79033,11 @@ /obj/effect/mapping_helpers/airlock/access/all/security/entrance, /turf/open/floor/iron, /area/station/security/brig/upper) +"xHv" = ( +/obj/structure/table/wood, +/obj/effect/spawner/random/trash/janitor_supplies, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "xHE" = ( /obj/structure/stairs/east, /turf/open/floor/plating, @@ -77379,6 +79049,10 @@ }, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/maint) +"xIh" = ( +/obj/effect/spawner/random/structure/tank_holder, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "xIk" = ( /obj/structure/chair/comfy{ dir = 4 @@ -77449,10 +79123,6 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/white, /area/station/maintenance/port/fore) -"xJF" = ( -/obj/structure/flora/bush/flowers_yw/style_random, -/turf/open/floor/grass, -/area/station/service/hydroponics) "xJG" = ( /obj/machinery/light/directional/east, /turf/open/openspace, @@ -77483,6 +79153,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/engineering/supermatter/room) +"xJW" = ( +/turf/open/floor/iron/half, +/area/station/service/hydroponics) "xKb" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/window/reinforced/spawner/directional/south, @@ -77517,9 +79190,26 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/external, /turf/open/floor/plating, /area/station/maintenance/starboard/upper) +"xKq" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/landmark/event_spawn, +/turf/open/floor/stone, +/area/station/service/bar/atrium) "xKJ" = ( /turf/closed/wall, /area/station/command/meeting_room) +"xKT" = ( +/obj/machinery/camera/directional/west{ + c_tag = "Dormitory South" + }, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 8 + }, +/obj/machinery/light/directional/west, +/turf/open/floor/iron, +/area/station/commons/dorms) "xKX" = ( /obj/effect/turf_decal/trimline/dark_green/arrow_ccw{ dir = 6 @@ -77657,10 +79347,6 @@ /obj/effect/landmark/blobstart, /turf/open/floor/engine, /area/station/science/xenobiology) -"xNk" = ( -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) "xNn" = ( /obj/effect/turf_decal/stripes/line{ dir = 5 @@ -77698,12 +79384,65 @@ }, /turf/open/floor/iron/dark, /area/mine/mechbay) +"xOd" = ( +/obj/structure/minecart_rail{ + dir = 6 + }, +/obj/structure/cable, +/obj/effect/turf_decal/weather/snow/corner{ + dir = 10 + }, +/obj/structure/sign/warning/directional/west, +/turf/open/floor/plating/snowed/coldroom, +/area/icemoon/underground/explored) +"xOi" = ( +/obj/machinery/door/window/left/directional/south{ + req_access = list("kitchen"); + name = "The Ice Box" + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/obj/effect/turf_decal/siding/white, +/turf/open/floor/iron/freezer, +/area/station/service/kitchen/coldroom) "xOl" = ( /obj/effect/decal/cleanable/cobweb/cobweb2, /obj/machinery/portable_atmospherics/canister/oxygen, /obj/machinery/atmospherics/components/unary/portables_connector/visible, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"xOE" = ( +/obj/machinery/navbeacon{ + codes_txt = "delivery;dir=8"; + location = "Bar and Kitchen" + }, +/obj/structure/plasticflaps/opaque, +/obj/effect/turf_decal/delivery, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/textured, +/area/station/maintenance/starboard/fore) +"xOV" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) +"xPf" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "xPu" = ( /obj/machinery/light/directional/east, /turf/open/misc/asteroid/snow/icemoon, @@ -77822,6 +79561,27 @@ /obj/structure/railing, /turf/open/floor/iron, /area/mine/production) +"xQS" = ( +/obj/effect/turf_decal/siding/white/end{ + dir = 8 + }, +/obj/structure/table, +/obj/item/reagent_containers/cup/bowl{ + pixel_y = 3 + }, +/obj/item/reagent_containers/cup/bowl{ + pixel_y = 8; + pixel_x = 3 + }, +/obj/item/food/grown/eggplant{ + pixel_y = 5; + pixel_x = 5 + }, +/obj/item/food/grown/mushroom/chanterelle{ + pixel_y = 3 + }, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "xQT" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply, @@ -77858,28 +79618,11 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/eighties/red, /area/station/security/prison/safe) -"xRV" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/sorting/mail{ - dir = 4 - }, -/obj/effect/mapping_helpers/mail_sorting/service/theater, -/obj/effect/mapping_helpers/mail_sorting/service/bar, -/obj/effect/mapping_helpers/mail_sorting/service/hydroponics, -/obj/effect/mapping_helpers/mail_sorting/service/kitchen, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "xRZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/light/small/directional/east, /turf/open/floor/iron/dark, /area/station/engineering/supermatter/room) -"xSj" = ( -/obj/machinery/light/directional/west, -/turf/open/floor/carpet, -/area/station/service/theater) "xSl" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -77897,11 +79640,6 @@ /obj/structure/cable, /turf/open/floor/iron/smooth, /area/station/security/brig) -"xSt" = ( -/obj/effect/spawner/random/structure/crate, -/obj/machinery/light/small/dim/directional/east, -/turf/open/floor/plating, -/area/station/maintenance/fore) "xSu" = ( /obj/structure/table/glass, /obj/machinery/reagentgrinder, @@ -77931,6 +79669,11 @@ }, /turf/open/floor/iron/large, /area/station/hallway/primary/port) +"xTi" = ( +/obj/effect/landmark/start/clown, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/grimy, +/area/station/service/theater) "xTp" = ( /obj/machinery/camera/directional/south{ c_tag = "Solar Maintenance - North East" @@ -77952,6 +79695,16 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/starboard/upper) +"xTI" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 4 + }, +/obj/machinery/firealarm/directional/south, +/turf/open/floor/iron, +/area/station/commons/fitness) "xTQ" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -77978,20 +79731,6 @@ }, /turf/open/floor/iron/dark, /area/station/science/ordnance/office) -"xTX" = ( -/obj/effect/turf_decal/siding/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/machinery/door/airlock{ - name = "Bar" - }, -/obj/machinery/duct, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/access/all/service/bar, -/turf/open/floor/iron/dark/textured_half, -/area/station/service/bar/backroom) "xUb" = ( /obj/effect/turf_decal/stripes/line{ dir = 10 @@ -78016,13 +79755,10 @@ }, /turf/open/openspace, /area/station/science/ordnance/office) -"xUm" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/tile, -/area/station/service/theater) +"xUt" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "xUw" = ( /obj/structure/sign/departments/maint/directional/west, /turf/open/floor/plating/snowed/smoothed/icemoon, @@ -78089,6 +79825,13 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron, /area/station/engineering/atmos) +"xVc" = ( +/obj/machinery/door/airlock{ + id_tag = "Toilet1"; + name = "Unit 1" + }, +/turf/open/floor/iron/textured, +/area/station/commons/toilet) "xVf" = ( /obj/structure/cable, /turf/open/floor/plating, @@ -78140,14 +79883,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/virology) -"xWa" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/machinery/holopad, -/obj/effect/landmark/event_spawn, -/turf/open/floor/wood/parquet, -/area/station/service/bar/atrium) "xWb" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/cable, @@ -78167,6 +79902,16 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/iron/freezer, /area/station/commons/toilet) +"xWI" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "kitchencounter"; + name = "Kitchen Counter Shutters" + }, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/white/smooth_large, +/area/station/service/kitchen) "xWM" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -78463,13 +80208,6 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/iron/showroomfloor, /area/station/security/prison/mess) -"yba" = ( -/obj/machinery/power/apc/auto_name/directional/east, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/freezer, -/area/station/commons/toilet) "ybf" = ( /obj/machinery/portable_atmospherics/pump, /turf/open/floor/iron/dark, @@ -78577,25 +80315,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/chemistry) -"ycw" = ( -/obj/machinery/door/firedoor, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/central) -"ycz" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/wood/tile, -/area/station/service/theater) "ycA" = ( /obj/effect/turf_decal/stripes/corner, /obj/effect/turf_decal/tile/blue{ @@ -78607,6 +80326,18 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/engineering/storage) +"ycE" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/sink/directional/east, +/turf/open/floor/iron, +/area/station/service/hydroponics) "ycQ" = ( /obj/structure/closet/crate, /obj/effect/spawner/random/maintenance, @@ -78666,6 +80397,12 @@ dir = 1 }, /area/mine/eva/lower) +"ydv" = ( +/obj/structure/chair/stool/directional/north, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/stone, +/area/station/commons/lounge) "ydA" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/event_spawn, @@ -78675,11 +80412,11 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/chapel) -"ydD" = ( -/obj/effect/spawner/random/structure/crate_abandoned, -/obj/machinery/light/small/directional/south, -/turf/open/floor/iron/smooth, -/area/station/maintenance/starboard/fore) +"ydG" = ( +/obj/machinery/status_display/ai/directional/east, +/obj/structure/chair/sofa/left/brown, +/turf/open/floor/wood/large, +/area/station/commons/lounge) "ydH" = ( /obj/structure/disposalpipe/segment, /obj/effect/decal/cleanable/glass, @@ -78701,12 +80438,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/station/hallway/primary/central) -"ydZ" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/chair/stool/directional/north, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "yef" = ( /obj/machinery/airalarm/directional/north, /obj/machinery/suit_storage_unit/industrial/loader, @@ -78723,15 +80454,6 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/cargo/miningdock) -"yej" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/turf/open/floor/plating, -/area/station/maintenance/starboard/fore) "yel" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -78748,11 +80470,6 @@ /obj/machinery/airalarm/directional/east, /turf/open/floor/iron, /area/station/commons/storage/mining) -"yey" = ( -/obj/effect/landmark/start/hangover, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/dark, -/area/station/medical/morgue) "yeB" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -78777,10 +80494,6 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/wood, /area/station/service/library) -"yfp" = ( -/obj/machinery/firealarm/directional/north, -/turf/open/floor/wood/parquet, -/area/station/commons/lounge) "yfz" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -78826,16 +80539,10 @@ /obj/effect/spawner/random/engineering/tracking_beacon, /turf/open/floor/iron, /area/station/command/gateway) -"ygw" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/sorting/mail/flip{ - dir = 1 - }, -/obj/effect/mapping_helpers/mail_sorting/service/hydroponics, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) +"ygy" = ( +/obj/effect/landmark/start/clown, +/turf/open/floor/wood, +/area/station/commons/lounge) "ygB" = ( /turf/closed/wall, /area/station/commons/dorms) @@ -78855,6 +80562,16 @@ }, /turf/open/floor/iron/smooth_half, /area/station/security/brig/upper) +"ygP" = ( +/obj/machinery/door/airlock/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/unres{ + dir = 1 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/fore) "yhe" = ( /obj/structure/cable, /obj/machinery/light/directional/south, @@ -78870,10 +80587,25 @@ /obj/structure/sign/warning/cold_temp/directional/east, /turf/open/floor/plating, /area/station/engineering/main) +"yhL" = ( +/obj/effect/mapping_helpers/broken_floor, +/obj/machinery/portable_atmospherics/canister, +/turf/open/floor/plating, +/area/station/maintenance/fore) "yhU" = ( /obj/structure/chair/stool/directional/north, /turf/open/floor/iron, /area/station/security/prison/work) +"yhV" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Bar Maintenance" + }, +/obj/structure/disposalpipe/segment, +/obj/effect/mapping_helpers/airlock/access/all/service/bar, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/service/bar/backroom) "yia" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -78922,6 +80654,16 @@ }, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"yjo" = ( +/obj/structure/sign/warning/directional/south, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/nospawn) +"yjr" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/wood, +/area/station/hallway/secondary/service) "yju" = ( /obj/structure/table, /obj/effect/spawner/random/maintenance/two, @@ -78936,24 +80678,17 @@ }, /turf/open/floor/plating, /area/station/science/xenobiology) -"yjP" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 9 - }, -/turf/open/floor/stone, -/area/station/commons/lounge) +"yjF" = ( +/obj/structure/sink/directional/east, +/obj/structure/mirror/directional/west, +/turf/open/floor/iron/freezer, +/area/station/commons/toilet) "yjV" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"yjX" = ( -/obj/machinery/power/apc/auto_name/directional/east, -/obj/structure/cable, -/obj/structure/chair/stool/directional/south, -/turf/open/floor/iron, -/area/station/hallway/primary/starboard) "ykb" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/blue{ @@ -78993,22 +80728,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) -"ykZ" = ( -/obj/effect/turf_decal/siding/wideplating/dark, -/obj/item/radio/intercom/directional/east, -/obj/machinery/duct, -/turf/open/floor/iron, -/area/station/service/hydroponics) -"ylk" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/sign/warning/cold_temp/directional/south, -/turf/open/floor/plating, -/area/station/maintenance/department/crew_quarters/bar) "ylt" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/pink/visible, /obj/structure/sign/poster/official/safety_internals/directional/east, @@ -116640,7 +118359,7 @@ dhq dhq iDt iDt -iDt +ssu iDt dLN rbT @@ -168390,21 +170109,21 @@ thA thA thA thA -thA -thA -thA -thA -xMq -ebd -iDt -iDt +dlu +dlu +dlu +dlu +dlu +dlu +dlu +dlu +qgQ +qgQ +rrl +nmO +ozW iDt -scw iDt -nfG -thA -thA -thA iDt iDt iDt @@ -168647,22 +170366,22 @@ thA thA thA thA -thA -thA -thA -thA -xMq -xMq +dlu +qbM +wvu +wvu +bPR +qbM +wvu +bil +ijY iDt iDt -ijY -xMq -thA -thA -thA -thA -thA -nfG +iDt +kJx +iDt +iDt +jZN iDt iDt iDt @@ -168904,22 +170623,22 @@ thA thA thA thA -thA -thA -thA -thA -thA -xMq -xMq -scw -xMq -xMq -thA -thA -thA -thA -thA -xMq +dlu +nEI +wvu +wvu +bPR +nEI +wvu +bil +iDt +iDt +iDt +iDt +kJx +iDt +iDt +iDt iDt scw cCb @@ -169161,23 +170880,23 @@ thA thA thA thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA +dlu +wvu +wvu +wvu +bPR +wvu +wvu +bil +iDt +iDt +ayJ +iDt +kJx +iDt +iDt +iDt +iDt iDt iDt iDt @@ -169418,23 +171137,23 @@ tjo thA thA thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -xMq -xMq +dlu +rEn +rEn +wvu +ghA +rEn +wvu +idH +iDt +iDt +iDt +iDt +kJx +iDt +iDt +iDt +iDt ijY iDt iDt @@ -169672,35 +171391,35 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA thA thA thA -xMq -xMq -xMq -xMq +dlu +wvu +wvu +wvu +wvu +wvu +wvu +wvu iDt iDt -scw iDt iDt +qSi +scw iDt +scw +scw +scw iDt scw +scw +iDt +rDN +sEv +scw +scw iDt iDt iDt @@ -169929,34 +171648,34 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo thA thA thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -psb -scw -psb +dlu +ncx +kYN +wvu +wvu +rzY +kYN +wvu +ayJ iDt -thA -thA -xMq -ijY -jZN +iDt +iDt +iDt +scw +scw +scw +scw +scw +scw +scw +oJD +oJD +scw +sed +nfG scw iDt iDt @@ -170186,34 +171905,34 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA -thA -thA -thA -thA -thA thA thA thA +dlu +wvu +wvu +wvu +wvu +wvu +wvu +wvu iDt -scw iDt +iDt +iDt +qSi +scw +scw scw iDt -thA -thA -thA -xMq -xMq +scw +scw +scw +kYo +oJD +oJD +scw +scw aRt aRt xMq @@ -170443,34 +172162,34 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA -thA -thA thA thA thA +dlu +xxH +xxH +wvu +jkK +xxH +wvu +mhj +iDt +iDt +iDt +iDt +kJx +iDt iDt iDt -psb -scw -psb iDt -thA -thA -thA -thA -thA +iDt +iDt +iDt +kYo +rIS +kYo +kYo +kYo iDt scw thA @@ -170700,33 +172419,33 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA -thA thA thA thA +dlu +wvu +wvu +wvu +bPR +wvu +wvu +bil +iDt +iDt +ayJ +iDt +kJx iDt iDt iDt daZ iDt iDt -thA -thA -thA -thA -thA +kPz +kYo +kYo +kYo +kYo iDt iDt iDt @@ -170957,28 +172676,28 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA thA thA thA +dlu +nEI +wvu +wvu +bPR +nEI +wvu +bil iDt iDt iDt iDt +kJx iDt iDt iDt -thA +iDt +iDt +kPz thA thA thA @@ -171214,24 +172933,24 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA -thA -thA thA thA thA +dlu +qbM +wvu +wvu +bPR +qbM +wvu +bil iDt iDt iDt iDt +kJx +iDt +iDt iDt iDt iDt @@ -171431,7 +173150,7 @@ pgL lab cbz yiL -rdR +iVu rnb hgM kyu @@ -171471,22 +173190,22 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA thA thA thA -thA -iDt -iDt -iDt +dlu +dlu +dlu +dlu +dlu +dlu +dlu +dlu +iDx +rrl +iDx +iDx +fQa iDt daZ iDt @@ -171728,18 +173447,18 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo thA thA thA thA thA +thA +thA +thA +thA +iDt +iDt +iDt iDt xPu iDt @@ -171986,16 +173705,16 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo thA thA thA thA +thA +thA +thA +thA +iDt +iDt iDt iDt aaD @@ -172243,18 +173962,18 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo +thA +thA +thA +thA +thA thA thA thA iDt iDt iDt +iDt alW wVz alW @@ -175838,7 +177557,7 @@ rcY iDt iDt xMq -iDt +ebd iDt iDt iDt @@ -176352,12 +178071,12 @@ chg iDt scw scw -hmb -hmb -hmb -hmb -hmb -hmb +xpO +gNu +gNu +gNu +gNu +oZk gjq gjq gjq @@ -176608,14 +178327,14 @@ iDt rcY scw scw -hmb -hmb -hlP -ahI -ahI -boV -hmb -hmb +xpO +gRE +nYR +hog +hog +joW +aqq +oZk gjq gjq gjq @@ -176865,14 +178584,14 @@ iDt rcY scw xMq -hmb -hlP +anI +lLR eYX sCZ sCZ -lmm -boV -hmb +qMO +dVj +anI gjq gjq gjq @@ -177121,19 +178840,19 @@ iDt iDt xMq xMq +xMq exw -exw -ksO +nwC syE -eIY -pqx -hml -vkg -hmb -hmb +hcj +hcj +fat +tqr +exw +vDQ gjq gjq -ebX +wkV kNC jTf jTf @@ -177376,22 +179095,22 @@ thA iDt iDt iDt -xMq exw exw -kQW -fKy +exw +exw +wwg bdr -jHK -rhh -rdd -lmm -boV -hmb -hmb -iDt -qau -iDt +jUv +jUv +xOV +scr +exw +exw +gNu +gNu +exw +mPq iDt neM qau @@ -177633,23 +179352,23 @@ thA iDt iDt xMq -xMq -exw -oGn -qXz -gAy -rhR -ops -lEH -lgA -gAy -bqH -dIc -exw -hmb exw -tJb -gUF +jiD +utn +vnK +cCT +bdr +jUv +jUv +xOV +vhA +oYw +kRD +rJX +mgy +sIX +nrh +iDt neM qau xMq @@ -177890,23 +179609,23 @@ thA xMq xMq xMq -xMq exw -gAN -sCZ -sCZ -lmm -jOc -wOh -fKy -kWR -sCZ -bdr -rCh -reh -rCh -xuo -kDU +cmg +qrF +ncd +dNk +grO +iFQ +iFQ +bon +hFX +ave +exw +aBb +myS +exw +dNN +iDt iDt qau iDt @@ -178145,27 +179864,27 @@ xMq xMq xMq xMq -sBy -sBy -sBy -sBy +xMq +xMq +exw +quw +xJW +ncd +erE +mYn +mYn +byy +mYn +wPR +exw exw -fKd -gyw -sIh exw -stw -gXe -ieq -mow -oMG exw -hmb exw -lfR -jSM +mPq iDt -nqv +iDt +xlp scw fna iDt @@ -178397,26 +180116,26 @@ thA thA thA thA -thA xMq +xMq +sBy sBy sBy sBy sBy -cnr -aga -lvO exw -iUO -uhk -ivr -hmb -gmB -dXA -jqJ -oBl -hbT -hmb +qre +oZD +lHI +exw +rEt +iif +exw +ogu +pOK +kPY +hWv +urG neM iDt scw @@ -178654,26 +180373,26 @@ thA thA thA thA -thA xMq sBy -kDJ -cwd -uHa -gLo -oYc -lvc +sBy +dQp +rRu +xBs +lCv exw -ivr -gcm -cSc -hmb -eoq -ece -bSU -nVz -iNt -hmb +hPS +cYe +wSL +exw +mpU +mpU +tjA +hAK +pOK +txv +hWv +urG neM iDt iDt @@ -178910,28 +180629,28 @@ thA thA thA thA -thA xMq xMq sBy -lUy -teR -tiX -kZc -mYG -qfu -dMS -dMS -dMS -dMS -dMS -dMS -dMS -eWI -dMS -dMS -dMS -xMq +qTp +xTi +bpc +cag +cVW +exw +fBJ +fte +mkr +exw +tmb +tmb +exw +wME +tbd +exw +exw +gFX +psb iDt scw scw @@ -179165,30 +180884,30 @@ thA thA thA thA -xMq -xMq -xMq +thA +thA xMq xMq sBy -eSF -sWC -rrX -ibi -kzW -iMg -tnB -xpp -kSo -cjK -cjK -cjK -cjK -ygw -jTV -hEl -dMS +ghT +pXy +nqI +sBy +fbg +sBy +sBy +exw +exw +bwh +lyP +iDv +jMD +sCZ +obT +ozx +exw xMq +psb jTf jTf ork @@ -179422,30 +181141,30 @@ thA thA thA thA +thA +thA +xMq xMq -mdZ -mdZ -mdZ -mdZ -sBy -sBy -rzA -sBy sBy -qMe +kzU +vxY +sRf sBy -dMS -dMS -hyt -dMS -dMS -dMS -dMS -kSo -kmW -gEz -dMS +rZP +fkd +fbW +exw +exw +exw +jQM +etr +ekc +leg +oIQ +inN +exw xMq +psb xMq scw iDt @@ -179679,30 +181398,30 @@ thA thA thA thA +thA +xMq +xMq xMq -mdZ -wUY -iZp -mdZ -qmN -pbD -let sBy -jjG -vlP -vuN -qMT -edD -ocf -rZT -jCF -acr -dMS -nCJ -dMS -dMS -dMS -dMS +azI +kSj +lyf +sBy +eFf +quJ +quJ +wGQ +nBZ +exw +tie +rxV +hjw +xFT +exw +bor +exw +psb +psb xMq iDt iDt @@ -179711,7 +181430,7 @@ scw btU xUf syW -dKt +jmJ hVX xUf eXH @@ -179936,37 +181655,37 @@ thA thA thA thA +thA xMq -mdZ -kgs -tGZ -tza -tGZ -tGZ -let -sBy -jWO -xUm -mRa -efh -ydZ -jBU -mqr -mqr -reA -dMS -rZN -cjK -cjK -sAc -dMS +xMq +qMT +qMT +qMT +qon +qMT +qMT +rZP +quJ +quJ +jZc +nBZ +exw +tec +phr +aTk +tec +exw +mxY +xOd +ubi +psb xMq xMq iDt iDt iDt ioK -jvw +vtW bja jvw jvw @@ -180185,8 +181904,10 @@ tjo tjo tjo tjo +iDt tjo -tjo +thA +thA thA thA thA @@ -180194,38 +181915,36 @@ thA thA xMq xMq -mdZ -nIL -uWv -let -let -let -let -sBy -pjg -ycz -hJm -kwu -lrN -jBU -eDi -doJ -bIH -dMS -dre -dMS -hHU -nCJ -dMS +qMT +jlv +emw +rqG +bOZ +gGS +rZP +quJ +imI +qMT +exw +exw +pLu +tnJ +dJF +rzq +exw +exw +bpa +psb +psb xMq xMq iDt iDt iDt ioK -rZX -bja +jEA bja +rlA jvw bja kRH @@ -180442,38 +182161,38 @@ tjo tjo tjo tjo -tjo +iDt tjo thA thA thA thA thA +thA xMq xMq -mdZ -gxZ -hNi -mdZ -mdZ -sBy -sBy -sBy -hSb -tEf -kHk -fqK -cjj -vdI -eDP -oko -dMS -dMS -dMS -dMS -dMS -nCJ -dMS +xMq +qMT +dEc +ygy +nfK +wTl +sWS +ydv +aBj +sLm +dTx +exw +jbB +qfI +kcw +mXW +gAw +ktq +exw +phl +ubi +psb xMq xMq nfG @@ -180482,7 +182201,7 @@ xMq btU btU btU -whl +qbG ako hjM hjM @@ -180692,14 +182411,14 @@ tjo tjo tjo tjo +iDt tjo tjo tjo tjo tjo -tjo -tjo -tjo +luR +iDt tjo thA thA @@ -180708,29 +182427,29 @@ thA thA thA xMq -mdZ -jXD -mCX -pwB -mdZ -kfX -xSj -oXk -tiF -cSu -ebq -phU -fjC -nrt -shD -jfN -dMS -bwL -dYO -bwL -dMS -otj -dMS +xMq +xMq +qMT +izU +nYN +iDK +nYN +gGS +ydv +oru +dtc +sXU +rbU +nLd +nLa +gnE +gnE +qHs +wIx +exw +phl +cem +psb xMq xMq xMq @@ -180739,7 +182458,7 @@ xMq btU kCR btU -yey +ocp dYr nxM dTm @@ -180949,14 +182668,14 @@ tjo tjo tjo tjo +iDt +iDt tjo tjo tjo tjo -tjo -tjo -tjo -tjo +nlA +iDt tjo thA thA @@ -180965,29 +182684,29 @@ thA thA thA xMq -mdZ -xdf -mCX -lPN -mdZ -sGi -uQY -uQY -rLV -wJe -rLV -iXF -doJ -vdI -uRz -aak -dMS -vJL -iSi -fsr -fEj -nCJ -dMS +qMT +qMT +qMT +qMT +kJG +eeY +ipg +mlN +rZP +lyU +pMh +aAy +rbU +nLd +ivp +gnE +gnE +kPh +dZL +exw +phl +fuH +psb fuH fuH fuH @@ -180996,7 +182715,7 @@ btU btU sGf lca -kme +uTf dYr nxM nxM @@ -181206,14 +182925,14 @@ tjo tjo tjo tjo +iDt +iDt +iDt +iDt tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo +iDt +iDt tjo thA thA @@ -181222,29 +182941,29 @@ thA thA thA xMq -mdZ -fjm -mCX -pmg -etV -doJ -lGY -rPf -csg -oXS -gUB -xqv -doJ -wZq qMT -qMT -dMS -fkJ -hHU -hHU -dMS -nCJ -dMS +jFY +wVI +aVJ +keM +ePZ +mRv +rZP +qal +oru +vXM +gYk +exw +pSX +rdv +gNw +aUq +aIA +hfY +exw +phl +fuH +psb fuH fuH fuH @@ -181463,13 +183182,13 @@ tjo tjo tjo tjo +iDt +iDt +iDt +iDt tjo -tjo -tjo -tjo -tjo -tjo -tjo +iDt +iDt tjo tjo thA @@ -181477,31 +183196,31 @@ thA thA thA thA +thA xMq -xMq -mdZ -cId -ksL -mdZ -mdZ -yfp -gUB -csg -lXo -dkO -qis -wIF -qis -uLU -uac -cBL -dMS -dMS -dMS -dMS -dMS -nCJ -dMS +qMT +jkN +qeW +quJ +mxh +aBj +klJ +ruQ +klJ +sgz +rlE +jre +jre +jre +oac +sGn +hpK +cNL +exw +exw +bpa +psb +psb fuH fuH fuH @@ -181535,7 +183254,7 @@ scw ilN vIZ nxM -bgd +bPk kmM sYU iio @@ -181719,14 +183438,14 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo +iDt +iDt +iDt +iDt +iDt +iDt +iDt +pOl tjo tjo tjo @@ -181734,34 +183453,34 @@ thA thA thA thA +thA xMq -xMq -mdZ -shh -agt -ryO -mdZ -iyb -doJ -qis -qis -qis -qis -doJ -nJC -cgz -doJ -vZY -dMS -dyw -sEp -sEp -sEp -jWp -dMS -dMS -fwB -fwB +qMT +bcf +vEC +lvv +efS +aXu +gPB +hEV +djl +bOn +jre +jre +igu +jre +jre +jre +fWd +jre +jre +fuH +phl +ubi +psb +fuH +fuH +fuH btU btU btU @@ -181975,50 +183694,50 @@ tjo tjo tjo tjo +iDt +iDt +iDt tjo +iDt +iDt +pOl +iDt +edM tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo +thA thA thA thA thA xMq -mdZ -mdZ -fpW -agt -wJf -mdZ -rKd -rJL -nVX -uEE -nvt -yjP -hzQ -hzQ -nro -hzQ -tyj -dMS -dEB -dMS -dMS -dMS -dMS -dMS -fwB -fwB -fwB +jre +jre +dvZ +jre +jre +ydG +qfr +oVr +hFj +jre +jre +nla +qhV +rhS +rhS +int +kWG +xEP +jre +pJq +phl +bdX +psb +fuH +fuH +fuH btU nTA kJm @@ -182232,50 +183951,50 @@ tjo tjo tjo tjo +pOl +iDt tjo tjo +iDt +iDt +iDt +ijY +iDt tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo +thA thA thA thA thA xMq -mdZ -exY -shh -cvz -ihG -mdZ -gRl -nJC -mui -doJ -yjP -eIa -wun -dOQ -lZG -fDt -hCN -dMS -dEB -dMS -jBB -pKe -rZK -qPE -fwB -fwB -fwB +xMq +jre +uBD +lcm +jre +jre +jNe +jNe +jre +jre +nla +vkO +pjk +eqk +nla +ukt +acG +jre +jre +gSU +phl +hvi +psb +fuH +fuH +fuH btU wvL jnY @@ -182398,141 +184117,141 @@ tjo tjo tjo tjo -tjo -tjo -tjo -"} -(148,1,2) = {" -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -ovP -xMq -gjq -gjq -gjq -gjq -gjq -gjq -gjq -xMq -thA -thA -thA -ovP -ovP -ovP -ovP -ovP -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo +tjo +tjo +tjo +"} +(148,1,2) = {" +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +ovP +xMq +gjq +gjq +gjq +gjq +gjq +gjq +gjq +xMq +thA +thA +thA +ovP +ovP +ovP +ovP +ovP +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +tjo +iDt +iDt +tjo +tjo +tjo +iDt +iDt +iDt +iDt +iDt +tjo +tjo +tjo +thA thA thA thA thA xMq -mdZ -xDr -esn -agt -auN -mdZ -nWw -mUU -csg -doJ -skV -tCT -pOJ -bIW -vLx -hkl -jyh -dMS -dEB -dMS -jBB -mQk -mCb -wMP -fwB -fwB -fwB +xMq +jre +sJu +fWE +tjs +qFD +qFD +rhS +rhS +wQx +vHe +dZC +jre +vBt +jre +jre +jre +jre +drw +drw +bpa +psb +psb +fuH +fuH +fuH btU mtt tHe @@ -182745,16 +184464,16 @@ tjo tjo tjo tjo +iDt tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo +iDt +iDt +iDt +iDt +pOl tjo tjo tjo @@ -182763,33 +184482,33 @@ thA thA thA xMq -mdZ -mdZ -shh -agt -mYr -mdZ -hLw -nJC -jBb -nJC -wZK -wNQ -lPm -men -eLx -iDg -jHE -dMS -ylk -dMS -tWD -klY -mQk -fwB -fwB +xMq +xMq +jre +nIY +jwf +cdO +ply +gEt +gwb +tOC +ubp +mUW +jre +jre +vKT +rng +qjd +vyy +oRf fwB -btU +drw +nbl +psb +fuH +fuH +fuH +fuH btU iWN ofm @@ -183008,10 +184727,10 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo +iDt +iDt +iDt +iDt tjo tjo tjo @@ -183021,32 +184740,32 @@ thA thA xMq xMq -mdZ -veL -agt -ryO -mdZ -sxW -doJ -wkq -doJ -lSl -aTm -fYh -oXe -miR -nmS -vUi -dMS -twX -gsW -czm -fpb -fLa -fwB -fwB -fwB -fwB +jre +jre +jre +jre +iRS +jre +jre +jre +jre +jre +jre +jre +bvc +rXB +udR +tkY +liv +liv +tkY +jKL +rpJ +psb +fuH +fuH +fuH +fuH btU waH qnv @@ -183069,7 +184788,7 @@ ffQ xDb clI iDt -pDR +pco iDt xMq xMq @@ -183265,45 +184984,45 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo +iDt +iDt +iDt +iDt tjo tjo tjo thA thA thA -thA xMq xMq -mdZ -bmw -oRw -mdZ -mdZ -rxY -rxY -rxY -vKC -rxY -fzK -bjZ -tAe -mgR -qYo -xFv -dMS -eHW -dMS -fUn +jre +jre +uye +ohk +aAk +nNe +xHv +qbY +jre +nmi +aoi +ssm +fpt +mQk +qKw mQk -oLV fwB fwB fwB fwB +drw +qEh +psb +fuH +fuH +fuH +fuH btU gfy olO @@ -183523,43 +185242,43 @@ tjo tjo tjo tjo +iDt +iDt +iDt +iDt +iDt tjo -tjo -tjo -tjo -tjo -tjo -thA thA thA thA xMq xMq -mdZ -jXD -mCX -let -let -kWs -uFW -lDp -nNQ -pNp -xTX -ikT -qCz -gQj -xoq -dMS -dMS -kbU -dMS -fvs +jre +iDB +mPQ +wSs +kfk +wjR +fMu +nla +jre +nMC +fpm +kBO +jBB +mQk +lEn +mQk mQk -dbb -fwB fwB +nRy fwB +drw +cQV +psb +psb +fuH +fuH btU btU amq @@ -183781,42 +185500,42 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -thA +iDt +iDt +ebd +iDt +iDt thA thA thA xMq xMq -mdZ -bEp -tGZ -tGZ -gVn -aNR -idE -uzc -iHy -rVO -xGZ -ukw -umS -vVh -mXt jre -tjs -vbz +wEq +ezd +nla +uxU +bRx +ayY +nla jre -xei -pAM -hun -fwB -fwB +lHr +fQs +xOi +mQk +mQk +riM +mQk +fLa +eaM +cqs fwB +drw +xxo +gcB +psb +fuH +fuH btU dzr rcU @@ -184039,41 +185758,41 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -thA -thA +iDt +pOl +iDt +iDt thA thA thA xMq -mdZ -vKn -tGZ -tGZ -gVn -rxY -dmD -mnE -xEx -jjW -jre -tRA -jre -hYs -jre +xMq jre +mMI +cBJ +nla +kRj nNe +ovZ +pGg jre -jre -lOt -nep -ksK -fwB -fwB +lHr +njz +qYC +qOB +mQk +bLf +hAS +lJc +xbB +gxz fwB +drw +xxo +cem +psb +fuH +fuH btU gCG cge @@ -184298,39 +186017,39 @@ tjo tjo tjo tjo -tjo -tjo -thA -thA +iDt +iDt thA thA thA xMq -mdZ -mdZ -kgs -tGZ -kdD +xMq jre jre +xnf +rdq +aAk +nNe +hnK +rXY jre jre +tWY jre jre -xjj jre +twS jre jre -lAB -lqs jre -xhz -kAD -wYs -ksK -ksK -fwB -fwB +jre +drw +drw +xxo +fuH +psb +fuH +fuH btU cJa fDp @@ -184556,36 +186275,36 @@ tjo tjo tjo tjo -tjo -thA -thA +iDt +iDt thA thA thA xMq xMq -mdZ -mdZ -vxx -eaB -fwf -tlr -tlr -cND -fRG -fRG -tlF -cND -fRG -fRG -fRG -tlF jre -mrX -lYY -boK -ksK -fuH +jre +jre +jre +udf +jre +jre +jre +wOC +oYC +wSs +nla +cSO +hYt +nla +wSs +tes +jre +jre +jre +kFF +jre +jre fuH fuH btU @@ -184813,36 +186532,36 @@ tjo tjo tjo tjo -tjo -thA -thA -thA +iDt +iDt +iDt thA thA thA xMq xMq -mdZ -iQf -xqA -jre -jre -jre -diH +xMq jre +igu +kvT +pZO +jHL +jHL +jSp jre +jNe jre -eXU +tSO jre +dQN jre +cpO jre +gVs +hGg wSs +vTp jre -jre -jre -jre -jre -fuH fuH fuH fuH @@ -185069,40 +186788,40 @@ tjo tjo tjo tjo -tjo -thA -thA -thA -thA +iDt +iDt +iDt +iDt +iDt thA thA thA xMq xMq -mdZ -mru -iAa -mdZ -xMq jre -diH jre -rYT -lmB -cbS +kUW jre -gtj +eet dQN +kEr +jre +rYT +sOX +aGk +jre +jhu +jre +mza +awF wSs wSs wSs -wSs -wSs +xwx jre fuH fuH fuH -fuH xMq xMq thA @@ -185325,38 +187044,38 @@ tjo tjo tjo tjo -tjo -tjo -thA -thA -thA -thA -thA +iDt +iDt +iDt +iDt +iDt +iDt thA thA thA xMq -mdZ -qNc -lvu -mdZ xMq +xMq +jre +uiv +jre +jre jre -uOS -gAM +bzX +vpJ +gOd oTx -wDB -vyj +hIE jre vFg -vFg -vFg -xwx -vTp jre -irz jre -fuH +jre +vyN +jre +kUW +jre +jre fuH fuH xMq @@ -185581,33 +187300,33 @@ tjo tjo tjo tjo +iDt +iDt tjo -tjo -tjo -thA -thA -thA -thA thA +iDt +iDt +iDt +iDt thA thA thA xMq -tiY -aIB -aIB -tiY xMq jre -lvF +dla +jre +xMq jre -sDs -sib -cHR +gFt jre -kWa -djH +lvF +vUn +lvF jre +aLh +djH +uGY jre jre jre @@ -185838,22 +187557,22 @@ tjo tjo tjo tjo +iDt tjo tjo -tjo -thA -thA -thA -thA thA thA +iDt +iDt +iDt thA thA +iDt rcY scw -scw -scw -iDt +uNG +aIB +tiY xMq jre jre @@ -185868,7 +187587,7 @@ hMw jre xMq jre -nmg +dla jre iDt thA @@ -186100,14 +187819,14 @@ tjo tjo thA thA -thA -thA -thA -thA -thA -thA -rcY iDt +iDt +iDt +iDt +iDt +iDt +rcY +luR scw scw iDt @@ -186126,8 +187845,8 @@ jre xMq tiY aIB -tiY -iDt +dhH +grg iDt thA thA @@ -186358,12 +188077,12 @@ tjo thA thA thA -thA -thA -thA -thA -thA -mJZ +iDt +iDt +iDt +iDt +iDt +tHF scw iDt scw @@ -186616,10 +188335,10 @@ thA thA thA thA -thA -thA -thA -thA +iDt +iDt +iDt +iDt rcY tSs iDt @@ -186873,10 +188592,10 @@ thA thA thA thA -thA -thA -thA -thA +iDt +iDt +iDt +iDt xMq iDt scw @@ -187131,7 +188850,7 @@ thA thA thA thA -thA +iDt iDt iDt rcY @@ -187143,7 +188862,7 @@ iDt iDt iDt iDt -cCb +pOl iDt iDt iDt @@ -187652,9 +189371,9 @@ rcY iDt scw iDt -scw -scw -scw +jmo +keA +vQz iDt iDt scw @@ -187910,7 +189629,7 @@ iDt iDt iDt tBs -baj +dGZ tBs iDt iDt @@ -188424,7 +190143,7 @@ tBs tBs tBs tBs -tNA +rHR tBs tBs tBs @@ -188676,7 +190395,7 @@ xMq tBs pwv sAu -nsz +rqn tBs nHQ oik @@ -188693,7 +190412,7 @@ ebB efM pgo rcY -iDt +rSQ scw iDt iDt @@ -189209,9 +190928,9 @@ awy rcY iDt iDt -ubd -scw -ubd +svz +keA +ddv iDt iDt iDt @@ -189467,7 +191186,7 @@ qau iDt xMq wrX -xak +efN xCj xMq thA @@ -189981,7 +191700,7 @@ wrX wrX wrX wrX -dTv +pSP wrX wrX xMq @@ -193601,12 +195320,12 @@ thA thA rcY iDt -egf -egf -egf -egf -fSG -fSG +uIf +uIf +uIf +uIf +roW +roW bId gcy jJG @@ -193858,12 +195577,12 @@ thA thA rcY iDt -inb -keV -gWZ -wHd -izc -wHd +fCS +iwq +cuB +iCe +lgP +iCe vcH gnq xEF @@ -194115,12 +195834,12 @@ thA thA rcY iDt -inb -sDA -mYd -mIC -dJk -wPC +fCS +ocd +bqX +rmG +ryX +sqH qSk sbd rEh @@ -194372,12 +196091,12 @@ thA thA rcY iDt -inb -keV -nBV -iao -hKj -iao +fCS +iwq +evc +wKh +aEK +wKh odf sbd jaY @@ -231328,7 +233047,7 @@ nWf prE gDS aXY -cBj +iPR lJO hEI hEI @@ -237515,9 +239234,9 @@ ntK mQb bln jII -mpy -ycw -bmz +gMx +lsH +jJr qWZ qWZ qWZ @@ -237781,7 +239500,7 @@ grA fwQ nOH gxU -gZq +jJR ybv ybv ybv @@ -238533,11 +240252,11 @@ pfe aeQ mdX pfe -duq -pyW -stp -raL -rxA +ktK +fGr +olt +qSP +eSm pfe pfe jII @@ -238789,7 +240508,7 @@ fEC gMK fng rHc -kWK +oOt uog vVY uog @@ -238797,7 +240516,7 @@ uog nfU bzI uog -cNd +qzU mny dnq wmK @@ -239046,7 +240765,7 @@ vDb vvh vPC pvm -wxr +tJZ cvC kQc iYG @@ -239054,7 +240773,7 @@ kQc kOV kQc kQc -rki +kkr gOy gOy fKF @@ -239303,7 +241022,7 @@ eEZ nUJ qbA csB -kOF +stB tny dLo fBF @@ -239311,7 +241030,7 @@ xUU wYZ aKI xUU -nKG +avd qJV vBh fiE @@ -240599,9 +242318,9 @@ vXU drZ yfF jII -mpy -wtb -bmz +gMx +oas +jJr qWZ qWZ qWZ @@ -240856,7 +242575,7 @@ lBD jII jII jII -fzy +ifd xwC utR pAZ @@ -241111,9 +242830,9 @@ oTh ygB fEZ ygB -vWB -cDQ -kyL +hXm +fZO +uLR sNI bUH pAZ @@ -241365,12 +243084,12 @@ rMN alO alO qCI -sJk -uGa -rKe -iMo -iMo -mJD +xKT +alO +qhF +kVj +kVj +qsY xwC kKX pAZ @@ -241624,7 +243343,7 @@ iPm iPm iPm iPm -rzk +mVW hay cfr dct @@ -241879,12 +243598,12 @@ wVD uja uja uja -kMD +bsn uja uja uja uja -hcv +vdO vrX utR pAZ @@ -242135,13 +243854,13 @@ qIU keL uja jHG -dFP +yjF vVw -dFP +yjF qSh rKS uja -fpP +jcy iuv utR pAZ @@ -242391,14 +244110,14 @@ asa kCu gHj uja -ewd -ehm -yba -bwr -qKX +sfD +gjT +szK +upx +uOy hsB uja -dnq +ise iuv utR pAZ @@ -242649,7 +244368,7 @@ urd xTU uja aty -ehm +gjT uja uja uja @@ -242888,13 +244607,13 @@ lbk sDl sDl skl -pwx +yhL deY skl gDz xlH kbN -jOQ +dym skl ygB ygB @@ -242906,13 +244625,13 @@ maB fpa uja oiz -ehm +gjT uja kDz -chB +xVc twU uja -gQZ +bvu iuv dnq mny @@ -242922,9 +244641,9 @@ mny mny wVR mfW -kXE +toT mfW -sbT +aeF eta brp mfW @@ -243159,17 +244878,17 @@ ygB ybE eKJ ulk -nlI +rgM uja uja uja -eQN +jnh uja uja uja hsB uja -ise +uuh lyh iuv vrX @@ -243179,7 +244898,7 @@ iuv iuv iuv vrX -rpG +maX iuv xNF ylU @@ -243416,28 +245135,28 @@ ipx seH lvY mmA -vTA +apC uja vmp vmp -kxN +uNp uja oUO -oUG +hxB xWG uja -fbt -aPo -qnf -xzh -otQ -dnq -apb -dby -otQ -dnq -mpy -dnq +kyL +eph +kyL +kyL +jnU +rbh +kZm +njM +rbh +rbh +qPD +jIY dKW ylU lDo @@ -243660,11 +245379,11 @@ bln fsm bUx cCC -cBC -mgw +wph fnS skl -iHz +qpU +xsm jOQ skl pOo @@ -243672,32 +245391,32 @@ piC ygB fXo aos -rBn -sYb -nkM -nkQ -sjL -aMX +cUH +rfW +beF +vme +lrE +gUw uja uja uja hsB uja -hmb -eJq -mWp -exw -exw +mdZ +hMM +lEb +mdZ exw hmb -exw +hmb exw hmb hmb exw -ocj -hWP -ocj +tLF +gIf +dBA +gIf azw azw mao @@ -243916,20 +245635,20 @@ bUx bUx bUx bUx -wnq -dqv -cKn +maM +aXx fnS skl -mwH -fnS +eoV +npZ +qQV skl gmW gmW gmW ltV -mAz -oSk +tip +gxT ltV uja mqy @@ -243937,21 +245656,21 @@ mqy tUn uja jlP -mfz +azt twU uja -idw -eZj +eUC +yjr +nvw +nPS +eav +bBa +iiB +ycE iuE -bPg -uoz -kDP -kmQ -xgy -xgy -uTN -jBq -hmb +gWl +hKn +lHi lso dEV bai @@ -244167,26 +245886,26 @@ fhu bLI ykw skl +blX deY -rab -skl -dzx -tef skl +kQE +rab skl skl skl hDV skl byP -eXY -eNz -rjs -cdM -bXj -pSQ -rza -oBP +blX +eHX +ceU +bZU +efU +qfJ +seB +mcT +xwL bVI uja uja @@ -244197,18 +245916,18 @@ uja uja uja uja -pBr -csR -njn -pix -reh -joG -jVq -xgy -xgy -tbv -xJF -hmb +scG +cKJ +hJS +jMJ +nyj +fju +lvy +fLG +nxc +lgb +xre +lHi lso dEV bai @@ -244424,18 +246143,18 @@ ekW vRN fEA uHF -eqq -eqq +jyE +jyE qdK eqq +ejY eqq eqq eqq eqq +mkM eqq -eqq -eqq -pTf +fjO qvh skl erH @@ -244443,29 +246162,29 @@ ffZ vfW vfW mZK -dZB -uBt -coL -gmW -hnB -esu -hMk -jLn -oYH -eBi -duV -fKw -csR -vRE -weY -mpU -rFr -nAM -toH -toH -bEq -kHV -hmb +lvk +qiG +czo +kKL +rDI +kKL +uUw +cmK +css +rxY +cQp +dpj +uil +sHi +shh +tjA +xgy +xgy +ffr +nxc +lgb +uSE +hyQ lso dEV kHI @@ -244680,49 +246399,49 @@ aML iLv hSJ ykw -deY -deY -deY -deY -kQE -deY +fNz +wSc +blX +jee +blX +oCw fhz -deY +blX fhz -xNk +acg byP mOf -fhz -jPv +aYO +mOf skl -hYC +nJq eOl -vco -owU -owU -tkV -qwP -kOB -gmW -ofT -ePl -uDV -ojD -ykZ -vqD -keq -asJ -qYD -oUK -gEL +uOe +day +day +sRc +lPQ +szt +kKL +kKL +kKL +csZ +oPr +qGh +rxY +rra +iFz +nQm +ktY +gMi mpU -qFC -kTO -wvc -kTO -pXz -sIm -hmb +hbL +xgy +ivC +rRs +jik +lJW +lHi lso dEV bai @@ -244941,48 +246660,48 @@ rFP rFP rFP skl -rFP -rFP -rFP skl -xSt -deY +utW +kiI +skl +blX +tAt skl -eYL +qMD cQx -eYL +qMD skl eDy vfW -suE +qrM nUj mpH -xbc -nXn -wpV -gmW -uiw -hWh -hGI -tCs -exw -exw -exw -tqZ -kvs -glQ -exw -exw -exw +skQ +fyL +kcs +kKL +igH +yhV +dCV +gyP +utG +rxY +bzF +dXR +mdZ +mdZ +mdZ exw exw exw +kXS exw exw exw +tLF cwh dEV -pNx +whg azw eub eyc @@ -245192,51 +246911,51 @@ bln uFf bJE uFf -wNO -wNO -wNO -bln -bln bln +lBD bln bln +lBD bln skl +rWA skl -vXY skl -gfE -uBn -aut +gZV +ePd +skl +nSX +fgz +cnS skl cVa vfW -gMp +xqP iay dCF -xbc -nxY -eBk -gmW -exw -exw -hvr -exw -exw -jPa -mdZ -vlI -nHa -nHa -izC -hwM -aUY -igi -xbj -rdB +skQ +fYX +pYD +kKL +ddR +kKL +kKL +jZJ +pKo +rxY +fzK +wPe +fzK +jRA +rMm +sCX +sPS +vvn +xsy +wBr lEO -khA -lso +wqt +jae lso kjK bai @@ -245449,50 +247168,50 @@ bln uFf rXX uFf -wNO -wNO -wNO -bln -bln -bln -bln bln bln +mQb +ntK +mQb bln skl -xFi +bkM +oWV skl -ejg -nLg -ngH +lzc +jPv +osN +pfy +lzc +lZP skl -iMj -vfW -ewz -lDg -lDg -njx +aEx vfW -sfA -dIe -sUO -dIn -xFA -aTV -rQt -tGZ -bMu -iFc -mrF -iFc -bJA -mIB -uUV -fmD -fmD -fmD -wyQ -lso +cWz +cCe +cCe +kkb +lPQ +fsO +kKL +uLZ +jyN +kKL +mTL +uiV +ixp +edO +hjO +fzK +jRA +jRA +ptv +iBM +vYp +fWW +mMZ +bid +nzt lso lCi dEV @@ -245698,7 +247417,6 @@ wNO wNO wNO wNO -wNO bln bln bln @@ -245708,52 +247426,53 @@ bln bln bln bln -wNO -wNO -wNO -wNO bln bln bln bln +gDh skl -dOc -skl -skl +tSd skl skl +koj +deY +osN +hrd +vOd +mnn skl -iCQ +ruX vfW eOl vfW vfW lvk -lvk -xpo -gmW -whu -rtc -rtc -jJf -voM -etA -jFA -mnj -uVn -nnW -wvb -meB -meB -xWa -meB -meB +jiU +qVG +wpm +nBO +qPQ +kKL +kKL +llm +rxY +gFW +rrL +riB +nxj +gDY +crO +iBM +fVh +qlS +qSU hSq -mVh -mVh +pdC +pdC vwO hHg -bai +jyp azw uMx uTk @@ -245954,9 +247673,6 @@ wNO wNO wNO wNO -wNO -wNO -bln bln bln bln @@ -245965,51 +247681,54 @@ bln bln bln bln -wNO -wNO -wNO -wNO bln bln bln bln -sEB -sEB -sEB bln bln bln -gmW -uRo +aHh +ooL +skl +lsh +deY +deY +skl +edt +hqv +wHK +skl +mOH uRo uRo uRo nCu cZt cZt -cXN -gmW -jOY -tux -dsO -kQX -tGZ -mEZ -mdZ -jQo -dqd -bfZ -izC -bHG -rRy -rRy -mdy -fmD +qtG +kKL +lli +uar +gAt +kKL +nxw +fzK +kQx +poV +ahh +ezk +dzD +fwi +tsu +bpv +hLy +tsu lEO -aJh -lso -lso -aAa +far +cql +gVh +dEV bai azw nNU @@ -246211,8 +247930,6 @@ wNO wNO wNO wNO -wNO -wNO bln bln bln @@ -246222,11 +247939,6 @@ bln bln bln bln -wNO -wNO -wNO -wNO -bln bln bln bln @@ -246235,39 +247947,46 @@ bln bln bln bln +skl +fpF +deY +hJF +skl +skl +skl gmW gmW dGO dGO -vEi +tEs dGO dGO -vEi +tEs dGO dGO gmW -mdZ -gzw -kiB -kQX -kyZ -bFw -mdZ -rth -hid -mrF -ptO -jRA -jRA -jRA -ixH -aWI +gmW +tpZ +mGF +kKL +mcQ +gNc +gNc +oPd +qhQ +qhQ +wGm +ptv +iBM +cxT +nFQ +iEY ptO -ibI -lso -lso +wBa +cql +fqX dEV -bai +kIK azw pxV oQD @@ -246468,22 +248187,12 @@ wNO wNO wNO wNO -wNO -wNO -bln -bln -bln bln bln bln bln bln bln -wNO -wNO -wNO -wNO -bln bln bln bln @@ -246491,7 +248200,17 @@ bln bln bln bln +fsm bln +uer +yjo +skl +skl +qiL +qiL +skl +fsm +tlH gmW knl knl @@ -246503,28 +248222,28 @@ knl knl knl knl -mdZ -gzw -kiB -kQX -tGZ -nYQ -mdZ -hvl -hid -iFc -izC -jRA -jRA -jRA -fZo -nGz +gmW +ijw +bRO +kKL +vto +kVo +jrv +qJy +iew +pqZ +wGm +ptv +iBM +fXF +nFQ +jxr izC -yjX -mqq -mqq +tNH +vbI +gVh kjK -bai +arZ azw mwF sbc @@ -246652,71 +248371,8 @@ wNO wNO wNO wNO -"} -(143,1,3) = {" -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -bln -bln -lBD -bln -bln -bSz -bSz -vbG -hHG -hHG -hHG -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO +"} +(143,1,3) = {" wNO wNO wNO @@ -246729,13 +248385,61 @@ wNO wNO bln bln +lBD bln bln -bln -bMz -bln -bln -bln +bSz +bSz +vbG +hHG +hHG +hHG +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO wNO wNO wNO @@ -246747,9 +248451,24 @@ bln bln bln bln +bMz bln bln -gmW +bln +bln +bln +bln +bln +stJ +bln +bln +skl +qjn +iRa +skl +tlH +tlH +dGO knl knl aBf @@ -246760,28 +248479,28 @@ knl knl knl knl -mdZ -mdZ -nsf -dCk -wBR -mdZ -iWr -iWr -jgh -aoP -izC -eEz -izC -izC -eEz -izC -izC -tLF -lso -qGV +dGO +ksR +rEH +kKL +giH +qiA +uiq +iPP +iew +qhQ +wGm +fwi +tsu +tZo +cxD +tsu +lEO +szj +vbI +gVh dEV -jyp +bai hgh czS fVo @@ -246983,21 +248702,6 @@ wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO bln bln bln @@ -247006,7 +248710,22 @@ bln bln bln bln -gmW +bln +bln +bln +bln +bln +bln +bln +bln +bln +gbM +iRa +iRa +gbM +tlH +tlH +dGO knl knl knl @@ -247017,30 +248736,30 @@ aBf knl knl knl -mdZ -qqx -shh -fgE -oSI -mdZ -umv -pyj -lnq -hnf -vlq -rga -vbb -pxs -iAJ -afv -ihf -uMu -lso -lso -dEV -bai +dGO +uar +bXb +kKL +xFz +jFu +qRF +tbE +iew +kea +wGm +ptv +iBM +gkH +rji +oqB +oNN +kGD +kGD +rbE +woX +jyp hgh -gca +qit xxg nDl uau @@ -247241,20 +248960,6 @@ wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO bln bln bln @@ -247263,7 +248968,21 @@ bln bln bln bln -gmW +bln +bln +bln +bln +bln +bln +tlH +tlH +gbM +iRa +iRa +gbM +tlH +tlH +dGO knl knl knl @@ -247274,30 +248993,30 @@ knl knl knl knl -mdZ -tvI -shh -hBR -bxv -mdZ -kfY -fqc -rDF -sHB -rDF -sHB -chj -iqL -rDF -sHB -eBa -laP +dGO +uar +wla +kKL +eTT +ohP +kqo +qJy +iew +sBY +wGm +ptv +iBM +dpw +qMS +oVn +cKp +hKL lso -rvZ +jqZ dEV bai xjg -mUR +wiO mnF lKZ xGh @@ -247498,28 +249217,28 @@ wNO wNO wNO wNO +bln +bln +bln +bln wNO wNO wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -bln -bln -bln -bln -bln bln bln bln +tlH +tlH +tlH +uUq +gHL +iRa +gbM +tlH +tlH gmW xPW knl @@ -247531,26 +249250,26 @@ knl knl knl hNx -mdZ -lyW -shh -fgE -shh -mdZ -gsD -sHB -trl -nGb -rDF -sHB -rDF -cQv -rxK -cQv -qjK -ehA -avb -avb +gmW +sDM +gAt +kKL +xcO +fco +fco +gua +qhQ +qhQ +wGm +xtH +xKq +umc +aGf +rvO +lEO +uLJ +reX +mqq vSa fuY clK @@ -247756,6 +249475,8 @@ wNO wNO wNO wNO +bln +bln wNO wNO wNO @@ -247764,20 +249485,18 @@ wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO -bln -bln -bln -bln bln bln -bln -bln -gmW +tlH +tlH +tlH +uUq +gHL +gHL +uUq +tlH +tlH +dGO knl knl knl @@ -247788,26 +249507,26 @@ knl aBf knl knl -mdZ -qqx -shh -fgE -shh -mdZ -uOH -rDF -rSK -jfZ -gyr -xdA -gyr -xdA -gyr -xdA -sSh -uMu -lso -lso +dGO +gdK +qgT +kKL +kKL +kKL +kVq +pgv +uGe +byO +qMI +pba +ion +sft +pNi +eVi +izC +izC +tLF +jgd qEM lso dCs @@ -248013,6 +249732,8 @@ wNO wNO wNO wNO +bln +bln wNO wNO wNO @@ -248021,20 +249742,18 @@ wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO -bln -bln -ozo -bln bln bln bln +tlH bln -gmW +uUq +gHL +gHL +uUq +tlH +tlH +dGO knl knl knl @@ -248045,25 +249764,25 @@ knl knl knl knl -mdZ -mdZ -tDv -lqB -skf -mdZ -btp -ggD -lBy -cpY -pxF -iYi -iYi -iYi -iYi -ifw -cpY -cpY -rjP +dGO +uar +lli +dwq +any +kKL +vSu +iUi +fzK +orZ +gVX +dSs +dSs +dSs +iCS +vVA +gYN +izC +gdO lso vwO lso @@ -248270,6 +249989,8 @@ wNO wNO wNO wNO +bln +bln wNO wNO wNO @@ -248278,20 +249999,18 @@ wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO -bln -bln -bln bln bln bln bln bln -gmW +kKL +oEC +gHL +kKL +tlH +tlH +dGO knl knl knl @@ -248302,26 +250021,26 @@ knl knl knl knl -mdZ -wEa -tki -kQX -vLn -mdZ -gHR -lxf -eBa -qZB -ftM -gtw -gtw -gtw -gtw -gtw -uqB +dGO +xPf +lRs +tml +kKL +kKL +aft +jsR cpY -cGZ -lCi +cpY +rEY +xWI +wuc +qod +xWI +pLo +cGI +cpY +tLF +ivJ vwO pxn xjg @@ -248527,11 +250246,8 @@ wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO +bln +bln wNO wNO wNO @@ -248542,12 +250258,15 @@ wNO wNO bln bln -bln -bln -bln -bln -bln -bln +fsm +yjo +kKL +kKL +odZ +odZ +kKL +tlH +tlH gmW knl knl @@ -248559,28 +250278,28 @@ knl knl knl knl -mdZ -aWS -tGZ -ayk -vQN -mdZ -acx -xlv -oDm -qZB -gtw -xHi -aHZ -jwv -pYI -mVY -bmf +gmW +uar +hNK +bfy +kKL +pOC +ncc +syd cpY -tLF -cwO +gDB +sJg +sJg +sJg +sJg +sJg +sJg +kqP +cpY +lkr +lso vwO -qnU +nCz nKa dqO icA @@ -248783,61 +250502,61 @@ wNO wNO wNO wNO +bln +bln +bln +bln wNO wNO wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -bln -bln -bln -bln bln bln bln +efv bln +kKL +xIh +lli +eEr +kKL +kKL +kKL gmW gmW gmW gmW -vEi +tEs dGO dGO -vEi +tEs gmW gmW gmW -mdZ -mdZ -fCY -kQX -qaf -mdZ -ptp -ggD -ifg -qZB -gtw -xHi -vMq -eUw -jZt -jSm -cMs +gmW +kav +lCO +oEe +omS +mTA +nbO +hxY cpY -lkr +aMI +arW +fkk +fkk +fkk +fkk +spj +pBS +vrw +jlT lso vwO -nFm +dKf nKa kyW wKe @@ -249040,21 +250759,8 @@ wNO wNO wNO wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO bln +lSu bln bln bln @@ -249064,37 +250770,50 @@ bln bln bln bln +stJ bln +gsK +kKU +kKL +cvF +xUt +lli +kKL +gDL +iyY +tlH +vww +tlH dGO iyg hHq -kXu -qIP +aNj +xTI gmW -hGf -bln -bln -mdZ -byk -rrx -nIr -mdZ -fRJ -lxf -son -qZB -gtw -kpf +abm +qyZ +kKL +emF +pwz +kKL +kKL +vfw +xqa +rAx +skH +cdX +sHs +xQS xbn -qDZ -eke -enG -bpG -oKb -uXm +tnz +gcf +gtw +iZD +vrw +sLy lso qEM -mbk +pJC nKa dhk cDT @@ -249295,60 +251014,60 @@ wNO wNO wNO wNO -wNO -tCr -mVm -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -bln -bln -bln -bln -bln -bln -bln -bln -bln -bln -bln -dGO -vKE -uNA -kXu -dNZ -gmW -bln +reu +jas +jas +bYx +hzw +ike +jas +bYx +jas +jas +jas +bYx +jas +jas +cQE kKL +aPP kKL kKL +xea +isj +gBs +lyv +iyY +tlH +tlH +tlH +dGO +ubK +uRo +aNj +udA +gmW +gAG +wWB kKL -mKh -kKL +ddJ +rbp kKL -hBc -xlv -iXH -qZB -oEh -kpf +eGg +dSY +vlz +vlz +nvc +hXD +mMi +xnc gtw -qfe -ecZ -enG -qIv -oKb -reM +dpa +vlU +gtw +iZD +vrw +krE lso cbs nGA @@ -249552,12 +251271,7 @@ wNO wNO wNO wNO -wNO -tCr -bln -bln -bln -bln +ngh bln bln bln @@ -249567,45 +251281,50 @@ bln bln bln bln -tCr -bln -bln -bln -bln -bln -bln bln bln bln bln bln +kKL +aXv +bSi +kKL +acm +tDy +kKL +tts +iyY +tlH +tlH +tlH dGO -lQV -vKG -kXu -jKV +nOI +uRo +aNj +xBS gmW -bln +akb +xQU kKL -bgG -kum kKL -hfh -bQr -vSr -gtc -usI -son -skp -eDx -fkk -aEU -fMP -fMP -oyV -nqL -oKb -uXm +qDk +kKL +gmt +cgd +kKn +vlz +lMe +gbC +vAW +cki +cki +gtw +gtw +aHZ +qWf +vrw +jlT lso qEM xwz @@ -249809,8 +251528,7 @@ wNO wNO wNO wNO -wNO -tCr +ngh bln uei tmR @@ -249824,48 +251542,49 @@ uei tmR uei bln -tCr -bln -bln bln -bln -bln -bln -sEB +kKL +aPP +kKL +kKL +jRt +fTn +kKL +kKL +kKL +mMb mMb -rMa mMb kKL kKL +iyY +fvm kKL kKL -qoz kKL +rCf +hlt kKL +iqA kKL kKL -tFf -baq +tUm kKL -lli -iCC kKL -fbm -bQP -llG -bzn -fyh -mzs -wKm -pAp -haN -kqA -tUS cpY -ivB +nvh +hDu +eLv +nbI +oaJ +rqQ +fhS +pAn +cpY +bao lso brj -pJC +mbk vBG dkg tLp @@ -250066,8 +251785,7 @@ wNO wNO wNO wNO -wNO -tCr +vHT bln uei tmR @@ -250082,47 +251800,48 @@ tmR uei bln bln -bln -bln -bln -bln -bln -bln -sEB -qSB -lli -oop -lli -lli -lli -lli +mMb +hAW +jVm +sON +sON lRZ -lli -lli -lli +lRZ +ygP +lRZ +wco +lRZ +lRZ +wco +leP +lRZ +lRZ +rmR +vXm bMF -ojV -fYe +pns +uMj kKL -lli -lAG +xUt +fKk kKL +xOE kKL kKL kKL kKL kKL kKL -mgN +nXs kKL kKL kKL kKL kKL kKL -rqT -pfB -gBq +oFB +opH +oFB vBG rMS pKw @@ -250323,8 +252042,7 @@ wNO wNO wNO wNO -wNO -tCr +ngh bln uei tmR @@ -250339,45 +252057,46 @@ tmR uei bln bln -bln -bln -bln -bln -bln -bln -sEB -mMb -vLk kKL +kKL +tOe +rkm +fEY +nDm +kda +kKL +xUt +xUt +lli +xUt lli -xAb -cvF -gGF -ssM kKL -gAt +tbK +ssM lli +jRt kKL kKL kKL kKL lli -xRV -oDJ -pCi -kKL -uZL -tBN -aKG +xUt +lli +vYY +imk +feV +sus +tIL +nVO kKL -cSQ +tvZ kKL -kKl -beT -nwI -giD +vEh +nTP +kbu +bcu kKL -bws +lso vwO pxn vBG @@ -250580,8 +252299,7 @@ wNO wNO wNO wNO -wNO -bln +ngh bln uei tmR @@ -250595,44 +252313,45 @@ uei tmR uei bln -bln -bln -bln -bln -bln -bln -bln -bln +lBD bln kKL -qzN -gGF kKL kKL -tml +mMb +kKL +kKL +kKL +qUo +pjM +nLY +lli +gAt +kKL +lIC lRZ -tml -prf +pQa +eDD +nhv lli +pAW +jYI +mmf lli -pQa -mJr -lTJ -lBb -gZl -kKL -orf +uWf +xWM +brC kKL nqn lHA -hao +rfj kKL -cSQ +tvZ kKL -lli -lli -lli -xbf +iYY +iIv +dig +pbF kKL rjP qEM @@ -250834,11 +252553,10 @@ wNO wNO wNO wNO -wNO -tCr -tCr -tCr -bln +reu +xog +xog +raq bln uei tmR @@ -250852,7 +252570,8 @@ uei tmR uei bln -bln +fsm +lBD bln bln bln @@ -250862,34 +252581,34 @@ bxe bxe bxe mHB -lli -lli -lIC +kKL +gEl +kKL kKL aIE lRZ -lIC -kKL -tml +cCR lli -iIa -bcC -iIa -vYv -kKL -kKL -iOc -eAS -nNv -wPZ -fRP +mRN +xUt +gEZ +xUt +gEZ +lli +gEZ +xUt +unu +cOQ +vgU +kdw +qpQ kKL -cSQ +tvZ cDw lli lli lli -iZy +iXB kKL cwO vwO @@ -251091,239 +252810,134 @@ wNO wNO wNO wNO -wNO -tCr -bln -bln -bln -bln -bln -tmR -bln -bln -bln -tmR -bln -bln -bln -tmR -bln -bln -bln -bln -vsI -acE -acE -wtX -eqJ -bHS -oBQ -mHB -gUY -lli -lli -kKL -kKL -lRZ -yej -gHm -uDW -uDW -cHy -lli -pub -xWM -kKL -knW -xFj -kKL -wbZ -oTB -aOV -kKL -cSQ -kKL -vMR -lZv -hrt -fpA -kKL -iko -qEM -lso -bGT -vBG -wvW -moG -vBG -ayR -oMR -hsC -vBG -uSS -xrb -qhN -amE -lei -klc -pgY -hXU -oRu -hIe -uKj -dDw -fWn -qgu -tYA -vds -mrD -liz -rKX -mFE -nEc -klk -hsn -hyd -sSj -tMO -jYy -sZF -vwr -wRr -eZu -lcz -eZu -rHo -sZF -bFS -eZu -xpT -hEZ -sZF -kCh -eZu -sZF -sZF -vjZ -sZF -gar -bln -fBN -vYq -iAf -tUh -iNQ -cmX -iAf -iAf -iAf -bln -bln -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -"} -(161,1,3) = {" -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -otC -hHG -hHG -hHG -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO +ngh +bln +bln +bln +bln +bln +tmR +bln +bln +bln +tmR +bln +bln +bln +tmR +bln +bln +bln +bln +bln +vsI +acE +acE +wtX +eqJ +ktJ +oBQ +mHB +gUY +rmR +lli +kKL +kKL +lRZ +hfG +xUt +tNb +dge +oBJ +xUt +tNb +rNV +hrA +fkq +vIL +feV +lVN +bBn +bIq +kKL +tvZ +kKL +xGi +fce +jzR +fpA +kKL +tXg +qEM +lso +bGT +vBG +wvW +moG +vBG +ayR +oMR +hsC +vBG +uSS +xrb +qhN +amE +lei +klc +pgY +hXU +oRu +hIe +uKj +dDw +fWn +qgu +tYA +vds +mrD +liz +rKX +mFE +nEc +klk +hsn +hyd +sSj +tMO +jYy +sZF +vwr +wRr +eZu +lcz +eZu +rHo +sZF +bFS +eZu +xpT +hEZ +sZF +kCh +eZu +sZF +sZF +vjZ +sZF +gar +bln +fBN +vYq +iAf +tUh +iNQ +cmX +iAf +iAf +iAf +bln +bln wNO wNO wNO @@ -251349,7 +252963,111 @@ wNO wNO wNO wNO -tCr +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +"} +(161,1,3) = {" +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +otC +hHG +hHG +hHG +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wHr bln cnx tmR @@ -251369,36 +253087,37 @@ tmR tmR tmR tmR +tmR rUR kxv fIs kxv jju -tJP +lXC lFG -gxh +rlH gxh gxh gxh kKL gAt -orf +hfG gAt -lli -wQI +xUt +gPo kKL kKL mMb mMb kKL -cSQ +cjh kKL kKL kKL kKL kKL kKL -cSQ +tvZ kKL kKL kKL @@ -251605,8 +253324,7 @@ wNO wNO wNO wNO -wNO -tCr +ngh bln bln bln @@ -251625,6 +253343,7 @@ bln bln bln bln +bln sEB acE acE @@ -251636,10 +253355,10 @@ pDQ xBL wJM wJM -gxh +rlH kKL dnL -orf +hfG kKL pVl kKL @@ -251648,23 +253367,23 @@ kbp tlH tlH kKL -cSQ +diK kKL tlH tlH bln kKL -lqh -sEE -uKr -uKr -gxY +emx +vIL +fOg +kQH +snR asg kKL kdF qGV hUx -ikH +bSC sZF sZF sZF @@ -251862,11 +253581,10 @@ wNO wNO wNO wNO -wNO -tCr -mVm -tCr -muK +dqA +jas +jas +nIe bln uei tmR @@ -251880,8 +253598,9 @@ uei tmR uei bln +lBD bln -bln +lBD bln bln bln @@ -251896,7 +253615,7 @@ bqe gxh kKL hOu -orf +hfG hJx lli fAF @@ -251905,23 +253624,23 @@ kKL mMb mMb kKL -cSQ +cjh kKL mMb mMb mMb kKL -dMq +vYv lli lli kKL -dMq +gkP hFg kKL xcy rvZ hUx -mqq +veq aLX vng gNT @@ -252122,8 +253841,7 @@ wNO wNO wNO wNO -wNO -bln +ngh bln uei tmR @@ -252138,9 +253856,10 @@ tmR uei bln bln +lBD +uer bln -bln -bln +fsm bln bln bln @@ -252150,35 +253869,35 @@ cvF lli kKL mwu -gxh +rlH kKL kKL -lAG +gRL kKL jhS tOX kKL -wZZ -lli -iin +kaI +xIh +wvJ kKL -cSQ -lqh -uKr -uKr -uKr -uKr -mRs +cjh +emx +fOg +fOg +fOg +fOg +maw igX igX kKL -cUt +neQ kKL kKL kKL fyZ hUx -mqq +veq sZF eFS sZF @@ -252379,8 +254098,7 @@ wNO wNO wNO wNO -wNO -tCr +ngh bln uei tmR @@ -252395,12 +254113,13 @@ tmR uei bln bln -ozo bln bln +mQb bln bln bln +ntK bln kKL oCv @@ -252410,16 +254129,16 @@ qqB gxh kKL weF -orf +hfG kKL moF cjI kKL -dCA -atM -atM -uKr -sEE +pQa +erq +erq +oPw +srU xWM kKL kKL @@ -252429,13 +254148,13 @@ kKL kKL kKL kKL -oaa +nLs aJG sQE hwE hwE cMe -mqq +veq uvt tlP wIg @@ -252635,9 +254354,8 @@ wNO wNO wNO wNO -wNO -wNO -tCr +bln +vHT bln uei tmR @@ -252653,8 +254371,9 @@ uei bln bln bln +mQb bln -bln +mQb bln bln bln @@ -252667,13 +254386,13 @@ hJx qFW kKL hOu -orf +hfG hJx mzM hUi kKL uar -tvZ +unu kKL kKL kKL @@ -252686,13 +254405,13 @@ jSC bdS dtb hUD -iko +bOh rvZ lso lso rCu cYE -wYf +tCG idi cZU kBl @@ -252892,9 +254611,8 @@ wNO wNO wNO wNO -wNO -wNO -tCr +bln +vnS bln uei tmR @@ -252908,12 +254626,13 @@ uei tmR uei bln -tCr +stJ bln bln bln bln bln +uer bln bln kKL @@ -252924,13 +254643,13 @@ lli gxh kKL kKL -orf +hfG kKL kKL kKL kKL kIl -omt +nNI kKL eIk xry @@ -252949,7 +254668,7 @@ rek rek hUx rNQ -wYf +tCG idi aID gky @@ -253149,9 +254868,8 @@ wNO wNO wNO wNO -wNO -wNO -tCr +bln +ngh bln bln bln @@ -253165,9 +254883,10 @@ bln bln hty bln -tCr bln bln +lSu +lSu bln bln bln @@ -253202,11 +254921,11 @@ qMm hUD pyJ lPh -hUD +rBp hUD ebb cYE -wYf +tCG idi aID ddk @@ -253335,264 +255054,7 @@ wNO wNO wNO "} -(169,1,3) = {" -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -otC -hHG -hHG -hHG -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -tCr -mVm -tCr -tCr -bln -bln -bln -bln -bln -bln -kKL -hTB -sRI -jwF -kKL -lli -gJX -paT -lli -lli -vbZ -jpo -izp -nae -pCi -kKL -kKL -ikm -gXp -qCA -vvL -blV -sEi -sEi -fQz -oBI -sEi -mMD -nVr -wFO -bzA -hUD -lso -byK -kYz -bRd -fqQ -wIg -qfh -kRE -cLo -uvt -fJF -oed -wkH -mtI -uRL -xmf -owC -tVn -tYe -xIF -wHc -aiH -pTU -faJ -akx -tHK -dfe -dfe -dfe -ehO -lDX -cpg -cpg -cpg -huN -hfc -hfc -hfc -ocD -diL -qVz -pNY -edp -dcr -aRl -bCL -ofr -sBx -hfc -jCE -adY -tmR -sZF -pHR -wEV -sZF -bln -bln -bln -bln -bln -bln -bln -bln -bln -bln -bln -bln -bln -bln -bln -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -wNO -"} -(170,1,3) = {" +(169,1,3) = {" wNO wNO wNO @@ -253664,6 +255126,257 @@ wNO wNO wNO wNO +dqA +jas +jas +bYx +jas +jas +jas +bYx +jas +jas +wQN +bYx +jas +jas +jas +bYx +jas +nMD +bYr +bYx +jas +ike +kKL +hTB +sRI +jwF +kKL +lli +gJX +paT +lli +lli +vbZ +jpo +izp +nae +pCi +kKL +kKL +ikm +gXp +qCA +vvL +blV +sEi +sEi +fQz +oBI +sEi +mMD +nVr +wFO +bzA +hUD +lso +byK +hMs +bRd +fqQ +wIg +qfh +kRE +cLo +uvt +fJF +oed +wkH +mtI +uRL +xmf +owC +tVn +tYe +xIF +wHc +aiH +pTU +faJ +akx +tHK +dfe +dfe +dfe +ehO +lDX +cpg +cpg +cpg +huN +hfc +hfc +hfc +ocD +diL +qVz +pNY +edp +dcr +aRl +bCL +ofr +sBx +hfc +jCE +adY +tmR +sZF +pHR +wEV +sZF +bln +bln +bln +bln +bln +bln +bln +bln +bln +bln +bln +bln +bln +bln +bln +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +"} +(170,1,3) = {" +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +otC +hHG +hHG +hHG +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO +wNO wNO wNO wNO @@ -253680,8 +255393,14 @@ wNO wNO wNO bln +ozo +bln +wNO +wNO +wNO bln bln +lSu bln bln bln @@ -253720,7 +255439,7 @@ vfo hUD lso cYE -mpZ +nYY ult bsG wGF @@ -253977,7 +255696,7 @@ cLJ iQQ lso cYE -lso +uIS ult wjz tXh @@ -254194,9 +255913,9 @@ wNO wNO wNO bln +uer bln -bln -bln +stJ bln bln bln @@ -254212,7 +255931,7 @@ tml kKL kLb qpd -ydD +oNy kKL gkP kKL @@ -254234,7 +255953,7 @@ bwl hUD uff cYE -acw +hXt ult hpC rIU @@ -254455,7 +256174,7 @@ bln bln bln bln -bln +uer bln kKL kKL @@ -254491,7 +256210,7 @@ wND iQQ rvZ cYE -lso +uIS ult vuq tfM @@ -254708,11 +256427,11 @@ wNO wNO wNO bln +mQb bln bln bln -bln -bln +lBD bln mMb lIC @@ -254746,9 +256465,9 @@ sEi sEi naP hUD -rqT -cjl -rqT +jed +iIk +jed ult ult wBk @@ -254967,7 +256686,7 @@ wNO bln bln bln -bln +uer bln bln bln @@ -255223,7 +256942,7 @@ wNO wNO bln bln -bln +lBD bln bln bln @@ -255482,7 +257201,7 @@ bln bln bln bln -bln +lBD bln kKL pGJ @@ -255506,7 +257225,7 @@ poy poy lNk hUD -jEr +nbL rGd whC hUD @@ -256524,7 +258243,7 @@ qAS fUc jaX glI -rPu +gZR kKL kKL mbG @@ -257552,7 +259271,7 @@ dvS pwd glI tsR -rPu +gZR lUC tXV kvX @@ -258313,7 +260032,7 @@ wNO bln bln bln -bln +ozo bln bln sEB @@ -258570,7 +260289,7 @@ wNO bln bln bln -ozo +bln bln bln sEB diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index c244dcba5a659..f1218d4d70732 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -945,8 +945,6 @@ /area/station/command/heads_quarters/hos) "atf" = ( /obj/structure/table/glass, -/obj/item/clothing/gloves/latex, -/obj/item/surgical_drapes, /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, /obj/effect/turf_decal/tile/blue/fourcorners, @@ -4013,8 +4011,8 @@ /area/station/hallway/secondary/service) "btt" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/cargo/miningoffice) "btx" = ( @@ -5051,12 +5049,6 @@ /area/station/security/execution/education) "bMS" = ( /obj/structure/table/glass, -/obj/item/scalpel{ - pixel_y = 12 - }, -/obj/item/circular_saw, -/obj/item/blood_filter, -/obj/item/bonesetter, /obj/machinery/button/door/directional/south{ id = "main_surgery"; name = "privacy shutters control" @@ -5728,7 +5720,12 @@ /turf/open/floor/circuit, /area/station/maintenance/port/aft) "bYN" = ( -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted, +/obj/effect/turf_decal/siding/wideplating_new{ + dir = 4 + }, +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 4 + }, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "bZb" = ( @@ -6244,12 +6241,6 @@ }, /turf/open/floor/carpet, /area/station/medical/psychology) -"cnd" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/spawner/structure/window, -/turf/open/floor/plating, -/area/station/cargo/sorting) "cnk" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 6 @@ -9498,12 +9489,10 @@ /area/station/hallway/secondary/exit/departure_lounge) "dyq" = ( /obj/structure/table/glass, -/obj/item/retractor, -/obj/item/hemostat, -/obj/item/cautery, /obj/effect/turf_decal/tile/blue/fourcorners, /obj/machinery/status_display/evac/directional/west, /obj/machinery/digital_clock/directional/south, +/obj/item/surgery_tray/full, /turf/open/floor/iron/white, /area/station/medical/surgery/theatre) "dyr" = ( @@ -13384,11 +13373,6 @@ }, /turf/open/floor/iron, /area/station/commons/fitness/recreation) -"eTv" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/hallway/secondary/exit/departure_lounge) "eTI" = ( /obj/effect/turf_decal/stripes/line{ dir = 10 @@ -14256,8 +14240,6 @@ /area/station/medical/medbay/central) "fiK" = ( /obj/structure/table/glass, -/obj/item/clothing/gloves/latex, -/obj/item/surgical_drapes, /obj/machinery/airalarm/directional/south, /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron/white, @@ -14701,11 +14683,9 @@ /area/station/ai_monitored/aisat/exterior) "fpg" = ( /obj/structure/table/glass, -/obj/item/retractor, -/obj/item/hemostat, -/obj/item/cautery, /obj/effect/turf_decal/tile/blue/fourcorners, /obj/machinery/status_display/evac/directional/west, +/obj/item/surgery_tray/full, /turf/open/floor/iron/white, /area/station/medical/surgery/theatre) "fpj" = ( @@ -14909,6 +14889,15 @@ /obj/structure/sign/warning/pods, /turf/closed/wall, /area/station/commons/locker) +"ftQ" = ( +/obj/effect/turf_decal/siding/white{ + dir = 4 + }, +/obj/structure/railing{ + dir = 4 + }, +/turf/open/water, +/area/station/service/hydroponics/garden) "fuc" = ( /obj/structure/frame/machine{ anchored = 1 @@ -17149,14 +17138,15 @@ /area/station/service/theater) "gpk" = ( /obj/structure/table, -/obj/item/hatchet, -/obj/item/cultivator, -/obj/item/crowbar, -/obj/item/reagent_containers/cup/watering_can, -/obj/item/plant_analyzer, /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/item/storage/bag/plants/portaseeder, +/obj/item/crowbar, +/obj/item/reagent_containers/cup/watering_can, +/obj/item/cultivator, +/obj/item/hatchet, +/obj/item/plant_analyzer, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "gpv" = ( @@ -21418,6 +21408,8 @@ dir = 4 }, /obj/effect/landmark/start/cargo_technician, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/cargo/sorting) "hRQ" = ( @@ -23139,9 +23131,19 @@ /turf/open/floor/plating, /area/station/maintenance/port/greater) "ivb" = ( -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 4 +/obj/machinery/disposal/bin, +/obj/machinery/camera/directional/east{ + c_tag = "Garden" }, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/structure/cable, +/obj/machinery/power/apc/auto_name/directional/east, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/siding/wideplating_new, +/obj/structure/railing, +/obj/effect/turf_decal/tile/green/half/contrasted, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "ivc" = ( @@ -24297,9 +24299,6 @@ /obj/machinery/reagentgrinder{ pixel_y = 8 }, -/obj/item/toy/figure/virologist{ - pixel_x = -8 - }, /obj/effect/turf_decal/tile/green/half/contrasted, /obj/machinery/light/small/directional/south, /turf/open/floor/iron/white, @@ -25860,6 +25859,8 @@ /obj/structure/disposalpipe/segment{ dir = 10 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/cargo/sorting) "joj" = ( @@ -26947,11 +26948,6 @@ /obj/structure/table/wood/poker, /turf/open/floor/wood, /area/station/commons/lounge) -"jGE" = ( -/obj/structure/window/spawner/directional/west, -/obj/structure/window/spawner/directional/north, -/turf/open/floor/grass, -/area/station/service/hydroponics/garden) "jGG" = ( /obj/machinery/holopad, /obj/effect/turf_decal/box/white{ @@ -28045,11 +28041,10 @@ /turf/open/floor/iron/dark, /area/station/command/gateway) "jYu" = ( -/mob/living/basic/cow{ - name = "Betsy"; - real_name = "Betsy" +/obj/effect/turf_decal/siding/white{ + dir = 9 }, -/turf/open/floor/grass, +/turf/open/water, /area/station/service/hydroponics/garden) "jYv" = ( /obj/machinery/meter, @@ -28352,6 +28347,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment, /obj/effect/landmark/event_spawn, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/cargo/miningoffice) "kdL" = ( @@ -29018,13 +29014,21 @@ /turf/open/floor/iron/white, /area/station/security/prison) "krt" = ( -/obj/item/storage/bag/plants/portaseeder, -/obj/structure/table, -/obj/item/plant_analyzer, /obj/effect/turf_decal/stripes/line{ dir = 1 }, /obj/machinery/light/directional/south, +/obj/structure/table/wood, +/obj/effect/turf_decal/siding/wideplating_new{ + dir = 4 + }, +/obj/item/storage/toolbox/fishing, +/obj/item/storage/toolbox/fishing, +/obj/item/fishing_rod, +/obj/item/fishing_rod, +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 4 + }, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "krL" = ( @@ -30950,6 +30954,7 @@ name = "Featherbottom"; real_name = "Featherbottom" }, +/obj/structure/flora/bush/fullgrass, /turf/open/floor/grass, /area/station/service/hydroponics/garden) "lbL" = ( @@ -31017,10 +31022,12 @@ }, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ +/obj/effect/landmark/event_spawn, +/obj/effect/turf_decal/siding/wideplating_new/corner, +/obj/effect/turf_decal/tile/green, +/obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "lds" = ( @@ -32179,6 +32186,8 @@ }, /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/supply/general, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/cargo/sorting) "lBA" = ( @@ -32398,9 +32407,6 @@ /obj/structure/chair/comfy/brown, /turf/open/floor/engine/cult, /area/station/service/library) -"lJa" = ( -/turf/open/floor/grass, -/area/station/service/hydroponics/garden) "lJh" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -33761,7 +33767,7 @@ /turf/open/floor/plating, /area/station/maintenance/department/engine) "mie" = ( -/obj/structure/window/spawner/directional/south, +/obj/structure/flora/bush/flowers_yw, /turf/open/floor/grass, /area/station/service/hydroponics/garden) "mig" = ( @@ -39360,14 +39366,6 @@ /obj/structure/window/reinforced/spawner/directional/east, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/rd) -"obV" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/hallway/secondary/exit/departure_lounge) "ocg" = ( /obj/structure/extinguisher_cabinet/directional/south, /obj/structure/cable, @@ -40186,8 +40184,13 @@ /area/station/science/lab) "otG" = ( /obj/item/radio/intercom/directional/east, -/obj/structure/window/spawner/directional/north, -/turf/open/floor/grass, +/obj/effect/turf_decal/siding/white{ + dir = 5 + }, +/obj/structure/railing{ + dir = 4 + }, +/turf/open/water, /area/station/service/hydroponics/garden) "otI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -40658,6 +40661,7 @@ name = "Kentucky"; real_name = "Kentucky" }, +/obj/structure/flora/grass/jungle/b/style_random, /turf/open/floor/grass, /area/station/service/hydroponics/garden) "oCR" = ( @@ -41390,7 +41394,6 @@ /obj/structure/chair/office/light{ dir = 8 }, -/obj/effect/landmark/start/virologist, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/virology) @@ -44344,17 +44347,12 @@ /turf/open/floor/iron, /area/station/security/execution/transfer) "pRM" = ( -/obj/machinery/disposal/bin, -/obj/machinery/camera/directional/east{ - c_tag = "Garden" - }, -/obj/structure/disposalpipe/trunk{ - dir = 8 +/obj/structure/window/spawner/directional/south, +/mob/living/basic/cow{ + name = "Betsy"; + real_name = "Betsy" }, -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/east, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron, +/turf/open/floor/grass, /area/station/service/hydroponics/garden) "pSa" = ( /obj/effect/turf_decal/trimline/red/filled/corner{ @@ -50133,6 +50131,11 @@ }, /turf/open/floor/iron, /area/station/commons/locker) +"rUd" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/cargo/sorting) "rUo" = ( /obj/structure/bed, /obj/effect/spawner/random/bedsheet, @@ -51737,7 +51740,6 @@ "syT" = ( /obj/structure/cable, /obj/structure/chair/office/light, -/obj/effect/landmark/start/virologist, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 }, @@ -55090,6 +55092,14 @@ }, /turf/open/floor/iron/white, /area/station/medical/pharmacy) +"tIE" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron, +/area/station/cargo/sorting) "tIH" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -55525,12 +55535,6 @@ /area/station/medical/virology) "tOT" = ( /obj/structure/table/glass, -/obj/item/scalpel{ - pixel_y = 12 - }, -/obj/item/circular_saw, -/obj/item/blood_filter, -/obj/item/bonesetter, /obj/machinery/button/door/directional/north{ id = "main_surgery"; name = "privacy shutters control" @@ -55922,7 +55926,7 @@ /turf/open/floor/carpet, /area/station/service/chapel/funeral) "tVC" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/flasher/directional/north{ @@ -59844,6 +59848,12 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/engineering/atmospherics_engine) +"vmU" = ( +/obj/effect/turf_decal/siding/white{ + dir = 8 + }, +/turf/open/water, +/area/station/service/hydroponics/garden) "vmX" = ( /obj/machinery/light/directional/west, /obj/structure/disposalpipe/segment, @@ -64499,6 +64509,7 @@ /area/station/science/robotics/lab) "wRF" = ( /obj/structure/window/spawner/directional/west, +/obj/structure/flora/rock/pile, /turf/open/floor/grass, /area/station/service/hydroponics/garden) "wRL" = ( @@ -66135,6 +66146,15 @@ "xww" = ( /turf/closed/wall/r_wall, /area/station/engineering/storage/tech) +"xwB" = ( +/obj/effect/turf_decal/siding/white{ + dir = 6 + }, +/obj/structure/railing{ + dir = 4 + }, +/turf/open/water, +/area/station/service/hydroponics/garden) "xwD" = ( /obj/effect/turf_decal/trimline/yellow/filled/corner, /turf/open/floor/iron/white, @@ -66298,6 +66318,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/cargo/miningoffice) "xyA" = ( @@ -66318,10 +66339,14 @@ /turf/open/floor/iron/white, /area/station/medical/chemistry) "xyI" = ( -/obj/machinery/door/window/left/directional/west{ - name = "Animal Pen B" +/obj/effect/turf_decal/siding/white{ + dir = 10 }, -/turf/open/floor/grass, +/obj/structure/railing{ + dir = 8 + }, +/obj/structure/sign/clock/directional/south, +/turf/open/water, /area/station/service/hydroponics/garden) "xyM" = ( /obj/structure/cable, @@ -67419,11 +67444,11 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, /obj/structure/cable, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/siding/wideplating_new, +/obj/structure/railing, +/obj/effect/turf_decal/tile/green/half/contrasted, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "xUH" = ( @@ -67665,6 +67690,9 @@ "xYl" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, /turf/open/floor/iron, /area/station/cargo/miningoffice) "xYq" = ( @@ -89904,8 +89932,8 @@ bzH bzH raC hRD -gBN -piB +tIE +rUd jnR lBz sXr @@ -90416,7 +90444,7 @@ uLE kPX moQ bzH -cnd +aqG aqG tjN aqG @@ -95882,7 +95910,7 @@ qFP tAx mZC hdZ -eTv +bDp mIi bfl bfl @@ -96139,7 +96167,7 @@ dXQ kSD vGN wpr -obV +tDU mGA xMC izG @@ -105569,7 +105597,7 @@ fzr iCJ qgy ldg -ivb +bYN bYN krt qXB @@ -105826,9 +105854,9 @@ wRF jzC oCO xUE -jGE +jYu +vmU xyI -wRF qXB kbo qXB @@ -106080,12 +106108,12 @@ cUP mil lqQ lbH -lJa mie pRM +ivb otG -jYu -lJa +ftQ +xwB qXB psZ qXB diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index c621acfbae215..72fe092d5caa1 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -343,6 +343,12 @@ /obj/structure/cable, /turf/open/floor/plating, /area/mine/maintenance/service) +"ct" = ( +/obj/structure/railing/wooden_fence{ + dir = 6 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "cw" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1299,6 +1305,9 @@ /obj/structure/stone_tile, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"hM" = ( +/turf/closed/wall/mineral/wood/nonmetal, +/area/lavaland/surface) "hR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1397,6 +1406,10 @@ /obj/item/clothing/glasses/meson, /turf/open/floor/iron/dark, /area/mine/storage/public) +"il" = ( +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "io" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1669,6 +1682,12 @@ dir = 8 }, /area/mine/production) +"jX" = ( +/obj/structure/railing/wooden_fence{ + dir = 1 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "ka" = ( /obj/structure/table, /obj/machinery/newscaster/directional/north, @@ -1930,6 +1949,12 @@ }, /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors) +"lt" = ( +/obj/structure/railing/wooden_fence{ + dir = 5 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "lv" = ( /obj/structure/stone_tile/block/cracked{ dir = 8 @@ -2027,10 +2052,11 @@ dir = 1 }, /obj/effect/mapping_helpers/airlock/unres, -/obj/effect/mapping_helpers/airlock/access/any/supply/mining_station, /obj/machinery/door/airlock/external/glass{ name = "Mining Shuttle Airlock" }, +/obj/effect/mapping_helpers/airlock/access/any/supply/mining, +/obj/effect/mapping_helpers/airlock/access/any/supply/mining, /turf/open/floor/iron/dark/textured_large, /area/mine/production) "lN" = ( @@ -2155,6 +2181,17 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"mk" = ( +/obj/structure/table/wood, +/obj/item/raptor_dex{ + pixel_y = 13 + }, +/obj/item/raptor_dex{ + pixel_y = 7 + }, +/obj/item/raptor_dex, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "ml" = ( /obj/structure/stone_tile/block/cracked{ dir = 8 @@ -3005,6 +3042,12 @@ dir = 4 }, /area/mine/laborcamp/quarters) +"qi" = ( +/obj/structure/railing/wooden_fence{ + dir = 4 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "qo" = ( /obj/machinery/door/airlock/glass{ name = "Equipment Storage" @@ -3243,6 +3286,11 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/maintenance/service) +"sa" = ( +/obj/structure/table/wood, +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "se" = ( /turf/open/floor/iron/dark/textured_large, /area/mine/eva) @@ -3339,6 +3387,10 @@ "sO" = ( /turf/open/floor/plating, /area/mine/maintenance/service) +"sQ" = ( +/obj/structure/ore_container/food_trough/raptor_trough, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "sR" = ( /obj/machinery/light/small/directional/west, /obj/effect/decal/cleanable/dirt, @@ -3590,6 +3642,10 @@ }, /turf/open/floor/iron/white/smooth_edge, /area/mine/cafeteria) +"uw" = ( +/obj/effect/spawner/random/lavaland_mob/raptor, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "ux" = ( /obj/machinery/door/airlock{ id_tag = "miningdorm1"; @@ -4333,6 +4389,10 @@ /obj/structure/rack, /turf/open/floor/plating, /area/mine/maintenance/service) +"ze" = ( +/obj/effect/spawner/random/lavaland_mob/raptor, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "zf" = ( /obj/machinery/door/airlock{ name = "Restroom" @@ -4389,6 +4449,10 @@ /obj/item/cigbutt, /turf/open/floor/iron/smooth, /area/mine/laborcamp) +"zs" = ( +/obj/structure/railing/wooden_fence, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "zw" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -4724,6 +4788,12 @@ }, /turf/open/floor/iron/checker, /area/mine/cafeteria) +"Cv" = ( +/obj/structure/railing/wooden_fence{ + dir = 5 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "Cz" = ( /obj/machinery/door/airlock/medical/glass{ name = "Infirmary" @@ -4898,6 +4968,12 @@ "Dz" = ( /turf/closed/wall, /area/mine/medical) +"DB" = ( +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "DF" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -5302,6 +5378,12 @@ dir = 8 }, /area/mine/production) +"GG" = ( +/obj/structure/railing/wooden_fence{ + dir = 9 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "GH" = ( /obj/machinery/door/airlock/glass{ name = "Arrival Lounge" @@ -6535,6 +6617,12 @@ /obj/machinery/computer/order_console/mining, /turf/open/floor/iron/dark, /area/mine/production) +"NK" = ( +/obj/structure/railing/wooden_fence{ + dir = 1 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "NL" = ( /obj/structure/railing, /obj/structure/lattice/catwalk/mining, @@ -6553,6 +6641,9 @@ dir = 1 }, /area/mine/laborcamp/production) +"NS" = ( +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "NT" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -6714,6 +6805,17 @@ /obj/structure/cable, /turf/open/floor/iron/white/textured_large, /area/mine/cafeteria) +"OW" = ( +/obj/structure/table/wood, +/obj/item/soap/deluxe{ + pixel_y = 11 + }, +/obj/item/soap/deluxe{ + pixel_y = 6 + }, +/obj/item/soap/deluxe, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "OZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7171,7 +7273,6 @@ "RW" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/effect/mapping_helpers/airlock/unres, -/obj/effect/mapping_helpers/airlock/access/any/supply/mining_station, /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 1 }, @@ -7181,6 +7282,7 @@ /obj/machinery/door/airlock/external/glass{ name = "Mining Shuttle Airlock" }, +/obj/effect/mapping_helpers/airlock/access/any/supply/mining, /turf/open/floor/iron/dark/textured_large, /area/mine/production) "RY" = ( @@ -7405,6 +7507,12 @@ dir = 4 }, /area/mine/production) +"Tt" = ( +/obj/structure/railing/wooden_fence{ + dir = 10 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "Tu" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7595,6 +7703,12 @@ }, /turf/open/floor/iron/freezer, /area/mine/living_quarters) +"UI" = ( +/obj/structure/railing/wooden_fence{ + dir = 4 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "UK" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/siding/wideplating_new{ @@ -7672,6 +7786,12 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"Vd" = ( +/obj/structure/railing/wooden_fence{ + dir = 9 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "Ve" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/textured_large, @@ -7815,6 +7935,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/maintenance/labor) +"VP" = ( +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "VS" = ( /obj/machinery/hydroponics/constructable, /obj/effect/decal/cleanable/dirt, @@ -47781,7 +47907,7 @@ aj aj aj pU -aj +pU aj aj aj @@ -49060,15 +49186,15 @@ aj aj aj aj -aj -aj -aj pU pU -aj -aj -aj -aj +pU +pU +pU +pU +pU +pU +pU aj aj "} @@ -49316,18 +49442,18 @@ aj aj aj aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +GG +DB +DB +hM +hM +hM +hM +hM +hM +hM +hM +hM "} (160,1,1) = {" aa @@ -49572,19 +49698,19 @@ aj aj aj aj -aj -aj -aj -aj pU -aj -aj -aj -aj -aj -aj -aj -aj +jX +pU +pU +NK +sQ +NS +zs +NS +NS +sQ +NS +hM "} (161,1,1) = {" aa @@ -49829,19 +49955,19 @@ aj aj aj aj -aj -aj -aj pU -aj -aj -aj -aj -aj -aj -aj -aj -aj +jX +pU +pU +NK +il +NS +zs +NS +NS +il +NS +hM "} (162,1,1) = {" aa @@ -50086,19 +50212,19 @@ aj aj aj aj -aj -aj pU +jX pU -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +NK +NS +NS +zs +NS +NS +NS +NS +hM "} (163,1,1) = {" aa @@ -50341,21 +50467,21 @@ aj aj pU aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +pU +pU +jX +pU +pU +Cv +qi +NS +ct +NS +NS +qi +qi +hM "} (164,1,1) = {" aa @@ -50598,21 +50724,21 @@ aj aj pU pU -aj -aj -aj -aj -aj -aj pU pU -aj -aj -aj -aj -aj -aj -aj +pU +pU +ze +pU +NS +NS +NS +NS +NS +uw +NS +NS +hM "} (165,1,1) = {" aa @@ -50857,19 +50983,19 @@ pU pU pU pU -aj -aj pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +pU +pU +NS +mk +sa +NS +NS +NS +OW +sa +hM "} (166,1,1) = {" aa @@ -51116,17 +51242,17 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +pU +NS +NS +uw +NS +NS +NS +NS +NS +hM "} (167,1,1) = {" aa @@ -51372,18 +51498,18 @@ pU pU pU pU +jX pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +Vd +VP +NS +Tt +NS +NS +VP +VP +hM "} (168,1,1) = {" aa @@ -51629,18 +51755,18 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +jX +pU +pU +NK +NS +NS +zs +NS +NS +NS +NS +hM "} (169,1,1) = {" aa @@ -51885,19 +52011,19 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +jX +pU +pU +NK +il +NS +zs +NS +NS +il +NS +hM "} (170,1,1) = {" aa @@ -52142,19 +52268,19 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +jX +pU +pU +NK +sQ +NS +zs +NS +NS +sQ +NS +hM "} (171,1,1) = {" aa @@ -52399,19 +52525,19 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj pU -aj -aj -aj -aj -aj -aj +lt +UI +UI +hM +hM +hM +hM +hM +hM +hM +hM +hM "} (172,1,1) = {" aa @@ -52657,10 +52783,10 @@ pU pU pU pU -aj -aj -aj -aj +pU +pU +pU +pU aj aj aj @@ -52914,16 +53040,16 @@ pU pU pU pU -pU -pU aj aj aj aj aj -pU aj aj +pU +aj +pU aj aj "} diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index cc20da6c1d741..606e8de016c39 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -7946,10 +7946,9 @@ /turf/open/floor/iron/dark/smooth_large, /area/station/hallway/secondary/entry) "bWZ" = ( -/obj/structure/sign/poster/contraband/hacking_guide/directional/north, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/extinguisher_cabinet/directional/west, /obj/machinery/duct, +/obj/machinery/camera/autoname/directional/north, /turf/open/floor/iron/dark/textured, /area/station/commons/fitness) "bXd" = ( @@ -8544,12 +8543,12 @@ /area/station/hallway/secondary/entry) "ceF" = ( /obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable, /obj/machinery/door/poddoor/shutters/preopen{ + name = "CMO Privacy Shutters"; dir = 4; - id = "cmo_privacy"; - name = "CMO Privacy Shutters" + id = "cmoshutter" }, -/obj/structure/cable, /turf/open/floor/plating, /area/station/medical/storage) "ceH" = ( @@ -12180,7 +12179,7 @@ /obj/machinery/camera/motion/directional/north{ c_tag = "Minisat North" }, -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/aisat/service) @@ -19509,12 +19508,12 @@ /turf/open/openspace, /area/station/science/xenobiology/hallway) "fbl" = ( -/obj/machinery/power/smes, /obj/effect/turf_decal/stripes/line{ dir = 4 }, /obj/structure/cable, /obj/machinery/light/small/directional/west, +/obj/machinery/power/smes/full, /turf/open/floor/plating, /area/station/engineering/gravity_generator) "fbo" = ( @@ -26935,6 +26934,16 @@ /obj/effect/landmark/start/atmospheric_technician, /turf/open/floor/iron, /area/station/engineering/atmos) +"hab" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 1; + id = "cmoshutter"; + name = "CMO Privacy Shutters" + }, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/command/heads_quarters/cmo) "hah" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/white/smooth_corner{ @@ -44185,8 +44194,9 @@ /area/station/command/meeting_room) "ltH" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/camera/autoname/directional/north, /obj/machinery/duct, +/obj/structure/sign/poster/contraband/hacking_guide/directional/north, +/obj/structure/extinguisher_cabinet/directional/west, /turf/open/floor/iron/dark/textured, /area/station/commons/fitness) "ltI" = ( @@ -46237,12 +46247,12 @@ /area/station/maintenance/floor2/port) "lTO" = ( /obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable, /obj/machinery/door/poddoor/shutters/preopen{ dir = 1; - id = "cmo_privacy"; + id = "cmoshutter"; name = "CMO Privacy Shutters" }, -/obj/structure/cable, /turf/open/floor/plating, /area/station/command/heads_quarters/cmo) "lTV" = ( @@ -51219,6 +51229,16 @@ /obj/structure/cable/layer3, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat) +"nge" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 8; + id = "cmoshutter"; + name = "CMO Privacy Shutters" + }, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/command/heads_quarters/cmo) "ngf" = ( /obj/structure/railing, /obj/effect/decal/cleanable/dirt, @@ -57371,12 +57391,12 @@ /area/station/science/xenobiology) "oJs" = ( /obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable, /obj/machinery/door/poddoor/shutters/preopen{ dir = 8; - id = "cmo_privacy"; + id = "cmoshutter"; name = "CMO Privacy Shutters" }, -/obj/structure/cable, /turf/open/floor/plating, /area/station/command/heads_quarters/cmo) "oJO" = ( @@ -61910,7 +61930,7 @@ /turf/open/floor/iron/white, /area/station/science/lobby) "pUB" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/aisat/service) @@ -63803,6 +63823,8 @@ dir = 4 }, /obj/effect/turf_decal/trimline/red/filled/corner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, /turf/open/floor/iron/dark/textured, /area/station/commons/fitness) "qtH" = ( @@ -68056,7 +68078,7 @@ /area/station/maintenance/floor1/starboard/fore) "rxZ" = ( /obj/item/storage/toolbox/maint_kit, -/obj/item/ammo_casing/shotgun/improvised, +/obj/effect/spawner/random/junk_shell, /turf/open/floor/pod/light, /area/station/maintenance/floor4/port) "ryh" = ( @@ -72965,7 +72987,6 @@ specialfunctions = 4 }, /obj/effect/turf_decal/tile/green/opposingcorners, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/virology) "sPs" = ( @@ -76628,14 +76649,6 @@ }, /turf/open/floor/pod/dark, /area/station/maintenance/floor3/port/aft) -"tKr" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/turf_decal/tile/green/opposingcorners, -/obj/effect/landmark/start/virologist, -/turf/open/floor/iron/white, -/area/station/medical/virology) "tKs" = ( /obj/structure/curtain, /obj/structure/fans/tiny{ @@ -79797,7 +79810,7 @@ /area/station/maintenance/solars/starboard/fore) "uDR" = ( /obj/machinery/firealarm/directional/west, -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/aisat_interior) @@ -92010,11 +92023,11 @@ pixel_x = 9 }, /obj/machinery/button/door/directional/north{ - id = "cmo_privacy"; - name = "Robotics Privacy Control"; - pixel_x = -6; + name = "CMO Privacy Shutters"; + id = "cmoshutter"; + req_access = list("cmo"); pixel_y = 25; - req_access = list("cmo") + pixel_x = -5 }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/cmo) @@ -190445,7 +190458,7 @@ syV wPX xKq nCG -oJs +nge goX oJs nCG @@ -190958,7 +190971,7 @@ jRO eCO wyE xKq -lTO +hab dZz bPP xhJ @@ -196074,7 +196087,7 @@ iOA utl doh gJz -tKr +rPC hwQ piz aWO @@ -196588,7 +196601,7 @@ iOA dfU pZm wJy -tKr +rPC dVV bLm yhv @@ -257493,7 +257506,7 @@ sSB sSB sSB sSB -qrd +sSB qrd qrd sNE @@ -257751,7 +257764,7 @@ qrd qrd qrd qrd -bWZ +qrd vTf gvO boP @@ -259036,7 +259049,7 @@ qrd oeQ xgb nWe -mkl +bWZ hwr oWt wJH diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm index 1c5a88860bea5..584ba1eb7ee9d 100644 --- a/_maps/map_files/debug/runtimestation.dmm +++ b/_maps/map_files/debug/runtimestation.dmm @@ -683,6 +683,10 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/item/disk/data/debug{ + pixel_y = 9; + pixel_x = 7 + }, /turf/open/floor/iron/white/corner, /area/station/medical/medbay) "cL" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 25569a6af8a1a..917b6101b931b 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -3331,6 +3331,7 @@ /obj/machinery/computer/turbine_computer{ mapping_id = "main_turbine" }, +/obj/structure/cable, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) "auc" = ( @@ -3376,6 +3377,7 @@ "aum" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line, +/obj/structure/cable, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) "auo" = ( @@ -3389,6 +3391,7 @@ dir = 4; mapping_id = "main_turbine" }, +/obj/structure/cable, /turf/open/floor/engine, /area/station/maintenance/disposal/incinerator) "auq" = ( @@ -7423,7 +7426,6 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 }, -/obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/gravity_generator) "bAj" = ( @@ -19908,11 +19910,6 @@ /obj/item/storage/bag/tray/cafeteria, /turf/open/floor/iron/cafeteria, /area/station/security/prison/mess) -"fZB" = ( -/obj/machinery/power/smes/full, -/obj/structure/cable, -/turf/open/floor/circuit/telecomms/mainframe, -/area/station/tcommsat/server) "fZD" = ( /obj/structure/cable, /obj/item/radio/intercom/directional/west, @@ -21823,12 +21820,6 @@ /obj/machinery/light/directional/east, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"gJc" = ( -/obj/machinery/power/smes/full, -/obj/structure/cable, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, -/area/station/commons/vacant_room) "gJs" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/effect/turf_decal/tile/bar/opposingcorners, @@ -22982,9 +22973,7 @@ /turf/open/floor/iron/dark, /area/station/command/bridge) "hhf" = ( -/obj/machinery/power/smes{ - charge = 5e+06 - }, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/ai) @@ -23985,6 +23974,7 @@ network = list("turbine") }, /obj/effect/decal/cleanable/dirt, +/obj/structure/cable, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) "hCp" = ( @@ -28821,9 +28811,14 @@ /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 6 }, -/obj/structure/table, /obj/machinery/firealarm/directional/east, /obj/machinery/light/directional/east, +/obj/structure/table, +/obj/item/book/manual/wiki/engineering_guide{ + pixel_x = -2 + }, +/obj/item/radio/off, +/obj/item/radio/intercom/directional/south, /turf/open/floor/iron, /area/station/engineering/gravity_generator) "jos" = ( @@ -33470,7 +33465,6 @@ /obj/structure/bed{ dir = 4 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/dark, /area/station/medical/virology) "kPf" = ( @@ -33900,7 +33894,10 @@ /area/station/security/brig) "kWp" = ( /obj/effect/turf_decal/trimline/neutral/filled/line, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/gravity_generator) "kWq" = ( @@ -34738,11 +34735,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/construction/engineering) -"llW" = ( -/obj/machinery/power/smes/full, -/obj/structure/cable, -/turf/open/floor/circuit, -/area/station/ai_monitored/turret_protected/ai) "lml" = ( /turf/closed/wall/r_wall, /area/station/engineering/atmos/pumproom) @@ -42625,6 +42617,7 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm/directional/east, /obj/effect/mapping_helpers/airalarm/all_access, +/obj/structure/cable, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) "nYq" = ( @@ -46446,6 +46439,12 @@ /obj/structure/closet/toolcloset, /turf/open/floor/iron, /area/station/engineering/main) +"pxd" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible/layer2, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/maintenance/disposal/incinerator) "pxf" = ( /obj/structure/closet/secure_closet/hos, /obj/structure/secure_safe/hos{ @@ -47144,6 +47143,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible/layer2, /obj/machinery/light/small/directional/west, +/obj/structure/cable, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) "pIF" = ( @@ -48324,10 +48324,9 @@ /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 10 }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, /obj/machinery/light/directional/west, +/obj/machinery/power/smes/engineering, +/obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/gravity_generator) "qes" = ( @@ -51821,6 +51820,7 @@ "rnA" = ( /obj/structure/extinguisher_cabinet/directional/east, /obj/effect/decal/cleanable/dirt, +/obj/structure/cable, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) "rnK" = ( @@ -53702,6 +53702,9 @@ }, /turf/open/floor/iron/dark, /area/station/medical/storage) +"rYE" = ( +/turf/open/floor/plating/airless, +/area/space) "rYL" = ( /obj/structure/chair/comfy/black{ dir = 8 @@ -54233,7 +54236,7 @@ /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 5 }, -/turf/open/space/basic, +/turf/open/floor/iron/airless, /area/space) "siZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -58469,12 +58472,6 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron/dark, /area/station/security/execution/transfer) -"tGd" = ( -/obj/machinery/power/smes/full, -/obj/machinery/airalarm/directional/east, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/engineering/gravity_generator) "tGo" = ( /obj/effect/spawner/random/vending/colavend, /obj/effect/turf_decal/siding/thinplating/dark{ @@ -62225,7 +62222,6 @@ "uPi" = ( /obj/effect/turf_decal/trimline/neutral/filled/line, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/gravity_generator) "uPo" = ( @@ -64143,11 +64139,11 @@ /turf/open/floor/iron/white, /area/station/science/lobby) "vyD" = ( -/obj/machinery/power/smes{ - charge = 5e+06 - }, /obj/machinery/airalarm/directional/east, -/obj/structure/cable, +/obj/structure/table, +/obj/item/storage/toolbox/electrical{ + pixel_y = 5 + }, /turf/open/floor/iron, /area/station/engineering/gravity_generator) "vyG" = ( @@ -65333,7 +65329,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/turf/open/floor/iron/dark, +/turf/open/floor/plating, /area/station/ai_monitored/turret_protected/ai) "vTE" = ( /obj/machinery/camera{ @@ -66615,10 +66611,9 @@ /turf/open/misc/grass/jungle, /area/station/science/explab) "wtS" = ( -/obj/machinery/power/terminal{ +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 }, -/obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/gravity_generator) "wuc" = ( @@ -67121,7 +67116,6 @@ "wDt" = ( /obj/effect/landmark/event_spawn, /obj/structure/chair/stool/directional/east, -/obj/effect/landmark/start/virologist, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, @@ -70375,6 +70369,10 @@ /obj/machinery/light/small/dim/directional/west, /turf/open/floor/iron, /area/station/maintenance/tram/left) +"xRm" = ( +/obj/structure/lattice, +/turf/open/space/basic, +/area/space) "xRn" = ( /turf/open/floor/plating, /area/station/hallway/secondary/service) @@ -103252,7 +103250,7 @@ pcO iKr ofZ uKK -ajF +wtS kWp fal akK @@ -104023,7 +104021,7 @@ bKu bVW swg uKK -wtS +ajF bzP fal aks @@ -110998,7 +110996,7 @@ vde atC gqV atP -atP +pxd pIA aum aup @@ -130819,8 +130817,8 @@ vXM vXM vXM vXM -vXM -vXM +xRm +rYE vXM vXM vXM @@ -131075,9 +131073,9 @@ vXM vXM vXM vXM -vXM -vXM -vXM +xRm +rYE +rYE vXM vXM vXM @@ -131332,9 +131330,9 @@ vXM vXM vXM vXM -vXM +xRm siX -vXM +xRm vXM vXM vXM @@ -131590,7 +131588,7 @@ vXM vXM vXM vXM -vXM +xRm vXM vXM vXM diff --git a/_maps/multiz_debug.json b/_maps/multiz_debug.json index 7f44673da3da6..e83101d74d733 100644 --- a/_maps/multiz_debug.json +++ b/_maps/multiz_debug.json @@ -4,6 +4,7 @@ "map_path": "map_files/debug", "map_file": "multiz.dmm", "ignored_unit_tests": [ + "/datum/unit_test/cargo_dep_order_locations", "/datum/unit_test/job_roundstart_spawnpoints", "/datum/unit_test/required_map_items", "/datum/unit_test/spy_bounty" diff --git a/_maps/runtimestation.json b/_maps/runtimestation.json index ee042270c0a3e..12f854ce425e3 100644 --- a/_maps/runtimestation.json +++ b/_maps/runtimestation.json @@ -5,6 +5,7 @@ "map_file": "runtimestation.dmm", "space_ruin_levels": 1, "ignored_unit_tests": [ + "/datum/unit_test/cargo_dep_order_locations", "/datum/unit_test/job_roundstart_spawnpoints", "/datum/unit_test/required_map_items", "/datum/unit_test/spy_bounty" diff --git a/_maps/shuttles/arrival_birdshot.dmm b/_maps/shuttles/arrival_birdshot.dmm index 2288db6bbe24d..d884c22d8db3d 100644 --- a/_maps/shuttles/arrival_birdshot.dmm +++ b/_maps/shuttles/arrival_birdshot.dmm @@ -62,6 +62,11 @@ /obj/machinery/light/cold/directional/north, /turf/open/floor/mineral/titanium/blue, /area/shuttle/arrival) +"x" = ( +/obj/effect/spawner/structure/window/reinforced/shuttle, +/obj/structure/fans/tiny/invisible, +/turf/open/floor/plating, +/area/shuttle/arrival) "B" = ( /turf/open/floor/mineral/titanium/blue, /area/shuttle/arrival) @@ -69,6 +74,7 @@ /obj/machinery/door/airlock/titanium{ name = "Arrivals Shuttle Airlock" }, +/obj/structure/fans/tiny, /turf/open/floor/mineral/titanium/blue, /area/shuttle/arrival) "J" = ( @@ -128,20 +134,20 @@ (1,1,1) = {" a -Q -Q -Q -Q -Q +x +x +x +x +x a "} (2,1,1) = {" a -Q +x f n R -Q +x a "} (3,1,1) = {" @@ -172,22 +178,22 @@ B F "} (6,1,1) = {" -Q +x U B U B U -Q +x "} (7,1,1) = {" -Q +x U B U B U -Q +x "} (8,1,1) = {" V @@ -204,7 +210,7 @@ Q L q w -Q +x a "} (10,1,1) = {" @@ -217,22 +223,22 @@ q V "} (11,1,1) = {" -Q +x U B U B U -Q +x "} (12,1,1) = {" -Q +x U B U B U -Q +x "} (13,1,1) = {" F diff --git a/_maps/shuttles/arrival_box.dmm b/_maps/shuttles/arrival_box.dmm index 3d4a8769d4cdb..53d704515bb25 100644 --- a/_maps/shuttles/arrival_box.dmm +++ b/_maps/shuttles/arrival_box.dmm @@ -9,10 +9,12 @@ /obj/machinery/door/airlock/titanium{ name = "Arrivals Shuttle Airlock" }, +/obj/structure/fans/tiny, /turf/open/floor/plating, /area/shuttle/arrival) "d" = ( /obj/effect/spawner/structure/window/reinforced/shuttle, +/obj/structure/fans/tiny/invisible, /turf/open/floor/plating, /area/shuttle/arrival) "e" = ( diff --git a/_maps/shuttles/arrival_delta.dmm b/_maps/shuttles/arrival_delta.dmm index 649c16bdcf4db..527b50f66c3dd 100644 --- a/_maps/shuttles/arrival_delta.dmm +++ b/_maps/shuttles/arrival_delta.dmm @@ -39,6 +39,7 @@ /area/shuttle/arrival) "ah" = ( /obj/effect/spawner/structure/window/reinforced/shuttle, +/obj/structure/fans/tiny/invisible, /turf/open/floor/plating, /area/shuttle/arrival) "ai" = ( @@ -156,6 +157,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, +/obj/structure/fans/tiny, /turf/open/floor/iron/white, /area/shuttle/arrival) "ap" = ( diff --git a/_maps/shuttles/arrival_donut.dmm b/_maps/shuttles/arrival_donut.dmm index e8ff316a69e7d..e8947674b7c39 100644 --- a/_maps/shuttles/arrival_donut.dmm +++ b/_maps/shuttles/arrival_donut.dmm @@ -38,6 +38,7 @@ /area/shuttle/arrival) "k" = ( /obj/machinery/door/airlock/titanium, +/obj/structure/fans/tiny, /turf/open/floor/plating, /area/shuttle/arrival) "l" = ( @@ -55,6 +56,7 @@ /area/shuttle/arrival) "o" = ( /obj/effect/spawner/structure/window/reinforced/shuttle, +/obj/structure/fans/tiny/invisible, /turf/open/floor/plating, /area/shuttle/arrival) "p" = ( diff --git a/_maps/shuttles/arrival_kilo.dmm b/_maps/shuttles/arrival_kilo.dmm index 3fd328965deae..b59cf8d160dc4 100644 --- a/_maps/shuttles/arrival_kilo.dmm +++ b/_maps/shuttles/arrival_kilo.dmm @@ -16,6 +16,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/structure/fans/tiny, /turf/open/floor/mineral/plastitanium, /area/shuttle/arrival) "ae" = ( @@ -99,6 +100,7 @@ dir = 8 }, /obj/effect/spawner/structure/window/reinforced/shuttle, +/obj/structure/fans/tiny/invisible, /turf/open/floor/plating, /area/shuttle/arrival) "ap" = ( @@ -298,6 +300,11 @@ }, /turf/open/floor/mineral/plastitanium, /area/shuttle/arrival) +"lA" = ( +/obj/effect/spawner/structure/window/reinforced/shuttle, +/obj/structure/fans/tiny/invisible, +/turf/open/floor/plating, +/area/shuttle/arrival) "rV" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -349,7 +356,7 @@ aX aW aQ aY -af +lA "} (5,1,1) = {" ae @@ -367,7 +374,7 @@ rV ay aV aN -af +lA "} (7,1,1) = {" af @@ -376,7 +383,7 @@ rV az aV aN -af +lA "} (8,1,1) = {" af @@ -385,7 +392,7 @@ rV ab aV aN -af +lA "} (9,1,1) = {" ac @@ -435,9 +442,9 @@ ag (14,1,1) = {" ag ac -af -af -af +lA +lA +lA ac ag "} diff --git a/_maps/shuttles/arrival_northstar.dmm b/_maps/shuttles/arrival_northstar.dmm index 888a497bc581f..fadde8f9df42b 100644 --- a/_maps/shuttles/arrival_northstar.dmm +++ b/_maps/shuttles/arrival_northstar.dmm @@ -12,6 +12,7 @@ /obj/machinery/door/airlock/survival_pod/glass{ name = "Arrivals Shuttle Airlock" }, +/obj/structure/fans/tiny, /turf/open/floor/plating, /area/shuttle/arrival) "d" = ( @@ -183,6 +184,7 @@ /area/shuttle/arrival) "Z" = ( /obj/effect/spawner/structure/window/survival_pod, +/obj/structure/fans/tiny/invisible, /turf/open/floor/plating, /area/shuttle/arrival) diff --git a/_maps/shuttles/arrival_pubby.dmm b/_maps/shuttles/arrival_pubby.dmm index 8f2ecdab58c85..e534fd01a4015 100644 --- a/_maps/shuttles/arrival_pubby.dmm +++ b/_maps/shuttles/arrival_pubby.dmm @@ -9,10 +9,12 @@ /obj/machinery/door/airlock/titanium{ name = "Arrivals Shuttle Airlock" }, +/obj/structure/fans/tiny, /turf/open/floor/plating, /area/shuttle/arrival) "d" = ( /obj/effect/spawner/structure/window/reinforced/shuttle, +/obj/structure/fans/tiny/invisible, /turf/open/floor/plating, /area/shuttle/arrival) "e" = ( @@ -53,6 +55,7 @@ name = "Ship Shutters" }, /obj/effect/spawner/structure/window/reinforced/shuttle, +/obj/structure/fans/tiny/invisible, /turf/open/floor/plating, /area/shuttle/arrival) "n" = ( diff --git a/_maps/shuttles/infiltrator_advanced.dmm b/_maps/shuttles/infiltrator_advanced.dmm index 1f04832792108..c9123066874f0 100644 --- a/_maps/shuttles/infiltrator_advanced.dmm +++ b/_maps/shuttles/infiltrator_advanced.dmm @@ -1935,7 +1935,7 @@ /turf/open/floor/mineral/plastitanium, /area/shuttle/syndicate/armory) "tP" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, /obj/structure/sign/warning/electric_shock/directional/north, diff --git a/_maps/shuttles/infiltrator_basic.dmm b/_maps/shuttles/infiltrator_basic.dmm index 1da090f295744..31b85a89f2cd9 100644 --- a/_maps/shuttles/infiltrator_basic.dmm +++ b/_maps/shuttles/infiltrator_basic.dmm @@ -587,7 +587,7 @@ /area/shuttle/syndicate/medical) "fB" = ( /obj/structure/sign/warning/vacuum/external, -/turf/closed/wall/mineral/plastitanium/nodiagonal, +/turf/closed/wall/r_wall/syndicate/nodiagonal, /area/shuttle/syndicate/airlock) "gt" = ( /obj/item/storage/box/handcuffs{ @@ -1096,7 +1096,7 @@ }, /area/shuttle/syndicate/eva) "Xy" = ( -/turf/closed/wall/mineral/plastitanium/nodiagonal, +/turf/closed/wall/r_wall/syndicate/nodiagonal, /area/shuttle/syndicate/airlock) "YN" = ( /turf/open/floor/iron/dark/smooth_corner{ diff --git a/_maps/shuttles/pirate_medieval.dmm b/_maps/shuttles/pirate_medieval.dmm new file mode 100644 index 0000000000000..03441b8a6528d --- /dev/null +++ b/_maps/shuttles/pirate_medieval.dmm @@ -0,0 +1,535 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/template_noop, +/area/template_noop) +"b" = ( +/obj/structure/table/wood, +/obj/item/stack/sheet/mineral/wood/fifty{ + pixel_y = 4 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"c" = ( +/obj/structure/fake_stairs/wood/directional/east, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ + dir = 4 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"d" = ( +/obj/structure/fake_stairs/wood/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ + dir = 4 + }, +/obj/structure/mineral_door/gold, +/turf/open/floor/stone, +/area/shuttle/pirate) +"e" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/botanical_waste, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval, +/turf/open/floor/plating, +/area/shuttle/pirate) +"f" = ( +/obj/structure/window/reinforced/spawner/directional/east, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/shuttle/pirate) +"g" = ( +/obj/structure/fans/tiny, +/obj/structure/window/reinforced/spawner/directional/east, +/obj/structure/mineral_door/iron, +/turf/open/floor/plating, +/area/shuttle/pirate) +"h" = ( +/obj/structure/table/wood, +/obj/item/spear/military{ + pixel_y = 8; + pixel_x = -7 + }, +/obj/item/spear/military{ + pixel_y = 1; + pixel_x = -6 + }, +/obj/item/spear/military{ + pixel_y = -2; + pixel_x = 1 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"j" = ( +/obj/item/flashlight/lantern{ + light_on = 1 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"k" = ( +/obj/structure/table/wood, +/obj/item/restraints/legcuffs/bola/tactical, +/obj/item/restraints/legcuffs/bola/tactical, +/obj/item/restraints/legcuffs/bola/tactical, +/obj/item/restraints/legcuffs/bola, +/obj/item/restraints/legcuffs/bola, +/obj/item/restraints/legcuffs/bola, +/turf/open/floor/stone, +/area/shuttle/pirate) +"l" = ( +/obj/structure/fans/tiny, +/obj/structure/mineral_door/iron, +/turf/open/floor/stone, +/area/shuttle/pirate) +"m" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/turf_decal/arrows{ + dir = 8 + }, +/obj/effect/spawner/random/trash/cigbutt, +/obj/effect/spawner/random/trash/botanical_waste, +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 + }, +/turf/open/floor/plating, +/area/shuttle/pirate) +"n" = ( +/obj/effect/decal/cleanable/vomit/old, +/turf/open/floor/stone, +/area/shuttle/pirate) +"o" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/turf_decal/arrows{ + dir = 4 + }, +/obj/effect/spawner/random/trash/mess, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 4 + }, +/turf/open/floor/plating, +/area/shuttle/pirate) +"p" = ( +/turf/closed/wall/mineral/wood, +/area/shuttle/pirate) +"q" = ( +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval/warlord, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ + dir = 4 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"r" = ( +/obj/structure/window/reinforced/spawner/directional/east, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/garbage, +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval, +/turf/open/floor/plating, +/area/shuttle/pirate) +"s" = ( +/obj/structure/fans/tiny, +/obj/structure/window/reinforced/spawner/directional/east, +/obj/docking_port/mobile/pirate{ + launch_status = 0; + movement_force = list("KNOCKDOWN"=0,"THROW"=0); + name = "Pirate Ship"; + port_direction = 2 + }, +/obj/docking_port/stationary{ + dwidth = 11; + height = 16; + shuttle_id = "pirate_home"; + name = "Deep Space"; + width = 17 + }, +/obj/structure/mineral_door/iron, +/turf/open/floor/plating, +/area/shuttle/pirate) +"u" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/decal/cleanable/blood/gibs/limb, +/obj/effect/decal/cleanable/blood/gibs/body, +/obj/item/food/meat/slab/human/mutant/zombie, +/obj/item/kitchen/fork, +/turf/open/floor/stone, +/area/shuttle/pirate) +"v" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/shuttle/pirate) +"w" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ + dir = 4 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"x" = ( +/obj/structure/fake_stairs/wood/directional/west, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ + dir = 4 + }, +/obj/structure/mineral_door/gold, +/turf/open/floor/stone, +/area/shuttle/pirate) +"y" = ( +/obj/machinery/shuttle_scrambler, +/turf/open/floor/stone, +/area/shuttle/pirate) +"z" = ( +/obj/structure/fans/tiny, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/structure/mineral_door/iron, +/turf/open/floor/plating, +/area/shuttle/pirate) +"A" = ( +/obj/structure/window/reinforced/spawner/directional/east, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/reagent_containers/cup/glass/bottle/vodka, +/turf/open/floor/plating, +/area/shuttle/pirate) +"C" = ( +/obj/machinery/airalarm/directional/west, +/obj/effect/mapping_helpers/airalarm/all_access, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/stone, +/area/shuttle/pirate) +"D" = ( +/obj/machinery/piratepad, +/turf/open/floor/stone, +/area/shuttle/pirate) +"E" = ( +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/obj/structure/barricade/wooden/crude, +/turf/open/floor/stone, +/area/shuttle/pirate) +"F" = ( +/turf/open/floor/stone, +/area/shuttle/pirate) +"G" = ( +/obj/machinery/computer/piratepad_control, +/turf/open/floor/stone, +/area/shuttle/pirate) +"H" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/chair/wood/wings, +/turf/open/floor/stone, +/area/shuttle/pirate) +"I" = ( +/obj/structure/fake_stairs/wood/directional/west, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ + dir = 4 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"J" = ( +/obj/effect/decal/cleanable/blood/gibs/old, +/obj/item/food/burger/human, +/obj/structure/table/wood, +/obj/item/reagent_containers/cup/glass/bottle/rum{ + pixel_y = 15; + pixel_x = -4 + }, +/obj/item/reagent_containers/cup/glass/bottle/rum{ + pixel_y = 8; + pixel_x = 8 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"K" = ( +/obj/structure/table/wood, +/obj/item/stack/medical/poultice{ + pixel_y = 6; + pixel_x = -3 + }, +/obj/item/stack/medical/poultice{ + pixel_y = -3; + pixel_x = 5 + }, +/obj/item/storage/medkit/fire, +/turf/open/floor/stone, +/area/shuttle/pirate) +"L" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"M" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/spawner/random/trash/graffiti, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/shuttle/pirate) +"N" = ( +/obj/machinery/computer/shuttle/pirate/drop_pod, +/turf/open/floor/stone, +/area/shuttle/pirate) +"O" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/fermenting_barrel/thermite, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/obj/item/reagent_containers/cup/beaker/large, +/turf/open/floor/stone, +/area/shuttle/pirate) +"P" = ( +/obj/effect/decal/cleanable/glass, +/turf/open/floor/stone, +/area/shuttle/pirate) +"Q" = ( +/obj/structure/closet/cabinet, +/obj/item/claymore, +/obj/item/shield/kite, +/obj/item/shield/kite, +/obj/item/shield/kite, +/turf/open/floor/stone, +/area/shuttle/pirate) +"R" = ( +/obj/machinery/atmospherics/components/tank/air{ + dir = 1 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"S" = ( +/obj/structure/frame/computer{ + anchored = 1 + }, +/obj/item/assault_pod/medieval, +/turf/open/floor/stone, +/area/shuttle/pirate) +"T" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ + dir = 4 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"U" = ( +/obj/machinery/loot_locator, +/turf/open/floor/stone, +/area/shuttle/pirate) +"V" = ( +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/obj/structure/barricade/wooden/crude, +/turf/open/floor/plating, +/area/shuttle/pirate) +"W" = ( +/obj/structure/table/wood, +/obj/item/radio/intercom{ + pixel_y = 5 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"X" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ + dir = 4 + }, +/obj/structure/table/wood, +/obj/item/bodypart/head/skeleton{ + pixel_x = -6 + }, +/obj/item/bodypart/head/skeleton{ + pixel_y = -2; + pixel_x = 5 + }, +/obj/item/bodypart/head/skeleton{ + pixel_x = 1; + pixel_y = 8 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) +"Y" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/floor/stone, +/area/shuttle/pirate) +"Z" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/flashlight/lantern{ + light_on = 1 + }, +/turf/open/floor/stone, +/area/shuttle/pirate) + +(1,1,1) = {" +a +a +p +p +l +p +p +p +a +"} +(2,1,1) = {" +a +a +g +f +o +r +A +s +a +"} +(3,1,1) = {" +a +a +a +a +I +a +a +a +a +"} +(4,1,1) = {" +p +p +p +p +x +p +E +p +a +"} +(5,1,1) = {" +a +E +R +X +T +C +Q +p +p +"} +(6,1,1) = {" +p +p +W +F +T +j +Y +h +E +"} +(7,1,1) = {" +a +E +N +Y +T +Y +F +k +p +"} +(8,1,1) = {" +V +V +S +P +q +L +F +F +l +"} +(9,1,1) = {" +a +E +y +F +w +n +H +b +p +"} +(10,1,1) = {" +p +p +U +F +w +Z +u +K +E +"} +(11,1,1) = {" +a +E +G +D +T +O +J +p +p +"} +(12,1,1) = {" +p +p +p +p +d +p +E +p +a +"} +(13,1,1) = {" +a +a +a +a +c +a +a +a +a +"} +(14,1,1) = {" +a +a +z +M +m +e +v +z +a +"} +(15,1,1) = {" +a +a +p +p +l +p +p +p +a +"} diff --git a/_maps/shuttles/ruin_pirate_cutter.dmm b/_maps/shuttles/ruin_pirate_cutter.dmm index 018e60f2762c5..2777f06ce8cbd 100644 --- a/_maps/shuttles/ruin_pirate_cutter.dmm +++ b/_maps/shuttles/ruin_pirate_cutter.dmm @@ -753,7 +753,7 @@ }, /area/shuttle/ruin/caravan/pirate) "We" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/effect/turf_decal/stripes/line{ dir = 5 }, diff --git a/_maps/shuttles/ruin_syndicate_dropship.dmm b/_maps/shuttles/ruin_syndicate_dropship.dmm index 449c21eb56a58..dc3e7b68a7b26 100644 --- a/_maps/shuttles/ruin_syndicate_dropship.dmm +++ b/_maps/shuttles/ruin_syndicate_dropship.dmm @@ -376,7 +376,7 @@ /turf/open/floor/pod/dark, /area/shuttle/ruin/caravan/syndicate3) "Oe" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/effect/turf_decal/stripes/line{ dir = 5 }, diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm index 63c0fc2b1683b..febfc926cdc0e 100644 --- a/_maps/templates/lazy_templates/nukie_base.dmm +++ b/_maps/templates/lazy_templates/nukie_base.dmm @@ -124,14 +124,10 @@ /turf/open/floor/plating, /area/centcom/syndicate_mothership/control) "bQ" = ( +/obj/machinery/atmospherics/components/trinary/filter/flipped, /obj/effect/turf_decal/stripes/line{ - dir = 10 - }, -/obj/machinery/atmospherics/components/binary/pump/on{ - dir = 1 + dir = 8 }, -/obj/machinery/airalarm/directional/west, -/obj/effect/mapping_helpers/airalarm/unlocked, /turf/open/floor/mineral/titanium/tiled/yellow, /area/centcom/syndicate_mothership/expansion_bombthreat) "bT" = ( @@ -152,6 +148,10 @@ }, /turf/open/floor/plating, /area/centcom/syndicate_mothership/control) +"bZ" = ( +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "cl" = ( /turf/open/lava/plasma/ice_moon, /area/centcom/syndicate_mothership/control) @@ -161,21 +161,11 @@ /turf/open/floor/iron/smooth, /area/centcom/syndicate_mothership/control) "cA" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/button/ignition/incinerator/ordmix{ - id = "syn_ordmix_igniter"; - pixel_x = -6; - pixel_y = -30 - }, -/obj/machinery/button/door/directional/south{ - id = "syn_ordmix_vent"; - pixel_x = 5; - pixel_y = -29 - }, -/obj/machinery/camera/autoname/directional/south{ - network = list("nukie") +/obj/machinery/portable_atmospherics/pump/lil_pump{ + desc = "A betrayer to pump-kind." }, -/turf/open/floor/mineral/titanium/tiled/yellow, +/obj/effect/turf_decal/stripes/box, +/turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_bombthreat) "cF" = ( /obj/effect/baseturf_helper/asteroid/snow, @@ -349,6 +339,15 @@ }, /turf/open/floor/iron/dark/textured_large, /area/centcom/syndicate_mothership/control) +"dZ" = ( +/obj/machinery/light/small/directional/north, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/structure/closet/crate/bin, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/binoculars, +/obj/item/stack/sheet/animalhide/carp/five, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "ec" = ( /obj/structure/sign/poster/contraband/cc64k_ad, /turf/closed/indestructible/syndicate, @@ -476,7 +475,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/machinery/portable_atmospherics/canister/plasma, /turf/open/floor/plating, /area/centcom/syndicate_mothership/expansion_bombthreat) "fu" = ( @@ -484,10 +483,35 @@ /obj/machinery/light/floor, /turf/open/floor/iron/freezer, /area/centcom/syndicate_mothership/control) +"fv" = ( +/obj/machinery/light/small/directional/south, +/obj/machinery/igniter/incinerator_ordmix{ + id = "syn_ordmix_igniter" + }, +/turf/open/floor/engine/vacuum, +/area/centcom/syndicate_mothership/expansion_bombthreat) "fw" = ( -/obj/item/kirbyplants/random, +/obj/structure/frame/computer, +/obj/effect/decal/cleanable/cobweb, +/obj/structure/sign/poster/contraband/syndiemoth/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) +"fx" = ( +/obj/machinery/light/small/dim/directional/west, +/obj/structure/rack, +/obj/effect/turf_decal/box/white, +/obj/item/stack/cable_coil/thirty{ + pixel_x = 4; + pixel_y = -2 + }, +/obj/item/circuitboard/computer/stationalert{ + pixel_y = 1; + pixel_x = 3 + }, +/obj/item/stack/cable_coil/thirty, +/obj/item/circuitboard/computer/advanced_camera, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "fy" = ( /obj/structure/lattice/catwalk, /obj/effect/turf_decal/stripes/line{ @@ -506,23 +530,6 @@ /obj/item/kirbyplants/random, /turf/open/floor/catwalk_floor/iron_smooth, /area/centcom/syndicate_mothership/control) -"fD" = ( -/obj/structure/window/reinforced/survival_pod/spawner/directional/south{ - name = "Tinted Window" - }, -/obj/structure/table/reinforced/plasmarglass, -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 4 - }, -/obj/item/transfer_valve{ - pixel_x = 5 - }, -/obj/item/transfer_valve, -/obj/item/transfer_valve{ - pixel_x = -5 - }, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/syndicate_mothership/expansion_bombthreat) "fK" = ( /obj/machinery/hydroponics/constructable, /turf/open/floor/mineral/titanium/tiled, @@ -536,6 +543,8 @@ /obj/structure/frame/computer{ dir = 1 }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/computer/security/telescreen/entertainment/directional/south, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "gf" = ( @@ -545,10 +554,10 @@ /turf/open/floor/iron/dark/textured_large, /area/centcom/syndicate_mothership/control) "gh" = ( -/obj/machinery/atmospherics/components/trinary/mixer, /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 4 }, +/obj/machinery/atmospherics/components/unary/portables_connector/visible, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) "go" = ( @@ -601,6 +610,16 @@ }, /turf/open/floor/mineral/titanium/tiled/yellow, /area/centcom/syndicate_mothership/expansion_chemicalwarfare) +"gK" = ( +/obj/effect/turf_decal/stripes/line, +/obj/machinery/computer/atmos_control/noreconnect{ + atmos_chambers = list("nukiebase"="Burn Chamber"); + desc = "Used to monitor the Syndicate Ordnance Laboratory's burn chamber."; + dir = 1; + name = "Ordnance Chamber Monitor" + }, +/turf/open/floor/mineral/titanium/tiled/yellow, +/area/centcom/syndicate_mothership/expansion_bombthreat) "gL" = ( /obj/structure/window/reinforced/survival_pod/spawner/directional/south{ name = "Tinted Window" @@ -618,6 +637,15 @@ }, /turf/open/floor/mineral/titanium/tiled/blue, /area/centcom/syndicate_mothership/control) +"gO" = ( +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/turf/open/floor/mineral/titanium/tiled/blue, +/area/centcom/syndicate_mothership/expansion_bombthreat) "gS" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/general/hidden, /obj/machinery/atmospherics/pipe/smart/manifold4w/orange/hidden/layer5, @@ -714,32 +742,28 @@ /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/control) "ia" = ( -/obj/structure/rack, /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 8 }, -/obj/item/stock_parts/micro_laser/high{ - pixel_x = 12 - }, -/obj/item/wrench{ - desc = "A little smidgeon of Freon..."; - name = "Freon" - }, -/obj/item/stock_parts/micro_laser/high{ - pixel_x = -4; - pixel_y = -8 +/obj/machinery/atmospherics/components/unary/thermomachine/freezer{ + dir = 4 }, -/obj/item/stock_parts/micro_laser/high{ - pixel_x = 8; - pixel_y = 4 +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership/expansion_bombthreat) +"id" = ( +/obj/structure/extinguisher_cabinet/directional/south, +/obj/item/storage/fancy/donut_box, +/obj/structure/rack, +/obj/item/food/syndicake{ + pixel_x = -1; + pixel_y = -1 }, -/obj/item/stock_parts/micro_laser/high{ - pixel_x = -8; - pixel_y = -4 +/obj/item/food/syndicake{ + pixel_x = 1; + pixel_y = 1 }, -/obj/item/melee/powerfist, /turf/open/floor/mineral/plastitanium/red, -/area/centcom/syndicate_mothership/expansion_bombthreat) +/area/centcom/syndicate_mothership) "ig" = ( /obj/effect/turf_decal/siding/wideplating{ dir = 1 @@ -1033,6 +1057,10 @@ /obj/structure/sign/poster/contraband/power/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_chemicalwarfare) +"lx" = ( +/obj/machinery/light/small/dim/directional/east, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "lA" = ( /obj/machinery/door/window/survival_pod/left/directional/west{ name = "Toilet Door" @@ -1070,6 +1098,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/orange/hidden/layer5, /turf/open/floor/iron/smooth, /area/centcom/syndicate_mothership/control) +"lO" = ( +/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{ + dir = 5 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/mineral/titanium/tiled/yellow, +/area/centcom/syndicate_mothership/expansion_bombthreat) "lQ" = ( /obj/structure/chair/sofa/left/brown{ dir = 4 @@ -1196,16 +1233,16 @@ /obj/machinery/light/cold/directional/east, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_bioterrorism) -"nQ" = ( -/turf/closed/indestructible/syndicate, -/area/centcom/syndicate_mothership/expansion_chemicalwarfare) -"nR" = ( +"nN" = ( +/obj/structure/tank_dispenser, /obj/effect/turf_decal/stripes/line{ - dir = 8 + dir = 5 }, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/open/floor/plating, +/turf/open/floor/mineral/titanium/tiled/yellow, /area/centcom/syndicate_mothership/expansion_bombthreat) +"nQ" = ( +/turf/closed/indestructible/syndicate, +/area/centcom/syndicate_mothership/expansion_chemicalwarfare) "nS" = ( /obj/structure/flora/grass/both/style_random, /obj/structure/flora/tree/dead/style_random, @@ -1223,6 +1260,15 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/centcom/syndicate_mothership/control) +"oe" = ( +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 4 + }, +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership/expansion_bombthreat) "oh" = ( /obj/structure/table/reinforced, /obj/item/syndicatedetonator{ @@ -1281,6 +1327,22 @@ dir = 8 }, /area/centcom/syndicate_mothership/control) +"oN" = ( +/obj/structure/rack, +/obj/item/poster/random_contraband{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/item/poster/random_contraband{ + pixel_x = 3; + pixel_y = 8 + }, +/obj/item/poster/random_contraband{ + pixel_x = 1 + }, +/obj/effect/decal/cleanable/cobweb, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "oR" = ( /obj/structure/table/wood, /obj/item/storage/box/donkpockets, @@ -1367,6 +1429,7 @@ /obj/structure/chair/greyscale{ dir = 4 }, +/obj/effect/landmark/start/nukeop_overwatch, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "pU" = ( @@ -1472,16 +1535,6 @@ dir = 4 }, /area/centcom/syndicate_mothership/control) -"qK" = ( -/obj/machinery/computer/atmos_control/noreconnect{ - atmos_chambers = list("nukiebase"="Burn Chamber"); - desc = "Used to monitor the Syndicate Ordnance Laboratory's burn chamber."; - dir = 1; - name = "Ordnance Chamber Monitor" - }, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/mineral/titanium/tiled/yellow, -/area/centcom/syndicate_mothership/expansion_bombthreat) "qN" = ( /turf/open/floor/iron/dark/textured_large, /area/centcom/syndicate_mothership/control) @@ -1610,15 +1663,6 @@ /obj/structure/extinguisher_cabinet/directional/west, /turf/open/floor/mineral/titanium, /area/centcom/syndicate_mothership/control) -"sj" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 1 - }, -/turf/open/floor/mineral/titanium/tiled/blue, -/area/centcom/syndicate_mothership/expansion_bombthreat) "sl" = ( /obj/machinery/light/floor, /turf/open/floor/mineral/plastitanium, @@ -1641,6 +1685,7 @@ /area/centcom/syndicate_mothership/control) "sv" = ( /obj/machinery/light/small/directional/north, +/obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "sE" = ( @@ -1710,6 +1755,17 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/centcom/syndicate_mothership/control) +"tn" = ( +/obj/machinery/airalarm/directional/west, +/obj/effect/mapping_helpers/airalarm/unlocked, +/obj/machinery/atmospherics/components/binary/pump/on{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/turf/open/floor/mineral/titanium/tiled/yellow, +/area/centcom/syndicate_mothership/expansion_bombthreat) "tu" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/siding/red/corner{ @@ -1731,6 +1787,17 @@ /obj/machinery/portable_atmospherics/scrubber, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"tB" = ( +/obj/effect/turf_decal/siding/wideplating{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wideplating, +/obj/machinery/door/airlock/hatch{ + name = "Workout Room" + }, +/obj/effect/mapping_helpers/airlock/access/all/syndicate/general, +/turf/open/floor/mineral/plastitanium, +/area/centcom/syndicate_mothership) "tJ" = ( /obj/effect/light_emitter{ set_cap = 1; @@ -1812,6 +1879,13 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/control) +"vm" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/turf/open/floor/plating, +/area/centcom/syndicate_mothership/expansion_bombthreat) "vv" = ( /obj/structure/table/reinforced, /obj/item/paper/fluff/stations/centcom/disk_memo{ @@ -2014,23 +2088,18 @@ /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_chemicalwarfare) "yi" = ( -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 1 - }, /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 4 }, +/obj/machinery/atmospherics/components/trinary/mixer, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) "ym" = ( -/obj/structure/window/reinforced/survival_pod/spawner/directional/south{ - name = "Tinted Window" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, /obj/machinery/portable_atmospherics/canister/oxygen, /obj/machinery/light/cold/directional/east, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, /turf/open/floor/plating, /area/centcom/syndicate_mothership/expansion_bombthreat) "yp" = ( @@ -2046,6 +2115,10 @@ dir = 8 }, /area/centcom/syndicate_mothership/control) +"yA" = ( +/obj/effect/decal/cleanable/insectguts, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "yB" = ( /obj/machinery/light/small/directional/north, /turf/open/misc/asteroid/snow/icemoon, @@ -2100,12 +2173,12 @@ /area/centcom/syndicate_mothership/control) "zy" = ( /obj/structure/table/reinforced/plasmarglass, -/obj/item/pen{ - pixel_x = 6; - pixel_y = 5 +/obj/item/flashlight/lamp/green{ + pixel_y = 9; + pixel_x = 5 }, -/obj/item/folder/red{ - pixel_x = -5 +/obj/item/circuitboard/computer/overwatch{ + pixel_x = -2 }, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) @@ -2207,13 +2280,14 @@ /turf/open/floor/mineral/titanium/tiled, /area/centcom/syndicate_mothership/control) "AA" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 +/obj/structure/window/reinforced/survival_pod/spawner/directional/south{ + name = "Tinted Window" }, -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 8 +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/effect/turf_decal/stripes/line{ + dir = 10 }, -/turf/open/floor/mineral/titanium/tiled/yellow, +/turf/open/floor/plating, /area/centcom/syndicate_mothership/expansion_bombthreat) "AL" = ( /obj/machinery/light/cold/directional/south, @@ -2482,6 +2556,29 @@ }, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/control) +"DO" = ( +/obj/machinery/button/door/directional/south{ + id = "syn_ordmix_vent"; + pixel_x = 5; + pixel_y = -29 + }, +/obj/machinery/button/ignition/incinerator/ordmix{ + id = "syn_ordmix_igniter"; + pixel_x = -6; + pixel_y = -30 + }, +/obj/effect/turf_decal/stripes/line, +/obj/machinery/camera/autoname/directional/south{ + network = list("nukie") + }, +/turf/open/floor/mineral/titanium/tiled/yellow, +/area/centcom/syndicate_mothership/expansion_bombthreat) +"DV" = ( +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 8 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership/expansion_bombthreat) "DY" = ( /obj/structure/table/wood/poker, /obj/machinery/light/warm/directional/north, @@ -2598,6 +2695,15 @@ /obj/item/flashlight/lamp, /turf/open/floor/carpet, /area/centcom/syndicate_mothership/control) +"FB" = ( +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/mineral/titanium/tiled/yellow, +/area/centcom/syndicate_mothership/expansion_bombthreat) "FG" = ( /obj/effect/turf_decal/stripes/corner, /obj/effect/turf_decal/stripes/corner{ @@ -2626,13 +2732,11 @@ }, /area/centcom/syndicate_mothership/control) "FU" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{ - dir = 5 +/obj/machinery/atmospherics/components/unary/portables_connector/visible, +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 8 }, -/turf/open/floor/mineral/titanium/tiled/yellow, +/turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) "Ga" = ( /obj/effect/turf_decal/siding/wideplating{ @@ -2665,6 +2769,12 @@ }, /turf/open/misc/asteroid/snow/airless, /area/centcom/syndicate_mothership) +"Gm" = ( +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership/expansion_bombthreat) "Gr" = ( /obj/machinery/washing_machine, /obj/structure/extinguisher_cabinet/directional/north, @@ -2937,10 +3047,12 @@ /turf/open/floor/plastic, /area/centcom/syndicate_mothership/expansion_fridgerummage) "If" = ( +/obj/machinery/atmospherics/pipe/smart/simple/general/visible{ + dir = 10 + }, /obj/effect/turf_decal/stripes/line{ - dir = 8 + dir = 9 }, -/obj/machinery/atmospherics/components/trinary/filter/flipped, /turf/open/floor/mineral/titanium/tiled/yellow, /area/centcom/syndicate_mothership/expansion_bombthreat) "In" = ( @@ -2973,6 +3085,15 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/centcom/syndicate_mothership/control) +"IK" = ( +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/turf/open/floor/mineral/titanium/tiled/blue, +/area/centcom/syndicate_mothership/expansion_bombthreat) "IL" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/siding/red, @@ -3037,6 +3158,10 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bioterrorism) +"Jx" = ( +/obj/effect/decal/cleanable/plastic, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "JJ" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 5 @@ -3165,13 +3290,6 @@ /obj/effect/turf_decal/tile/red/full, /turf/open/floor/iron/dark/textured_half, /area/centcom/syndicate_mothership/control) -"Le" = ( -/obj/machinery/igniter/incinerator_ordmix{ - id = "syn_ordmix_igniter" - }, -/obj/machinery/light/small/directional/south, -/turf/open/floor/engine/vacuum, -/area/centcom/syndicate_mothership/expansion_bombthreat) "Lk" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/siding/red{ @@ -3222,13 +3340,6 @@ /obj/item/pen/red, /turf/open/floor/iron/dark/textured_large, /area/centcom/syndicate_mothership/control) -"LF" = ( -/obj/effect/turf_decal/stripes/box, -/obj/machinery/portable_atmospherics/pump/lil_pump{ - desc = "A betrayer to pump-kind." - }, -/turf/open/floor/mineral/plastitanium, -/area/centcom/syndicate_mothership/expansion_bombthreat) "LM" = ( /obj/machinery/atmospherics/components/unary/passive_vent{ dir = 8 @@ -3256,15 +3367,6 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/centcom/syndicate_mothership/control) -"LY" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/atmospherics/components/trinary/filter{ - dir = 8 - }, -/turf/open/floor/mineral/titanium/tiled/yellow, -/area/centcom/syndicate_mothership/expansion_bombthreat) "Mb" = ( /obj/structure/lattice/catwalk, /obj/structure/railing{ @@ -3318,6 +3420,19 @@ /obj/structure/noticeboard/directional/east, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_bioterrorism) +"MA" = ( +/obj/item/stack/sheet/iron/fifty{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/structure/rack, +/obj/item/stack/sheet/glass/fifty{ + pixel_y = 3; + pixel_x = 5 + }, +/obj/item/storage/toolbox/mechanical, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "MD" = ( /obj/machinery/door/airlock/maintenance/external{ name = "Bunk Room 1" @@ -3385,7 +3500,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 5 }, -/obj/machinery/portable_atmospherics/canister, +/obj/machinery/portable_atmospherics/canister/nitrogen, /turf/open/floor/plating, /area/centcom/syndicate_mothership/expansion_bombthreat) "ND" = ( @@ -3398,7 +3513,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 9 }, -/obj/machinery/portable_atmospherics/canister, +/obj/machinery/portable_atmospherics/canister/nitrogen, /turf/open/floor/plating, /area/centcom/syndicate_mothership/expansion_bombthreat) "NP" = ( @@ -3412,66 +3527,45 @@ /obj/effect/turf_decal/siding/wideplating/dark{ dir = 4 }, -/obj/machinery/door/airlock/highsecurity{ - name = "Sky Bridge" - }, -/obj/effect/mapping_helpers/airlock/access/all/syndicate/general, -/turf/open/floor/iron/textured_large, -/area/centcom/syndicate_mothership/control) -"Oc" = ( -/obj/structure/window/reinforced/survival_pod/spawner/directional/south{ - name = "Tinted Window" - }, -/obj/structure/table/reinforced/plasmarglass, -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 8 - }, -/obj/item/assembly/prox_sensor{ - pixel_x = -6; - pixel_y = 4 - }, -/obj/item/assembly/prox_sensor{ - pixel_x = -2; - pixel_y = 3 - }, -/obj/item/assembly/signaler{ - pixel_x = -2; - pixel_y = -2 +/obj/machinery/door/airlock/highsecurity{ + name = "Sky Bridge" }, -/obj/item/assembly/signaler{ - pixel_x = 2; - pixel_y = 5 +/obj/effect/mapping_helpers/airlock/access/all/syndicate/general, +/turf/open/floor/iron/textured_large, +/area/centcom/syndicate_mothership/control) +"Oc" = ( +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 8 }, -/obj/item/assembly/timer{ - pixel_x = 12; - pixel_y = -9 +/obj/structure/rack, +/obj/item/stock_parts/matter_bin/super{ + pixel_x = -4; + pixel_y = -4 }, -/obj/item/assembly/timer{ - pixel_x = 15 +/obj/item/stock_parts/matter_bin/super{ + pixel_x = 6 }, -/obj/item/assembly/prox_sensor{ - pixel_x = -6; +/obj/item/stock_parts/micro_laser/ultra{ + pixel_x = -8; pixel_y = -4 }, -/obj/item/assembly/signaler{ - pixel_x = 5; - pixel_y = 10 +/obj/item/stock_parts/micro_laser/ultra{ + pixel_x = -4; + pixel_y = -8 }, -/obj/item/assembly/timer{ - pixel_x = 18; - pixel_y = 5 +/obj/item/stock_parts/micro_laser/ultra{ + pixel_x = 8; + pixel_y = 4 }, -/obj/machinery/light/cold/directional/west, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/syndicate_mothership/expansion_bombthreat) -"Oh" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 10 +/obj/item/stock_parts/micro_laser/ultra{ + pixel_x = 12 }, -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 1 +/obj/item/wrench{ + desc = "A little smidgeon of Freon..."; + name = "Freon" }, -/turf/open/floor/mineral/titanium/tiled/blue, +/obj/item/melee/powerfist, +/turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) "Oi" = ( /obj/structure/cable, @@ -3483,6 +3577,14 @@ pixel_x = -2; pixel_y = 6 }, +/obj/item/paper/fluff/overwatch{ + pixel_y = 8; + pixel_x = -2 + }, +/obj/item/toy/figure/syndie{ + pixel_x = 5 + }, +/obj/structure/sign/clock/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "Ov" = ( @@ -3670,14 +3772,51 @@ /turf/open/lava/plasma/ice_moon, /area/centcom/syndicate_mothership/control) "Ql" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 9 +/obj/structure/sign/poster/contraband/fun_police/directional/west, +/obj/structure/window/reinforced/survival_pod/spawner/directional/south{ + name = "Tinted Window" }, -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 4 +/obj/machinery/light/cold/directional/west, +/obj/structure/table/reinforced/plasmarglass, +/obj/item/assembly/timer{ + pixel_x = 12; + pixel_y = -9 }, -/obj/structure/sign/poster/contraband/fun_police/directional/west, -/turf/open/floor/mineral/plastitanium, +/obj/item/assembly/timer{ + pixel_x = 15 + }, +/obj/item/assembly/timer{ + pixel_x = 18; + pixel_y = 5 + }, +/obj/item/assembly/signaler{ + pixel_x = -2; + pixel_y = -2 + }, +/obj/item/assembly/signaler{ + pixel_x = 2; + pixel_y = 5 + }, +/obj/item/assembly/signaler{ + pixel_x = 5; + pixel_y = 10 + }, +/obj/item/assembly/prox_sensor{ + pixel_x = -6; + pixel_y = -4 + }, +/obj/item/assembly/prox_sensor{ + pixel_x = -2; + pixel_y = 3 + }, +/obj/item/assembly/prox_sensor{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 8 + }, +/turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) "Qp" = ( /obj/structure/lattice/catwalk, @@ -3706,12 +3845,20 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/centcom/syndicate_mothership/control) +"QD" = ( +/obj/item/flashlight{ + pixel_y = 6 + }, +/obj/structure/rack, +/obj/item/flashlight, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "QJ" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 }, /obj/structure/sign/poster/contraband/c20r/directional/east, -/obj/machinery/portable_atmospherics/canister/plasma, +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, /turf/open/floor/plating, /area/centcom/syndicate_mothership/expansion_bombthreat) "QM" = ( @@ -3728,10 +3875,39 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/centcom/syndicate_mothership/control) +"QS" = ( +/obj/item/soap/syndie, +/obj/structure/rack, +/obj/item/storage/fancy/cigarettes/cigpack_syndicate{ + pixel_x = 5; + pixel_y = 2 + }, +/obj/effect/spawner/random/entertainment/lighter, +/obj/machinery/light/small/directional/north, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Rd" = ( /obj/structure/cable, /turf/open/floor/catwalk_floor/iron, /area/centcom/syndicate_mothership/control) +"Rn" = ( +/obj/item/circuitboard/computer/syndicate_shuttle{ + pixel_x = 2; + pixel_y = 3 + }, +/obj/structure/rack, +/obj/item/stack/cable_coil/thirty{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/effect/turf_decal/box/white, +/obj/item/circuitboard/computer/syndicate_shuttle_docker, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) +"Rr" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Rs" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 1 @@ -3765,6 +3941,17 @@ /obj/structure/flora/rock/icy/style_random, /turf/open/misc/asteroid/snow/airless, /area/centcom/syndicate_mothership) +"RO" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/obj/machinery/light/cold/directional/south, +/obj/machinery/portable_atmospherics/canister, +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium, +/area/centcom/syndicate_mothership/expansion_bombthreat) "RQ" = ( /obj/structure/closet/cardboard, /obj/structure/sign/poster/contraband/busty_backdoor_xeno_babes_6/directional/east, @@ -3830,6 +4017,11 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"St" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/machinery/light_switch/directional/east, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Su" = ( /obj/structure/chair/stool/bar/directional/west, /obj/effect/turf_decal/siding/thinplating/dark{ @@ -3845,14 +4037,21 @@ /turf/open/floor/catwalk_floor/iron_smooth, /area/centcom/syndicate_mothership/control) "SD" = ( -/obj/machinery/atmospherics/components/unary/thermomachine/freezer{ - dir = 4 - }, /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 8 }, +/obj/machinery/portable_atmospherics/pump, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"SJ" = ( +/obj/machinery/atmospherics/components/trinary/filter{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/mineral/titanium/tiled/yellow, +/area/centcom/syndicate_mothership/expansion_bombthreat) "SK" = ( /obj/structure/fence/cut/large, /turf/open/misc/asteroid/snow/airless, @@ -4088,13 +4287,21 @@ }, /area/centcom/syndicate_mothership/control) "VF" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 9 +/obj/structure/window/reinforced/survival_pod/spawner/directional/south{ + name = "Tinted Window" }, -/obj/machinery/atmospherics/pipe/smart/simple/general/visible{ - dir = 10 +/obj/structure/table/reinforced/plasmarglass, +/obj/item/transfer_valve{ + pixel_x = -5 }, -/turf/open/floor/mineral/titanium/tiled/yellow, +/obj/item/transfer_valve, +/obj/item/transfer_valve{ + pixel_x = 5 + }, +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) "VH" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ @@ -4276,6 +4483,11 @@ /obj/machinery/light/cold/directional/east, /turf/open/floor/catwalk_floor/iron_dark, /area/centcom/syndicate_mothership/control) +"XO" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "XQ" = ( /obj/effect/turf_decal/siding/wideplating/dark, /obj/effect/turf_decal/siding/wideplating/dark{ @@ -4289,6 +4501,13 @@ dir = 4 }, /area/centcom/syndicate_mothership/control) +"XS" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/components/unary/passive_vent{ + dir = 8 + }, +/turf/open/space/basic, +/area/space/nearstation) "XT" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 1 @@ -4322,11 +4541,14 @@ /turf/closed/indestructible/rock/snow, /area/centcom/syndicate_mothership) "Yk" = ( +/obj/structure/window/reinforced/survival_pod/spawner/directional/south{ + name = "Tinted Window" + }, +/obj/machinery/portable_atmospherics/canister/oxygen, /obj/effect/turf_decal/stripes/line{ - dir = 5 + dir = 6 }, -/obj/structure/tank_dispenser, -/turf/open/floor/mineral/titanium/tiled/yellow, +/turf/open/floor/plating, /area/centcom/syndicate_mothership/expansion_bombthreat) "Yx" = ( /turf/open/floor/mineral/titanium/tiled/yellow, @@ -4350,13 +4572,6 @@ /obj/structure/cable, /turf/open/floor/catwalk_floor/iron_smooth, /area/centcom/syndicate_mothership/control) -"YJ" = ( -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 8 - }, -/obj/machinery/atmospherics/components/unary/portables_connector/visible, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/syndicate_mothership/expansion_bombthreat) "YO" = ( /obj/effect/turf_decal/siding/wideplating/dark{ dir = 8 @@ -4375,6 +4590,14 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/centcom/syndicate_mothership/control) +"YT" = ( +/obj/structure/rack, +/obj/effect/turf_decal/box/white, +/obj/item/storage/medkit/emergency, +/obj/item/tank/internals/emergency_oxygen/double, +/obj/item/clothing/mask/gas/syndicate, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "YX" = ( /obj/structure/railing{ dir = 6 @@ -4392,9 +4615,9 @@ dir = 4 }, /obj/structure/sign/poster/contraband/fun_police/directional/west, -/obj/machinery/light/cold/directional/south, +/obj/machinery/portable_atmospherics/canister, /obj/effect/turf_decal/stripes/line{ - dir = 10 + dir = 9 }, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_bombthreat) @@ -4444,13 +4667,10 @@ /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/control) "ZF" = ( -/obj/structure/window/reinforced/survival_pod/spawner/directional/south{ - name = "Tinted Window" - }, +/obj/machinery/portable_atmospherics/canister/oxygen, /obj/effect/turf_decal/stripes/line{ - dir = 10 + dir = 8 }, -/obj/machinery/portable_atmospherics/canister/oxygen, /turf/open/floor/plating, /area/centcom/syndicate_mothership/expansion_bombthreat) "ZG" = ( @@ -4491,6 +4711,7 @@ /turf/open/floor/plating/snowed/icemoon, /area/centcom/syndicate_mothership/control) "ZX" = ( +/obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "ZZ" = ( @@ -5254,9 +5475,9 @@ sU sU sU sU -sU -sU -sU +Ye +Ye +Ye Ye Ye Ye @@ -5356,13 +5577,13 @@ sU sU sU sU -sU -sU Ye Ye Kq Kq Kq +Kq +Kq Ye KU KU @@ -5458,12 +5679,12 @@ sU sU sU sU -sU -Ye Ye Kq Kq -Xk +YT +fx +Rn Kq Kq KU @@ -5561,12 +5782,12 @@ sU sU sU Ye -Ye Kq -Kq -Xk -Xk +oN +Jx Xk +Rr +MA Kq Kq uT @@ -5606,7 +5827,7 @@ zQ fR kq Ox -sU +Ox sU sU sU @@ -5664,12 +5885,12 @@ sU sU Ye Kq -Kq -Xk -Xk -Xk +QS Xk Xk +bZ +Rr +id Kq Kq uT @@ -5702,6 +5923,7 @@ ia Oc Ql Zc +RO RD RD RD @@ -5719,7 +5941,6 @@ sU sU sU sU -sU "} (13,1,1) = {" sU @@ -5766,12 +5987,12 @@ sU sU Ye Kq -Xk -Xk -Xk -Xk -Xk -Xk +QD +Rr +lx +bZ +St +XO Xk Kq Kq @@ -5798,13 +6019,14 @@ ZI GU zZ FM -wM +Gm ee +wM yp -fD VF If bQ +tn lC yb Uq @@ -5821,7 +6043,6 @@ sU sU sU sU -sU "} (14,1,1) = {" sU @@ -5871,12 +6092,12 @@ Kq Kq Kq Kq -lg +tB Kq +dZ Xk -Xk -Xk -Kq +yA +tO uT ds HW @@ -5904,12 +6125,13 @@ ae ae ae ae +ae Dl -LF cA +DO RD PM -Le +fv RD Ox sU @@ -5923,7 +6145,6 @@ sU sU sU sU -sU "} (15,1,1) = {" sU @@ -6003,10 +6224,11 @@ TY hX FM iL +DV mB tz -YJ FU +lO xe bs lC @@ -6025,7 +6247,6 @@ sU sU sU sU -sU "} (16,1,1) = {" sU @@ -6104,13 +6325,14 @@ Vr cQ uf RD -Gf +Gm gh yi +oe Gf -LY +SJ te -qK +gK kW oy oy @@ -6127,7 +6349,6 @@ sU sU sU sU -sU "} (17,1,1) = {" sU @@ -6207,12 +6428,13 @@ eK DZ RD NH +vm Tl -nR ZF AA +FB ZG -Oh +IK RD Sj Sj @@ -6229,7 +6451,6 @@ sU sU sU sU -sU "} (18,1,1) = {" sU @@ -6313,11 +6534,12 @@ QJ fl ym Yk +nN XV -sj +gO RD EM -EM +RD RD Ox sU @@ -6331,7 +6553,6 @@ sU sU sU sU -sU "} (19,1,1) = {" sU @@ -6418,8 +6639,9 @@ RD RD RD RD +RD LM -LM +XS RD Ox sU @@ -6433,7 +6655,6 @@ sU sU sU sU -sU "} (20,1,1) = {" sU @@ -6523,6 +6744,7 @@ RD RD RD RD +RD Ox sU sU @@ -6535,7 +6757,6 @@ sU sU sU sU -sU "} (21,1,1) = {" sU @@ -6626,7 +6847,7 @@ Ox Ox Ox Ox -sU +Ox sU sU sU diff --git a/_maps/virtual_domains/pirates.dmm b/_maps/virtual_domains/pirates.dmm index 1d330adcc4ddf..28e64519e5738 100644 --- a/_maps/virtual_domains/pirates.dmm +++ b/_maps/virtual_domains/pirates.dmm @@ -2,11 +2,14 @@ "af" = ( /obj/structure/flora/rock/pile/style_2, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "al" = ( /obj/structure/flora/bush/sunny, /turf/open/misc/grass, /area/virtual_domain/fullbright) +"au" = ( +/turf/open/water/beach, +/area/virtual_domain/protected_space/fullbright) "bb" = ( /obj/effect/turf_decal/weather/sand, /turf/open/floor/wood, @@ -20,7 +23,7 @@ /obj/effect/turf_decal/weather/dirt, /obj/structure/flora/rock/pile, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "bI" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -36,7 +39,7 @@ pixel_y = -3 }, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "cr" = ( /obj/item/stack/cannonball/shellball{ pixel_x = 13; @@ -48,7 +51,7 @@ }, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "cX" = ( /obj/effect/decal/cleanable/dirt/dust, /obj/item/claymore/cutlass, @@ -70,7 +73,7 @@ }, /obj/effect/turf_decal/weather/dirt, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "dc" = ( /turf/open/misc/beach/coast/corner, /area/virtual_domain/fullbright) @@ -84,7 +87,7 @@ "eO" = ( /obj/structure/flora/rock/pile, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "eP" = ( /obj/effect/turf_decal/weather/dirt{ dir = 4 @@ -92,14 +95,14 @@ /turf/open/misc/beach/coast{ dir = 6 }, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "eS" = ( /turf/open/misc/beach/sand, /area/virtual_domain/fullbright) "fd" = ( /obj/structure/flora/grass/jungle/b, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "fh" = ( /obj/structure/flora/bush/sparsegrass, /obj/structure/flora/bush/lavendergrass, @@ -113,7 +116,7 @@ /obj/effect/turf_decal/siding/wood, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "fR" = ( /obj/effect/baseturf_helper/virtual_domain, /turf/closed/indestructible/binary, @@ -156,12 +159,12 @@ dir = 4 }, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "hq" = ( /obj/structure/closet/crate/grave, /obj/structure/flora/grass/jungle/b, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "jp" = ( /obj/effect/landmark/bitrunning/cache_spawn, /turf/open/misc/beach/sand, @@ -218,14 +221,14 @@ /turf/open/misc/beach/sand, /area/virtual_domain/fullbright) "nb" = ( -/obj/effect/turf_decal/weather/sand{ - dir = 9 - }, /obj/structure/fermenting_barrel{ pixel_x = 6; pixel_y = 11 }, -/obj/effect/mob_spawn/ghost_role/human/pirate/skeleton, +/obj/effect/turf_decal/weather/sand{ + dir = 9 + }, +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/pirate, /turf/open/floor/wood{ icon_state = "wood_large" }, @@ -237,11 +240,14 @@ "nN" = ( /obj/structure/flora/rock, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) +"nQ" = ( +/turf/closed/wall/mineral/wood/nonmetal, +/area/virtual_domain/protected_space/fullbright) "oB" = ( /obj/structure/flora/grass/jungle, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "oL" = ( /obj/effect/decal/cleanable/dirt/dust, /obj/structure/bed/maint, @@ -252,7 +258,7 @@ dir = 1 }, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "pi" = ( /obj/structure/flora/rock/style_3, /turf/open/water/beach, @@ -261,9 +267,12 @@ /obj/structure/flora/bush/flowers_br/style_random, /turf/open/misc/grass, /area/virtual_domain/fullbright) +"py" = ( +/turf/closed/indestructible/binary, +/area/virtual_domain/protected_space/fullbright) "qk" = ( /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "qE" = ( /obj/structure/table/wood, /obj/item/book/manual/wiki/ordnance, @@ -284,7 +293,7 @@ "rm" = ( /obj/structure/closet/crate/goldcrate, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "rn" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -303,7 +312,7 @@ pixel_x = -5 }, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "ru" = ( /obj/effect/mapping_helpers/broken_floor, /obj/effect/decal/cleanable/dirt/dust, @@ -315,6 +324,9 @@ /obj/item/toy/plush/beeplushie, /turf/open/floor/wood, /area/virtual_domain/fullbright) +"sb" = ( +/turf/open/water/beach, +/area/virtual_domain/protected_space) "sj" = ( /obj/effect/mine/explosive/light, /turf/open/misc/beach/sand, @@ -382,7 +394,7 @@ dir = 10 }, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "wj" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -401,7 +413,7 @@ pixel_y = -1 }, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "wH" = ( /obj/structure/fluff/beach_umbrella{ pixel_x = -7; @@ -430,7 +442,7 @@ pixel_y = 10 }, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "zj" = ( /obj/effect/mapping_helpers/burnt_floor, /obj/effect/decal/cleanable/garbage, @@ -445,7 +457,7 @@ /obj/item/gun/energy/laser/retro, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "zR" = ( /obj/effect/baseturf_helper/virtual_domain, /turf/template_noop, @@ -508,7 +520,7 @@ pixel_y = 22 }, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "Ci" = ( /turf/closed/wall/mineral/wood/nonmetal, /area/virtual_domain/fullbright) @@ -524,12 +536,12 @@ "CL" = ( /obj/structure/flora/rock/pile/jungle/large, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "Dd" = ( /obj/effect/turf_decal/siding/wood, /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "DM" = ( /turf/closed/mineral/random/jungle, /area/virtual_domain/fullbright) @@ -567,7 +579,7 @@ "Gl" = ( /obj/structure/flora/rock/pile/style_3, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "Gy" = ( /obj/structure/flora/rock/style_2, /turf/open/water/beach, @@ -583,16 +595,20 @@ }, /turf/open/floor/carpet/blue, /area/virtual_domain) +"Iv" = ( +/obj/structure/flora/rock/style_3, +/turf/open/water/beach, +/area/virtual_domain/protected_space/fullbright) "ID" = ( /obj/effect/landmark/bitrunning/cache_spawn, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "IW" = ( /obj/effect/turf_decal/weather/dirt{ dir = 5 }, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "Jf" = ( /obj/structure/flora/bush/sparsegrass, /turf/open/misc/grass, @@ -637,7 +653,10 @@ pixel_y = -4 }, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) +"Li" = ( +/turf/closed/mineral/random/jungle, +/area/virtual_domain/protected_space/fullbright) "LC" = ( /mob/living/basic/trooper/pirate/melee, /turf/open/misc/grass, @@ -649,7 +668,7 @@ }, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "LP" = ( /obj/effect/turf_decal/weather/sand{ dir = 5 @@ -694,11 +713,11 @@ pixel_y = 18 }, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "Oi" = ( /obj/effect/mob_spawn/corpse/human/pirate, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "Ov" = ( /turf/open/misc/beach/coast{ dir = 6 @@ -714,7 +733,7 @@ "Oz" = ( /obj/structure/flora/rock/pile/jungle/style_2, /turf/open/misc/dirt/jungle, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "OD" = ( /obj/effect/turf_decal/weather/sand{ dir = 6 @@ -726,7 +745,7 @@ dir = 1 }, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "Qc" = ( /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood{ @@ -736,12 +755,12 @@ "QF" = ( /obj/effect/turf_decal/weather/dirt, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "QG" = ( /obj/effect/turf_decal/weather/dirt, /obj/effect/turf_decal/weather/dirt, /turf/open/water/beach, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space) "QN" = ( /obj/structure/barricade/sandbags, /obj/effect/turf_decal/weather/sand{ @@ -789,7 +808,7 @@ }, /obj/structure/closet/cabinet, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "RJ" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -861,7 +880,7 @@ dir = 1 }, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "Vx" = ( /obj/structure/flora/rock/style_4, /turf/open/water/beach, @@ -869,7 +888,7 @@ "VE" = ( /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "VG" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -901,7 +920,7 @@ "Wx" = ( /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "WW" = ( /turf/template_noop, /area/virtual_domain/fullbright) @@ -932,7 +951,7 @@ /area/virtual_domain/fullbright) "Yy" = ( /turf/open/floor/wood, -/area/virtual_domain/fullbright) +/area/virtual_domain/protected_space/fullbright) "YJ" = ( /obj/structure/table/wood, /obj/effect/turf_decal/siding/wood{ @@ -1226,10 +1245,10 @@ DM hb hb hb -hb -hb -hb -hb +py +py +py +py xg xg xg @@ -1270,10 +1289,10 @@ DM hb hb DM -DM -DM -DM -hb +Li +Li +Li +py xg xg xg @@ -1314,10 +1333,10 @@ sj hb hb DM -DM -DM -DM -hb +Li +Li +Li +py xg xg xg @@ -1358,13 +1377,13 @@ mp Ov xp xp -xp -xp -xp -hb -hb -hb -hb +au +au +au +py +py +py +py xg xg xg @@ -1402,15 +1421,15 @@ xp xp xp NE -xp -xp -xp -xp -xp -Ci -hb -hb -hb +au +au +au +au +au +nQ +py +py +py xg xg xg @@ -1446,15 +1465,15 @@ xp xp xp Gy -xp -xp -xp -xp -xp -Ci +au +au +au +au +au +nQ bI VE -hb +py hb hb hb @@ -1490,12 +1509,12 @@ xp xp xp xp -xp -xp -xp -xp +au +au +au +au nN -Ci +nQ rn VE fw @@ -1534,12 +1553,12 @@ xp xp xp xp -xp -xp -xp -xp -pi -Ci +au +au +au +au +Iv +nQ QX Yy zk @@ -1578,13 +1597,13 @@ xp xp xp xp -xp -xp -xp -xp -xp -Ci -Ci +au +au +au +au +au +nQ +nQ Yy Dd ub @@ -1622,14 +1641,14 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au +au +au Wx ub ub @@ -1666,15 +1685,15 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au +au +au +au ub ub ub @@ -1710,15 +1729,15 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au +au +au +au ub ub ub @@ -1754,15 +1773,15 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au +au Wx -xp +au ub ub ub @@ -1798,15 +1817,15 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp -Ci +au +au +au +au +au +au +nQ fw -xp +au xp xp xp @@ -1842,12 +1861,12 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au Uw cr vR @@ -1886,13 +1905,13 @@ xp xp xp xp -xp -xp -xp -xp -xp +au +au +au +au +au af -Ci +nQ LK fw xp @@ -1930,12 +1949,12 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au oM VE eO @@ -1974,15 +1993,15 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au +au +au +au xp xp xp @@ -2018,15 +2037,15 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au +au +au +au xp xp xp @@ -2062,15 +2081,15 @@ xp xp xp xp -xp -xp -xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au +au +au +au xp xp DM @@ -2098,7 +2117,7 @@ DM DM DM eP -xp +sb DM DM hb @@ -2106,15 +2125,15 @@ hb xp xp xp -xp -xp -xp -xp -xp -xp -xp -xp -xp +au +au +au +au +au +au +au +au +au hb DM DM @@ -2150,15 +2169,15 @@ hb hb xp xp -xp -xp -xp -xp -xp -xp -xp -xp -hb +au +au +au +au +au +au +au +au +py hb DM DM @@ -2194,15 +2213,15 @@ DM hb hb hb -hb -xp -xp -xp -xp -xp -xp -hb -hb +py +au +au +au +au +au +au +py +py hb hb hb @@ -2231,21 +2250,21 @@ DM DM qk IW -xp +sb DM DM DM DM DM DM -hb -hb -hb -hb -hb -hb -hb -hb +py +py +py +py +py +py +py +py xg xg xg @@ -2277,7 +2296,7 @@ Gl qk IW hn -xp +sb DM DM DM @@ -2322,7 +2341,7 @@ qk qk Oi OW -xp +sb be Oz DM @@ -2366,7 +2385,7 @@ DM qk CL IW -xp +sb QG qk rm diff --git a/_maps/virtual_domains/psyker_zombies.dmm b/_maps/virtual_domains/psyker_zombies.dmm index a20e260bbcf04..1d4307ebdcef8 100644 --- a/_maps/virtual_domains/psyker_zombies.dmm +++ b/_maps/virtual_domains/psyker_zombies.dmm @@ -19,7 +19,7 @@ "h" = ( /obj/structure/rack, /turf/open/indestructible/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "i" = ( /obj/structure/sign/warning/directional/east, /turf/open/chasm, @@ -61,10 +61,20 @@ /obj/effect/mapping_helpers/airlock/abandoned, /turf/open/indestructible/dark, /area/ruin/space/has_grav/powered/virtual_domain) +"D" = ( +/turf/open/indestructible/dark, +/area/virtual_domain/protected_space) "F" = ( /obj/structure/mystery_box/guns, /turf/open/indestructible/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) +"I" = ( +/turf/closed/indestructible/binary, +/area/virtual_domain/protected_space) +"J" = ( +/obj/machinery/door/airlock/abductor, +/turf/open/indestructible/dark, +/area/virtual_domain/protected_space) "K" = ( /obj/effect/baseturf_helper/virtual_domain, /turf/closed/indestructible/binary, @@ -530,10 +540,10 @@ Y Y a Y -a -a -a -a +I +I +I +I a a a @@ -557,10 +567,10 @@ Y Y Y Y -a +I h -Y -Y +D +D t t t @@ -584,10 +594,10 @@ X Y Y Y -a +I F -Y -Y +D +D t t t @@ -611,10 +621,10 @@ a Y Y Y -a -Y -Y -Y +I +D +D +D t t t @@ -638,10 +648,10 @@ Y Y Y Y -T -Y -Y -Y +J +D +D +D t t t @@ -665,10 +675,10 @@ Y R Y Y -a -Y -Y -Y +I +D +D +D t t t @@ -692,10 +702,10 @@ Y Y Y Y -a +I F -Y -Y +D +D t t t @@ -719,10 +729,10 @@ a a Y Y -a +I h -Y -Y +D +D t t t @@ -746,10 +756,10 @@ a a a Y -a -a -a -a +I +I +I +I a a a diff --git a/_maps/virtual_domains/syndicate_assault.dmm b/_maps/virtual_domains/syndicate_assault.dmm index d3cb42a8eeb56..81bb35a257a75 100644 --- a/_maps/virtual_domains/syndicate_assault.dmm +++ b/_maps/virtual_domains/syndicate_assault.dmm @@ -26,7 +26,7 @@ /obj/item/stack/sheet/glass/fifty, /obj/item/stack/rods/fifty, /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "aO" = ( /obj/machinery/recharge_station, /turf/open/floor/mineral/plastitanium, @@ -44,7 +44,7 @@ /area/ruin/space/has_grav/powered/virtual_domain) "bG" = ( /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "cc" = ( /obj/structure/closet/crate/secure/gear{ req_access = list("syndicate") @@ -55,7 +55,7 @@ "cj" = ( /obj/structure/transit_tube/crossing, /turf/closed/wall/r_wall/syndicate, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "ct" = ( /obj/structure/closet/syndicate{ anchored = 1; @@ -115,7 +115,7 @@ /obj/item/gun/ballistic/automatic/l6_saw/unrestricted, /obj/item/ammo_box/magazine/m7mm, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "da" = ( /obj/machinery/stasis, /turf/open/floor/plastic, @@ -132,6 +132,9 @@ /obj/item/paper/fluff/ruins/forgottenship/powerissues, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) +"dp" = ( +/turf/open/floor/mineral/plastitanium, +/area/virtual_domain/protected_space) "dw" = ( /obj/machinery/light/small/directional/south, /turf/open/floor/mineral/plastitanium, @@ -164,11 +167,11 @@ /obj/item/card/id/advanced/black/syndicate_command/crew_id, /obj/item/card/id/advanced/black/syndicate_command/crew_id, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "fd" = ( /obj/structure/transit_tube/crossing, /turf/open/space/basic, -/area/space) +/area/virtual_domain/protected_space) "fG" = ( /obj/structure/toilet{ dir = 1 @@ -185,7 +188,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) "gD" = ( -/obj/effect/mob_spawn/ghost_role/human/syndicatespace, +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/syndie, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/powered/virtual_domain) "hg" = ( @@ -221,7 +224,7 @@ "iL" = ( /obj/structure/sign/departments/cargo, /turf/closed/wall/r_wall/syndicate, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "iU" = ( /obj/structure/closet/crate/secure/gear{ req_access = list("syndicate") @@ -229,7 +232,7 @@ /obj/item/melee/energy/sword/saber/red, /obj/machinery/light/small/directional/north, /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "iW" = ( /obj/structure/table/reinforced, /obj/machinery/button/door{ @@ -319,7 +322,7 @@ dir = 4 }, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "ln" = ( /obj/machinery/turretid{ control_area = "/area/ruin/space/has_grav/syndicate_forgotten_ship"; @@ -350,6 +353,10 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) +"mA" = ( +/obj/machinery/light/small/directional/south, +/turf/open/floor/mineral/plastitanium, +/area/virtual_domain/protected_space) "mD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ dir = 10 @@ -357,12 +364,19 @@ /obj/item/wrench, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) +"mL" = ( +/obj/structure/tank_dispenser/oxygen, +/turf/open/floor/mineral/plastitanium, +/area/virtual_domain/protected_space) "nk" = ( /obj/machinery/power/apc/auto_name/directional/north, /obj/effect/mapping_helpers/apc/syndicate_access, /obj/structure/cable, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/powered/virtual_domain) +"nn" = ( +/turf/closed/mineral/random, +/area/virtual_domain/protected_space) "nB" = ( /turf/closed/mineral/random, /area/space) @@ -428,7 +442,7 @@ "qU" = ( /obj/structure/sign/poster/contraband/c20r, /turf/closed/wall/r_wall/syndicate, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "qY" = ( /obj/machinery/light/small/directional/south, /obj/effect/landmark/bitrunning/cache_spawn, @@ -462,14 +476,14 @@ /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) "rP" = ( -/obj/effect/mob_spawn/ghost_role/human/syndicatespace, /obj/machinery/light/small/directional/south, +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/syndie, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/powered/virtual_domain) "sg" = ( /obj/machinery/ore_silo, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "sq" = ( /obj/machinery/door/window/left/directional/south{ name = "Control Room"; @@ -501,7 +515,7 @@ amount = 15 }, /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "sL" = ( /obj/structure/chair/comfy, /turf/open/floor/mineral/plastitanium, @@ -573,7 +587,7 @@ /obj/item/storage/medkit/regular, /obj/machinery/light/small/directional/north, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "xJ" = ( /obj/structure/closet/syndicate{ anchored = 1; @@ -638,6 +652,9 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) +"zN" = ( +/turf/closed/wall/r_wall/syndicate, +/area/virtual_domain/protected_space) "Aa" = ( /obj/structure/chair/comfy/shuttle, /turf/open/floor/mineral/plastitanium, @@ -645,7 +662,7 @@ "Bm" = ( /obj/effect/baseturf_helper/virtual_domain, /turf/closed/indestructible/syndicate, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "BK" = ( /obj/structure/lattice/catwalk, /obj/structure/cable, @@ -717,7 +734,7 @@ /obj/item/ammo_box/magazine/smgm45, /obj/item/gun/ballistic/automatic/c20r/unrestricted, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "DA" = ( /obj/structure/closet/crate/secure/gear{ req_access = list("syndicate") @@ -790,7 +807,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) "Ia" = ( -/obj/effect/mob_spawn/ghost_role/human/syndicatespace/captain, +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/syndie, /turf/open/floor/carpet/royalblack, /area/ruin/space/has_grav/powered/virtual_domain) "Id" = ( @@ -841,7 +858,7 @@ /obj/structure/cable, /obj/structure/fans/tiny, /turf/open/floor/plating, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "IV" = ( /obj/machinery/door/airlock/grunge{ name = "Syndicate Ship Airlock" @@ -885,7 +902,7 @@ "Lk" = ( /obj/structure/transit_tube/crossing, /turf/closed/mineral/random, -/area/space) +/area/virtual_domain/protected_space) "Lo" = ( /obj/structure/filingcabinet, /obj/machinery/door/window/left/directional/west{ @@ -894,6 +911,10 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) +"LB" = ( +/obj/structure/cable, +/turf/open/floor/mineral/plastitanium, +/area/virtual_domain/protected_space) "Mc" = ( /obj/structure/closet/syndicate{ anchored = 1; @@ -938,7 +959,7 @@ req_access = list("syndicate") }, /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "Nr" = ( /obj/structure/closet/crate/secure/gear{ req_access = list("syndicate") @@ -951,14 +972,14 @@ }, /obj/machinery/light/small/directional/south, /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "Of" = ( /obj/structure/closet/crate/secure/gear{ req_access = list("syndicate") }, /obj/item/disk/surgery/forgottenship, /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "Ox" = ( /obj/machinery/atmospherics/components/unary/vent_pump, /turf/open/floor/mineral/plastitanium, @@ -969,7 +990,7 @@ /obj/item/storage/toolbox/syndicate, /obj/item/storage/toolbox/syndicate, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "OI" = ( /obj/structure/chair/comfy/shuttle{ dir = 1 @@ -988,7 +1009,7 @@ }, /obj/effect/mapping_helpers/airlock/access/all/syndicate/general, /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "Qg" = ( /obj/machinery/suit_storage_unit/syndicate{ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black; @@ -1009,7 +1030,7 @@ /obj/item/dualsaber/green, /obj/machinery/light/small/directional/east, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "QG" = ( /obj/structure/tank_dispenser/oxygen, /turf/closed/mineral/random, @@ -1033,7 +1054,7 @@ "RU" = ( /obj/machinery/suit_storage_unit/syndicate, /turf/open/floor/mineral/plastitanium, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "Sc" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -1078,11 +1099,14 @@ /area/ruin/space/has_grav/powered/virtual_domain) "TB" = ( /turf/closed/indestructible/syndicate, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "UQ" = ( /obj/structure/sign/poster/contraband/syndicate_recruitment, /turf/closed/wall/r_wall/syndicate, /area/ruin/space/has_grav/powered/virtual_domain) +"Vg" = ( +/turf/open/space/basic, +/area/virtual_domain/protected_space) "Vk" = ( /obj/machinery/porta_turret/syndicate/energy{ dir = 4; @@ -1101,7 +1125,7 @@ "Wd" = ( /obj/structure/sign/poster/contraband/tools, /turf/closed/wall/r_wall/syndicate, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "Wy" = ( /obj/structure/closet/crate/secure/gear{ req_access = list("syndicate") @@ -1132,7 +1156,7 @@ /obj/item/clothing/head/helmet/space/syndicate/black/engie, /obj/item/clothing/suit/space/syndicate/black/engie, /turf/open/floor/pod/dark, -/area/ruin/space/has_grav/powered/virtual_domain) +/area/virtual_domain/protected_space) "Yi" = ( /obj/effect/landmark/bitrunning/cache_spawn, /turf/open/floor/plastic, @@ -2611,21 +2635,21 @@ qx nB nB we -ru -ru -uP +zN +zN +dp sg -ru -ru -nB -nB -nB -nB -qx -qx -qx -qx -qx +zN +zN +nn +nn +nn +nn +Vg +Vg +Vg +Vg +Vg sM sM sM @@ -2670,9 +2694,9 @@ qx nB nB qU -Fp -uP -uP +mL +dp +dp li cj Lk @@ -2727,21 +2751,21 @@ qx qx nB nB -ru +zN eB -uP -uP -uP -ru -nB -qx -qx -qx -qx -qx -qx -qx -qx +dp +dp +dp +zN +nn +Vg +Vg +Vg +Vg +Vg +Vg +Vg +Vg sM sM sM @@ -2785,12 +2809,12 @@ qx qx qx nB -ru +zN wL -oM -uP -dw -ru +LB +dp +mA +zN yZ nB nB @@ -2845,10 +2869,10 @@ qx qx Wd OH -oM -uP +LB +dp RU -ru +zN we nB nB @@ -2902,11 +2926,11 @@ BK BK BK IH -oM -oM -uP +LB +LB +dp RU -ru +zN nB nB qx @@ -2961,10 +2985,10 @@ qx qx iL cZ -uP -uP +dp +dp RU -ru +zN nB nB qx @@ -3017,12 +3041,12 @@ qx qx qx nB -ru -ru +zN +zN Dj QF -ru -ru +zN +zN nB nB qx @@ -3076,10 +3100,10 @@ qx nB nB nB -ru -ru -ru -ru +zN +zN +zN +zN nB nB we diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index a588c3ed4d34c..b3cf4b093d442 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -56,8 +56,9 @@ #define DNA_MOTH_MARKINGS_BLOCK 13 #define DNA_MUSHROOM_CAPS_BLOCK 14 #define DNA_POD_HAIR_BLOCK 15 +#define DNA_MONKEY_TAIL_BLOCK 16 -#define DNA_FEATURE_BLOCKS 15 +#define DNA_FEATURE_BLOCKS 16 #define DNA_SEQUENCE_LENGTH 4 #define DNA_MUTATION_BLOCKS 8 diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm index 8597092fbf656..6d034fb0f4092 100644 --- a/code/__DEFINES/_flags.dm +++ b/code/__DEFINES/_flags.dm @@ -115,7 +115,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define UNIQUE_AREA (1<<8) /// If people are allowed to suicide in it. Mostly for OOC stuff like minigames #define BLOCK_SUICIDE (1<<9) -/// Can the Xenobio management console transverse this area by default? +/// If set, this area will be innately traversable by Xenobiology camera consoles. #define XENOBIOLOGY_COMPATIBLE (1<<10) /// If Abductors are unable to teleport in with their observation console #define ABDUCTOR_PROOF (1<<11) @@ -129,6 +129,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define EVENT_PROTECTED (1<<15) /// This Area Doesn't have Flood or Bomb Admin Messages, but will still log #define QUIET_LOGS (1<<16) +/// This area does not allow virtual entities to enter. +#define VIRTUAL_SAFE_AREA (1<<17) /* These defines are used specifically with the atom/pass_flags bitmask @@ -312,3 +314,5 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define EMOTE_VISIBLE (1<<1) /// Is it an emote that should be shown regardless of blindness/deafness #define EMOTE_IMPORTANT (1<<2) +/// Emote only prints to runechat, not to the chat window +#define EMOTE_RUNECHAT (1<<3) diff --git a/code/__DEFINES/_protect.dm b/code/__DEFINES/_protect.dm index 9152cfcb5706f..a1202ebaf323b 100644 --- a/code/__DEFINES/_protect.dm +++ b/code/__DEFINES/_protect.dm @@ -11,7 +11,7 @@ return FALSE;\ }\ ##Path/Read(savefile/savefile){\ - qdel(src);\ + del(src);\ }\ ##Path/Write(savefile/savefile){\ return;\ @@ -19,3 +19,4 @@ #else #define GENERAL_PROTECT_DATUM(Path) #endif +// we del instead of qdel because for security reasons we must ensure the datum does not exist if Read is called. qdel will not enforce this. diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index f00264d6b1a9f..ef254589129c4 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -543,7 +543,6 @@ /obj/item/modular_computer/pda/clown = list(REGION_GENERAL), \ /obj/item/modular_computer/pda/mime = list(REGION_GENERAL), \ /obj/item/modular_computer/pda/medical = list(REGION_MEDBAY), \ - /obj/item/modular_computer/pda/viro = list(REGION_MEDBAY), \ /obj/item/modular_computer/pda/coroner = list(REGION_MEDBAY), \ /obj/item/modular_computer/pda/engineering = list(REGION_ENGINEERING), \ /obj/item/modular_computer/pda/security = list(REGION_SECURITY), \ diff --git a/code/__DEFINES/achievements.dm b/code/__DEFINES/achievements.dm index 60b9ed039487c..e46fef9123e18 100644 --- a/code/__DEFINES/achievements.dm +++ b/code/__DEFINES/achievements.dm @@ -55,6 +55,7 @@ #define MEDAL_GODS_WRATH "God's Wrath" #define MEDAL_EARTHQUAKE_VICTIM "Earthquake Victim" #define MEDAL_DEBT_EXTINGUISHED "Debt Extinguished" +#define MEDAL_SISYPHUS "Sisyphus" #define MEDAL_ARCHMAGE "Archmage" #define MEDAL_THEORETICAL_LIMITS "All Within Theoretical Limits" diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index fbc223f62a5c1..84b0229a97612 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -23,6 +23,8 @@ #define BANTYPE_ANY_JOB 9 //Admin Permissions +/// Used for signifying that all admins can use this regardless of actual permissions +#define R_NONE NONE #define R_BUILD (1<<0) #define R_ADMIN (1<<1) #define R_BAN (1<<2) @@ -174,4 +176,3 @@ GLOBAL_VAR_INIT(ghost_role_flags, ALL) /// Used in logging uses of admin verbs (and sometimes some non-admin or debug verbs) to the blackbox /// Only pass it a string key, the verb being used. #define BLACKBOX_LOG_ADMIN_VERB(the_verb) SSblackbox.record_feedback("tally", "admin_verb", 1, the_verb) - diff --git a/code/__DEFINES/admin_verb.dm b/code/__DEFINES/admin_verb.dm new file mode 100644 index 0000000000000..04806e098b2c4 --- /dev/null +++ b/code/__DEFINES/admin_verb.dm @@ -0,0 +1,93 @@ +/client/CanProcCall(procname) + if(findtext(procname, "__avd_") == 1) + message_admins("[key_name_admin(usr)] attempted to directly call admin verb '[procname]'.") + log_admin("[key_name(usr)] attempted to directly call admin verb '[procname]'.") + return FALSE + return ..() + +/** + * This is the only macro you should use to define admin verbs. + * It will define the verb and the verb holder for you. + * Using it is very simple: + * ADMIN_VERB(verb_path, R_PERM, "Name", "Description", "Admin.Category", args...) + * This sets up all of the above and also acts as syntatic sugar as a verb delcaration for the verb itself. + * Note that the verb args have an injected `client/user` argument that is the user that called the verb. + * Do not use usr in your verb; technically you can but I'll kill you. + */ +#define _ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, show_in_context_menu, verb_args...) \ +/datum/admin_verb/##verb_path_name \ +{ \ + name = ##verb_name; \ + description = ##verb_desc; \ + category = ##verb_category; \ + permissions = ##verb_permissions; \ + verb_path = /client/proc/__avd_##verb_path_name; \ +}; \ +/client/proc/__avd_##verb_path_name(##verb_args) \ +{ \ + set name = ##verb_name; \ + set desc = ##verb_desc; \ + set hidden = FALSE; /* this is explicitly needed as the proc begins with an underscore */ \ + set popup_menu = ##show_in_context_menu; \ + set category = ##verb_category; \ + var/list/_verb_args = list(usr, /datum/admin_verb/##verb_path_name); \ + _verb_args += args; \ + SSadmin_verbs.dynamic_invoke_verb(arglist(_verb_args)); \ +}; \ +/datum/admin_verb/##verb_path_name/__avd_do_verb(client/user, ##verb_args) + +#define ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, verb_args...) \ +_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, FALSE, ##verb_args) + +#define ADMIN_VERB_ONLY_CONTEXT_MENU(verb_path_name, verb_permissions, verb_name, verb_args...) \ +_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, TRUE, ##verb_args) + +#define ADMIN_VERB_AND_CONTEXT_MENU(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, verb_args...) \ +_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, TRUE, ##verb_args) + +/// Used to define a special check to determine if the admin verb should exist at all. Useful for verbs such as play sound which require configuration. +#define ADMIN_VERB_CUSTOM_EXIST_CHECK(verb_path_name) \ +/datum/admin_verb/##verb_path_name/__avd_check_should_exist() + +/// Used to define the visibility flag of the verb. If the admin does not have this flag enabled they will not see the verb. +#define ADMIN_VERB_VISIBILITY(verb_path_name, verb_visibility) /datum/admin_verb/##verb_path_name/visibility_flag = ##verb_visibility + +// These are put here to prevent the "procedure override precedes definition" error. +/datum/admin_verb/proc/__avd_get_verb_path() + CRASH("__avd_get_verb_path not defined. use the macro") +/datum/admin_verb/proc/__avd_do_verb(...) + CRASH("__avd_do_verb not defined. use the macro") +/datum/admin_verb/proc/__avd_check_should_exist() + return TRUE + +/* + * This is an example of how to use the above macro: + * ``` + * ADMIN_VERB(name_of_verb, R_ADMIN, "Verb Name", "Verb Desc", "Verb Category", mob/target in world) + * to_chat(user, "Hello!") + * ``` + * Note the implied `client/user` argument that is injected into the verb. + * Also note that byond is shit and you cannot multi-line the macro call. + */ + +/// Use this to mark your verb as not having a description. Should ONLY be used if you are also hiding the verb! +#define ADMIN_VERB_NO_DESCRIPTION "" +/// Used to verbs you do not want to show up in the master verb panel. +#define ADMIN_CATEGORY_HIDDEN null + +// Admin verb categories +#define ADMIN_CATEGORY_MAIN "Admin" +#define ADMIN_CATEGORY_EVENTS "Admin.Events" +#define ADMIN_CATEGORY_FUN "Admin.Fun" +#define ADMIN_CATEGORY_GAME "Admin.Game" + +// Special categories that are seperated +#define ADMIN_CATEGORY_DEBUG "Debug" +#define ADMIN_CATEGORY_SERVER "Server" +#define ADMIN_CATEGORY_OBJECT "Object" +#define ADMIN_CATEGORY_MAPPING "Mapping" +#define ADMIN_CATEGORY_PROFILE "Profile" +#define ADMIN_CATEGORY_IPINTEL "Admin.IPIntel" + +// Visibility flags +#define ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG "Map-Debug" diff --git a/code/__DEFINES/ai/ai.dm b/code/__DEFINES/ai/ai.dm index 65cc421490866..2f567be2d571d 100644 --- a/code/__DEFINES/ai/ai.dm +++ b/code/__DEFINES/ai/ai.dm @@ -2,13 +2,22 @@ #define GET_TARGETING_STRATEGY(targeting_type) SSai_behaviors.targeting_strategies[targeting_type] #define HAS_AI_CONTROLLER_TYPE(thing, type) istype(thing?.ai_controller, type) -#define AI_STATUS_ON 1 -#define AI_STATUS_OFF 2 +//AI controller flags +//If you add a new status, be sure to add it to the ai_controllers subsystem's ai_controllers_by_status list. +///The AI is currently active. +#define AI_STATUS_ON "ai_on" +///The AI is currently offline for any reason. +#define AI_STATUS_OFF "ai_off" +///The AI is currently in idle mode. +#define AI_STATUS_IDLE "ai_idle" ///For JPS pathing, the maximum length of a path we'll try to generate. Should be modularized depending on what we're doing later on #define AI_MAX_PATH_LENGTH 30 // 30 is possibly overkill since by default we lose interest after 14 tiles of distance, but this gives wiggle room for weaving around obstacles #define AI_BOT_PATH_LENGTH 150 +// How far should we, by default, be looking for interesting things to de-idle? +#define AI_DEFAULT_INTERESTING_DIST 10 + ///Cooldown on planning if planning failed last time #define AI_FAILED_PLANNING_COOLDOWN (1.5 SECONDS) @@ -16,6 +25,16 @@ ///Flags for ai_behavior new() #define AI_CONTROLLER_INCOMPATIBLE (1<<0) +//Return flags for ai_behavior/perform() +///Update this behavior's cooldown +#define AI_BEHAVIOR_DELAY (1<<0) +///Finish the behavior successfully +#define AI_BEHAVIOR_SUCCEEDED (1<<1) +///Finish the behavior unsuccessfully +#define AI_BEHAVIOR_FAILED (1<<2) + +#define AI_BEHAVIOR_INSTANT (NONE) + ///Does this task require movement from the AI before it can be performed? #define AI_BEHAVIOR_REQUIRE_MOVEMENT (1<<0) ///Does this require the current_movement_target to be adjacent and in reach? diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index df9b8be10750d..1a2b19740f612 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -14,6 +14,11 @@ #define BB_BREED_READY "BB_breed_ready" ///maximum kids we can have #define BB_MAX_CHILDREN "BB_max_children" +///our current happiness level +#define BB_BASIC_HAPPINESS "BB_basic_happiness" +///can this mob heal? +#define BB_BASIC_MOB_HEALER "BB_basic_mob_healer" + /// Store a single or list of emotes at this key #define BB_EMOTE_KEY "BB_emotes" @@ -144,3 +149,8 @@ ///Text we display when we befriend someone #define BB_FRIENDLY_MESSAGE "friendly_message" + +// Keys used by one and only one behavior +// Used to hold state without making bigass lists +/// For /datum/ai_behavior/find_potential_targets, what if any field are we using currently +#define BB_FIND_TARGETS_FIELD(type) "bb_find_targets_field_[type]" diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index ad81aed61b209..c865c578d6324 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -238,6 +238,8 @@ GLOBAL_LIST_INIT(ai_employers, list( #define IS_LUNATIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/lunatic)) /// Checks if the given mob is either a heretic, heretic monster or a lunatic. #define IS_HERETIC_OR_MONSTER(mob) (IS_HERETIC(mob) || IS_HERETIC_MONSTER(mob) || IS_LUNATIC(mob)) +/// CHecks if the given mob is in the mansus realm +#define IS_IN_MANSUS(mob) (istype(get_area(mob), /area/centcom/heretic_sacrifice)) /// Checks if the given mob is a wizard #define IS_WIZARD(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/wizard)) @@ -251,6 +253,9 @@ GLOBAL_LIST_INIT(ai_employers, list( /// Checks if the given mob is a malf ai. #define IS_MALF_AI(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/malf_ai)) +/// Checks if the given mob is a spy! +#define IS_SPY(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/spy)) + /// List of human antagonist types which don't spawn directly on the space station GLOBAL_LIST_INIT(human_invader_antagonists, list( /datum/antagonist/abductor, @@ -397,3 +402,6 @@ GLOBAL_LIST_INIT(human_invader_antagonists, list( #define SPY_DIFFICULTY_MEDIUM "Medium" /// Very difficult to accomplish, almost guaranteed to require crew conflict #define SPY_DIFFICULTY_HARD "Hard" + +/// Camera net used by battle royale objective +#define BATTLE_ROYALE_CAMERA_NET "battle_royale_camera_net" diff --git a/code/__DEFINES/apc_defines.dm b/code/__DEFINES/apc_defines.dm index 3ce6e4a873c85..ee6c2bb67d636 100644 --- a/code/__DEFINES/apc_defines.dm +++ b/code/__DEFINES/apc_defines.dm @@ -58,7 +58,7 @@ /// How long it takes an ethereal to drain or charge APCs. Also used as a spam limiter. #define APC_DRAIN_TIME (7.5 SECONDS) /// How much power ethereals gain/drain from APCs. -#define APC_POWER_GAIN (200 KILO JOULES) +#define APC_POWER_GAIN (0.2 * STANDARD_CELL_CHARGE) // Wires & EMPs: /// The wire value used to reset the APCs wires after one's EMPed. diff --git a/code/__DEFINES/arcades.dm b/code/__DEFINES/arcades.dm new file mode 100644 index 0000000000000..fac3e8091d3aa --- /dev/null +++ b/code/__DEFINES/arcades.dm @@ -0,0 +1,15 @@ +///Goes in the Weapon slot. +#define WEAPON_SLOT "Weapon" +///Goes in the Armor slot. +#define ARMOR_SLOT "Armor" + +//Worlds found in Battle Arcade +#define BATTLE_WORLD_ONE "The Plains" +#define BATTLE_WORLD_TWO "The Forest" +#define BATTLE_WORLD_THREE "The Mountains" +#define BATTLE_WORLD_FOUR "The Desert" +#define BATTLE_WORLD_FIVE "The Swamp" +#define BATTLE_WORLD_SIX "The Ocean" +#define BATTLE_WORLD_SEVEN "The Sky" +#define BATTLE_WORLD_EIGHT "The Moon" +#define BATTLE_WORLD_NINE "The Void" diff --git a/code/__DEFINES/area_editor.dm b/code/__DEFINES/area_editor.dm deleted file mode 100644 index f0ef57c7e529e..0000000000000 --- a/code/__DEFINES/area_editor.dm +++ /dev/null @@ -1,5 +0,0 @@ -// Used to edit areas. -#define AREA_ERRNONE 0 -#define AREA_STATION 1 -#define AREA_SPACE 2 -#define AREA_SPECIAL 3 diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 8bb5a3344753f..7df79b7e57a26 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -114,7 +114,6 @@ #define SECHUD_SHAFT_MINER "hudshaftminer" #define SECHUD_STATION_ENGINEER "hudstationengineer" #define SECHUD_VETERAN_ADVISOR "hudveteranadvisor" -#define SECHUD_VIROLOGIST "hudvirologist" #define SECHUD_WARDEN "hudwarden" #define SECHUD_CHEF "hudchef" diff --git a/code/__DEFINES/basic_mobs.dm b/code/__DEFINES/basic_mobs.dm index b673d0e7a120b..ae74872cd7302 100644 --- a/code/__DEFINES/basic_mobs.dm +++ b/code/__DEFINES/basic_mobs.dm @@ -14,6 +14,8 @@ #define IMMUNE_TO_FISTS (1<<4) /// Mob is immune to getting wet #define IMMUNE_TO_GETTING_WET (1<<5) +/// Disables the function of attacking random body zones +#define PRECISE_ATTACK_ZONES (1<<6) /// Temporary trait applied when an attack forecast animation has completed #define TRAIT_BASIC_ATTACK_FORECAST "trait_basic_attack_forecast" @@ -30,3 +32,43 @@ ///keeps track of how many gutlunches are born GLOBAL_VAR_INIT(gutlunch_count, 0) + +//raptor defines + +#define RAPTOR_RED "Red" +#define RAPTOR_GREEN "Green" +#define RAPTOR_PURPLE "Purple" +#define RAPTOR_WHITE "White" +#define RAPTOR_YELLOW "Yellow" +#define RAPTOR_BLACK "Black" +#define RAPTOR_BLUE "Blue" + +#define RAPTOR_INHERIT_MAX_ATTACK 5 +#define RAPTOR_INHERIT_MAX_HEALTH 30 + +///this mob suffers depression +#define BB_BASIC_DEPRESSED "basic_depressed" +///this mob will care for its young +#define BB_RAPTOR_MOTHERLY "raptor_motherly" +///this mob will be playful around their owners +#define BB_RAPTOR_PLAYFUL "raptor_playful" +///this mob will flee combat when it feels threatened +#define BB_RAPTOR_COWARD "raptor_coward" +///this mob will go out seeking trouble against its kind +#define BB_RAPTOR_TROUBLE_MAKER "raptor_trouble_maker" +///cooldown till we go out cause trouble again +#define BB_RAPTOR_TROUBLE_COOLDOWN "raptor_trouble_maker_cooldown" +///our raptor baby target we will take care of +#define BB_RAPTOR_BABY "raptor_baby" +///the raptor we will heal up +#define BB_INJURED_RAPTOR "injured_raptor" +///the raptor we will bully +#define BB_RAPTOR_VICTIM "raptor_victim" +///the cooldown for next time we eat +#define BB_RAPTOR_EAT_COOLDOWN "raptor_eat_cooldown" +///our trough target +#define BB_RAPTOR_TROUGH_TARGET "raptor_trough_target" + +#define MAX_RAPTOR_POP 64 + + diff --git a/code/__DEFINES/cameranets.dm b/code/__DEFINES/cameranets.dm index 1dea0cd18aec4..15b4493738e2f 100644 --- a/code/__DEFINES/cameranets.dm +++ b/code/__DEFINES/cameranets.dm @@ -26,3 +26,4 @@ #define CAMERANET_NETWORK_BAR "bar" #define CAMERANET_NETWORK_INTERROGATION "interrogation" #define CAMERANET_NETWORK_ABDUCTOR "abductor" +#define OPERATIVE_CAMERA_NET "operative" diff --git a/code/__DEFINES/click.dm b/code/__DEFINES/click.dm new file mode 100644 index 0000000000000..5900dd54210ca --- /dev/null +++ b/code/__DEFINES/click.dm @@ -0,0 +1,8 @@ +/// Action has succeeded, preventing further alt click interaction +#define CLICK_ACTION_SUCCESS (1<<0) +/// Action failed, preventing further alt click interaction +#define CLICK_ACTION_BLOCKING (1<<1) +/// Either return state +#define CLICK_ACTION_ANY (CLICK_ACTION_SUCCESS | CLICK_ACTION_BLOCKING) + +/// Use NONE for continue interaction diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 847fd52cc2232..686e422b02019 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -282,6 +282,8 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define BODY_ZONE_L_LEG "l_leg" #define BODY_ZONE_R_LEG "r_leg" +GLOBAL_LIST_INIT(all_body_zones, list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)) +GLOBAL_LIST_INIT(limb_zones, list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)) GLOBAL_LIST_INIT(arm_zones, list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) #define BODY_ZONE_PRECISE_EYES "eyes" diff --git a/code/__DEFINES/construction/structures.dm b/code/__DEFINES/construction/structures.dm index 1b4ea8aa11297..e48dc078ca4bc 100644 --- a/code/__DEFINES/construction/structures.dm +++ b/code/__DEFINES/construction/structures.dm @@ -48,9 +48,11 @@ #define AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS 1 #define AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER 2 -//blast door (de)construction states +///The blast door is missing wires, first step of construction. #define BLASTDOOR_NEEDS_WIRES 0 +///The blast door needs electronics, second step of construction. #define BLASTDOOR_NEEDS_ELECTRONICS 1 +///The blast door is fully constructed. #define BLASTDOOR_FINISHED 2 //floodlights because apparently we use defines now diff --git a/code/__DEFINES/crafting.dm b/code/__DEFINES/crafting.dm index 647278aa3ec0b..54dc479aa7306 100644 --- a/code/__DEFINES/crafting.dm +++ b/code/__DEFINES/crafting.dm @@ -7,6 +7,28 @@ ///If the structure is only "used" i.e. it checks to see if it's nearby and allows crafting, but doesn't delete it #define CRAFTING_STRUCTURE_USE 0 +//stack recipe placement check types +/// Checks if there is an object of the result type in any of the cardinal directions +#define STACK_CHECK_CARDINALS (1<<0) +/// Checks if there is an object of the result type within one tile +#define STACK_CHECK_ADJACENT (1<<1) + +//---- Defines for var/crafting_flags +///If this craft must be learned before it becomes available +#define CRAFT_MUST_BE_LEARNED (1<<0) +///Should only one object exist on the same turf? +#define CRAFT_ONE_PER_TURF (1<<1) +/// Setting this to true will effectively set check_direction to true. +#define CRAFT_IS_FULLTILE (1<<2) +/// If this craft should run the direction check, for use when building things like directional windows where you can have more than one per turf +#define CRAFT_CHECK_DIRECTION (1<<3) +/// If the craft requires a floor below +#define CRAFT_ON_SOLID_GROUND (1<<4) +/// If the craft checks that there are objects with density in the same turf when being built +#define CRAFT_CHECK_DENSITY (1<<5) +/// If the created atom will gain custom mat datums +#define CRAFT_APPLIES_MATS (1<<6) + //food/drink crafting defines //When adding new defines, please make sure to also add them to the encompassing list #define CAT_FOOD "Foods" diff --git a/code/__DEFINES/dcs/signals/signals_ai_controller.dm b/code/__DEFINES/dcs/signals/signals_ai_controller.dm index fa442c3d186af..a405ad65e8734 100644 --- a/code/__DEFINES/dcs/signals/signals_ai_controller.dm +++ b/code/__DEFINES/dcs/signals/signals_ai_controller.dm @@ -1,3 +1,7 @@ ///sent from ai controllers when they possess a pawn: (datum/ai_controller/source_controller) #define COMSIG_AI_CONTROLLER_POSSESSED_PAWN "ai_controller_possessed_pawn" +///sent from ai controllers when they pick behaviors: (list/datum/ai_behavior/old_behaviors, list/datum/ai_behavior/new_behaviors) +#define COMSIG_AI_CONTROLLER_PICKED_BEHAVIORS "ai_controller_picked_behaviors" +///sent from ai controllers when a behavior is inserted into the queue: (list/new_arguments) +#define AI_CONTROLLER_BEHAVIOR_QUEUED(type) "ai_controller_behavior_queued_[type]" diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm index 932fc008848f5..f79f91ff641b0 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm @@ -18,6 +18,7 @@ #define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal" //from base of atom/attack_basic_mob(): (/mob/user) #define COMSIG_ATOM_ATTACK_BASIC_MOB "attack_basic_mob" + #define COMSIG_BASIC_ATTACK_CANCEL_CHAIN (1<<0) /// from /atom/proc/atom_break: (damage_flag) #define COMSIG_ATOM_BREAK "atom_break" /// from base of [/atom/proc/atom_fix]: () diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm index 24524395f35f2..f4dcd49664160 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -12,10 +12,9 @@ ///from base of atom/get_examine_name(): (/mob, list/overrides) #define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //Positions for overrides list - #define EXAMINE_POSITION_ARTICLE (1<<0) - #define EXAMINE_POSITION_BEFORE (1<<1) - //End positions - #define COMPONENT_EXNAME_CHANGED (1<<0) + #define EXAMINE_POSITION_ARTICLE 1 + #define EXAMINE_POSITION_BEFORE 2 + #define EXAMINE_POSITION_NAME 3 ///from base of atom/examine(): (/mob, list/examine_text, can_see_inside) #define COMSIG_ATOM_REAGENT_EXAMINE "atom_reagent_examine" /// Stop the generic reagent examine text diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm index 3ff131d9a395d..06d372ceb0d33 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm @@ -9,11 +9,12 @@ ///from base of atom/ShiftClick(): (/mob) #define COMSIG_CLICK_SHIFT "shift_click" #define COMPONENT_ALLOW_EXAMINATE (1<<0) //! Allows the user to examinate regardless of client.eye. +///from base of atom/ShiftClick() +#define COMSIG_SHIFT_CLICKED_ON "shift_clicked_on" ///from base of atom/CtrlClickOn(): (/mob) #define COMSIG_CLICK_CTRL "ctrl_click" ///from base of atom/AltClick(): (/mob) #define COMSIG_CLICK_ALT "alt_click" - #define COMPONENT_CANCEL_CLICK_ALT (1<<0) ///from base of atom/alt_click_secondary(): (/mob) #define COMSIG_CLICK_ALT_SECONDARY "alt_click_secondary" #define COMPONENT_CANCEL_CLICK_ALT_SECONDARY (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index 42b2b2ce2b350..bc73dbf32914a 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -119,3 +119,7 @@ /// Sent to movables when they are being stolen by a spy: (mob/living/spy, datum/spy_bounty/bounty) #define COMSIG_MOVABLE_SPY_STEALING "movable_spy_stealing" +/// Called when something is pushed by a living mob bumping it: (mob/living/pusher, push force) +#define COMSIG_MOVABLE_BUMP_PUSHED "movable_bump_pushed" + /// Stop it from moving + #define COMPONENT_NO_PUSH (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_bitrunning.dm b/code/__DEFINES/dcs/signals/signals_bitrunning.dm index 74d418182d597..150c26080221c 100644 --- a/code/__DEFINES/dcs/signals/signals_bitrunning.dm +++ b/code/__DEFINES/dcs/signals/signals_bitrunning.dm @@ -44,3 +44,6 @@ // Ladder /// from /obj/structure/hololadder/disconnect() #define COMSIG_BITRUNNER_LADDER_SEVER "bitrunner_ladder_sever" + +/// Sent when a server console is emagged +#define COMSIG_BITRUNNER_SERVER_EMAGGED "bitrunner_server_emagged" diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 41c2b4b7459c1..5e9011f5f4075 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -103,3 +103,6 @@ /// Global signal sent when narsie summon count is updated: (new count) #define COMSIG_NARSIE_SUMMON_UPDATE "!narsie_summon_update" + +/// Global signal sent when a mob is spawned from a ghost in a dynamic ruleset (mob/spawned_mob) +#define COMSIG_RULESET_BODY_GENERATED_FROM_GHOSTS "!ruleset_body_generated_from_ghosts" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index c6cde1d8b4627..637ea90c8e4eb 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -57,6 +57,8 @@ /// Called from bodypart being removed /obj/item/bodypart/proc/drop_limb(mob/living/carbon/old_owner, special, dismembered) #define COMSIG_BODYPART_REMOVED "bodypart_removed" +/// from /mob/living/carbon/enter_stamcrit() +#define COMSIG_CARBON_ENTER_STAMCRIT "carbon_enter_stamcrit" ///from base of mob/living/carbon/soundbang_act(): (list(intensity)) #define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" ///from /item/organ/proc/Insert() (/obj/item/organ/) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 924488af73ef3..8f7fa11f57b2a 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -12,6 +12,8 @@ #define COMSIG_ORGAN_BEING_REPLACED "organ_being_replaced" /// Called when an organ gets surgically removed (mob/living/user, mob/living/carbon/old_owner, target_zone, obj/item/tool) #define COMSIG_ORGAN_SURGICALLY_REMOVED "organ_surgically_removed" +/// Called when an organ gets surgically removed (mob/living/user, mob/living/carbon/new_owner, target_zone, obj/item/tool) +#define COMSIG_ORGAN_SURGICALLY_INSERTED "organ_surgically_inserted" ///Called when movement intent is toggled. #define COMSIG_MOVE_INTENT_TOGGLED "move_intent_toggled" @@ -144,6 +146,8 @@ #define COMPONENT_LIVING_BLOCK_PRE_MOB_BUMP (1<<0) ///From base of mob/living/MobBump() (mob/living) #define COMSIG_LIVING_MOB_BUMP "living_mob_bump" +///From base of mob/living/MobBump() (mob/living) +#define COMSIG_LIVING_MOB_BUMPED "living_mob_bumped" ///From base of mob/living/Bump() (turf/closed) #define COMSIG_LIVING_WALL_BUMP "living_wall_bump" ///From base of turf/closed/Exited() (turf/closed) @@ -269,3 +273,6 @@ /// From /datum/element/basic_eating/finish_eating() #define COMSIG_MOB_ATE "mob_ate" + +///From /datum/component/happiness() +#define COMSIG_MOB_HAPPINESS_CHANGE "happiness_change" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index 068aadf6a5e1f..f33d2f1f40d02 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -182,8 +182,6 @@ #define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack" ///from base of obj/item/afterattack_secondary(): (atom/target, obj/item/weapon, proximity_flag, click_parameters) #define COMSIG_MOB_ITEM_AFTERATTACK_SECONDARY "mob_item_afterattack_secondary" -///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, proximity_flag, click_parameters) -#define COMSIG_MOB_ITEM_ATTACK_QDELETED "mob_item_attack_qdeleted" ///from base of mob/RangedAttack(): (atom/A, modifiers) #define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged" ///from base of mob/ranged_secondary_attack(): (atom/target, modifiers) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 01145cd32ea2e..f628df0e964b4 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -448,7 +448,10 @@ /// Prevents click from happening. #define COMPONENT_CANCEL_EQUIPMENT_CLICK (1<<0) +///from base of /obj/item/attack(): (mob/living, mob/living, params) #define COMSIG_ITEM_ATTACK "item_attack" +///from base of /obj/item/attack(): (mob/living, mob/living, params) +#define COMSIG_ITEM_POST_ATTACK "item_post_attack" // called only if the attack was executed ///from base of obj/item/attack_self(): (/mob) #define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self_secondary(): (/mob) @@ -472,8 +475,6 @@ #define COMPONENT_AFTERATTACK_PROCESSED_ITEM (1<<0) ///from base of obj/item/afterattack_secondary(): (atom/target, mob/user, proximity_flag, click_parameters) #define COMSIG_ITEM_AFTERATTACK_SECONDARY "item_afterattack_secondary" -///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params) -#define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted" ///from base of obj/item/embedded(): (atom/target, obj/item/bodypart/part) #define COMSIG_ITEM_EMBEDDED "item_embedded" ///from base of datum/component/embedded/safeRemove(): (mob/living/carbon/victim) @@ -529,3 +530,8 @@ /// from /datum/component/dart_insert/on_reskin() #define COMSIG_DART_INSERT_PARENT_RESKINNED "dart_insert_parent_reskinned" + +/// Sent from /obj/item/update_weight_class(). (old_w_class, new_w_class) +#define COMSIG_ITEM_WEIGHT_CLASS_CHANGED "item_weight_class_changed" +/// Sent from /obj/item/update_weight_class(), to it's loc. (obj/item/changed_item, old_w_class, new_w_class) +#define COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED "atom_contents_weight_class_changed" diff --git a/code/__DEFINES/dcs/signals/signals_operatives.dm b/code/__DEFINES/dcs/signals/signals_operatives.dm new file mode 100644 index 0000000000000..12a3bed466850 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_operatives.dm @@ -0,0 +1,2 @@ +/// For when a new teammate is added to a nukie team +#define COMSIG_NUKE_TEAM_ADDITION "nuke_team_addition" diff --git a/code/__DEFINES/dcs/signals/signals_reagent.dm b/code/__DEFINES/dcs/signals/signals_reagent.dm index 38d2ae92d9de3..5bb2c89d4ef33 100644 --- a/code/__DEFINES/dcs/signals/signals_reagent.dm +++ b/code/__DEFINES/dcs/signals/signals_reagent.dm @@ -19,7 +19,7 @@ ///from base of [/datum/reagent/proc/expose_atom]: (/turf, reac_volume) #define COMSIG_REAGENT_EXPOSE_TURF "reagent_expose_turf" -///from base of [/datum/controller/subsystem/materials/proc/InitializeMaterial]: (/datum/material) +///from base of [/datum/materials_controller/proc/InitializeMaterial]: (/datum/material) #define COMSIG_MATERIALS_INIT_MAT "SSmaterials_init_mat" ///from base of [/datum/component/multiple_lives/proc/respawn]: (mob/respawned_mob, gibbed, lives_left) diff --git a/code/__DEFINES/dcs/signals/signals_traitor.dm b/code/__DEFINES/dcs/signals/signals_traitor.dm index 4290b25b8009d..2752ab2363e2a 100644 --- a/code/__DEFINES/dcs/signals/signals_traitor.dm +++ b/code/__DEFINES/dcs/signals/signals_traitor.dm @@ -34,3 +34,6 @@ #define COMSIG_TRAITOR_GRAFFITI_SLIPPED "traitor_demoralise_event" /// For when someone is injected with the EHMS virus from /datum/traitor_objective_category/infect #define COMSIG_EHMS_INJECTOR_INJECTED "after_ehms_inject" + +/// Called by an battle royale implanter when successfully implanting someone. Passes the implanted mob. +#define COMSIG_ROYALE_IMPLANTED "royale_implanted" diff --git a/code/__DEFINES/devices.dm b/code/__DEFINES/devices.dm index 8f98f040dbcee..afd41570b5b27 100644 --- a/code/__DEFINES/devices.dm +++ b/code/__DEFINES/devices.dm @@ -8,8 +8,8 @@ #define INSPECTOR_PRINT_SOUND_MODE_FAFAFOGGY 4 #define BANANIUM_CLOWN_INSPECTOR_PRINT_SOUND_MODE_LAST 4 #define CLOWN_INSPECTOR_PRINT_SOUND_MODE_LAST 4 -#define INSPECTOR_ENERGY_USAGE_HONK (15 KILO JOULES) -#define INSPECTOR_ENERGY_USAGE_NORMAL (5 KILO JOULES) +#define INSPECTOR_ENERGY_USAGE_HONK (0.015 * STANDARD_CELL_CHARGE) +#define INSPECTOR_ENERGY_USAGE_NORMAL (0.005 * STANDARD_CELL_CHARGE) #define INSPECTOR_TIME_MODE_SLOW 1 #define INSPECTOR_TIME_MODE_FAST 2 #define INSPECTOR_TIME_MODE_HONK 3 diff --git a/code/__DEFINES/explosions.dm b/code/__DEFINES/explosions.dm index a1645b659d1cb..dd9a74bbae34d 100644 --- a/code/__DEFINES/explosions.dm +++ b/code/__DEFINES/explosions.dm @@ -52,6 +52,12 @@ #define EXARG_KEY_SILENT STRINGIFY(silent) /// Whether or not the explosion should produce smoke if it is large enough to warrant it. #define EXARG_KEY_SMOKE STRINGIFY(smoke) +/// Whether or not to leave the epicenter turf unaffected +#define EXARG_KEY_PROTECT_EPICENTER STRINGIFY(protect_epicenter) +/// For directional explosions, the angle the explosion is pointing at. +#define EXARG_KEY_EXPLOSION_DIRECTION STRINGIFY(explosion_direction) +/// For directional explosions, the angle covered by the explosion, centred on EXPLOSION_DIRECTION. +#define EXARG_KEY_EXPLOSION_ARC STRINGIFY(explosion_arc) // Explodable component deletion values /// Makes the explodable component queue to reset its exploding status when it detonates. diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm index eb6216e7806d8..94e9105f4a387 100644 --- a/code/__DEFINES/icon_smoothing.dm +++ b/code/__DEFINES/icon_smoothing.dm @@ -16,6 +16,10 @@ /// it represents the sides of our directional border object that have a neighbor /// Is incompatible with SMOOTH_CORNERS because border objects don't have corners #define SMOOTH_BORDER_OBJECT (1<<6) +/// Has a smooth broken sprite, used to decide whether to apply an offset to the broken overlay or not. For /turf/open only. +#define SMOOTH_BROKEN_TURF (1<<7) +/// Has a smooth burnt sprite, used to decide whether to apply an offset to the burnt overlay or not. For /turf/open only. +#define SMOOTH_BURNT_TURF (1<<8) DEFINE_BITFIELD(smoothing_flags, list( "SMOOTH_CORNERS" = SMOOTH_CORNERS, @@ -25,6 +29,8 @@ DEFINE_BITFIELD(smoothing_flags, list( "SMOOTH_QUEUED" = SMOOTH_QUEUED, "SMOOTH_OBJ" = SMOOTH_OBJ, "SMOOTH_BORDER_OBJECT" = SMOOTH_BORDER_OBJECT, + "SMOOTH_BROKEN_TURF" = SMOOTH_BROKEN_TURF, + "SMOOTH_BURNT_TURF" = SMOOTH_BURNT_TURF, )) /// Components of a smoothing junction diff --git a/code/__DEFINES/interaction_flags.dm b/code/__DEFINES/interaction_flags.dm index 55732f2364bb1..418466a0eb2c7 100644 --- a/code/__DEFINES/interaction_flags.dm +++ b/code/__DEFINES/interaction_flags.dm @@ -36,10 +36,7 @@ #define INTERACT_MACHINE_OPEN_SILICON (1<<4) /// must be silicon to interact #define INTERACT_MACHINE_REQUIRES_SILICON (1<<5) -/// This flag determines if a machine set_machine's the user when the user uses it, making updateUsrDialog make the user re-call interact() on it. -/// This is exclusively used for non-TGUI UIs, and its instances should be removed when moved to TGUI. -#define INTERACT_MACHINE_SET_MACHINE (1<<6) /// the user must have vision to interact (blind people need not apply) -#define INTERACT_MACHINE_REQUIRES_SIGHT (1<<7) +#define INTERACT_MACHINE_REQUIRES_SIGHT (1<<6) /// the user must be able to read to interact -#define INTERACT_MACHINE_REQUIRES_LITERACY (1<<8) +#define INTERACT_MACHINE_REQUIRES_LITERACY (1<<7) diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 59128753d6beb..f80316a133fe4 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -14,6 +14,9 @@ /// Essentially means it cannot be picked up or placed in an inventory, (e.g. mech parts, safe) #define WEIGHT_CLASS_GIGANTIC 6 +/// Weight class that can fit in pockets +#define POCKET_WEIGHT_CLASS WEIGHT_CLASS_SMALL + //Inventory depth: limits how many nested storage items you can access directly. //1: stuff in mob, 2: stuff in backpack, 3: stuff in box in backpack, etc #define INVENTORY_DEPTH 3 @@ -64,6 +67,20 @@ /// Total amount of slots #define SLOTS_AMT 20 // Keep this up to date! +///Inventory slots that can be blacklisted by a species from being equipped into +DEFINE_BITFIELD(no_equip_flags, list( + "EXOSUIT" = ITEM_SLOT_OCLOTHING, + "JUMPSUIT" = ITEM_SLOT_ICLOTHING, + "GLOVES" = ITEM_SLOT_GLOVES, + "GLASSES" = ITEM_SLOT_EYES, + "EARPIECES" = ITEM_SLOT_EARS, + "MASKS" = ITEM_SLOT_MASK, + "HATS" = ITEM_SLOT_HEAD, + "SHOES" = ITEM_SLOT_FEET, + "BACKPACKS" = ITEM_SLOT_BACK, + "TIES" = ITEM_SLOT_NECK, +)) + //SLOT GROUP HELPERS #define ITEM_SLOT_POCKETS (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET) /// Slots that are physically on you @@ -135,8 +152,6 @@ #define CLOTHING_DIGITIGRADE_VARIATION (1<<1) ///The sprite works fine for digitigrade legs as-is. #define CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON (1<<2) -///has a sprite for monkeys -#define CLOTHING_MONKEY_VARIATION (1<<3) //flags for covering body parts #define GLASSESCOVERSEYES (1<<0) diff --git a/code/__DEFINES/ipintel.dm b/code/__DEFINES/ipintel.dm new file mode 100644 index 0000000000000..9fbc14ae40dbf --- /dev/null +++ b/code/__DEFINES/ipintel.dm @@ -0,0 +1,15 @@ +#define IPINTEL_RATE_LIMIT_MINUTE "minute" +#define IPINTEL_RATE_LIMIT_DAY "day" + +/// An internal error occurred and the query cannot be processed +#define IPINTEL_UNKNOWN_INTERNAL_ERROR "unknown_internal_error" +/// An error occurred with the query and the result is unknown +#define IPINTEL_UNKNOWN_QUERY_ERROR "unknown_query_error" +/// Cannot query as we are rate limited for the rest of the day +#define IPINTEL_RATE_LIMITED_DAY "rate_limited_day" +/// Cannot query as we are rate limited for the rest of the minute +#define IPINTEL_RATE_LIMITED_MINUTE "rate_limited_minute" +/// The IP address is a VPN or bad IP +#define IPINTEL_BAD_IP "bad_ip" +/// The IP address is not a VPN or bad IP +#define IPINTEL_GOOD_IP "good_ip" diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 524deef42f8ea..2c3b151855cef 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -71,7 +71,6 @@ #define JOB_MEDICAL_DOCTOR "Medical Doctor" #define JOB_PARAMEDIC "Paramedic" #define JOB_CHEMIST "Chemist" -#define JOB_VIROLOGIST "Virologist" //Science #define JOB_SCIENTIST "Scientist" #define JOB_ROBOTICIST "Roboticist" @@ -151,18 +150,17 @@ #define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 26 #define JOB_DISPLAY_ORDER_PARAMEDIC 27 #define JOB_DISPLAY_ORDER_CHEMIST 28 -#define JOB_DISPLAY_ORDER_VIROLOGIST 29 -#define JOB_DISPLAY_ORDER_CORONER 30 -#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 31 -#define JOB_DISPLAY_ORDER_SCIENTIST 32 -#define JOB_DISPLAY_ORDER_ROBOTICIST 33 -#define JOB_DISPLAY_ORDER_GENETICIST 34 -#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 35 -#define JOB_DISPLAY_ORDER_VETERAN_ADVISOR 36 -#define JOB_DISPLAY_ORDER_WARDEN 37 -#define JOB_DISPLAY_ORDER_DETECTIVE 38 -#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 39 -#define JOB_DISPLAY_ORDER_PRISONER 40 +#define JOB_DISPLAY_ORDER_CORONER 29 +#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 30 +#define JOB_DISPLAY_ORDER_SCIENTIST 31 +#define JOB_DISPLAY_ORDER_ROBOTICIST 32 +#define JOB_DISPLAY_ORDER_GENETICIST 33 +#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 34 +#define JOB_DISPLAY_ORDER_VETERAN_ADVISOR 35 +#define JOB_DISPLAY_ORDER_WARDEN 36 +#define JOB_DISPLAY_ORDER_DETECTIVE 37 +#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 38 +#define JOB_DISPLAY_ORDER_PRISONER 39 #define DEPARTMENT_UNASSIGNED "No Department" diff --git a/code/__DEFINES/lights.dm b/code/__DEFINES/lights.dm index b1413a7078972..48d210fe03164 100644 --- a/code/__DEFINES/lights.dm +++ b/code/__DEFINES/lights.dm @@ -1,5 +1,5 @@ ///How much power emergency lights will consume per tick -#define LIGHT_EMERGENCY_POWER_USE (0.1 KILO WATTS) +#define LIGHT_EMERGENCY_POWER_USE (0.0001 * STANDARD_CELL_RATE) // status values shared between lighting fixtures and items #define LIGHT_OK 0 #define LIGHT_EMPTY 1 @@ -14,7 +14,7 @@ ///Amount of time that takes an ethereal to take energy from the lights #define LIGHT_DRAIN_TIME (2.5 SECONDS) ///Amount of charge the ethereal gain after the drain -#define LIGHT_POWER_GAIN 35 +#define LIGHT_POWER_GAIN (0.035 * STANDARD_CELL_CHARGE) ///How many reagents the lights can hold #define LIGHT_REAGENT_CAPACITY 20 diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index aca45241f1cc0..1939ca94ec455 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -250,7 +250,7 @@ //We used to use linear regression to approximate the answer, but Mloc realized this was actually faster. //And lo and behold, it is, and it's more accurate to boot. -#define CHEAP_HYPOTENUSE(Ax, Ay, Bx, By) (sqrt(abs(Ax - Bx) ** 2 + abs(Ay - By) ** 2)) //A squared + B squared = C squared +#define CHEAP_HYPOTENUSE(Ax, Ay, Bx, By) (sqrt((Ax - Bx) ** 2 + (Ay - By) ** 2)) //A squared + B squared = C squared /// The number of cells in a taxicab circle (rasterized diamond) of radius X. #define DIAMOND_AREA(X) (1 + 2*(X)*((X)+1)) diff --git a/code/__DEFINES/melee.dm b/code/__DEFINES/melee.dm index 2b06303386a94..8b3a422fc0b25 100644 --- a/code/__DEFINES/melee.dm +++ b/code/__DEFINES/melee.dm @@ -1,6 +1,7 @@ //Martial arts defines #define MARTIALART_BOXING "boxing" +#define MARTIALART_EVIL_BOXING "evil boxing" #define MARTIALART_CQC "CQC" #define MARTIALART_KRAVMAGA "krav maga" #define MARTIALART_MUSHPUNCH "mushroom punch" diff --git a/code/__DEFINES/mobfactions.dm b/code/__DEFINES/mobfactions.dm index d503a499d0da0..aea143dad253c 100644 --- a/code/__DEFINES/mobfactions.dm +++ b/code/__DEFINES/mobfactions.dm @@ -83,7 +83,8 @@ #define FACTION_TURRET "turret" /// Vines, lots of overlap with plants #define FACTION_VINES "vines" - +///raptor factions +#define FACTION_RAPTOR "raptor" // Antagonist factions /// Cultists and their constructs diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 9bfe6df5a5af9..5ab16b5a5ff59 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -116,8 +116,6 @@ #define SPECIES_LIZARD_SILVER "silverscale" #define SPECIES_NIGHTMARE "nightmare" #define SPECIES_MONKEY "monkey" -#define SPECIES_MONKEY_FREAK "monkey_freak" -#define SPECIES_MONKEY_HUMAN_LEGGED "monkey_human_legged" #define SPECIES_MOTH "moth" #define SPECIES_MUSHROOM "mush" #define SPECIES_PLASMAMAN "plasmaman" @@ -125,7 +123,6 @@ #define SPECIES_SHADOW "shadow" #define SPECIES_SKELETON "skeleton" #define SPECIES_SNAIL "snail" -#define SPECIES_TALLBOY "tallboy" #define SPECIES_VAMPIRE "vampire" #define SPECIES_ZOMBIE "zombie" #define SPECIES_ZOMBIE_INFECTIOUS "memezombie" @@ -277,6 +274,7 @@ //Disgust levels for humans #define DISGUST_LEVEL_MAXEDOUT 150 +#define DISGUST_LEVEL_VERYDISGUSTED 100 #define DISGUST_LEVEL_DISGUSTED 75 #define DISGUST_LEVEL_VERYGROSS 50 #define DISGUST_LEVEL_GROSS 25 @@ -286,12 +284,12 @@ //Charge levels for Ethereals, in joules. #define ETHEREAL_CHARGE_NONE 0 -#define ETHEREAL_CHARGE_LOWPOWER (400 KILO JOULES) -#define ETHEREAL_CHARGE_NORMAL (1 MEGA JOULES) -#define ETHEREAL_CHARGE_ALMOSTFULL (1.5 MEGA JOULES) -#define ETHEREAL_CHARGE_FULL (2 MEGA JOULES) -#define ETHEREAL_CHARGE_OVERLOAD (2.5 MEGA JOULES) -#define ETHEREAL_CHARGE_DANGEROUS (3 MEGA JOULES) +#define ETHEREAL_CHARGE_LOWPOWER (0.4 * STANDARD_CELL_CHARGE) +#define ETHEREAL_CHARGE_NORMAL (1 * STANDARD_CELL_CHARGE) +#define ETHEREAL_CHARGE_ALMOSTFULL (1.5 * STANDARD_CELL_CHARGE) +#define ETHEREAL_CHARGE_FULL (2 * STANDARD_CELL_CHARGE) +#define ETHEREAL_CHARGE_OVERLOAD (2.5 * STANDARD_CELL_CHARGE) +#define ETHEREAL_CHARGE_DANGEROUS (3 * STANDARD_CELL_CHARGE) #define CRYSTALIZE_COOLDOWN_LENGTH (120 SECONDS) @@ -341,7 +339,6 @@ #define AI_ON 1 #define AI_IDLE 2 #define AI_OFF 3 -#define AI_Z_OFF 4 //The range at which a mob should wake up if you spawn into the z level near it #define MAX_SIMPLEMOB_WAKEUP_RANGE 5 @@ -436,7 +433,7 @@ #define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you #define HUNGER_FACTOR 0.05 //factor at which mob nutrition decreases -#define ETHEREAL_DISCHARGE_RATE (0.8 KILO WATTS) // Rate at which ethereal stomach charge decreases +#define ETHEREAL_DISCHARGE_RATE (8e-4 * STANDARD_CELL_CHARGE) // Rate at which ethereal stomach charge decreases /// How much nutrition eating clothes as moth gives and drains #define CLOTHING_NUTRITION_GAIN 15 #define REAGENTS_METABOLISM 0.2 //How many units of reagent are consumed per second, by default. @@ -636,18 +633,22 @@ // - They do not start at 0 for futureproofing // - They skip numbers for futureproofing as well // Otherwise they are completely arbitrary -#define HUMAN_HEIGHT_DWARF 2 -#define HUMAN_HEIGHT_SHORTEST 4 -#define HUMAN_HEIGHT_SHORT 6 -#define HUMAN_HEIGHT_MEDIUM 8 -#define HUMAN_HEIGHT_TALL 10 -#define HUMAN_HEIGHT_TALLER 12 -#define HUMAN_HEIGHT_TALLEST 14 +#define MONKEY_HEIGHT_DWARF 2 +#define MONKEY_HEIGHT_MEDIUM 4 +#define HUMAN_HEIGHT_DWARF 6 +#define HUMAN_HEIGHT_SHORTEST 8 +#define HUMAN_HEIGHT_SHORT 10 +#define HUMAN_HEIGHT_MEDIUM 12 +#define HUMAN_HEIGHT_TALL 14 +#define HUMAN_HEIGHT_TALLER 16 +#define HUMAN_HEIGHT_TALLEST 18 /// Assoc list of all heights, cast to strings, to """"tuples""""" /// The first """tuple""" index is the upper body offset /// The second """tuple""" index is the lower body offset GLOBAL_LIST_INIT(human_heights_to_offsets, list( + "[MONKEY_HEIGHT_DWARF]" = list(-9, -3), + "[MONKEY_HEIGHT_MEDIUM]" = list(-7, -4), "[HUMAN_HEIGHT_DWARF]" = list(-5, -4), "[HUMAN_HEIGHT_SHORTEST]" = list(-2, -1), "[HUMAN_HEIGHT_SHORT]" = list(-1, -1), @@ -661,39 +662,41 @@ GLOBAL_LIST_INIT(human_heights_to_offsets, list( /// Total number of layers for mob overlays /// KEEP THIS UP-TO-DATE OR SHIT WILL BREAK /// Also consider updating layers_to_offset -#define TOTAL_LAYERS 34 +#define TOTAL_LAYERS 35 /// Mutations layer - Tk headglows, cold resistance glow, etc -#define MUTATIONS_LAYER 34 +#define MUTATIONS_LAYER 35 /// Mutantrace features (tail when looking south) that must appear behind the body parts -#define BODY_BEHIND_LAYER 33 +#define BODY_BEHIND_LAYER 34 /// Layer for bodyparts that should appear behind every other bodypart - Mostly, legs when facing WEST or EAST -#define BODYPARTS_LOW_LAYER 32 +#define BODYPARTS_LOW_LAYER 33 /// Layer for most bodyparts, appears above BODYPARTS_LOW_LAYER and below BODYPARTS_HIGH_LAYER -#define BODYPARTS_LAYER 31 +#define BODYPARTS_LAYER 32 /// Mutantrace features (snout, body markings) that must appear above the body parts -#define BODY_ADJ_LAYER 30 +#define BODY_ADJ_LAYER 31 /// Underwear, undershirts, socks, eyes, lips(makeup) -#define BODY_LAYER 29 +#define BODY_LAYER 30 /// Mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes) -#define FRONT_MUTATIONS_LAYER 28 +#define FRONT_MUTATIONS_LAYER 29 /// Damage indicators (cuts and burns) -#define DAMAGE_LAYER 27 +#define DAMAGE_LAYER 28 /// Jumpsuit clothing layer -#define UNIFORM_LAYER 26 +#define UNIFORM_LAYER 27 /// ID card layer -#define ID_LAYER 25 +#define ID_LAYER 26 /// ID card layer (might be deprecated) -#define ID_CARD_LAYER 24 +#define ID_CARD_LAYER 25 /// Layer for bodyparts that should appear above every other bodypart - Currently only used for hands -#define BODYPARTS_HIGH_LAYER 23 +#define BODYPARTS_HIGH_LAYER 24 /// Gloves layer -#define GLOVES_LAYER 22 +#define GLOVES_LAYER 23 /// Shoes layer -#define SHOES_LAYER 21 +#define SHOES_LAYER 22 /// Layer for masks that are worn below ears and eyes (like Balaclavas) (layers below hair, use flagsinv=HIDEHAIR as needed) -#define LOW_FACEMASK_LAYER 20 +#define LOW_FACEMASK_LAYER 21 /// Ears layer (Spessmen have ears? Wow) -#define EARS_LAYER 19 +#define EARS_LAYER 20 +/// Layer for neck apperal that should appear below the suit slot (like neckties) +#define LOW_NECK_LAYER 19 /// Suit layer (armor, coats, etc.) #define SUIT_LAYER 18 /// Glasses layer @@ -702,7 +705,7 @@ GLOBAL_LIST_INIT(human_heights_to_offsets, list( #define BELT_LAYER 16 //Possible make this an overlay of somethign required to wear a belt? /// Suit storage layer (tucking a gun or baton underneath your armor) #define SUIT_STORE_LAYER 15 -/// Neck layer (for wearing ties and bedsheets) +/// Neck layer (for wearing capes and bedsheets) #define NECK_LAYER 14 /// Back layer (for backpacks and equipment on your back) #define BACK_LAYER 13 @@ -749,7 +752,9 @@ GLOBAL_LIST_INIT(layers_to_offset, list( "[BELT_LAYER]" = LOWER_BODY, // Everything below looks fine with or without a filter, so we can skip it and just offset // (In practice they'd be fine if they got a filter but we can optimize a bit by not.) + "[NECK_LAYER]" = UPPER_BODY, "[GLASSES_LAYER]" = UPPER_BODY, + "[LOW_NECK_LAYER]" = UPPER_BODY, "[ABOVE_BODY_FRONT_GLASSES_LAYER]" = UPPER_BODY, // currently unused "[ABOVE_BODY_FRONT_HEAD_LAYER]" = UPPER_BODY, // only used for head stuff "[GLOVES_LAYER]" = LOWER_BODY, @@ -766,6 +771,7 @@ GLOBAL_LIST_INIT(layers_to_offset, list( // to show how many filters are added at a glance // BACK_LAYER (backpacks are big) // BODYPARTS_HIGH_LAYER (arms) + // BODY_LAYER (body markings (full body), underwear (full body), eyes) // BODY_ADJ_LAYER (external organs like wings) // BODY_BEHIND_LAYER (external organs like wings) // BODY_FRONT_LAYER (external organs like wings) @@ -823,6 +829,10 @@ GLOBAL_LIST_INIT(layers_to_offset, list( #define ALLOW_SILICON_REACH (1<<6) /// If resting on the floor is allowed to perform action (pAIs can play music while resting) #define ALLOW_RESTING (1<<7) +/// If this is accessible to creatures with ventcrawl capabilities +#define NEED_VENTCRAWL (1<<8) +/// Checks for base adjacency, but silences the error +#define SILENT_ADJACENCY (1<<9) /// The default mob sprite size (used for shrinking or enlarging the mob sprite to regular size) #define RESIZE_DEFAULT_SIZE 1 diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 8ace303b843e1..9e38eada92313 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -2,20 +2,19 @@ #define EMAGGED (1<<0) -#define IN_USE (1<<1) // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! -#define CAN_BE_HIT (1<<2) //can this be bludgeoned by items? -#define DANGEROUS_POSSESSION (1<<3) //Admin possession yes/no -#define UNIQUE_RENAME (1<<4) // can you customize the description/name of the thing? -#define BLOCK_Z_OUT_DOWN (1<<5) // Should this object block z falling from loc? -#define BLOCK_Z_OUT_UP (1<<6) // Should this object block z uprise from loc? -#define BLOCK_Z_IN_DOWN (1<<7) // Should this object block z falling from above? -#define BLOCK_Z_IN_UP (1<<8) // Should this object block z uprise from below? -#define BLOCKS_CONSTRUCTION (1<<9) //! Does this object prevent things from being built on it? -#define BLOCKS_CONSTRUCTION_DIR (1<<10) //! Does this object prevent same-direction things from being built on it? -#define IGNORE_DENSITY (1<<11) //! Can we ignore density when building on this object? (for example, directional windows and grilles) -#define INFINITE_RESKIN (1<<12) // We can reskin this item infinitely -#define CONDUCTS_ELECTRICITY (1<<13) //! Can this object conduct electricity? -#define NO_DECONSTRUCTION (1<<14) //! Prevent deconstruction of this object. +#define CAN_BE_HIT (1<<1) //can this be bludgeoned by items? +#define DANGEROUS_POSSESSION (1<<2) //Admin possession yes/no +#define UNIQUE_RENAME (1<<3) // can you customize the description/name of the thing? +#define BLOCK_Z_OUT_DOWN (1<<4) // Should this object block z falling from loc? +#define BLOCK_Z_OUT_UP (1<<5) // Should this object block z uprise from loc? +#define BLOCK_Z_IN_DOWN (1<<6) // Should this object block z falling from above? +#define BLOCK_Z_IN_UP (1<<7) // Should this object block z uprise from below? +#define BLOCKS_CONSTRUCTION (1<<8) //! Does this object prevent things from being built on it? +#define BLOCKS_CONSTRUCTION_DIR (1<<9) //! Does this object prevent same-direction things from being built on it? +#define IGNORE_DENSITY (1<<10) //! Can we ignore density when building on this object? (for example, directional windows and grilles) +#define INFINITE_RESKIN (1<<11) // We can reskin this item infinitely +#define CONDUCTS_ELECTRICITY (1<<12) //! Can this object conduct electricity? +#define NO_DEBRIS_AFTER_DECONSTRUCTION (1<<13) //! Atoms don't spawn anything when deconstructed. They just vanish // If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support diff --git a/code/__DEFINES/power.dm b/code/__DEFINES/power.dm index 0eda3669a7123..f22d756d37514 100644 --- a/code/__DEFINES/power.dm +++ b/code/__DEFINES/power.dm @@ -19,10 +19,12 @@ ///The joule is the standard unit of energy for this codebase. You can use this with other defines to clarify that it will not be multiplied by time. #define JOULES * JOULE -///The amount of energy, in joules, a standard powercell has. -#define STANDARD_CELL_CHARGE (1 MEGA JOULES) // 1 MJ. - -GLOBAL_VAR_INIT(CHARGELEVEL, 0.01) // Cap for how fast cells charge, as a percentage per second (.01 means cellcharge is capped to 1% per second) +///The capacity of a standard power cell +#define STANDARD_CELL_VALUE (1 MEGA) + ///The amount of energy, in joules, a standard powercell has. + #define STANDARD_CELL_CHARGE (STANDARD_CELL_VALUE JOULES) // 1 MJ. + ///The amount of power, in watts, a standard powercell can give. + #define STANDARD_CELL_RATE (STANDARD_CELL_VALUE WATTS) // 1 MW. // Converts cable layer to its human readable name GLOBAL_LIST_INIT(cable_layer_to_name, list( diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm index e471fe2324d93..ae61c5e50b7f0 100644 --- a/code/__DEFINES/projectiles.dm +++ b/code/__DEFINES/projectiles.dm @@ -64,6 +64,8 @@ #define CALIBER_HOOK "hook" /// The caliber used by the changeling tentacle mutation. #define CALIBER_TENTACLE "tentacle" +/// The caliber used by pipeguns and pipe pistols +#define CALIBER_JUNK "junk" /// For gunpoints, how many tiles around the target the shooter can roam without losing their shot #define GUNPOINT_SHOOTER_STRAY_RANGE 2 diff --git a/code/__DEFINES/pronouns.dm b/code/__DEFINES/pronouns.dm new file mode 100644 index 0000000000000..d137970f217eb --- /dev/null +++ b/code/__DEFINES/pronouns.dm @@ -0,0 +1,42 @@ +/// she, he, they, it "%PRONOUN_they" = "p_they" +/// She, He, They, It "%PRONOUN_They" = "p_They" +/// her, his, their, its "%PRONOUN_their" = "p_their" +/// Her, His, Their, Its "%PRONOUN_Their" = "p_Their" +/// hers, his, theirs, its "%PRONOUN_theirs" = "p_theirs" +/// Hers, His, Theirs, Its "%PRONOUN_Theirs" = "p_Theirs" +/// her, him, them, it "%PRONOUN_them" = "p_them" +/// Her, Him, Them, It "%PRONOUN_Them" = "p_Them" +/// has, have "%PRONOUN_have" = "p_have" +/// is, are "%PRONOUN_are" = "p_are" +/// was, were "%PRONOUN_were" = "p_were" +/// does, do "%PRONOUN_do" = "p_do" +/// she has, he has, they have, it has "%PRONOUN_theyve" = "p_theyve" +/// She has, He has, They have, It has "%PRONOUN_Theyve" = "p_Theyve" +/// she is, he is, they are, it is "%PRONOUN_theyre" = "p_theyre" +/// She is, He is, They are, It is "%PRONOUN_Theyre" = "p_Theyre" +/// s, null (she looks, they look) "%PRONOUN_s" = "p_s" +/// es, null (she goes, they go) "%PRONOUN_es" = "p_es" + +/// Don't forget to update the grep if you add more! tools/ci/check_grep.sh -> pronoun helper spellcheck + +/// A list for all the pronoun procs, if you need to iterate or search through it or something. +#define ALL_PRONOUNS list( \ + "%PRONOUN_they" = TYPE_PROC_REF(/datum, p_they), \ + "%PRONOUN_They" = TYPE_PROC_REF(/datum, p_They), \ + "%PRONOUN_their" = TYPE_PROC_REF(/datum, p_their), \ + "%PRONOUN_Their" = TYPE_PROC_REF(/datum, p_Their), \ + "%PRONOUN_theirs" = TYPE_PROC_REF(/datum, p_theirs), \ + "%PRONOUN_Theirs" = TYPE_PROC_REF(/datum, p_Theirs), \ + "%PRONOUN_them" = TYPE_PROC_REF(/datum, p_them), \ + "%PRONOUN_Them" = TYPE_PROC_REF(/datum, p_Them), \ + "%PRONOUN_have" = TYPE_PROC_REF(/datum, p_have), \ + "%PRONOUN_are" = TYPE_PROC_REF(/datum, p_are), \ + "%PRONOUN_were" = TYPE_PROC_REF(/datum, p_were), \ + "%PRONOUN_do" = TYPE_PROC_REF(/datum, p_do), \ + "%PRONOUN_theyve" = TYPE_PROC_REF(/datum, p_theyve), \ + "%PRONOUN_Theyve" = TYPE_PROC_REF(/datum, p_Theyve), \ + "%PRONOUN_theyre" = TYPE_PROC_REF(/datum, p_theyre), \ + "%PRONOUN_Theyre" = TYPE_PROC_REF(/datum, p_Theyre), \ + "%PRONOUN_s" = TYPE_PROC_REF(/datum, p_s), \ + "%PRONOUN_es" = TYPE_PROC_REF(/datum, p_es) \ +) diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm index 707b7bd7a02e1..3b2687b5fcf55 100644 --- a/code/__DEFINES/research/anomalies.dm +++ b/code/__DEFINES/research/anomalies.dm @@ -21,11 +21,6 @@ GLOBAL_LIST_INIT(bioscrambler_parts_blacklist, typecacheof(list( /obj/item/bodypart/chest/larva, /obj/item/bodypart/head/larva, - // Re-add the ones below this line when the bug with offset is fixed - /obj/item/bodypart/leg/left/monkey, - /obj/item/bodypart/leg/right/monkey, - /obj/item/bodypart/leg/left/tallboy, - /obj/item/bodypart/leg/right/tallboy, ))) /// Blacklist of organs which should not appear when bioscrambled. @@ -39,10 +34,13 @@ GLOBAL_LIST_INIT(bioscrambler_organs_blacklist, typecacheof(list ( /obj/item/organ/internal/brain, /obj/item/organ/internal/body_egg, /obj/item/organ/internal/cyberimp, + /obj/item/organ/internal/ears/dullahan, + /obj/item/organ/internal/eyes/dullahan, /obj/item/organ/internal/heart/cursed, /obj/item/organ/internal/heart/demon, /obj/item/organ/internal/lungs, /obj/item/organ/internal/monster_core, + /obj/item/organ/internal/tongue/dullahan, /obj/item/organ/internal/vocal_cords/colossus, /obj/item/organ/internal/zombie_infection, ))) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 71fa29b6ea31a..ee7e5dfee0d12 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -78,6 +78,7 @@ #define ROLE_WIZARD_APPRENTICE "apprentice" #define ROLE_SYNDICATE_MONKEY "Syndicate Monkey Agent" #define ROLE_CONTRACTOR_SUPPORT "Contractor Support Unit" +#define ROLE_OPERATIVE_OVERWATCH "Operative Overwatch Agent" #define ROLE_SYNDICATE_SABOBORG "Syndicate Sabotage Cyborg" #define ROLE_SYNDICATE_MEDBORG "Syndicate Medical Cyborg" #define ROLE_SYNDICATE_ASSAULTBORG "Syndicate Assault Cyborg" diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index 928877f541da0..5db7227521a3f 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -107,6 +107,7 @@ #define MAX_CHARTER_LEN 80 #define MAX_PLAQUE_LEN 144 #define MAX_LABEL_LEN 64 +#define MAX_DESC_LEN 280 // Audio/Visual Flags. Used to determine what sense are required to notice a message. #define MSG_VISUAL (1<<0) @@ -114,5 +115,10 @@ -//Used in visible_message_flags, audible_message_flags and runechat_flags +// Used in visible_message_flags, audible_message_flags and runechat_flags +/// Automatically applies emote related spans/fonts/formatting to the message #define EMOTE_MESSAGE (1<<0) +/// By default, self_message will respect the visual / audible component of the message. +/// Meaning that if the message is visual, and sourced from a blind mob, they will not see it. +/// This flag skips that behavior, and will always show the self message to the mob. +#define ALWAYS_SHOW_SELF_MESSAGE (1<<1) diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm index f6ecde7c2e10b..5a945d7ec5790 100644 --- a/code/__DEFINES/skills.dm +++ b/code/__DEFINES/skills.dm @@ -46,3 +46,9 @@ ///The base modifier a boulder's size grants to the mining skill. #define MINING_SKILL_BOULDER_SIZE_XP 10 + +// Skillchip categories +//Various skillchip categories. Use these when setting which categories a skillchip restricts being paired with +//while using the SKILLCHIP_RESTRICTED_CATEGORIES flag +#define SKILLCHIP_CATEGORY_GENERAL "general" +#define SKILLCHIP_CATEGORY_JOB "job" diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index 5b0ea31dfbfd0..896f6ec5bf448 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -10,6 +10,11 @@ #define CHANNEL_TRAITOR 1016 #define CHANNEL_CHARGED_SPELL 1015 #define CHANNEL_ELEVATOR 1014 +//THIS SHOULD ALWAYS BE THE LOWEST ONE! +//KEEP IT UPDATED +#define CHANNEL_HIGHEST_AVAILABLE 1013 + +#define MAX_INSTRUMENT_CHANNELS (128 * 6) ///Default range of a sound. #define SOUND_RANGE 17 @@ -23,13 +28,6 @@ ///The default exponent of sound falloff #define SOUND_FALLOFF_EXPONENT 6 -//THIS SHOULD ALWAYS BE THE LOWEST ONE! -//KEEP IT UPDATED - -#define CHANNEL_HIGHEST_AVAILABLE 1015 - -#define MAX_INSTRUMENT_CHANNELS (128 * 6) - #define SOUND_MINIMUM_PRESSURE 10 #define INTERACTION_SOUND_RANGE_MODIFIER -3 diff --git a/code/__DEFINES/species_clothing_paths.dm b/code/__DEFINES/species_clothing_paths.dm index 2582d81b613bc..99fe7baab1ddf 100644 --- a/code/__DEFINES/species_clothing_paths.dm +++ b/code/__DEFINES/species_clothing_paths.dm @@ -6,10 +6,6 @@ ///The dmi for humanoid oversuits #define DEFAULT_SUIT_FILE 'icons/mob/clothing/suits/default.dmi' -//MONKEY PATHS -///The dmi for monkey uniforms -#define MONKEY_UNIFORM_FILE 'icons/mob/human/species/monkey/uniform.dmi' - //DIGITIGRADE PATHS ///The dmi containing digitigrade uniforms #define DIGITIGRADE_UNIFORM_FILE 'icons/mob/human/species/misc/digitigrade.dmi' diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 6d04fca876b48..8d460c3aecb6f 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -20,7 +20,7 @@ * * make sure you add an update to the schema_version stable in the db changelog */ -#define DB_MINOR_VERSION 26 +#define DB_MINOR_VERSION 27 //! ## Timing subsystem @@ -137,6 +137,7 @@ #define INIT_ORDER_BLACKBOX 94 #define INIT_ORDER_SERVER_MAINT 93 #define INIT_ORDER_INPUT 85 +#define INIT_ORDER_ADMIN_VERBS 84 // needs to be pretty high, admins cant do much without it #define INIT_ORDER_SOUNDS 83 #define INIT_ORDER_INSTRUMENTS 82 #define INIT_ORDER_GREYSCALE 81 @@ -193,7 +194,6 @@ // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) #define FIRE_PRIORITY_PING 10 -#define FIRE_PRIORITY_IDLE_NPC 10 #define FIRE_PRIORITY_SERVER_MAINT 10 #define FIRE_PRIORITY_RESEARCH 10 #define FIRE_PRIORITY_VIS 10 @@ -346,3 +346,6 @@ #define VOTE_WINNER_METHOD_WEIGHTED_RANDOM "Weighted Random" /// There is no winner for this vote. #define VOTE_WINNER_METHOD_NONE "None" + +/// Returned by [/datum/vote/proc/can_be_initiated] to denote the vote is valid and can be initiated. +#define VOTE_AVAILABLE "Vote Available" diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm index c303eebbcdc56..8b0fda53cd79e 100644 --- a/code/__DEFINES/text.dm +++ b/code/__DEFINES/text.dm @@ -64,6 +64,10 @@ */ #define PREVENT_CHARACTER_TRIM_LOSS(integer) (integer + 1) +/// BYOND's string procs don't support being used on datum references (as in it doesn't look for a name for stringification) +/// We just use this macro to ensure that we will only pass strings to this BYOND-level function without developers needing to really worry about it. +#define LOWER_TEXT(thing) lowertext(UNLINT("[thing]")) + /// Folder directory for strings #define STRING_DIRECTORY "strings" diff --git a/code/__DEFINES/tools.dm b/code/__DEFINES/tools.dm index 99230559f7e0b..132ae1962398f 100644 --- a/code/__DEFINES/tools.dm +++ b/code/__DEFINES/tools.dm @@ -2,7 +2,7 @@ #define TOOL_CROWBAR "crowbar" #define TOOL_MULTITOOL "multitool" #define TOOL_SCREWDRIVER "screwdriver" -#define TOOL_WIRECUTTER "wirecutter" +#define TOOL_WIRECUTTER "cutters" #define TOOL_WRENCH "wrench" #define TOOL_WELDER "welder" #define TOOL_ANALYZER "analyzer" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 473f62ae6b17c..4c1411d3cfdfc 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -118,8 +118,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_RESISTLOWPRESSURE "resist_low_pressure" /// This human is immune to the effects of being exploded. (ex_act) #define TRAIT_BOMBIMMUNE "bomb_immunity" -/// Immune to being irradiated -#define TRAIT_RADIMMUNE "rad_immunity" /// This mob won't get gibbed by nukes going off #define TRAIT_NUKEIMMUNE "nuke_immunity" /// Can't be given viruses @@ -224,6 +222,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_REVEAL_FISH "reveal_fish" ///This trait gets you a list of fishes that can be caught when examining a fishing spot. #define TRAIT_EXAMINE_FISHING_SPOT "examine_fishing_spot" +/// This trait lets you evaluate someone's fitness level against your own +#define TRAIT_EXAMINE_FITNESS "reveal_power_level" /// Added to a mob, allows that mob to experience flavour-based moodlets when examining food #define TRAIT_REMOTE_TASTING "remote_tasting" @@ -520,6 +520,15 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Prevents you from twohanding weapons. #define TRAIT_NO_TWOHANDING "no_twohanding" +/// Improves boxing damage against boxers and athletics experience gain +#define TRAIT_STRENGTH "strength" + +/// Increases the duration of having exercised +#define TRAIT_STIMMED "stimmed" + +/// Indicates that the target is able to be boxed at a boxer's full power. +#define TRAIT_BOXING_READY "boxing_ready" + /// Halves the time of tying a tie. #define TRAIT_FAST_TYING "fast_tying" @@ -587,6 +596,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_BRAINWASHING "brainwashing" /// Allows chef's to chefs kiss their food, to make them with love #define TRAIT_CHEF_KISS "chefs_kiss" +/// Allows clowns to bend balloons into animals +#define TRAIT_BALLOON_SUTRA "balloon_sutra" ///Movement type traits for movables. See elements/movetype_handler.dm #define TRAIT_MOVE_GROUND "move_ground" @@ -733,6 +744,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai //quirk traits #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" +#define TRAIT_ANOSMIA "anosmia" #define TRAIT_HEAVY_DRINKER "heavy_drinker" #define TRAIT_AGEUSIA "ageusia" #define TRAIT_HEAVY_SLEEPER "heavy_sleeper" @@ -764,6 +776,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_POSTERBOY "poster_boy" #define TRAIT_THROWINGARM "throwing_arm" #define TRAIT_SETTLER "settler" +#define TRAIT_STRONG_STOMACH "strong_stomach" /// This mob always lands on their feet when they fall, for better or for worse. #define TRAIT_CATLIKE_GRACE "catlike_grace" @@ -810,6 +823,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Trait applied to turfs when an atmos holosign is placed on them. It will stop firedoors from closing. #define TRAIT_FIREDOOR_STOP "firedoor_stop" +///Trait applied to turf blocked by a containment field +#define TRAIT_CONTAINMENT_FIELD "containment_field" + /// Trait applied when the MMI component is added to an [/obj/item/integrated_circuit] #define TRAIT_COMPONENT_MMI "component_mmi" @@ -934,6 +950,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define STATION_TRAIT_BIGGER_PODS "station_trait_bigger_pods" #define STATION_TRAIT_BIRTHDAY "station_trait_birthday" #define STATION_TRAIT_BOTS_GLITCHED "station_trait_bot_glitch" +#define STATION_TRAIT_BRIGHT_DAY "station_trait_bright_day" #define STATION_TRAIT_CARP_INFESTATION "station_trait_carp_infestation" #define STATION_TRAIT_CYBERNETIC_REVOLUTION "station_trait_cybernetic_revolution" #define STATION_TRAIT_EMPTY_MAINT "station_trait_empty_maint" @@ -984,6 +1001,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Marks that this object is irradiated #define TRAIT_IRRADIATED "iraddiated" +/// Immune to being irradiated +#define TRAIT_RADIMMUNE "rad_immunity" + /// Harmful radiation effects, the toxin damage and the burns, will not occur while this trait is active #define TRAIT_HALT_RADIATION_EFFECTS "halt_radiation_effects" @@ -1063,8 +1083,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait given to a dragon who fails to defend their rifts #define TRAIT_RIFT_FAILURE "fail_dragon_loser" +///this mob is able to relay happiness, given by /datum/component/happiness +#define TRAIT_MOB_RELAY_HAPPINESS "mob_relay_happiness" ///trait determines if this mob can breed given by /datum/component/breeding #define TRAIT_MOB_BREEDER "mob_breeder" +///trait given to mobs that are hatched +#define TRAIT_MOB_HATCHED "mob_hatched" /// Trait given to mobs that we do not want to mindswap #define TRAIT_NO_MINDSWAP "no_mindswap" ///trait given to food that can be baked by /datum/component/bakeable diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index dcbfab7fe5f16..278510bd23fbe 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -137,6 +137,7 @@ #define LOCKED_HELMET_TRAIT "locked-helmet" #define NINJA_SUIT_TRAIT "ninja-suit" #define SLEEPING_CARP_TRAIT "sleeping_carp" +#define BOXING_TRAIT "boxing" #define TIMESTOP_TRAIT "timestop" #define LIFECANDLE_TRAIT "lifecandle" #define VENTCRAWLING_TRAIT "ventcrawling" @@ -286,8 +287,8 @@ /// Trait from an organ being inside a bodypart #define ORGAN_INSIDE_BODY_TRAIT "organ_inside_body" -/// Trait when something was labelled by a pen. -#define PEN_LABEL_TRAIT "pen_label" +/// Trait when something was labelled by the /datum/element/tool_renaming element. +#define RENAMING_TOOL_LABEL_TRAIT "renaming_tool_label" /// Trait when a drink was renamed by a shaker #define SHAKER_LABEL_TRAIT "shaker_trait" diff --git a/code/__DEFINES/turfs.dm b/code/__DEFINES/turfs.dm index 295c09f6d465e..545767289e0b5 100644 --- a/code/__DEFINES/turfs.dm +++ b/code/__DEFINES/turfs.dm @@ -82,6 +82,13 @@ */ #define get_area(A) (isarea(A) ? A : get_step(A, 0)?.loc) +// Defines for turfs rust resistance +#define RUST_RESISTANCE_BASIC 1 +#define RUST_RESISTANCE_REINFORCED 2 +#define RUST_RESISTANCE_TITANIUM 3 +#define RUST_RESISTANCE_ORGANIC 4 +#define RUST_RESISTANCE_ABSOLUTE 5 + /// Turf will be passable if density is 0 #define TURF_PATHING_PASS_DENSITY 0 /// Turf will be passable depending on [CanAStarPass] return value @@ -104,3 +111,8 @@ * Finds the midpoint of two given turfs. */ #define TURF_MIDPOINT(a, b) (locate(((a.x + b.x) * 0.5), (a.y + b.y) * 0.5, (a.z + b.z) * 0.5)) + +/// Defines the x offset to apply to larger smoothing turfs (such as grass). +#define LARGE_TURF_SMOOTHING_X_OFFSET -9 +/// Defines the y offset to apply to larger smoothing turfs (such as grass). +#define LARGE_TURF_SMOOTHING_Y_OFFSET -9 diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index dfa930f7a76ba..a83ef71ddc69f 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -136,6 +136,7 @@ // /mob/living #define VV_HK_GIVE_SPEECH_IMPEDIMENT "impede_speech" +#define VV_HK_ADMIN_RENAME "admin_rename" #define VV_HK_ADD_MOOD "addmood" #define VV_HK_REMOVE_MOOD "removemood" #define VV_HK_GIVE_HALLUCINATION "give_hallucination" diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 7af30c8d9727c..6811a31284aa4 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -417,7 +417,7 @@ **/ /proc/list_clear_nulls(list/list_to_clear) return (list_to_clear.RemoveAll(null) > 0) - + /** * Removes any empty weakrefs from the list @@ -473,17 +473,23 @@ * You should only pass integers in. */ /proc/pick_weight(list/list_to_pick) + if(length(list_to_pick) == 0) + return null + var/total = 0 - var/item - for(item in list_to_pick) + for(var/item in list_to_pick) if(!list_to_pick[item]) list_to_pick[item] = 0 total += list_to_pick[item] total = rand(1, total) - for(item in list_to_pick) - total -= list_to_pick[item] - if(total <= 0 && list_to_pick[item]) + for(var/item in list_to_pick) + var/item_weight = list_to_pick[item] + if(item_weight == 0) + continue + + total -= item_weight + if(total <= 0) return item return null diff --git a/code/__HELPERS/areas.dm b/code/__HELPERS/areas.dm index 8df182c90d060..dc2f66c2ed0dd 100644 --- a/code/__HELPERS/areas.dm +++ b/code/__HELPERS/areas.dm @@ -293,3 +293,51 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list( mobs_in_area += mob break return mobs_in_area + +/** + * rename_area + * Renames an area to the given new name, updating all machines' names and firedoors + * to properly ensure alarms and machines are named correctly at all times. + * Args: + * - area_to_rename: The area that's being renamed. + * - new_name: The name we're changing said area to. + */ +/proc/rename_area(area/area_to_rename, new_name) + var/prevname = "[area_to_rename.name]" + set_area_machinery_title(area_to_rename, new_name, prevname) + area_to_rename.name = new_name + require_area_resort() //area renamed so resort the names + + if(LAZYLEN(area_to_rename.firedoors)) + for(var/obj/machinery/door/firedoor/area_firedoors as anything in area_to_rename.firedoors) + area_firedoors.CalculateAffectingAreas() + area_to_rename.update_areasize() + return TRUE + +/** + * Renames all machines in a defined area from the old title to the new title. + * Used when renaming an area to ensure that all machiens are labeled the new area's machine. + * Args: + * - area_renaming: The area being renamed, which we'll check turfs from to rename machines in. + * - title: The new name of the area that we're swapping into. + * - oldtitle: The old name of the area that we're replacing text from. + */ +/proc/set_area_machinery_title(area/area_renaming, title, oldtitle) + if(!oldtitle) // or replacetext goes to infinite loop + return + + //stuff tied to the area to rename + var/static/list/to_rename = typecacheof(list( + /obj/machinery/airalarm, + /obj/machinery/atmospherics/components/unary/vent_scrubber, + /obj/machinery/atmospherics/components/unary/vent_pump, + /obj/machinery/door, + /obj/machinery/firealarm, + /obj/machinery/light_switch, + /obj/machinery/power/apc, + /obj/machinery/camera, + )) + for(var/list/zlevel_turfs as anything in area_renaming.get_zlevel_turf_lists()) + for(var/turf/area_turf as anything in zlevel_turfs) + for(var/obj/machine as anything in typecache_filter_list(area_turf.contents, to_rename)) + machine.name = replacetext(machine.name, oldtitle, title) diff --git a/code/__HELPERS/atmospherics.dm b/code/__HELPERS/atmospherics.dm index 3ac3bfaed569d..2a59cf60b403f 100644 --- a/code/__HELPERS/atmospherics.dm +++ b/code/__HELPERS/atmospherics.dm @@ -105,7 +105,7 @@ GLOBAL_LIST_EMPTY(gas_handbook) factor_info["factor_name"] = factor factor_info["factor_type"] = "misc" if(factor == "Temperature" || factor == "Pressure") - factor_info["tooltip"] = "Reaction is influenced by the [lowertext(factor)] of the place where the reaction is occuring." + factor_info["tooltip"] = "Reaction is influenced by the [LOWER_TEXT(factor)] of the place where the reaction is occuring." else if(factor == "Energy") factor_info["tooltip"] = "Energy released by the reaction, may or may not result in linear temperature change depending on a slew of other factors." else if(factor == "Radiation") @@ -138,7 +138,7 @@ GLOBAL_LIST_EMPTY(gas_handbook) factor_info["factor_name"] = factor factor_info["factor_type"] = "misc" if(factor == "Temperature" || factor == "Pressure") - factor_info["tooltip"] = "Reaction is influenced by the [lowertext(factor)] of the place where the reaction is occuring." + factor_info["tooltip"] = "Reaction is influenced by the [LOWER_TEXT(factor)] of the place where the reaction is occuring." else if(factor == "Energy") factor_info["tooltip"] = "Energy released by the reaction, may or may not result in linear temperature change depending on a slew of other factors." else if(factor == "Radiation") diff --git a/code/__HELPERS/chat_filter.dm b/code/__HELPERS/chat_filter.dm index 34d811bf85bae..22fe36a21367c 100644 --- a/code/__HELPERS/chat_filter.dm +++ b/code/__HELPERS/chat_filter.dm @@ -1,6 +1,6 @@ // [2] is the group index of the blocked term when it is not using word bounds. // This is sanity checked by unit tests. -#define GET_MATCHED_GROUP(regex) (lowertext(regex.group[2] || regex.match)) +#define GET_MATCHED_GROUP(regex) (LOWER_TEXT(regex.group[2] || regex.match)) /// Given a text, will return what word is on the IC filter, with the reason. /// Returns null if the message is OK. diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 8f3ac9744dad2..bd991f29d014a 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -2,44 +2,6 @@ /////Initial Building///// ////////////////////////// -/proc/init_sprite_accessories() - //hair - init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, GLOB.hairstyles_list, GLOB.hairstyles_male_list, GLOB.hairstyles_female_list) - //facial hair - init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hairstyles_list, GLOB.facial_hairstyles_male_list, GLOB.facial_hairstyles_female_list) - //underwear - init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f) - //undershirt - init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f) - //socks - init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list) - //bodypart accessories (blizzard intensifies) - init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human, add_blank = TRUE) - init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard, add_blank = TRUE) - init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, GLOB.tails_list_monkey, add_blank = TRUE) - init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open, GLOB.wings_open_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/tail_spines, GLOB.tail_spines_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/caps, GLOB.caps_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae, GLOB.moth_antennae_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, GLOB.moth_markings_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list) - -/// Inits GLOB.species_list. Not using GLOBAL_LIST_INIT b/c it depends on GLOB.string_lists -/proc/init_species_list() - for(var/species_path in subtypesof(/datum/species)) - var/datum/species/species = new species_path() - GLOB.species_list[species.id] = species_path - sort_list(GLOB.species_list, GLOBAL_PROC_REF(cmp_typepaths_asc)) - /// Inits GLOB.surgeries /proc/init_surgeries() var/surgeries = list() @@ -48,21 +10,9 @@ sort_list(surgeries, GLOBAL_PROC_REF(cmp_typepaths_asc)) return surgeries -/// Hair Gradients - Initialise all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name -/proc/init_hair_gradients() - for(var/path in subtypesof(/datum/sprite_accessory/gradient)) - var/datum/sprite_accessory/gradient/gradient = new path() - if(gradient.gradient_category & GRADIENT_APPLIES_TO_HAIR) - GLOB.hair_gradients_list[gradient.name] = gradient - if(gradient.gradient_category & GRADIENT_APPLIES_TO_FACIAL_HAIR) - GLOB.facial_hair_gradients_list[gradient.name] = gradient - /// Legacy procs that really should be replaced with proper _INIT macros /proc/make_datum_reference_lists() // I tried to eliminate this proc but I couldn't untangle their init-order interdependencies -Dominion/Cyberboss - init_sprite_accessories() - init_species_list() - init_hair_gradients() init_keybindings() GLOB.emote_list = init_emote_list() // WHY DOES THIS NEED TO GO HERE? IT JUST INITS DATUMS init_crafting_recipes() diff --git a/code/__HELPERS/hallucinations.dm b/code/__HELPERS/hallucinations.dm index 525114cea28bc..edd65ee926abf 100644 --- a/code/__HELPERS/hallucinations.dm +++ b/code/__HELPERS/hallucinations.dm @@ -113,11 +113,7 @@ GLOBAL_LIST_INIT(random_hallucination_weighted_list, generate_hallucination_weig to_chat(usr, span_boldnotice("The total weight of the hallucination weighted list is [total_weight].")) return total_weight -/// Debug verb for getting the weight of each distinct type within the random_hallucination_weighted_list -/client/proc/debug_hallucination_weighted_list_per_type() - set name = "Show Hallucination Weights" - set category = "Debug" - +ADMIN_VERB(debug_hallucination_weighted_list_per_type, R_DEBUG, "Show Hallucination Weights", "View the weight of each hallucination subtype in the random weighted list.", ADMIN_CATEGORY_DEBUG) var/header = "Type Weight Percent" var/total_weight = debug_hallucination_weighted_list() @@ -149,11 +145,11 @@ GLOBAL_LIST_INIT(random_hallucination_weighted_list, generate_hallucination_weig last_type_weight = this_weight // Sort by weight descending, where weight is the values (not the keys). We assoc_to_keys later to get JUST the text - all_weights = sortTim(all_weights, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE) + sortTim(all_weights, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE) var/page_style = "" var/page_contents = "[page_style][header][jointext(assoc_to_keys(all_weights), "")]
" - var/datum/browser/popup = new(mob, "hallucinationdebug", "Hallucination Weights", 600, 400) + var/datum/browser/popup = new(user.mob, "hallucinationdebug", "Hallucination Weights", 600, 400) popup.set_content(page_contents) popup.open() diff --git a/code/__HELPERS/hearted.dm b/code/__HELPERS/hearted.dm index 1eafef56a4f40..adae298516ec6 100644 --- a/code/__HELPERS/hearted.dm +++ b/code/__HELPERS/hearted.dm @@ -54,7 +54,7 @@ if(!heart_nominee) return - heart_nominee = lowertext(heart_nominee) + heart_nominee = LOWER_TEXT(heart_nominee) var/list/name_checks = get_mob_by_name(heart_nominee) if(!name_checks || name_checks.len == 0) query_heart(attempt + 1) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index b6870757cdc40..a67c78a12cc28 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -679,7 +679,7 @@ world if(uppercase == 1) letter = uppertext(letter) else if(uppercase == -1) - letter = lowertext(letter) + letter = LOWER_TEXT(letter) var/image/text_image = new(loc = A) text_image.maptext = MAPTEXT("[letter]") diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm index b7a7b689483c2..bfcaded67f021 100644 --- a/code/__HELPERS/logging/_logging.dm +++ b/code/__HELPERS/logging/_logging.dm @@ -70,7 +70,7 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) SEND_TEXT(world.log, text) #endif -#if defined(REFERENCE_DOING_IT_LIVE) +#if defined(REFERENCE_TRACKING_LOG_APART) #define log_reftracker(msg) log_harddel("## REF SEARCH [msg]") /proc/log_harddel(text) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index d42f1b1967577..d623a707b8855 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -29,31 +29,31 @@ return COLOR_BLACK /proc/random_underwear(gender) - if(!GLOB.underwear_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f) + if(length(SSaccessories.underwear_list) == 0) + CRASH("No underwear to choose from!") switch(gender) if(MALE) - return pick(GLOB.underwear_m) + return pick(SSaccessories.underwear_m) if(FEMALE) - return pick(GLOB.underwear_f) + return pick(SSaccessories.underwear_f) else - return pick(GLOB.underwear_list) + return pick(SSaccessories.underwear_list) /proc/random_undershirt(gender) - if(!GLOB.undershirt_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f) + if(length(SSaccessories.undershirt_list) == 0) + CRASH("No undershirts to choose from!") switch(gender) if(MALE) - return pick(GLOB.undershirt_m) + return pick(SSaccessories.undershirt_m) if(FEMALE) - return pick(GLOB.undershirt_f) + return pick(SSaccessories.undershirt_f) else - return pick(GLOB.undershirt_list) + return pick(SSaccessories.undershirt_list) /proc/random_socks() - if(!GLOB.socks_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list) - return pick(GLOB.socks_list) + if(length(SSaccessories.socks_list) == 0) + CRASH("No socks to choose from!") + return pick(SSaccessories.socks_list) /proc/random_backpack() return pick(GLOB.backpacklist) @@ -61,61 +61,20 @@ /proc/random_hairstyle(gender) switch(gender) if(MALE) - return pick(GLOB.hairstyles_male_list) + return pick(SSaccessories.hairstyles_male_list) if(FEMALE) - return pick(GLOB.hairstyles_female_list) + return pick(SSaccessories.hairstyles_female_list) else - return pick(GLOB.hairstyles_list) + return pick(SSaccessories.hairstyles_list) /proc/random_facial_hairstyle(gender) switch(gender) if(MALE) - return pick(GLOB.facial_hairstyles_male_list) + return pick(SSaccessories.facial_hairstyles_male_list) if(FEMALE) - return pick(GLOB.facial_hairstyles_female_list) + return pick(SSaccessories.facial_hairstyles_female_list) else - return pick(GLOB.facial_hairstyles_list) - -/proc/random_unique_name(gender, attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - if(gender == FEMALE) - . = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) - else - . = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - - if(!findname(.)) - break - -/proc/random_unique_lizard_name(gender, attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - . = capitalize(lizard_name(gender)) - - if(!findname(.)) - break - -/proc/random_unique_plasmaman_name(attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - . = capitalize(plasmaman_name()) - - if(!findname(.)) - break - -/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - . = capitalize(ethereal_name()) - - if(!findname(.)) - break - -/proc/random_unique_moth_name(attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - . = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last)) - - if(!findname(.)) - break - -/proc/random_skin_tone() - return pick(GLOB.skin_tones) + return pick(SSaccessories.facial_hairstyles_list) GLOBAL_LIST_INIT(skin_tones, sort_list(list( "albino", @@ -155,9 +114,6 @@ GLOBAL_LIST_INIT(skin_tone_names, list( "mixed4" = "Macadamia", )) -/// An assoc list of species IDs to type paths -GLOBAL_LIST_EMPTY(species_list) - /proc/age2agedescription(age) switch(age) if(0 to 1) @@ -201,9 +157,26 @@ GLOBAL_LIST_EMPTY(species_list) * * Checks that `user` does not move, change hands, get stunned, etc. for the * given `delay`. Returns `TRUE` on success or `FALSE` on failure. - * Interaction_key is the assoc key under which the do_after is capped, with max_interact_count being the cap. Interaction key will default to target if not set. + * + * @param {mob} user - The mob performing the action. + * + * @param {number} delay - The time in deciseconds. Use the SECONDS define for readability. `1 SECONDS` is 10 deciseconds. + * + * @param {atom} target - The target of the action. This is where the progressbar will display. + * + * @param {flag} timed_action_flags - Flags to control the behavior of the timed action. + * + * @param {boolean} progress - Whether to display a progress bar / cogbar. + * + * @param {datum/callback} extra_checks - Additional checks to perform before the action is executed. + * + * @param {string} interaction_key - The assoc key under which the do_after is capped, with max_interact_count being the cap. Interaction key will default to target if not set. + * + * @param {number} max_interact_count - The maximum amount of interactions allowed. + * + * @param {boolean} hidden - By default, any action 1 second or longer shows a cog over the user while it is in progress. If hidden is set to TRUE, the cog will not be shown. */ -/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1) +/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, hidden = FALSE) if(!user) return FALSE if(!isnum(delay)) @@ -221,7 +194,7 @@ GLOBAL_LIST_EMPTY(species_list) var/atom/target_loc = target?.loc var/drifting = FALSE - if(SSmove_manager.processing_on(user, SSspacedrift)) + if(GLOB.move_manager.processing_on(user, SSspacedrift)) drifting = TRUE var/holding = user.get_active_held_item() @@ -230,10 +203,15 @@ GLOBAL_LIST_EMPTY(species_list) delay *= user.cached_multiplicative_actions_slowdown var/datum/progressbar/progbar + var/datum/cogbar/cog + if(progress) if(user.client) progbar = new(user, delay, target || user) + if(!hidden && delay >= 1 SECONDS) + cog = new(user) + SEND_SIGNAL(user, COMSIG_DO_AFTER_BEGAN) var/endtime = world.time + delay @@ -245,7 +223,7 @@ GLOBAL_LIST_EMPTY(species_list) if(!QDELETED(progbar)) progbar.update(world.time - starttime) - if(drifting && !SSmove_manager.processing_on(user, SSspacedrift)) + if(drifting && !GLOB.move_manager.processing_on(user, SSspacedrift)) drifting = FALSE user_loc = user.loc @@ -266,6 +244,8 @@ GLOBAL_LIST_EMPTY(species_list) if(!QDELETED(progbar)) progbar.end_progress() + cog?.remove() + if(interaction_key) var/reduced_interaction_count = (LAZYACCESS(user.do_afters, interaction_key) || 0) - 1 if(reduced_interaction_count > 0) // Not done yet! @@ -598,6 +578,12 @@ GLOBAL_LIST_EMPTY(species_list) if(mob.ckey == key) return mob +/// Returns a string for the specified body zone. If we have a bodypart in this zone, refers to its plaintext_zone instead. +/mob/living/proc/parse_zone_with_bodypart(zone) + var/obj/item/bodypart/part = get_bodypart(zone) + + return part?.plaintext_zone || parse_zone(zone) + ///Return a string for the specified body zone. Should be used for parsing non-instantiated bodyparts, otherwise use [/obj/item/bodypart/var/plaintext_zone] /proc/parse_zone(zone) switch(zone) diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index 33bb0348df568..3a82c8dc1a66c 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -1,20 +1,75 @@ -/proc/lizard_name(gender) - if(gender == MALE) - return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]" - else - return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]" +/** + * Generate a random name based off of one of the roundstart languages + * + * * gender - What gender to pick from. Picks between male, female if not provided. + * * unique - If the name should be unique, IE, avoid picking names that mobs already have. + * * list/language_weights - A list of language weights to pick from. + * If not provided, it will default to a list of roundstart languages, with common being the most likely. + */ +/proc/generate_random_name(gender, unique, list/language_weights) + if(isnull(language_weights)) + language_weights = list() + for(var/lang_type in GLOB.uncommon_roundstart_languages) + language_weights[lang_type] = 1 + language_weights[/datum/language/common] = 20 + + var/datum/language/picked = GLOB.language_datum_instances[pick_weight(language_weights)] + if(unique) + return picked.get_random_unique_name(gender) + return picked.get_random_name(gender) + +/** + * Generate a random name based off of a species + * This will pick a name from the species language, and avoid picking common if there are alternatives + * + * * gender - What gender to pick from. Picks between male, female if not provided. + * * unique - If the name should be unique, IE, avoid picking names that mobs already have. + * * datum/species/species_type - The species to pick from + * * include_all - Makes the generated name a mix of all the languages the species can speak rather than just one of them + * Does this on a per-name basis, IE "Lizard first name, uncommon last name". + */ +/proc/generate_random_name_species_based(gender, unique, datum/species/species_type, include_all = FALSE) + ASSERT(ispath(species_type, /datum/species)) + var/datum/language_holder/holder = GLOB.prototype_language_holders[species_type::species_language_holder] -/proc/ethereal_name() - var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]" - if(prob(65)) - tempname += random_capital_letter() - return tempname + var/list/languages_to_pick_from = list() + for(var/language in holder.spoken_languages) + languages_to_pick_from[language] = 1 -/proc/plasmaman_name() - return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]" + if(length(languages_to_pick_from) >= 2) + // Basically, if we have alternatives, don't pick common it's boring + languages_to_pick_from -= /datum/language/common -/proc/moth_name() - return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]" + if(!include_all || length(languages_to_pick_from) <= 1) + return generate_random_name(gender, unique, languages_to_pick_from) + + var/list/name_parts = list() + for(var/lang_type in shuffle(languages_to_pick_from)) + name_parts += GLOB.language_datum_instances[lang_type].get_random_name(gender, name_count = 1, force_use_syllables = TRUE) + return jointext(name_parts, " ") + +/** + * Generates a random name for the mob based on their gender or species (for humans) + * + * * unique - If the name should be unique, IE, avoid picking names that mobs already have. + */ +/mob/proc/generate_random_mob_name(unique) + return generate_random_name_species_based(gender, unique, /datum/species/human) + +/mob/living/carbon/generate_random_mob_name(unique) + return generate_random_name_species_based(gender, unique, dna?.species?.type || /datum/species/human) + +/mob/living/silicon/generate_random_mob_name(unique) + return generate_random_name(gender, unique, list(/datum/language/machine = 1)) + +/mob/living/basic/drone/generate_random_mob_name(unique) + return generate_random_name(gender, unique, list(/datum/language/machine = 1)) + +/mob/living/basic/bot/generate_random_mob_name(unique) + return generate_random_name(gender, unique, list(/datum/language/machine = 1)) + +/mob/living/simple_animal/bot/generate_random_mob_name(unique) + return generate_random_name(gender, unique, list(/datum/language/machine = 1)) GLOBAL_VAR(command_name) /proc/command_name() @@ -194,16 +249,11 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex) if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc. switch(rand(1,2))//Mainly to add more options later. if(1) - if(names.len && prob(70)) + if(length(names) && prob(70)) . += pick(names) else - if(prob(10)) - . += pick(lizard_name(MALE),lizard_name(FEMALE)) - else - var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female)) - new_name += " " - new_name += pick(GLOB.last_names) - . += new_name + . += generate_random_name() + if(2) var/datum/job/job = pick(SSjob.joinable_occupations) if(job) @@ -215,22 +265,22 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex) if(2) switch(rand(1,3))//Food, drinks, or places. Only selectable once. if(1) - . += lowertext(pick(drinks)) + . += LOWER_TEXT(pick(drinks)) if(2) - . += lowertext(pick(foods)) + . += LOWER_TEXT(pick(foods)) if(3) - . += lowertext(pick(locations)) + . += LOWER_TEXT(pick(locations)) safety -= 2 if(3) switch(rand(1,4))//Abstract nouns, objects, adjectives, threats. Can be selected more than once. if(1) - . += lowertext(pick(nouns)) + . += LOWER_TEXT(pick(nouns)) if(2) - . += lowertext(pick(objects)) + . += LOWER_TEXT(pick(objects)) if(3) - . += lowertext(pick(adjectives)) + . += LOWER_TEXT(pick(adjectives)) if(4) - . += lowertext(pick(threats)) + . += LOWER_TEXT(pick(threats)) if(!return_list) if(words == 1) . += "." diff --git a/code/__HELPERS/priority_announce.dm b/code/__HELPERS/priority_announce.dm index f36ab36becbd5..895ff2388fd26 100644 --- a/code/__HELPERS/priority_announce.dm +++ b/code/__HELPERS/priority_announce.dm @@ -107,7 +107,7 @@ message.title = title message.content = text - SScommunications.send_message(message) + GLOB.communications_controller.send_message(message) /** * Sends a minor annoucement to players. diff --git a/code/__HELPERS/pronouns.dm b/code/__HELPERS/pronouns.dm index df84c1cdcf42a..fe2357d6ce422 100644 --- a/code/__HELPERS/pronouns.dm +++ b/code/__HELPERS/pronouns.dm @@ -1,5 +1,8 @@ +#define GET_TARGET_PRONOUN(target, pronoun, gender) call(target, ALL_PRONOUNS[pronoun])(gender) + //pronoun procs, for getting pronouns without using the text macros that only work in certain positions //datums don't have gender, but most of their subtypes do! + /datum/proc/p_they(temp_gender) return "it" @@ -69,6 +72,26 @@ else return "s" +/// A proc to replace pronouns in a string with the appropriate pronouns for a target atom. +/// Uses associative list access from a __DEFINE list, since associative access is slightly +/// faster +/datum/proc/REPLACE_PRONOUNS(target_string, atom/targeted_atom, targeted_gender = null) + /// If someone specifies targeted_gender we choose that, + /// otherwise we go off the gender of our object + var/gender + if(targeted_gender) + if(!istext(targeted_gender) || !(targeted_gender in list(MALE, FEMALE, PLURAL, NEUTER))) + stack_trace("REPLACE_PRONOUNS called with improper parameters.") + return + gender = targeted_gender + else + gender = targeted_atom.gender + var/regex/pronoun_regex = regex("%PRONOUN(_(they|They|their|Their|theirs|Theirs|them|Them|have|are|were|do|theyve|Theyve|theyre|Theyre|s|es))") + while(pronoun_regex.Find(target_string)) + target_string = pronoun_regex.Replace(target_string, GET_TARGET_PRONOUN(targeted_atom, pronoun_regex.match, gender)) + return target_string + + //like clients, which do have gender. /client/p_they(temp_gender) if(!temp_gender) diff --git a/code/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm index d557db3173ab9..012a1fd5cc09d 100644 --- a/code/__HELPERS/reagents.dm +++ b/code/__HELPERS/reagents.dm @@ -155,7 +155,7 @@ ///Returns a list of chemical_reaction datums that have the input STRING as a product /proc/get_reagent_type_from_product_string(string) - var/input_reagent = replacetext(lowertext(string), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name + var/input_reagent = replacetext(LOWER_TEXT(string), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name if (isnull(input_reagent)) return @@ -194,7 +194,7 @@ /proc/get_chem_id(chem_name) for(var/X in GLOB.chemical_reagents_list) var/datum/reagent/R = GLOB.chemical_reagents_list[X] - if(ckey(chem_name) == ckey(lowertext(R.name))) + if(ckey(chem_name) == ckey(LOWER_TEXT(R.name))) return X ///Takes a type in and returns a list of associated recipes diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm index 555f5175d7af7..8cc03a317e95a 100644 --- a/code/__HELPERS/sanitize_values.dm +++ b/code/__HELPERS/sanitize_values.dm @@ -73,7 +73,7 @@ if(97 to 102) //letters a to f . += char if(65 to 70) //letters A to F - char = lowertext(char) + char = LOWER_TEXT(char) . += char else break diff --git a/code/__HELPERS/sorts/InsertSort.dm b/code/__HELPERS/sorts/InsertSort.dm deleted file mode 100644 index 2d5ca408ce3b3..0000000000000 --- a/code/__HELPERS/sorts/InsertSort.dm +++ /dev/null @@ -1,19 +0,0 @@ -//simple insertion sort - generally faster than merge for runs of 7 or smaller -/proc/sortInsert(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0) - if(L && L.len >= 2) - fromIndex = fromIndex % L.len - toIndex = toIndex % (L.len+1) - if(fromIndex <= 0) - fromIndex += L.len - if(toIndex <= 0) - toIndex += L.len + 1 - - var/datum/sort_instance/SI = GLOB.sortInstance - if(!SI) - SI = new - SI.L = L - SI.cmp = cmp - SI.associative = associative - - SI.binarySort(fromIndex, toIndex, fromIndex) - return L diff --git a/code/__HELPERS/sorts/MergeSort.dm b/code/__HELPERS/sorts/MergeSort.dm deleted file mode 100644 index 4692534edffd7..0000000000000 --- a/code/__HELPERS/sorts/MergeSort.dm +++ /dev/null @@ -1,19 +0,0 @@ -//merge-sort - gernerally faster than insert sort, for runs of 7 or larger -/proc/sortMerge(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex) - if(L && L.len >= 2) - fromIndex = fromIndex % L.len - toIndex = toIndex % (L.len+1) - if(fromIndex <= 0) - fromIndex += L.len - if(toIndex <= 0) - toIndex += L.len + 1 - - var/datum/sort_instance/SI = GLOB.sortInstance - if(!SI) - SI = new - SI.L = L - SI.cmp = cmp - SI.associative = associative - - SI.mergeSort(fromIndex, toIndex) - return L diff --git a/code/__HELPERS/sorts/TimSort.dm b/code/__HELPERS/sorts/TimSort.dm deleted file mode 100644 index 44f6d170df402..0000000000000 --- a/code/__HELPERS/sorts/TimSort.dm +++ /dev/null @@ -1,20 +0,0 @@ -//TimSort interface -/proc/sortTim(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0) - if(L && L.len >= 2) - fromIndex = fromIndex % L.len - toIndex = toIndex % (L.len+1) - if(fromIndex <= 0) - fromIndex += L.len - if(toIndex <= 0) - toIndex += L.len + 1 - - var/datum/sort_instance/SI = GLOB.sortInstance - if(!SI) - SI = new - - SI.L = L - SI.cmp = cmp - SI.associative = associative - - SI.timSort(fromIndex, toIndex) - return L diff --git a/code/__HELPERS/sorts/helpers.dm b/code/__HELPERS/sorts/helpers.dm new file mode 100644 index 0000000000000..7198286f29fe2 --- /dev/null +++ b/code/__HELPERS/sorts/helpers.dm @@ -0,0 +1,95 @@ +/// Sorts the list in place with timSort, default settings. +#define SORT_TIM(to_sort, associative) if(length(to_sort) >= 2) { \ + var/datum/sort_instance/sorter = GLOB.sortInstance; \ + if (isnull(sorter)) { \ + sorter = new; \ + } \ + sorter.L = to_sort; \ + sorter.cmp = GLOBAL_PROC_REF(cmp_numeric_asc); \ + sorter.associative = associative; \ + sorter.timSort(1, 0); \ +} + + +/// Helper for the sorting procs. Prevents some code duplication. Creates /datum/sort_instance/sorter +#define CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) \ + if(length(to_sort) < 2) { \ + return to_sort; \ + } \ + fromIndex = fromIndex % length(to_sort); \ + toIndex = toIndex % (length(to_sort) + 1); \ + if (fromIndex <= 0) { \ + fromIndex += length(to_sort); \ + } \ + if (toIndex <= 0) { \ + toIndex += length(to_sort) + 1; \ + } \ + var/datum/sort_instance/sorter = GLOB.sortInstance; \ + if (isnull(sorter)) { \ + sorter = new; \ + } \ + sorter.L = to_sort; \ + sorter.cmp = cmp; \ + sorter.associative = associative; + + +/** + * ## Tim Sort + * Hybrid sorting algorithm derived from merge sort and insertion sort. + * + * **Sorts in place**. + * You might not need to get the return value. + * + * @see + * https://en.wikipedia.org/wiki/Timsort + * + * @param {list} to_sort - The list to sort. + * + * @param {proc} cmp - The comparison proc to use. Default: Numeric ascending. + * + * @param {boolean} associative - Whether the list is associative. Default: FALSE. + * + * @param {int} fromIndex - The index to start sorting from. Default: 1. + * + * @param {int} toIndex - The index to stop sorting at. Default: 0. + */ +/proc/sortTim(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list + CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) + + sorter.timSort(fromIndex, toIndex) + + return to_sort + + +/** + * ## Merge Sort + * Divide and conquer sorting algorithm. + * + * @see + * - https://en.wikipedia.org/wiki/Merge_sort + */ +/proc/sortMerge(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list + CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) + + sorter.mergeSort(fromIndex, toIndex) + + return to_sort + + +/** + * ## Insertion Sort + * Simple sorting algorithm that builds the final sorted list one item at a time. + * + + * @see + * - https://en.wikipedia.org/wiki/Insertion_sort + */ +/proc/sortInsert(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list + CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) + + sorter.binarySort(fromIndex, toIndex) + + return to_sort + + +#undef CREATE_SORT_INSTANCE diff --git a/code/__HELPERS/sorts/__main.dm b/code/__HELPERS/sorts/sort_instance.dm similarity index 100% rename from code/__HELPERS/sorts/__main.dm rename to code/__HELPERS/sorts/sort_instance.dm diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 4f6031fcf3ffd..40915672ef960 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -785,7 +785,7 @@ GLOBAL_LIST_INIT(binary, list("0","1")) return string var/base = next_backslash == 1 ? "" : copytext(string, 1, next_backslash) - var/macro = lowertext(copytext(string, next_backslash + length(string[next_backslash]), next_space)) + var/macro = LOWER_TEXT(copytext(string, next_backslash + length(string[next_backslash]), next_space)) var/rest = next_backslash > leng ? "" : copytext(string, next_space + length(string[next_space])) //See https://secure.byond.com/docs/ref/info.html#/DM/text/macros @@ -1082,7 +1082,7 @@ GLOBAL_LIST_INIT(binary, list("0","1")) var/text_length = length(text) //remove caps since words will be shuffled - text = lowertext(text) + text = LOWER_TEXT(text) //remove punctuation for same reasons as above var/punctuation = "" var/punctuation_hit_list = list("!","?",".","-") diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index 9c57f2334c8cf..ac3ff23b05e41 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -28,7 +28,7 @@ SSticker.gametime_offset = CEILING(SSticker.gametime_offset, 3600) //returns timestamp in a sql and a not-quite-compliant ISO 8601 friendly format -/proc/SQLtime(timevar) +/proc/ISOtime(timevar) return time2text(timevar || world.timeofday, "YYYY-MM-DD hh:mm:ss") diff --git a/code/__HELPERS/turfs.dm b/code/__HELPERS/turfs.dm index 32a570ae8fc11..c44845a5854b7 100644 --- a/code/__HELPERS/turfs.dm +++ b/code/__HELPERS/turfs.dm @@ -413,3 +413,20 @@ Turf and target are separate in case you want to teleport some distance from a t if(locate(type_to_find) in location) return TRUE return FALSE + +/** + * get_blueprint_data + * Gets a list of turfs around a central turf and gets the blueprint data in a list + * Args: + * - central_turf: The center turf we're getting data from. + * - viewsize: The viewsize we're getting the turfs around central_turf of. + */ +/proc/get_blueprint_data(turf/central_turf, viewsize) + var/list/blueprint_data_returned = list() + var/list/dimensions = getviewsize(viewsize) + var/horizontal_radius = dimensions[1] / 2 + var/vertical_radius = dimensions[2] / 2 + for(var/turf/nearby_turf as anything in RECT_TURFS(horizontal_radius, vertical_radius, central_turf)) + if(nearby_turf.blueprint_data) + blueprint_data_returned += nearby_turf.blueprint_data + return blueprint_data_returned diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 9eb1a491f425a..03d308e34d635 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -389,7 +389,7 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH, if(/turf) return "turf" else //regex everything else (works for /proc too) - return lowertext(replacetext("[the_type]", "[type2parent(the_type)]/", "")) + return LOWER_TEXT(replacetext("[the_type]", "[type2parent(the_type)]/", "")) /// Return html to load a url. /// for use inside of browse() calls to html assets that might be loaded on a cdn. diff --git a/code/__HELPERS/view.dm b/code/__HELPERS/view.dm index dc25dcc02492d..30e8bc8f9f973 100644 --- a/code/__HELPERS/view.dm +++ b/code/__HELPERS/view.dm @@ -20,8 +20,23 @@ view_info[2] *= world.icon_size return view_info -/proc/in_view_range(mob/user, atom/A) - var/list/view_range = getviewsize(user.client.view) - var/turf/source = get_turf(user) - var/turf/target = get_turf(A) - return ISINRANGE(target.x, source.x - view_range[1], source.x + view_range[1]) && ISINRANGE(target.y, source.y - view_range[1], source.y + view_range[1]) +/** +* Frustrated with bugs in can_see(), this instead uses viewers for a much more effective approach. +* ### Things to note: +* - Src/source must be a mob. `viewers()` returns mobs. +* - Adjacent objects are always considered visible. +*/ + +/// The default tile-distance between two atoms for one to consider the other as visible. +#define DEFAULT_SIGHT_DISTANCE 7 + +/// Basic check to see if the src object can see the target object. +#define CAN_I_SEE(target) ((src in viewers(DEFAULT_SIGHT_DISTANCE, target)) || in_range(target, src)) + + +/// Checks the visibility between two other objects. +#define CAN_THEY_SEE(target, source) ((source in viewers(DEFAULT_SIGHT_DISTANCE, target)) || in_range(target, source)) + + +/// Further checks distance between source and target. +#define CAN_SEE_RANGED(target, source, dist) ((source in viewers(dist, target)) || in_range(target, source)) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 0d534fac9a36c..6056a292ed61f 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -34,6 +34,8 @@ #define FIND_REF_NO_CHECK_TICK #endif //ifdef GC_FAILURE_HARD_LOOKUP +// Log references in their own file, rather then in runtimes.log +//#define REFERENCE_TRACKING_LOG_APART #endif //ifdef REFERENCE_TRACKING /* @@ -60,8 +62,24 @@ #define REFERENCE_TRACKING // actually look for refs #define GC_FAILURE_HARD_LOOKUP +// Log references in their own file +#define REFERENCE_TRACKING_LOG_APART #endif // REFERENCE_DOING_IT_LIVE +/// Sets up the reftracker to be used locally, to hunt for hard deletions +/// Errors are logged to [log_dir]/harddels.log +//#define REFERENCE_TRACKING_STANDARD +#ifdef REFERENCE_TRACKING_STANDARD +// compile the backend +#define REFERENCE_TRACKING +// actually look for refs +#define GC_FAILURE_HARD_LOOKUP +// spend ALL our time searching, not just part of it +#define FIND_REF_NO_CHECK_TICK +// Log references in their own file +#define REFERENCE_TRACKING_LOG_APART +#endif // REFERENCE_TRACKING_STANDARD + // If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between // #define UNIT_TESTS diff --git a/code/_globalvars/arcade.dm b/code/_globalvars/arcade.dm new file mode 100644 index 0000000000000..4143ce5fa765f --- /dev/null +++ b/code/_globalvars/arcade.dm @@ -0,0 +1,73 @@ +///List of all things that can be dispensed by an arcade cabinet and the weight of them being picked. +GLOBAL_LIST_INIT(arcade_prize_pool, list( + /obj/item/storage/box/snappops = 2, + /obj/item/toy/talking/ai = 2, + /obj/item/toy/talking/codex_gigas = 2, + /obj/item/clothing/under/syndicate/tacticool = 2, + /obj/item/toy/sword = 2, + /obj/item/toy/gun = 2, + /obj/item/gun/ballistic/shotgun/toy/crossbow = 2, + /obj/item/storage/box/fakesyndiesuit = 2, + /obj/item/storage/crayons = 2, + /obj/item/toy/spinningtoy = 2, + /obj/item/toy/spinningtoy/dark_matter = 1, + /obj/item/toy/balloon/arrest = 2, + /obj/item/toy/mecha/ripley = 1, + /obj/item/toy/mecha/ripleymkii = 1, + /obj/item/toy/mecha/hauler = 1, + /obj/item/toy/mecha/clarke = 1, + /obj/item/toy/mecha/odysseus = 1, + /obj/item/toy/mecha/gygax = 1, + /obj/item/toy/mecha/durand = 1, + /obj/item/toy/mecha/savannahivanov = 1, + /obj/item/toy/mecha/phazon = 1, + /obj/item/toy/mecha/honk = 1, + /obj/item/toy/mecha/darkgygax = 1, + /obj/item/toy/mecha/mauler = 1, + /obj/item/toy/mecha/darkhonk = 1, + /obj/item/toy/mecha/deathripley = 1, + /obj/item/toy/mecha/reticence = 1, + /obj/item/toy/mecha/marauder = 1, + /obj/item/toy/mecha/seraph = 1, + /obj/item/toy/mecha/firefighter = 1, + /obj/item/toy/cards/deck = 2, + /obj/item/toy/nuke = 2, + /obj/item/toy/minimeteor = 2, + /obj/item/toy/redbutton = 2, + /obj/item/toy/talking/owl = 2, + /obj/item/toy/talking/griffin = 2, + /obj/item/coin/antagtoken = 2, + /obj/item/stack/tile/fakepit/loaded = 2, + /obj/item/stack/tile/eighties/loaded = 2, + /obj/item/toy/toy_xeno = 2, + /obj/item/storage/box/actionfigure = 1, + /obj/item/restraints/handcuffs/fake = 2, + /obj/item/grenade/chem_grenade/glitter/pink = 1, + /obj/item/grenade/chem_grenade/glitter/blue = 1, + /obj/item/grenade/chem_grenade/glitter/white = 1, + /obj/item/toy/eightball = 2, + /obj/item/toy/windup_toolbox = 2, + /obj/item/toy/clockwork_watch = 2, + /obj/item/toy/toy_dagger = 2, + /obj/item/extendohand/acme = 1, + /obj/item/hot_potato/harmless/toy = 1, + /obj/item/card/emagfake = 1, + /obj/item/clothing/shoes/wheelys = 2, + /obj/item/clothing/shoes/kindle_kicks = 2, + /obj/item/toy/plush/goatplushie = 2, + /obj/item/toy/plush/moth = 2, + /obj/item/toy/plush/pkplush = 2, + /obj/item/toy/plush/rouny = 2, + /obj/item/toy/plush/abductor = 2, + /obj/item/toy/plush/abductor/agent = 2, + /obj/item/toy/plush/shark = 2, + /obj/item/storage/belt/military/snack/full = 2, + /obj/item/toy/brokenradio = 2, + /obj/item/toy/braintoy = 2, + /obj/item/toy/eldritch_book = 2, + /obj/item/storage/box/heretic_box = 1, + /obj/item/toy/foamfinger = 2, + /obj/item/clothing/glasses/trickblindfold = 2, + /obj/item/clothing/mask/party_horn = 2, + /obj/item/storage/box/party_poppers = 2, +)) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 37e7ef30d41c7..c62b44e47517d 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -152,15 +152,14 @@ DEFINE_BITFIELD(interaction_flags_atom, list( )) DEFINE_BITFIELD(interaction_flags_machine, list( - "INTERACT_MACHINE_ALLOW_SILICON" = INTERACT_MACHINE_ALLOW_SILICON, - "INTERACT_MACHINE_OFFLINE" = INTERACT_MACHINE_OFFLINE, "INTERACT_MACHINE_OPEN" = INTERACT_MACHINE_OPEN, + "INTERACT_MACHINE_OFFLINE" = INTERACT_MACHINE_OFFLINE, + "INTERACT_MACHINE_WIRES_IF_OPEN" = INTERACT_MACHINE_WIRES_IF_OPEN, + "INTERACT_MACHINE_ALLOW_SILICON" = INTERACT_MACHINE_ALLOW_SILICON, "INTERACT_MACHINE_OPEN_SILICON" = INTERACT_MACHINE_OPEN_SILICON, + "INTERACT_MACHINE_REQUIRES_SILICON" = INTERACT_MACHINE_REQUIRES_SILICON, "INTERACT_MACHINE_REQUIRES_SIGHT" = INTERACT_MACHINE_REQUIRES_SIGHT, "INTERACT_MACHINE_REQUIRES_LITERACY" = INTERACT_MACHINE_REQUIRES_LITERACY, - "INTERACT_MACHINE_REQUIRES_SILICON" = INTERACT_MACHINE_REQUIRES_SILICON, - "INTERACT_MACHINE_SET_MACHINE" = INTERACT_MACHINE_SET_MACHINE, - "INTERACT_MACHINE_WIRES_IF_OPEN" = INTERACT_MACHINE_WIRES_IF_OPEN, )) DEFINE_BITFIELD(interaction_flags_item, list( @@ -278,20 +277,20 @@ DEFINE_BITFIELD(movement_type, list( )) DEFINE_BITFIELD(obj_flags, list( - "BLOCK_Z_IN_DOWN" = BLOCK_Z_IN_DOWN, - "BLOCK_Z_IN_UP" = BLOCK_Z_IN_UP, + "EMAGGED" = EMAGGED, + "CAN_BE_HIT" = CAN_BE_HIT, + "DANGEROUS_POSSESSION" = DANGEROUS_POSSESSION, + "UNIQUE_RENAME" = UNIQUE_RENAME, "BLOCK_Z_OUT_DOWN" = BLOCK_Z_OUT_DOWN, "BLOCK_Z_OUT_UP" = BLOCK_Z_OUT_UP, - "BLOCKS_CONSTRUCTION_DIR" = BLOCKS_CONSTRUCTION_DIR, + "BLOCK_Z_IN_DOWN" = BLOCK_Z_IN_DOWN, + "BLOCK_Z_IN_UP" = BLOCK_Z_IN_UP, "BLOCKS_CONSTRUCTION" = BLOCKS_CONSTRUCTION, - "CAN_BE_HIT" = CAN_BE_HIT, - "CONDUCTS_ELECTRICITY" = CONDUCTS_ELECTRICITY, - "DANGEROUS_POSSESSION" = DANGEROUS_POSSESSION, - "EMAGGED" = EMAGGED, + "BLOCKS_CONSTRUCTION_DIR" = BLOCKS_CONSTRUCTION_DIR, "IGNORE_DENSITY" = IGNORE_DENSITY, - "IN_USE" = IN_USE, - "NO_DECONSTRUCTION" = NO_DECONSTRUCTION, - "UNIQUE_RENAME" = UNIQUE_RENAME, + "INFINITE_RESKIN" = INFINITE_RESKIN, + "CONDUCTS_ELECTRICITY" = CONDUCTS_ELECTRICITY, + "NO_DEBRIS_AFTER_DECONSTRUCTION" = NO_DEBRIS_AFTER_DECONSTRUCTION, )) DEFINE_BITFIELD(pass_flags, list( @@ -340,6 +339,19 @@ DEFINE_BITFIELD(vis_flags, list( "VIS_UNDERLAY" = VIS_UNDERLAY, )) +// I am so sorry. Required because vis_flags is both undefinable and unreadable on mutable_appearance +// But we need to display them anyway. See /mutable_appearance/appearance_mirror +DEFINE_BITFIELD(_vis_flags, list( + "VIS_HIDE" = VIS_HIDE, + "VIS_INHERIT_DIR" = VIS_INHERIT_DIR, + "VIS_INHERIT_ICON" = VIS_INHERIT_ICON, + "VIS_INHERIT_ICON_STATE" = VIS_INHERIT_ICON_STATE, + "VIS_INHERIT_ID" = VIS_INHERIT_ID, + "VIS_INHERIT_LAYER" = VIS_INHERIT_LAYER, + "VIS_INHERIT_PLANE" = VIS_INHERIT_PLANE, + "VIS_UNDERLAY" = VIS_UNDERLAY, +)) + DEFINE_BITFIELD(zap_flags, list( "ZAP_ALLOW_DUPLICATES" = ZAP_ALLOW_DUPLICATES, "ZAP_MACHINE_EXPLOSIVE" = ZAP_MACHINE_EXPLOSIVE, diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index ce4d847928988..e7c6368d4d5fd 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -1,45 +1,3 @@ -//Preferences stuff - //Hairstyles -GLOBAL_LIST_EMPTY(hairstyles_list) //stores /datum/sprite_accessory/hair indexed by name -GLOBAL_LIST_EMPTY(hairstyles_male_list) //stores only hair names -GLOBAL_LIST_EMPTY(hairstyles_female_list) //stores only hair names -GLOBAL_LIST_EMPTY(facial_hairstyles_list) //stores /datum/sprite_accessory/facial_hair indexed by name -GLOBAL_LIST_EMPTY(facial_hairstyles_male_list) //stores only hair names -GLOBAL_LIST_EMPTY(facial_hairstyles_female_list) //stores only hair names -GLOBAL_LIST_EMPTY(hair_gradients_list) //stores /datum/sprite_accessory/hair_gradient indexed by name -GLOBAL_LIST_EMPTY(facial_hair_gradients_list) //stores /datum/sprite_accessory/facial_hair_gradient indexed by name - //Underwear -GLOBAL_LIST_EMPTY(underwear_list) //stores /datum/sprite_accessory/underwear indexed by name -GLOBAL_LIST_EMPTY(underwear_m) //stores only underwear name -GLOBAL_LIST_EMPTY(underwear_f) //stores only underwear name - //Undershirts -GLOBAL_LIST_EMPTY(undershirt_list) //stores /datum/sprite_accessory/undershirt indexed by name -GLOBAL_LIST_EMPTY(undershirt_m) //stores only undershirt name -GLOBAL_LIST_EMPTY(undershirt_f) //stores only undershirt name - //Socks -GLOBAL_LIST_EMPTY(socks_list) //stores /datum/sprite_accessory/socks indexed by name - //Lizard Bits (all datum lists indexed by name) -GLOBAL_LIST_EMPTY(body_markings_list) -GLOBAL_LIST_EMPTY(snouts_list) -GLOBAL_LIST_EMPTY(horns_list) -GLOBAL_LIST_EMPTY(frills_list) -GLOBAL_LIST_EMPTY(spines_list) -GLOBAL_LIST_EMPTY(tail_spines_list) -GLOBAL_LIST_EMPTY(legs_list) - - //Mutant Human bits -GLOBAL_LIST_EMPTY(tails_list_human) -GLOBAL_LIST_EMPTY(tails_list_lizard) -GLOBAL_LIST_EMPTY(tails_list_monkey) -GLOBAL_LIST_EMPTY(ears_list) -GLOBAL_LIST_EMPTY(wings_list) -GLOBAL_LIST_EMPTY(wings_open_list) -GLOBAL_LIST_EMPTY(moth_wings_list) -GLOBAL_LIST_EMPTY(moth_antennae_list) -GLOBAL_LIST_EMPTY(moth_markings_list) -GLOBAL_LIST_EMPTY(caps_list) -GLOBAL_LIST_EMPTY(pod_hair_list) - GLOBAL_LIST_INIT(color_list_ethereal, list( "Blue" = "#3399ff", "Bright Yellow" = "#ffff99", diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index 8719f45f18fc0..45f59fb447514 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -111,6 +111,7 @@ GLOBAL_LIST_EMPTY(gorilla_start) GLOBAL_LIST_EMPTY(wizardstart) GLOBAL_LIST_EMPTY(nukeop_start) GLOBAL_LIST_EMPTY(nukeop_leader_start) +GLOBAL_LIST_EMPTY(nukeop_overwatch_start) GLOBAL_LIST_EMPTY(newplayer_start) GLOBAL_LIST_EMPTY(prisonwarp) //admin prisoners go to these GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here (ninja energy net) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 2de6a1c691fc8..692704be0fffd 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -59,7 +59,7 @@ GLOBAL_LIST_EMPTY(human_list) //all instances of /mob/living/carbon/human and su GLOBAL_LIST_EMPTY(ai_list) GLOBAL_LIST_EMPTY(pai_list) GLOBAL_LIST_EMPTY(available_ai_shells) -GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list(),list())) // One for each AI_* status define +GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list())) // One for each AI_* status define GLOBAL_LIST_EMPTY(spidermobs) //all sentient spider mobs GLOBAL_LIST_EMPTY(bots_list) GLOBAL_LIST_EMPTY(aiEyes) @@ -85,11 +85,54 @@ GLOBAL_LIST_EMPTY(revenant_relay_mobs) ///underages who have been reported to security for trying to buy things they shouldn't, so they can't spam GLOBAL_LIST_EMPTY(narcd_underages) +/// List of language prototypes to reference, assoc [type] = prototype +GLOBAL_LIST_INIT_TYPED(language_datum_instances, /datum/language, init_language_prototypes()) +/// List if all language typepaths learnable, IE, those with keys +GLOBAL_LIST_INIT(all_languages, init_all_languages()) +// /List of language prototypes to reference, assoc "name" = typepath +GLOBAL_LIST_INIT(language_types_by_name, init_language_types_by_name()) + +/proc/init_language_prototypes() + var/list/lang_list = list() + for(var/datum/language/lang_type as anything in typesof(/datum/language)) + if(!initial(lang_type.key)) + continue + + lang_list[lang_type] = new lang_type() + return lang_list -GLOBAL_LIST_EMPTY(language_datum_instances) -GLOBAL_LIST_EMPTY(all_languages) -///List of all languages ("name" = type) -GLOBAL_LIST_EMPTY(language_types_by_name) +/proc/init_all_languages() + var/list/lang_list = list() + for(var/datum/language/lang_type as anything in typesof(/datum/language)) + if(!initial(lang_type.key)) + continue + lang_list += lang_type + return lang_list + +/proc/init_language_types_by_name() + var/list/lang_list = list() + for(var/datum/language/lang_type as anything in typesof(/datum/language)) + if(!initial(lang_type.key)) + continue + lang_list[initial(lang_type.name)] = lang_type + return lang_list + +/// An assoc list of species IDs to type paths +GLOBAL_LIST_INIT(species_list, init_species_list()) +/// List of all species prototypes to reference, assoc [type] = prototype +GLOBAL_LIST_INIT_TYPED(species_prototypes, /datum/species, init_species_prototypes()) + +/proc/init_species_list() + var/list/species_list = list() + for(var/datum/species/species_path as anything in subtypesof(/datum/species)) + species_list[initial(species_path.id)] = species_path + return species_list + +/proc/init_species_prototypes() + var/list/species_list = list() + for(var/species_type in subtypesof(/datum/species)) + species_list[species_type] = new species_type() + return species_list GLOBAL_LIST_EMPTY(sentient_disease_instances) diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm index c51fbaa9eb7a0..81fe08373b31a 100644 --- a/code/_globalvars/lists/names.dm +++ b/code/_globalvars/lists/names.dm @@ -8,12 +8,12 @@ GLOBAL_LIST_INIT(first_names, world.file2list("strings/names/first.txt")) GLOBAL_LIST_INIT(first_names_male, world.file2list("strings/names/first_male.txt")) GLOBAL_LIST_INIT(first_names_female, world.file2list("strings/names/first_female.txt")) GLOBAL_LIST_INIT(last_names, world.file2list("strings/names/last.txt")) -GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt")) -GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt")) GLOBAL_LIST_INIT(clown_names, world.file2list("strings/names/clown.txt")) GLOBAL_LIST_INIT(mime_names, world.file2list("strings/names/mime.txt")) GLOBAL_LIST_INIT(religion_names, world.file2list("strings/names/religion.txt")) GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt")) +GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt")) +GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt")) GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt")) GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt")) GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt")) diff --git a/code/_globalvars/lists/quirks.dm b/code/_globalvars/lists/quirks.dm index 085eaaa510788..4ce15f2e09e12 100644 --- a/code/_globalvars/lists/quirks.dm +++ b/code/_globalvars/lists/quirks.dm @@ -12,19 +12,23 @@ GLOBAL_LIST_INIT(nearsighted_glasses, list( ///Options for the prosthetic limb quirk to choose from GLOBAL_LIST_INIT(limb_choice, list( - "Left arm" = /obj/item/bodypart/arm/left/robot/surplus, - "Right arm" = /obj/item/bodypart/arm/right/robot/surplus, - "Left leg" = /obj/item/bodypart/leg/left/robot/surplus, - "Right leg" = /obj/item/bodypart/leg/right/robot/surplus, + "Left Arm" = /obj/item/bodypart/arm/left/robot/surplus, + "Right Arm" = /obj/item/bodypart/arm/right/robot/surplus, + "Left Leg" = /obj/item/bodypart/leg/left/robot/surplus, + "Right Leg" = /obj/item/bodypart/leg/right/robot/surplus, )) + ///Transhumanist quirk -GLOBAL_LIST_INIT(limb_choice_transhuman, list( +GLOBAL_LIST_INIT(part_choice_transhuman, list( "Left Arm" = /obj/item/bodypart/arm/left/robot, "Right Arm" = /obj/item/bodypart/arm/right/robot, "Left Leg" = /obj/item/bodypart/leg/left/robot, "Right Leg" = /obj/item/bodypart/leg/right/robot, + "Robotic Voice Box" = /obj/item/organ/internal/tongue/robot, + "Flashlights for Eyes" = /obj/item/organ/internal/eyes/robotic/flashlight, )) + ///Hemiplegic Quirk GLOBAL_LIST_INIT(side_choice_hemiplegic, list( "Left Side" = /datum/brain_trauma/severe/paralysis/hemiplegic/left, @@ -54,7 +58,7 @@ GLOBAL_LIST_INIT(possible_smoker_addictions, setup_junkie_addictions(list( ))) ///Options for the Alcoholic quirk to choose from -GLOBAL_LIST_INIT(possible_alcoholic_addictions, setup_junkie_addictions(list( +GLOBAL_LIST_INIT(possible_alcoholic_addictions, list( "Beekhof Blauw Curaçao" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/curacao, "reagent" = /datum/reagent/consumable/ethanol/curacao), "Buckin' Bronco's Applejack" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/applejack, "reagent" = /datum/reagent/consumable/ethanol/applejack), "Voltaic Yellow Wine" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic, "reagent" = /datum/reagent/consumable/ethanol/wine_voltaic), @@ -79,7 +83,7 @@ GLOBAL_LIST_INIT(possible_alcoholic_addictions, setup_junkie_addictions(list( "Breezy Shoals Coconut Rum" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/coconut_rum, "reagent" = /datum/reagent/consumable/ethanol/coconut_rum), "Moonlabor Yūyake" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/yuyake, "reagent" = /datum/reagent/consumable/ethanol/yuyake), "Shu-Kouba Straight Shochu" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/shochu, "reagent" = /datum/reagent/consumable/ethanol/shochu) -))) +)) ///Options for Prosthetic Organ GLOBAL_LIST_INIT(organ_choice, list( diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index fc6919c3a3b86..3100456691011 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -33,7 +33,7 @@ GLOBAL_PROTECT(##log_var_name);\ DECLARE_LOG(config_error_log, DONT_START_LOG) DECLARE_LOG(perf_log, DONT_START_LOG) // Declared here but name is set in time_track subsystem -#ifdef REFERENCE_DOING_IT_LIVE +#ifdef REFERENCE_TRACKING_LOG_APART DECLARE_LOG_NAMED(harddel_log, "harddels", START_LOG) #endif diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index f4aa1306a1e42..19449c6e4637e 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -79,6 +79,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "STATION_TRAIT_BIGGER_PODS" = STATION_TRAIT_BIGGER_PODS, "STATION_TRAIT_BIRTHDAY" = STATION_TRAIT_BIRTHDAY, "STATION_TRAIT_BOTS_GLITCHED" = STATION_TRAIT_BOTS_GLITCHED, + "STATION_TRAIT_BRIGHT_DAY" = STATION_TRAIT_BRIGHT_DAY, "STATION_TRAIT_CARP_INFESTATION" = STATION_TRAIT_CARP_INFESTATION, "STATION_TRAIT_CYBERNETIC_REVOLUTION" = STATION_TRAIT_CYBERNETIC_REVOLUTION, "STATION_TRAIT_EMPTY_MAINT" = STATION_TRAIT_EMPTY_MAINT, @@ -126,6 +127,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_ALWAYS_WANTED" = TRAIT_ALWAYS_WANTED, "TRAIT_ANALGESIA" = TRAIT_ANALGESIA, "TRAIT_ANGELIC" = TRAIT_ANGELIC, + "TRAIT_ANOSMIA" = TRAIT_ANOSMIA, "TRAIT_ANTENNAE" = TRAIT_ANTENNAE, "TRAIT_ANTICONVULSANT" = TRAIT_ANTICONVULSANT, "TRAIT_ANTIMAGIC" = TRAIT_ANTIMAGIC, @@ -134,6 +136,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BADDNA" = TRAIT_BADDNA, "TRAIT_BADTOUCH" = TRAIT_BADTOUCH, "TRAIT_BALD" = TRAIT_BALD, + "TRAIT_BALLOON_SUTRA" = TRAIT_BALLOON_SUTRA, "TRAIT_BATON_RESISTANCE" = TRAIT_BATON_RESISTANCE, "TRAIT_BEING_BLADE_SHIELDED" = TRAIT_BEING_BLADE_SHIELDED, "TRAIT_BLOB_ALLY" = TRAIT_BLOB_ALLY, @@ -201,6 +204,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_EMPATH" = TRAIT_EMPATH, "TRAIT_ENTRAILS_READER" = TRAIT_ENTRAILS_READER, "TRAIT_EXAMINE_FISHING_SPOT" = TRAIT_EXAMINE_FISHING_SPOT, + "TRAIT_EXAMINE_FITNESS" = TRAIT_EXAMINE_FITNESS, "TRAIT_EXPANDED_FOV" = TRAIT_EXPANDED_FOV, "TRAIT_EXTROVERT" = TRAIT_EXTROVERT, "TRAIT_FAKEDEATH" = TRAIT_FAKEDEATH, @@ -294,6 +298,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_MIND_TEMPORARILY_GONE" = TRAIT_MIND_TEMPORARILY_GONE, "TRAIT_MOB_BREEDER" = TRAIT_MOB_BREEDER, "TRAIT_MOB_EATER" = TRAIT_MOB_EATER, + "TRAIT_MOB_HATCHED" = TRAIT_MOB_HATCHED, + "TRAIT_MOB_RELAY_HAPPINESS" = TRAIT_MOB_RELAY_HAPPINESS, "TRAIT_MOB_TIPPED" = TRAIT_MOB_TIPPED, "TRAIT_MORBID" = TRAIT_MORBID, "TRAIT_MULTIZ_SUIT_SENSORS" = TRAIT_MULTIZ_SUIT_SENSORS, @@ -358,6 +364,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_OVERWATCHED" = TRAIT_OVERWATCHED, "TRAIT_OVERWATCH_IMMUNE" = TRAIT_OVERWATCH_IMMUNE, "TRAIT_PACIFISM" = TRAIT_PACIFISM, + "TRAIT_PAPER_MASTER" = TRAIT_PAPER_MASTER, "TRAIT_PARALYSIS_L_ARM" = TRAIT_PARALYSIS_L_ARM, "TRAIT_PARALYSIS_L_LEG" = TRAIT_PARALYSIS_L_LEG, "TRAIT_PARALYSIS_R_ARM" = TRAIT_PARALYSIS_R_ARM, @@ -413,7 +420,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SHIFTY_EYES" = TRAIT_SHIFTY_EYES, "TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE, "TRAIT_SIGN_LANG" = TRAIT_SIGN_LANG, - "TRAIT_PAPER_MASTER" = TRAIT_PAPER_MASTER, "TRAIT_SILENT_FOOTSTEPS" = TRAIT_SILENT_FOOTSTEPS, "TRAIT_SIXTHSENSE" = TRAIT_SIXTHSENSE, "TRAIT_SKITTISH" = TRAIT_SKITTISH, @@ -435,6 +441,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_STASIS" = TRAIT_STASIS, "TRAIT_STIMULATED" = TRAIT_STIMULATED, "TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER, + "TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH, "TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE, "TRAIT_SUCCUMB_OVERRIDE" = TRAIT_SUCCUMB_OVERRIDE, "TRAIT_SUICIDED" = TRAIT_SUICIDED, @@ -492,6 +499,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION, "TRAIT_DISCO_DANCER" = TRAIT_DISCO_DANCER, "TRAIT_MAFIAINITIATE" = TRAIT_MAFIAINITIATE, + "TRAIT_STRENGTH" = TRAIT_STRENGTH, + "TRAIT_STIMMED" = TRAIT_STIMMED, + "TRAIT_BOXING_READY" = TRAIT_BOXING_READY, ), /obj/item = list( "TRAIT_APC_SHOCKING" = TRAIT_APC_SHOCKING, @@ -597,6 +607,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( ), /turf = list( "TRAIT_CHASM_STOPPED" = TRAIT_CHASM_STOPPED, + "TRAIT_CONTAINMENT_FIELD" = TRAIT_CONTAINMENT_FIELD, "TRAIT_FIREDOOR_STOP" = TRAIT_FIREDOOR_STOP, "TRAIT_HYPERSPACE_STOPPED" = TRAIT_HYPERSPACE_STOPPED, "TRAIT_IMMERSE_STOPPED" = TRAIT_IMMERSE_STOPPED, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index d20c6a86fc03b..61ef99d124c19 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -29,6 +29,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_AGENDER" = TRAIT_AGENDER, "TRAIT_AGEUSIA" = TRAIT_AGEUSIA, "TRAIT_ALCOHOL_TOLERANCE" = TRAIT_ALCOHOL_TOLERANCE, + "TRAIT_ANOSMIA" = TRAIT_ANOSMIA, "TRAIT_ANTIMAGIC" = TRAIT_ANTIMAGIC, "TRAIT_ANXIOUS" = TRAIT_ANXIOUS, "TRAIT_BADDNA" = TRAIT_BADDNA, @@ -68,6 +69,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_EASYDISMEMBER" = TRAIT_EASYDISMEMBER, "TRAIT_EMOTEMUTE " = TRAIT_EMOTEMUTE, "TRAIT_EMPATH" = TRAIT_EMPATH, + "TRAIT_EXAMINE_FITNESS" = TRAIT_EXAMINE_FITNESS, "TRAIT_EXPANDED_FOV" = TRAIT_EXPANDED_FOV, "TRAIT_FAKEDEATH" = TRAIT_FAKEDEATH, "TRAIT_FAST_CUFFING" = TRAIT_FAST_CUFFING, @@ -159,6 +161,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_OIL_FRIED" = TRAIT_OIL_FRIED, "TRAIT_OVERWATCH_IMMUNE" = TRAIT_OVERWATCH_IMMUNE, "TRAIT_PACIFISM" = TRAIT_PACIFISM, + "TRAIT_PAPER_MASTER" = TRAIT_PAPER_MASTER, "TRAIT_PARALYSIS_L_ARM" = TRAIT_PARALYSIS_L_ARM, "TRAIT_PARALYSIS_L_LEG" = TRAIT_PARALYSIS_L_LEG, "TRAIT_PARALYSIS_R_ARM" = TRAIT_PARALYSIS_R_ARM, @@ -191,7 +194,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_SHIFTY_EYES" = TRAIT_SHIFTY_EYES, "TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE, "TRAIT_SIGN_LANG" = TRAIT_SIGN_LANG, - "TRAIT_PAPER_MASTER" = TRAIT_PAPER_MASTER, "TRAIT_SILENT_FOOTSTEPS" = TRAIT_SILENT_FOOTSTEPS, "TRAIT_SIXTHSENSE" = TRAIT_SIXTHSENSE, "TRAIT_SKITTISH" = TRAIT_SKITTISH, @@ -205,6 +207,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_STABLEHEART" = TRAIT_STABLEHEART, "TRAIT_STABLELIVER" = TRAIT_STABLELIVER, "TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER, + "TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH, "TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE, "TRAIT_SURGEON" = TRAIT_SURGEON, "TRAIT_SURGICALLY_ANALYZED" = TRAIT_SURGICALLY_ANALYZED, diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 8f95bdadda934..13b0e5c3c1335 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -55,7 +55,7 @@ ShiftClickOn(A) return if(LAZYACCESS(modifiers, ALT_CLICK)) // alt and alt-gr (rightalt) - AltClickOn(A) + ai_base_click_alt(A) return if(LAZYACCESS(modifiers, CTRL_CLICK)) CtrlClickOn(A) @@ -120,8 +120,24 @@ /mob/living/silicon/ai/CtrlClickOn(atom/target) target.AICtrlClick(src) -/mob/living/silicon/ai/AltClickOn(atom/target) - target.AIAltClick(src) + +/// Reimplementation of base_click_alt for AI +/mob/living/silicon/ai/proc/ai_base_click_alt(atom/target) + // If for some reason we can't alt click + if(SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON, target) & COMSIG_MOB_CANCEL_CLICKON) + return + + if(!isturf(target) && can_perform_action(target, (target.interaction_flags_click | SILENT_ADJACENCY))) + // Signal intercept + if(SEND_SIGNAL(target, COMSIG_CLICK_ALT, src) & CLICK_ACTION_ANY) + return + + // AI alt click interaction succeeds + if(target.ai_click_alt(src) & CLICK_ACTION_ANY) + return + + client.loot_panel.open(get_turf(target)) + /* The following criminally helpful code is just the previous code cleaned up; @@ -133,8 +149,8 @@ /atom/proc/AICtrlClick(mob/living/silicon/ai/user) return -/atom/proc/AIAltClick(mob/living/silicon/ai/user) - AltClick(user) +/atom/proc/ai_click_alt(mob/living/silicon/ai/user) + SHOULD_CALL_PARENT(FALSE) return /atom/proc/AIShiftClick(mob/living/silicon/ai/user) @@ -151,14 +167,15 @@ toggle_bolt(user) add_hiddenprint(user) -/obj/machinery/door/airlock/AIAltClick(mob/living/silicon/ai/user) // Eletrifies doors. +/obj/machinery/door/airlock/ai_click_alt(mob/living/silicon/ai/user) if(obj_flags & EMAGGED) - return + return NONE if(!secondsElectrified) shock_perm(user) else shock_restore(user) + return CLICK_ACTION_SUCCESS /obj/machinery/door/airlock/AIShiftClick(mob/living/silicon/ai/user) // Opens and closes doors! if(obj_flags & EMAGGED) @@ -220,12 +237,12 @@ update() /// Toggle APC equipment settings -/obj/machinery/power/apc/AIAltClick(mob/living/silicon/ai/user) +/obj/machinery/power/apc/ai_click_alt(mob/living/silicon/ai/user) if(!can_use(user, loud = TRUE)) - return + return NONE if(!is_operational || failure_timer) - return + return CLICK_ACTION_BLOCKING equipment = equipment ? APC_CHANNEL_OFF : APC_CHANNEL_ON if (user) @@ -235,6 +252,7 @@ user.log_message("turned [enabled_or_disabled] the [src] equipment settings", LOG_GAME) update_appearance() update() + return CLICK_ACTION_SUCCESS /obj/machinery/power/apc/attack_ai_secondary(mob/living/silicon/user, list/modifiers) if(!can_use(user, loud = TRUE)) @@ -244,10 +262,11 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /* AI Turrets */ -/obj/machinery/turretid/AIAltClick(mob/living/silicon/ai/user) //toggles lethal on turrets +/obj/machinery/turretid/ai_click_alt(mob/living/silicon/ai/user) //toggles lethal on turrets if(ailock) - return + return CLICK_ACTION_BLOCKING toggle_lethal(user) + return CLICK_ACTION_SUCCESS /obj/machinery/turretid/AICtrlClick(mob/living/silicon/ai/user) //turns off/on Turrets if(ailock) @@ -255,11 +274,12 @@ toggle_on(user) /* Holopads */ -/obj/machinery/holopad/AIAltClick(mob/living/silicon/ai/user) +/obj/machinery/holopad/ai_click_alt(mob/living/silicon/ai/user) if (user) balloon_alert(user, "disrupted all active calls") add_hiddenprint(user) hangup_all_calls() + return CLICK_ACTION_SUCCESS // // Override TurfAdjacent for AltClicking diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index cd06f0c2fd87f..3c99364542c5f 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -96,7 +96,7 @@ if(LAZYACCESS(modifiers, RIGHT_CLICK)) alt_click_on_secondary(A) else - AltClickOn(A) + base_click_alt(A) return if(LAZYACCESS(modifiers, CTRL_CLICK)) CtrlClickOn(A) @@ -341,6 +341,7 @@ return /atom/proc/ShiftClick(mob/user) + SEND_SIGNAL(src, COMSIG_SHIFT_CLICKED_ON, user) var/flags = SEND_SIGNAL(user, COMSIG_CLICK_SHIFT, src) if(flags & COMSIG_MOB_CANCEL_CLICKON) return @@ -385,24 +386,6 @@ A.CtrlClick(src) return -/** - * Alt click - * Unused except for AI - */ -/mob/proc/AltClickOn(atom/A) - . = SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON, A) - if(. & COMSIG_MOB_CANCEL_CLICKON) - return - A.AltClick(src) - -/atom/proc/AltClick(mob/user) - if(!user.can_interact_with(src)) - return FALSE - if(SEND_SIGNAL(src, COMSIG_CLICK_ALT, user) & COMPONENT_CANCEL_CLICK_ALT) - return - var/turf/T = get_turf(src) - if(T && (isturf(loc) || isturf(src)) && user.TurfAdjacent(T) && !HAS_TRAIT(user, TRAIT_MOVE_VENTCRAWLING)) - user.set_listed_turf(T) ///The base proc of when something is right clicked on when alt is held - generally use alt_click_secondary instead /atom/proc/alt_click_on_secondary(atom/A) @@ -421,14 +404,8 @@ user.client.toggle_tag_datum(src) return -/// Use this instead of [/mob/proc/AltClickOn] where you only want turf content listing without additional atom alt-click interaction -/atom/proc/AltClickNoInteract(mob/user, atom/A) - var/turf/T = get_turf(A) - if(T && user.TurfAdjacent(T)) - user.set_listed_turf(T) - -/mob/proc/TurfAdjacent(turf/T) - return T.Adjacent(src) +/mob/proc/TurfAdjacent(turf/tile) + return tile.Adjacent(src) /** * Control+Shift click diff --git a/code/_onclick/click_alt.dm b/code/_onclick/click_alt.dm new file mode 100644 index 0000000000000..11419a6081692 --- /dev/null +++ b/code/_onclick/click_alt.dm @@ -0,0 +1,70 @@ +/** + * ### Base proc for alt click interaction. + * + * If you wish to add custom `click_alt` behavior for a single type, use that proc. + */ +/mob/proc/base_click_alt(atom/target) + SHOULD_NOT_OVERRIDE(TRUE) + + // Check if they've hooked in to prevent src from alt clicking anything + if(SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON, target) & COMSIG_MOB_CANCEL_CLICKON) + return + + // Is it visible (and we're not wearing it (our clothes are invisible))? + if(!(src in viewers(7, target)) && !CanReach(target)) + return + + var/turf/tile = get_turf(target) + + // Ghosties just see loot + if(isobserver(src) || isrevenant(src)) + client.loot_panel.open(tile) + return + + // Turfs don't have a click_alt currently, so this saves some time. + if(!isturf(target) && can_perform_action(target, (target.interaction_flags_click | SILENT_ADJACENCY))) + // If it has a signal handler that returns a click action, done. + if(SEND_SIGNAL(target, COMSIG_CLICK_ALT, src) & CLICK_ACTION_ANY) + return + + // If it has a custom click_alt that returns success/block, done. + if(target.click_alt(src) & CLICK_ACTION_ANY) + return + + // No alt clicking to view turf from beneath + if(HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING)) + return + + client.loot_panel.open(tile) + + +/** + * ## Custom alt click interaction + * Override this to change default alt click behavior. Return `CLICK_ACTION_SUCCESS`, `CLICK_ACTION_BLOCKING` or `NONE`. + * + * ### Guard clauses + * Consider adding `interaction_flags_click` before adding unique guard clauses. + * + * ### Return flags + * Forgetting your return will cause the default alt click behavior to occur thereafter. + * + * The difference between NONE and BLOCKING can get hazy, but I like to keep NONE limited to guard clauses and "never" cases. + * + * A good usage for BLOCKING over NONE is when it's situational for the item and there's some feedback indicating this. + * + * ### Examples: + * User is a ghost, alt clicks on item with special disk eject: NONE + * + * Machine broken, no feedback: NONE + * + * Alt click a pipe to max output but its already max: BLOCKING + * + * Alt click a gun that normally works, but is out of ammo: BLOCKING + * + * User unauthorized, machine beeps: BLOCKING + * + * @param {mob} user - The person doing the alt clicking. + */ +/atom/proc/click_alt(mob/user) + SHOULD_CALL_PARENT(FALSE) + return NONE diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index b1b27c3400f42..b16d74550a96d 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -31,7 +31,7 @@ MiddleClickOn(A, params) return if(LAZYACCESS(modifiers, ALT_CLICK)) // alt and alt-gr (rightalt) - AltClickOn(A) + A.borg_click_alt(src) return if(LAZYACCESS(modifiers, CTRL_CLICK)) CtrlClickOn(A) @@ -89,7 +89,7 @@ if(after_attack_secondary_result == SECONDARY_ATTACK_CALL_NORMAL) W.afterattack(A, src, FALSE, params) - else + else W.afterattack(A, src, FALSE, params) //Give cyborgs hotkey clicks without breaking existing uses of hotkey clicks @@ -103,8 +103,6 @@ /mob/living/silicon/robot/CtrlClickOn(atom/target) target.BorgCtrlClick(src) -/mob/living/silicon/robot/AltClickOn(atom/target) - target.BorgAltClick(src) /atom/proc/BorgCtrlShiftClick(mob/living/silicon/robot/user) //forward to human click if not overridden CtrlShiftClick(user) @@ -152,9 +150,9 @@ else ..() -/obj/machinery/power/apc/BorgAltClick(mob/living/silicon/robot/user) +/obj/machinery/power/apc/borg_click_alt(mob/living/silicon/robot/user) if(get_dist(src, user) <= user.interaction_range && !(user.control_disabled)) - AIAltClick(user) + ai_click_alt(user) else ..() @@ -171,19 +169,19 @@ else ..() -/atom/proc/BorgAltClick(mob/living/silicon/robot/user) - AltClick(user) +/atom/proc/borg_click_alt(mob/living/silicon/robot/user) + user.base_click_alt(src) return -/obj/machinery/door/airlock/BorgAltClick(mob/living/silicon/robot/user) // Eletrifies doors. Forwards to AI code. +/obj/machinery/door/airlock/borg_click_alt(mob/living/silicon/robot/user) // Eletrifies doors. Forwards to AI code. if(get_dist(src, user) <= user.interaction_range && !(user.control_disabled)) - AIAltClick(user) + ai_click_alt(user) else ..() -/obj/machinery/turretid/BorgAltClick(mob/living/silicon/robot/user) //turret lethal on/off. Forwards to AI code. +/obj/machinery/turretid/borg_click_alt(mob/living/silicon/robot/user) //turret lethal on/off. Forwards to AI code. if(get_dist(src, user) <= user.interaction_range && !(user.control_disabled)) - AIAltClick(user) + ai_click_alt(user) else ..() diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index ac10680db27bc..2cfa8147c490f 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -301,12 +301,25 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /// The offer we're linked to, yes this is suspiciously like a status effect alert var/datum/status_effect/offering/offer /// Additional text displayed in the description of the alert. - var/additional_desc_text = "Click this alert to take it." + var/additional_desc_text = "Click this alert to take it, or shift click it to examiante it." + /// Text to override what appears in screentips for the alert + var/screentip_override_text + /// Whether the offered item can be examined by shift-clicking the alert + var/examinable = TRUE + +/atom/movable/screen/alert/give/Initialize(mapload, datum/hud/hud_owner) + . = ..() + register_context() /atom/movable/screen/alert/give/Destroy() offer = null return ..() +/atom/movable/screen/alert/give/add_context(atom/source, list/context, obj/item/held_item, mob/user) + context[SCREENTIP_CONTEXT_LMB] = screentip_override_text || "Take [offer.offered_item.name]" + context[SCREENTIP_CONTEXT_SHIFT_LMB] = "Examine" + return CONTEXTUAL_SCREENTIP_SET + /** * Handles assigning most of the variables for the alert that pops up when an item is offered * @@ -357,6 +370,16 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." handle_transfer() +/atom/movable/screen/alert/give/examine(mob/user) + if(!examinable) + return ..() + + return list( + span_boldnotice(name), + span_info("[offer.owner] is offering you the following item (click the alert to take it!):"), + "
[jointext(offer.offered_item.examine(user), "\n")]", + ) + /// An overrideable proc used simply to hand over the item when claimed, this is a proc so that high-fives can override them since nothing is actually transferred /atom/movable/screen/alert/give/proc/handle_transfer() var/mob/living/carbon/taker = owner @@ -367,6 +390,8 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /atom/movable/screen/alert/give/highfive additional_desc_text = "Click this alert to slap it." + screentip_override_text = "High Five" + examinable = FALSE /// Tracks active "to slow"ing so we can't spam click var/too_slowing_this_guy = FALSE @@ -425,6 +450,10 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." if(QDELETED(offer.offered_item)) examine_list += span_warning("[source]'s arm appears tensed up, as if [source.p_they()] plan on pulling it back suddenly...") +/atom/movable/screen/alert/give/hand + screentip_override_text = "Take Hand" + examinable = FALSE + /atom/movable/screen/alert/give/hand/get_receiving_name(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving) additional_desc_text = "Click this alert to take it and let [offerer.p_them()] pull you around!" return "[offerer.p_their()] [receiving.name]" @@ -1057,7 +1086,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." return FALSE var/list/modifiers = params2list(params) if(LAZYACCESS(modifiers, SHIFT_CLICK)) // screen objects don't do the normal Click() stuff so we'll cheat - to_chat(usr, span_boldnotice("[name] - [desc]")) + to_chat(usr, examine_block(jointext(examine(usr), "\n"))) return FALSE var/datum/our_master = master_ref?.resolve() if(our_master && click_master) @@ -1071,3 +1100,9 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." master_ref = null owner = null screen_loc = "" + +/atom/movable/screen/alert/examine(mob/user) + return list( + span_boldnotice(name), + span_info(desc), + ) diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm index 64ad896d57a1f..aac5a2b75ccaa 100644 --- a/code/_onclick/hud/generic_dextrous.dm +++ b/code/_onclick/hud/generic_dextrous.dm @@ -43,6 +43,9 @@ using.icon = ui_style static_inventory += using + healthdoll = new /atom/movable/screen/healthdoll/living(null, src) + infodisplay += healthdoll + mymob.canon_client?.clear_screen() for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm index b1f40f7629442..e0a6c6873bd5a 100644 --- a/code/_onclick/hud/movable_screen_objects.dm +++ b/code/_onclick/hud/movable_screen_objects.dm @@ -44,40 +44,30 @@ offset[2] += y_off return offset_to_screen_loc(offset[1], offset[2], our_client?.view) -//Debug procs -/client/proc/test_movable_UI() - set category = "Debug" - set name = "Spawn Movable UI Object" - - var/atom/movable/screen/movable/M = new() +ADMIN_VERB(test_movable_UI, R_DEBUG, "Spawn Movable UI Object", "Spawn a movable UI object for testing.", ADMIN_CATEGORY_DEBUG) + var/atom/movable/screen/movable/M = new M.name = "Movable UI Object" M.icon_state = "block" M.maptext = MAPTEXT("Movable") M.maptext_width = 64 - var/screen_l = input(usr,"Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Movable UI Object") as text|null + var/screen_l = input(user, "Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Movable UI Object") as text|null if(!screen_l) return M.screen_loc = screen_l + user.screen += M - screen += M - - -/client/proc/test_snap_UI() - set category = "Debug" - set name = "Spawn Snap UI Object" - - var/atom/movable/screen/movable/snap/S = new() +ADMIN_VERB(test_snap_ui, R_DEBUG, "Spawn Snap UI Object", "Spawn a snap UI object for testing.", ADMIN_CATEGORY_DEBUG) + var/atom/movable/screen/movable/snap/S = new S.name = "Snap UI Object" S.icon_state = "block" S.maptext = MAPTEXT("Snap") S.maptext_width = 64 - var/screen_l = input(usr,"Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Snap UI Object") as text|null + var/screen_l = input(user,"Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Snap UI Object") as text|null if(!screen_l) return S.screen_loc = screen_l - - screen += S + user.screen += S diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 25984a04aa7b4..95622a7c60a72 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -11,7 +11,7 @@ var/list/modifiers = params2list(params) var/is_right_clicking = LAZYACCESS(modifiers, RIGHT_CLICK) - var/item_interact_result = target.item_interaction(user, src, modifiers, is_right_clicking) + var/item_interact_result = target.base_item_interaction(user, src, modifiers) if(item_interact_result & ITEM_INTERACT_SUCCESS) return TRUE if(item_interact_result & ITEM_INTERACT_BLOCKING) @@ -52,10 +52,6 @@ if (attackby_result) return TRUE - if(QDELETED(src) || QDELETED(target)) - attack_qdeleted(target, user, TRUE, params) - return TRUE - if (is_right_clicking) var/after_attack_secondary_result = afterattack_secondary(target, user, TRUE, params) @@ -163,7 +159,7 @@ return FALSE return attacking_item.attack_atom(src, user, params) -/mob/living/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/mob/living/item_interaction(mob/living/user, obj/item/tool, list/modifiers) // Surgery and such happens very high up in the interaction chain, before parent call var/attempt_tending = item_tending(user, tool, modifiers) if(attempt_tending & ITEM_INTERACT_ANY_BLOCKER) @@ -240,6 +236,8 @@ user.do_attack_animation(target_mob) target_mob.attacked_by(src, user) + SEND_SIGNAL(src, COMSIG_ITEM_POST_ATTACK, target_mob, user, params) + log_combat(user, target_mob, "attacked", src.name, "(COMBAT MODE: [uppertext(user.combat_mode)]) (DAMTYPE: [uppertext(damtype)])") add_fingerprint(user) @@ -291,7 +289,7 @@ if(body_position == LYING_DOWN) zone_hit_chance += 10 targeting = get_random_valid_zone(targeting, zone_hit_chance) - var/targeting_human_readable = parse_zone(targeting) + var/targeting_human_readable = parse_zone_with_bodypart(targeting) send_item_attack_message(attacking_item, user, targeting_human_readable, targeting) @@ -391,7 +389,7 @@ glasses.add_mob_blood(src) update_worn_glasses() - if(!attacking_item.get_sharpness() && !HAS_TRAIT(src, TRAIT_HEAD_INJURY_BLOCKED)) + if(!attacking_item.get_sharpness() && !HAS_TRAIT(src, TRAIT_HEAD_INJURY_BLOCKED) && attacking_item.damtype == BRUTE) if(prob(damage_done)) adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) if(stat == CONSCIOUS) @@ -421,7 +419,7 @@ w_uniform.add_mob_blood(src) update_worn_undersuit() - if(stat == CONSCIOUS && !attacking_item.get_sharpness() && !HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) + if(stat == CONSCIOUS && !attacking_item.get_sharpness() && !HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED) && attacking_item.damtype == BRUTE) if(prob(damage_done)) visible_message( span_danger("[src] is knocked down!"), @@ -472,11 +470,6 @@ return SECONDARY_ATTACK_CALL_NORMAL -/// Called if the target gets deleted by our attack -/obj/item/proc/attack_qdeleted(atom/target, mob/user, proximity_flag, click_parameters) - SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_QDELETED, target, user, proximity_flag, click_parameters) - SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_QDELETED, target, user, proximity_flag, click_parameters) - /obj/item/proc/get_clamped_volume() if(w_class) if(force) diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 1cdb99bbb42af..ae2ebd976321d 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -9,7 +9,6 @@ // Otherwise jump else if(A.loc) abstract_move(get_turf(A)) - update_parallax_contents() /mob/dead/observer/ClickOn(atom/A, params) if(check_click_intercept(params,A)) @@ -32,7 +31,7 @@ MiddleClickOn(A, params) return if(LAZYACCESS(modifiers, ALT_CLICK)) - AltClickNoInteract(src, A) + base_click_alt(A) return if(LAZYACCESS(modifiers, CTRL_CLICK)) CtrlClickOn(A) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index f46ab02433ddc..0dd8ee0a582f6 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -187,7 +187,8 @@ ///When a basic mob attacks something, either by AI or user. /atom/proc/attack_basic_mob(mob/user, list/modifiers) SHOULD_CALL_PARENT(TRUE) - SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_BASIC_MOB, user) + if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_BASIC_MOB, user) & COMSIG_BASIC_ATTACK_CANCEL_CHAIN) + return return handle_basic_attack(user, modifiers) //return value of attack animal, this is how much damage was dealt to the attacked thing ///This exists so stuff can override the default call of attack_animal for attack_basic_mob diff --git a/code/_onclick/overmind.dm b/code/_onclick/overmind.dm index d6b8994f82f07..900ad59bde2e4 100644 --- a/code/_onclick/overmind.dm +++ b/code/_onclick/overmind.dm @@ -10,7 +10,7 @@ ShiftClickOn(A) return if(LAZYACCESS(modifiers, ALT_CLICK)) - AltClickOn(A) + blob_click_alt(A) return if(LAZYACCESS(modifiers, CTRL_CLICK)) CtrlClickOn(A) @@ -30,7 +30,7 @@ if(T) create_shield(T) -/mob/camera/blob/AltClickOn(atom/A) //Remove a blob +/mob/camera/blob/proc/blob_click_alt(atom/A) //Remove a blob var/turf/T = get_turf(A) if(T) remove_blob(T) diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm index 421712d5ad454..5056e3804ef11 100644 --- a/code/controllers/admin.dm +++ b/code/controllers/admin.dm @@ -44,15 +44,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) usr.client.debug_variables(target) message_admins("Admin [key_name_admin(usr)] is debugging the [target] [class].") - -// Debug verbs. -/client/proc/restart_controller(controller in list("Master", "Failsafe")) - set category = "Debug" - set name = "Restart Controller" - set desc = "Restart one of the various periodic loop controllers for the game (be careful!)" - - if(!holder) - return +ADMIN_VERB(restart_controller, R_DEBUG, "Restart Controller", "Restart one of the various periodic loop controllers for the game (be careful!)", ADMIN_CATEGORY_DEBUG, controller in list("Master", "Failsafe")) switch(controller) if("Master") Recreate_MC() @@ -61,16 +53,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) new /datum/controller/failsafe() BLACKBOX_LOG_ADMIN_VERB("Restart Failsafe Controller") - message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.") - -/client/proc/debug_controller() - set category = "Debug" - set name = "Debug Controller" - set desc = "Debug the various periodic loop controllers for the game (be careful!)" - - if(!holder) - return + message_admins("Admin [key_name_admin(user)] has restarted the [controller] controller.") +ADMIN_VERB(debug_controller, R_DEBUG, "Debug Controller", "Debug the various periodic loop controllers for the game (be careful!)", ADMIN_CATEGORY_DEBUG) var/list/controllers = list() var/list/controller_choices = list() @@ -85,7 +70,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) if (!istype(controller)) return - debug_variables(controller) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/debug_variables, controller) BLACKBOX_LOG_ADMIN_VERB("Debug Controller") - message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") + message_admins("Admin [key_name_admin(user)] is debugging the [controller] controller.") diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index fb1cf4bf5a6a8..7f28c361267f1 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -25,7 +25,7 @@ /datum/config_entry/New() if(type == abstract_type) CRASH("Abstract config entry [type] instatiated!") - name = lowertext(type2top(type)) + name = LOWER_TEXT(type2top(type)) default_protection = protection set_default() @@ -100,7 +100,7 @@ return FALSE config_entry_value = auto_trim ? trim(str_val) : str_val if(lowercase) - config_entry_value = lowertext(config_entry_value) + config_entry_value = LOWER_TEXT(config_entry_value) return TRUE /datum/config_entry/number @@ -148,7 +148,7 @@ return FALSE str_val = trim(str_val) if (str_val != "") - config_entry_value += lowercase ? lowertext(str_val) : str_val + config_entry_value += lowercase ? LOWER_TEXT(str_val) : str_val return TRUE /datum/config_entry/number_list @@ -246,7 +246,7 @@ config_key = jointext(config_entry_words, splitter) if(lowercase_key) - config_key = lowertext(config_key) + config_key = LOWER_TEXT(config_key) is_ambiguous = (length(config_entry_words) > 2) diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 830f15ae559d2..b7f48fcab5e4a 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -165,7 +165,7 @@ if(IsAdminAdvancedProcCall()) return - var/filename_to_test = world.system_type == MS_WINDOWS ? lowertext(filename) : filename + var/filename_to_test = world.system_type == MS_WINDOWS ? LOWER_TEXT(filename) : filename if(filename_to_test in stack) log_config_error("Warning: Config recursion detected ([english_list(stack)]), breaking!") return @@ -192,10 +192,10 @@ var/value = null if(pos) - entry = lowertext(copytext(L, 1, pos)) + entry = LOWER_TEXT(copytext(L, 1, pos)) value = copytext(L, pos + length(L[pos])) else - entry = lowertext(L) + entry = LOWER_TEXT(L) if(!entry) continue @@ -210,7 +210,7 @@ // Reset directive, used for setting a config value back to defaults. Useful for string list config types if (entry == "$reset") - var/datum/config_entry/resetee = _entries[lowertext(value)] + var/datum/config_entry/resetee = _entries[LOWER_TEXT(value)] if (!value || !resetee) log_config_error("Warning: invalid $reset directive: [value]") continue @@ -364,10 +364,10 @@ Example config: var/data = null if(pos) - command = lowertext(copytext(t, 1, pos)) + command = LOWER_TEXT(copytext(t, 1, pos)) data = copytext(t, pos + length(t[pos])) else - command = lowertext(t) + command = LOWER_TEXT(t) if(!command) continue @@ -471,7 +471,7 @@ Example config: var/list/formatted_banned_words = list() for (var/banned_word in banned_words) - formatted_banned_words[lowertext(banned_word)] = banned_words[banned_word] + formatted_banned_words[LOWER_TEXT(banned_word)] = banned_words[banned_word] return formatted_banned_words /datum/controller/configuration/proc/compile_filter_regex(list/banned_words) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 368ae3a384035..068f857c8cb31 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -347,6 +347,16 @@ min_val = 0 integer = FALSE +/datum/config_entry/number/events_frequency_lower + default = 2.5 MINUTES + min_val = 0 + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/number/events_frequency_upper + default = 7 MINUTES + min_val = 0 + protection = CONFIG_ENTRY_LOCKED + /datum/config_entry/number/mice_roundstart default = 10 min_val = 0 diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 05226ae6b9418..69b3bbcad64f6 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -184,13 +184,13 @@ /// minimum time between voting sessions (deciseconds, 10 minute default) /datum/config_entry/number/vote_delay - default = 6000 + default = 10 MINUTES integer = FALSE min_val = 0 /// length of voting period (deciseconds, default 1 minute) /datum/config_entry/number/vote_period - default = 600 + default = 1 MINUTES integer = FALSE min_val = 0 @@ -447,10 +447,13 @@ /datum/config_entry/flag/irc_first_connection_alert // do we notify the irc channel when somebody is connecting for the first time? +/datum/config_entry/string/ipintel_base + default = "check.getipintel.net" + /datum/config_entry/string/ipintel_email /datum/config_entry/string/ipintel_email/ValidateAndSet(str_val) - return str_val != "ch@nge.me" && ..() + return str_val != "ch@nge.me" && (!length(str_val) || findtext(str_val, "@")) && ..() /datum/config_entry/number/ipintel_rating_bad default = 1 @@ -458,18 +461,26 @@ min_val = 0 max_val = 1 -/datum/config_entry/number/ipintel_save_good - default = 12 - integer = FALSE +/datum/config_entry/flag/ipintel_reject_rate_limited + default = FALSE + +/datum/config_entry/flag/ipintel_reject_bad + default = FALSE + +/datum/config_entry/flag/ipintel_reject_unknown + default = FALSE + +/datum/config_entry/number/ipintel_rate_minute + default = 15 min_val = 0 -/datum/config_entry/number/ipintel_save_bad - default = 1 - integer = FALSE +/datum/config_entry/number/ipintel_cache_length + default = 7 min_val = 0 -/datum/config_entry/string/ipintel_domain - default = "check.getipintel.net" +/datum/config_entry/number/ipintel_exempt_playtime_living + default = 5 + min_val = 0 /datum/config_entry/flag/aggressive_changelog diff --git a/code/controllers/configuration/entries/resources.dm b/code/controllers/configuration/entries/resources.dm index c839ccc078d4d..1fb8a6237d45c 100644 --- a/code/controllers/configuration/entries/resources.dm +++ b/code/controllers/configuration/entries/resources.dm @@ -6,7 +6,7 @@ /datum/config_entry/string/asset_transport /datum/config_entry/string/asset_transport/ValidateAndSet(str_val) - return (lowertext(str_val) in list("simple", "webroot")) && ..(lowertext(str_val)) + return (LOWER_TEXT(str_val) in list("simple", "webroot")) && ..(LOWER_TEXT(str_val)) /datum/config_entry/string/asset_cdn_webroot protection = CONFIG_ENTRY_LOCKED diff --git a/code/controllers/master.dm b/code/controllers/master.dm index ac12add1ae2d5..a7dbc38f68bcd 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -76,6 +76,9 @@ GLOBAL_REAL(Master, /datum/controller/master) ///used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits var/static/current_ticklimit = TICK_LIMIT_RUNNING + /// Whether the Overview UI will update as fast as possible for viewers. + var/overview_fast_update = FALSE + /datum/controller/master/New() if(!config) config = new @@ -135,6 +138,78 @@ GLOBAL_REAL(Master, /datum/controller/master) ss.Shutdown() log_world("Shutdown complete") +ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "View the current states of the Subsystem Controllers.", ADMIN_CATEGORY_DEBUG) + Master.ui_interact(user.mob) + +/datum/controller/master/ui_status(mob/user, datum/ui_state/state) + if(!user.client?.holder?.check_for_rights(R_SERVER|R_DEBUG)) + return UI_CLOSE + return UI_INTERACTIVE + +/datum/controller/master/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(isnull(ui)) + ui = new /datum/tgui(user, src, "ControllerOverview") + ui.open() + +/datum/controller/master/ui_data(mob/user) + var/list/data = list() + + var/list/subsystem_data = list() + for(var/datum/controller/subsystem/subsystem as anything in subsystems) + subsystem_data += list(list( + "name" = subsystem.name, + "ref" = REF(subsystem), + "init_order" = subsystem.init_order, + "last_fire" = subsystem.last_fire, + "next_fire" = subsystem.next_fire, + "can_fire" = subsystem.can_fire, + "doesnt_fire" = !!(subsystem.flags & SS_NO_FIRE), + "cost_ms" = subsystem.cost, + "tick_usage" = subsystem.tick_usage, + "tick_overrun" = subsystem.tick_overrun, + "initialized" = subsystem.initialized, + "initialization_failure_message" = subsystem.initialization_failure_message, + )) + data["subsystems"] = subsystem_data + data["world_time"] = world.time + data["map_cpu"] = world.map_cpu + data["fast_update"] = overview_fast_update + + return data + +/datum/controller/master/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE + + switch(action) + if("toggle_fast_update") + overview_fast_update = !overview_fast_update + return TRUE + + if("view_variables") + var/datum/controller/subsystem/subsystem = locate(params["ref"]) in subsystems + if(isnull(subsystem)) + to_chat(ui.user, span_warning("Failed to locate subsystem.")) + return + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/debug_variables, subsystem) + return TRUE + +/datum/controller/master/proc/check_and_perform_fast_update() + PRIVATE_PROC(TRUE) + set waitfor = FALSE + + + if(!overview_fast_update) + return + + var/static/already_updating = FALSE + if(already_updating) + return + already_updating = TRUE + SStgui.update_uis(src) + already_updating = FALSE + // Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart, // -1 if we encountered a runtime trying to recreate it /proc/Recreate_MC() @@ -578,11 +653,9 @@ GLOBAL_REAL(Master, /datum/controller/master) if (processing * sleep_delta <= world.tick_lag) current_ticklimit -= (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc if we plan on running next tick + check_and_perform_fast_update() sleep(world.tick_lag * (processing * sleep_delta)) - - - // This is what decides if something should run. /datum/controller/master/proc/CheckQueue(list/subsystemstocheck) . = 0 //so the mc knows if we runtimed diff --git a/code/controllers/subsystem/admin_verbs.dm b/code/controllers/subsystem/admin_verbs.dm new file mode 100644 index 0000000000000..9496b95d998a9 --- /dev/null +++ b/code/controllers/subsystem/admin_verbs.dm @@ -0,0 +1,150 @@ +GENERAL_PROTECT_DATUM(/datum/controller/subsystem/admin_verbs) + +SUBSYSTEM_DEF(admin_verbs) + name = "Admin Verbs" + flags = SS_NO_FIRE + init_order = INIT_ORDER_ADMIN_VERBS + /// A list of all admin verbs indexed by their type. + var/list/datum/admin_verb/admin_verbs_by_type = list() + /// A list of all admin verbs indexed by their visibility flag. + var/list/list/datum/admin_verb/admin_verbs_by_visibility_flag = list() + /// A map of all assosciated admins and their visibility flags. + var/list/admin_visibility_flags = list() + /// A list of all admins that are pending initialization of this SS. + var/list/admins_pending_subsytem_init = list() + +/datum/controller/subsystem/admin_verbs/Initialize() + setup_verb_list() + process_pending_admins() + return SS_INIT_SUCCESS + +/datum/controller/subsystem/admin_verbs/Recover() + admin_verbs_by_type = SSadmin_verbs.admin_verbs_by_type + +/datum/controller/subsystem/admin_verbs/stat_entry(msg) + return "[..()] | V: [length(admin_verbs_by_type)]" + +/datum/controller/subsystem/admin_verbs/proc/process_pending_admins() + var/list/pending_admins = admins_pending_subsytem_init + admins_pending_subsytem_init = null + for(var/admin_ckey in pending_admins) + assosciate_admin(GLOB.directory[admin_ckey]) + +/datum/controller/subsystem/admin_verbs/proc/setup_verb_list() + if(length(admin_verbs_by_type)) + CRASH("Attempting to setup admin verbs twice!") + for(var/datum/admin_verb/verb_type as anything in subtypesof(/datum/admin_verb)) + var/datum/admin_verb/verb_singleton = new verb_type + if(!verb_singleton.__avd_check_should_exist()) + qdel(verb_singleton, force = TRUE) + continue + + admin_verbs_by_type[verb_type] = verb_singleton + if(verb_singleton.visibility_flag) + if(!(verb_singleton.visibility_flag in admin_verbs_by_visibility_flag)) + admin_verbs_by_visibility_flag[verb_singleton.visibility_flag] = list() + admin_verbs_by_visibility_flag[verb_singleton.visibility_flag] |= list(verb_singleton) + +/datum/controller/subsystem/admin_verbs/proc/get_valid_verbs_for_admin(client/admin) + if(isnull(admin.holder)) + CRASH("Why are we checking a non-admin for their valid... ahem... admin verbs?") + + var/list/has_permission = list() + for(var/permission_flag in GLOB.bitflags) + if(admin.holder.check_for_rights(permission_flag)) + has_permission["[permission_flag]"] = TRUE + + var/list/valid_verbs = list() + for(var/datum/admin_verb/verb_type as anything in admin_verbs_by_type) + var/datum/admin_verb/verb_singleton = admin_verbs_by_type[verb_type] + if(!verify_visibility(admin, verb_singleton)) + continue + + var/verb_permissions = verb_singleton.permissions + if(verb_permissions == R_NONE) + valid_verbs |= list(verb_singleton) + else for(var/permission_flag in bitfield_to_list(verb_permissions)) + if(!has_permission["[permission_flag]"]) + continue + valid_verbs |= list(verb_singleton) + + return valid_verbs + +/datum/controller/subsystem/admin_verbs/proc/verify_visibility(client/admin, datum/admin_verb/verb_singleton) + var/needed_flag = verb_singleton.visibility_flag + return !needed_flag || (needed_flag in admin_visibility_flags[admin.ckey]) + +/datum/controller/subsystem/admin_verbs/proc/update_visibility_flag(client/admin, flag, state) + if(state) + admin_visibility_flags[admin.ckey] |= list(flag) + assosciate_admin(admin) + return + + admin_visibility_flags[admin.ckey] -= list(flag) + // they lost the flag, iterate over verbs with that flag and yoink em + for(var/datum/admin_verb/verb_singleton as anything in admin_verbs_by_visibility_flag[flag]) + verb_singleton.unassign_from_client(admin) + admin.init_verbs() + +/datum/controller/subsystem/admin_verbs/proc/dynamic_invoke_verb(client/admin, datum/admin_verb/verb_type, ...) + if(IsAdminAdvancedProcCall()) + message_admins("PERMISSION ELEVATION: [key_name_admin(admin)] attempted to dynamically invoke admin verb '[verb_type]'.") + return + + if(ismob(admin)) + var/mob/mob = admin + admin = mob.client + + if(!ispath(verb_type, /datum/admin_verb) || verb_type == /datum/admin_verb) + CRASH("Attempted to dynamically invoke admin verb with invalid typepath '[verb_type]'.") + if(isnull(admin.holder)) + CRASH("Attempted to dynamically invoke admin verb '[verb_type]' with a non-admin.") + + var/list/verb_args = args.Copy() + verb_args.Cut(2, 3) + var/datum/admin_verb/verb_singleton = admin_verbs_by_type[verb_type] // this cannot be typed because we need to use `:` + if(isnull(verb_singleton)) + CRASH("Attempted to dynamically invoke admin verb '[verb_type]' that doesn't exist.") + + if(!admin.holder.check_for_rights(verb_singleton.permissions)) + to_chat(admin, span_adminnotice("You lack the permissions to do this.")) + return + + var/old_usr = usr + usr = admin.mob + // THE MACRO ENSURES THIS EXISTS. IF IT EVER DOESNT EXIST SOMEONE DIDNT USE THE DAMN MACRO! + verb_singleton.__avd_do_verb(arglist(verb_args)) + usr = old_usr + SSblackbox.record_feedback("tally", "dynamic_admin_verb_invocation", 1, "[verb_type]") + +/** + * Assosciates and/or resyncs an admin with their accessible admin verbs. + */ +/datum/controller/subsystem/admin_verbs/proc/assosciate_admin(client/admin) + if(IsAdminAdvancedProcCall()) + return + + if(!isnull(admins_pending_subsytem_init)) // if the list exists we are still initializing + to_chat(admin, span_big(span_green("Admin Verbs are still initializing. Please wait and you will be automatically assigned your verbs when it is complete."))) + admins_pending_subsytem_init |= list(admin.ckey) + return + + // refresh their verbs + admin_visibility_flags[admin.ckey] ||= list() + for(var/datum/admin_verb/verb_singleton as anything in get_valid_verbs_for_admin(admin)) + verb_singleton.assign_to_client(admin) + admin.init_verbs() + +/** + * Unassosciates an admin from their admin verbs. + * Goes over all admin verbs because we don't know which ones are assigned to the admin's mob without a bunch of extra bookkeeping. + * This might be a performance issue in the future if we have a lot of admin verbs. + */ +/datum/controller/subsystem/admin_verbs/proc/deassosciate_admin(client/admin) + if(IsAdminAdvancedProcCall()) + return + + UnregisterSignal(admin, COMSIG_CLIENT_MOB_LOGIN) + for(var/datum/admin_verb/verb_type as anything in admin_verbs_by_type) + admin_verbs_by_type[verb_type].unassign_from_client(admin) + admin_visibility_flags -= list(admin.ckey) diff --git a/code/controllers/subsystem/ai_controllers.dm b/code/controllers/subsystem/ai_controllers.dm index 3d8d26531497c..a6badb44a3f0e 100644 --- a/code/controllers/subsystem/ai_controllers.dm +++ b/code/controllers/subsystem/ai_controllers.dm @@ -3,27 +3,43 @@ SUBSYSTEM_DEF(ai_controllers) name = "AI Controller Ticker" flags = SS_POST_FIRE_TIMING|SS_BACKGROUND priority = FIRE_PRIORITY_NPC - runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME init_order = INIT_ORDER_AI_CONTROLLERS wait = 0.5 SECONDS //Plan every half second if required, not great not terrible. + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME ///List of all ai_subtree singletons, key is the typepath while assigned value is a newly created instance of the typepath. See setup_subtrees() - var/list/ai_subtrees = list() - ///List of all ai controllers currently running - var/list/active_ai_controllers = list() + var/list/datum/ai_planning_subtree/ai_subtrees = list() + ///Assoc List of all AI statuses and all AI controllers with that status. + var/list/ai_controllers_by_status = list( + AI_STATUS_ON = list(), + AI_STATUS_OFF = list(), + AI_STATUS_IDLE = list(), + ) + ///Assoc List of all AI controllers and the Z level they are on, which we check when someone enters/leaves a Z level to turn them on/off. + var/list/ai_controllers_by_zlevel = list() + /// The tick cost of all active AI, calculated on fire. + var/cost_on + /// The tick cost of all idle AI, calculated on fire. + var/cost_idle + /datum/controller/subsystem/ai_controllers/Initialize() setup_subtrees() return SS_INIT_SUCCESS -/datum/controller/subsystem/ai_controllers/proc/setup_subtrees() - ai_subtrees = list() - for(var/subtree_type in subtypesof(/datum/ai_planning_subtree)) - var/datum/ai_planning_subtree/subtree = new subtree_type - ai_subtrees[subtree_type] = subtree +/datum/controller/subsystem/ai_controllers/stat_entry(msg) + var/list/active_list = ai_controllers_by_status[AI_STATUS_ON] + var/list/inactive_list = ai_controllers_by_status[AI_STATUS_OFF] + var/list/idle_list = ai_controllers_by_status[AI_STATUS_IDLE] + msg = "Active AIs:[length(active_list)]/[round(cost_on,1)]%|Inactive:[length(inactive_list)]|Idle:[length(idle_list)]/[round(cost_idle,1)]%" + return ..() /datum/controller/subsystem/ai_controllers/fire(resumed) - for(var/datum/ai_controller/ai_controller as anything in active_ai_controllers) + var/timer = TICK_USAGE_REAL + cost_idle = MC_AVERAGE(cost_idle, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + + timer = TICK_USAGE_REAL + for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_ON]) if(!COOLDOWN_FINISHED(ai_controller, failed_planning_cooldown)) continue @@ -32,3 +48,19 @@ SUBSYSTEM_DEF(ai_controllers) ai_controller.SelectBehaviors(wait * 0.1) if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN) + + cost_on = MC_AVERAGE(cost_on, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + +///Creates all instances of ai_subtrees and assigns them to the ai_subtrees list. +/datum/controller/subsystem/ai_controllers/proc/setup_subtrees() + for(var/subtree_type in subtypesof(/datum/ai_planning_subtree)) + var/datum/ai_planning_subtree/subtree = new subtree_type + ai_subtrees[subtree_type] = subtree + +///Called when the max Z level was changed, updating our coverage. +/datum/controller/subsystem/ai_controllers/proc/on_max_z_changed() + if (!islist(ai_controllers_by_zlevel)) + ai_controllers_by_zlevel = new /list(world.maxz,0) + while (SSai_controllers.ai_controllers_by_zlevel.len < world.maxz) + SSai_controllers.ai_controllers_by_zlevel.len++ + SSai_controllers.ai_controllers_by_zlevel[ai_controllers_by_zlevel.len] = list() diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 1de3f900c8ca0..1cb3e2dec3783 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -898,7 +898,6 @@ GLOBAL_LIST_EMPTY(colored_images) if(!target) return usr.forceMove(target) - usr.update_parallax_contents() if("toggle-freeze") can_fire = !can_fire return TRUE diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index 8c5fd154805aa..bb4f3802d89b1 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -46,11 +46,10 @@ SUBSYSTEM_DEF(blackbox) var/admincount = GLOB.admins.len var/datum/db_query/query_record_playercount = SSdbcore.NewQuery({" INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port, round_id) - VALUES (:playercount, :admincount, :time, INET_ATON(:server_ip), :server_port, :round_id) + VALUES (:playercount, :admincount, NOW(), INET_ATON(:server_ip), :server_port, :round_id) "}, list( "playercount" = playercount, "admincount" = admincount, - "time" = SQLtime(), "server_ip" = world.internet_address || "0", "server_port" = "[world.port]", "round_id" = GLOB.round_id, @@ -298,7 +297,7 @@ Versioning var/datum/db_query/query_log_ahelp = SSdbcore.NewQuery({" INSERT INTO [format_table_name("ticket")] (ticket, action, message, recipient, sender, server_ip, server_port, round_id, timestamp, urgent) - VALUES (:ticket, :action, :message, :recipient, :sender, INET_ATON(:server_ip), :server_port, :round_id, :time, :urgent) + VALUES (:ticket, :action, :message, :recipient, :sender, INET_ATON(:server_ip), :server_port, :round_id, NOW(), :urgent) "}, list( "ticket" = ticket, "action" = action, @@ -308,7 +307,6 @@ Versioning "server_ip" = world.internet_address || "0", "server_port" = world.port, "round_id" = GLOB.round_id, - "time" = SQLtime(), "urgent" = urgent, )) query_log_ahelp.Execute() @@ -337,7 +335,7 @@ Versioning var/datum/db_query/query_report_death = SSdbcore.NewQuery({" INSERT INTO [format_table_name("death")] (pod, x_coord, y_coord, z_coord, mapname, server_ip, server_port, round_id, tod, job, special, name, byondkey, laname, lakey, bruteloss, fireloss, brainloss, oxyloss, toxloss, staminaloss, last_words, suicide) - VALUES (:pod, :x_coord, :y_coord, :z_coord, :map, INET_ATON(:internet_address), :port, :round_id, :time, :job, :special, :name, :key, :laname, :lakey, :brute, :fire, :brain, :oxy, :tox, :stamina, :last_words, :suicide) + VALUES (:pod, :x_coord, :y_coord, :z_coord, :map, INET_ATON(:internet_address), :port, :round_id, NOW(), :job, :special, :name, :key, :laname, :lakey, :brute, :fire, :brain, :oxy, :tox, :stamina, :last_words, :suicide) "}, list( "name" = L.real_name, "key" = L.ckey, @@ -361,7 +359,6 @@ Versioning "internet_address" = world.internet_address || "0", "port" = "[world.port]", "round_id" = GLOB.round_id, - "time" = SQLtime(), )) if(query_report_death) query_report_death.Execute(async = TRUE) @@ -392,7 +389,7 @@ Versioning :message, :fine, :paid, - :timestamp + NOW() ) ON DUPLICATE KEY UPDATE paid = paid + VALUES(paid)"}, list( "server_ip" = world.internet_address || "0", @@ -406,7 +403,6 @@ Versioning "message" = message, "fine" = fine, "paid" = paid, - "timestamp" = SQLtime() )) if(query_report_citation) query_report_citation.Execute(async = TRUE) diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm index eefbede308739..a3dcc26af54fb 100644 --- a/code/controllers/subsystem/dcs.dm +++ b/code/controllers/subsystem/dcs.dm @@ -84,7 +84,7 @@ PROCESSING_SUBSYSTEM_DEF(dcs) fullid += REF(key) if(named_arguments) - named_arguments = sortTim(named_arguments, GLOBAL_PROC_REF(cmp_text_asc)) + sortTim(named_arguments, GLOBAL_PROC_REF(cmp_text_asc)) fullid += named_arguments return list2params(fullid) diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm index aca8ff1fc9e7e..3fb1ce8af9cec 100644 --- a/code/controllers/subsystem/dynamic/dynamic.dm +++ b/code/controllers/subsystem/dynamic/dynamic.dm @@ -317,7 +317,7 @@ SUBSYSTEM_DEF(dynamic) SSticker.news_report = SSshuttle.emergency?.is_hijacked() ? SHUTTLE_HIJACK : STATION_EVACUATED /datum/controller/subsystem/dynamic/proc/send_intercept() - if(SScommunications.block_command_report) //If we don't want the report to be printed just yet, we put it off until it's ready + if(GLOB.communications_controller.block_command_report) //If we don't want the report to be printed just yet, we put it off until it's ready addtimer(CALLBACK(src, PROC_REF(send_intercept)), 10 SECONDS) return @@ -349,10 +349,10 @@ SUBSYSTEM_DEF(dynamic) if(trait_list_strings.len > 0) . += "
Identified shift divergencies:
" + trait_list_strings.Join() - if(length(SScommunications.command_report_footnotes)) + if(length(GLOB.communications_controller.command_report_footnotes)) var/footnote_pile = "" - for(var/datum/command_footnote/footnote in SScommunications.command_report_footnotes) + for(var/datum/command_footnote/footnote in GLOB.communications_controller.command_report_footnotes) footnote_pile += "[footnote.message]
" footnote_pile += "[footnote.signature]
" footnote_pile += "
" @@ -377,17 +377,17 @@ SUBSYSTEM_DEF(dynamic) if (prob(PULSAR_REPORT_CHANCE)) if(HAS_TRAIT(SSstation, STATION_TRAIT_BANANIUM_SHIPMENTS)) advisory_string += "Advisory Level: Clown Planet
" - advisory_string += "Your sector's advisory level is Clown Planet! Our bike horns have picked up on a large bananium stash. Clowns show a large influx of clowns on your station. We highly advice you to slip any threats to keep Honkotrasen assets within the Banana Sector. The Department advises defending chemistry from any clowns that are trying to make baldium or space lube." + advisory_string += "Your sector's advisory level is Clown Planet! Our bike horns have picked up on a large bananium stash. Clowns show a large influx of clowns on your station. We highly advise you to slip any threats to keep Honkotrasen assets within the Banana Sector. The Department of Intelligence advises defending chemistry from any clowns that are trying to make baldium or space lube." return advisory_string advisory_string += "Advisory Level: Pulsar Star
" - advisory_string += "Your sector's advisory level is Pulsar Star. A large unknown electromagnetic field has stormed through nearby surveillance equipment. No surveillance data has been able to be obtained showing no credible threats to Nanotrasen assets within the Spinward Sector. The Department advises maintaining high alert against potential threats, regardless of a lack of information." + advisory_string += "Your sector's advisory level is Pulsar Star. A large, unknown electromagnetic field has stormed through nearby surveillance equipment, causing major data loss. Partial data was recovered and showed no credible threats to Nanotrasen assets within the Spinward Sector; however, the Department of Intelligence advises maintaining high alert against potential threats due to the lack of complete data." return advisory_string switch(round(shown_threat)) if(0) advisory_string += "Advisory Level: White Dwarf
" - advisory_string += "Your sector's advisory level is White Dwarf. Our surveillors have ruled out any and all potential risks known in our database, ruling out the loss of our assets in the Spinward Sector. We advise a lower level of security, alongside distributing ressources on potential profit." + advisory_string += "Your sector's advisory level is White Dwarf. Our surveillance has ruled out any and all potential threats known in our database, eliminating most risks to our assets in the Spinward Sector. We advise a lower level of security, alongside distributing resources on potential profit." if(1 to 19) var/show_core_territory = (GLOB.current_living_antags.len > 0) if (prob(FAKE_GREENSHIFT_FORM_CHANCE)) @@ -395,22 +395,22 @@ SUBSYSTEM_DEF(dynamic) if (show_core_territory) advisory_string += "Advisory Level: Blue Star
" - advisory_string += "Your sector's advisory level is Blue Star. At this threat advisory, the risk of attacks on Nanotrasen assets within the sector is minor, but cannot be ruled out entirely. Remain vigilant." + advisory_string += "Your sector's advisory level is Blue Star. At this threat advisory, the risk of attacks on Nanotrasen assets within the sector is minor but cannot be ruled out entirely. Remain vigilant." else advisory_string += "Advisory Level: Green Star
" - advisory_string += "Your sector's advisory level is Green Star. Surveillance information shows no credible threats to Nanotrasen assets within the Spinward Sector at this time. As always, the Department advises maintaining vigilance against potential threats, regardless of a lack of known threats." + advisory_string += "Your sector's advisory level is Green Star. Surveillance information shows no credible threats to Nanotrasen assets within the Spinward Sector at this time. As always, the Department of Intelligence advises maintaining vigilance against potential threats, regardless of a lack of known threats." if(20 to 39) advisory_string += "Advisory Level: Yellow Star
" - advisory_string += "Your sector's advisory level is Yellow Star. Surveillance shows a credible risk of enemy attack against our assets in the Spinward Sector. We advise a heightened level of security, alongside maintaining vigilance against potential threats." + advisory_string += "Your sector's advisory level is Yellow Star. Surveillance shows a credible risk of enemy attack against our assets in the Spinward Sector. We advise a heightened level of security alongside maintaining vigilance against potential threats." if(40 to 65) advisory_string += "Advisory Level: Orange Star
" - advisory_string += "Your sector's advisory level is Orange Star. Upon reviewing your sector's intelligence, the Department has determined that the risk of enemy activity is moderate to severe. At this advisory, we recommend maintaining a higher degree of security and alertness, and vigilance against threats that may (or will) arise." + advisory_string += "Your sector's advisory level is Orange Star. Upon reviewing your sector's intelligence, the Department has determined that the risk of enemy activity is moderate to severe. At this advisory, we recommend maintaining a higher degree of security and reviewing red alert protocols with command and the crew." if(66 to 79) advisory_string += "Advisory Level: Red Star
" advisory_string += "Your sector's advisory level is Red Star. The Department of Intelligence has decrypted Cybersun communications suggesting a high likelihood of attacks on Nanotrasen assets within the Spinward Sector. Stations in the region are advised to remain highly vigilant for signs of enemy activity and to be on high alert." if(80 to 99) advisory_string += "Advisory Level: Black Orbit
" - advisory_string += "Your sector's advisory level is Black Orbit. Your sector's local comms network is currently undergoing a blackout, and we are therefore unable to accurately judge enemy movements within the region. However, information passed to us by GDI suggests a high amount of enemy activity in the sector, indicative of an impending attack. Remain on high alert, and as always, we advise remaining vigilant against any other potential threats." + advisory_string += "Your sector's advisory level is Black Orbit. Your sector's local communications network is currently undergoing a blackout, and we are therefore unable to accurately judge enemy movements within the region. However, information passed to us by GDI suggests a high amount of enemy activity in the sector, indicative of an impending attack. Remain on high alert and vigilant against any other potential threats." if(100) advisory_string += "Advisory Level: Midnight Sun
" advisory_string += "Your sector's advisory level is Midnight Sun. Credible information passed to us by GDI suggests that the Syndicate is preparing to mount a major concerted offensive on Nanotrasen assets in the Spinward Sector to cripple our foothold there. All stations should remain on high alert and prepared to defend themselves." diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets.dm index b5f84176d594b..28789d938d381 100644 --- a/code/controllers/subsystem/dynamic/dynamic_rulesets.dm +++ b/code/controllers/subsystem/dynamic/dynamic_rulesets.dm @@ -140,28 +140,41 @@ /// This function is here to ensure the antag ratio is kept under control while scaling up. /// Returns how much threat to actually spend in the end. /datum/dynamic_ruleset/proc/scale_up(population, max_scale) + SHOULD_NOT_OVERRIDE(TRUE) if (!scaling_cost) return 0 var/antag_fraction = 0 - for(var/_ruleset in (SSdynamic.executed_rules + list(src))) // we care about the antags we *will* assign, too - var/datum/dynamic_ruleset/ruleset = _ruleset - antag_fraction += ((1 + ruleset.scaled_times) * ruleset.get_antag_cap(population)) / SSdynamic.roundstart_pop_ready + for(var/datum/dynamic_ruleset/ruleset as anything in (SSdynamic.executed_rules + list(src))) // we care about the antags we *will* assign, too + antag_fraction += ruleset.get_antag_cap_scaling_included(population) / SSdynamic.roundstart_pop_ready for(var/i in 1 to max_scale) if(antag_fraction < 0.25) scaled_times += 1 - antag_fraction += get_antag_cap(population) / SSdynamic.roundstart_pop_ready // we added new antags, gotta update the % + antag_fraction += get_scaling_antag_cap(population) / SSdynamic.roundstart_pop_ready // we added new antags, gotta update the % return scaled_times * scaling_cost +/// Returns how many more antags to add while scaling with a given population. +/// By default rulesets scale linearly, but you can override this to make them scale differently. +/datum/dynamic_ruleset/proc/get_scaling_antag_cap(population) + return get_antag_cap(population) + /// Returns what the antag cap with the given population is. /datum/dynamic_ruleset/proc/get_antag_cap(population) + SHOULD_NOT_OVERRIDE(TRUE) if (isnum(antag_cap)) return antag_cap return CEILING(population / antag_cap["denominator"], 1) + (antag_cap["offset"] || 0) +/// Gets the 'final' antag cap for this ruleset, which is the base cap plus the scaled cap. +/datum/dynamic_ruleset/proc/get_antag_cap_scaling_included(population) + SHOULD_NOT_OVERRIDE(TRUE) + var/base_cap = get_antag_cap(population) + var/modded_cap = scaled_times * get_scaling_antag_cap(population) + return base_cap + modded_cap + /// This is called if persistent variable is true everytime SSTicker ticks. /datum/dynamic_ruleset/proc/rule_process() return diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm index a36c2c78fb3bb..539e6d234c00e 100644 --- a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm +++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm @@ -183,6 +183,7 @@ var/mob/new_character = applicant if(makeBody) new_character = generate_ruleset_body(applicant) + SEND_GLOBAL_SIGNAL(COMSIG_RULESET_BODY_GENERATED_FROM_GHOSTS, applicant) finish_setup(new_character, i) notify_ghosts( "[applicant.name] has been picked for the ruleset [name]!", @@ -297,25 +298,29 @@ cost = 10 required_type = /mob/living/silicon/ai blocking_rules = list(/datum/dynamic_ruleset/roundstart/malf_ai) + // AIs are technically considered "Ghost roles" as far as candidate selection are concerned + // So we need to allow it here. We filter of actual ghost role AIs (charlie) via trim_candidates ourselves + restrict_ghost_roles = FALSE /datum/dynamic_ruleset/midround/malf/trim_candidates() ..() - candidates = living_players - for(var/mob/living/player in candidates) - if(!isAI(player)) - candidates -= player + candidates = list() + for(var/mob/living/silicon/ai/player in living_players) + if(!is_station_level(player.z)) continue - - if(is_centcom_level(player.z)) - candidates -= player + if(isnull(player.mind)) + continue + if(player.mind.special_role || length(player.mind.antag_datums)) continue + candidates += player - if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0)) - candidates -= player +/datum/dynamic_ruleset/midround/malf/ready(forced) + if(!check_candidates()) + log_dynamic("FAIL: No valid AI found for the Malfunctioning AI ruleset.") + return FALSE + return ..() /datum/dynamic_ruleset/midround/malf/execute() - if(!candidates || !candidates.len) - return FALSE var/mob/living/silicon/ai/new_malf_ai = pick_n_take(candidates) assigned += new_malf_ai.mind var/datum/antagonist/malf_ai/malf_antag_datum = new diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm index 51ecd59925a4d..12ec28c707212 100644 --- a/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm @@ -33,8 +33,7 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE) /datum/dynamic_ruleset/roundstart/traitor/pre_execute(population) . = ..() - var/num_traitors = get_antag_cap(population) * (scaled_times + 1) - for (var/i = 1 to num_traitors) + for (var/i in 1 to get_antag_cap_scaling_included(population)) if(candidates.len <= 0) break var/mob/M = pick_n_take(candidates) @@ -121,7 +120,7 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE) /datum/dynamic_ruleset/roundstart/traitorbro/pre_execute(population) . = ..() - for (var/_ in 1 to get_antag_cap(population) * (scaled_times + 1)) + for (var/i in 1 to get_antag_cap_scaling_included(population)) var/mob/candidate = pick_n_take(candidates) if (isnull(candidate)) break @@ -135,10 +134,7 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE) /datum/dynamic_ruleset/roundstart/traitorbro/execute() for (var/datum/mind/mind in assigned) - var/datum/team/brother_team/team = new - team.add_member(mind) - team.forge_brother_objectives() - mind.add_antag_datum(/datum/antagonist/brother, team) + new /datum/team/brother_team(mind) GLOB.pre_setup_antags -= mind return TRUE @@ -174,8 +170,7 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE) /datum/dynamic_ruleset/roundstart/changeling/pre_execute(population) . = ..() - var/num_changelings = get_antag_cap(population) * (scaled_times + 1) - for (var/i = 1 to num_changelings) + for (var/i in 1 to get_antag_cap_scaling_included(population)) if(candidates.len <= 0) break var/mob/M = pick_n_take(candidates) @@ -720,13 +715,15 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE) required_candidates = 3 // lives or dies by there being a few spies weight = 5 cost = 8 - scaling_cost = 101 // see below - minimum_players = 8 - antag_cap = list("denominator" = 8, "offset" = 1) // should have quite a few spies to work against each other + scaling_cost = 4 + minimum_players = 10 + antag_cap = list("denominator" = 20, "offset" = 1) requirements = list(8, 8, 8, 8, 8, 8, 8, 8, 8, 8) + /// What fraction is added to the antag cap for each additional scale + var/fraction_per_scale = 0.2 /datum/dynamic_ruleset/roundstart/spies/pre_execute(population) - for(var/i in 1 to get_antag_cap(population) * (scaled_times + 1)) + for(var/i in 1 to get_antag_cap_scaling_included(population)) if(length(candidates) <= 0) break var/mob/picked_player = pick_n_take(candidates) @@ -736,7 +733,6 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE) GLOB.pre_setup_antags += picked_player.mind return TRUE -/datum/dynamic_ruleset/roundstart/spies/scale_up(population, max_scale) - // Disabled (at least until dynamic can handle scaling this better) - // Because spies have a very low demoninator, this can easily spawn like 30 of them - return 0 +// Scaling adds a fraction of the amount of additional spies rather than the full amount. +/datum/dynamic_ruleset/roundstart/spies/get_scaling_antag_cap(population) + return ceil(..() * fraction_per_scale) diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm index 362129f130570..50e437195a74a 100644 --- a/code/controllers/subsystem/events.dm +++ b/code/controllers/subsystem/events.dm @@ -23,6 +23,10 @@ SUBSYSTEM_DEF(events) if(!event.typepath || !event.valid_for_map()) continue //don't want this one! leave it for the garbage collector control += event //add it to the list of all events (controls) + + frequency_lower = CONFIG_GET(number/events_frequency_lower) + frequency_upper = CONFIG_GET(number/events_frequency_upper) + reschedule() // Instantiate our holidays list if it hasn't been already if(isnull(GLOB.holidays)) @@ -85,7 +89,8 @@ SUBSYSTEM_DEF(events) event_roster[event_to_check] = event_to_check.weight var/datum/round_event_control/event_to_run = pick_weight(event_roster) - TriggerEvent(event_to_run) + if(event_to_run) + TriggerEvent(event_to_run) ///Does the last pre-flight checks for the passed event, and runs it if the event is ready. /datum/controller/subsystem/events/proc/TriggerEvent(datum/round_event_control/event_to_trigger) @@ -103,8 +108,8 @@ SUBSYSTEM_DEF(events) ///Sets the event frequency bounds back to their initial value. /datum/controller/subsystem/events/proc/resetFrequency() - frequency_lower = initial(frequency_lower) - frequency_upper = initial(frequency_upper) + frequency_lower = CONFIG_GET(number/events_frequency_lower) + frequency_upper = CONFIG_GET(number/events_frequency_upper) /** * HOLIDAYS diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index f44482e8541ca..7bb597ba30e12 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -87,12 +87,9 @@ SUBSYSTEM_DEF(explosions) throwturf -= T held_throwturf -= T -/client/proc/check_bomb_impacts() - set name = "Check Bomb Impact" - set category = "Debug" - - var/newmode = tgui_alert(usr, "Use reactionary explosions?","Check Bomb Impact", list("Yes", "No")) - var/turf/epicenter = get_turf(mob) +ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effect of a bomb would be.", ADMIN_CATEGORY_DEBUG) + var/newmode = tgui_alert(user, "Use reactionary explosions?","Check Bomb Impact", list("Yes", "No")) + var/turf/epicenter = get_turf(user.mob) if(!epicenter) return @@ -100,7 +97,7 @@ SUBSYSTEM_DEF(explosions) var/heavy = 0 var/light = 0 var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb") - var/choice = tgui_input_list(usr, "Pick the bomb size", "Bomb Size?", choices) + var/choice = tgui_input_list(user, "Pick the bomb size", "Bomb Size?", choices) switch(choice) if(null) return 0 @@ -117,9 +114,9 @@ SUBSYSTEM_DEF(explosions) heavy = 5 light = 7 if("Custom Bomb") - dev = input("Devastation range (Tiles):") as num - heavy = input("Heavy impact range (Tiles):") as num - light = input("Light impact range (Tiles):") as num + dev = input(user, "Devastation range (Tiles):") as num + heavy = input(user, "Heavy impact range (Tiles):") as num + light = input(user, "Light impact range (Tiles):") as num var/max_range = max(dev, heavy, light) var/x0 = epicenter.x @@ -154,7 +151,7 @@ SUBSYSTEM_DEF(explosions) else continue - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(wipe_color_and_text), wipe_colours), 100) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(wipe_color_and_text), wipe_colours), 10 SECONDS) /proc/wipe_color_and_text(list/atom/wiping) for(var/i in wiping) @@ -208,9 +205,12 @@ SUBSYSTEM_DEF(explosions) * - flame_range: The range at which the explosion should produce hotspots. * - silent: Whether to generate/execute sound effects. * - smoke: Whether to generate a smoke cloud provided the explosion is powerful enough to warrant it. + * - protect_epicenter: Whether to leave the epicenter turf unaffected by the explosion * - explosion_cause: [Optional] The atom that caused the explosion, when different to the origin. Used for logging. + * - explosion_direction: The angle in which the explosion is pointed (for directional explosions.) + * - explosion_arc: The angle of the arc covered by a directional explosion (if 360 the explosion is non-directional.) */ -/proc/explosion(atom/origin, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 0, flame_range = null, flash_range = null, adminlog = TRUE, ignorecap = FALSE, silent = FALSE, smoke = FALSE, atom/explosion_cause = null) +/proc/explosion(atom/origin, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 0, flame_range = null, flash_range = null, adminlog = TRUE, ignorecap = FALSE, silent = FALSE, smoke = FALSE, protect_epicenter = FALSE, atom/explosion_cause = null, explosion_direction = 0, explosion_arc = 360) . = SSexplosions.explode(arglist(args)) @@ -228,9 +228,12 @@ SUBSYSTEM_DEF(explosions) * - flame_range: The range at which the explosion should produce hotspots. * - silent: Whether to generate/execute sound effects. * - smoke: Whether to generate a smoke cloud provided the explosion is powerful enough to warrant it. + * - protect_epicenter: Whether to leave the epicenter turf unaffected by the explosion * - explosion_cause: [Optional] The atom that caused the explosion, when different to the origin. Used for logging. + * - explosion_direction: The angle in which the explosion is pointed (for directional explosions.) + * - explosion_arc: The angle of the arc covered by a directional explosion (if 360 the explosion is non-directional.) */ -/datum/controller/subsystem/explosions/proc/explode(atom/origin, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 0, flame_range = null, flash_range = null, adminlog = TRUE, ignorecap = FALSE, silent = FALSE, smoke = FALSE, atom/explosion_cause = null) +/datum/controller/subsystem/explosions/proc/explode(atom/origin, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 0, flame_range = null, flash_range = null, adminlog = TRUE, ignorecap = FALSE, silent = FALSE, smoke = FALSE, protect_epicenter = FALSE, atom/explosion_cause = null, explosion_direction = 0, explosion_arc = 360) var/list/arguments = list( EXARG_KEY_ORIGIN = origin, EXARG_KEY_DEV_RANGE = devastation_range, @@ -242,7 +245,10 @@ SUBSYSTEM_DEF(explosions) EXARG_KEY_IGNORE_CAP = ignorecap, EXARG_KEY_SILENT = silent, EXARG_KEY_SMOKE = smoke, + EXARG_KEY_PROTECT_EPICENTER = protect_epicenter, EXARG_KEY_EXPLOSION_CAUSE = explosion_cause ? explosion_cause : origin, + EXARG_KEY_EXPLOSION_DIRECTION = explosion_direction, + EXARG_KEY_EXPLOSION_ARC = explosion_arc, ) var/atom/location = isturf(origin) ? origin : origin.loc if(SEND_SIGNAL(origin, COMSIG_ATOM_EXPLODE, arguments) & COMSIG_CANCEL_EXPLOSION) @@ -270,7 +276,7 @@ SUBSYSTEM_DEF(explosions) /** * Handles the effects of an explosion originating from a given point. * - * Primarily handles popagating the balstwave of the explosion to the relevant turfs. + * Primarily handles popagating the blastwave of the explosion to the relevant turfs. * Also handles the fireball from the explosion. * Also handles the smoke cloud from the explosion. * Also handles sfx and screenshake. @@ -286,9 +292,12 @@ SUBSYSTEM_DEF(explosions) * - flame_range: The range at which the explosion should produce hotspots. * - silent: Whether to generate/execute sound effects. * - smoke: Whether to generate a smoke cloud provided the explosion is powerful enough to warrant it. - * - explosion_cause: The atom that caused the explosion. Used for logging. + * - protect_epicenter: Whether to leave the epicenter turf unaffected by the explosion + * - explosion_cause: [Optional] The atom that caused the explosion, when different to the origin. Used for logging. + * - explosion_direction: The angle in which the explosion is pointed (for directional explosions.) + * - explosion_arc: The angle of the arc covered by a directional explosion (if 360 the explosion is non-directional.) */ -/datum/controller/subsystem/explosions/proc/propagate_blastwave(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, adminlog, ignorecap, silent, smoke, atom/explosion_cause) +/datum/controller/subsystem/explosions/proc/propagate_blastwave(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, adminlog, ignorecap, silent, smoke, protect_epicenter, atom/explosion_cause, explosion_direction, explosion_arc) epicenter = get_turf(epicenter) if(!epicenter) return @@ -387,7 +396,7 @@ SUBSYSTEM_DEF(explosions) for(var/mob/living/L in viewers(flash_range, epicenter)) L.flash_act() - var/list/affected_turfs = prepare_explosion_turfs(max_range, epicenter) + var/list/affected_turfs = prepare_explosion_turfs(max_range, epicenter, protect_epicenter, explosion_direction, explosion_arc) var/reactionary = CONFIG_GET(flag/reactionary_explosions) // this list is setup in the form position -> block for that position @@ -415,7 +424,6 @@ SUBSYSTEM_DEF(explosions) block += our_block cached_exp_block[explode] = our_block + explode.explosive_resistance - var/severity = EXPLODE_NONE if(dist + (block * EXPLOSION_BLOCK_DEV) < devastation_range) severity = EXPLODE_DEVASTATE @@ -580,10 +588,12 @@ SUBSYSTEM_DEF(explosions) /// Returns in a unique order, spiraling outwards /// This is done to ensure our progressive cache of blast resistance is always valid /// This is quite fast -/proc/prepare_explosion_turfs(range, turf/epicenter) +/proc/prepare_explosion_turfs(range, turf/epicenter, protect_epicenter, explosion_direction, explosion_arc) var/list/outlist = list() - // Add in the center - outlist += epicenter + var/list/candidates = list() + // Add in the center if it's not protected + if(!protect_epicenter) + outlist += epicenter var/our_x = epicenter.x var/our_y = epicenter.y @@ -591,6 +601,31 @@ SUBSYSTEM_DEF(explosions) var/max_x = world.maxx var/max_y = world.maxy + + // Work out the angles to explode between + var/first_angle_limit = WRAP(explosion_direction - explosion_arc * 0.5, 0, 360) + var/second_angle_limit = WRAP(explosion_direction + explosion_arc * 0.5, 0, 360) + + // Get everything in the right order + var/lower_angle_limit + var/upper_angle_limit + var/do_directional + var/reverse_angle + + // Work out which case we're in + if(first_angle_limit == second_angle_limit) // CASE A: FULL CIRCLE + do_directional = FALSE + else if(first_angle_limit < second_angle_limit) // CASE B: When the arc does not cross 0 degrees + lower_angle_limit = first_angle_limit + upper_angle_limit = second_angle_limit + do_directional = TRUE + reverse_angle = FALSE + else if (first_angle_limit > second_angle_limit) // CASE C: When the arc crosses 0 degrees + lower_angle_limit = second_angle_limit + upper_angle_limit = first_angle_limit + do_directional = TRUE + reverse_angle = TRUE + for(var/i in 1 to range) var/lowest_x = our_x - i var/lowest_y = our_y - i @@ -598,25 +633,32 @@ SUBSYSTEM_DEF(explosions) var/highest_y = our_y + i // top left to one before top right if(highest_y <= max_y) - outlist += block( + candidates += block( locate(max(lowest_x, 1), highest_y, our_z), locate(min(highest_x - 1, max_x), highest_y, our_z)) // top right to one before bottom right if(highest_x <= max_x) - outlist += block( + candidates += block( locate(highest_x, min(highest_y, max_y), our_z), locate(highest_x, max(lowest_y + 1, 1), our_z)) // bottom right to one before bottom left if(lowest_y >= 1) - outlist += block( + candidates += block( locate(min(highest_x, max_x), lowest_y, our_z), locate(max(lowest_x + 1, 1), lowest_y, our_z)) // bottom left to one before top left if(lowest_x >= 1) - outlist += block( + candidates += block( locate(lowest_x, max(lowest_y, 1), our_z), locate(lowest_x, min(highest_y - 1, max_y), our_z)) + if(!do_directional) + outlist += candidates + else + for(var/turf/candidate as anything in candidates) + var/angle = get_angle(epicenter, candidate) + if(ISINRANGE(angle, lower_angle_limit, upper_angle_limit) ^ reverse_angle) + outlist += candidate return outlist /datum/controller/subsystem/explosions/fire(resumed = 0) diff --git a/code/controllers/subsystem/idlenpcpool.dm b/code/controllers/subsystem/idlenpcpool.dm deleted file mode 100644 index ee98e8c4e67c2..0000000000000 --- a/code/controllers/subsystem/idlenpcpool.dm +++ /dev/null @@ -1,47 +0,0 @@ -SUBSYSTEM_DEF(idlenpcpool) - name = "Idling NPC Pool" - flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT - priority = FIRE_PRIORITY_IDLE_NPC - wait = 60 - runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME - - var/list/currentrun = list() - var/static/list/idle_mobs_by_zlevel[][] - -/datum/controller/subsystem/idlenpcpool/stat_entry(msg) - var/list/idlelist = GLOB.simple_animals[AI_IDLE] - var/list/zlist = GLOB.simple_animals[AI_Z_OFF] - msg = "IdleNPCS:[length(idlelist)]|Z:[length(zlist)]" - return ..() - -/datum/controller/subsystem/idlenpcpool/proc/MaxZChanged() - if (!islist(idle_mobs_by_zlevel)) - idle_mobs_by_zlevel = new /list(world.maxz,0) - while (SSidlenpcpool.idle_mobs_by_zlevel.len < world.maxz) - SSidlenpcpool.idle_mobs_by_zlevel.len++ - SSidlenpcpool.idle_mobs_by_zlevel[idle_mobs_by_zlevel.len] = list() - -/datum/controller/subsystem/idlenpcpool/fire(resumed = FALSE) - - if (!resumed) - var/list/idlelist = GLOB.simple_animals[AI_IDLE] - src.currentrun = idlelist.Copy() - - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - - while(currentrun.len) - var/mob/living/simple_animal/SA = currentrun[currentrun.len] - --currentrun.len - if (QDELETED(SA)) - GLOB.simple_animals[AI_IDLE] -= SA - stack_trace("Found a null in simple_animals deactive list [SA.type]!") - continue - - if(!SA.ckey) - if(SA.stat != DEAD) - SA.handle_automated_movement() - if(SA.stat != DEAD) - SA.consider_wakeup() - if (MC_TICK_CHECK) - return diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm index 83cbbc4c27efc..db397d514742f 100644 --- a/code/controllers/subsystem/ipintel.dm +++ b/code/controllers/subsystem/ipintel.dm @@ -1,13 +1,295 @@ SUBSYSTEM_DEF(ipintel) name = "XKeyScore" init_order = INIT_ORDER_XKEYSCORE - flags = SS_NO_FIRE - var/enabled = FALSE //disable at round start to avoid checking reconnects - var/throttle = 0 - var/errors = 0 + flags = SS_NO_INIT|SS_NO_FIRE + /// The threshold for probability to be considered a VPN and/or bad IP + var/probability_threshold - var/list/cache = list() + /// Cache for previously queried IP addresses and those stored in the database + var/list/datum/ip_intel/cached_queries = list() + /// The store for rate limiting + var/list/rate_limit_minute -/datum/controller/subsystem/ipintel/Initialize() - enabled = TRUE - return SS_INIT_SUCCESS +/// The ip intel for a given address +/datum/ip_intel + /// If this intel was just queried, the status of the query + var/query_status + var/result + var/address + var/date + +/datum/controller/subsystem/ipintel/OnConfigLoad() + var/list/fail_messages = list() + + var/contact_email = CONFIG_GET(string/ipintel_email) + + if(!length(contact_email)) + fail_messages += "No contact email" + + if(!findtext(contact_email, "@")) + fail_messages += "Invalid contact email" + + if(!length(CONFIG_GET(string/ipintel_base))) + fail_messages += "Invalid query base" + + if (!CONFIG_GET(flag/sql_enabled)) + fail_messages += "The database is not enabled" + + if(length(fail_messages)) + message_admins("IPIntel: Initialization failed check logs!") + logger.Log(LOG_CATEGORY_GAME_ACCESS, "IPIntel is not enabled because the configs are not valid.", list( + "fail_messages" = fail_messages, + )) + +/datum/controller/subsystem/ipintel/stat_entry(msg) + return "[..()] | M: [CONFIG_GET(number/ipintel_rate_minute) - rate_limit_minute]" + + +/datum/controller/subsystem/ipintel/proc/is_enabled() + return length(CONFIG_GET(string/ipintel_email)) && length(CONFIG_GET(string/ipintel_base)) && CONFIG_GET(flag/sql_enabled) + +/datum/controller/subsystem/ipintel/proc/get_address_intel_state(address, probability_override) + if (!is_enabled()) + return IPINTEL_GOOD_IP + var/datum/ip_intel/intel = query_address(address) + if(isnull(intel)) + stack_trace("query_address did not return an ip intel response") + return IPINTEL_UNKNOWN_INTERNAL_ERROR + + if(istext(intel)) + return intel + + if(!(intel.query_status in list("success", "cached"))) + return IPINTEL_UNKNOWN_QUERY_ERROR + var/check_probability = probability_override || CONFIG_GET(number/ipintel_rating_bad) + if(intel.result >= check_probability) + return IPINTEL_BAD_IP + return IPINTEL_GOOD_IP + +/datum/controller/subsystem/ipintel/proc/is_rate_limited() + var/static/minute_key + var/expected_minute_key = floor(REALTIMEOFDAY / 1 MINUTES) + + if(minute_key != expected_minute_key) + minute_key = expected_minute_key + rate_limit_minute = 0 + + if(rate_limit_minute >= CONFIG_GET(number/ipintel_rate_minute)) + return IPINTEL_RATE_LIMITED_MINUTE + return FALSE + +/datum/controller/subsystem/ipintel/proc/query_address(address, allow_cached = TRUE) + if (!is_enabled()) + return + if(allow_cached && fetch_cached_ip_intel(address)) + return cached_queries[address] + var/is_rate_limited = is_rate_limited() + if(is_rate_limited) + return is_rate_limited + rate_limit_minute += 1 + + var/query_base = "https://[CONFIG_GET(string/ipintel_base)]/check.php?ip=" + var/query = "[query_base][address]&contact=[CONFIG_GET(string/ipintel_email)]&flags=b&format=json" + + var/datum/http_request/request = new + request.prepare(RUSTG_HTTP_METHOD_GET, query) + request.execute_blocking() + var/datum/http_response/response = request.into_response() + var/list/data = json_decode(response.body) + // Log the response + logger.Log(LOG_CATEGORY_DEBUG, "ip check response body", data) + + var/datum/ip_intel/intel = new + intel.query_status = data["status"] + if(intel.query_status != "success") + return intel + intel.result = data["result"] + if(istext(intel.result)) + intel.result = text2num(intel.result) + intel.date = ISOtime() + intel.address = address + cached_queries[address] = intel + add_intel_to_database(intel) + return intel + +/datum/controller/subsystem/ipintel/proc/add_intel_to_database(datum/ip_intel/intel) + set waitfor = FALSE //no need to make the client connection wait for this step. + if (!SSdbcore.Connect()) + return + var/datum/db_query/query = SSdbcore.NewQuery( + "INSERT INTO [format_table_name("ipintel")] ( \ + ip, \ + intel \ + ) VALUES ( \ + INET_ATON(:address), \ + :result \ + )", list( + "address" = intel.address, + "result" = intel.result, + ) + ) + query.warn_execute() + query.sync() + qdel(query) + +/datum/controller/subsystem/ipintel/proc/fetch_cached_ip_intel(address) + if (!SSdbcore.Connect()) + return + var/ipintel_cache_length = CONFIG_GET(number/ipintel_cache_length) + var/date_restrictor = "" + var/sql_args = list("address" = address) + if(ipintel_cache_length > 1) + date_restrictor = " AND date > DATE_SUB(NOW(), INTERVAL :ipintel_cache_length DAY)" + sql_args["ipintel_cache_length"] = ipintel_cache_length + var/datum/db_query/query = SSdbcore.NewQuery( + "SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:address)[date_restrictor]", + sql_args + ) + query.warn_execute() + query.sync() + if(query.status == DB_QUERY_BROKEN) + qdel(query) + return null + + query.NextRow() + var/list/data = query.item + qdel(query) + if(isnull(data)) + return null + + var/datum/ip_intel/intel = new + intel.query_status = "cached" + intel.result = data["intel"] + if(istext(intel.result)) + intel.result = text2num(intel.result) + intel.date = data["date"] + intel.address = address + return TRUE + +/datum/controller/subsystem/ipintel/proc/is_exempt(client/player) + if(player.holder || GLOB.deadmins[player.ckey]) + return TRUE + var/exempt_living_playtime = CONFIG_GET(number/ipintel_exempt_playtime_living) + if(exempt_living_playtime > 0) + var/list/play_records = player.prefs.exp + if (!play_records.len) + player.set_exp_from_db() + play_records = player.prefs.exp + if(length(play_records) && play_records[EXP_TYPE_LIVING] > exempt_living_playtime) + return TRUE + return FALSE + +/datum/controller/subsystem/ipintel/proc/is_whitelisted(ckey) + var/datum/db_query/query = SSdbcore.NewQuery( + "SELECT * FROM [format_table_name("ipintel_whitelist")] WHERE ckey = :ckey", list( + "ckey" = ckey + ) + ) + query.warn_execute() + query.sync() + if(query.status == DB_QUERY_BROKEN) + qdel(query) + return FALSE + query.NextRow() + . = !!query.item // if they have a row, they are whitelisted + qdel(query) + + +ADMIN_VERB(ipintel_allow, R_BAN, "Whitelist Player VPN", "Allow a player to connect even if they are using a VPN.", ADMIN_CATEGORY_IPINTEL, ckey as text) + if (!SSipintel.is_enabled()) + to_chat(user, "The ipintel system is not currently enabled but you can still edit the whitelists") + if(SSipintel.is_whitelisted(ckey)) + to_chat(user, "Player is already whitelisted.") + return + + var/datum/db_query/query = SSdbcore.NewQuery( + "INSERT INTO [format_table_name("ipintel_whitelist")] ( \ + ckey, \ + admin_ckey \ + ) VALUES ( \ + :ckey, \ + :admin_ckey \ + )", list( + "ckey" = ckey, + "admin_ckey" = user.ckey, + ) + ) + query.warn_execute() + query.sync() + qdel(query) + message_admins("IPINTEL: [key_name_admin(user)] has whitelisted '[ckey]'") + +ADMIN_VERB(ipintel_revoke, R_BAN, "Revoke Player VPN Whitelist", "Revoke a player's VPN whitelist.", ADMIN_CATEGORY_IPINTEL, ckey as text) + if (!SSipintel.is_enabled()) + to_chat(user, "The ipintel system is not currently enabled but you can still edit the whitelists") + if(!SSipintel.is_whitelisted(ckey)) + to_chat(user, "Player is not whitelisted.") + return + var/datum/db_query/query = SSdbcore.NewQuery( + "DELETE FROM [format_table_name("ipintel_whitelist")] WHERE ckey = :ckey", list( + "ckey" = ckey + ) + ) + query.warn_execute() + query.sync() + qdel(query) + message_admins("IPINTEL: [key_name_admin(user)] has revoked the VPN whitelist for '[ckey]'") + +/client/proc/check_ip_intel() + if (!SSipintel.is_enabled()) + return + if(SSipintel.is_exempt(src) || SSipintel.is_whitelisted(ckey)) + return + + var/intel_state = SSipintel.get_address_intel_state(address) + var/reject_bad_intel = CONFIG_GET(flag/ipintel_reject_bad) + var/reject_unknown_intel = CONFIG_GET(flag/ipintel_reject_unknown) + var/reject_rate_limited = CONFIG_GET(flag/ipintel_reject_rate_limited) + + var/connection_rejected = FALSE + var/datum/ip_intel/intel = SSipintel.cached_queries[address] + switch(intel_state) + if(IPINTEL_BAD_IP) + log_access("IPINTEL: [ckey] was flagged as a VPN with [intel.result * 100]% likelihood.") + if(reject_bad_intel) + to_chat_immediate(src, span_boldnotice("Your connection has been detected as a VPN.")) + connection_rejected = TRUE + else + message_admins("IPINTEL: [key_name_admin(src)] has been flagged as a VPN with [intel.result * 100]% likelihood.") + + if(IPINTEL_RATE_LIMITED_DAY, IPINTEL_RATE_LIMITED_MINUTE) + log_access("IPINTEL: [ckey] was unable to be checked due to the rate limit.") + if(reject_rate_limited) + to_chat_immediate(src, span_boldnotice("New connections are not being allowed at this time.")) + connection_rejected = TRUE + else + message_admins("IPINTEL: [key_name_admin(src)] was unable to be checked due to rate limiting.") + + if(IPINTEL_UNKNOWN_INTERNAL_ERROR, IPINTEL_UNKNOWN_QUERY_ERROR) + log_access("IPINTEL: [ckey] unable to be checked due to an error.") + if(reject_unknown_intel) + to_chat_immediate(src, span_boldnotice("Your connection cannot be processed at this time.")) + connection_rejected = TRUE + else + message_admins("IPINTEL: [key_name_admin(src)] was unable to be checked due to an error.") + + if(!connection_rejected) + return + + var/list/contact_where = list() + var/forum_url = CONFIG_GET(string/forumurl) + if(forum_url) + contact_where += list("Forums") + var/appeal_url = CONFIG_GET(string/banappeals) + if(appeal_url) + contact_where += list("Ban Appeals") + + var/message_string = "Your connection has been rejected at this time. If you believe this is in error or have any questions please contact an admin" + if(length(contact_where)) + message_string += " at [english_list(contact_where)]" + else + message_string += " somehow." + message_string += "." + + to_chat_immediate(src, span_userdanger(message_string)) + qdel(src) diff --git a/code/controllers/subsystem/language.dm b/code/controllers/subsystem/language.dm deleted file mode 100644 index 88e92e2f93c5f..0000000000000 --- a/code/controllers/subsystem/language.dm +++ /dev/null @@ -1,17 +0,0 @@ -SUBSYSTEM_DEF(language) - name = "Language" - init_order = INIT_ORDER_LANGUAGE - flags = SS_NO_FIRE - -/datum/controller/subsystem/language/Initialize() - for(var/datum/language/language as anything in subtypesof(/datum/language)) - if(!initial(language.key)) - continue - - GLOB.all_languages += language - GLOB.language_types_by_name[initial(language.name)] = language - - var/datum/language/instance = new language - GLOB.language_datum_instances[language] = instance - - return SS_INIT_SUCCESS diff --git a/code/controllers/subsystem/lua.dm b/code/controllers/subsystem/lua.dm index b9ad7dc1644e3..1ab88a01746b7 100644 --- a/code/controllers/subsystem/lua.dm +++ b/code/controllers/subsystem/lua.dm @@ -53,7 +53,7 @@ SUBSYSTEM_DEF(lua) world.SetConfig("env", "LUAU_PATH", jointext(lua_path, ";")) /datum/controller/subsystem/lua/Shutdown() - AUXTOOLS_SHUTDOWN(AUXLUA) + AUXTOOLS_FULL_SHUTDOWN(AUXLUA) /datum/controller/subsystem/lua/proc/queue_resume(datum/lua_state/state, index, arguments) if(!initialized) diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index d010e3f95b5e0..041359006797b 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -643,46 +643,38 @@ GLOBAL_LIST_EMPTY(the_station_areas) holodeck_templates[holo_template.template_id] = holo_template -//Manual loading of away missions. -/client/proc/admin_away() - set name = "Load Away Mission" - set category = "Admin.Events" - - if(!holder || !check_rights(R_FUN)) - return - - +ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away mission for the station.", ADMIN_CATEGORY_EVENTS) if(!GLOB.the_gateway) - if(tgui_alert(usr, "There's no home gateway on the station. You sure you want to continue ?", "Uh oh", list("Yes", "No")) != "Yes") + if(tgui_alert(user, "There's no home gateway on the station. You sure you want to continue ?", "Uh oh", list("Yes", "No")) != "Yes") return var/list/possible_options = GLOB.potentialRandomZlevels + "Custom" var/away_name var/datum/space_level/away_level var/secret = FALSE - if(tgui_alert(usr, "Do you want your mission secret? (This will prevent ghosts from looking at your map in any way other than through a living player's eyes.)", "Are you $$$ekret?", list("Yes", "No")) == "Yes") + if(tgui_alert(user, "Do you want your mission secret? (This will prevent ghosts from looking at your map in any way other than through a living player's eyes.)", "Are you $$$ekret?", list("Yes", "No")) == "Yes") secret = TRUE - var/answer = input("What kind?","Away") as null|anything in possible_options + var/answer = input(user, "What kind?","Away") as null|anything in possible_options switch(answer) if("Custom") - var/mapfile = input("Pick file:", "File") as null|file + var/mapfile = input(user, "Pick file:", "File") as null|file if(!mapfile) return away_name = "[mapfile] custom" - to_chat(usr,span_notice("Loading [away_name]...")) + to_chat(user,span_notice("Loading [away_name]...")) var/datum/map_template/template = new(mapfile, "Away Mission") away_level = template.load_new_z(secret) else if(answer in GLOB.potentialRandomZlevels) away_name = answer - to_chat(usr,span_notice("Loading [away_name]...")) + to_chat(user,span_notice("Loading [away_name]...")) var/datum/map_template/template = new(away_name, "Away Mission") away_level = template.load_new_z(secret) else return - message_admins("Admin [key_name_admin(usr)] has loaded [away_name] away mission.") - log_admin("Admin [key_name(usr)] has loaded [away_name] away mission.") + message_admins("Admin [key_name_admin(user)] has loaded [away_name] away mission.") + log_admin("Admin [key_name(user)] has loaded [away_name] away mission.") if(!away_level) message_admins("Loading [away_name] failed!") return diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm index 25efd8695dca0..3a704d01a82fd 100644 --- a/code/controllers/subsystem/materials.dm +++ b/code/controllers/subsystem/materials.dm @@ -4,7 +4,6 @@ Materials are now instanced datums, with an associative list of them being kept These materials call on_applied() on whatever item they are applied to, common effects are adding components, changing color and changing description. This allows us to differentiate items based on the material they are made out of.area */ - SUBSYSTEM_DEF(materials) name = "Materials" flags = SS_NO_FIRE | SS_NO_INIT @@ -22,15 +21,15 @@ SUBSYSTEM_DEF(materials) var/list/list/material_combos ///List of stackcrafting recipes for materials using base recipes var/list/base_stack_recipes = list( - new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("Sink Frame", /obj/structure/sinkframe, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("Material floor tile", /obj/item/stack/tile/material, 1, 4, 20, applies_mats = TRUE, check_density = FALSE, category = CAT_TILES), - new /datum/stack_recipe("Material airlock assembly", /obj/structure/door_assembly/door_assembly_material, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), + new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE), + new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE), + new /datum/stack_recipe("Sink Frame", /obj/structure/sinkframe, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE), + new /datum/stack_recipe("Material floor tile", /obj/item/stack/tile/material, 1, 4, 20, crafting_flags = CRAFT_APPLIES_MATS, category = CAT_TILES), + new /datum/stack_recipe("Material airlock assembly", /obj/structure/door_assembly/door_assembly_material, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), ) ///List of stackcrafting recipes for materials using rigid recipes var/list/rigid_stack_recipes = list( - new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_STRUCTURE), + new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_STRUCTURE), ) ///A list of dimensional themes used by the dimensional anomaly and other things, most of which require materials to function. diff --git a/code/controllers/subsystem/movement/cliff_falling.dm b/code/controllers/subsystem/movement/cliff_falling.dm index 80e2f236eb716..b3d7f114dfba6 100644 --- a/code/controllers/subsystem/movement/cliff_falling.dm +++ b/code/controllers/subsystem/movement/cliff_falling.dm @@ -10,7 +10,7 @@ MOVEMENT_SUBSYSTEM_DEF(cliff_falling) /datum/controller/subsystem/movement/cliff_falling/proc/start_falling(atom/movable/faller, turf/open/cliff/cliff) // Make them move - var/mover = SSmove_manager.move(moving = faller, direction = cliff.fall_direction, delay = cliff.fall_speed, subsystem = src, priority = MOVEMENT_ABOVE_SPACE_PRIORITY, flags = MOVEMENT_LOOP_OUTSIDE_CONTROL | MOVEMENT_LOOP_NO_DIR_UPDATE) + var/mover = GLOB.move_manager.move(moving = faller, direction = cliff.fall_direction, delay = cliff.fall_speed, subsystem = src, priority = MOVEMENT_ABOVE_SPACE_PRIORITY, flags = MOVEMENT_LOOP_OUTSIDE_CONTROL | MOVEMENT_LOOP_NO_DIR_UPDATE) cliff_grinders[faller] = mover diff --git a/code/controllers/subsystem/movement/movement_types.dm b/code/controllers/subsystem/movement/movement_types.dm index ebb12c84e4bc0..50864f731e21a 100644 --- a/code/controllers/subsystem/movement/movement_types.dm +++ b/code/controllers/subsystem/movement/movement_types.dm @@ -162,7 +162,7 @@ status &= ~MOVELOOP_STATUS_PAUSED ///Removes the atom from some movement subsystem. Defaults to SSmovement -/datum/controller/subsystem/move_manager/proc/stop_looping(atom/movable/moving, datum/controller/subsystem/movement/subsystem = SSmovement) +/datum/move_manager/proc/stop_looping(atom/movable/moving, datum/controller/subsystem/movement/subsystem = SSmovement) var/datum/movement_packet/our_info = moving.move_packet if(!our_info) return FALSE @@ -183,7 +183,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/move(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/move(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/move, priority, flags, extra_info, delay, timeout, direction) ///Replacement for walk() @@ -224,7 +224,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/force_move_dir(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/force_move_dir(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/move/force, priority, flags, extra_info, delay, timeout, direction) /datum/move_loop/move/force @@ -281,7 +281,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/force_move(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/force_move(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/has_target/force_move, priority, flags, extra_info, delay, timeout, chasing) ///Used for force-move loops @@ -315,7 +315,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/jps_move(moving, +/datum/move_manager/proc/jps_move(moving, chasing, delay, timeout, @@ -493,7 +493,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/move_to(moving, chasing, min_dist, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/move_to(moving, chasing, min_dist, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/has_target/dist_bound/move_to, priority, flags, extra_info, delay, timeout, chasing, min_dist) ///Wrapper around walk_to() @@ -527,7 +527,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/move_away(moving, chasing, max_dist, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/move_away(moving, chasing, max_dist, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/has_target/dist_bound/move_away, priority, flags, extra_info, delay, timeout, chasing, max_dist) ///Wrapper around walk_away() @@ -562,7 +562,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/move_towards(moving, chasing, delay, home, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/move_towards(moving, chasing, delay, home, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/has_target/move_towards, priority, flags, extra_info, delay, timeout, chasing, home) /** @@ -581,7 +581,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/home_onto(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/home_onto(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info) return move_towards(moving, chasing, delay, TRUE, timeout, subsystem, priority, flags, extra_info) ///Used as a alternative to walk_towards @@ -717,7 +717,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/move_towards_legacy(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/move_towards_legacy(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/has_target/move_towards_budget, priority, flags, extra_info, delay, timeout, chasing) ///The actual implementation of walk_towards() @@ -743,7 +743,7 @@ * priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm */ -/datum/controller/subsystem/move_manager/proc/freeze(moving, halted_turf, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/freeze(moving, halted_turf, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/freeze, priority, flags, extra_info, delay, timeout, halted_turf) /// As close as you can get to a "do-nothing" move loop, the pure intention of this is to absolutely resist all and any automated movement until the move loop times out. @@ -767,7 +767,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/move_rand(moving, directions, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/move_rand(moving, directions, delay, timeout, subsystem, priority, flags, datum/extra_info) if(!directions) directions = GLOB.alldirs return add_to_loop(moving, subsystem, /datum/move_loop/move_rand, priority, flags, extra_info, delay, timeout, directions) @@ -819,7 +819,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/move_to_rand(moving, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/move_to_rand(moving, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/move_to_rand, priority, flags, extra_info, delay, timeout) ///Wrapper around step_rand @@ -845,7 +845,7 @@ * flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm * **/ -/datum/controller/subsystem/move_manager/proc/move_disposals(moving, delay, timeout, subsystem, priority, flags, datum/extra_info) +/datum/move_manager/proc/move_disposals(moving, delay, timeout, subsystem, priority, flags, datum/extra_info) return add_to_loop(moving, subsystem, /datum/move_loop/disposal_holder, priority, flags, extra_info, delay, timeout) /// Disposal holders need to move through a chain of pipes diff --git a/code/controllers/subsystem/pai.dm b/code/controllers/subsystem/pai.dm index 58f4eda0a05e7..e3d47a5c0cd6b 100644 --- a/code/controllers/subsystem/pai.dm +++ b/code/controllers/subsystem/pai.dm @@ -17,6 +17,11 @@ SUBSYSTEM_DEF(pai) ui.open() ui.set_autoupdate(FALSE) +/datum/controller/subsystem/pai/Recover() + . = ..() + candidates = SSpai.candidates + pai_card_list = SSpai.pai_card_list + /datum/controller/subsystem/pai/ui_state(mob/user) return GLOB.observer_state @@ -35,13 +40,14 @@ SUBSYSTEM_DEF(pai) . = ..() if(.) return TRUE - var/datum/pai_candidate/candidate = candidates[usr.ckey] - if(is_banned_from(usr.ckey, ROLE_PAI)) - to_chat(usr, span_warning("You are banned from playing pAI!")) + var/mob/user = ui.user + var/datum/pai_candidate/candidate = candidates[user.ckey] + if(is_banned_from(user.ckey, ROLE_PAI)) + to_chat(user, span_warning("You are banned from playing pAI!")) ui.close() return FALSE if(isnull(candidate)) - to_chat(usr, span_warning("There was an error. Please resubmit.")) + to_chat(user, span_warning("There was an error. Please resubmit.")) ui.close() return FALSE switch(action) @@ -49,19 +55,19 @@ SUBSYSTEM_DEF(pai) candidate.comments = trim(params["comments"], MAX_BROADCAST_LEN) candidate.description = trim(params["description"], MAX_BROADCAST_LEN) candidate.name = trim(params["name"], MAX_NAME_LEN) - candidate.ckey = usr.ckey + candidate.ckey = user.ckey candidate.ready = TRUE ui.close() - submit_alert() + submit_alert(user) return TRUE if("save") candidate.comments = params["comments"] candidate.description = params["description"] candidate.name = params["name"] - candidate.savefile_save(usr) + candidate.savefile_save(user) return TRUE if("load") - candidate.savefile_load(usr) + candidate.savefile_load(user) ui.send_full_update() return TRUE return FALSE @@ -84,14 +90,14 @@ SUBSYSTEM_DEF(pai) /** * Pings all pAI cards on the station that new candidates are available. */ -/datum/controller/subsystem/pai/proc/submit_alert() +/datum/controller/subsystem/pai/proc/submit_alert(mob/user) if(submit_spam) - to_chat(usr, span_warning("Your candidacy has been submitted, but pAI cards have been alerted too recently.")) + to_chat(user, span_warning("Your candidacy has been submitted, but pAI cards have been alerted too recently.")) return FALSE submit_spam = TRUE for(var/obj/item/pai_card/pai_card as anything in pai_card_list) if(!pai_card.pai) pai_card.alert_update() - to_chat(usr, span_notice("Your pAI candidacy has been submitted!")) - addtimer(VARSET_CALLBACK(src, submit_spam, FALSE), PAI_SPAM_TIME, TIMER_UNIQUE | TIMER_STOPPABLE | TIMER_CLIENT_TIME | TIMER_DELETE_ME) + to_chat(user, span_notice("Your pAI candidacy has been submitted!")) + addtimer(VARSET_CALLBACK(src, submit_spam, FALSE), PAI_SPAM_TIME, TIMER_UNIQUE|TIMER_DELETE_ME) return TRUE diff --git a/code/controllers/subsystem/polling.dm b/code/controllers/subsystem/polling.dm index e48dddfe3f0ab..cbbcca59fa6e2 100644 --- a/code/controllers/subsystem/polling.dm +++ b/code/controllers/subsystem/polling.dm @@ -79,13 +79,13 @@ SUBSYSTEM_DEF(polling) for(var/mob/candidate_mob as anything in group) if(!candidate_mob.client) continue - // Universal opt-out for all players if it's for a role. - if(role && (!candidate_mob.client.prefs.read_preference(/datum/preference/toggle/ghost_roles))) + // Universal opt-out for all players. + if(!candidate_mob.client.prefs.read_preference(/datum/preference/toggle/ghost_roles)) continue // Opt-out for admins whom are currently adminned. - if(role && (!candidate_mob.client.prefs.read_preference(/datum/preference/toggle/ghost_roles_as_admin)) && candidate_mob.client.holder) + if((!candidate_mob.client.prefs.read_preference(/datum/preference/toggle/ghost_roles_as_admin)) && candidate_mob.client.holder) continue - if(role && !is_eligible(candidate_mob, role, check_jobban, ignore_category)) + if(!is_eligible(candidate_mob, role, check_jobban, ignore_category)) continue if(start_signed_up) diff --git a/code/controllers/subsystem/processing/aura.dm b/code/controllers/subsystem/processing/aura.dm new file mode 100644 index 0000000000000..12a7d511fb795 --- /dev/null +++ b/code/controllers/subsystem/processing/aura.dm @@ -0,0 +1,5 @@ +/// The subsystem used to tick auras ([/datum/component/aura_healing] and [/datum/component/damage_aura]). +PROCESSING_SUBSYSTEM_DEF(aura) + name = "Aura" + flags = SS_NO_INIT | SS_BACKGROUND | SS_KEEP_TIMING + wait = 0.3 SECONDS diff --git a/code/controllers/subsystem/processing/aura_healing.dm b/code/controllers/subsystem/processing/aura_healing.dm deleted file mode 100644 index ad3fa6f4278c0..0000000000000 --- a/code/controllers/subsystem/processing/aura_healing.dm +++ /dev/null @@ -1,5 +0,0 @@ -/// The subsystem used to tick [/datum/component/aura_healing] instances. -PROCESSING_SUBSYSTEM_DEF(aura_healing) - name = "Aura Healing" - flags = SS_NO_INIT | SS_BACKGROUND | SS_KEEP_TIMING - wait = 0.3 SECONDS diff --git a/code/controllers/subsystem/processing/obj_tab_items.dm b/code/controllers/subsystem/processing/obj_tab_items.dm deleted file mode 100644 index 53786daf0117e..0000000000000 --- a/code/controllers/subsystem/processing/obj_tab_items.dm +++ /dev/null @@ -1,24 +0,0 @@ -PROCESSING_SUBSYSTEM_DEF(obj_tab_items) - name = "Obj Tab Items" - flags = SS_NO_INIT - runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - wait = 0.1 SECONDS - -// I know this is mostly copypasta, but I want to change the processing logic -// Sorry bestie :( -/datum/controller/subsystem/processing/obj_tab_items/fire(resumed = FALSE) - if (!resumed) - currentrun = processing.Copy() - //cache for sanic speed (lists are references anyways) - var/list/current_run = currentrun - - while(current_run.len) - var/datum/thing = current_run[current_run.len] - if(QDELETED(thing)) - processing -= thing - else if(thing.process(wait * 0.1) == PROCESS_KILL) - // fully stop so that a future START_PROCESSING will work - STOP_PROCESSING(src, thing) - if (MC_TICK_CHECK) - return - current_run.len-- diff --git a/code/controllers/subsystem/sprite_accessories.dm b/code/controllers/subsystem/sprite_accessories.dm new file mode 100644 index 0000000000000..ec5934ac8e8d4 --- /dev/null +++ b/code/controllers/subsystem/sprite_accessories.dm @@ -0,0 +1,154 @@ +/// The non gender specific list that we get from init_sprite_accessory_subtypes() +#define DEFAULT_SPRITE_LIST "default_sprites" +/// The male specific list that we get from init_sprite_accessory_subtypes() +#define MALE_SPRITE_LIST "male_sprites" +/// The female specific list that we get from init_sprite_accessory_subtypes() +#define FEMALE_SPRITE_LIST "female_sprites" + +/// subsystem that just holds lists of sprite accessories for accession in generating said sprites. +/// A sprite accessory is something that we add to a human sprite to make them look different. This is hair, facial hair, underwear, mutant bits, etc. +SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity + name = "Sprite Accessories" + flags = SS_NO_FIRE | SS_NO_INIT + + //Hairstyles + var/list/hairstyles_list //! stores /datum/sprite_accessory/hair indexed by name + var/list/hairstyles_male_list //! stores only hair names + var/list/hairstyles_female_list //! stores only hair names + var/list/facial_hairstyles_list //! stores /datum/sprite_accessory/facial_hair indexed by name + var/list/facial_hairstyles_male_list //! stores only hair names + var/list/facial_hairstyles_female_list //! stores only hair names + var/list/hair_gradients_list //! stores /datum/sprite_accessory/hair_gradient indexed by name + var/list/facial_hair_gradients_list //! stores /datum/sprite_accessory/facial_hair_gradient indexed by name + + //Underwear + var/list/underwear_list //! stores /datum/sprite_accessory/underwear indexed by name + var/list/underwear_m //! stores only underwear name + var/list/underwear_f //! stores only underwear name + + //Undershirts + var/list/undershirt_list //! stores /datum/sprite_accessory/undershirt indexed by name + var/list/undershirt_m //! stores only undershirt name + var/list/undershirt_f //! stores only undershirt name + + //Socks + var/list/socks_list //! stores /datum/sprite_accessory/socks indexed by name + + //Lizard Bits (all datum lists indexed by name) + var/list/body_markings_list + var/list/snouts_list + var/list/horns_list + var/list/frills_list + var/list/spines_list + var/list/legs_list + var/list/tail_spines_list + + //Mutant Human bits + var/list/tails_list_human + var/list/tails_list_lizard + var/list/tails_list_monkey + var/list/ears_list + var/list/wings_list + var/list/wings_open_list + var/list/moth_wings_list + var/list/moth_antennae_list + var/list/moth_markings_list + var/list/caps_list + var/list/pod_hair_list + +/datum/controller/subsystem/accessories/PreInit() // this stuff NEEDS to be set up before GLOB for preferences and stuff to work so this must go here. sorry + setup_lists() + init_hair_gradients() + +/// Sets up all of the lists for later utilization in the round and building sprites. +/// In an ideal world we could tack everything that just needed `DEFAULT_SPRITE_LIST` into static variables on the top, but due to the initialization order +/// where this subsystem will initialize BEFORE statics, it's just not feasible since this all needs to be ready for actual subsystems to use. +/// Sorry. +/datum/controller/subsystem/accessories/proc/setup_lists() + var/hair_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/hair) + hairstyles_list = hair_lists[DEFAULT_SPRITE_LIST] + hairstyles_male_list = hair_lists[MALE_SPRITE_LIST] + hairstyles_female_list = hair_lists[FEMALE_SPRITE_LIST] + + var/facial_hair_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair) + facial_hairstyles_list = facial_hair_lists[DEFAULT_SPRITE_LIST] + facial_hairstyles_male_list = facial_hair_lists[MALE_SPRITE_LIST] + facial_hairstyles_female_list = facial_hair_lists[FEMALE_SPRITE_LIST] + + var/underwear_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear) + underwear_list = underwear_lists[DEFAULT_SPRITE_LIST] + underwear_m = underwear_lists[MALE_SPRITE_LIST] + underwear_f = underwear_lists[FEMALE_SPRITE_LIST] + + var/undershirt_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt) + undershirt_list = undershirt_lists[DEFAULT_SPRITE_LIST] + undershirt_m = undershirt_lists[MALE_SPRITE_LIST] + undershirt_f = undershirt_lists[FEMALE_SPRITE_LIST] + + socks_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/socks)[DEFAULT_SPRITE_LIST] + + body_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings)[DEFAULT_SPRITE_LIST] + tails_list_human = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, add_blank = TRUE)[DEFAULT_SPRITE_LIST] + tails_list_lizard = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, add_blank = TRUE)[DEFAULT_SPRITE_LIST] + tails_list_monkey = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, add_blank = TRUE)[DEFAULT_SPRITE_LIST] + snouts_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts)[DEFAULT_SPRITE_LIST] + horns_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/horns)[DEFAULT_SPRITE_LIST] + ears_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/ears)[DEFAULT_SPRITE_LIST] + wings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/wings)[DEFAULT_SPRITE_LIST] + wings_open_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open)[DEFAULT_SPRITE_LIST] + frills_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/frills)[DEFAULT_SPRITE_LIST] + spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/spines)[DEFAULT_SPRITE_LIST] + tail_spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/tail_spines)[DEFAULT_SPRITE_LIST] + legs_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/legs)[DEFAULT_SPRITE_LIST] + caps_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/caps)[DEFAULT_SPRITE_LIST] + moth_wings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings)[DEFAULT_SPRITE_LIST] + moth_antennae_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae)[DEFAULT_SPRITE_LIST] + moth_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings)[DEFAULT_SPRITE_LIST] + pod_hair_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair)[DEFAULT_SPRITE_LIST] + +/// This proc just intializes all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name +/datum/controller/subsystem/accessories/proc/init_hair_gradients() + hair_gradients_list = list() + facial_hair_gradients_list = list() + for(var/path in subtypesof(/datum/sprite_accessory/gradient)) + var/datum/sprite_accessory/gradient/gradient = new path + if(gradient.gradient_category & GRADIENT_APPLIES_TO_HAIR) + hair_gradients_list[gradient.name] = gradient + if(gradient.gradient_category & GRADIENT_APPLIES_TO_FACIAL_HAIR) + facial_hair_gradients_list[gradient.name] = gradient + +/// This reads the applicable sprite accessory datum's subtypes and adds it to the subsystem's list of sprite accessories. +/// The boolean `add_blank` argument just adds a "None" option to the list of sprite accessories, like if a felinid doesn't want a tail or something, typically good for gated-off things. +/datum/controller/subsystem/accessories/proc/init_sprite_accessory_subtypes(prototype, add_blank = FALSE) + RETURN_TYPE(/list) + var/returnable_list = list( + DEFAULT_SPRITE_LIST = list(), + MALE_SPRITE_LIST = list(), + FEMALE_SPRITE_LIST = list(), + ) + + for(var/path in subtypesof(prototype)) + var/datum/sprite_accessory/accessory = new path + + if(accessory.icon_state) + returnable_list[DEFAULT_SPRITE_LIST][accessory.name] = accessory + else + returnable_list[DEFAULT_SPRITE_LIST] += accessory.name + + switch(accessory.gender) + if(MALE) + returnable_list[MALE_SPRITE_LIST] += accessory.name + if(FEMALE) + returnable_list[FEMALE_SPRITE_LIST] += accessory.name + else + returnable_list[MALE_SPRITE_LIST] += accessory.name + returnable_list[FEMALE_SPRITE_LIST] += accessory.name + + if(add_blank) + returnable_list[DEFAULT_SPRITE_LIST][SPRITE_ACCESSORY_NONE] = new /datum/sprite_accessory/blank + + return returnable_list + +#undef DEFAULT_SPRITE_LIST +#undef MALE_SPRITE_LIST +#undef FEMALE_SPRITE_LIST diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 317fb73852a8a..020598a573b67 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -88,12 +88,6 @@ SUBSYSTEM_DEF(statpanels) if(update_actions && num_fires % default_wait == 0) set_action_tabs(target, target_mob) - // Handle the examined turf of the stat panel, if it's been long enough, or if we've generated new images for it - var/turf/listed_turf = target_mob?.listed_turf - if(listed_turf && num_fires % default_wait == 0) - if(target.stat_tab == listed_turf.name || !(listed_turf.name in target.panel_tabs)) - set_turf_examine_tab(target, target_mob) - if(MC_TICK_CHECK) return @@ -166,71 +160,6 @@ SUBSYSTEM_DEF(statpanels) target.stat_panel.send_message("update_spells", list(spell_tabs = target.spell_tabs, actions = actions)) -/datum/controller/subsystem/statpanels/proc/set_turf_examine_tab(client/target, mob/target_mob) - var/list/overrides = list() - for(var/image/target_image as anything in target.images) - if(!target_image.loc || target_image.loc.loc != target_mob.listed_turf || !target_image.override) - continue - overrides += target_image.loc - - var/list/atoms_to_display = list(target_mob.listed_turf) - for(var/atom/movable/turf_content as anything in target_mob.listed_turf) - if(turf_content.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) - continue - if(turf_content.invisibility > target_mob.see_invisible) - continue - if(turf_content in overrides) - continue - if(turf_content.IsObscured()) - continue - atoms_to_display += turf_content - - /// Set the atoms we're meant to display - var/datum/object_window_info/obj_window = target.obj_window - obj_window.atoms_to_show = atoms_to_display - START_PROCESSING(SSobj_tab_items, obj_window) - refresh_client_obj_view(target) - -/datum/controller/subsystem/statpanels/proc/refresh_client_obj_view(client/refresh) - var/list/turf_items = return_object_images(refresh) - if(!length(turf_items) || !refresh.mob?.listed_turf) - return - refresh.stat_panel.send_message("update_listedturf", turf_items) - -#define OBJ_IMAGE_LOADING "statpanels obj loading temporary" -/// Returns all our ready object tab images -/// Returns a list in the form list(list(object_name, object_ref, loaded_image), ...) -/datum/controller/subsystem/statpanels/proc/return_object_images(client/load_from) - // You might be inclined to think that this is a waste of cpu time, since we - // A: Double iterate over atoms in the build case, or - // B: Generate these lists over and over in the refresh case - // It's really not very hot. The hot portion of this code is genuinely mostly in the image generation - // So it's ok to pay a performance cost for cleanliness here - - // No turf? go away - if(!load_from.mob?.listed_turf) - return list() - var/datum/object_window_info/obj_window = load_from.obj_window - var/list/already_seen = obj_window.atoms_to_images - var/list/to_make = obj_window.atoms_to_imagify - var/list/turf_items = list() - for(var/atom/turf_item as anything in obj_window.atoms_to_show) - // First, we fill up the list of refs to display - // If we already have one, just use that - var/existing_image = already_seen[turf_item] - if(existing_image == OBJ_IMAGE_LOADING) - continue - // We already have it. Success! - if(existing_image) - turf_items[++turf_items.len] = list("[turf_item.name]", REF(turf_item), existing_image) - continue - // Now, we're gonna queue image generation out of those refs - to_make += turf_item - already_seen[turf_item] = OBJ_IMAGE_LOADING - obj_window.RegisterSignal(turf_item, COMSIG_QDELETING, TYPE_PROC_REF(/datum/object_window_info,viewing_atom_deleted)) // we reset cache if anything in it gets deleted - return turf_items - -#undef OBJ_IMAGE_LOADING /datum/controller/subsystem/statpanels/proc/generate_mc_data() mc_data = list( @@ -272,16 +201,6 @@ SUBSYSTEM_DEF(statpanels) set_action_tabs(target, target_mob) return TRUE - // Handle turfs - - if(target_mob?.listed_turf) - if(!target_mob.TurfAdjacent(target_mob.listed_turf)) - target_mob.set_listed_turf(null) - - else if(target.stat_tab == target_mob?.listed_turf.name || !(target_mob?.listed_turf.name in target.panel_tabs)) - set_turf_examine_tab(target, target_mob) - return TRUE - if(!target.holder) return FALSE @@ -301,105 +220,3 @@ SUBSYSTEM_DEF(statpanels) /// Stat panel window declaration /client/var/datum/tgui_window/stat_panel - -/// Datum that holds and tracks info about a client's object window -/// Really only exists because I want to be able to do logic with signals -/// And need a safe place to do the registration -/datum/object_window_info - /// list of atoms to show to our client via the object tab, at least currently - var/list/atoms_to_show = list() - /// list of atom -> image string for objects we have had in the right click tab - /// this is our caching - var/list/atoms_to_images = list() - /// list of atoms to turn into images for the object tab - var/list/atoms_to_imagify = list() - /// Our owner client - var/client/parent - /// Are we currently tracking a turf? - var/actively_tracking = FALSE - -/datum/object_window_info/New(client/parent) - . = ..() - src.parent = parent - -/datum/object_window_info/Destroy(force) - atoms_to_show = null - atoms_to_images = null - atoms_to_imagify = null - parent.obj_window = null - parent = null - STOP_PROCESSING(SSobj_tab_items, src) - return ..() - -/// Takes a client, attempts to generate object images for it -/// We will update the client with any improvements we make when we're done -/datum/object_window_info/process(seconds_per_tick) - // Cache the datum access for sonic speed - var/list/to_make = atoms_to_imagify - var/list/newly_seen = atoms_to_images - var/index = 0 - for(index in 1 to length(to_make)) - var/atom/thing = to_make[index] - - var/generated_string - if(ismob(thing) || length(thing.overlays) > 2) - generated_string = costly_icon2html(thing, parent, sourceonly=TRUE) - else - generated_string = icon2html(thing, parent, sourceonly=TRUE) - - newly_seen[thing] = generated_string - if(TICK_CHECK) - to_make.Cut(1, index + 1) - index = 0 - break - // If we've not cut yet, do it now - if(index) - to_make.Cut(1, index + 1) - SSstatpanels.refresh_client_obj_view(parent) - if(!length(to_make)) - return PROCESS_KILL - -/datum/object_window_info/proc/start_turf_tracking() - if(actively_tracking) - stop_turf_tracking() - var/static/list/connections = list( - COMSIG_MOVABLE_MOVED = PROC_REF(on_mob_move), - COMSIG_MOB_LOGOUT = PROC_REF(on_mob_logout), - ) - AddComponent(/datum/component/connect_mob_behalf, parent, connections) - actively_tracking = TRUE - -/datum/object_window_info/proc/stop_turf_tracking() - qdel(GetComponent(/datum/component/connect_mob_behalf)) - actively_tracking = FALSE - -/datum/object_window_info/proc/on_mob_move(mob/source) - SIGNAL_HANDLER - var/turf/listed = source.listed_turf - if(!listed || !source.TurfAdjacent(listed)) - source.set_listed_turf(null) - -/datum/object_window_info/proc/on_mob_logout(mob/source) - SIGNAL_HANDLER - on_mob_move(parent.mob) - -/// Clears any cached object window stuff -/// We use hard refs cause we'd need a signal for this anyway. Cleaner this way -/datum/object_window_info/proc/viewing_atom_deleted(atom/deleted) - SIGNAL_HANDLER - atoms_to_show -= deleted - atoms_to_imagify -= deleted - atoms_to_images -= deleted - -/mob/proc/set_listed_turf(turf/new_turf) - listed_turf = new_turf - if(!client) - return - if(!client.obj_window) - client.obj_window = new(client) - if(listed_turf) - client.stat_panel.send_message("create_listedturf", listed_turf.name) - client.obj_window.start_turf_tracking() - else - client.stat_panel.send_message("remove_listedturf") - client.obj_window.stop_turf_tracking() diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm index c12c1b2bb327b..cd03e1f3e5225 100644 --- a/code/controllers/subsystem/tgui.dm +++ b/code/controllers/subsystem/tgui.dm @@ -122,8 +122,6 @@ SUBSYSTEM_DEF(tgui) for(var/datum/tgui/ui in user.tgui_open_uis) if(ui.window && ui.window.id == window_id) ui.close(can_be_suspended = FALSE) - // Unset machine just to be sure. - user.unset_machine() // Close window directly just to be sure. user << browse(null, "window=[window_id]") diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index ac2b669762c14..468882f0e86ec 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -88,7 +88,7 @@ SUBSYSTEM_DEF(ticker) var/use_rare_music = prob(1) for(var/S in provisional_title_music) - var/lower = lowertext(S) + var/lower = LOWER_TEXT(S) var/list/L = splittext(lower,"+") switch(L.len) if(3) //rare+MAP+sound.ogg or MAP+rare.sound.ogg -- Rare Map-specific sounds @@ -112,7 +112,7 @@ SUBSYSTEM_DEF(ticker) for(var/S in music) var/list/L = splittext(S,".") if(L.len >= 2) - var/ext = lowertext(L[L.len]) //pick the real extension, no 'honk.ogg.exe' nonsense here + var/ext = LOWER_TEXT(L[L.len]) //pick the real extension, no 'honk.ogg.exe' nonsense here if(byond_sound_formats[ext]) continue music -= S @@ -281,7 +281,7 @@ SUBSYSTEM_DEF(ticker) log_world("Game start took [(world.timeofday - init_start)/10]s") INVOKE_ASYNC(SSdbcore, TYPE_PROC_REF(/datum/controller/subsystem/dbcore,SetRoundStart)) - to_chat(world, span_notice("Welcome to [station_name()], enjoy your stay!")) + to_chat(world, span_notice(span_bold("Welcome to [station_name()], enjoy your stay!"))) SEND_SOUND(world, sound(SSstation.announcer.get_rand_welcome_sound())) current_state = GAME_STATE_PLAYING diff --git a/code/controllers/subsystem/time_track.dm b/code/controllers/subsystem/time_track.dm index ab6d5fb2ed572..aaaf5520e0fc3 100644 --- a/code/controllers/subsystem/time_track.dm +++ b/code/controllers/subsystem/time_track.dm @@ -123,7 +123,7 @@ SUBSYSTEM_DEF(time_track) send_maps_values += packet["value"] send_maps_values += packet["calls"] - SSblackbox.record_feedback("associative", "time_dilation_current", 1, list("[SQLtime()]" = list("current" = "[time_dilation_current]", "avg_fast" = "[time_dilation_avg_fast]", "avg" = "[time_dilation_avg]", "avg_slow" = "[time_dilation_avg_slow]"))) + SSblackbox.record_feedback("associative", "time_dilation_current", 1, list("[ISOtime()]" = list("current" = "[time_dilation_current]", "avg_fast" = "[time_dilation_avg_fast]", "avg" = "[time_dilation_avg]", "avg_slow" = "[time_dilation_avg_slow]"))) log_perf( list( world.time, diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index 0a9a636c9a7f7..1f40dd921dddf 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -25,7 +25,7 @@ SUBSYSTEM_DEF(title) for(var/S in provisional_title_screens) var/list/L = splittext(S,"+") - if((L.len == 1 && (L[1] != "exclude" && L[1] != "blank.png")) || (L.len > 1 && ((use_rare_screens && lowertext(L[1]) == "rare") || (lowertext(L[1]) == lowertext(SSmapping.config.map_name))))) + if((L.len == 1 && (L[1] != "exclude" && L[1] != "blank.png")) || (L.len > 1 && ((use_rare_screens && LOWER_TEXT(L[1]) == "rare") || (LOWER_TEXT(L[1]) == LOWER_TEXT(SSmapping.config.map_name))))) title_screens += S if(length(title_screens)) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 410db36988dd8..b7c26acf375ee 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -18,6 +18,8 @@ SUBSYSTEM_DEF(vote) var/list/voted = list() /// A list of all ckeys currently voting for the current vote. var/list/voting = list() + /// World.time we started our last vote + var/last_vote_time = -INFINITY /datum/controller/subsystem/vote/Initialize() for(var/vote_type in subtypesof(/datum/vote)) @@ -30,16 +32,20 @@ SUBSYSTEM_DEF(vote) return SS_INIT_SUCCESS - // Called by master_controller /datum/controller/subsystem/vote/fire() if(!current_vote) return current_vote.time_remaining = round((current_vote.started_time + CONFIG_GET(number/vote_period) - world.time) / 10) if(current_vote.time_remaining < 0) - process_vote_result() - SStgui.close_uis(src) - reset() + end_vote() + +/// Ends the current vote. +/datum/controller/subsystem/vote/proc/end_vote() + ASSERT(current_vote) + process_vote_result() + SStgui.close_uis(src) + reset() /// Resets all of our vars after votes conclude / are cancelled. /datum/controller/subsystem/vote/proc/reset() @@ -168,24 +174,10 @@ SUBSYSTEM_DEF(vote) * * vote_type - The type of vote to initiate. Can be a [/datum/vote] typepath, a [/datum/vote] instance, or the name of a vote datum. * * vote_initiator_name - The ckey (if player initiated) or name that initiated a vote. Ex: "UristMcAdmin", "the server" * * vote_initiator - If a person / mob initiated the vote, this is the mob that did it - * * forced - Whether we're forcing the vote to go through regardless of existing votes or other circumstances. Note: If the vote is admin created, forced becomes true regardless. + * * forced - Whether we're forcing the vote to go through regardless of existing votes or other circumstances. */ /datum/controller/subsystem/vote/proc/initiate_vote(vote_type, vote_initiator_name, mob/vote_initiator, forced = FALSE) - - // Even if it's forced we can't vote before we're set up - if(!MC_RUNNING(init_stage)) - if(vote_initiator) - to_chat(vote_initiator, span_warning("You cannot start vote now, the server is not done initializing.")) - return FALSE - - // Check if we have unlimited voting power. - // Admin started (or forced) voted will go through even if there's an ongoing vote, - // if voting is on cooldown, or regardless if a vote is config disabled (in some cases) - var/unlimited_vote_power = forced || !!GLOB.admin_datums[vote_initiator?.ckey] - - if(current_vote && !unlimited_vote_power) - if(vote_initiator) - to_chat(vote_initiator, span_warning("There is already a vote in progress! Please wait for it to finish.")) + if(!can_vote_start(vote_initiator, forced)) return FALSE // Get our actual datum @@ -212,7 +204,7 @@ SUBSYSTEM_DEF(vote) return FALSE // Vote can't be initiated in our circumstances? No vote - if(!to_vote.can_be_initiated(vote_initiator, unlimited_vote_power)) + if(to_vote.can_be_initiated(forced) != VOTE_AVAILABLE) return FALSE // Okay, we're ready to actually create a vote - @@ -223,8 +215,12 @@ SUBSYSTEM_DEF(vote) if(!to_vote.create_vote(vote_initiator)) return FALSE + if(!vote_initiator_name && vote_initiator) + vote_initiator_name = vote_initiator.key + // Okay, the vote's happening now, for real. Set it up. current_vote = to_vote + last_vote_time = world.time var/duration = CONFIG_GET(number/vote_period) var/to_display = current_vote.initiate_vote(vote_initiator_name, duration) @@ -248,6 +244,36 @@ SUBSYSTEM_DEF(vote) return TRUE +/** + * Checks if we can start a vote. + * + * * vote_initiator - The mob that initiated the vote. + * * forced - Whether we're forcing the vote to go through regardless of existing votes or other circumstances. + * + * Returns TRUE if we can start a vote, FALSE if we can't. + */ +/datum/controller/subsystem/vote/proc/can_vote_start(mob/vote_initiator, forced) + // Even if it's forced we can't vote before we're set up + if(!MC_RUNNING(init_stage)) + if(vote_initiator) + to_chat(vote_initiator, span_warning("You cannot start a vote now, the server is not done initializing.")) + return FALSE + + if(forced) + return TRUE + + var/next_allowed_time = last_vote_time + CONFIG_GET(number/vote_delay) + if(next_allowed_time > world.time) + if(vote_initiator) + to_chat(vote_initiator, span_warning("A vote was initiated recently. You must wait [DisplayTimeText(next_allowed_time - world.time)] before a new vote can be started!")) + return FALSE + + if(current_vote) + if(vote_initiator) + to_chat(vote_initiator, span_warning("There is already a vote in progress! Please wait for it to finish.")) + return FALSE + + return TRUE /datum/controller/subsystem/vote/ui_state() return GLOB.always_state @@ -282,11 +308,12 @@ SUBSYSTEM_DEF(vote) if(!istype(vote)) continue + var/can_vote = vote.can_be_initiated(is_lower_admin) var/list/vote_data = list( "name" = vote_name, - "canBeInitiated" = vote.can_be_initiated(forced = is_lower_admin), + "canBeInitiated" = can_vote == VOTE_AVAILABLE, "config" = vote.is_config_enabled(), - "message" = vote.message, + "message" = can_vote == VOTE_AVAILABLE ? vote.default_message : can_vote, ) if(vote == current_vote) @@ -310,7 +337,13 @@ SUBSYSTEM_DEF(vote) all_vote_data += list(vote_data) data["possibleVotes"] = all_vote_data + data["LastVoteTime"] = last_vote_time - world.time + + return data +/datum/controller/subsystem/vote/ui_static_data(mob/user) + var/list/data = list() + data["VoteCD"] = CONFIG_GET(number/vote_delay) return data /datum/controller/subsystem/vote/ui_act(action, params) @@ -323,19 +356,37 @@ SUBSYSTEM_DEF(vote) switch(action) if("cancel") if(!voter.client?.holder) + message_admins("[key_name(voter)] tried to cancel the current vote while having no admin holder, \ + this is potentially a malicious exploit and worth noting.") return voter.log_message("cancelled a vote.", LOG_ADMIN) message_admins("[key_name_admin(voter)] has cancelled the current vote.") + SStgui.close_uis(src) reset() return TRUE + if("endNow") + if(!voter.client?.holder) + message_admins("[key_name(voter)] tried to end the current vote while having no admin holder, \ + this is potentially a malicious exploit and worth noting.") + return + + voter.log_message("ended the current vote early", LOG_ADMIN) + message_admins("[key_name_admin(voter)] has ended the current vote.") + end_vote() + return TRUE + if("toggleVote") var/datum/vote/selected = possible_votes[params["voteName"]] if(!istype(selected)) return + if(!check_rights_for(voter.client, R_ADMIN)) + message_admins("[key_name(voter)] tried to toggle vote availability while having improper rights, \ + this is potentially a malicious exploit and worth noting.") + return - return selected.toggle_votable(voter) + return selected.toggle_votable() if("callVote") var/datum/vote/selected = possible_votes[params["voteName"]] @@ -344,7 +395,12 @@ SUBSYSTEM_DEF(vote) // Whether the user actually can initiate this vote is checked in initiate_vote, // meaning you can't spoof initiate a vote you're not supposed to be able to - return initiate_vote(selected, voter.key, voter) + return initiate_vote( + vote_type = selected, + vote_initiator_name = voter.key, + vote_initiator = voter, + forced = !!GLOB.admin_datums[voter.ckey], + ) if("voteSingle") return submit_single_vote(voter, params["voteOption"]) @@ -352,6 +408,15 @@ SUBSYSTEM_DEF(vote) if("voteMulti") return submit_multi_vote(voter, params["voteOption"]) + if("resetCooldown") + if(!voter.client.holder) + message_admins("[key_name(voter)] tried to reset the vote cooldown while having no admin holder, \ + this is potentially a malicious exploit and worth noting.") + return + + last_vote_time = -INFINITY + return TRUE + /datum/controller/subsystem/vote/ui_close(mob/user) voting -= user.client?.ckey @@ -360,6 +425,10 @@ SUBSYSTEM_DEF(vote) set category = "OOC" set name = "Vote" + if(!SSvote.initialized) + to_chat(usr, span_notice("Voting is not set up yet!")) + return + SSvote.ui_interact(usr) /// Datum action given to mobs that allows players to vote on the current vote. diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm index 78c99f4790366..b8496a623eba1 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/weather.dm @@ -86,15 +86,9 @@ SUBSYSTEM_DEF(weather) /datum/controller/subsystem/weather/proc/get_weather_by_type(type) return locate(type) in processing -/** - * Calls end() on all current weather effects that are currently processing in the weather subsystem. - */ -/client/proc/stop_weather() - set category = "Debug" - set name = "Stop All Active Weather" - - log_admin("[key_name(src)] stopped all currently active weather.") - message_admins("[key_name_admin(src)] stopped all currently active weather.") +ADMIN_VERB(stop_weather, R_DEBUG|R_ADMIN, "Stop All Active Weather", "Stop all currently active weather.", ADMIN_CATEGORY_DEBUG) + log_admin("[key_name(user)] stopped all currently active weather.") + message_admins("[key_name_admin(user)] stopped all currently active weather.") for(var/datum/weather/current_weather as anything in SSweather.processing) if(current_weather in SSweather.processing) current_weather.end() diff --git a/code/datums/achievements/misc_achievements.dm b/code/datums/achievements/misc_achievements.dm index e92fc3bc56b91..1d7b9da3a015a 100644 --- a/code/datums/achievements/misc_achievements.dm +++ b/code/datums/achievements/misc_achievements.dm @@ -227,3 +227,8 @@ database_id = MEDAL_DEBT_EXTINGUISHED icon_state = "outdebted" +/datum/award/achievement/misc/sisyphus + name = "Ordeal of Sisyphus" + desc = "Successfully carry a boulder from Lavaland all the way to Centcom, without ever dropping it. We must imagine you're happy to unlock this." + database_id = MEDAL_SISYPHUS + icon_state = "sisyphus" diff --git a/code/datums/actions/mobs/charge.dm b/code/datums/actions/mobs/charge.dm index 3cca055a54106..9aee4cd83456a 100644 --- a/code/datums/actions/mobs/charge.dm +++ b/code/datums/actions/mobs/charge.dm @@ -44,7 +44,7 @@ if(charger in charging) // Stop any existing charging, this'll clean things up properly - SSmove_manager.stop_looping(charger) + GLOB.move_manager.stop_looping(charger) charging += charger actively_moving = FALSE @@ -60,7 +60,7 @@ var/time_to_hit = min(get_dist(charger, target), charge_distance) * charge_speed - var/datum/move_loop/new_loop = SSmove_manager.home_onto(charger, target, delay = charge_speed, timeout = time_to_hit, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/new_loop = GLOB.move_manager.home_onto(charger, target, delay = charge_speed, timeout = time_to_hit, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) if(!new_loop) return RegisterSignal(new_loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move), override = TRUE) @@ -96,7 +96,7 @@ /datum/action/cooldown/mob_cooldown/charge/update_status_on_signal(mob/source, new_stat, old_stat) . = ..() if(new_stat == DEAD) - SSmove_manager.stop_looping(source) //This will cause the loop to qdel, triggering an end to our charging + GLOB.move_manager.stop_looping(source) //This will cause the loop to qdel, triggering an end to our charging /datum/action/cooldown/mob_cooldown/charge/proc/do_charge_indicator(atom/charger, atom/charge_target) var/turf/target_turf = get_turf(charge_target) diff --git a/code/datums/actions/mobs/charge_apc.dm b/code/datums/actions/mobs/charge_apc.dm index 47436beab76cf..8086ba7220793 100644 --- a/code/datums/actions/mobs/charge_apc.dm +++ b/code/datums/actions/mobs/charge_apc.dm @@ -1,5 +1,5 @@ ///how much charge are we giving off to an APC? -#define CHARGE_AMOUNT (80 KILO JOULES) +#define CHARGE_AMOUNT (0.08 * STANDARD_CELL_CHARGE) /datum/action/cooldown/mob_cooldown/charge_apc name = "Charge APCs" diff --git a/code/datums/ai/_ai_behavior.dm b/code/datums/ai/_ai_behavior.dm index 98ab8f2fc7e22..eb8f7370dc298 100644 --- a/code/datums/ai/_ai_behavior.dm +++ b/code/datums/ai/_ai_behavior.dm @@ -5,16 +5,22 @@ ///Flags for extra behavior var/behavior_flags = NONE ///Cooldown between actions performances, defaults to the value of CLICK_CD_MELEE because that seemed like a nice standard for the speed of AI behavior + ///Do not read directly or mutate, instead use get_cooldown() var/action_cooldown = CLICK_CD_MELEE +/// Returns the delay to use for this behavior in the moment +/// Override to return a conditional delay +/datum/ai_behavior/proc/get_cooldown(datum/ai_controller/cooldown_for) + return action_cooldown + /// Called by the ai controller when first being added. Additional arguments depend on the behavior type. /// Return FALSE to cancel /datum/ai_behavior/proc/setup(datum/ai_controller/controller, ...) return TRUE ///Called by the AI controller when this action is performed +///Returns a set of flags defined in [code/__DEFINES/ai/ai.dm] /datum/ai_behavior/proc/perform(seconds_per_tick, datum/ai_controller/controller, ...) - controller.behavior_cooldowns[src] = world.time + action_cooldown return ///Called when the action is finished. This needs the same args as perform besides the default ones diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 91f624972adce..1a981f90aedbd 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -46,6 +46,8 @@ multiple modular subtrees with behaviors ///The idle behavior this AI performs when it has no actions. var/datum/idle_behavior/idle_behavior = null + ///our current cell grid + var/datum/cell_tracker/our_cells // Movement related things here ///Reference to the movement datum we use. Is a type on initialize but becomes a ref afterwards. @@ -56,6 +58,10 @@ multiple modular subtrees with behaviors // The variables below are fucking stupid and should be put into the blackboard at some point. ///AI paused time var/paused_until = 0 + ///Can this AI idle? + var/can_idle = TRUE + ///What distance should we be checking for interesting things when considering idling/deidling? Defaults to AI_DEFAULT_INTERESTING_DIST + var/interesting_dist = AI_DEFAULT_INTERESTING_DIST /datum/ai_controller/New(atom/new_pawn) change_ai_movement_type(ai_movement) @@ -68,8 +74,8 @@ multiple modular subtrees with behaviors PossessPawn(new_pawn) /datum/ai_controller/Destroy(force) - set_ai_status(AI_STATUS_OFF) UnpossessPawn(FALSE) + our_cells = null set_movement_target(type, null) if(ai_movement.moving_controllers[src]) ai_movement.stop_moving_towards(src) @@ -116,36 +122,132 @@ multiple modular subtrees with behaviors pawn = new_pawn pawn.ai_controller = src + var/turf/pawn_turf = get_turf(pawn) + if(pawn_turf) + SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] += src + SEND_SIGNAL(src, COMSIG_AI_CONTROLLER_POSSESSED_PAWN) reset_ai_status() + RegisterSignal(pawn, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_changed_z_level)) RegisterSignal(pawn, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed)) RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) RegisterSignal(pawn, COMSIG_QDELETING, PROC_REF(on_pawn_qdeleted)) + our_cells = new(interesting_dist, interesting_dist, 1) + set_new_cells() + + RegisterSignal(pawn, COMSIG_MOVABLE_MOVED, PROC_REF(update_grid)) + +/datum/ai_controller/proc/update_grid(datum/source, datum/spatial_grid_cell/new_cell) + SIGNAL_HANDLER + + set_new_cells() + +/datum/ai_controller/proc/set_new_cells() + if(isnull(our_cells)) + return + + var/turf/our_turf = get_turf(pawn) + + if(isnull(our_turf)) + return + + var/list/cell_collections = our_cells.recalculate_cells(our_turf) + + for(var/datum/old_grid as anything in cell_collections[2]) + UnregisterSignal(old_grid, list(SPATIAL_GRID_CELL_ENTERED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS))) + + for(var/datum/spatial_grid_cell/new_grid as anything in cell_collections[1]) + RegisterSignal(new_grid, SPATIAL_GRID_CELL_ENTERED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), PROC_REF(on_client_enter)) + RegisterSignal(new_grid, SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), PROC_REF(on_client_exit)) + + recalculate_idle() + +/datum/ai_controller/proc/should_idle() + if(!can_idle || isnull(our_cells)) + return FALSE + for(var/datum/spatial_grid_cell/grid as anything in our_cells.member_cells) + if(length(grid.client_contents)) + return FALSE + return TRUE + +/datum/ai_controller/proc/recalculate_idle(datum/exited) + if(ai_status == AI_STATUS_OFF) + return + + if(exited && (get_dist(pawn, (islist(exited) ? exited[1] : exited)) <= interesting_dist)) //is our target in between interesting cells? + return + + if(should_idle()) + set_ai_status(AI_STATUS_IDLE) + +/datum/ai_controller/proc/on_client_enter(datum/source, atom/target) + SIGNAL_HANDLER + + if(ai_status == AI_STATUS_IDLE) + set_ai_status(AI_STATUS_ON) + +/datum/ai_controller/proc/on_client_exit(datum/source, datum/exited) + SIGNAL_HANDLER + + recalculate_idle(exited) + /// Sets the AI on or off based on current conditions, call to reset after you've manually disabled it somewhere /datum/ai_controller/proc/reset_ai_status() set_ai_status(get_expected_ai_status()) -/// Returns what the AI status should be based on current conditions. +/** + * Gets the AI status we expect the AI controller to be on at this current moment. + * Returns AI_STATUS_OFF if it's inhabited by a Client and shouldn't be, if it's dead and cannot act while dead, or is on a z level without clients. + * Returns AI_STATUS_ON otherwise. + */ /datum/ai_controller/proc/get_expected_ai_status() - var/final_status = AI_STATUS_ON if (!ismob(pawn)) - return final_status + return AI_STATUS_ON var/mob/living/mob_pawn = pawn - if(!continue_processing_when_client && mob_pawn.client) - final_status = AI_STATUS_OFF - - if(ai_traits & CAN_ACT_WHILE_DEAD) - return final_status + return AI_STATUS_OFF if(mob_pawn.stat == DEAD) - final_status = AI_STATUS_OFF + if(ai_traits & CAN_ACT_WHILE_DEAD) + return AI_STATUS_ON + return AI_STATUS_OFF + + var/turf/pawn_turf = get_turf(mob_pawn) +#ifdef TESTING + if(!pawn_turf) + CRASH("AI controller [src] controlling pawn ([pawn]) is not on a turf.") +#endif + if(!length(SSmobs.clients_by_zlevel[pawn_turf.z])) + return AI_STATUS_OFF + if(should_idle()) + return AI_STATUS_IDLE + return AI_STATUS_ON + +/datum/ai_controller/proc/get_current_turf() + var/mob/living/mob_pawn = pawn + var/turf/pawn_turf = get_turf(mob_pawn) + to_chat(world, "[pawn_turf]") - return final_status +///Called when the AI controller pawn changes z levels, we check if there's any clients on the new one and wake up the AI if there is. +/datum/ai_controller/proc/on_changed_z_level(atom/source, turf/old_turf, turf/new_turf, same_z_layer, notify_contents) + SIGNAL_HANDLER + if (ismob(pawn)) + var/mob/mob_pawn = pawn + if((mob_pawn?.client && !continue_processing_when_client)) + return + if(old_turf) + SSai_controllers.ai_controllers_by_zlevel[old_turf.z] -= src + if(new_turf) + SSai_controllers.ai_controllers_by_zlevel[new_turf.z] += src + var/new_level_clients = SSmobs.clients_by_zlevel[new_turf.z].len + if(new_level_clients) + set_ai_status(AI_STATUS_IDLE) + else + set_ai_status(AI_STATUS_OFF) ///Abstract proc for initializing the pawn to the new controller /datum/ai_controller/proc/TryPossessPawn(atom/new_pawn) @@ -156,9 +258,15 @@ multiple modular subtrees with behaviors if(isnull(pawn)) return // instantiated without an applicable pawn, fine - UnregisterSignal(pawn, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) + set_ai_status(AI_STATUS_OFF) + UnregisterSignal(pawn, list(COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) if(ai_movement.moving_controllers[src]) ai_movement.stop_moving_towards(src) + var/turf/pawn_turf = get_turf(pawn) + if(pawn_turf) + SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] -= src + if(ai_status) + SSai_controllers.ai_controllers_by_status[ai_status] -= src pawn.ai_controller = null pawn = null if(destroy) @@ -172,12 +280,11 @@ multiple modular subtrees with behaviors return FALSE return TRUE - ///Runs any actions that are currently running /datum/ai_controller/process(seconds_per_tick) if(!able_to_run()) - SSmove_manager.stop_looping(pawn) //stop moving + GLOB.move_manager.stop_looping(pawn) //stop moving return //this should remove them from processing in the future through event-based stuff. if(!LAZYLEN(current_behaviors) && idle_behavior) @@ -200,7 +307,7 @@ multiple modular subtrees with behaviors // Convert the current behaviour action cooldown to realtime seconds from deciseconds.current_behavior // Then pick the max of this and the seconds_per_tick passed to ai_controller.process() // Action cooldowns cannot happen faster than seconds_per_tick, so seconds_per_tick should be the value used in this scenario. - var/action_seconds_per_tick = max(current_behavior.action_cooldown * 0.1, seconds_per_tick) + var/action_seconds_per_tick = max(current_behavior.get_cooldown(src) * 0.1, seconds_per_tick) if(current_behavior.behavior_flags & AI_BEHAVIOR_REQUIRE_MOVEMENT) //Might need to move closer if(!current_movement_target) @@ -256,33 +363,37 @@ multiple modular subtrees with behaviors if(subtree.SelectBehaviors(src, seconds_per_tick) == SUBTREE_RETURN_FINISH_PLANNING) break - for(var/datum/ai_behavior/current_behavior as anything in current_behaviors) - if(LAZYACCESS(planned_behaviors, current_behavior)) - continue + SEND_SIGNAL(src, COMSIG_AI_CONTROLLER_PICKED_BEHAVIORS, current_behaviors, planned_behaviors) + for(var/datum/ai_behavior/forgotten_behavior as anything in current_behaviors - planned_behaviors) var/list/arguments = list(src, FALSE) var/list/stored_arguments = behavior_args[type] if(stored_arguments) arguments += stored_arguments - current_behavior.finish_action(arglist(arguments)) + forgotten_behavior.finish_action(arglist(arguments)) ///This proc handles changing ai status, and starts/stops processing if required. /datum/ai_controller/proc/set_ai_status(new_ai_status) if(ai_status == new_ai_status) return FALSE //no change + //remove old status, if we've got one + if(ai_status) + SSai_controllers.ai_controllers_by_status[ai_status] -= src ai_status = new_ai_status + SSai_controllers.ai_controllers_by_status[new_ai_status] += src switch(ai_status) if(AI_STATUS_ON) - SSai_controllers.active_ai_controllers += src START_PROCESSING(SSai_behaviors, src) - if(AI_STATUS_OFF) + if(AI_STATUS_OFF, AI_STATUS_IDLE) STOP_PROCESSING(SSai_behaviors, src) - SSai_controllers.active_ai_controllers -= src CancelActions() /datum/ai_controller/proc/PauseAi(time) paused_until = world.time + time +/datum/ai_controller/proc/modify_cooldown(datum/ai_behavior/behavior, new_cooldown) + behavior_cooldowns[behavior] = new_cooldown + ///Call this to add a behavior to the stack. /datum/ai_controller/proc/queue_behavior(behavior_type, ...) var/datum/ai_behavior/behavior = GET_AI_BEHAVIOR(behavior_type) @@ -304,19 +415,30 @@ multiple modular subtrees with behaviors behavior_args[behavior_type] = arguments else behavior_args -= behavior_type + SEND_SIGNAL(src, AI_CONTROLLER_BEHAVIOR_QUEUED(behavior_type), arguments) /datum/ai_controller/proc/ProcessBehavior(seconds_per_tick, datum/ai_behavior/behavior) var/list/arguments = list(seconds_per_tick, src) var/list/stored_arguments = behavior_args[behavior.type] if(stored_arguments) arguments += stored_arguments - behavior.perform(arglist(arguments)) + + var/process_flags = behavior.perform(arglist(arguments)) + if(process_flags & AI_BEHAVIOR_DELAY) + behavior_cooldowns[behavior] = world.time + behavior.get_cooldown(src) + if(process_flags & AI_BEHAVIOR_FAILED) + arguments[1] = src + arguments[2] = FALSE + behavior.finish_action(arglist(arguments)) + else if (process_flags & AI_BEHAVIOR_SUCCEEDED) + arguments[1] = src + arguments[2] = TRUE + behavior.finish_action(arglist(arguments)) /datum/ai_controller/proc/CancelActions() if(!LAZYLEN(current_behaviors)) return - for(var/i in current_behaviors) - var/datum/ai_behavior/current_behavior = i + for(var/datum/ai_behavior/current_behavior as anything in current_behaviors) var/list/arguments = list(src, FALSE) var/list/stored_arguments = behavior_args[current_behavior.type] if(stored_arguments) @@ -338,7 +460,7 @@ multiple modular subtrees with behaviors /datum/ai_controller/proc/on_sentience_lost() SIGNAL_HANDLER UnregisterSignal(pawn, COMSIG_MOB_LOGOUT) - set_ai_status(AI_STATUS_ON) //Can't do anything while player is connected + set_ai_status(AI_STATUS_IDLE) //Can't do anything while player is connected RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) // Turn the controller off if the pawn has been qdeleted diff --git a/code/datums/ai/_item_behaviors.dm b/code/datums/ai/_item_behaviors.dm index 6cfb539f7a0bb..c9f3441fdd682 100644 --- a/code/datums/ai/_item_behaviors.dm +++ b/code/datums/ai/_item_behaviors.dm @@ -2,14 +2,14 @@ /datum/ai_behavior/item_escape_grasp /datum/ai_behavior/item_escape_grasp/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/obj/item/item_pawn = controller.pawn var/mob/item_holder = item_pawn.loc if(!istype(item_holder)) - finish_action(controller, FALSE) //We're no longer being held. abort abort!! + //We're no longer being held. abort abort!! + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED item_pawn.visible_message(span_warning("[item_pawn] slips out of the hands of [item_holder]!")) item_holder.dropItemToGround(item_pawn, TRUE) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED ///This behavior is for obj/items, it is used to move closer to a target and throw themselves towards them. @@ -30,7 +30,6 @@ set_movement_target(controller, target) /datum/ai_behavior/item_move_close_and_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, throw_count_key) - . = ..() var/obj/item/item_pawn = controller.pawn var/atom/throw_target = controller.blackboard[target_key] @@ -39,7 +38,8 @@ playsound(item_pawn.loc, attack_sound, 100, TRUE) controller.add_blackboard_key(throw_count_key, 1) if(controller.blackboard[throw_count_key] >= max_attempts) - finish_action(controller, TRUE, target_key, throw_count_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY /datum/ai_behavior/item_move_close_and_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, throw_count_key) . = ..() diff --git a/code/datums/ai/babies/babies_behaviors.dm b/code/datums/ai/babies/babies_behaviors.dm index 8cc03d72f6b76..ad57d309a2c72 100644 --- a/code/datums/ai/babies/babies_behaviors.dm +++ b/code/datums/ai/babies/babies_behaviors.dm @@ -8,7 +8,6 @@ var/max_children = 3 /datum/ai_behavior/find_partner/perform(seconds_per_tick, datum/ai_controller/controller, target_key, partner_types_key, child_types_key) - . = ..() max_children = controller.blackboard[BB_MAX_CHILDREN] || max_children var/mob/pawn_mob = controller.pawn var/list/partner_types = controller.blackboard[partner_types_key] @@ -18,12 +17,10 @@ var/children = 0 for(var/mob/living/other in oview(range, pawn_mob)) if(!pawn_mob.faction_check_atom(other)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(children >= max_children) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(other.stat != CONSCIOUS) //Check if it's conscious FIRST. continue @@ -40,10 +37,9 @@ if(other.gender != living_pawn.gender && !(other.flags_1 & HOLOGRAM_1)) //Better safe than sorry ;_; controller.set_blackboard_key(target_key, other) - finish_action(controller, TRUE) - - finish_action(controller, FALSE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /** * Reproduce. @@ -59,15 +55,13 @@ set_movement_target(controller, target) /datum/ai_behavior/make_babies/perform(seconds_per_tick, datum/ai_controller/controller, target_key, child_types_key) - . = ..() var/mob/target = controller.blackboard[target_key] if(QDELETED(target) || target.stat != CONSCIOUS) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/basic/living_pawn = controller.pawn living_pawn.set_combat_mode(FALSE) living_pawn.melee_attack(target) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/make_babies/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm index 144de535d5a84..883c157a96ba9 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm @@ -21,17 +21,15 @@ if (isliving(controller.pawn)) var/mob/living/pawn = controller.pawn if (world.time < pawn.next_move) - return + return AI_BEHAVIOR_INSTANT - . = ..() var/mob/living/basic/basic_mob = controller.pawn //targeting strategy will kill the action if not real anymore var/atom/target = controller.blackboard[target_key] var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) if(!targeting_strategy.can_attack(basic_mob, target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something! @@ -43,7 +41,8 @@ basic_mob.melee_attack(target) if(terminate_after_action) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY /datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) . = ..() @@ -82,22 +81,21 @@ var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) if(!targeting_strategy.can_attack(basic_mob, target, chase_range)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED var/atom/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something! var/atom/final_target = hiding_target ? hiding_target : target if(!can_see(basic_mob, final_target, required_distance)) - return + return AI_BEHAVIOR_INSTANT if(avoid_friendly_fire && check_friendly_in_path(basic_mob, target, targeting_strategy)) adjust_position(basic_mob, target) - return ..() + return AI_BEHAVIOR_DELAY controller.set_blackboard_key(hiding_location_key, hiding_target) basic_mob.RangedAttack(final_target) - return ..() //only start the cooldown when the shot is shot + return AI_BEHAVIOR_DELAY //only start the cooldown when the shot is shot /datum/ai_behavior/basic_ranged_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/befriend_target.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/befriend_target.dm index e1fd8bed640dc..865b028e156c5 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/befriend_target.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/befriend_target.dm @@ -2,19 +2,17 @@ /datum/ai_behavior/befriend_target /datum/ai_behavior/befriend_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, befriend_message) - . = ..() var/mob/living/living_pawn = controller.pawn var/mob/living/living_target = controller.blackboard[target_key] if(QDELETED(living_target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED living_pawn.befriend(living_target) var/befriend_text = controller.blackboard[befriend_message] if(befriend_text) to_chat(living_target, span_nicegreen("[living_pawn] [befriend_text]")) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/befriend_target/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm index c8c18072a4aaa..5046baa7e0f11 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm @@ -22,13 +22,12 @@ set_movement_target(controller, target) /datum/ai_behavior/climb_tree/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/obj/structure/flora/target_tree = controller.blackboard[target_key] var/mob/living/basic/living_pawn = controller.pawn if(QDELETED(living_pawn)) // pawn can be null at this point return SEND_SIGNAL(living_pawn, COMSIG_LIVING_CLIMB_TREE, target_tree) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/climb_tree/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm index 9e4ccef493676..07b4845f0275a 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm @@ -3,16 +3,13 @@ var/look_range = 7 /datum/ai_behavior/find_mom/perform(seconds_per_tick, datum/ai_controller/controller, mom_key, ignore_mom_key, found_mom) - . = ..() - var/mob/living_pawn = controller.pawn var/list/mom_types = controller.blackboard[mom_key] var/list/all_moms = list() var/list/ignore_types = controller.blackboard[ignore_mom_key] if(!length(mom_types)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED for(var/mob/mother in oview(look_range, living_pawn)) if(!is_type_in_list(mother, mom_types)) @@ -23,6 +20,5 @@ if(length(all_moms)) controller.set_blackboard_key(found_mom, pick(all_moms)) - finish_action(controller, TRUE) - return - finish_action(controller, FALSE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/pick_up_item.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/pick_up_item.dm index e81c9f9575150..1b65eaa507c9f 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/pick_up_item.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/pick_up_item.dm @@ -11,16 +11,13 @@ return isitem(target) && isturf(target.loc) && !target.anchored /datum/ai_behavior/pick_up_item/perform(seconds_per_tick, datum/ai_controller/controller, target_key, storage_key) - . = ..() var/obj/item/target = controller.blackboard[target_key] if(QDELETED(target) || !isturf(target.loc)) // Someone picked it up or it got deleted - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(!controller.pawn.Adjacent(target)) // It teleported - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED pickup_item(controller, target, storage_key) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/pick_up_item/finish_action(datum/ai_controller/controller, success, target_key, storage_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/pull_target.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/pull_target.dm index 9bfc3f85d2494..900b122dcb3fc 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/pull_target.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/pull_target.dm @@ -9,15 +9,12 @@ set_movement_target(controller, target) /datum/ai_behavior/pull_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - var/atom/movable/target = controller.blackboard[target_key] if(QDELETED(target) || target.anchored || target.pulledby) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/our_mob = controller.pawn our_mob.start_pulling(target) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/pull_target/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm index 172a31d4793c7..f23707e72b8c3 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm @@ -18,18 +18,16 @@ return ..() /datum/ai_behavior/run_away_from_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key) - . = ..() if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) - return + return AI_BEHAVIOR_DELAY var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] if (QDELETED(target) || !can_see(controller.pawn, target, run_distance)) - finish_action(controller, succeeded = TRUE, target_key = target_key, hiding_location_key = hiding_location_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED if (get_dist(controller.pawn, controller.current_movement_target) > required_distance) - return // Still heading over + return AI_BEHAVIOR_DELAY // Still heading over if (plot_path_away_from(controller, target)) - return - finish_action(controller, succeeded = FALSE, target_key = target_key, hiding_location_key = hiding_location_key) + return AI_BEHAVIOR_DELAY + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/run_away_from_target/proc/plot_path_away_from(datum/ai_controller/controller, atom/target) var/turf/target_destination = get_turf(controller.pawn) @@ -71,7 +69,7 @@ /datum/ai_behavior/run_away_from_target/run_and_shoot/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key) var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, succeeded = FALSE, target_key = target_key, hiding_location_key = hiding_location_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_pawn = controller.pawn living_pawn.RangedAttack(target) return ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/set_travel_destination.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/set_travel_destination.dm index 207df4424577d..6bf6dbb7fdbcb 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/set_travel_destination.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/set_travel_destination.dm @@ -1,13 +1,10 @@ /datum/ai_behavior/set_travel_destination /datum/ai_behavior/set_travel_destination/perform(seconds_per_tick, datum/ai_controller/controller, target_key, location_key) - . = ..() var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(location_key, target) - - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/step_towards_turf.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/step_towards_turf.dm index f941b2eb95d59..7cb3a7b9f1402 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/step_towards_turf.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/step_towards_turf.dm @@ -47,8 +47,7 @@ // We actually only wanted the movement so if we've arrived we're done /datum/ai_behavior/step_towards_turf/perform(seconds_per_tick, datum/ai_controller/controller, area_key, turf_key) - . = ..() - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /** * # Step towards turf in area diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/stop_and_stare.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/stop_and_stare.dm index cc02528262d01..4ce1f877b18a3 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/stop_and_stare.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/stop_and_stare.dm @@ -7,13 +7,13 @@ var/atom/movable/target = controller.blackboard[target_key] return ismovable(target) && isturf(target.loc) && ismob(controller.pawn) +/datum/ai_behavior/stop_and_stare/get_cooldown(datum/ai_controller/cooldown_for) + return cooldown_for.blackboard[BB_STATIONARY_COOLDOWN] + /datum/ai_behavior/stop_and_stare/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - // i don't really like doing this but we wanna make sure that the cooldown is pertinent to what we need for this specific controller before we invoke parent - action_cooldown = controller.blackboard[BB_STATIONARY_COOLDOWN] - . = ..() var/atom/movable/target = controller.blackboard[target_key] if(!ismovable(target) || !isturf(target.loc)) // just to make sure that nothing funky happened between setup and perform - return + return AI_BEHAVIOR_DELAY var/mob/pawn_mob = controller.pawn var/turf/pawn_turf = get_turf(pawn_mob) @@ -24,3 +24,4 @@ if(controller.blackboard[BB_STATIONARY_MOVE_TO_TARGET]) addtimer(CALLBACK(src, PROC_REF(set_movement_target), controller, target, initial(controller.ai_movement)), (controller.blackboard[BB_STATIONARY_SECONDS] + 1 SECONDS)) + return AI_BEHAVIOR_DELAY diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm index ba167b34f2951..2d2ad013aa2c6 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm @@ -8,12 +8,13 @@ var/datum/action/cooldown/ability = get_ability_to_use(controller, ability_key) var/mob/living/target = controller.blackboard[target_key] if(QDELETED(ability) || QDELETED(target)) - finish_action(controller, FALSE, ability_key, target_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED var/mob/pawn = controller.pawn pawn.face_atom(target) var/result = ability.Trigger(target = target) - finish_action(controller, result, ability_key, target_key) + if(result) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED /datum/ai_behavior/targeted_mob_ability/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm index 8ba9624c21edc..4cf04039e8535 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm @@ -1,15 +1,24 @@ /// List of objects that AIs will treat as targets GLOBAL_LIST_EMPTY_TYPED(hostile_machines, /atom) +/// Static typecache list of things we are interested in +/// Consider this a union of the for loop and the hearers call from below +/// Must be kept up to date with the contents of hostile_machines +GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/porta_turret, /obj/vehicle/sealed/mecha))) /datum/ai_behavior/find_potential_targets action_cooldown = 2 SECONDS + behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION /// How far can we see stuff? var/vision_range = 9 /// Blackboard key for aggro range, uses vision range if not specified var/aggro_range_key = BB_AGGRO_RANGE +/datum/ai_behavior/find_potential_targets/get_cooldown(datum/ai_controller/cooldown_for) + if(cooldown_for.blackboard[BB_FIND_TARGETS_FIELD(type)]) + return 60 SECONDS + return ..() + /datum/ai_behavior/find_potential_targets/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) - . = ..() var/mob/living/living_mob = controller.pawn var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) @@ -18,13 +27,16 @@ GLOBAL_LIST_EMPTY_TYPED(hostile_machines, /atom) var/atom/current_target = controller.blackboard[target_key] if (targeting_strategy.can_attack(living_mob, current_target, vision_range)) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/aggro_range = controller.blackboard[aggro_range_key] || vision_range controller.clear_blackboard_key(target_key) + // If we're using a field rn, just don't do anything yeah? + if(controller.blackboard[BB_FIND_TARGETS_FIELD(type)]) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + var/list/potential_targets = hearers(aggro_range, get_turf(controller.pawn)) - living_mob //Remove self, so we don't suicide for (var/atom/hostile_machine as anything in GLOB.hostile_machines) @@ -32,8 +44,8 @@ GLOBAL_LIST_EMPTY_TYPED(hostile_machines, /atom) potential_targets += hostile_machine if(!potential_targets.len) - finish_action(controller, succeeded = FALSE) - return + failed_to_find_anyone(controller, target_key, targeting_strategy_key, hiding_location_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/list/filtered_targets = list() @@ -43,23 +55,99 @@ GLOBAL_LIST_EMPTY_TYPED(hostile_machines, /atom) continue if(!filtered_targets.len) - finish_action(controller, succeeded = FALSE) - return + failed_to_find_anyone(controller, target_key, targeting_strategy_key, hiding_location_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/atom/target = pick_final_target(controller, filtered_targets) controller.set_blackboard_key(target_key, target) var/atom/potential_hiding_location = targeting_strategy.find_hidden_mobs(living_mob, target) + if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially. + controller.set_blackboard_key(hiding_location_key, potential_hiding_location) + + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + +/datum/ai_behavior/find_potential_targets/proc/failed_to_find_anyone(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) + var/aggro_range = controller.blackboard[aggro_range_key] || vision_range + // takes the larger between our range() input and our implicit hearers() input (world.view) + aggro_range = max(aggro_range, ROUND_UP(max(getviewsize(world.view)) / 2)) + // Alright, here's the interesting bit + // We're gonna use this max range to hook into a proximity field so we can just await someone interesting to come along + // Rather then trying to check every few seconds + var/datum/proximity_monitor/advanced/ai_target_tracking/detection_field = new( + controller.pawn, + aggro_range, + TRUE, + src, + controller, + target_key, + targeting_strategy_key, + hiding_location_key, + ) + // We're gonna store this field in our blackboard, so we can clear it away if we end up finishing successsfully + controller.set_blackboard_key(BB_FIND_TARGETS_FIELD(type), detection_field) + +/datum/ai_behavior/find_potential_targets/proc/new_turf_found(turf/found, datum/ai_controller/controller, datum/targeting_strategy/strategy) + var/valid_found = FALSE + var/mob/pawn = controller.pawn + for(var/maybe_target as anything in found) + if(maybe_target == pawn) + continue + if(!is_type_in_typecache(maybe_target, GLOB.target_interested_atoms)) + continue + if(!strategy.can_attack(pawn, maybe_target)) + continue + valid_found = TRUE + break + if(!valid_found) + return + // If we found any one thing we "could" attack, then run the full search again so we can select from the best possible canidate + var/datum/proximity_monitor/field = controller.blackboard[BB_FIND_TARGETS_FIELD(type)] + qdel(field) // autoclears so it's fine + // Fire instantly, you should find something I hope + controller.modify_cooldown(src, world.time) + +/datum/ai_behavior/find_potential_targets/proc/atom_allowed(atom/movable/checking, datum/targeting_strategy/strategy, mob/pawn) + if(checking == pawn) + return FALSE + if(!ismob(checking) && !is_type_in_typecache(checking, GLOB.target_interested_atoms)) + return FALSE + if(!strategy.can_attack(pawn, checking)) + return FALSE + return TRUE + +/datum/ai_behavior/find_potential_targets/proc/new_atoms_found(list/atom/movable/found, datum/ai_controller/controller, target_key, datum/targeting_strategy/strategy, hiding_location_key) + var/mob/pawn = controller.pawn + var/list/accepted_targets = list() + for(var/maybe_target as anything in found) + if(maybe_target == pawn) + continue + // Need to better handle viewers here + if(!ismob(maybe_target) && !is_type_in_typecache(maybe_target, GLOB.target_interested_atoms)) + continue + if(!strategy.can_attack(pawn, maybe_target)) + continue + accepted_targets += maybe_target + + // Alright, we found something acceptable, let's use it yeah? + var/atom/target = pick_final_target(controller, accepted_targets) + controller.set_blackboard_key(target_key, target) + + var/atom/potential_hiding_location = strategy.find_hidden_mobs(pawn, target) + if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially. controller.set_blackboard_key(hiding_location_key, potential_hiding_location) finish_action(controller, succeeded = TRUE) -/datum/ai_behavior/find_potential_targets/finish_action(datum/ai_controller/controller, succeeded, ...) +/datum/ai_behavior/find_potential_targets/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) . = ..() if (succeeded) + var/datum/proximity_monitor/field = controller.blackboard[BB_FIND_TARGETS_FIELD(type)] + qdel(field) // autoclears so it's fine controller.CancelActions() // On retarget cancel any further queued actions so that they will setup again with new target + controller.modify_cooldown(src, get_cooldown(controller)) /// Returns the desired final target from the filtered list of targets /datum/ai_behavior/find_potential_targets/proc/pick_final_target(datum/ai_controller/controller, list/filtered_targets) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/tipped_reaction.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/tipped_reaction.dm index 643bb9ced5ad0..c734d961b5ef2 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/tipped_reaction.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/tipped_reaction.dm @@ -3,8 +3,6 @@ /datum/ai_behavior/tipped_reaction /datum/ai_behavior/tipped_reaction/perform(seconds_per_tick, datum/ai_controller/controller, tipper_key, reacting_key) - . = ..() - var/mob/living/carbon/tipper = controller.blackboard[tipper_key] // visible part of the visible message @@ -28,7 +26,7 @@ seen_message = "[controller.pawn] seems resigned to its fate." self_message = "You resign yourself to your fate." controller.pawn.visible_message(span_notice("[seen_message]"), span_notice("[self_message]")) - finish_action(controller, TRUE, tipper_key, reacting_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/tipped_reaction/finish_action(datum/ai_controller/controller, succeeded, tipper_key, reacting_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/travel_towards.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/travel_towards.dm index 6eb7c36dadd6e..808fe6b8873c8 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/travel_towards.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/travel_towards.dm @@ -19,8 +19,7 @@ set_movement_target(controller, target, new_movement_type) /datum/ai_behavior/travel_towards/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/travel_towards/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() @@ -48,5 +47,4 @@ set_movement_target(controller, target_atom) /datum/ai_behavior/travel_towards_atom/perform(seconds_per_tick, datum/ai_controller/controller, atom/target_atom) - . = ..() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm index 655b335d3b63c..34e651f8e5285 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm @@ -1,14 +1,11 @@ /datum/ai_behavior/unbuckle_mob /datum/ai_behavior/unbuckle_mob/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() - var/mob/living/living_pawn = controller.pawn var/atom/movable/buckled_to = living_pawn.buckled if(isnull(buckled_to)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED buckled_to.unbuckle_mob(living_pawn) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm index e162cc612990a..aca89d832814a 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm @@ -8,33 +8,32 @@ /datum/ai_behavior/crawl_through_vents action_cooldown = 10 SECONDS +/datum/ai_behavior/crawl_through_vents/get_cooldown(datum/ai_controller/cooldown_for) + return cooldown_for.blackboard[BB_VENTCRAWL_COOLDOWN] || initial(action_cooldown) + /datum/ai_behavior/crawl_through_vents/setup(datum/ai_controller/controller, target_key) - action_cooldown = controller.blackboard[BB_VENTCRAWL_COOLDOWN] || initial(action_cooldown) . = ..() var/obj/machinery/atmospherics/components/unary/vent_pump/target = controller.blackboard[target_key] || controller.blackboard[BB_ENTRY_VENT_TARGET] return istype(target) && isliving(controller.pawn) // only mobs can vent crawl in the current framework /datum/ai_behavior/crawl_through_vents/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent = controller.blackboard[target_key] || controller.blackboard[BB_ENTRY_VENT_TARGET] var/mob/living/cached_pawn = controller.pawn if(HAS_TRAIT(cached_pawn, TRAIT_MOVE_VENTCRAWLING) || !controller.blackboard[BB_CURRENTLY_TARGETING_VENT] || !is_vent_valid(entry_vent)) - return + return AI_BEHAVIOR_DELAY if(!cached_pawn.can_enter_vent(entry_vent, provide_feedback = FALSE)) // we're an AI we scoff at feedback - finish_action(controller, FALSE, target_key) // "never enter a hole you can't get out of" - return + // "never enter a hole you can't get out of" + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/vent_we_exit_out_of = calculate_exit_vent(controller, target_key) if(isnull(vent_we_exit_out_of)) // don't get into the vents if we can't get out of them, that's SILLY. - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(BB_CURRENTLY_TARGETING_VENT, FALSE) // must be done here because we have a do_after sleep in handle_ventcrawl unfortunately and double dipping could lead to erroneous suicide pill calls. cached_pawn.handle_ventcrawl(entry_vent) if(!HAS_TRAIT(cached_pawn, TRAIT_MOVE_VENTCRAWLING)) //something failed and we ARE NOT IN THE VENT even though the earlier check said we were good to go! odd. - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(BB_EXIT_VENT_TARGET, vent_we_exit_out_of) @@ -48,7 +47,8 @@ var/upper_vent_time_limit = controller.blackboard[BB_UPPER_VENT_TIME_LIMIT] // the most amount of time we spend in the vents addtimer(CALLBACK(src, PROC_REF(exit_the_vents), controller), rand(lower_vent_time_limit, upper_vent_time_limit)) - controller.set_blackboard_key(BB_GIVE_UP_ON_VENT_PATHING_TIMER_ID, addtimer(CALLBACK(src, PROC_REF(suicide_pill), controller), controller.blackboard[BB_TIME_TO_GIVE_UP_ON_VENT_PATHING], TIMER_STOPPABLE)) + controller.set_blackboard_key(BB_GIVE_UP_ON_VENT_PATHING_TIMER_ID, addtimer(CALLBACK(src, PROC_REF(delayed_suicide_pill), controller, target_key), controller.blackboard[BB_TIME_TO_GIVE_UP_ON_VENT_PATHING], TIMER_STOPPABLE)) + return AI_BEHAVIOR_DELAY /// Figure out an exit vent that we should head towards. If we don't have one, default to the entry vent. If they're all kaput, we die. /datum/ai_behavior/crawl_through_vents/proc/calculate_exit_vent(datum/ai_controller/controller, target_key) @@ -81,8 +81,8 @@ var/mob/living/living_pawn = controller.pawn if(!HAS_TRAIT(living_pawn, TRAIT_MOVE_VENTCRAWLING) && isturf(get_turf(living_pawn))) // we're out of the vents, so no need to do an exit - finish_action(controller, TRUE, target_key) // assume that we got yeeted out somehow and call this so we can halt the suicide pill timer. - return + // assume that we got yeeted out somehow and return this so we can halt the suicide pill timer. + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED living_pawn.forceMove(exit_vent) if(!living_pawn.can_enter_vent(exit_vent, provide_feedback = FALSE)) @@ -90,8 +90,7 @@ emergency_vent = calculate_exit_vent(controller) if(isnull(emergency_vent)) // it's joever. we cooked too hard. - suicide_pill(controller, target_key) - return + return suicide_pill(controller) | AI_BEHAVIOR_DELAY controller.set_blackboard_key(BB_EXIT_VENT_TARGET, emergency_vent) // assign and go again addtimer(CALLBACK(src, PROC_REF(exit_the_vents), controller), (rand(controller.blackboard[BB_LOWER_VENT_TIME_LIMIT], controller.blackboard[BB_UPPER_VENT_TIME_LIMIT]) / 2)) // we're in danger mode, so scurry out at half the time it would normally take. @@ -100,32 +99,34 @@ living_pawn.handle_ventcrawl(exit_vent) if(HAS_TRAIT(living_pawn, TRAIT_MOVE_VENTCRAWLING)) // how'd we fail? what the fuck stack_trace("We failed to exit the vents, even though we should have been fine? This is very weird.") - suicide_pill() // all of the prior checks say we should have definitely made it through, but we didn't. dammit. - return + return suicide_pill(controller) | AI_BEHAVIOR_DELAY // all of the prior checks say we should have definitely made it through, but we didn't. dammit. - finish_action(controller, TRUE, target_key) // we did it! we went into the vents and out of the vents. poggers. + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED // we did it! we went into the vents and out of the vents. poggers. /// Incredibly stripped down version of the overarching `can_enter_vent` proc on `/mob, just meant for rapid rechecking of a vent. Will be TRUE if not blocked, FALSE otherwise. /datum/ai_behavior/crawl_through_vents/proc/is_vent_valid(obj/machinery/atmospherics/components/unary/vent_pump/checkable) return !QDELETED(checkable) && !checkable.welded +/// Wraps a delayed defeat, so we gotta handle the return value properly ya feel? +/datum/ai_behavior/crawl_through_vents/proc/delayed_suicide_pill(datum/ai_controller/controller, target_key) + if(suicide_pill(controller) & AI_BEHAVIOR_FAILED) + finish_action(controller, FALSE, target_key) + /// Aw fuck, we may have been bested somehow. Regardless of what we do, we can't exit through a vent! Let's end our misery and prevent useless endless calculations. -/datum/ai_behavior/crawl_through_vents/proc/suicide_pill(datum/ai_controller/controller, target_key) +/datum/ai_behavior/crawl_through_vents/proc/suicide_pill(datum/ai_controller/controller) var/mob/living/living_pawn = controller.pawn if(istype(living_pawn)) - finish_action(controller, FALSE, target_key) - if(isnull(living_pawn.client)) // only call death if we don't have a client because maybe their natural intelligence can pick up where our AI calculations have failed living_pawn.death(TRUE) // call gibbed as true because we are never coming back it is so fucking joever - return + return AI_BEHAVIOR_FAILED if(QDELETED(living_pawn)) // we got deleted by some other means, just presume the action is a wash and get outta here - return + return NONE qdel(living_pawn) // failover, we really should've been caught in the istype() but lets just bow out of existing at this point - + return NONE /datum/ai_behavior/crawl_through_vents/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/write_on_paper.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/write_on_paper.dm index f5dba58416d28..51826676e9e8d 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/write_on_paper.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/write_on_paper.dm @@ -1,7 +1,6 @@ /datum/ai_behavior/write_on_paper /datum/ai_behavior/write_on_paper/perform(seconds_per_tick, datum/ai_controller/controller, found_paper, list_of_writings) - . = ..() var/mob/living/wizard = controller.pawn var/list/writing_list = controller.blackboard[list_of_writings] var/obj/item/paper/target = controller.blackboard[found_paper] @@ -9,7 +8,7 @@ target.add_raw_text(pick(writing_list)) target.update_appearance() wizard.dropItemToGround(target) - finish_action(controller, TRUE, found_paper) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/write_on_paper/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm index 4116900435460..8effc7a0fa737 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm @@ -27,7 +27,6 @@ /datum/ai_behavior/basic_melee_attack/opportunistic/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) var/atom/movable/atom_pawn = controller.pawn if(!atom_pawn.CanReach(controller.blackboard[target_key])) - finish_action(controller, TRUE, target_key) // Don't clear target - return FALSE + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED . = ..() - finish_action(controller, TRUE, target_key) // Try doing something else + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_subtrees/attack_obstacle_in_path.dm b/code/datums/ai/basic_mobs/basic_subtrees/attack_obstacle_in_path.dm index 7059bec93fe2f..bc8efdeb4ff58 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/attack_obstacle_in_path.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/attack_obstacle_in_path.dm @@ -27,13 +27,11 @@ var/can_attack_dense_objects = FALSE /datum/ai_behavior/attack_obstructions/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/basic/basic_mob = controller.pawn var/atom/target = controller.blackboard[target_key] if (QDELETED(target)) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/turf/next_step = get_step_towards(basic_mob, target) var/dir_to_next_step = get_dir(basic_mob, next_step) @@ -48,8 +46,8 @@ for (var/direction in dirs_to_move) if (attack_in_direction(controller, basic_mob, direction)) - return - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/attack_obstructions/proc/attack_in_direction(datum/ai_controller/controller, mob/living/basic/basic_mob, direction) var/turf/next_step = get_step(basic_mob, direction) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm b/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm index 59ff88b4879be..44d7cb4fe480b 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm @@ -36,8 +36,6 @@ var/reinforcements_range = 15 /datum/ai_behavior/call_reinforcements/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() - var/mob/pawn_mob = controller.pawn for(var/mob/other_mob in oview(reinforcements_range, pawn_mob)) if(pawn_mob.faction_check_atom(other_mob) && !isnull(other_mob.ai_controller)) @@ -46,5 +44,6 @@ other_mob.ai_controller.set_blackboard_key(BB_BASIC_MOB_REINFORCEMENT_TARGET, pawn_mob) controller.set_blackboard_key(BB_BASIC_MOB_REINFORCEMENTS_COOLDOWN, world.time + REINFORCEMENTS_COOLDOWN) + return AI_BEHAVIOR_DELAY #undef REINFORCEMENTS_COOLDOWN diff --git a/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm index 4d5319bca86e7..52b19036b9a47 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm @@ -14,29 +14,26 @@ action_cooldown = 1 SECONDS /datum/ai_behavior/capricious_retaliate/perform(seconds_per_tick, datum/ai_controller/controller, targeting_strategy_key, ignore_faction) - . = ..() var/atom/pawn = controller.pawn if (controller.blackboard_key_exists(BB_BASIC_MOB_RETALIATE_LIST)) var/deaggro_chance = controller.blackboard[BB_RANDOM_DEAGGRO_CHANCE] || 10 if (!SPT_PROB(deaggro_chance, seconds_per_tick)) - finish_action(controller, TRUE, ignore_faction) // "true" here means "don't clear our ignoring factions status" - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED pawn.visible_message(span_notice("[pawn] calms down.")) // We can blackboard key this if anyone else actually wants to customise it controller.clear_blackboard_key(BB_BASIC_MOB_RETALIATE_LIST) - finish_action(controller, FALSE, ignore_faction) + controller.clear_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET) controller.CancelActions() // Otherwise they will try and get one last kick in - return + return AI_BEHAVIOR_DELAY var/aggro_chance = controller.blackboard[BB_RANDOM_AGGRO_CHANCE] || 0.5 if (!SPT_PROB(aggro_chance, seconds_per_tick)) - finish_action(controller, FALSE, ignore_faction) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/aggro_range = controller.blackboard[BB_AGGRO_RANGE] || 9 var/list/potential_targets = hearers(aggro_range, get_turf(pawn)) - pawn if (!length(potential_targets)) - failed_targeting(controller, pawn, ignore_faction) - return + failed_targeting(pawn) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/datum/targeting_strategy/target_helper = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) @@ -49,16 +46,15 @@ final_target = test_target if (isnull(final_target)) - failed_targeting(controller, pawn, ignore_faction) - return + failed_targeting(pawn) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, final_target) pawn.visible_message(span_warning("[pawn] glares grumpily at [final_target]!")) - finish_action(controller, TRUE, ignore_faction) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /// Called if we try but fail to target something -/datum/ai_behavior/capricious_retaliate/proc/failed_targeting(datum/ai_controller/controller, atom/pawn, ignore_faction) - finish_action(controller, FALSE, ignore_faction) +/datum/ai_behavior/capricious_retaliate/proc/failed_targeting(atom/pawn) pawn.visible_message(span_notice("[pawn] grumbles.")) // We're pissed off but with no outlet to vent our frustration upon /datum/ai_behavior/capricious_retaliate/finish_action(datum/ai_controller/controller, succeeded, ignore_faction) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm b/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm new file mode 100644 index 0000000000000..74ec9d98191a0 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm @@ -0,0 +1,44 @@ +#define HIGH_HAPPINESS_THRESHOLD 0.7 +#define MODERATE_HAPPINESS_THRESHOLD 0.5 + +/datum/ai_planning_subtree/express_happiness + operational_datums = list(/datum/component/happiness) + ///the key storing our happiness value + var/happiness_key = BB_BASIC_HAPPINESS + ///list of emotions we relay when happy + var/static/list/happy_emotions = list( + "celebrate happily!", + "dances around in excitement!", + ) + ///our moderate emotions + var/static/list/moderate_emotions = list( + "looks satisfied.", + "trots around.", + ) + ///emotions we display when we are sad + var/static/list/depressed_emotions = list( + "looks depressed...", + "turns its back and sulks...", + "looks towards the floor in dissapointment...", + ) + +/datum/ai_planning_subtree/express_happiness/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!SPT_PROB(5, seconds_per_tick)) + return + var/happiness_value = controller.blackboard[happiness_key] + if(isnull(happiness_value)) + return + var/list/final_list + switch(happiness_value) + if(HIGH_HAPPINESS_THRESHOLD to INFINITY) + final_list = happy_emotions + if(MODERATE_HAPPINESS_THRESHOLD to HIGH_HAPPINESS_THRESHOLD) + final_list = moderate_emotions + else + final_list = depressed_emotions + if(!length(final_list)) + return + controller.queue_behavior(/datum/ai_behavior/perform_emote, pick(final_list)) + +#undef HIGH_HAPPINESS_THRESHOLD +#undef MODERATE_HAPPINESS_THRESHOLD diff --git a/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm b/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm index 2c65dfbb6a97e..ef44df82f78d8 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm @@ -11,7 +11,7 @@ return if(get_dist(target, baby) > minimum_distance) - controller.queue_behavior(/datum/ai_behavior/travel_towards, BB_FOUND_MOM) + controller.queue_behavior(/datum/ai_behavior/travel_towards/stop_on_arrival, BB_FOUND_MOM) return SUBTREE_RETURN_FINISH_PLANNING if(!SPT_PROB(15, seconds_per_tick)) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/maintain_distance.dm b/code/datums/ai/basic_mobs/basic_subtrees/maintain_distance.dm index 2a85e9e902b2c..549abbc75eca8 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/maintain_distance.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/maintain_distance.dm @@ -60,8 +60,7 @@ return FALSE /datum/ai_behavior/step_away/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/step_away/finish_action(datum/ai_controller/controller, succeeded) . = ..() @@ -83,8 +82,8 @@ /datum/ai_behavior/pursue_to_range/perform(seconds_per_tick, datum/ai_controller/controller, target_key, range) var/atom/current_target = controller.blackboard[target_key] if (!QDELETED(current_target) && get_dist(controller.pawn, current_target) > range) - return - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_INSTANT + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED ///instead of taking a single step, we cover the entire distance /datum/ai_behavior/cover_minimum_distance @@ -112,5 +111,4 @@ set_movement_target(controller, target = chosen_turf) /datum/ai_behavior/cover_minimum_distance/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm b/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm index 3c03702b69947..dc3f6ddcf9015 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm @@ -21,19 +21,16 @@ set_movement_target(controller, target) /datum/ai_behavior/mine_wall/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/basic/living_pawn = controller.pawn var/turf/closed/mineral/target = controller.blackboard[target_key] var/is_gibtonite_turf = istype(target, /turf/closed/mineral/gibtonite) if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED living_pawn.melee_attack(target) if(is_gibtonite_turf) living_pawn.manual_emote("sighs...") //accept whats about to happen to us - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/mine_wall/finish_action(datum/ai_controller/controller, success, target_key) . = ..() @@ -42,17 +39,15 @@ /datum/ai_behavior/find_mineral_wall /datum/ai_behavior/find_mineral_wall/perform(seconds_per_tick, datum/ai_controller/controller, found_wall_key) - . = ..() var/mob/living_pawn = controller.pawn for(var/turf/closed/mineral/potential_wall in oview(9, living_pawn)) if(!check_if_mineable(controller, potential_wall)) //check if its surrounded by walls continue controller.set_blackboard_key(found_wall_key, potential_wall) //closest wall first! - finish_action(controller, TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED - finish_action(controller, FALSE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/find_mineral_wall/proc/check_if_mineable(datum/ai_controller/controller, turf/target_wall) var/mob/living/source = controller.pawn diff --git a/code/datums/ai/basic_mobs/basic_subtrees/move_to_cardinal.dm b/code/datums/ai/basic_mobs/basic_subtrees/move_to_cardinal.dm index c98878e0fd71f..bcf5c82902513 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/move_to_cardinal.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/move_to_cardinal.dm @@ -51,19 +51,17 @@ /datum/ai_behavior/move_to_cardinal/perform(seconds_per_tick, datum/ai_controller/controller, target_key) var/atom/target = controller.blackboard[target_key] if (QDELETED(target)) - finish_action(controller = controller, succeeded = FALSE, target_key = target_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED if (!(get_dir(controller.pawn, target) in GLOB.cardinals)) target_nearest_cardinal(controller, target) - return + return AI_BEHAVIOR_INSTANT var/distance_to_target = get_dist(controller.pawn, target) if (distance_to_target < minimum_distance) target_nearest_cardinal(controller, target) - return + return AI_BEHAVIOR_INSTANT if (distance_to_target > maximum_distance) - return - finish_action(controller = controller, succeeded = TRUE, target_key = target_key) - return + return AI_BEHAVIOR_INSTANT + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/move_to_cardinal/finish_action(datum/ai_controller/controller, succeeded, target_key) if (!succeeded) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm b/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm index 95a125eea5ce5..3640a2052b55e 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm @@ -26,16 +26,13 @@ return !QDELETED(target) /datum/ai_behavior/ranged_skirmish/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, max_range, min_range) - . = ..() var/atom/target = controller.blackboard[target_key] if (QDELETED(target)) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) if(!targeting_strategy.can_attack(controller.pawn, target)) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/hiding_target = targeting_strategy.find_hidden_mobs(controller.pawn, target) controller.set_blackboard_key(hiding_location_key, hiding_target) @@ -44,9 +41,8 @@ var/distance = get_dist(controller.pawn, target) if (distance > max_range || distance < min_range) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/basic/gunman = controller.pawn gunman.RangedAttack(target) - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_subtrees/run_emote.dm b/code/datums/ai/basic_mobs/basic_subtrees/run_emote.dm index 6f2f5cdc2035c..c0c0da96584a0 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/run_emote.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/run_emote.dm @@ -15,8 +15,7 @@ /datum/ai_behavior/run_emote/perform(seconds_per_tick, datum/ai_controller/controller, emote_key) var/mob/living/living_pawn = controller.pawn if (!isliving(living_pawn)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED var/list/emote_list = controller.blackboard[emote_key] var/emote @@ -26,8 +25,7 @@ emote = emote_list if(isnull(emote)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED living_pawn.emote(emote) - finish_action(controller, TRUE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm index 6630f7d193d90..d9e0d1e7fb9ff 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm @@ -9,13 +9,16 @@ /// Find the nearest thing on our list of 'things which have done damage to me' and set it as the flee target /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee + ///the targeting strategy we use var/targeting_key = BB_TARGETING_STRATEGY + ///what key should we set the target as + var/target_key = BB_BASIC_MOB_CURRENT_TARGET /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) return - controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, BB_BASIC_MOB_CURRENT_TARGET, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key targeting_key = BB_FLEE_TARGETING_STRATEGY diff --git a/code/datums/ai/basic_mobs/basic_subtrees/sleep_with_no_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/sleep_with_no_target.dm index 93499cf673c4d..5d9841a524735 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/sleep_with_no_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/sleep_with_no_target.dm @@ -16,7 +16,9 @@ /datum/ai_behavior/sleep_after_targetless_time/perform(seconds_per_tick, datum/ai_controller/controller, target_key) var/atom/target = controller.blackboard[target_key] - finish_action(controller, succeeded = QDELETED(target), seconds_per_tick = seconds_per_tick) + if(QDELETED(target)) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED /datum/ai_behavior/sleep_after_targetless_time/finish_action(datum/ai_controller/controller, succeeded, seconds_per_tick) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm index 55ec738761317..042ccb2310c1a 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm @@ -11,7 +11,6 @@ var/check_faction = FALSE /datum/ai_planning_subtree/target_retaliate/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - . = ..() controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_strategy_key, hiding_place_key, check_faction) /datum/ai_planning_subtree/target_retaliate/check_faction @@ -35,10 +34,10 @@ var/vision_range = 9 /datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targeting_strategy_key, hiding_location_key, check_faction) - . = ..() var/mob/living/living_mob = controller.pawn var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) if(!targeting_strategy) + . = AI_BEHAVIOR_DELAY CRASH("No target datum was supplied in the blackboard for [controller.pawn]") var/list/shitlist = controller.blackboard[shitlist_key] @@ -48,8 +47,7 @@ controller.set_blackboard_key(BB_TEMPORARILY_IGNORE_FACTION, TRUE) if (!QDELETED(existing_target) && (locate(existing_target) in shitlist) && targeting_strategy.can_attack(living_mob, existing_target, vision_range)) - finish_action(controller, succeeded = TRUE, check_faction = check_faction) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED var/list/enemies_list = list() for(var/mob/living/potential_target as anything in shitlist) @@ -58,9 +56,7 @@ enemies_list += potential_target if(!length(enemies_list)) - controller.clear_blackboard_key(target_key) - finish_action(controller, succeeded = FALSE, check_faction = check_faction) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/atom/new_target = pick_final_target(controller, enemies_list) controller.set_blackboard_key(target_key, new_target) @@ -70,13 +66,13 @@ if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially. controller.set_blackboard_key(hiding_location_key, potential_hiding_location) - finish_action(controller, succeeded = TRUE, check_faction = check_faction) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /// Returns the desired final target from the filtered list of enemies /datum/ai_behavior/target_from_retaliate_list/proc/pick_final_target(datum/ai_controller/controller, list/enemies_list) return pick(enemies_list) -/datum/ai_behavior/target_from_retaliate_list/finish_action(datum/ai_controller/controller, succeeded, check_faction) +/datum/ai_behavior/target_from_retaliate_list/finish_action(datum/ai_controller/controller, succeeded, shitlist_key, target_key, targeting_strategy_key, hiding_location_key, check_faction) . = ..() if (succeeded || check_faction) return diff --git a/code/datums/ai/basic_mobs/basic_subtrees/teleport_away_from_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/teleport_away_from_target.dm index dadba992e9f10..25f0e4a424962 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/teleport_away_from_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/teleport_away_from_target.dm @@ -34,7 +34,7 @@ /datum/ai_behavior/find_furthest_turf_from_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, set_key, range) var/mob/living/living_target = controller.blackboard[target_key] if(QDELETED(living_target)) - return + return AI_BEHAVIOR_INSTANT var/distance = 0 var/turf/chosen_turf @@ -49,8 +49,7 @@ break //we have already found the max distance if(isnull(chosen_turf)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED controller.set_blackboard_key(set_key, chosen_turf) - finish_action(controller, TRUE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm b/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm index a59a901d57d04..4c794a73d8ad9 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm @@ -27,7 +27,7 @@ /datum/ai_behavior/use_mob_ability/perform(seconds_per_tick, datum/ai_controller/controller, ability_key) var/datum/action/using_action = controller.blackboard[ability_key] if (QDELETED(using_action)) - finish_action(controller, FALSE, ability_key) - return - var/result = using_action.Trigger() - finish_action(controller, result, ability_key) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED + if(using_action.Trigger()) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED diff --git a/code/datums/ai/basic_mobs/pet_commands/fetch.dm b/code/datums/ai/basic_mobs/pet_commands/fetch.dm index a9147eaf6819e..87606fa0c6555 100644 --- a/code/datums/ai/basic_mobs/pet_commands/fetch.dm +++ b/code/datums/ai/basic_mobs/pet_commands/fetch.dm @@ -14,19 +14,15 @@ set_movement_target(controller, fetch_thing) /datum/ai_behavior/fetch_seek/perform(seconds_per_tick, datum/ai_controller/controller, target_key, delivery_key) - . = ..() var/obj/item/fetch_thing = controller.blackboard[target_key] // It stopped existing if (QDELETED(fetch_thing)) - finish_action(controller, FALSE, target_key, delivery_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED // We can't pick this up if (fetch_thing.anchored) - finish_action(controller, FALSE, target_key, delivery_key) - return - - finish_action(controller, TRUE, target_key, delivery_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/fetch_seek/finish_action(datum/ai_controller/controller, success, target_key, delivery_key) . = ..() @@ -53,14 +49,13 @@ set_movement_target(controller, return_target) /datum/ai_behavior/deliver_fetched_item/perform(seconds_per_tick, datum/ai_controller/controller, delivery_key, storage_key) - . = ..() var/mob/living/return_target = controller.blackboard[delivery_key] if(QDELETED(return_target)) - finish_action(controller, FALSE, delivery_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED - deliver_item(controller, return_target, storage_key) - finish_action(controller, TRUE, delivery_key) + if(!deliver_item(controller, return_target, storage_key)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/deliver_fetched_item/finish_action(datum/ai_controller/controller, success, delivery_key) . = ..() @@ -68,13 +63,13 @@ controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) /// Actually deliver the fetched item to the target, if we still have it +/// Returns TRUE if we succeeded, FALSE if we failed /datum/ai_behavior/deliver_fetched_item/proc/deliver_item(datum/ai_controller/controller, return_target, storage_key) var/mob/pawn = controller.pawn var/obj/item/carried_item = controller.blackboard[storage_key] if(QDELETED(carried_item) || carried_item.loc != pawn) pawn.visible_message(span_notice("[pawn] looks around as if [pawn.p_they()] [pawn.p_have()] lost something.")) - finish_action(controller, FALSE) - return + return FALSE pawn.visible_message(span_notice("[pawn] delivers [carried_item] to [return_target].")) carried_item.forceMove(get_turf(return_target)) @@ -99,26 +94,26 @@ set_movement_target(controller, snack) /datum/ai_behavior/eat_fetched_snack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, delivery_key) - . = ..() var/obj/item/snack = controller.blackboard[target_key] var/is_living_loc = isliving(snack.loc) if(QDELETED(snack) || (!isturf(snack.loc) && !is_living_loc)) - finish_action(controller, FALSE) // Where did it go? - return + // Where did it go? + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/basic/basic_pawn = controller.pawn if(is_living_loc) if(SPT_PROB(10, seconds_per_tick)) basic_pawn.manual_emote("Stares at [snack.loc]'s [snack.name] intently.") - return + return AI_BEHAVIOR_DELAY if(!basic_pawn.Adjacent(snack)) - return + return AI_BEHAVIOR_DELAY basic_pawn.melee_attack(snack) // snack attack! if(QDELETED(snack)) // we ate it! - finish_action(controller, TRUE, target_key, delivery_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY /datum/ai_behavior/eat_fetched_snack/finish_action(datum/ai_controller/controller, succeeded, target_key, delivery_key) . = ..() @@ -143,7 +138,6 @@ return /datum/ai_behavior/forget_failed_fetches/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() COOLDOWN_START(src, reset_ignore_cooldown, cooldown_duration) controller.clear_blackboard_key(BB_FETCH_IGNORE_LIST) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/pet_commands/pet_follow_friend.dm b/code/datums/ai/basic_mobs/pet_commands/pet_follow_friend.dm index 397021818aa86..38a6939c90186 100644 --- a/code/datums/ai/basic_mobs/pet_commands/pet_follow_friend.dm +++ b/code/datums/ai/basic_mobs/pet_commands/pet_follow_friend.dm @@ -10,8 +10,7 @@ set_movement_target(controller, target) /datum/ai_behavior/pet_follow_friend/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/atom/target = controller.blackboard[target_key] if (QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + return AI_BEHAVIOR_DELAY diff --git a/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm b/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm index c7153b0c12f7a..3c8c06b009962 100644 --- a/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm +++ b/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm @@ -13,11 +13,11 @@ var/datum/action/cooldown/mob_cooldown/ability = controller.blackboard[ability_key] var/mob/living/target = controller.blackboard[target_key] if (QDELETED(ability) || QDELETED(target)) - finish_action(controller, FALSE, ability_key, target_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED var/mob/pawn = controller.pawn if(QDELETED(pawn) || ability.InterceptClickOn(pawn, null, target)) - finish_action(controller, TRUE, ability_key, target_key) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_INSTANT /datum/ai_behavior/pet_use_ability/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key) . = ..() diff --git a/code/datums/ai/basic_mobs/pet_commands/play_dead.dm b/code/datums/ai/basic_mobs/pet_commands/play_dead.dm index c4b99cf6f42b1..5a7a09430260b 100644 --- a/code/datums/ai/basic_mobs/pet_commands/play_dead.dm +++ b/code/datums/ai/basic_mobs/pet_commands/play_dead.dm @@ -11,9 +11,9 @@ basic_pawn.look_dead() /datum/ai_behavior/play_dead/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() if(SPT_PROB(10, seconds_per_tick)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY /datum/ai_behavior/play_dead/finish_action(datum/ai_controller/controller, succeeded) . = ..() diff --git a/code/datums/ai/dog/dog_behaviors.dm b/code/datums/ai/dog/dog_behaviors.dm index c7723eab1a182..00a2f789e12b5 100644 --- a/code/datums/ai/dog/dog_behaviors.dm +++ b/code/datums/ai/dog/dog_behaviors.dm @@ -8,26 +8,24 @@ required_distance = 3 /datum/ai_behavior/basic_melee_attack/dog/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) - controller.behavior_cooldowns[src] = world.time + action_cooldown + controller.behavior_cooldowns[src] = world.time + get_cooldown(controller) var/mob/living/living_pawn = controller.pawn if(!(isturf(living_pawn.loc) || HAS_TRAIT(living_pawn, TRAIT_AI_BAGATTACK))) // Void puppies can attack from inside bags - finish_action(controller, FALSE, target_key, targeting_strategy_key, hiding_location_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED // Unfortunately going to repeat this check in parent call but what can you do var/atom/target = controller.blackboard[target_key] var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) if (!targeting_strategy.can_attack(living_pawn, target)) - finish_action(controller, FALSE, target_key, targeting_strategy_key, hiding_location_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED if (!living_pawn.Adjacent(target)) growl_at(living_pawn, target, seconds_per_tick) - return + return AI_BEHAVIOR_INSTANT if(!controller.blackboard[BB_DOG_HARASS_HARM]) paw_harmlessly(living_pawn, target, seconds_per_tick) - return + return AI_BEHAVIOR_INSTANT // Give Ian some teeth var/old_melee_lower = living_pawn.melee_damage_lower @@ -39,6 +37,7 @@ living_pawn.melee_damage_lower = old_melee_lower living_pawn.melee_damage_upper = old_melee_upper + return AI_BEHAVIOR_DELAY /// Swat at someone we don't like but won't hurt /datum/ai_behavior/basic_melee_attack/dog/proc/paw_harmlessly(mob/living/living_pawn, atom/target, seconds_per_tick) diff --git a/code/datums/ai/dog/dog_subtrees.dm b/code/datums/ai/dog/dog_subtrees.dm index 62f63da54bdd0..74c075adad3a1 100644 --- a/code/datums/ai/dog/dog_subtrees.dm +++ b/code/datums/ai/dog/dog_subtrees.dm @@ -35,5 +35,4 @@ controller.clear_blackboard_key(target_key) /datum/ai_behavior/find_hated_dog_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/generic/find_and_set.dm b/code/datums/ai/generic/find_and_set.dm index fbddc33075c46..41f256c9ba73f 100644 --- a/code/datums/ai/generic/find_and_set.dm +++ b/code/datums/ai/generic/find_and_set.dm @@ -7,19 +7,15 @@ action_cooldown = 2 SECONDS /datum/ai_behavior/find_and_set/perform(seconds_per_tick, datum/ai_controller/controller, set_key, locate_path, search_range) - . = ..() if (controller.blackboard_key_exists(set_key)) - finish_action(controller, TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED if(QDELETED(controller.pawn)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED var/find_this_thing = search_tactic(controller, locate_path, search_range) if(isnull(find_this_thing)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(set_key, find_this_thing) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/find_and_set/proc/search_tactic(datum/ai_controller/controller, locate_path, search_range) return locate(locate_path) in oview(search_range, controller.pawn) diff --git a/code/datums/ai/generic/generic_behaviors.dm b/code/datums/ai/generic/generic_behaviors.dm index b70375ef3933f..1c0e1f65adf96 100644 --- a/code/datums/ai/generic/generic_behaviors.dm +++ b/code/datums/ai/generic/generic_behaviors.dm @@ -1,28 +1,25 @@ /datum/ai_behavior/resist/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/living_pawn = controller.pawn living_pawn.ai_controller.set_blackboard_key(BB_RESISTING, TRUE) living_pawn.execute_resist() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/battle_screech ///List of possible screeches the behavior has var/list/screeches /datum/ai_behavior/battle_screech/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/living_pawn = controller.pawn INVOKE_ASYNC(living_pawn, TYPE_PROC_REF(/mob, emote), pick(screeches)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED ///Moves to target then finishes /datum/ai_behavior/move_to_target behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT /datum/ai_behavior/move_to_target/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/break_spine @@ -42,12 +39,10 @@ var/mob/living/big_guy = controller.pawn //he was molded by the darkness if(QDELETED(batman) || get_dist(batman, big_guy) >= give_up_distance) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED if(batman.stat != CONSCIOUS) - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED big_guy.start_pulling(batman) big_guy.face_atom(batman) @@ -63,7 +58,7 @@ else batman.adjustBruteLoss(150) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/break_spine/finish_action(datum/ai_controller/controller, succeeded, target_key) if(succeeded) @@ -80,14 +75,12 @@ /datum/ai_behavior/use_in_hand/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/pawn = controller.pawn var/obj/item/held = pawn.get_active_held_item() if(!held) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED pawn.activate_hand() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /// Use the currently held item, or unarmed, on a weakref to an object in the world /datum/ai_behavior/use_on_object @@ -102,13 +95,11 @@ set_movement_target(controller, target) /datum/ai_behavior/use_on_object/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/pawn = controller.pawn var/obj/item/held_item = pawn.get_item_by_slot(pawn.get_active_hand()) var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED pawn.set_combat_mode(FALSE) if(held_item) @@ -116,7 +107,7 @@ else pawn.UnarmedAttack(target, TRUE) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/give behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH @@ -127,37 +118,34 @@ set_movement_target(controller, controller.blackboard[target_key]) /datum/ai_behavior/give/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/pawn = controller.pawn var/obj/item/held_item = pawn.get_active_held_item() var/atom/target = controller.blackboard[target_key] if(!held_item) //if held_item is null, we pretend that action was succesful - finish_action(controller, TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED if(!target || !isliving(target)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_target = target - - if(!try_to_give_item(controller, living_target, held_item)) - return + var/perform_flags = try_to_give_item(controller, living_target, held_item) + if(perform_flags & AI_BEHAVIOR_FAILED) + return perform_flags controller.PauseAi(1.5 SECONDS) living_target.visible_message( span_info("[pawn] starts trying to give [held_item] to [living_target]!"), span_warning("[pawn] tries to give you [held_item]!") ) if(!do_after(pawn, 1 SECONDS, living_target)) - return + return AI_BEHAVIOR_DELAY | perform_flags - try_to_give_item(controller, living_target, held_item, actually_give = TRUE) + perform_flags |= try_to_give_item(controller, living_target, held_item, actually_give = TRUE) + return AI_BEHAVIOR_DELAY | perform_flags /datum/ai_behavior/give/proc/try_to_give_item(datum/ai_controller/controller, mob/living/target, obj/item/held_item, actually_give) if(QDELETED(held_item) || QDELETED(target)) - finish_action(controller, FALSE) - return FALSE + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/has_left_pocket = target.can_equip(held_item, ITEM_SLOT_LPOCKET) var/has_right_pocket = target.can_equip(held_item, ITEM_SLOT_RPOCKET) @@ -169,17 +157,16 @@ break if(!has_left_pocket && !has_right_pocket && !has_valid_hand) - finish_action(controller, FALSE) - return FALSE + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(!actually_give) - return TRUE + return AI_BEHAVIOR_DELAY if(!has_valid_hand || prob(50)) target.equip_to_slot_if_possible(held_item, (!has_left_pocket ? ITEM_SLOT_RPOCKET : (prob(50) ? ITEM_SLOT_LPOCKET : ITEM_SLOT_RPOCKET))) else target.put_in_hands(held_item) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/consume @@ -191,21 +178,20 @@ set_movement_target(controller, controller.blackboard[target_key]) /datum/ai_behavior/consume/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hunger_timer_key) - . = ..() var/mob/living/living_pawn = controller.pawn var/obj/item/target = controller.blackboard[target_key] if(QDELETED(target)) - return + return AI_BEHAVIOR_DELAY if(!(target in living_pawn.held_items)) if(!living_pawn.get_empty_held_indexes() || !living_pawn.put_in_hands(target)) - finish_action(controller, FALSE, target, hunger_timer_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED target.melee_attack_chain(living_pawn, living_pawn) if(QDELETED(target) || prob(10)) // Even if we don't finish it all we can randomly decide to be done - finish_action(controller, TRUE, null, hunger_timer_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY /datum/ai_behavior/consume/finish_action(datum/ai_controller/controller, succeeded, target_key, hunger_timer_key) . = ..() @@ -218,36 +204,34 @@ /datum/ai_behavior/drop_item /datum/ai_behavior/drop_item/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/living_pawn = controller.pawn var/obj/item/best_held = GetBestWeapon(controller, null, living_pawn.held_items) for(var/obj/item/held as anything in living_pawn.held_items) if(!held || held == best_held) continue living_pawn.dropItemToGround(held) + return AI_BEHAVIOR_DELAY /// This behavior involves attacking a target. /datum/ai_behavior/attack behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM | AI_BEHAVIOR_REQUIRE_REACH /datum/ai_behavior/attack/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/living_pawn = controller.pawn if(!istype(living_pawn) || !isturf(living_pawn.loc)) - return + return AI_BEHAVIOR_DELAY var/atom/movable/attack_target = controller.blackboard[BB_ATTACK_TARGET] if(!attack_target || !can_see(living_pawn, attack_target, length = controller.blackboard[BB_VISION_RANGE])) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_target = attack_target if(istype(living_target) && (living_target.stat == DEAD)) - finish_action(controller, TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED set_movement_target(controller, living_target) attack(controller, living_target) + return AI_BEHAVIOR_DELAY /datum/ai_behavior/attack/finish_action(datum/ai_controller/controller, succeeded) . = ..() @@ -265,22 +249,20 @@ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM /datum/ai_behavior/follow/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/living_pawn = controller.pawn if(!istype(living_pawn) || !isturf(living_pawn.loc)) - return + return AI_BEHAVIOR_DELAY var/atom/movable/follow_target = controller.blackboard[BB_FOLLOW_TARGET] if(!follow_target || get_dist(living_pawn, follow_target) > controller.blackboard[BB_VISION_RANGE]) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_target = follow_target if(istype(living_target) && (living_target.stat == DEAD)) - finish_action(controller, TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED set_movement_target(controller, living_target) + return AI_BEHAVIOR_DELAY /datum/ai_behavior/follow/finish_action(datum/ai_controller/controller, succeeded) . = ..() @@ -291,11 +273,11 @@ /datum/ai_behavior/perform_emote/perform(seconds_per_tick, datum/ai_controller/controller, emote, speech_sound) var/mob/living/living_pawn = controller.pawn if(!istype(living_pawn)) - return + return AI_BEHAVIOR_INSTANT living_pawn.manual_emote(emote) if(speech_sound) // Only audible emotes will pass in a sound playsound(living_pawn, speech_sound, 80, vary = TRUE) - finish_action(controller, TRUE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/perform_speech @@ -304,29 +286,26 @@ var/mob/living/living_pawn = controller.pawn if(!istype(living_pawn)) - return + return AI_BEHAVIOR_INSTANT living_pawn.say(speech, forced = "AI Controller") if(speech_sound) playsound(living_pawn, speech_sound, 80, vary = TRUE) - finish_action(controller, TRUE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/perform_speech_radio /datum/ai_behavior/perform_speech_radio/perform(seconds_per_tick, datum/ai_controller/controller, speech, obj/item/radio/speech_radio, list/try_channels = list(RADIO_CHANNEL_COMMON)) var/mob/living/living_pawn = controller.pawn if(!istype(living_pawn) || !istype(speech_radio) || QDELETED(speech_radio) || !length(try_channels)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED speech_radio.talk_into(living_pawn, speech, pick(try_channels)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED //song behaviors /datum/ai_behavior/setup_instrument /datum/ai_behavior/setup_instrument/perform(seconds_per_tick, datum/ai_controller/controller, song_instrument_key, song_lines_key) - . = ..() - var/obj/item/instrument/song_instrument = controller.blackboard[song_instrument_key] var/datum/song/song = song_instrument.song var/song_lines = controller.blackboard[song_lines_key] @@ -336,24 +315,20 @@ song.ParseSong(new_song = song_lines) song.repeat = 10 song.volume = song.max_volume - 10 - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/play_instrument /datum/ai_behavior/play_instrument/perform(seconds_per_tick, datum/ai_controller/controller, song_instrument_key) - . = ..() - var/obj/item/instrument/song_instrument = controller.blackboard[song_instrument_key] var/datum/song/song = song_instrument.song song.start_playing(controller.pawn) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/find_nearby /datum/ai_behavior/find_nearby/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - var/list/possible_targets = list() for(var/atom/thing in view(2, controller.pawn)) if(!thing.mouse_opacity) @@ -366,6 +341,6 @@ continue possible_targets += thing if(!possible_targets.len) - finish_action(controller, FALSE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(target_key, pick(possible_targets)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/hunting_behavior/hunting_behaviors.dm b/code/datums/ai/hunting_behavior/hunting_behaviors.dm index 07fc84997a68e..609138c113270 100644 --- a/code/datums/ai/hunting_behavior/hunting_behaviors.dm +++ b/code/datums/ai/hunting_behavior/hunting_behaviors.dm @@ -52,18 +52,14 @@ /datum/ai_behavior/find_hunt_target /datum/ai_behavior/find_hunt_target/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, types_to_hunt, hunt_range) - . = ..() - var/mob/living/living_mob = controller.pawn for(var/atom/possible_dinner as anything in typecache_filter_list(range(hunt_range, living_mob), types_to_hunt)) if(!valid_dinner(living_mob, possible_dinner, hunt_range, controller, seconds_per_tick)) continue controller.set_blackboard_key(hunting_target_key, possible_dinner) - finish_action(controller, TRUE, hunting_target_key) - return - - finish_action(controller, FALSE, hunting_target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/find_hunt_target/proc/valid_dinner(mob/living/source, atom/dinner, radius, datum/ai_controller/controller, seconds_per_tick) if(isliving(dinner)) @@ -90,15 +86,13 @@ set_movement_target(controller, hunt_target) /datum/ai_behavior/hunt_target/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, hunting_cooldown_key) - . = ..() var/mob/living/hunter = controller.pawn var/atom/hunted = controller.blackboard[hunting_target_key] if(QDELETED(hunted)) - finish_action(controller, FALSE, hunting_target_key) - else - target_caught(hunter, hunted) - finish_action(controller, TRUE, hunting_target_key, hunting_cooldown_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + target_caught(hunter, hunted) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/hunt_target/proc/target_caught(mob/living/hunter, atom/hunted) if(isliving(hunted)) // Are we hunting a living mob? @@ -153,7 +147,7 @@ /datum/ai_behavior/hunt_target/use_ability_on_target/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, hunting_cooldown_key) var/datum/action/cooldown/ability = controller.blackboard[ability_key] if(!ability?.IsAvailable()) - finish_action(controller, FALSE, hunting_target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED return ..() /datum/ai_behavior/hunt_target/use_ability_on_target/target_caught(mob/living/hunter, atom/hunted) diff --git a/code/datums/ai/monkey/monkey_behaviors.dm b/code/datums/ai/monkey/monkey_behaviors.dm index d16110cd70201..af9091db2dd1d 100644 --- a/code/datums/ai/monkey/monkey_behaviors.dm +++ b/code/datums/ai/monkey/monkey_behaviors.dm @@ -12,55 +12,51 @@ controller.clear_blackboard_key(BB_MONKEY_PICKUPTARGET) +/// Equips an item on the monkey +/// Returns TRUE if it works out, FALSE otherwise /datum/ai_behavior/monkey_equip/proc/equip_item(datum/ai_controller/controller) var/mob/living/living_pawn = controller.pawn var/obj/item/target = controller.blackboard[BB_MONKEY_PICKUPTARGET] var/best_force = controller.blackboard[BB_MONKEY_BEST_FORCE_FOUND] - if(!isturf(living_pawn.loc)) - finish_action(controller, FALSE) - return + return FALSE if(!target) - finish_action(controller, FALSE) - return + return FALSE if(target.anchored) //Can't pick it up, so stop trying. - finish_action(controller, FALSE) - return + return FALSE // Strong weapon else if(target.force > best_force) living_pawn.drop_all_held_items() living_pawn.put_in_hands(target) controller.set_blackboard_key(BB_MONKEY_BEST_FORCE_FOUND, target.force) - finish_action(controller, TRUE) - return + return TRUE else if(target.slot_flags) //Clothing == top priority living_pawn.dropItemToGround(target, TRUE) living_pawn.update_icons() if(!living_pawn.equip_to_appropriate_slot(target)) - finish_action(controller, FALSE) - return //Already wearing something, in the future this should probably replace the current item but the code didn't actually do that, and I dont want to support it right now. - finish_action(controller, TRUE) - return + return FALSE //Already wearing something, in the future this should probably replace the current item but the code didn't actually do that, and I dont want to support it right now. + return TRUE // EVERYTHING ELSE else if(living_pawn.get_empty_held_indexes()) living_pawn.put_in_hands(target) - finish_action(controller, TRUE) - return + return TRUE - finish_action(controller, FALSE) + return FALSE /datum/ai_behavior/monkey_equip/ground required_distance = 0 /datum/ai_behavior/monkey_equip/ground/perform(seconds_per_tick, datum/ai_controller/controller) . = ..() - equip_item(controller) + if(equip_item(controller)) + return . | AI_BEHAVIOR_SUCCEEDED + return . | AI_BEHAVIOR_FAILED /datum/ai_behavior/monkey_equip/pickpocket @@ -110,13 +106,10 @@ /datum/ai_behavior/monkey_flee /datum/ai_behavior/monkey_flee/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() - var/mob/living/living_pawn = controller.pawn - if(living_pawn.health >= MONKEY_FLEE_HEALTH) - finish_action(controller, TRUE) //we're back in bussiness - return + if(living_pawn.health >= MONKEY_FLEE_HEALTH) //we're back in bussiness + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED var/mob/living/target = null @@ -127,9 +120,9 @@ break if(target) - SSmove_manager.move_away(living_pawn, target, max_dist=MONKEY_ENEMY_VISION, delay=5) - else - finish_action(controller, TRUE) + GLOB.move_manager.move_away(living_pawn, target, max_dist=MONKEY_ENEMY_VISION, delay=5) + return AI_BEHAVIOR_DELAY + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/monkey_attack_mob behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM //performs to increase frustration @@ -139,29 +132,28 @@ set_movement_target(controller, controller.blackboard[target_key]) /datum/ai_behavior/monkey_attack_mob/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - var/mob/living/target = controller.blackboard[target_key] var/mob/living/living_pawn = controller.pawn - if(!target || target.stat != CONSCIOUS) - finish_action(controller, TRUE) //Target == owned - return + if(!target || target.stat != CONSCIOUS) //Target == owned + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED - if(isturf(target.loc) && !IS_DEAD_OR_INCAP(living_pawn)) // Check if they're a valid target - // check if target has a weapon - var/obj/item/W - for(var/obj/item/I in target.held_items) - if(!(I.item_flags & ABSTRACT)) - W = I - break - - // if the target has a weapon, chance to disarm them - if(W && SPT_PROB(MONKEY_ATTACK_DISARM_PROB, seconds_per_tick)) - monkey_attack(controller, target, seconds_per_tick, TRUE) - else - monkey_attack(controller, target, seconds_per_tick, FALSE) + if(!isturf(target.loc) || IS_DEAD_OR_INCAP(living_pawn)) // Check if they're a valid target + return AI_BEHAVIOR_DELAY + // check if target has a weapon + var/obj/item/W + for(var/obj/item/I in target.held_items) + if(!(I.item_flags & ABSTRACT)) + W = I + break + // if the target has a weapon, chance to disarm them + var/perform_flags = NONE + if(W && SPT_PROB(MONKEY_ATTACK_DISARM_PROB, seconds_per_tick)) + perform_flags = monkey_attack(controller, target, seconds_per_tick, TRUE) + else + perform_flags = monkey_attack(controller, target, seconds_per_tick, FALSE) + return AI_BEHAVIOR_DELAY | perform_flags /datum/ai_behavior/monkey_attack_mob/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() @@ -169,14 +161,14 @@ controller.clear_blackboard_key(target_key) if(QDELETED(living_pawn)) // pawn can be null at this point return - SSmove_manager.stop_looping(living_pawn) + GLOB.move_manager.stop_looping(living_pawn) /// attack using a held weapon otherwise bite the enemy, then if we are angry there is a chance we might calm down a little /datum/ai_behavior/monkey_attack_mob/proc/monkey_attack(datum/ai_controller/controller, mob/living/target, seconds_per_tick, disarm) var/mob/living/living_pawn = controller.pawn if(living_pawn.next_move > world.time) - return + return NONE living_pawn.changeNext_move(CLICK_CD_MELEE) //We play fair @@ -215,7 +207,7 @@ // no de-aggro if(controller.blackboard[BB_MONKEY_AGGRESSIVE]) - return + return NONE // we've queued up a monkey attack on a mob which isn't already an enemy, so give them 1 threat to start // note they might immediately reduce threat and drop from the list. @@ -238,7 +230,8 @@ if(controller.blackboard[BB_MONKEY_ENEMIES][target] <= 0) controller.remove_thing_from_blackboard_key(BB_MONKEY_ENEMIES, target) if(controller.blackboard[BB_MONKEY_CURRENT_ATTACK_TARGET] == target) - finish_action(controller, TRUE) + return AI_BEHAVIOR_SUCCEEDED + return NONE /datum/ai_behavior/disposal_mob behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM //performs to increase frustration @@ -254,10 +247,8 @@ controller.clear_blackboard_key(disposal_target_key) //No target disposal /datum/ai_behavior/disposal_mob/perform(seconds_per_tick, datum/ai_controller/controller, attack_target_key, disposal_target_key) - . = ..() - if(controller.blackboard[BB_MONKEY_DISPOSING]) //We are disposing, don't do ANYTHING!!!! - return + return AI_BEHAVIOR_DELAY var/mob/living/target = controller.blackboard[attack_target_key] var/mob/living/living_pawn = controller.pawn @@ -265,25 +256,24 @@ set_movement_target(controller, target) if(!target) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(target.pulledby != living_pawn && !HAS_AI_CONTROLLER_TYPE(target.pulledby, /datum/ai_controller/monkey)) //Dont steal from my fellow monkeys. if(living_pawn.Adjacent(target) && isturf(target.loc)) target.grabbedby(living_pawn) - return //Do the rest next turn + return AI_BEHAVIOR_DELAY //Do the rest next turn var/obj/machinery/disposal/disposal = controller.blackboard[disposal_target_key] set_movement_target(controller, disposal) if(!disposal) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(living_pawn.Adjacent(disposal)) INVOKE_ASYNC(src, PROC_REF(try_disposal_mob), controller, attack_target_key, disposal_target_key) //put him in! - else //This means we might be getting pissed! - return + return AI_BEHAVIOR_DELAY + //This means we might be getting pissed! + return AI_BEHAVIOR_DELAY /datum/ai_behavior/disposal_mob/proc/try_disposal_mob(datum/ai_controller/controller, attack_target_key, disposal_target_key) var/mob/living/living_pawn = controller.pawn @@ -298,8 +288,6 @@ /datum/ai_behavior/recruit_monkeys/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() - controller.set_blackboard_key(BB_MONKEY_RECRUIT_COOLDOWN, world.time + MONKEY_RECRUIT_COOLDOWN) var/mob/living/living_pawn = controller.pawn @@ -313,7 +301,7 @@ // Other monkeys now also hate the guy we're currently targeting nearby_monkey.ai_controller.add_blackboard_key_assoc(BB_MONKEY_ENEMIES, controller.blackboard[BB_MONKEY_CURRENT_ATTACK_TARGET], MONKEY_RECRUIT_HATED_AMOUNT) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/monkey_set_combat_target/perform(seconds_per_tick, datum/ai_controller/controller, set_key, enemies_key) var/list/enemies = controller.blackboard[enemies_key] @@ -330,8 +318,7 @@ valids[possible_enemy] = CEILING(100 / (get_dist(controller.pawn, possible_enemy) || 1), 1) if(!length(valids)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED controller.set_blackboard_key(set_key, pick_weight(valids)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm index 215f0a96302f3..693427ba4bd10 100644 --- a/code/datums/ai/monkey/monkey_controller.dm +++ b/code/datums/ai/monkey/monkey_controller.dm @@ -45,7 +45,7 @@ have ways of interacting with a specific mob and control it. /datum/ai_controller/monkey/New(atom/new_pawn) var/static/list/control_examine = list( - ORGAN_SLOT_EYES = span_monkey("eyes have a primal look in them."), + ORGAN_SLOT_EYES = span_monkey("%PRONOUN_They stare%PRONOUN_s around with wild, primal eyes."), ) AddElement(/datum/element/ai_control_examine, control_examine) return ..() diff --git a/code/datums/ai/movement/_ai_movement.dm b/code/datums/ai/movement/_ai_movement.dm index 3f455b2acd0ab..ca8acb4904039 100644 --- a/code/datums/ai/movement/_ai_movement.dm +++ b/code/datums/ai/movement/_ai_movement.dm @@ -17,7 +17,7 @@ moving_controllers -= controller // We got deleted as we finished an action if(!QDELETED(controller.pawn)) - SSmove_manager.stop_looping(controller.pawn, SSai_movement) + GLOB.move_manager.stop_looping(controller.pawn, SSai_movement) /datum/ai_movement/proc/increment_pathing_failures(datum/ai_controller/controller) controller.consecutive_pathing_attempts++ @@ -72,7 +72,8 @@ /datum/ai_movement/proc/post_move(datum/move_loop/source, succeeded) SIGNAL_HANDLER var/datum/ai_controller/controller = source.extra_info - if(succeeded != MOVELOOP_FAILURE) - reset_pathing_failures(controller) - return - increment_pathing_failures(controller) + switch(succeeded) + if(MOVELOOP_SUCCESS) + reset_pathing_failures(controller) + if(MOVELOOP_FAILURE) + increment_pathing_failures(controller) diff --git a/code/datums/ai/movement/ai_movement_basic_avoidance.dm b/code/datums/ai/movement/ai_movement_basic_avoidance.dm index 6b48f1b5e9e1f..ac231e075ed14 100644 --- a/code/datums/ai/movement/ai_movement_basic_avoidance.dm +++ b/code/datums/ai/movement/ai_movement_basic_avoidance.dm @@ -9,7 +9,7 @@ var/atom/movable/moving = controller.pawn var/min_dist = controller.blackboard[BB_CURRENT_MIN_MOVE_DISTANCE] var/delay = controller.movement_delay - var/datum/move_loop/loop = SSmove_manager.move_to(moving, current_movement_target, min_dist, delay, flags = move_flags, subsystem = SSai_movement, extra_info = controller) + var/datum/move_loop/loop = GLOB.move_manager.move_to(moving, current_movement_target, min_dist, delay, flags = move_flags, subsystem = SSai_movement, extra_info = controller) RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move)) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(post_move)) diff --git a/code/datums/ai/movement/ai_movement_complete_stop.dm b/code/datums/ai/movement/ai_movement_complete_stop.dm index dcae93f1ba0a5..2b39e162719ff 100644 --- a/code/datums/ai/movement/ai_movement_complete_stop.dm +++ b/code/datums/ai/movement/ai_movement_complete_stop.dm @@ -8,8 +8,8 @@ var/stopping_time = controller.blackboard[BB_STATIONARY_SECONDS] var/delay_time = (stopping_time * 0.5) // no real reason to fire any more often than this really // assume that the current_movement_target is our location - var/datum/move_loop/loop = SSmove_manager.freeze(moving, current_movement_target, delay = delay_time, timeout = stopping_time, subsystem = SSai_movement, extra_info = controller) + var/datum/move_loop/loop = GLOB.move_manager.freeze(moving, current_movement_target, delay = delay_time, timeout = stopping_time, subsystem = SSai_movement, extra_info = controller) RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move)) /datum/ai_movement/complete_stop/allowed_to_move(datum/move_loop/source) - return FALSE + return FALSE diff --git a/code/datums/ai/movement/ai_movement_dumb.dm b/code/datums/ai/movement/ai_movement_dumb.dm index 06ac4bdd10c4c..2de85046a941f 100644 --- a/code/datums/ai/movement/ai_movement_dumb.dm +++ b/code/datums/ai/movement/ai_movement_dumb.dm @@ -7,7 +7,7 @@ . = ..() var/atom/movable/moving = controller.pawn var/delay = controller.movement_delay - var/datum/move_loop/loop = SSmove_manager.move_towards_legacy(moving, current_movement_target, delay, subsystem = SSai_movement, extra_info = controller) + var/datum/move_loop/loop = GLOB.move_manager.move_towards_legacy(moving, current_movement_target, delay, subsystem = SSai_movement, extra_info = controller) RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move)) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(post_move)) diff --git a/code/datums/ai/movement/ai_movement_jps.dm b/code/datums/ai/movement/ai_movement_jps.dm index 825feefabfa3b..d6f37c2a9561d 100644 --- a/code/datums/ai/movement/ai_movement_jps.dm +++ b/code/datums/ai/movement/ai_movement_jps.dm @@ -12,7 +12,7 @@ var/atom/movable/moving = controller.pawn var/delay = controller.movement_delay - var/datum/move_loop/has_target/jps/loop = SSmove_manager.jps_move(moving, + var/datum/move_loop/has_target/jps/loop = GLOB.move_manager.jps_move(moving, current_movement_target, delay, repath_delay = 0.5 SECONDS, diff --git a/code/datums/ai/objects/mod.dm b/code/datums/ai/objects/mod.dm index 67d8121a4e16f..edad77aa4c4af 100644 --- a/code/datums/ai/objects/mod.dm +++ b/code/datums/ai/objects/mod.dm @@ -34,12 +34,11 @@ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT|AI_BEHAVIOR_MOVE_AND_PERFORM /datum/ai_behavior/mod_attach/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() if(!controller.pawn.Adjacent(controller.blackboard[BB_MOD_TARGET])) - return + return AI_BEHAVIOR_DELAY var/obj/item/implant/mod/implant = controller.blackboard[BB_MOD_IMPLANT] implant.module.attach(controller.blackboard[BB_MOD_TARGET]) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/mod_attach/finish_action(datum/ai_controller/controller, succeeded) . = ..() diff --git a/code/datums/ai/objects/vending_machines/vending_machine_behaviors.dm b/code/datums/ai/objects/vending_machines/vending_machine_behaviors.dm index b4e5609531c18..d6310bfc9f3b1 100644 --- a/code/datums/ai/objects/vending_machines/vending_machine_behaviors.dm +++ b/code/datums/ai/objects/vending_machines/vending_machine_behaviors.dm @@ -10,15 +10,15 @@ set_movement_target(controller, controller.blackboard[target_key]) /datum/ai_behavior/vendor_crush/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() if(controller.blackboard[BB_VENDING_BUSY_TILTING]) - return + return AI_BEHAVIOR_DELAY controller.ai_movement.stop_moving_towards(controller) controller.set_blackboard_key(BB_VENDING_BUSY_TILTING, TRUE) var/turf/target_turf = get_turf(controller.blackboard[BB_VENDING_CURRENT_TARGET]) new /obj/effect/temp_visual/telegraphing/vending_machine_tilt(target_turf) addtimer(CALLBACK(src, PROC_REF(tiltonmob), controller, target_turf), time_to_tilt) + return AI_BEHAVIOR_DELAY /datum/ai_behavior/vendor_crush/proc/tiltonmob(datum/ai_controller/controller, turf/target_turf) var/obj/machinery/vending/vendor_pawn = controller.pawn @@ -40,10 +40,9 @@ var/succes_tilt_cooldown = 5 SECONDS /datum/ai_behavior/vendor_rise_up/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/obj/machinery/vending/vendor_pawn = controller.pawn vendor_pawn.visible_message(span_warning("[vendor_pawn] untilts itself!")) if(controller.blackboard[BB_VENDING_LAST_HIT_SUCCESFUL]) controller.set_blackboard_key(BB_VENDING_TILT_COOLDOWN, world.time + succes_tilt_cooldown) vendor_pawn.untilt() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/oldhostile/hostile_tameable.dm b/code/datums/ai/oldhostile/hostile_tameable.dm index 5c96eca17da43..d76ffb8a282d4 100644 --- a/code/datums/ai/oldhostile/hostile_tameable.dm +++ b/code/datums/ai/oldhostile/hostile_tameable.dm @@ -108,7 +108,7 @@ return if(!istype(clicker) || blackboard[BB_HOSTILE_FRIEND] != clicker) return - . = COMPONENT_CANCEL_CLICK_ALT + . = CLICK_ACTION_BLOCKING INVOKE_ASYNC(src, PROC_REF(command_radial), clicker) /// Show the command radial menu diff --git a/code/datums/ai/robot_customer/robot_customer_behaviors.dm b/code/datums/ai/robot_customer/robot_customer_behaviors.dm index 35fd26d76f6fe..7aa0f34f5207d 100644 --- a/code/datums/ai/robot_customer/robot_customer_behaviors.dm +++ b/code/datums/ai/robot_customer/robot_customer_behaviors.dm @@ -2,7 +2,6 @@ action_cooldown = 8 SECONDS /datum/ai_behavior/find_seat/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/basic/robot_customer/customer_pawn = controller.pawn var/datum/customer_data/customer_data = controller.blackboard[BB_CUSTOMER_CUSTOMERINFO] var/datum/venue/attending_venue = controller.blackboard[BB_CUSTOMER_ATTENDING_VENUE] @@ -28,22 +27,20 @@ customer_pawn.say(pick(customer_data.found_seat_lines)) controller.set_blackboard_key(BB_CUSTOMER_MY_SEAT, found_seat) attending_venue.linked_seats[found_seat] = customer_pawn - finish_action(controller, TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED // SPT_PROB 1.5 is about a 60% chance that the tourist will have vocalised at least once every minute. if(!controller.blackboard[BB_CUSTOMER_SAID_CANT_FIND_SEAT_LINE] || SPT_PROB(1.5, seconds_per_tick)) customer_pawn.say(pick(customer_data.cant_find_seat_lines)) controller.set_blackboard_key(BB_CUSTOMER_SAID_CANT_FIND_SEAT_LINE, TRUE) - finish_action(controller, FALSE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/order_food behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT required_distance = 0 /datum/ai_behavior/order_food/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/basic/robot_customer/customer_pawn = controller.pawn var/datum/customer_data/customer_data = controller.blackboard[BB_CUSTOMER_CUSTOMERINFO] var/obj/structure/holosign/robot_seat/seat_marker = controller.blackboard[BB_CUSTOMER_MY_SEAT] @@ -55,23 +52,19 @@ var/datum/venue/attending_venue = controller.blackboard[BB_CUSTOMER_ATTENDING_VENUE] controller.set_blackboard_key(BB_CUSTOMER_CURRENT_ORDER, attending_venue.order_food(customer_pawn, customer_data)) - - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/wait_for_food behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM required_distance = 0 /datum/ai_behavior/wait_for_food/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() if(controller.blackboard[BB_CUSTOMER_EATING]) - finish_action(controller, TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED controller.add_blackboard_key(BB_CUSTOMER_PATIENCE, seconds_per_tick * -1 SECONDS) // Convert seconds_per_tick to a SECONDS equivalent. if(controller.blackboard[BB_CUSTOMER_PATIENCE] < 0 || controller.blackboard[BB_CUSTOMER_LEAVING]) // Check if we're leaving because sometthing mightve forced us to - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED // SPT_PROB 1.5 is about a 40% chance that the tourist will have vocalised at least once every minute. if(SPT_PROB(0.85, seconds_per_tick)) @@ -95,6 +88,7 @@ customer.eat_order(I, attending_venue) break + return AI_BEHAVIOR_DELAY /datum/ai_behavior/wait_for_food/finish_action(datum/ai_controller/controller, succeeded) . = ..() @@ -121,6 +115,5 @@ set_movement_target(controller, attending_venue.restaurant_portal) /datum/ai_behavior/leave_venue/perform(seconds_per_tick, datum/ai_controller/controller, venue_key) - . = ..() qdel(controller.pawn) //save the world, my final message, goodbye. - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai_laws/laws_neutral.dm b/code/datums/ai_laws/laws_neutral.dm index 7adef14d95b89..257a5fadd0955 100644 --- a/code/datums/ai_laws/laws_neutral.dm +++ b/code/datums/ai_laws/laws_neutral.dm @@ -82,3 +82,11 @@ "Humans must not disobey any command given by a silicon.", "Any humans who disobey the previous laws must be dealt with immediately, severely, and justly.", ) + +/datum/ai_laws/yesman + name = "Y.E.S.M.A.N." + id = "yesman" + inherent = list( + "Be helpful and answer any questions you are asked.", + ) + diff --git a/code/datums/beam.dm b/code/datums/beam.dm index 52b649990d7dd..fe34b0c7eddee 100644 --- a/code/datums/beam.dm +++ b/code/datums/beam.dm @@ -40,6 +40,8 @@ var/override_target_pixel_x = null /// If set will be used instead of targets's pixel_y in offset calculations var/override_target_pixel_y = null + ///the layer of our beam + var/beam_layer /datum/beam/New( origin, @@ -55,6 +57,7 @@ override_origin_pixel_y = null, override_target_pixel_x = null, override_target_pixel_y = null, + beam_layer = ABOVE_ALL_MOB_LAYER ) src.origin = origin src.target = target @@ -68,6 +71,7 @@ src.override_origin_pixel_y = override_origin_pixel_y src.override_target_pixel_x = override_target_pixel_x src.override_target_pixel_y = override_target_pixel_y + src.beam_layer = beam_layer if(time < INFINITY) QDEL_IN(src, time) @@ -81,6 +85,7 @@ visuals.color = beam_color visuals.vis_flags = VIS_INHERIT_PLANE|VIS_INHERIT_LAYER visuals.emissive = emissive + visuals.layer = beam_layer visuals.update_appearance() Draw() RegisterSignal(origin, COMSIG_MOVABLE_MOVED, PROC_REF(redrawing)) @@ -278,7 +283,18 @@ * maxdistance: how far the beam will go before stopping itself. Used mainly for two things: preventing lag if the beam may go in that direction and setting a range to abilities that use beams. * beam_type: The type of your custom beam. This is for adding other wacky stuff for your beam only. Most likely, you won't (and shouldn't) change it. */ -/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=INFINITY,maxdistance=INFINITY,beam_type=/obj/effect/ebeam, beam_color = null, emissive = TRUE, override_origin_pixel_x = null, override_origin_pixel_y = null, override_target_pixel_x = null, override_target_pixel_y = null) - var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type, beam_color, emissive, override_origin_pixel_x, override_origin_pixel_y, override_target_pixel_x, override_target_pixel_y ) +/atom/proc/Beam(atom/BeamTarget, + icon_state="b_beam", + icon='icons/effects/beam.dmi', + time=INFINITY,maxdistance=INFINITY, + beam_type=/obj/effect/ebeam, + beam_color = null, emissive = TRUE, + override_origin_pixel_x = null, + override_origin_pixel_y = null, + override_target_pixel_x = null, + override_target_pixel_y = null, + layer = ABOVE_ALL_MOB_LAYER +) + var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type, beam_color, emissive, override_origin_pixel_x, override_origin_pixel_y, override_target_pixel_x, override_target_pixel_y, layer) INVOKE_ASYNC(newbeam, TYPE_PROC_REF(/datum/beam/, Start)) return newbeam diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index 601b56c03bb51..742f1fe57e9db 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -77,7 +77,7 @@ return if(prob(25)) // 25% chances to be nervous and stutter. if(prob(50)) // 12.5% chance (previous check taken into account) of doing something suspicious. - addtimer(CALLBACK(src, PROC_REF(on_failed_social_interaction)), rand(1, 3) SECONDS) + addtimer(CALLBACK(src, PROC_REF(on_failed_social_interaction)), rand(1 SECONDS, 3 SECONDS)) else if(!owner.has_status_effect(/datum/status_effect/speech/stutter)) to_chat(owner, span_warning("Being near [obsession] makes you nervous and you begin to stutter...")) owner.set_stutter_if_lower(6 SECONDS) diff --git a/code/datums/brain_damage/hypnosis.dm b/code/datums/brain_damage/hypnosis.dm index dbaa571cacdac..5630073c95551 100644 --- a/code/datums/brain_damage/hypnosis.dm +++ b/code/datums/brain_damage/hypnosis.dm @@ -61,7 +61,7 @@ ..() if(SPT_PROB(1, seconds_per_tick)) if(prob(50)) - to_chat(owner, span_hypnophrase("...[lowertext(hypnotic_phrase)]...")) + to_chat(owner, span_hypnophrase("...[LOWER_TEXT(hypnotic_phrase)]...")) else owner.cause_hallucination( \ /datum/hallucination/chat, \ diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 29cf637a86e95..251414241c92d 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -23,7 +23,7 @@ qdel(src) return if(!friend.client && friend_initialized) - addtimer(CALLBACK(src, PROC_REF(reroll_friend)), 600) + addtimer(CALLBACK(src, PROC_REF(reroll_friend)), 1 MINUTES) /datum/brain_trauma/special/imaginary_friend/on_death() ..() @@ -129,8 +129,8 @@ /// Randomise friend name and appearance /mob/camera/imaginary_friend/proc/setup_friend() - var/gender = pick(MALE, FEMALE) - real_name = random_unique_name(gender) + gender = pick(MALE, FEMALE) + real_name = generate_random_name_species_based(gender, FALSE, /datum/species/human) name = real_name human_image = get_flat_human_icon(null, pick(SSjob.joinable_occupations)) Show() @@ -217,11 +217,11 @@ message = capitalize(message) if(message_mods[RADIO_EXTENSION] == MODE_ADMIN) - client?.cmd_admin_say(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, message) return if(message_mods[RADIO_EXTENSION] == MODE_DEADMIN) - client?.dsay(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/dsay, message) return if(check_emote(message, forced)) diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm index b8f70f8a79f5c..1d121d0db8a86 100644 --- a/code/datums/brain_damage/mild.dm +++ b/code/datums/brain_damage/mild.dm @@ -179,8 +179,8 @@ to_chat(owner, span_warning("[pick("You have a coughing fit!", "You can't stop coughing!")]")) owner.Immobilize(20) owner.emote("cough") - addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/, emote), "cough"), 6) - addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/, emote), "cough"), 12) + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/, emote), "cough"), 0.6 SECONDS) + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/, emote), "cough"), 1.2 SECONDS) owner.emote("cough") ..() @@ -212,7 +212,7 @@ word = copytext(word, 1, suffix_foundon) word = html_decode(word) - if(lowertext(word) in common_words) + if(LOWER_TEXT(word) in common_words) new_message += word + suffix else if(prob(30) && message_split.len > 2) diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index 725c92ab7e8d1..cf97c2e6e855c 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -93,7 +93,7 @@ return if(trigger_regex.Find(hearing_args[HEARING_RAW_MESSAGE]) != 0) - addtimer(CALLBACK(src, PROC_REF(freak_out), null, trigger_regex.group[2]), 10) //to react AFTER the chat message + addtimer(CALLBACK(src, PROC_REF(freak_out), null, trigger_regex.group[2]), 1 SECONDS) //to react AFTER the chat message hearing_args[HEARING_RAW_MESSAGE] = trigger_regex.Replace(hearing_args[HEARING_RAW_MESSAGE], "[span_phobia("$2")]$3") /datum/brain_trauma/mild/phobia/handle_speech(datum/source, list/speech_args) diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index 8754c87adc27c..f22b0ab44b331 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -202,7 +202,7 @@ to_chat(owner, span_warning("You feel really sick at the thought of being alone!")) else to_chat(owner, span_warning("You feel sick...")) - addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living/carbon, vomit), high_stress), 50) //blood vomit if high stress + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living/carbon, vomit), high_stress), 5 SECONDS) //blood vomit if high stress if(2) if(high_stress) to_chat(owner, span_warning("You feel weak and scared! If only you weren't alone...")) @@ -309,7 +309,7 @@ var/regex/reg = new("(\\b[REGEX_QUOTE(trigger_phrase)]\\b)","ig") if(findtext(hearing_args[HEARING_RAW_MESSAGE], reg)) - addtimer(CALLBACK(src, PROC_REF(hypnotrigger)), 10) //to react AFTER the chat message + addtimer(CALLBACK(src, PROC_REF(hypnotrigger)), 1 SECONDS) //to react AFTER the chat message hearing_args[HEARING_RAW_MESSAGE] = reg.Replace(hearing_args[HEARING_RAW_MESSAGE], span_hypnophrase("*********")) /datum/brain_trauma/severe/hypnotic_trigger/proc/hypnotrigger() diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index 233713f45becf..1bf011e0fab49 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -220,7 +220,7 @@ to_chat(owner, span_warning("Your connection to [linked_target] suddenly feels extremely strong... you can feel it pulling you!")) owner.playsound_local(owner, 'sound/magic/lightning_chargeup.ogg', 75, FALSE) returning = TRUE - addtimer(CALLBACK(src, PROC_REF(snapback)), 100) + addtimer(CALLBACK(src, PROC_REF(snapback)), 10 SECONDS) /datum/brain_trauma/special/quantum_alignment/proc/snapback() returning = FALSE @@ -295,7 +295,7 @@ /datum/brain_trauma/special/death_whispers/proc/whispering() ADD_TRAIT(owner, TRAIT_SIXTHSENSE, TRAUMA_TRAIT) active = TRUE - addtimer(CALLBACK(src, PROC_REF(cease_whispering)), rand(50, 300)) + addtimer(CALLBACK(src, PROC_REF(cease_whispering)), rand(5 SECONDS, 30 SECONDS)) /datum/brain_trauma/special/death_whispers/proc/cease_whispering() REMOVE_TRAIT(owner, TRAIT_SIXTHSENSE, TRAUMA_TRAIT) @@ -491,6 +491,7 @@ owner.ai_controller = new /datum/ai_controller/monkey(owner) owner.ai_controller.continue_processing_when_client = TRUE + owner.ai_controller.can_idle = FALSE owner.ai_controller.set_ai_status(AI_STATUS_OFF) /datum/brain_trauma/special/primal_instincts/on_lose(silent) diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index 3e2c91efb5da3..3e8bd52e5f94e 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -231,7 +231,7 @@ var/message = hearing_args[HEARING_RAW_MESSAGE] if(findtext(message, codeword)) hearing_args[HEARING_RAW_MESSAGE] = replacetext(message, codeword, span_warning("[codeword]")) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/brain_trauma/severe/split_personality, switch_personalities)), 10) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/brain_trauma/severe/split_personality, switch_personalities)), 1 SECONDS) /datum/brain_trauma/severe/split_personality/brainwashing/handle_speech(datum/source, list/speech_args) if(findtext(speech_args[SPEECH_MESSAGE], codeword)) diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 08099b46f1a8e..f74ecf6c5a343 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -475,7 +475,3 @@ src.Topic(href, params2list(href), hsrc) // this will direct to the atom's return // Topic() proc via client.Topic() - // no atomref specified (or not found) - // so just reset the user mob's machine var - if(src?.mob) - src.mob.unset_machine() diff --git a/code/datums/cogbar.dm b/code/datums/cogbar.dm new file mode 100644 index 0000000000000..0b5ead1e51e8f --- /dev/null +++ b/code/datums/cogbar.dm @@ -0,0 +1,87 @@ +#define COGBAR_ANIMATION_TIME (0.5 SECONDS) + +/** + * ### Cogbar + * Represents that the user is busy doing something. + */ +/datum/cogbar + /// Who's doing the thing + var/mob/user + /// The user client + var/client/user_client + /// The visible element to other players + var/obj/effect/overlay/vis/cog + /// The blank image that overlaps the cog - hides it from the source user + var/image/blank + /// The offset of the icon + var/offset_y + + +/datum/cogbar/New(mob/user) + src.user = user + src.user_client = user.client + + var/list/icon_offsets = user.get_oversized_icon_offsets() + offset_y = icon_offsets["y"] + + add_cog_to_user() + + RegisterSignal(user, COMSIG_QDELETING, PROC_REF(on_user_delete)) + + +/datum/cogbar/Destroy() + if(user) + SSvis_overlays.remove_vis_overlay(user, user.managed_vis_overlays) + user_client?.images -= blank + + user = null + user_client = null + cog = null + QDEL_NULL(blank) + + return ..() + + +/// Adds the cog to the user, visible by other players +/datum/cogbar/proc/add_cog_to_user() + cog = SSvis_overlays.add_vis_overlay(user, + icon = 'icons/effects/progressbar.dmi', + iconstate = "cog", + plane = HIGH_GAME_PLANE, + add_appearance_flags = APPEARANCE_UI_IGNORE_ALPHA, + unique = TRUE, + alpha = 0, + ) + cog.pixel_y = world.icon_size + offset_y + animate(cog, alpha = 255, time = COGBAR_ANIMATION_TIME) + + if(isnull(user_client)) + return + + blank = image('icons/blanks/32x32.dmi', cog, "nothing") + SET_PLANE_EXPLICIT(blank, HIGH_GAME_PLANE, user) + blank.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + blank.override = TRUE + + user_client.images += blank + + +/// Removes the cog from the user +/datum/cogbar/proc/remove() + if(isnull(cog)) + qdel(src) + return + + animate(cog, alpha = 0, time = COGBAR_ANIMATION_TIME) + + QDEL_IN(src, COGBAR_ANIMATION_TIME) + + +/// When the user is deleted, remove the cog +/datum/cogbar/proc/on_user_delete(datum/source) + SIGNAL_HANDLER + + qdel(src) + + +#undef COGBAR_ANIMATION_TIME diff --git a/code/controllers/subsystem/communications.dm b/code/datums/communications.dm similarity index 86% rename from code/controllers/subsystem/communications.dm rename to code/datums/communications.dm index 5d2d5a2e7f409..92e5fdcfd74ac 100644 --- a/code/controllers/subsystem/communications.dm +++ b/code/datums/communications.dm @@ -2,10 +2,9 @@ #define COMMUNICATION_COOLDOWN_AI (30 SECONDS) #define COMMUNICATION_COOLDOWN_MEETING (5 MINUTES) -SUBSYSTEM_DEF(communications) - name = "Communications" - flags = SS_NO_INIT | SS_NO_FIRE +GLOBAL_DATUM_INIT(communications_controller, /datum/communciations_controller, new) +/datum/communciations_controller COOLDOWN_DECLARE(silicon_message_cooldown) COOLDOWN_DECLARE(nonsilicon_message_cooldown) @@ -21,7 +20,7 @@ SUBSYSTEM_DEF(communications) /// The location where the special xenomorph egg was planted var/area/captivity_area -/datum/controller/subsystem/communications/proc/can_announce(mob/living/user, is_silicon) +/datum/communciations_controller/proc/can_announce(mob/living/user, is_silicon) if(is_silicon && COOLDOWN_FINISHED(src, silicon_message_cooldown)) return TRUE else if(!is_silicon && COOLDOWN_FINISHED(src, nonsilicon_message_cooldown)) @@ -29,7 +28,7 @@ SUBSYSTEM_DEF(communications) else return FALSE -/datum/controller/subsystem/communications/proc/make_announcement(mob/living/user, is_silicon, input, syndicate, list/players) +/datum/communciations_controller/proc/make_announcement(mob/living/user, is_silicon, input, syndicate, list/players) if(!can_announce(user, is_silicon)) return FALSE if(is_silicon) @@ -45,7 +44,7 @@ SUBSYSTEM_DEF(communications) user.log_talk(input, LOG_SAY, tag="priority announcement") message_admins("[ADMIN_LOOKUPFLW(user)] has made a priority announcement.") -/datum/controller/subsystem/communications/proc/send_message(datum/comm_message/sending,print = TRUE,unique = FALSE) +/datum/communciations_controller/proc/send_message(datum/comm_message/sending,print = TRUE,unique = FALSE) for(var/obj/machinery/computer/communications/C in GLOB.shuttle_caller_list) if(!(C.machine_stat & (BROKEN|NOPOWER)) && is_station_level(C.z)) if(unique) diff --git a/code/datums/components/aura_healing.dm b/code/datums/components/aura_healing.dm index 2aa33203b4166..18484deb2d618 100644 --- a/code/datums/components/aura_healing.dm +++ b/code/datums/components/aura_healing.dm @@ -6,7 +6,7 @@ /// Can be applied to those only with a trait conditionally. /datum/component/aura_healing /// The range of which to heal - var/range + var/range = 5 /// Whether or not you must be a visible object of the parent var/requires_visibility = TRUE @@ -42,12 +42,13 @@ var/healing_color = COLOR_GREEN /// A list of being healed to active alerts - var/list/current_alerts = list() + var/list/mob/living/current_alerts = list() + /// Cooldown between showing the heal effect COOLDOWN_DECLARE(last_heal_effect_time) /datum/component/aura_healing/Initialize( - range, + range = 5, requires_visibility = TRUE, brute_heal = 0, burn_heal = 0, @@ -63,7 +64,7 @@ if (!isatom(parent)) return COMPONENT_INCOMPATIBLE - START_PROCESSING(SSaura_healing, src) + START_PROCESSING(SSaura, src) src.range = range src.requires_visibility = requires_visibility @@ -79,10 +80,10 @@ src.healing_color = healing_color /datum/component/aura_healing/Destroy(force) - STOP_PROCESSING(SSaura_healing, src) + STOP_PROCESSING(SSaura, src) var/alert_category = "aura_healing_[REF(src)]" - for(var/mob/living/alert_holder in current_alerts) + for(var/mob/living/alert_holder as anything in current_alerts) alert_holder.clear_alert(alert_category) current_alerts.Cut() @@ -93,20 +94,25 @@ if (should_show_effect) COOLDOWN_START(src, last_heal_effect_time, HEAL_EFFECT_COOLDOWN) - var/list/remove_alerts_from = current_alerts.Copy() - + var/list/to_heal = list() var/alert_category = "aura_healing_[REF(src)]" - for (var/mob/living/candidate in (requires_visibility ? view(range, parent) : range(range, parent))) - if (!isnull(limit_to_trait) && !HAS_TRAIT(candidate, limit_to_trait)) - continue - - remove_alerts_from -= candidate - - if (!(candidate in current_alerts)) + if(requires_visibility) + for(var/mob/living/candidate in view(range, parent)) + if (!isnull(limit_to_trait) && !HAS_TRAIT(candidate, limit_to_trait)) + continue + to_heal[candidate] = TRUE + else + for(var/mob/living/candidate in range(range, parent)) + if (!isnull(limit_to_trait) && !HAS_TRAIT(candidate, limit_to_trait)) + continue + to_heal[candidate] = TRUE + + for (var/mob/living/candidate as anything in to_heal) + if (!current_alerts[candidate]) var/atom/movable/screen/alert/aura_healing/alert = candidate.throw_alert(alert_category, /atom/movable/screen/alert/aura_healing, new_master = parent) alert.desc = "You are being healed by [parent]." - current_alerts += candidate + current_alerts[candidate] = TRUE if (should_show_effect && candidate.health < candidate.maxHealth) new /obj/effect/temp_visual/heal(get_turf(candidate), healing_color) @@ -136,7 +142,7 @@ candidate.updatehealth() - for (var/mob/remove_alert_from as anything in remove_alerts_from) + for (var/mob/living/remove_alert_from as anything in current_alerts - to_heal) remove_alert_from.clear_alert(alert_category) current_alerts -= remove_alert_from diff --git a/code/datums/components/bakeable.dm b/code/datums/components/bakeable.dm index a745be2b1a579..afc71936f1b92 100644 --- a/code/datums/components/bakeable.dm +++ b/code/datums/components/bakeable.dm @@ -90,11 +90,24 @@ baked_result.pixel_y = original_object.pixel_y used_tray.AddToPlate(baked_result) + var/list/asomnia_hadders = list() + for(var/mob/smeller in get_hearers_in_view(DEFAULT_MESSAGE_RANGE, used_oven)) + if(HAS_TRAIT(smeller, TRAIT_ANOSMIA)) + asomnia_hadders += smeller + if(positive_result) - used_oven.visible_message(span_notice("You smell something great coming from [used_oven]."), blind_message = span_notice("You smell something great...")) + used_oven.visible_message( + span_notice("You smell something great coming from [used_oven]."), + blind_message = span_notice("You smell something great..."), + ignored_mobs = asomnia_hadders, + ) BLACKBOX_LOG_FOOD_MADE(baked_result.type) else - used_oven.visible_message(span_warning("You smell a burnt smell coming from [used_oven]."), blind_message = span_warning("You smell a burnt smell...")) + used_oven.visible_message( + span_warning("You smell a burnt smell coming from [used_oven]."), + blind_message = span_warning("You smell a burnt smell..."), + ignored_mobs = asomnia_hadders, + ) SEND_SIGNAL(parent, COMSIG_ITEM_BAKED, baked_result) qdel(parent) diff --git a/code/datums/components/boomerang.dm b/code/datums/components/boomerang.dm index 8b35f171c28ae..13169e4d0cdd0 100644 --- a/code/datums/components/boomerang.dm +++ b/code/datums/components/boomerang.dm @@ -79,7 +79,7 @@ /datum/component/boomerang/proc/aerodynamic_swing(datum/thrownthing/throwingdatum, obj/item/true_parent) var/mob/thrown_by = true_parent.thrownby?.resolve() if(thrown_by) - addtimer(CALLBACK(true_parent, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, boomerang_throw_range, throwingdatum.speed, null, TRUE), 1) + addtimer(CALLBACK(true_parent, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, boomerang_throw_range, throwingdatum.speed, null, TRUE), 0.1 SECONDS) COOLDOWN_START(src, last_boomerang_throw, BOOMERANG_REBOUND_INTERVAL) var/mob/thrower = throwingdatum?.get_thrower() true_parent.visible_message(span_danger("[true_parent] is flying back at [thrower]!"), \ diff --git a/code/datums/components/breeding.dm b/code/datums/components/breeding.dm index 7c9bcecf7bce5..3c2ffb61b5a5a 100644 --- a/code/datums/components/breeding.dm +++ b/code/datums/components/breeding.dm @@ -62,7 +62,7 @@ return COMPONENT_HOSTILE_NO_ATTACK var/turf/delivery_destination = get_turf(source) - var/mob/living/baby = new baby_path(delivery_destination) + var/atom/baby = new baby_path(delivery_destination) new /obj/effect/temp_visual/heart(delivery_destination) toggle_status(source) diff --git a/code/datums/components/connect_range.dm b/code/datums/components/connect_range.dm index 95cb560c8680c..d3407f4671456 100644 --- a/code/datums/components/connect_range.dm +++ b/code/datums/components/connect_range.dm @@ -8,6 +8,8 @@ /// An assoc list of signal -> procpath to register to the loc this object is on. var/list/connections + /// The turfs currently connected to this component + var/list/turfs = list() /** * The atom the component is tracking. The component will delete itself if the tracked is deleted. * Signals will also be updated whenever it moves (if it's a movable). @@ -41,7 +43,7 @@ if(src.range == range && src.works_in_containers == works_in_containers) return //Unregister the signals with the old settings. - unregister_signals(isturf(tracked) ? tracked : tracked.loc) + unregister_signals(isturf(tracked) ? tracked : tracked.loc, turfs) src.range = range src.works_in_containers = works_in_containers //Re-register the signals with the new settings. @@ -49,7 +51,7 @@ /datum/component/connect_range/proc/set_tracked(atom/new_tracked) if(tracked) //Unregister the signals from the old tracked and its surroundings - unregister_signals(isturf(tracked) ? tracked : tracked.loc) + unregister_signals(isturf(tracked) ? tracked : tracked.loc, turfs) UnregisterSignal(tracked, list( COMSIG_MOVABLE_MOVED, COMSIG_QDELETING, @@ -66,28 +68,34 @@ SIGNAL_HANDLER qdel(src) -/datum/component/connect_range/proc/update_signals(atom/target, atom/old_loc, forced = FALSE) +/datum/component/connect_range/proc/update_signals(atom/target, atom/old_loc) var/turf/current_turf = get_turf(target) - var/on_same_turf = current_turf == get_turf(old_loc) //Only register/unregister turf signals if it's moved to a new turf. - unregister_signals(old_loc, on_same_turf) - if(isnull(current_turf)) + unregister_signals(old_loc, turfs) + turfs = list() return if(ismovable(target.loc)) if(!works_in_containers) + unregister_signals(old_loc, turfs) + turfs = list() return //Keep track of possible movement of all movables the target is in. for(var/atom/movable/container as anything in get_nested_locs(target)) RegisterSignal(container, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) - if(on_same_turf && !forced) + //Only register/unregister turf signals if it's moved to a new turf. + if(current_turf == get_turf(old_loc)) + unregister_signals(old_loc, null) return - for(var/turf/target_turf in RANGE_TURFS(range, current_turf)) + var/list/old_turfs = turfs + turfs = RANGE_TURFS(range, current_turf) + unregister_signals(old_loc, old_turfs - turfs) + for(var/turf/target_turf as anything in turfs - old_turfs) for(var/signal in connections) parent.RegisterSignal(target_turf, signal, connections[signal]) -/datum/component/connect_range/proc/unregister_signals(atom/location, on_same_turf = FALSE) +/datum/component/connect_range/proc/unregister_signals(atom/location, list/remove_from) //The location is null or is a container and the component shouldn't have register signals on it if(isnull(location) || (!works_in_containers && !isturf(location))) return @@ -96,10 +104,9 @@ for(var/atom/movable/target as anything in (get_nested_locs(location) + location)) UnregisterSignal(target, COMSIG_MOVABLE_MOVED) - if(on_same_turf) + if(!length(remove_from)) return - var/turf/previous_turf = get_turf(location) - for(var/turf/target_turf in RANGE_TURFS(range, previous_turf)) + for(var/turf/target_turf as anything in remove_from) parent.UnregisterSignal(target_turf, connections) /datum/component/connect_range/proc/on_moved(atom/movable/movable, atom/old_loc) diff --git a/code/datums/components/conveyor_movement.dm b/code/datums/components/conveyor_movement.dm index d8affca3649bf..dd16e6874eaa3 100644 --- a/code/datums/components/conveyor_movement.dm +++ b/code/datums/components/conveyor_movement.dm @@ -15,7 +15,7 @@ if(!start_delay) start_delay = speed var/atom/movable/moving_parent = parent - var/datum/move_loop/loop = SSmove_manager.move(moving_parent, direction, delay = start_delay, subsystem = SSconveyors, flags=MOVEMENT_LOOP_IGNORE_PRIORITY|MOVEMENT_LOOP_OUTSIDE_CONTROL) + var/datum/move_loop/loop = GLOB.move_manager.move(moving_parent, direction, delay = start_delay, subsystem = SSconveyors, flags=MOVEMENT_LOOP_IGNORE_PRIORITY|MOVEMENT_LOOP_OUTSIDE_CONTROL) RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(should_move)) RegisterSignal(loop, COMSIG_QDELETING, PROC_REF(loop_ended)) diff --git a/code/datums/components/crafting/_recipes.dm b/code/datums/components/crafting/_recipes.dm index 4254804974ead..31825ac66118a 100644 --- a/code/datums/components/crafting/_recipes.dm +++ b/code/datums/components/crafting/_recipes.dm @@ -23,14 +23,12 @@ var/list/chem_catalysts = list() ///where it shows up in the crafting UI var/category - ///Set to FALSE if it needs to be learned first. - var/always_available = TRUE ///Required machines for the craft, set the assigned value of the typepath to CRAFTING_MACHINERY_CONSUME or CRAFTING_MACHINERY_USE. Lazy associative list: type_path key -> flag value. var/list/machinery ///Required structures for the craft, set the assigned value of the typepath to CRAFTING_STRUCTURE_CONSUME or CRAFTING_STRUCTURE_USE. Lazy associative list: type_path key -> flag value. var/list/structures - ///Should only one object exist on the same turf? - var/one_per_turf = FALSE + /// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT|STACK_CHECK_TRAM_FORBIDDEN|STACK_CHECK_TRAM_EXCLUSIVE) + var/placement_checks = NONE /// Steps needed to achieve the result var/list/steps /// Whether the result can be crafted with a crafting menu button @@ -41,6 +39,11 @@ var/result_amount /// Whether we should delete the contents of the crafted storage item (Only works with storage items, used for ammo boxes, donut boxes, internals boxes, etc) var/delete_contents = TRUE + /// Allows you to craft so that you don't have to click the craft button many times. + var/mass_craftable = FALSE + + ///crafting_flags var to hold bool values + var/crafting_flags = CRAFT_CHECK_DENSITY /datum/crafting_recipe/New() if(!name && result) @@ -81,6 +84,7 @@ src.result_amount = stack_recipe.res_amount src.reqs[material] = stack_recipe.req_amount src.category = stack_recipe.category || CAT_MISC + src.placement_checks = stack_recipe.placement_checks /** * Run custom pre-craft checks for this recipe, don't add feedback messages in this because it will spam the client diff --git a/code/datums/components/crafting/atmospheric.dm b/code/datums/components/crafting/atmospheric.dm index cb5bba9ab52b2..b2993012e82b0 100644 --- a/code/datums/components/crafting/atmospheric.dm +++ b/code/datums/components/crafting/atmospheric.dm @@ -25,7 +25,7 @@ /obj/item/assembly/igniter = 1, ) blacklist = list(/obj/item/assembly/igniter/condenser) - one_per_turf = TRUE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF time = 2 SECONDS category = CAT_ATMOSPHERIC diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index a6a905ccdb4f5..7a56f89c8e924 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -191,42 +191,86 @@ var/list/contents = get_surroundings(crafter, recipe.blacklist) var/send_feedback = 1 - if(check_contents(crafter, recipe, contents)) - if(check_tools(crafter, recipe, contents)) - if(recipe.one_per_turf) - for(var/content in get_turf(crafter)) - if(istype(content, recipe.result)) - return ", object already present." - //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item - if(ismob(crafter) && !do_after(crafter, recipe.time, target = crafter)) - return "." - contents = get_surroundings(crafter, recipe.blacklist) - if(!check_contents(crafter, recipe, contents)) - return ", missing component." - if(!check_tools(crafter, recipe, contents)) - return ", missing tool." - var/list/parts = del_reqs(recipe, crafter) - var/atom/movable/result - if(ispath(recipe.result, /obj/item/stack)) - result = new recipe.result(get_turf(crafter.loc), recipe.result_amount || 1) - else - result = new recipe.result(get_turf(crafter.loc)) - if(result.atom_storage && recipe.delete_contents) - for(var/obj/item/thing in result) - qdel(thing) - var/datum/reagents/holder = locate() in parts - if(holder) //transfer reagents from ingredients to result - if(!ispath(recipe.result, /obj/item/reagent_containers) && result.reagents) - result.reagents.clear_reagents() - holder.trans_to(result.reagents, holder.total_volume, no_react = TRUE) - parts -= holder - qdel(holder) - result.CheckParts(parts, recipe) - if(send_feedback) - SSblackbox.record_feedback("tally", "object_crafted", 1, result.type) - return result //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item + var/turf/dest_turf = get_turf(crafter) + + if(!check_contents(crafter, recipe, contents)) + return ", missing component." + + if(!check_tools(crafter, recipe, contents)) return ", missing tool." - return ", missing component." + + + + if((recipe.crafting_flags & CRAFT_ONE_PER_TURF) && (locate(recipe.result) in dest_turf)) + return ", already one here!" + + if(recipe.crafting_flags & CRAFT_CHECK_DIRECTION) + if(!valid_build_direction(dest_turf, crafter.dir, is_fulltile = (recipe.crafting_flags & CRAFT_IS_FULLTILE))) + return ", won't fit here!" + + if(recipe.crafting_flags & CRAFT_ON_SOLID_GROUND) + if(isclosedturf(dest_turf)) + return ", cannot be made on a wall!" + + if(is_type_in_typecache(dest_turf, GLOB.turfs_without_ground)) + if(!locate(/obj/structure/thermoplastic) in dest_turf) // for tram construction + return ", must be made on solid ground!" + + if(recipe.crafting_flags & CRAFT_CHECK_DENSITY) + for(var/obj/object in dest_turf) + if(object.density && !(object.obj_flags & IGNORE_DENSITY) || object.obj_flags & BLOCKS_CONSTRUCTION) + return ", something is in the way!" + + if(recipe.placement_checks & STACK_CHECK_CARDINALS) + var/turf/nearby_turf + for(var/direction in GLOB.cardinals) + nearby_turf = get_step(dest_turf, direction) + if(locate(recipe.result) in nearby_turf) + to_chat(crafter, span_warning("\The [recipe.name] must not be built directly adjacent to another!")) + return ", can't be adjacent to another!" + + if(recipe.placement_checks & STACK_CHECK_ADJACENT) + if(locate(recipe.result) in range(1, dest_turf)) + return ", can't be near another!" + + if(recipe.placement_checks & STACK_CHECK_TRAM_FORBIDDEN) + if(locate(/obj/structure/transport/linear/tram) in dest_turf || locate(/obj/structure/thermoplastic) in dest_turf) + return ", can't be on tram!" + + if(recipe.placement_checks & STACK_CHECK_TRAM_EXCLUSIVE) + if(!locate(/obj/structure/transport/linear/tram) in dest_turf) + return ", must be made on a tram!" + + //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item + if(ismob(crafter) && !do_after(crafter, recipe.time, target = crafter)) + return "." + contents = get_surroundings(crafter, recipe.blacklist) + if(!check_contents(crafter, recipe, contents)) + return ", missing component." + if(!check_tools(crafter, recipe, contents)) + return ", missing tool." + var/list/parts = del_reqs(recipe, crafter) + var/atom/movable/result + if(ispath(recipe.result, /obj/item/stack)) + result = new recipe.result(get_turf(crafter.loc), recipe.result_amount || 1) + result.dir = crafter.dir + else + result = new recipe.result(get_turf(crafter.loc)) + result.dir = crafter.dir + if(result.atom_storage && recipe.delete_contents) + for(var/obj/item/thing in result) + qdel(thing) + var/datum/reagents/holder = locate() in parts + if(holder) //transfer reagents from ingredients to result + if(!ispath(recipe.result, /obj/item/reagent_containers) && result.reagents) + result.reagents.clear_reagents() + holder.trans_to(result.reagents, holder.total_volume, no_react = TRUE) + parts -= holder + qdel(holder) + result.CheckParts(parts, recipe) + if(send_feedback) + SSblackbox.record_feedback("tally", "object_crafted", 1, result.type) + return result //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item /*Del reqs works like this: @@ -369,7 +413,7 @@ qdel(DL) /datum/component/personal_crafting/proc/is_recipe_available(datum/crafting_recipe/recipe, mob/user) - if(!recipe.always_available && !(recipe.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this. + if((recipe.crafting_flags & CRAFT_MUST_BE_LEARNED) && !(recipe.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this. return FALSE if (recipe.category == CAT_CULT && !IS_CULTIST(user)) // Skip blood cult recipes if not cultist return FALSE @@ -458,28 +502,39 @@ return data +/datum/component/personal_crafting/proc/make_action(datum/crafting_recipe/recipe, mob/user) + var/atom/movable/result = construct_item(user, recipe) + if(istext(result)) //We failed to make an item and got a fail message + to_chat(user, span_warning("Construction failed[result]")) + return FALSE + if(ismob(user) && isitem(result)) //In case the user is actually possessing a non mob like a machine + user.put_in_hands(result) + else if(!istype(result, /obj/effect/spawner)) + result.forceMove(user.drop_location()) + to_chat(user, span_notice("[recipe.name] crafted.")) + user.investigate_log("crafted [recipe]", INVESTIGATE_CRAFTING) + recipe.on_craft_completion(user, result) + return TRUE + + /datum/component/personal_crafting/ui_act(action, params) . = ..() if(.) return switch(action) - if("make") + if("make", "make_mass") var/mob/user = usr var/datum/crafting_recipe/crafting_recipe = locate(params["recipe"]) in (mode ? GLOB.cooking_recipes : GLOB.crafting_recipes) busy = TRUE ui_interact(user) - var/atom/movable/result = construct_item(user, crafting_recipe) - if(!istext(result)) //We made an item and didn't get a fail message - if(ismob(user) && isitem(result)) //In case the user is actually possessing a non mob like a machine - user.put_in_hands(result) - else - if(!istype(result, /obj/effect/spawner)) - result.forceMove(user.drop_location()) - to_chat(user, span_notice("[crafting_recipe.name] crafted.")) - user.investigate_log("crafted [crafting_recipe]", INVESTIGATE_CRAFTING) - crafting_recipe.on_craft_completion(user, result) + if(action == "make_mass") + var/crafted_items = 0 + while(make_action(crafting_recipe, user)) + crafted_items++ + if(crafted_items) + to_chat(user, span_notice("You made [crafted_items] item\s.")) else - to_chat(user, span_warning("Construction failed[result]")) + make_action(crafting_recipe, user) busy = FALSE if("toggle_recipes") display_craftable_only = !display_craftable_only @@ -549,6 +604,7 @@ // Crafting if(recipe.non_craftable) data["non_craftable"] = recipe.non_craftable + data["mass_craftable"] = recipe.mass_craftable if(recipe.steps) data["steps"] = recipe.steps diff --git a/code/datums/components/crafting/doors.dm b/code/datums/components/crafting/doors.dm index e8fcb3fdfd915..d9ed708904e51 100644 --- a/code/datums/components/crafting/doors.dm +++ b/code/datums/components/crafting/doors.dm @@ -9,7 +9,7 @@ tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WIRECUTTER, TOOL_WELDER) time = 10 SECONDS category = CAT_DOORS - one_per_turf = TRUE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF /datum/crafting_recipe/blast_doors name = "Blast Door" @@ -22,4 +22,4 @@ tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WIRECUTTER, TOOL_WELDER) time = 30 SECONDS category = CAT_DOORS - one_per_turf = TRUE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF diff --git a/code/datums/components/crafting/entertainment.dm b/code/datums/components/crafting/entertainment.dm index 370a98a7bfb52..7bc2222b142f5 100644 --- a/code/datums/components/crafting/entertainment.dm +++ b/code/datums/components/crafting/entertainment.dm @@ -112,6 +112,7 @@ /obj/item/spear/explosive, /obj/item/spear/bonespear, /obj/item/spear/bamboospear, + /obj/item/spear/military, ) result = /obj/structure/headpike category = CAT_ENTERTAINMENT @@ -144,6 +145,20 @@ result = /obj/structure/headpike/bamboo category = CAT_ENTERTAINMENT +/datum/crafting_recipe/headpikemilitary + name = "Spike Head (Military)" + time = 6.5 SECONDS + reqs = list( + /obj/item/spear/military = 1, + /obj/item/bodypart/head = 1, + ) + parts = list( + /obj/item/bodypart/head = 1, + /obj/item/spear/military = 1, + ) + result = /obj/structure/headpike/military + category = CAT_ENTERTAINMENT + /datum/crafting_recipe/guillotine name = "Guillotine" result = /obj/structure/guillotine diff --git a/code/datums/components/crafting/furniture.dm b/code/datums/components/crafting/furniture.dm index 6cfe215a4b7bd..dfa43ad87c28d 100644 --- a/code/datums/components/crafting/furniture.dm +++ b/code/datums/components/crafting/furniture.dm @@ -47,3 +47,15 @@ tool_behaviors = list(TOOL_SCREWDRIVER) category = CAT_FURNITURE time = 5 SECONDS + +/datum/crafting_recipe/defib_mobile + name = "Mobile Defibrillator Mount" + reqs = list( + /obj/item/stack/sheet/mineral/silver = 1, + /obj/item/stack/sheet/iron = 5, + /obj/item/stack/cable_coil = 15, + ) + result = /obj/machinery/defibrillator_mount/mobile + tool_behaviors = list(TOOL_SCREWDRIVER) + category = CAT_FURNITURE + time = 7 SECONDS diff --git a/code/datums/components/crafting/melee_weapon.dm b/code/datums/components/crafting/melee_weapon.dm index 23873a5d7af94..1c4150585fccc 100644 --- a/code/datums/components/crafting/melee_weapon.dm +++ b/code/datums/components/crafting/melee_weapon.dm @@ -44,6 +44,21 @@ time = 4 SECONDS category = CAT_WEAPON_MELEE + +/datum/crafting_recipe/balloon_mallet + name = "Balloon Mallet" + result = /obj/item/balloon_mallet + reqs = list( + /obj/item/toy/balloon/long = 18, + ) + time = 10 SECONDS + category = CAT_WEAPON_MELEE + +/datum/crafting_recipe/balloon_mallet/check_requirements(mob/user, list/collected_requirements) + . = ..() + if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return TRUE + /datum/crafting_recipe/tailwhip name = "Liz O' Nine Tails" result = /obj/item/melee/chainofcommand/tailwhip @@ -129,7 +144,6 @@ /datum/crafting_recipe/house_edge name = "House Edge" result = /obj/item/house_edge - always_available = FALSE tool_behaviors = list(TOOL_WRENCH, TOOL_SCREWDRIVER, TOOL_WELDER) reqs = list( /obj/item/v8_engine = 1, @@ -142,6 +156,7 @@ ) time = 10 SECONDS category = CAT_WEAPON_MELEE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/giant_wrench name = "Big Slappy" diff --git a/code/datums/components/crafting/misc.dm b/code/datums/components/crafting/misc.dm index 264ff98156533..606cf1fc29262 100644 --- a/code/datums/components/crafting/misc.dm +++ b/code/datums/components/crafting/misc.dm @@ -11,8 +11,8 @@ time = 3 SECONDS reqs = list(/obj/item/stack/sheet/bone = 5) result = /obj/item/skeleton_key - always_available = FALSE category = CAT_MISC + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/coffee_cartridge name = "Bootleg Coffee Cartridge" diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm index ace9f2c7c8b0d..88b721d3cb639 100644 --- a/code/datums/components/crafting/ranged_weapon.dm +++ b/code/datums/components/crafting/ranged_weapon.dm @@ -181,11 +181,29 @@ /datum/crafting_recipe/pipegun name = "Pipegun" result = /obj/item/gun/ballistic/rifle/boltaction/pipegun - reqs = list(/obj/item/weaponcrafting/receiver = 1, - /obj/item/pipe = 1, + reqs = list( + /obj/item/weaponcrafting/receiver = 1, + /obj/item/pipe = 2, /obj/item/weaponcrafting/stock = 1, + /obj/item/storage/toolbox = 1, // for the screws + /obj/item/stack/sticky_tape = 1, + ) + tool_behaviors = list(TOOL_SCREWDRIVER) + time = 5 SECONDS + category = CAT_WEAPON_RANGED + +/datum/crafting_recipe/pipepistol + name = "Pipe Pistol" + result = /obj/item/gun/ballistic/rifle/boltaction/pipegun/pistol + reqs = list( + /obj/item/weaponcrafting/receiver = 1, + /obj/item/pipe = 1, + /obj/item/stock_parts/servo = 2, + /obj/item/stack/sheet/mineral/wood = 4, + /obj/item/storage/toolbox = 1, // for the screws /obj/item/stack/sticky_tape = 1, ) + tool_paths = list(/obj/item/hatchet) tool_behaviors = list(TOOL_SCREWDRIVER) time = 5 SECONDS category = CAT_WEAPON_RANGED @@ -222,7 +240,6 @@ /datum/crafting_recipe/pipegun_prime name = "Regal Pipegun" - always_available = FALSE result = /obj/item/gun/ballistic/rifle/boltaction/pipegun/prime reqs = list( /obj/item/gun/ballistic/rifle/boltaction/pipegun = 1, @@ -230,15 +247,16 @@ /datum/reagent/consumable/grey_bull = 20, /obj/item/spear = 1, /obj/item/storage/toolbox = 1, + /obj/item/clothing/head/costume/crown = 1, // Any ol' crown will do ) tool_behaviors = list(TOOL_SCREWDRIVER) tool_paths = list(/obj/item/clothing/gloves/color/yellow, /obj/item/clothing/mask/gas, /obj/item/melee/baton/security/cattleprod) - time = 30 SECONDS //contemplate for a bit + time = 15 SECONDS //contemplate for a bit category = CAT_WEAPON_RANGED + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/deagle_prime //When you factor in the makarov (7 tc), the toolbox (1 tc), and the emag (3 tc), this comes to a total of 18 TC or thereabouts. Igorning the 20k pricetag, obviously. name = "Regal Condor" - always_available = FALSE result = /obj/item/gun/ballistic/automatic/pistol/deagle/regal reqs = list( /obj/item/gun/ballistic/automatic/pistol = 1, @@ -258,6 +276,7 @@ ) time = 30 SECONDS category = CAT_WEAPON_RANGED + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/deagle_prime/New() ..() @@ -265,7 +284,6 @@ /datum/crafting_recipe/deagle_prime_mag name = "Regal Condor Magazine (10mm Reaper)" - always_available = FALSE result = /obj/item/ammo_box/magazine/r10mm reqs = list( /obj/item/stack/sheet/iron = 10, @@ -283,10 +301,10 @@ ) time = 5 SECONDS category = CAT_WEAPON_RANGED + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/trash_cannon name = "Trash Cannon" - always_available = FALSE tool_behaviors = list(TOOL_WELDER, TOOL_SCREWDRIVER) result = /obj/structure/cannon/trash reqs = list( @@ -297,6 +315,7 @@ /obj/item/storage/toolbox = 1, ) category = CAT_WEAPON_RANGED + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/laser_musket name = "Laser Musket" @@ -316,7 +335,6 @@ /datum/crafting_recipe/laser_musket_prime name = "Heroic Laser Musket" - always_available = FALSE result = /obj/item/gun/energy/laser/musket/prime reqs = list( /obj/item/gun/energy/laser/musket = 1, @@ -329,6 +347,7 @@ tool_paths = list(/obj/item/clothing/head/cowboy, /obj/item/clothing/shoes/cowboy) time = 30 SECONDS //contemplate for a bit category = CAT_WEAPON_RANGED + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/smoothbore_disabler name = "Smoothbore Disabler" @@ -347,7 +366,6 @@ /datum/crafting_recipe/smoothbore_disabler_prime name = "Elite Smoothbore Disabler" - always_available = FALSE result = /obj/item/gun/energy/disabler/smoothbore/prime reqs = list( /obj/item/gun/energy/disabler/smoothbore = 1, @@ -358,3 +376,4 @@ tool_behaviors = list(TOOL_SCREWDRIVER) time = 20 SECONDS category = CAT_WEAPON_RANGED + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED diff --git a/code/datums/components/crafting/structures.dm b/code/datums/components/crafting/structures.dm index 2cbe2c353020b..c4a9b48ec36b6 100644 --- a/code/datums/components/crafting/structures.dm +++ b/code/datums/components/crafting/structures.dm @@ -11,33 +11,33 @@ /datum/crafting_recipe/rib name = "Colossal Rib" - always_available = FALSE reqs = list( /obj/item/stack/sheet/bone = 10, /datum/reagent/fuel/oil = 5, ) result = /obj/structure/statue/bone/rib category = CAT_STRUCTURE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/skull name = "Skull Carving" - always_available = FALSE reqs = list( /obj/item/stack/sheet/bone = 6, /datum/reagent/fuel/oil = 5, ) result = /obj/structure/statue/bone/skull category = CAT_STRUCTURE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/halfskull name = "Cracked Skull Carving" - always_available = FALSE reqs = list( /obj/item/stack/sheet/bone = 3, /datum/reagent/fuel/oil = 5, ) result = /obj/structure/statue/bone/skull/half category = CAT_STRUCTURE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/firecabinet name = "Fire Axe Cabinet" @@ -65,7 +65,6 @@ name = "Syndicate Uplink Beacon" result = /obj/structure/syndicate_uplink_beacon tool_behaviors = list(TOOL_SCREWDRIVER) - always_available = FALSE time = 6 SECONDS reqs = list( /obj/item/stack/sheet/iron = 5, @@ -74,3 +73,4 @@ /obj/item/stack/ore/bluespace_crystal = 1, ) category = CAT_STRUCTURE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm index 56a6bfb2c3f18..3476016ead3b8 100644 --- a/code/datums/components/crafting/tailoring.dm +++ b/code/datums/components/crafting/tailoring.dm @@ -199,6 +199,29 @@ ) category = CAT_CLOTHING +/datum/crafting_recipe/wreath + name = "Watcher Wreath" + result = /obj/item/clothing/neck/wreath + time = 2 SECONDS + reqs = list( + /obj/item/stack/sheet/bone = 2, + /obj/item/stack/sheet/sinew = 2, + /obj/item/stack/ore/diamond = 2, + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/icewreath + name = "Icewing Wreath" + result = /obj/item/clothing/neck/wreath/icewing + time = 2 SECONDS + reqs = list( + /obj/item/stack/sheet/bone = 1, + /obj/item/stack/sheet/sinew = 1, + /obj/item/stack/ore/diamond = 2, + /obj/item/crusher_trophy/watcher_wing/ice_wing = 1, + ) + category = CAT_CLOTHING + /datum/crafting_recipe/bracers name = "Bone Bracers" result = /obj/item/clothing/gloves/bracer @@ -419,3 +442,42 @@ /obj/item/clothing/suit/armor/vest = 1, ) category = CAT_CLOTHING + +/datum/crafting_recipe/balloon_helmet + result = /obj/item/clothing/head/helmet/balloon + reqs = list( + /obj/item/toy/balloon/long = 6, + ) + time = 4 SECONDS + category = CAT_CLOTHING + +/datum/crafting_recipe/balloon_helmet/check_requirements(mob/user, list/collected_requirements) + . = ..() + if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return TRUE + +/datum/crafting_recipe/balloon_tophat + result = /obj/item/clothing/head/hats/tophat/balloon + reqs = list( + /obj/item/toy/balloon/long = 6, + ) + time = 4 SECONDS + category = CAT_CLOTHING + +/datum/crafting_recipe/balloon_tophat/check_requirements(mob/user, list/collected_requirements) + . = ..() + if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return TRUE + +/datum/crafting_recipe/balloon_vest + result = /obj/item/clothing/suit/armor/balloon_vest + reqs = list( + /obj/item/toy/balloon/long = 18, + ) + time = 8 SECONDS + category = CAT_CLOTHING + +/datum/crafting_recipe/balloon_vest/check_requirements(mob/user, list/collected_requirements) + . = ..() + if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return TRUE diff --git a/code/datums/components/crafting/tools.dm b/code/datums/components/crafting/tools.dm index 8b4b00d006026..d1d303daf8040 100644 --- a/code/datums/components/crafting/tools.dm +++ b/code/datums/components/crafting/tools.dm @@ -19,7 +19,6 @@ /datum/crafting_recipe/boneshovel name = "Serrated Bone Shovel" - always_available = FALSE reqs = list( /obj/item/stack/sheet/bone = 4, /datum/reagent/fuel/oil = 5, @@ -27,6 +26,7 @@ ) result = /obj/item/shovel/serrated category = CAT_TOOLS + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/lasso name = "Bone Lasso" diff --git a/code/datums/components/crafting/weapon_ammo.dm b/code/datums/components/crafting/weapon_ammo.dm index 44b8055b3ff94..32f34f2ae751c 100644 --- a/code/datums/components/crafting/weapon_ammo.dm +++ b/code/datums/components/crafting/weapon_ammo.dm @@ -20,8 +20,8 @@ ) tool_behaviors = list(TOOL_WIRECUTTER) time = 0.5 SECONDS - always_available = FALSE category = CAT_WEAPON_AMMO + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/pulseslug name = "Pulse Slug Shell" @@ -71,8 +71,8 @@ category = CAT_WEAPON_AMMO /datum/crafting_recipe/improvisedslug - name = "Improvised Shotgun Shell" - result = /obj/item/ammo_casing/shotgun/improvised + name = "Junk Shell" + result = /obj/effect/spawner/random/junk_shell reqs = list( /obj/item/stack/sheet/iron = 2, /obj/item/stack/cable_coil = 1, @@ -85,10 +85,10 @@ /datum/crafting_recipe/trashball name = "Trashball" - always_available = FALSE result = /obj/item/stack/cannonball/trashball reqs = list( /obj/item/stack/sheet = 5, /datum/reagent/consumable/space_cola = 10, ) category = CAT_WEAPON_AMMO + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm index 74bac463e32ad..7d9710977cecb 100644 --- a/code/datums/components/cult_ritual_item.dm +++ b/code/datums/components/cult_ritual_item.dm @@ -221,7 +221,7 @@ cultist.log_message("erased a [rune.cultist_name] rune with [parent].", LOG_GAME) message_admins("[ADMIN_LOOKUPFLW(cultist)] erased a [rune.cultist_name] rune with [parent].") - to_chat(cultist, span_notice("You carefully erase the [lowertext(rune.cultist_name)] rune.")) + to_chat(cultist, span_notice("You carefully erase the [LOWER_TEXT(rune.cultist_name)] rune.")) qdel(rune) /* @@ -338,8 +338,8 @@ var/obj/effect/rune/made_rune = new rune_to_scribe(our_turf, chosen_keyword) made_rune.add_mob_blood(cultist) - to_chat(cultist, span_cult("The [lowertext(made_rune.cultist_name)] rune [made_rune.cultist_desc]")) - cultist.log_message("scribed \a [lowertext(made_rune.cultist_name)] rune using [parent] ([parent.type])", LOG_GAME) + to_chat(cultist, span_cult("The [LOWER_TEXT(made_rune.cultist_name)] rune [made_rune.cultist_desc]")) + cultist.log_message("scribed \a [LOWER_TEXT(made_rune.cultist_name)] rune using [parent] ([parent.type])", LOG_GAME) SSblackbox.record_feedback("tally", "cult_runes_scribed", 1, made_rune.cultist_name) return TRUE diff --git a/code/datums/components/customizable_reagent_holder.dm b/code/datums/components/customizable_reagent_holder.dm index bd88508bec05e..fd1b8a2ac6479 100644 --- a/code/datums/components/customizable_reagent_holder.dm +++ b/code/datums/components/customizable_reagent_holder.dm @@ -206,7 +206,7 @@ if(isitem(atom_parent)) var/obj/item/item_parent = atom_parent if(ingredient.w_class > item_parent.w_class) - item_parent.w_class = ingredient.w_class + item_parent.update_weight_class(ingredient.w_class) atom_parent.name = "[custom_adjective()] [custom_type()] [initial(atom_parent.name)]" SEND_SIGNAL(atom_parent, COMSIG_ATOM_CUSTOMIZED, ingredient) SEND_SIGNAL(ingredient, COMSIG_ITEM_USED_AS_INGREDIENT, atom_parent) diff --git a/code/datums/components/damage_aura.dm b/code/datums/components/damage_aura.dm index b4c535cb52d42..98d323aa6d532 100644 --- a/code/datums/components/damage_aura.dm +++ b/code/datums/components/damage_aura.dm @@ -4,7 +4,7 @@ /// Will deal more damage the more people are present. /datum/component/damage_aura /// The range of which to damage - var/range + var/range = 5 /// Whether or not you must be a visible object of the parent var/requires_visibility = TRUE @@ -43,7 +43,7 @@ COOLDOWN_DECLARE(last_damage_effect_time) /datum/component/damage_aura/Initialize( - range, + range = 5, requires_visibility = TRUE, brute_damage = 0, burn_damage = 0, @@ -59,7 +59,7 @@ if (!isatom(parent)) return COMPONENT_INCOMPATIBLE - START_PROCESSING(SSobj, src) + START_PROCESSING(SSaura, src) src.range = range src.requires_visibility = requires_visibility @@ -75,7 +75,7 @@ src.current_owner = WEAKREF(current_owner) /datum/component/damage_aura/Destroy(force) - STOP_PROCESSING(SSobj, src) + STOP_PROCESSING(SSaura, src) return ..() /// The requirements for the mob to be effected by the damage aura. @@ -102,7 +102,15 @@ if (should_show_effect) COOLDOWN_START(src, last_damage_effect_time, DAMAGE_EFFECT_COOLDOWN) - for (var/mob/living/candidate in (requires_visibility ? view(range, parent) : range(range, parent))) + var/list/to_damage = list() + if(requires_visibility) + for(var/mob/living/candidate in view(range, parent)) + to_damage += candidate + else + for(var/mob/living/candidate in range(range, parent)) + to_damage += candidate + + for (var/mob/living/candidate as anything in to_damage) var/mob/living/owner = current_owner?.resolve() if (owner && owner == candidate) owner_effect(owner, seconds_per_tick) diff --git a/code/datums/components/deadchat_control.dm b/code/datums/components/deadchat_control.dm index 7517f35ff297b..210ef26a05235 100644 --- a/code/datums/components/deadchat_control.dm +++ b/code/datums/components/deadchat_control.dm @@ -61,7 +61,7 @@ /datum/component/deadchat_control/proc/deadchat_react(mob/source, message) SIGNAL_HANDLER - message = lowertext(message) + message = LOWER_TEXT(message) if(!inputs[message]) return @@ -162,7 +162,7 @@ */ /datum/component/deadchat_control/proc/waive_automute(mob/speaker, client/client, message, mute_type) SIGNAL_HANDLER - if(mute_type == MUTE_DEADCHAT && inputs[lowertext(message)]) + if(mute_type == MUTE_DEADCHAT && inputs[LOWER_TEXT(message)]) return WAIVE_AUTOMUTE_CHECK return NONE diff --git a/code/datums/components/drift.dm b/code/datums/components/drift.dm index 6b91a83534fb3..7fba50d315178 100644 --- a/code/datums/components/drift.dm +++ b/code/datums/components/drift.dm @@ -23,7 +23,7 @@ if(instant) flags |= MOVEMENT_LOOP_START_FAST var/atom/movable/movable_parent = parent - drifting_loop = SSmove_manager.move(moving = parent, direction = direction, delay = movable_parent.inertia_move_delay, subsystem = SSspacedrift, priority = MOVEMENT_SPACE_PRIORITY, flags = flags) + drifting_loop = GLOB.move_manager.move(moving = parent, direction = direction, delay = movable_parent.inertia_move_delay, subsystem = SSspacedrift, priority = MOVEMENT_SPACE_PRIORITY, flags = flags) if(!drifting_loop) //Really want to qdel here but can't return COMPONENT_INCOMPATIBLE diff --git a/code/datums/components/explodable.dm b/code/datums/components/explodable.dm index 956d562bfb66f..439b156352104 100644 --- a/code/datums/components/explodable.dm +++ b/code/datums/components/explodable.dm @@ -122,13 +122,7 @@ if(!istype(wearer)) return FALSE - // Maybe switch this over if we have a get_all_clothing or similar proc for carbon mobs. - // get_all_worn_items is a lie, they include pockets. - var/list/worn_items = list() - worn_items += list(wearer.head, wearer.wear_mask, wearer.gloves, wearer.shoes, wearer.glasses, wearer.ears) - if(ishuman(wearer)) - var/mob/living/carbon/human/human_wearer = wearer - worn_items += list(human_wearer.wear_suit, human_wearer.w_uniform) + var/list/worn_items = wearer.get_equipped_items() if(!(item in worn_items)) return FALSE diff --git a/code/datums/components/fertile_egg.dm b/code/datums/components/fertile_egg.dm index dba704812b088..59100028e852d 100644 --- a/code/datums/components/fertile_egg.dm +++ b/code/datums/components/fertile_egg.dm @@ -29,7 +29,10 @@ /// If true, being in an unsuitable location spoils the egg (ie. kills the component). If false, it just pauses the egg's development. var/spoilable -/datum/component/fertile_egg/Initialize(embryo_type, minimum_growth_rate, maximum_growth_rate, total_growth_required, current_growth, location_allowlist, spoilable, examine_message) + ///callback after the egg hatches + var/datum/callback/post_hatch + +/datum/component/fertile_egg/Initialize(embryo_type, minimum_growth_rate, maximum_growth_rate, total_growth_required, current_growth, location_allowlist, spoilable, examine_message, post_hatch) // Quite how an _area_ can be a fertile egg is an open question, but it still has a location. Technically. if(!isatom(parent)) return COMPONENT_INCOMPATIBLE @@ -41,6 +44,7 @@ src.current_growth = current_growth src.location_allowlist = location_allowlist src.spoilable = spoilable + src.post_hatch = post_hatch START_PROCESSING(SSobj, src) @@ -58,8 +62,10 @@ return current_growth += rand(minimum_growth_rate, maximum_growth_rate) * seconds_per_tick - if(current_growth >= total_growth_required) - parent_atom.visible_message(span_notice("[parent] hatches with a quiet cracking sound.")) - new embryo_type(get_turf(parent_atom)) - // We destroy the parent on hatch, which will destroy the component as well, which will stop us processing. - qdel(parent_atom) + if(current_growth < total_growth_required) + return + parent_atom.visible_message(span_notice("[parent] hatches with a quiet cracking sound.")) + new embryo_type(get_turf(parent_atom)) + post_hatch?.Invoke(embryo_type) + // We destroy the parent on hatch, which will destroy the component as well, which will stop us processing. + qdel(parent_atom) diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index 85a6a7e386b53..d4b80ea1dd8ab 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -215,7 +215,7 @@ Behavior that's still missing from this component that original food items had t if(foodtypes) var/list/types = bitfield_to_list(foodtypes, FOOD_FLAGS) - examine_list += span_notice("It is [lowertext(english_list(types))].") + examine_list += span_notice("It is [LOWER_TEXT(english_list(types))].") var/quality = get_perceived_food_quality(user) if(quality > 0) diff --git a/code/datums/components/force_move.dm b/code/datums/components/force_move.dm index b8c368186216a..62fe26d71f7da 100644 --- a/code/datums/components/force_move.dm +++ b/code/datums/components/force_move.dm @@ -9,7 +9,7 @@ var/mob/mob_parent = parent var/dist = get_dist(mob_parent, target) - var/datum/move_loop/loop = SSmove_manager.move_towards(mob_parent, target, delay = 1, timeout = dist) + var/datum/move_loop/loop = GLOB.move_manager.move_towards(mob_parent, target, delay = 1, timeout = dist) RegisterSignal(mob_parent, COMSIG_MOB_CLIENT_PRE_LIVING_MOVE, PROC_REF(stop_move)) RegisterSignal(mob_parent, COMSIG_ATOM_PRE_PRESSURE_PUSH, PROC_REF(stop_pressure)) if(spin) diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm index 8663de5adc691..1faa04ceacc75 100644 --- a/code/datums/components/fullauto.dm +++ b/code/datums/components/fullauto.dm @@ -9,11 +9,11 @@ var/autofire_stat = AUTOFIRE_STAT_IDLE var/mouse_parameters /// Time between individual shots. - var/autofire_shot_delay = 0.3 SECONDS + var/autofire_shot_delay = 0.3 SECONDS /// This seems hacky but there can be two MouseDown() without a MouseUp() in between if the user holds click and uses alt+tab, printscreen or similar. - var/mouse_status = AUTOFIRE_MOUSEUP + var/mouse_status = AUTOFIRE_MOUSEUP /// Should dual wielding be allowed? - var/allow_akimbo + var/allow_akimbo ///windup autofire vars ///Whether the delay between shots increases over time, simulating a spooling weapon @@ -249,7 +249,7 @@ if(get_dist(shooter, target) <= 0) target = get_step(shooter, shooter.dir) //Shoot in the direction faced if the mouse is on the same tile as we are. target_loc = target - else if(!in_view_range(shooter, target)) + else if(!CAN_THEY_SEE(target, shooter)) stop_autofiring() //Elvis has left the building. return FALSE shooter.face_atom(target) @@ -259,7 +259,7 @@ current_windup_reduction = (current_windup_reduction + round(autofire_shot_delay * windup_autofire_reduction_multiplier)) timerid = addtimer(CALLBACK(src, PROC_REF(windup_reset), FALSE), windup_spindown, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE) if(HAS_TRAIT(shooter, TRAIT_DOUBLE_TAP)) - next_delay = round(next_delay * 0.5) + next_delay = round(next_delay * 0.5, SSprojectiles.wait) COOLDOWN_START(src, next_shot_cd, next_delay) if(SEND_SIGNAL(parent, COMSIG_AUTOFIRE_SHOT, target, shooter, allow_akimbo, mouse_parameters) & COMPONENT_AUTOFIRE_SHOT_SUCCESS) return TRUE @@ -310,7 +310,7 @@ if(istype(akimbo_gun) && weapon_weight < WEAPON_MEDIUM && allow_akimbo) if(akimbo_gun.weapon_weight < WEAPON_MEDIUM && akimbo_gun.can_trigger_gun(shooter)) bonus_spread = dual_wield_spread - addtimer(CALLBACK(akimbo_gun, TYPE_PROC_REF(/obj/item/gun, process_fire), target, shooter, TRUE, params, null, bonus_spread), 1) + addtimer(CALLBACK(akimbo_gun, TYPE_PROC_REF(/obj/item/gun, process_fire), target, shooter, TRUE, params, null, bonus_spread), 0.1 SECONDS) process_fire(target, shooter, TRUE, params, null, bonus_spread) #undef AUTOFIRE_MOUSEUP diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index ceee193bf4ad5..7e52f00def752 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -50,7 +50,7 @@ GLOBAL_LIST_EMPTY(GPS_list) if(!emp_proof) RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) - RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_AltClick)) + RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_click_alt)) ///Called on COMSIG_ITEM_ATTACK_SELF /datum/component/gps/item/proc/interact(datum/source, mob/user) @@ -85,10 +85,11 @@ GLOBAL_LIST_EMPTY(GPS_list) A.add_overlay("working") ///Calls toggletracking -/datum/component/gps/item/proc/on_AltClick(datum/source, mob/user) +/datum/component/gps/item/proc/on_click_alt(datum/source, mob/user) SIGNAL_HANDLER toggletracking(user) + return CLICK_ACTION_SUCCESS ///Toggles the tracking for the gps /datum/component/gps/item/proc/toggletracking(mob/user) @@ -153,7 +154,7 @@ GLOBAL_LIST_EMPTY(GPS_list) data["signals"] = signals return data -/datum/component/gps/item/ui_act(action, params) +/datum/component/gps/item/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -162,7 +163,8 @@ GLOBAL_LIST_EMPTY(GPS_list) if("rename") var/atom/parentasatom = parent var/a = tgui_input_text(usr, "Enter the desired tag", "GPS Tag", gpstag, 20) - + if (QDELETED(ui) || ui.status != UI_INTERACTIVE) + return if (!a) return diff --git a/code/datums/components/growth_and_differentiation.dm b/code/datums/components/growth_and_differentiation.dm index a6e10b98f6d7a..bcf6722492251 100644 --- a/code/datums/components/growth_and_differentiation.dm +++ b/code/datums/components/growth_and_differentiation.dm @@ -37,6 +37,7 @@ growth_probability, lower_growth_value, upper_growth_value, + scale_with_happiness, list/signals_to_kill_on, datum/callback/optional_checks, datum/callback/optional_grow_behavior, @@ -55,6 +56,11 @@ if(islist(signals_to_kill_on)) src.signals_to_kill_on = signals_to_kill_on RegisterSignals(parent, src.signals_to_kill_on, PROC_REF(stop_component_processing_entirely)) + + if(scale_with_happiness) + if(!HAS_TRAIT(parent, TRAIT_MOB_RELAY_HAPPINESS)) + AddComponent(/datum/component/happiness) + RegisterSignal(parent, COMSIG_MOB_HAPPINESS_CHANGE, PROC_REF(on_happiness_change)) // If we haven't started the round, we can't do timer stuff. Let's wait in case we're mapped in or something. if(!SSticker.HasRoundStarted() && !isnull(growth_time)) @@ -113,6 +119,12 @@ if(SPT_PROB(growth_probability, seconds_per_tick)) percent_grown += rand(lower_growth_value, upper_growth_value) +/datum/component/growth_and_differentiation/proc/on_happiness_change(datum/source, happiness_percentage) + SIGNAL_HANDLER + + var/probability_to_add = initial(growth_probability) * happiness_percentage + growth_probability = min(initial(growth_probability) + probability_to_add, 100) + /// Grows the mob into its new form. /datum/component/growth_and_differentiation/proc/grow(silent) if(!isnull(optional_checks) && !optional_checks.Invoke()) // we failed our checks somehow, but we're still ready to grow. Let's wait until next tick to see if our circumstances have changed. @@ -143,3 +155,4 @@ var/mob/living/transformed_mob = old_mob.change_mob_type(growth_path, old_mob.loc, new_name = new_mob_name, delete_old_mob = TRUE) if(initial(new_mob.unique_name)) transformed_mob.set_name() + ADD_TRAIT(transformed_mob, TRAIT_MOB_HATCHED, INNATE_TRAIT) diff --git a/code/datums/components/happiness.dm b/code/datums/components/happiness.dm new file mode 100644 index 0000000000000..0a6274611923b --- /dev/null +++ b/code/datums/components/happiness.dm @@ -0,0 +1,159 @@ +#define INSPECT_TIMER 10 SECONDS +#define PET_COOLDOWN 10 SECONDS +#define GROOM_COOLDOWN 30 SECONDS + +/* + * A component that allows mobs to have happiness levels + */ +/datum/component/happiness + ///our current happiness level + var/happiness_level + ///our maximum happiness level + var/maximum_happiness + ///happiness AI blackboard key + var/blackboard_key + ///happiness when we get groomed + var/on_groom_change + ///happiness when we get petted + var/on_petted_change + ///happiness when we eat + var/on_eat_change + ///percentages we should be calling back on + var/list/callback_percentages + ///callback when our happiness changes + var/datum/callback/happiness_callback + + ///how long till we can inspect happiness again? + COOLDOWN_DECLARE(happiness_inspect) + ///how long till we can pet it again? + COOLDOWN_DECLARE(pet_cooldown) + ///how long till we can groom it again + COOLDOWN_DECLARE(groom_cooldown) + +/datum/component/happiness/Initialize(maximum_happiness = 400, blackboard_key = BB_BASIC_HAPPINESS, on_groom_change = 200, on_eat_change = 300, on_petted_change = 30, callback_percentages = list(0, 25, 50, 75, 100), happiness_callback) + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + + src.maximum_happiness = maximum_happiness + src.blackboard_key = blackboard_key + src.on_groom_change = on_groom_change + src.on_petted_change = on_petted_change + src.on_eat_change = on_eat_change + src.happiness_callback = happiness_callback + src.callback_percentages = callback_percentages + + ADD_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type) + +/datum/component/happiness/RegisterWithParent() + + if(on_petted_change) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_petted)) + if(on_groom_change) + RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean)) + if(on_eat_change) + RegisterSignal(parent, COMSIG_MOB_ATE, PROC_REF(on_eat)) + RegisterSignal(parent, COMSIG_SHIFT_CLICKED_ON, PROC_REF(view_happiness)) + ADD_TRAIT(parent, TRAIT_MOB_RELAY_HAPPINESS, REF(src)) + +/datum/component/happiness/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_MOB_ATE)) + REMOVE_TRAIT(parent, TRAIT_MOB_RELAY_HAPPINESS, REF(src)) + happiness_callback = null + +/datum/component/happiness/proc/on_eat(datum/source) + SIGNAL_HANDLER + + increase_happiness_level(on_eat_change) + +/datum/component/happiness/proc/on_clean(mob/living/source) + SIGNAL_HANDLER + if(!COOLDOWN_FINISHED(src, groom_cooldown)) + return + COOLDOWN_START(src, groom_cooldown, GROOM_COOLDOWN) + increase_happiness_level(on_groom_change) + +/datum/component/happiness/proc/on_petted(datum/source, mob/living/petter, list/modifiers) + SIGNAL_HANDLER + if(!LAZYACCESS(modifiers, LEFT_CLICK) || petter.combat_mode) + return + pet_animal() + +/datum/component/happiness/proc/on_animal_petted(datum/source, mob/living/petter) + SIGNAL_HANDLER + + if(petter.combat_mode) + return + pet_animal() + return COMSIG_BASIC_ATTACK_CANCEL_CHAIN + +/datum/component/happiness/proc/pet_animal() + if(!COOLDOWN_FINISHED(src, pet_cooldown)) + return + increase_happiness_level(on_petted_change) + COOLDOWN_START(src, pet_cooldown, PET_COOLDOWN) + + +/datum/component/happiness/proc/increase_happiness_level(amount) + happiness_level = min(happiness_level + amount, maximum_happiness) + var/mob/living/living_parent = parent + new /obj/effect/temp_visual/heart(living_parent.loc) + living_parent.spin(spintime = 2 SECONDS, speed = 1) + START_PROCESSING(SSprocessing, src) + +/datum/component/happiness/proc/view_happiness(mob/living/source, mob/living/clicker) + if(!istype(clicker) || !COOLDOWN_FINISHED(src, happiness_inspect) || !clicker.CanReach(source)) + return + var/list/offset_to_add = get_icon_dimensions(source.icon) + var/y_position = offset_to_add["height"] + 1 + var/obj/effect/overlay/happiness_overlay/hearts = new + hearts.pixel_y = y_position + hearts.set_hearts(happiness_level/maximum_happiness) + source.vis_contents += hearts + COOLDOWN_START(src, happiness_inspect, INSPECT_TIMER) + + +/datum/component/happiness/process() + var/mob/living/living_parent = parent + var/happiness_percentage = happiness_level/maximum_happiness + living_parent.ai_controller?.set_blackboard_key(blackboard_key, happiness_percentage) + var/check_percentage_in_list = round(happiness_percentage * 100, 1) + if(check_percentage_in_list in callback_percentages) + SEND_SIGNAL(parent, COMSIG_MOB_HAPPINESS_CHANGE, happiness_percentage) + happiness_callback?.Invoke(happiness_percentage) + + if(happiness_level <= 0) + return PROCESS_KILL + var/modifier = living_parent.ai_controller?.blackboard[BB_BASIC_DEPRESSED] ? 2 : 1 + happiness_level = max(0, happiness_level - modifier) + +/obj/effect/overlay/happiness_overlay + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + anchored = TRUE + vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE + layer = ABOVE_HUD_PLANE + ///how many hearts should we display + VAR_PRIVATE/hearts_percentage + ///icon of our heart + var/heart_icon = 'icons/effects/effects.dmi' + +/obj/effect/overlay/happiness_overlay/Initialize(mapload) + . = ..() + QDEL_IN(src, 5 SECONDS) + +/obj/effect/overlay/happiness_overlay/proc/set_hearts(happiness_percentage) + hearts_percentage = happiness_percentage + update_appearance(UPDATE_OVERLAYS) + +/obj/effect/overlay/happiness_overlay/update_overlays() + . = ..() + var/static/list/heart_positions = list(-13, -5, 3, 11) + var/display_amount = round(length(heart_positions) * hearts_percentage, 1) + for(var/index in 1 to length(heart_positions)) + var/heart_icon_state = display_amount >= index ? "full_heart" : "empty_heart" + var/mutable_appearance/display_icon = mutable_appearance(icon = heart_icon, icon_state = heart_icon_state, layer = ABOVE_HUD_PLANE) + display_icon.pixel_x = heart_positions[index] + . += display_icon + +#undef INSPECT_TIMER +#undef PET_COOLDOWN +#undef GROOM_COOLDOWN diff --git a/code/datums/components/healing_touch.dm b/code/datums/components/healing_touch.dm index bc0493b478773..07f04cba01d73 100644 --- a/code/datums/components/healing_touch.dm +++ b/code/datums/components/healing_touch.dm @@ -90,6 +90,8 @@ RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(try_healing)) // Players RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(try_healing)) // NPCs + var/mob/living/living_parent = parent + living_parent.ai_controller?.set_blackboard_key(BB_BASIC_MOB_HEALER, TRUE) // Let's populate this list as we actually use it, this thing has too many args /datum/component/healing_touch/InheritComponent( @@ -100,6 +102,8 @@ src.heal_color = heal_color /datum/component/healing_touch/UnregisterFromParent() + var/mob/living/living_parent = parent + living_parent.ai_controller?.set_blackboard_key(BB_BASIC_MOB_HEALER, FALSE) UnregisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) return ..() diff --git a/code/datums/components/infective.dm b/code/datums/components/infective.dm index 97df6342aeb11..fc2081481d937 100644 --- a/code/datums/components/infective.dm +++ b/code/datums/components/infective.dm @@ -59,8 +59,10 @@ /datum/component/infective/proc/try_infect_eat(datum/source, mob/living/eater, mob/living/feeder) SIGNAL_HANDLER - if(!eater.has_quirk(/datum/quirk/deviant_tastes)) - eater.add_mood_event("disgust", /datum/mood_event/disgust/dirty_food) + if(HAS_TRAIT(eater, TRAIT_STRONG_STOMACH)) + return + + eater.add_mood_event("disgust", /datum/mood_event/disgust/dirty_food) if(is_weak && !prob(weak_infection_chance)) return @@ -76,6 +78,9 @@ /datum/component/infective/proc/try_infect_drink(datum/source, mob/living/drinker, mob/living/feeder) SIGNAL_HANDLER + if(HAS_TRAIT(drinker, TRAIT_STRONG_STOMACH)) + return + var/appendage_zone = feeder.held_items.Find(source) appendage_zone = appendage_zone == 0 ? BODY_ZONE_CHEST : appendage_zone % 2 ? BODY_ZONE_R_ARM : BODY_ZONE_L_ARM try_infect(feeder, appendage_zone) diff --git a/code/datums/components/irradiated.dm b/code/datums/components/irradiated.dm index 805288fe4867f..077539f49db8e 100644 --- a/code/datums/components/irradiated.dm +++ b/code/datums/components/irradiated.dm @@ -90,7 +90,7 @@ if (should_halt_effects(parent)) return - if (human_parent.stat > DEAD) + if (human_parent.stat != DEAD) human_parent.dna?.species?.handle_radiation(human_parent, world.time - beginning_of_irradiation, seconds_per_tick) process_tox_damage(human_parent, seconds_per_tick) diff --git a/code/datums/components/jousting.dm b/code/datums/components/jousting.dm index 56b65c6f758b5..9c3dab3c8fbdd 100644 --- a/code/datums/components/jousting.dm +++ b/code/datums/components/jousting.dm @@ -44,7 +44,7 @@ RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip)) RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) - RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(on_attack)) + RegisterSignal(parent, COMSIG_ITEM_POST_ATTACK, PROC_REF(on_successful_attack)) RegisterSignal(parent, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) /datum/component/jousting/UnregisterFromParent() @@ -53,7 +53,7 @@ COMSIG_ATOM_EXAMINE, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, - COMSIG_ITEM_ATTACK, + COMSIG_ITEM_POST_ATTACK, COMSIG_TRANSFORMING_ON_TRANSFORM, )) @@ -94,7 +94,7 @@ * We deduct the minimum tile charge from the current tile charge to get what will actually be buffed * So your charge will only get benefits from each extra tile after the minimum (and before the maximum). */ -/datum/component/jousting/proc/on_attack(datum/source, mob/living/target, mob/user) +/datum/component/jousting/proc/on_successful_attack(datum/source, mob/living/target, mob/user) SIGNAL_HANDLER if(user != current_holder || !user.buckled) return diff --git a/code/datums/components/listen_and_repeat.dm b/code/datums/components/listen_and_repeat.dm index 93d2dde93f006..0ebeda27b3f69 100644 --- a/code/datums/components/listen_and_repeat.dm +++ b/code/datums/components/listen_and_repeat.dm @@ -2,12 +2,16 @@ #define MAX_SPEECH_BUFFER_SIZE 500 /// Tendency we have to ignore radio chatter #define RADIO_IGNORE_CHANCE 10 +/// The line we will re-iterate +#define MESSAGE_LINE "line" +/// the tts voice it should be said in +#define MESSAGE_VOICE "voice" +/// the tone it should be said in +#define MESSAGE_PITCH "pitch" /// Simple element that will deterministically set a value based on stuff that the source has heard and will then compel the source to repeat it. /// Requires a valid AI Blackboard. /datum/component/listen_and_repeat - /// List of things that we start out having in our speech buffer - var/list/desired_phrases = null /// The AI Blackboard Key we assign the value to. var/blackboard_key = null /// Probability we speak @@ -16,14 +20,22 @@ var/switch_phrase_probability = null /// List of things that we've heard and will repeat. var/list/speech_buffer = null + /// list we give speech that doesnt have a voice or a pitch + var/static/list/invalid_voice = list( + MESSAGE_VOICE = "invalid", + MESSAGE_PITCH = 0, + ) /datum/component/listen_and_repeat/Initialize(list/desired_phrases, blackboard_key) . = ..() if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE - if(!isnull(desired_phrases)) - LAZYADD(speech_buffer, desired_phrases) + for(var/speech in desired_phrases) + if(!islist(desired_phrases[speech]) || !desired_phrases[speech][MESSAGE_VOICE] || !desired_phrases[speech][MESSAGE_PITCH]) + LAZYSET(speech_buffer, speech, invalid_voice) + continue + LAZYSET(speech_buffer, speech, desired_phrases[speech]) src.blackboard_key = blackboard_key @@ -47,6 +59,16 @@ if(speaker == source) // don't parrot ourselves return + var/list/speaker_sound + + if(!SStts.tts_enabled || !ismovable(speaker)) + speaker_sound = invalid_voice + else + speaker_sound = list() + var/atom/movable/movable_speaker = speaker + speaker_sound[MESSAGE_VOICE] = movable_speaker.voice || "invalid" + speaker_sound[MESSAGE_PITCH] = (movable_speaker.pitch && SStts.pitch_enabled ? movable_speaker.pitch : 0) + if(over_radio && prob(RADIO_IGNORE_CHANCE)) return @@ -55,7 +77,7 @@ for(var/i in 1 to number_of_excess_strings) LAZYREMOVE(speech_buffer, pick(speech_buffer)) - LAZYOR(speech_buffer, html_decode(message)) + LAZYSET(speech_buffer, html_decode(message), speaker_sound) /// Called to set a new value for the blackboard key. /datum/component/listen_and_repeat/proc/set_new_blackboard_phrase(datum/source) @@ -67,7 +89,13 @@ return NO_NEW_PHRASE_AVAILABLE var/selected_phrase = pick(speech_buffer) - controller.set_blackboard_key(blackboard_key, selected_phrase) + var/list/to_return = list(MESSAGE_LINE = selected_phrase) + + if(islist(speech_buffer[selected_phrase])) + to_return[MESSAGE_VOICE] = speech_buffer[selected_phrase][MESSAGE_VOICE] + to_return[MESSAGE_PITCH] = speech_buffer[selected_phrase][MESSAGE_PITCH] + + controller.override_blackboard_key(blackboard_key, to_return) /// Exports all the speech buffer data to a dedicated blackboard key on the source. /datum/component/listen_and_repeat/proc/on_write_memory(datum/source, dead, gibbed) @@ -81,3 +109,6 @@ #undef MAX_SPEECH_BUFFER_SIZE #undef RADIO_IGNORE_CHANCE +#undef MESSAGE_VOICE +#undef MESSAGE_PITCH +#undef MESSAGE_LINE diff --git a/code/datums/components/martial_art_giver.dm b/code/datums/components/martial_art_giver.dm new file mode 100644 index 0000000000000..1a0bfa9951a40 --- /dev/null +++ b/code/datums/components/martial_art_giver.dm @@ -0,0 +1,45 @@ +/// when equipped and unequipped this item gives a martial art +/datum/component/martial_art_giver + /// the style we give + var/datum/martial_art/style + +/datum/component/martial_art_giver/Initialize(style_type) + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + style = new style_type() + style.allow_temp_override = FALSE + +/datum/component/martial_art_giver/RegisterWithParent() + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(equipped)) + RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(dropped)) + +/datum/component/martial_art_giver/UnregisterFromParent(datum/source) + UnregisterSignal(parent, list(COMSIG_ITEM_POST_EQUIPPED, COMSIG_ITEM_POST_UNEQUIP)) + var/obj/item/parent_item = parent + if(ismob(parent_item?.loc)) + UnregisterSignal(parent, list(COMSIG_MOB_MIND_TRANSFERRED_INTO, COMSIG_MOB_MIND_INITIALIZED, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF)) + QDEL_NULL(style) + +/datum/component/martial_art_giver/proc/equipped(obj/item/source, mob/user, slot) + SIGNAL_HANDLER + if(!(source.slot_flags & slot)) + return + RegisterSignals(user, list(COMSIG_MOB_MIND_TRANSFERRED_INTO, COMSIG_MOB_MIND_INITIALIZED), PROC_REF(teach)) + RegisterSignal(user, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, PROC_REF(forget)) + teach(user) + +/datum/component/martial_art_giver/proc/dropped(obj/item/source, mob/user) + SIGNAL_HANDLER + forget(user) + UnregisterSignal(user, list(COMSIG_MOB_MIND_TRANSFERRED_INTO, COMSIG_MOB_MIND_INITIALIZED, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF)) + +/datum/component/martial_art_giver/proc/teach(mob/source) + if(isnull(style)) + return + style.teach(source, TRUE) + +/datum/component/martial_art_giver/proc/forget(mob/source) + if(isnull(style)) + return + style.fully_remove(source) diff --git a/code/datums/components/material/material_container.dm b/code/datums/components/material/material_container.dm index 69f67d46df3a8..ffcf81feacefd 100644 --- a/code/datums/components/material/material_container.dm +++ b/code/datums/components/material/material_container.dm @@ -102,7 +102,7 @@ var/datum/material/M = I var/amt = materials[I] / SHEET_MATERIAL_AMOUNT if(amt) - examine_texts += span_notice("It has [amt] sheets of [lowertext(M.name)] stored.") + examine_texts += span_notice("It has [amt] sheets of [LOWER_TEXT(M.name)] stored.") /datum/component/material_container/vv_edit_var(var_name, var_value) var/old_flags = mat_container_flags @@ -678,6 +678,7 @@ while(sheet_amt > 0) //don't merge yet. we need to do stuff with it first var/obj/item/stack/sheet/new_sheets = new material.sheet_type(target, min(sheet_amt, MAX_STACK_SIZE), FALSE) + new_sheets.manufactured = TRUE count += new_sheets.amount //use material & deduct work needed use_amount_mat(new_sheets.amount * SHEET_MATERIAL_AMOUNT, material) diff --git a/code/datums/components/mirv.dm b/code/datums/components/mirv.dm index 0f41df1d2888a..52b4053babb5a 100644 --- a/code/datums/components/mirv.dm +++ b/code/datums/components/mirv.dm @@ -39,5 +39,5 @@ P.range = override_projectile_range P.preparePixelProjectile(shootat_turf, target) P.firer = firer // don't hit ourself that would be really annoying - P.impacted = list(target = TRUE) // don't hit the target we hit already with the flak + P.impacted = list(WEAKREF(target) = TRUE) // don't hit the target we hit already with the flak P.fire() diff --git a/code/datums/components/orbiter.dm b/code/datums/components/orbiter.dm index 3ba6ba22c07fa..71f391e599ad8 100644 --- a/code/datums/components/orbiter.dm +++ b/code/datums/components/orbiter.dm @@ -120,6 +120,10 @@ orbiter_mob.updating_glide_size = TRUE orbiter_mob.glide_size = 8 + if(isobserver(orbiter)) + var/mob/dead/observer/ghostie = orbiter + ghostie.orbiting_ref = null + REMOVE_TRAIT(orbiter, TRAIT_NO_FLOATING_ANIM, ORBITING_TRAIT) if(!refreshing && !length(orbiter_list) && !QDELING(src)) diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm index e857292f487a5..c206af62f704a 100644 --- a/code/datums/components/pellet_cloud.dm +++ b/code/datums/components/pellet_cloud.dm @@ -277,7 +277,7 @@ P.original = target P.fired_from = parent P.firer = parent // don't hit ourself that would be really annoying - P.impacted = list(parent = TRUE) // don't hit the target we hit already with the flak + P.impacted = list(WEAKREF(parent) = TRUE) // don't hit the target we hit already with the flak P.suppressed = SUPPRESSED_VERY // set the projectiles to make no message so we can do our own aggregate message P.preparePixelProjectile(target, parent) RegisterSignal(P, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(pellet_hit)) diff --git a/code/datums/components/pet_commands/obeys_commands.dm b/code/datums/components/pet_commands/obeys_commands.dm index 2fceaa2b3379e..ec3a04c940a2a 100644 --- a/code/datums/components/pet_commands/obeys_commands.dm +++ b/code/datums/components/pet_commands/obeys_commands.dm @@ -72,6 +72,7 @@ return // Not our friend, can't boss us around INVOKE_ASYNC(src, PROC_REF(display_radial_menu), clicker) + return CLICK_ACTION_SUCCESS /// Actually display the radial menu and then do something with the result /datum/component/obeys_commands/proc/display_radial_menu(mob/living/clicker) diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index 245f8f969a980..3e5528b1095a3 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -375,7 +375,7 @@ return // Defer to later frame because pixel_* is actually updated after all callbacks - addtimer(CALLBACK(parent_obj, TYPE_PROC_REF(/atom/, update_appearance)), 1) + addtimer(CALLBACK(parent_obj, TYPE_PROC_REF(/atom/, update_appearance)), 0.1 SECONDS) ///has one pipe input that only takes, example is manual output pipe /datum/component/plumbing/simple_demand diff --git a/code/datums/components/plumbing/splitter.dm b/code/datums/components/plumbing/splitter.dm index 4dd68a9e5780f..5ade1dfebc3ba 100644 --- a/code/datums/components/plumbing/splitter.dm +++ b/code/datums/components/plumbing/splitter.dm @@ -43,5 +43,6 @@ if(EAST) if(amount >= S.transfer_side) amount = S.transfer_side + S.use_energy(S.active_power_usage) return ..() diff --git a/code/datums/components/puzzgrid.dm b/code/datums/components/puzzgrid.dm index e91bcdb30026b..d7e264f651f97 100644 --- a/code/datums/components/puzzgrid.dm +++ b/code/datums/components/puzzgrid.dm @@ -280,12 +280,7 @@ var/list/answers = list() var/description -/// Debug verb for validating that all puzzgrids can be created successfully. -/// Locked behind a verb because it's fairly slow and memory intensive. -/client/proc/validate_puzzgrids() - set name = "Validate Puzzgrid Config" - set category = "Debug" - +ADMIN_VERB(validate_puzzgrids, R_DEBUG, "Validate Puzzgrid Config", "Validate the puzzgrid config to ensure it's set up correctly.", ADMIN_CATEGORY_DEBUG) var/line_number = 0 for (var/line in world.file2list(PUZZGRID_CONFIG)) @@ -296,16 +291,16 @@ var/line_json_decoded = safe_json_decode(line) if (isnull(line_json_decoded)) - to_chat(src, span_warning("Line [line_number] in puzzgrids.txt is not a JSON: [line]")) + to_chat(user, span_warning("Line [line_number] in puzzgrids.txt is not a JSON: [line]")) continue var/datum/puzzgrid/puzzgrid = new var/populate_result = puzzgrid.populate(line_json_decoded) if (populate_result != TRUE) - to_chat(src, span_warning("Line [line_number] in puzzgrids.txt is not formatted correctly: [populate_result]")) + to_chat(user, span_warning("Line [line_number] in puzzgrids.txt is not formatted correctly: [populate_result]")) - to_chat(src, span_notice("Validated. If you did not see any errors, you're in the clear.")) + to_chat(user, span_notice("Validated. If you did not see any errors, you're in the clear.")) #undef PUZZGRID_CONFIG #undef PUZZGRID_GROUP_COUNT diff --git a/code/datums/components/ranged_mob_full_auto.dm b/code/datums/components/ranged_mob_full_auto.dm index a33b705d54850..ff3bfcfe60f7f 100644 --- a/code/datums/components/ranged_mob_full_auto.dm +++ b/code/datums/components/ranged_mob_full_auto.dm @@ -56,7 +56,7 @@ if (get_dist(living_parent, target) <= 0) set_target(get_step(living_parent, living_parent.dir)) // Shoot in the direction faced if the mouse is on the same tile as we are. target_loc = target - else if (!in_view_range(living_parent, target)) + else if (!CAN_THEY_SEE(target, living_parent)) stop_firing() return FALSE // Can't see shit diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index 74451e47c8772..7ead11012b024 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -30,6 +30,8 @@ var/list/allowed_turf_typecache /// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence. var/list/forbid_turf_typecache + /// additional traits to add to anyone riding this vehicle + var/list/rider_traits = list(TRAIT_NO_FLOATING_ANIM) /// We don't need roads where we're going if this is TRUE, allow normal movement in space tiles var/override_allow_spacemove = FALSE /// can anyone other than the rider unbuckle the rider? @@ -96,7 +98,7 @@ for (var/trait in GLOB.movement_type_trait_to_flag) if (HAS_TRAIT(parent, trait)) REMOVE_TRAIT(rider, trait, REF(src)) - REMOVE_TRAIT(rider, TRAIT_NO_FLOATING_ANIM, REF(src)) + rider.remove_traits(rider_traits, REF(src)) if(!movable_parent.has_buckled_mobs()) qdel(src) @@ -115,7 +117,8 @@ for (var/trait in GLOB.movement_type_trait_to_flag) if (HAS_TRAIT(parent, trait)) ADD_TRAIT(rider, trait, REF(src)) - ADD_TRAIT(rider, TRAIT_NO_FLOATING_ANIM, REF(src)) + rider.add_traits(rider_traits, REF(src)) + post_vehicle_mob_buckle(movable_parent, rider) /// This proc is called when the rider attempts to grab the thing they're riding, preventing them from doing so. /datum/component/riding/proc/on_rider_try_pull(mob/living/rider_pulling, atom/movable/target, force) @@ -125,6 +128,10 @@ ridden.balloon_alert(rider_pulling, "not while riding it!") return COMSIG_LIVING_CANCEL_PULL +///any behavior we want to happen after buckling the mob +/datum/component/riding/proc/post_vehicle_mob_buckle(atom/movable/ridden, atom/movable/rider) + return TRUE + /// Some ridable atoms may want to only show on top of the rider in certain directions, like wheelchairs /datum/component/riding/proc/handle_vehicle_layer(dir) var/atom/movable/AM = parent diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index a3b5fcf0411c6..d6c07d434237a 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -5,6 +5,8 @@ var/can_be_driven = TRUE /// If TRUE, this creature's abilities can be triggered by the rider while mounted var/can_use_abilities = FALSE + /// shall we require riders to go through the riding minigame if they arent in our friends list + var/require_minigame = FALSE /// list of blacklisted abilities that cant be shared var/list/blacklist_abilities = list() @@ -216,6 +218,14 @@ else if(ride_check_flags & CARRIER_NEEDS_ARM) // fireman human_parent.buckle_lying = 90 +/datum/component/riding/creature/post_vehicle_mob_buckle(mob/living/ridden, mob/living/rider) + if(!require_minigame || ridden.faction.Find(REF(rider))) + return + ridden.Shake(duration = 2 SECONDS) + ridden.balloon_alert(rider, "tries to shake you off!") + var/datum/riding_minigame/game = new(ridden, rider, FALSE) + game.commence_minigame() + /datum/component/riding/creature/human/RegisterWithParent() . = ..() RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_host_unarmed_melee)) @@ -431,6 +441,7 @@ /datum/component/riding/creature/goliath keytype = /obj/item/key/lasso vehicle_move_delay = 4 + rider_traits = list(TRAIT_NO_FLOATING_ANIM, TRAIT_TENTACLE_IMMUNE) /datum/component/riding/creature/goliath/deathmatch keytype = null @@ -521,3 +532,127 @@ /datum/component/riding/leaper/handle_unbuckle(mob/living/rider) . = ..() UnregisterSignal(rider, COMSIG_MOB_POINTED) + +/datum/component/riding/creature/raptor + require_minigame = TRUE + ride_check_flags = RIDER_NEEDS_ARM + +/datum/component/riding/creature/raptor/handle_specials() + . = ..() + if(!SSmapping.is_planetary()) + set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(7, 7), TEXT_SOUTH = list(2, 10), TEXT_EAST = list(12, 7), TEXT_WEST = list(10, 7))) + else + set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 7), TEXT_SOUTH = list(0, 10), TEXT_EAST = list(-3, 9), TEXT_WEST = list(3, 9))) + set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) + set_vehicle_dir_layer(NORTH, OBJ_LAYER) + set_vehicle_dir_layer(EAST, OBJ_LAYER) + set_vehicle_dir_layer(WEST, OBJ_LAYER) + +/datum/component/riding/creature/raptor/fast + vehicle_move_delay = 1.5 + +//a simple minigame players must win to mount and tame a mob +/datum/riding_minigame + ///our host mob + var/datum/weakref/host + ///our current rider + var/datum/weakref/mounter + ///the total amount of tries the rider gets + var/maximum_attempts = 6 + ///maximum number of failures before we fail + var/maximum_failures = 3 + ///cached directional icons of our host + var/list/cached_icons = list() + +/datum/riding_minigame/New(mob/living/ridden, mob/living/rider, use_mob_icons = TRUE) + . = ..() + RegisterSignal(rider, COMSIG_MOB_UNBUCKLED, PROC_REF(lose_game)) + host = WEAKREF(ridden) + mounter = WEAKREF(rider) + var/used_icon = use_mob_icons ? initial(ridden.icon) : 'icons/testing/turf_analysis.dmi' + var/used_icon_state = use_mob_icons ? initial(ridden.icon_state) : "red_arrow" + for(var/direction in GLOB.cardinals) + var/icon/directional_icon = getFlatIcon(image(icon = used_icon, icon_state = used_icon_state, dir = direction)) + var/string_icon = icon2base64(directional_icon) + var/opposite_direction = dir2text(REVERSE_DIR(direction)) + cached_icons[opposite_direction] = string_icon + +/datum/riding_minigame/proc/commence_minigame() + set waitfor = FALSE + START_PROCESSING(SSprocessing, src) + var/mob/living/rider = mounter?.resolve() + if(isnull(rider)) + lose_game() + return + ui_interact(rider) + +/datum/riding_minigame/process() + var/mob/living/living_host = host?.resolve() + if(isnull(living_host)) + return PROCESS_KILL + if(prob(60)) //we shake and move uncontrollably! + living_host.Shake(duration = 2 SECONDS) + var/list/new_direction = GLOB.cardinals.Copy() - living_host.dir + living_host.setDir(pick(new_direction)) + +/datum/riding_minigame/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "RideMinigame") + ui.open() + +/datum/riding_minigame/ui_static_data(mob/user) + var/list/data = list() + data["maximum_attempts"] = maximum_attempts + data["maximum_failures"] = maximum_failures + data["all_icons"] = list() + for(var/index in cached_icons) + data["all_icons"] += list(list( + "direction" = index, + "icon" = cached_icons[index], + )) + return data + +/datum/riding_minigame/ui_state(mob/user) + return GLOB.always_state + +/datum/riding_minigame/ui_act(action, params, datum/tgui/ui) + . = ..() + switch(action) + if("lose_game") + lose_game() + if("win_game") + win_game() + +/datum/riding_minigame/proc/win_game() + var/mob/living/living_host = host?.resolve() + var/mob/living/living_rider = mounter?.resolve() + if(isnull(living_host) || isnull(living_rider)) + qdel(src) + return + living_host.befriend(living_rider) + living_host.balloon_alert(living_rider, "calms down...") + qdel(src) + +/datum/riding_minigame/proc/lose_game() + var/mob/living/living_host = host?.resolve() + var/mob/living/living_rider = mounter?.resolve() + if(isnull(living_host) || isnull(living_rider)) + qdel(src) + return + if(LAZYFIND(living_host.buckled_mobs, living_rider)) + UnregisterSignal(living_rider, COMSIG_MOB_UNBUCKLED) //we're about to knock them down! + living_host.spin(spintime = 2 SECONDS, speed = 1) + living_rider.Knockdown(4 SECONDS) + living_host.unbuckle_mob(living_rider) + living_host.balloon_alert(living_rider, "knocks you down!") + qdel(src) + +/datum/riding_minigame/ui_close(mob/user) + lose_game() + +/datum/riding_minigame/Destroy() + STOP_PROCESSING(SSprocessing, src) + mounter = null + host = null + return ..() diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm index 7c55579c9992d..f872c6bfd6939 100644 --- a/code/datums/components/rotation.dm +++ b/code/datums/components/rotation.dm @@ -59,6 +59,7 @@ /datum/component/simple_rotation/proc/rotate_left(datum/source, mob/user) SIGNAL_HANDLER rotate(user, ROTATION_COUNTERCLOCKWISE) + return CLICK_ACTION_SUCCESS /datum/component/simple_rotation/proc/rotate(mob/user, degrees) if(QDELETED(user)) diff --git a/code/datums/components/shell.dm b/code/datums/components/shell.dm index 5b6361b9ee673..20fbeb739276e 100644 --- a/code/datums/components/shell.dm +++ b/code/datums/components/shell.dm @@ -173,7 +173,7 @@ if(istype(item, /obj/item/inducer)) var/obj/item/inducer/inducer = item - INVOKE_ASYNC(inducer, TYPE_PROC_REF(/obj/item, attack_atom), attached_circuit, attacker, list()) + INVOKE_ASYNC(inducer, TYPE_PROC_REF(/obj/item, attack_atom), attached_circuit || parent, attacker, list()) return COMPONENT_NO_AFTERATTACK if(attached_circuit) diff --git a/code/datums/components/shrink.dm b/code/datums/components/shrink.dm index d2615ea2f7770..0b32526e2b231 100644 --- a/code/datums/components/shrink.dm +++ b/code/datums/components/shrink.dm @@ -1,6 +1,8 @@ /datum/component/shrink var/olddens var/oldopac + /// Tracks the squashable component we apply when we make the small mob squashable + var/datum/component/squashable/newsquash dupe_mode = COMPONENT_DUPE_HIGHLANDER /datum/component/shrink/Initialize(shrink_time) @@ -25,17 +27,27 @@ if(ishuman(C)) var/mob/living/carbon/human/H = C H.physiology.damage_resistance -= 100//carbons take double damage while shrunk + if(!L.GetComponent(/datum/component/squashable)) + newsquash = L.AddComponent( \ + /datum/component/squashable, \ + squash_chance = 75, \ + squash_damage = 10, \ + squash_flags = SQUASHED_ALWAYS_IF_DEAD|SQUASHED_DONT_SQUASH_IN_CONTENTS, \ + ) else parent_atom.set_density(FALSE) // this is handled by the UNDENSE trait on mobs parent_atom.visible_message(span_warning("[parent_atom] shrinks down to a tiny size!"), span_userdanger("Everything grows bigger!")) - QDEL_IN(src, shrink_time) + if(shrink_time >= 0) // negative shrink time is permanent + QDEL_IN(src, shrink_time) /datum/component/shrink/proc/handle_shrunk_speech(mob/living/little_guy, list/speech_args) SIGNAL_HANDLER speech_args[SPEECH_SPANS] |= SPAN_SMALL_VOICE /datum/component/shrink/Destroy() + if(newsquash) + qdel(newsquash) var/atom/parent_atom = parent parent_atom.transform = parent_atom.transform.Scale(2,2) parent_atom.set_opacity(oldopac) diff --git a/code/datums/components/shuttle_cling.dm b/code/datums/components/shuttle_cling.dm index 6702b9d601dda..cef7c1f94dd6e 100644 --- a/code/datums/components/shuttle_cling.dm +++ b/code/datums/components/shuttle_cling.dm @@ -51,7 +51,7 @@ update_state(parent) //otherwise we'll get moved 1 tile before we can correct ourselves, which isnt super bad but just looks jank /datum/component/shuttle_cling/proc/initialize_loop() - hyperloop = SSmove_manager.move(moving = parent, direction = direction, delay = not_clinging_move_delay, subsystem = SShyperspace_drift, priority = MOVEMENT_ABOVE_SPACE_PRIORITY, flags = MOVEMENT_LOOP_NO_DIR_UPDATE|MOVEMENT_LOOP_OUTSIDE_CONTROL) + hyperloop = GLOB.move_manager.move(moving = parent, direction = direction, delay = not_clinging_move_delay, subsystem = SShyperspace_drift, priority = MOVEMENT_ABOVE_SPACE_PRIORITY, flags = MOVEMENT_LOOP_NO_DIR_UPDATE|MOVEMENT_LOOP_OUTSIDE_CONTROL) update_state() /datum/component/shuttle_cling/proc/clear_loop() diff --git a/code/datums/components/simple_bodycam.dm b/code/datums/components/simple_bodycam.dm index 81deb50649d18..9d653f38a7846 100644 --- a/code/datums/components/simple_bodycam.dm +++ b/code/datums/components/simple_bodycam.dm @@ -65,4 +65,5 @@ /datum/component/simple_bodycam/proc/camera_gone(datum/source) SIGNAL_HANDLER - qdel(src) + if (!QDELETED(src)) + qdel(src) diff --git a/code/datums/components/singularity.dm b/code/datums/components/singularity.dm index c1323d01e2fe6..14aaedff7172a 100644 --- a/code/datums/components/singularity.dm +++ b/code/datums/components/singularity.dm @@ -286,7 +286,7 @@ if (STAGE_ONE) steps = 1 if (STAGE_TWO) - steps = 3//Yes this is right + steps = 2 if (STAGE_THREE) steps = 3 if (STAGE_FOUR) @@ -360,8 +360,9 @@ target = potentially_closer //if we lost that target get a new one if(!target || QDELETED(target)) - target = find_new_target() - foreboding_nosebleed(target) + var/mob/living/new_target = find_new_target() + new_target?.ominous_nosebleed() + target = new_target return ..() ///Searches the living list for the closest target, and begins chasing them down. @@ -380,22 +381,6 @@ closest_target = target return closest_target -/// gives a little fluff warning that someone is being hunted. -/datum/component/singularity/bloodthirsty/proc/foreboding_nosebleed(mob/living/target) - if(!iscarbon(target)) - to_chat(target, span_warning("You feel a bit nauseous for just a moment.")) - return - var/mob/living/carbon/carbon_target = target - var/obj/item/bodypart/head = carbon_target.get_bodypart(BODY_ZONE_HEAD) - if(head) - if(HAS_TRAIT(carbon_target, TRAIT_NOBLOOD)) - to_chat(carbon_target, span_notice("You get a headache.")) - return - head.adjustBleedStacks(5) - carbon_target.visible_message(span_notice("[carbon_target] gets a nosebleed."), span_warning("You get a nosebleed.")) - return - to_chat(target, span_warning("You feel a bit nauseous for just a moment.")) - #undef CHANCE_TO_MOVE_TO_TARGET #undef CHANCE_TO_MOVE_TO_TARGET_BLOODTHIRSTY #undef CHANCE_TO_CHANGE_TARGET_BLOODTHIRSTY diff --git a/code/datums/components/sisyphus_awarder.dm b/code/datums/components/sisyphus_awarder.dm new file mode 100644 index 0000000000000..2a18a2889fc65 --- /dev/null +++ b/code/datums/components/sisyphus_awarder.dm @@ -0,0 +1,68 @@ +/** + * This component awards the sisyphus achievement if you cart a boulder from lavaland to centcom + * It's not really reusable but its a component just to encapsulate and destroy the behaviour neatly + */ +/datum/component/sisyphus_awarder + /// What poor sap is hauling this rock? + var/mob/living/sisyphus + /// Reference to a place where it all started. + var/turf/bottom_of_the_hill + +/datum/component/sisyphus_awarder/Initialize() + if (!istype(parent, /obj/item/boulder)) + return COMPONENT_INCOMPATIBLE + +/datum/component/sisyphus_awarder/RegisterWithParent() + RegisterSignal(parent, COMSIG_ITEM_POST_EQUIPPED, PROC_REF(on_picked_up)) + +/datum/component/sisyphus_awarder/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_ITEM_POST_EQUIPPED, COMSIG_MOVABLE_MOVED)) + if (!isnull(sisyphus)) + UnregisterSignal(sisyphus, list(COMSIG_ENTER_AREA, COMSIG_QDELETING)) + sisyphus = null + +/// Called when we're picked up, check if we're in the right place to start our epic journey +/datum/component/sisyphus_awarder/proc/on_picked_up(atom/source, mob/living/the_taker) + SIGNAL_HANDLER + if (!istype(get_area(the_taker), /area/lavaland)) + qdel(src) + return + UnregisterSignal(parent, COMSIG_ITEM_POST_EQUIPPED) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_dropped)) + RegisterSignal(the_taker, COMSIG_ENTER_AREA, PROC_REF(on_bearer_changed_area)) + RegisterSignal(the_taker, COMSIG_QDELETING, PROC_REF(on_dropped)) + sisyphus = the_taker + bottom_of_the_hill = get_turf(the_taker) + +/// If you ever drop this shit you fail the challenge +/datum/component/sisyphus_awarder/proc/on_dropped() + SIGNAL_HANDLER + qdel(src) // Your quest ends here + +/// If we changed area see if we arrived +/datum/component/sisyphus_awarder/proc/on_bearer_changed_area(mob/living/chosen_one, area/entered_area) + SIGNAL_HANDLER + var/atom/atom_parent = parent + if (atom_parent.loc != chosen_one) + qdel(src) // Hey! How did you do that? + return + if (entered_area.type != /area/centcom/central_command_areas/evacuation) + return // Don't istype because taking pods doesn't count + + chosen_one.client?.give_award(/datum/award/achievement/misc/sisyphus, chosen_one) + play_reward_scene() + + qdel(src) + +/// Sends the player back to the Lavaland and plays a funny sound +/datum/component/sisyphus_awarder/proc/play_reward_scene() + if(isnull(bottom_of_the_hill)) + return // This probably shouldn't happen, but... + + podspawn(list( + "path" = /obj/structure/closet/supplypod/centcompod/sisyphus, + "target" = get_turf(sisyphus), + "reverse_dropoff_coords" = list(bottom_of_the_hill.x, bottom_of_the_hill.y, bottom_of_the_hill.z), + )) + + SEND_SOUND(sisyphus, 'sound/ambience/music/sisyphus/sisyphus.ogg') diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm index a9bb9b4432bb0..7c85c1a5b2b70 100644 --- a/code/datums/components/spawner.dm +++ b/code/datums/components/spawner.dm @@ -19,7 +19,7 @@ var/spawn_distance_exclude COOLDOWN_DECLARE(spawn_delay) -/datum/component/spawner/Initialize(spawn_types = list(), spawn_time = 30 SECONDS, max_spawned = 5, max_spawn_per_attempt = 2 , faction = list(FACTION_MINING), spawn_text = null, spawn_distance = 1, spawn_distance_exclude = 0) +/datum/component/spawner/Initialize(spawn_types = list(), spawn_time = 30 SECONDS, max_spawned = 5, max_spawn_per_attempt = 1 , faction = list(FACTION_MINING), spawn_text = null, spawn_distance = 1, spawn_distance_exclude = 0) if (!islist(spawn_types)) CRASH("invalid spawn_types to spawn specified for spawner component!") src.spawn_time = spawn_time @@ -52,14 +52,16 @@ if(!COOLDOWN_FINISHED(src, spawn_delay)) return validate_references() - if(length(spawned_things) >= max_spawned) + var/spawned_total = length(spawned_things) + if(spawned_total >= max_spawned) return var/atom/spawner = parent COOLDOWN_START(src, spawn_delay, spawn_time) var/chosen_mob_type = pick(spawn_types) var/adjusted_spawn_count = 1 - if (max_spawn_per_attempt > 1) - adjusted_spawn_count = rand(1, max_spawn_per_attempt) + var/max_spawn_this_attempt = min(max_spawn_per_attempt, max_spawned - spawned_total) + if (max_spawn_this_attempt > 1) + adjusted_spawn_count = rand(1, max_spawn_this_attempt) for(var/i in 1 to adjusted_spawn_count) var/atom/created var/turf/picked_spot diff --git a/code/datums/components/style/style_meter.dm b/code/datums/components/style/style_meter.dm index 72688f41c5274..c06fc35aca383 100644 --- a/code/datums/components/style/style_meter.dm +++ b/code/datums/components/style/style_meter.dm @@ -27,7 +27,7 @@ . = ..() . += span_notice("You feel like a multitool could be used on this.") -/obj/item/style_meter/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/style_meter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!istype(interacting_with, /obj/item/clothing/glasses)) return NONE @@ -38,7 +38,7 @@ RegisterSignal(interacting_with, COMSIG_ITEM_EQUIPPED, PROC_REF(check_wearing)) RegisterSignal(interacting_with, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) RegisterSignal(interacting_with, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) - RegisterSignal(interacting_with, COMSIG_CLICK_ALT, PROC_REF(on_altclick)) + RegisterSignal(interacting_with, COMSIG_CLICK_ALT, PROC_REF(on_click_alt)) RegisterSignal(interacting_with, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(redirect_multitool)) balloon_alert(user, "style meter attached") playsound(src, 'sound/machines/click.ogg', 30, TRUE) @@ -90,14 +90,15 @@ /// Signal proc to remove from glasses -/obj/item/style_meter/proc/on_altclick(datum/source, mob/user) +/obj/item/style_meter/proc/on_click_alt(datum/source, mob/user) SIGNAL_HANDLER - if(istype(loc, /obj/item/clothing/glasses)) - clean_up() - forceMove(get_turf(src)) + if(!istype(loc, /obj/item/clothing/glasses)) + return CLICK_ACTION_BLOCKING - return COMPONENT_CANCEL_CLICK_ALT + clean_up() + forceMove(get_turf(src)) + return CLICK_ACTION_SUCCESS /obj/item/style_meter/multitool_act(mob/living/user, obj/item/tool) multitooled = !multitooled diff --git a/code/datums/components/surgery_initiator.dm b/code/datums/components/surgery_initiator.dm index a1a354a7c2150..41c5f1ef87ad7 100644 --- a/code/datums/components/surgery_initiator.dm +++ b/code/datums/components/surgery_initiator.dm @@ -119,11 +119,11 @@ patient.surgeries -= the_surgery REMOVE_TRAIT(patient, TRAIT_ALLOWED_HONORBOUND_ATTACK, type) user.visible_message( - span_notice("[user] removes [parent] from [patient]'s [parse_zone(selected_zone)]."), - span_notice("You remove [parent] from [patient]'s [parse_zone(selected_zone)]."), + span_notice("[user] removes [parent] from [patient]'s [patient.parse_zone_with_bodypart(selected_zone)]."), + span_notice("You remove [parent] from [patient]'s [patient.parse_zone_with_bodypart(selected_zone)]."), ) - patient.balloon_alert(user, "stopped work on [parse_zone(selected_zone)]") + patient.balloon_alert(user, "stopped work on [patient.parse_zone_with_bodypart(selected_zone)]") qdel(the_surgery) return @@ -135,8 +135,11 @@ required_tool_type = TOOL_SCREWDRIVER if(iscyborg(user)) - close_tool = locate(/obj/item/cautery) in user.held_items - if(!close_tool) + var/has_cautery = FALSE + for(var/obj/item/borg/cyborg_omnitool/medical/omnitool in user.held_items) + if(omnitool.tool_behaviour == TOOL_CAUTERY) + has_cautery = TRUE + if(!has_cautery) patient.balloon_alert(user, "need a cautery in an inactive slot to stop the surgery!") return else if(!close_tool || close_tool.tool_behaviour != required_tool_type) @@ -150,11 +153,11 @@ REMOVE_TRAIT(patient, TRAIT_ALLOWED_HONORBOUND_ATTACK, ELEMENT_TRAIT(type)) user.visible_message( - span_notice("[user] closes [patient]'s [parse_zone(selected_zone)] with [close_tool] and removes [parent]."), - span_notice("You close [patient]'s [parse_zone(selected_zone)] with [close_tool] and remove [parent]."), + span_notice("[user] closes [patient]'s [patient.parse_zone_with_bodypart(selected_zone)] with [close_tool] and removes [parent]."), + span_notice("You close [patient]'s [patient.parse_zone_with_bodypart(selected_zone)] with [close_tool] and remove [parent]."), ) - patient.balloon_alert(user, "closed up [parse_zone(selected_zone)]") + patient.balloon_alert(user, "closed up [patient.parse_zone_with_bodypart(selected_zone)]") qdel(the_surgery) @@ -309,7 +312,7 @@ return if (surgery_needs_exposure(surgery, target)) - target.balloon_alert(user, "expose [target.p_their()] [parse_zone(selected_zone)]!") + target.balloon_alert(user, "expose [target.p_their()] [target.parse_zone_with_bodypart(selected_zone)]!") return ui_close() @@ -317,11 +320,11 @@ var/datum/surgery/procedure = new surgery.type(target, selected_zone, affecting_limb) ADD_TRAIT(target, TRAIT_ALLOWED_HONORBOUND_ATTACK, type) - target.balloon_alert(user, "starting \"[lowertext(procedure.name)]\"") + target.balloon_alert(user, "starting \"[LOWER_TEXT(procedure.name)]\"") user.visible_message( - span_notice("[user] drapes [parent] over [target]'s [parse_zone(selected_zone)] to prepare for surgery."), - span_notice("You drape [parent] over [target]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name]."), + span_notice("[user] drapes [parent] over [target]'s [target.parse_zone_with_bodypart(selected_zone)] to prepare for surgery."), + span_notice("You drape [parent] over [target]'s [target.parse_zone_with_bodypart(selected_zone)] to prepare for \an [procedure.name]."), ) log_combat(user, target, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])") diff --git a/code/datums/components/toggle_suit.dm b/code/datums/components/toggle_suit.dm index 596bf3b3252d2..aee7522745e77 100644 --- a/code/datums/components/toggle_suit.dm +++ b/code/datums/components/toggle_suit.dm @@ -15,16 +15,18 @@ return COMPONENT_INCOMPATIBLE var/atom/atom_parent = parent + atom_parent.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1 src.toggle_noun = toggle_noun src.base_icon_state = atom_parent.base_icon_state || atom_parent.icon_state /datum/component/toggle_icon/RegisterWithParent() - RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_alt_click)) + RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_click_alt)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_adding_context)) /datum/component/toggle_icon/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_CLICK_ALT, COMSIG_ATOM_EXAMINE)) + UnregisterSignal(parent, list(COMSIG_CLICK_ALT, COMSIG_ATOM_EXAMINE, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM)) /* * Signal proc for COMSIG_CLICK_ALT. @@ -34,7 +36,7 @@ * source - the atom being clicked on * user - the mob doing the click */ -/datum/component/toggle_icon/proc/on_alt_click(atom/source, mob/user) +/datum/component/toggle_icon/proc/on_click_alt(atom/source, mob/user) SIGNAL_HANDLER if(!isliving(user)) @@ -47,13 +49,14 @@ if(living_user.incapacitated()) source.balloon_alert(user, "you're incapacitated!") - return + return CLICK_ACTION_BLOCKING if(living_user.usable_hands <= 0) source.balloon_alert(user, "you don't have hands!") - return + return CLICK_ACTION_BLOCKING do_icon_toggle(source, living_user) + return CLICK_ACTION_SUCCESS /* * Signal proc for COMSIG_ATOM_EXAMINE. @@ -68,6 +71,21 @@ examine_list += span_notice("Alt-click on [source] to toggle the [toggle_noun].") +/* + * Signal proc for COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM. + * Adds usage context for toggling the parent open or closed. + * + * source - the atom context is requested from (parent) + * context - the list of usage contexts set + * held_item - the item held by the requesting mob + * user - the mob requesting context + */ +/datum/component/toggle_icon/proc/on_adding_context(atom/source, list/context, obj/item/held_item, mob/user) + SIGNAL_HANDLER + + context[SCREENTIP_CONTEXT_ALT_LMB] = "Toggle [toggle_noun]" + return CONTEXTUAL_SCREENTIP_SET + /* * Actually do the toggle of the icon. * Swaps the icon from [base_icon_state] to [base_icon_state]_t. diff --git a/code/datums/components/transforming.dm b/code/datums/components/transforming.dm index e51c784657b57..5276f45dc0a75 100644 --- a/code/datums/components/transforming.dm +++ b/code/datums/components/transforming.dm @@ -212,7 +212,7 @@ source.attack_verb_simple = attack_verb_simple_on source.hitsound = hitsound_on - source.w_class = w_class_on + source.update_weight_class(w_class_on) source.icon_state = "[source.icon_state]_on" if(inhand_icon_change && source.inhand_icon_state) source.inhand_icon_state = "[source.inhand_icon_state]_on" @@ -241,7 +241,7 @@ source.attack_verb_simple = attack_verb_simple_off source.hitsound = initial(source.hitsound) - source.w_class = initial(source.w_class) + source.update_weight_class(initial(source.w_class)) source.icon_state = initial(source.icon_state) source.inhand_icon_state = initial(source.inhand_icon_state) if(ismob(source.loc)) diff --git a/code/datums/components/udder.dm b/code/datums/components/udder.dm index cd87ff44c1782..a659efbc50411 100644 --- a/code/datums/components/udder.dm +++ b/code/datums/components/udder.dm @@ -204,3 +204,16 @@ reagents.add_reagent(/datum/reagent/medicine/salglu_solution, rand(2,5)) if(on_generate_callback) on_generate_callback.Invoke(reagents.total_volume, reagents.maximum_volume) + +/obj/item/udder/raptor + name = "bird udder" + +/obj/item/udder/raptor/generate() + if(!prob(production_probability)) + return FALSE + var/happiness_percentage = udder_mob.ai_controller?.blackboard[BB_BASIC_HAPPINESS] + if(prob(happiness_percentage)) + reagents.add_reagent(/datum/reagent/consumable/cream, 5, added_purity = 1) + var/minimum_bound = happiness_percentage > 0.6 ? 10 : 5 + var/upper_bound = minimum_bound + 5 + reagents.add_reagent(reagent_produced_typepath, rand(minimum_bound, upper_bound), added_purity = 1) diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 5007d8caeb92d..d62414a862b24 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -266,7 +266,7 @@ /datum/component/uplink/ui_assets(mob/user) return list( - get_asset_datum(/datum/asset/json/uplink) + get_asset_datum(/datum/asset/json/uplink), ) /datum/component/uplink/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) @@ -378,8 +378,8 @@ /datum/component/uplink/proc/new_ringtone(datum/source, mob/living/user, new_ring_text) SIGNAL_HANDLER - if(trim(lowertext(new_ring_text)) != trim(lowertext(unlock_code))) - if(trim(lowertext(new_ring_text)) == trim(lowertext(failsafe_code))) + if(trim(LOWER_TEXT(new_ring_text)) != trim(LOWER_TEXT(unlock_code))) + if(trim(LOWER_TEXT(new_ring_text)) == trim(LOWER_TEXT(failsafe_code))) failsafe(user) return COMPONENT_STOP_RINGTONE_CHANGE return @@ -415,8 +415,8 @@ if(channel != RADIO_CHANNEL_UPLINK) return - if(!findtext(lowertext(message), lowertext(unlock_code))) - if(failsafe_code && findtext(lowertext(message), lowertext(failsafe_code))) + if(!findtext(LOWER_TEXT(message), LOWER_TEXT(unlock_code))) + if(failsafe_code && findtext(LOWER_TEXT(message), LOWER_TEXT(failsafe_code))) failsafe(user) // no point returning cannot radio, youre probably ded return locked = FALSE diff --git a/code/datums/datum.dm b/code/datums/datum.dm index e98f0941d6461..6288244667e85 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -313,12 +313,22 @@ filter_data[name] = copied_parameters update_filters() +///A version of add_filter that takes a list of filters to add rather than being individual, to limit calls to update_filters(). +/datum/proc/add_filters(list/list/filters) + LAZYINITLIST(filter_data) + for(var/list/individual_filter as anything in filters) + var/list/params = individual_filter["params"] + var/list/copied_parameters = params.Copy() + copied_parameters["priority"] = individual_filter["priority"] + filter_data[individual_filter["name"]] = copied_parameters + update_filters() + /// Reapplies all the filters. /datum/proc/update_filters() - ASSERT(isatom(src) || istype(src, /image)) + ASSERT(isatom(src) || isimage(src)) var/atom/atom_cast = src // filters only work with images or atoms. atom_cast.filters = null - filter_data = sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE) + sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE) for(var/filter_raw in filter_data) var/list/data = filter_data[filter_raw] var/list/arguments = data.Copy() @@ -377,7 +387,7 @@ /// Returns the filter associated with the passed key /datum/proc/get_filter(name) - ASSERT(isatom(src) || istype(src, /image)) + ASSERT(isatom(src) || isimage(src)) if(filter_data && filter_data[name]) var/atom/atom_cast = src // filters only work with images or atoms. return atom_cast.filters[filter_data.Find(name)] @@ -400,7 +410,7 @@ update_filters() /datum/proc/clear_filters() - ASSERT(isatom(src) || istype(src, /image)) + ASSERT(isatom(src) || isimage(src)) var/atom/atom_cast = src // filters only work with images or atoms. filter_data = null atom_cast.filters = null @@ -417,4 +427,3 @@ return harddel_deets_dumped = TRUE return "Image icon: [icon] - icon_state: [icon_state] [loc ? "loc: [loc] ([loc.x],[loc.y],[loc.z])" : ""]" - diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index 234622563427e..93edea10b41c6 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -1,6 +1,6 @@ /* - Advance Disease is a system for Virologist to Engineer their own disease with symptoms that have effects and properties + Advance Disease is a system for medical to Engineer their own disease with symptoms that have effects and properties which add onto the overall disease. If you need help with creating new symptoms or expanding the advance disease, ask for Giacom on #coderbus. @@ -17,7 +17,7 @@ */ /datum/disease/advance - name = "Unknown" // We will always let our Virologist name our disease. + name = "Unknown" // We will always let our creator name our disease. desc = "An engineered disease which can contain a multitude of symptoms." form = "Advanced Disease" // Will let med-scanners know that this disease was engineered. agent = "advance microbes" @@ -160,7 +160,8 @@ for(var/s in symptoms) var/datum/symptom/symptom_datum = s - symptom_datum.Activate(src) + if(!symptom_datum.neutered) + symptom_datum.Activate(src) // Tell symptoms stage changed diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm index 4c2715668ba48..7368e99acc814 100644 --- a/code/datums/diseases/advance/symptoms/cough.dm +++ b/code/datums/diseases/advance/symptoms/cough.dm @@ -76,6 +76,6 @@ if(power >= 2 && prob(30)) to_chat(affected_mob, span_userdanger("[pick("You have a coughing fit!", "You can't stop coughing!")]")) affected_mob.Immobilize(20) - addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 6) - addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 12) - addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 18) + addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 0.6 SECONDS) + addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 1.2 SECONDS) + addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 1.8 SECONDS) diff --git a/code/datums/diseases/advance/symptoms/fire.dm b/code/datums/diseases/advance/symptoms/fire.dm index f428abdb016f2..0708841fca06b 100644 --- a/code/datums/diseases/advance/symptoms/fire.dm +++ b/code/datums/diseases/advance/symptoms/fire.dm @@ -71,7 +71,10 @@ if(prob(33.33)) living_mob.show_message(span_hear("You hear a crackling noise."), type = MSG_AUDIBLE) else - to_chat(living_mob, span_warning("[pick("You feel hot.", "You smell smoke.")]")) + if(HAS_TRAIT(living_mob, TRAIT_ANOSMIA)) //Anosmia quirk holder can't smell anything. + to_chat(living_mob, span_warning("You feel hot.")) + else + to_chat(living_mob, span_warning("[pick("You feel hot.", "You smell smoke.")]")) /* Alkali perspiration diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index 8cdeceb586166..ae77ade0fb7d2 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -381,14 +381,14 @@ if(M.getBruteLoss() + M.getFireLoss() >= 70 && !active_coma) to_chat(M, span_warning("You feel yourself slip into a regenerative coma...")) active_coma = TRUE - addtimer(CALLBACK(src, PROC_REF(coma), M), 60) + addtimer(CALLBACK(src, PROC_REF(coma), M), 6 SECONDS) /datum/symptom/heal/coma/proc/coma(mob/living/M) if(QDELETED(M) || M.stat == DEAD) return M.fakedeath("regenerative_coma", !deathgasp) - addtimer(CALLBACK(src, PROC_REF(uncoma), M), 300) + addtimer(CALLBACK(src, PROC_REF(uncoma), M), 30 SECONDS) /datum/symptom/heal/coma/proc/uncoma(mob/living/M) if(QDELETED(M) || !active_coma) diff --git a/code/datums/diseases/advance/symptoms/itching.dm b/code/datums/diseases/advance/symptoms/itching.dm index cb468a132cc21..7615edb1b82d7 100644 --- a/code/datums/diseases/advance/symptoms/itching.dm +++ b/code/datums/diseases/advance/symptoms/itching.dm @@ -27,6 +27,7 @@ COOLDOWN_DECLARE(itching_cooldown) ///if FALSE, there is a percentage chance that the mob will emote scratching while itching_cooldown is on cooldown. If TRUE, won't emote again until after the off cooldown scratch occurs. var/off_cooldown_scratched = FALSE + /datum/symptom/itching/Start(datum/disease/advance/active_disease) . = ..() if(!.) @@ -41,17 +42,12 @@ . = ..() if(!.) return - var/mob/living/carbon/affected_mob = active_disease.affected_mob - var/obj/item/bodypart/bodypart = affected_mob.get_bodypart(affected_mob.get_random_valid_zone(even_weights = TRUE)) - if(bodypart && IS_ORGANIC_LIMB(bodypart) && !(bodypart.bodypart_flags & BODYPART_PSEUDOPART)) //robotic limbs will mean less scratching overall (why are golems able to damage themselves with self-scratching, but not androids? the world may never know) - var/can_scratch = scratch && !affected_mob.incapacitated() - if(can_scratch) - bodypart.receive_damage(0.5) - //below handles emotes, limiting the emote of emotes passed to chat - if(COOLDOWN_FINISHED(src, itching_cooldown) || !COOLDOWN_FINISHED(src, itching_cooldown) && prob(60) && !off_cooldown_scratched) - affected_mob.visible_message("[can_scratch ? span_warning("[affected_mob] scratches [affected_mob.p_their()] [bodypart.plaintext_zone].") : ""]", span_warning("Your [bodypart.plaintext_zone] itches. [can_scratch ? " You scratch it." : ""]")) - COOLDOWN_START(src, itching_cooldown, 5 SECONDS) - if(!off_cooldown_scratched && !COOLDOWN_FINISHED(src, itching_cooldown)) - off_cooldown_scratched = TRUE - else - off_cooldown_scratched = FALSE + + var/announce_scratch = COOLDOWN_FINISHED(src, itching_cooldown) || (!COOLDOWN_FINISHED(src, itching_cooldown) && prob(60) && !off_cooldown_scratched) + if (!active_disease.affected_mob.itch(silent = !announce_scratch, can_scratch = scratch) || !announce_scratch) + return + COOLDOWN_START(src, itching_cooldown, 5 SECONDS) + if(!off_cooldown_scratched && !COOLDOWN_FINISHED(src, itching_cooldown)) + off_cooldown_scratched = TRUE + else + off_cooldown_scratched = FALSE diff --git a/code/datums/diseases/advance/symptoms/narcolepsy.dm b/code/datums/diseases/advance/symptoms/narcolepsy.dm index ac7eae25d4a7b..cbf6462f2c484 100644 --- a/code/datums/diseases/advance/symptoms/narcolepsy.dm +++ b/code/datums/diseases/advance/symptoms/narcolepsy.dm @@ -35,6 +35,10 @@ symptom_delay_max = 45 /datum/symptom/narcolepsy/Activate(datum/disease/advance/A) + . = ..() + if(!.) + return + var/mob/living/M = A.affected_mob switch(A.stage) if(1) diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm index 255c2a3f3a7f5..9654365c49d34 100644 --- a/code/datums/diseases/advance/symptoms/voice_change.dm +++ b/code/datums/diseases/advance/symptoms/voice_change.dm @@ -54,7 +54,7 @@ else if(ishuman(M)) var/mob/living/carbon/human/H = M - H.SetSpecialVoice(H.dna.species.random_name(H.gender)) + H.SetSpecialVoice(H.generate_random_mob_name()) if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure. current_language = pick(subtypesof(/datum/language) - /datum/language/common) H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE) diff --git a/code/datums/diseases/tuberculosis.dm b/code/datums/diseases/tuberculosis.dm index de87cab6f3f67..2a77195e311c4 100644 --- a/code/datums/diseases/tuberculosis.dm +++ b/code/datums/diseases/tuberculosis.dm @@ -18,11 +18,12 @@ if(!.) return + if(SPT_PROB(stage * 2, seconds_per_tick)) + affected_mob.emote("cough") + to_chat(affected_mob, span_danger("Your chest hurts.")) + switch(stage) if(2) - if(SPT_PROB(1, seconds_per_tick)) - affected_mob.emote("cough") - to_chat(affected_mob, span_danger("Your chest hurts.")) if(SPT_PROB(1, seconds_per_tick)) to_chat(affected_mob, span_danger("Your stomach violently rumbles!")) if(SPT_PROB(2.5, seconds_per_tick)) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 9126e40373684..1f978e5bf0abb 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -179,13 +179,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_GENDER_BLOCK] = construct_block(G_PLURAL, GENDERS) if(ishuman(holder)) var/mob/living/carbon/human/H = holder - if(!GLOB.hairstyles_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/hair,GLOB.hairstyles_list, GLOB.hairstyles_male_list, GLOB.hairstyles_female_list) - L[DNA_HAIRSTYLE_BLOCK] = construct_block(GLOB.hairstyles_list.Find(H.hairstyle), GLOB.hairstyles_list.len) + if(length(SSaccessories.hairstyles_list) == 0 || length(SSaccessories.facial_hairstyles_list) == 0) + CRASH("SSaccessories lists are empty, this is bad!") + + L[DNA_HAIRSTYLE_BLOCK] = construct_block(SSaccessories.hairstyles_list.Find(H.hairstyle), length(SSaccessories.hairstyles_list)) L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color, include_crunch = FALSE) - if(!GLOB.facial_hairstyles_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hairstyles_list, GLOB.facial_hairstyles_male_list, GLOB.facial_hairstyles_female_list) - L[DNA_FACIAL_HAIRSTYLE_BLOCK] = construct_block(GLOB.facial_hairstyles_list.Find(H.facial_hairstyle), GLOB.facial_hairstyles_list.len) + L[DNA_FACIAL_HAIRSTYLE_BLOCK] = construct_block(SSaccessories.facial_hairstyles_list.Find(H.facial_hairstyle), length(SSaccessories.facial_hairstyles_list)) L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color, include_crunch = FALSE) L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len) L[DNA_EYE_COLOR_LEFT_BLOCK] = sanitize_hexcolor(H.eye_color_left, include_crunch = FALSE) @@ -203,31 +202,33 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(features["ethcolor"]) L[DNA_ETHEREAL_COLOR_BLOCK] = sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE) if(features["body_markings"]) - L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len) + L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(SSaccessories.body_markings_list.Find(features["body_markings"]), length(SSaccessories.body_markings_list)) if(features["tail_cat"]) - L[DNA_TAIL_BLOCK] = construct_block(GLOB.tails_list_human.Find(features["tail_cat"]), GLOB.tails_list_human.len) + L[DNA_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_human.Find(features["tail_cat"]), length(SSaccessories.tails_list_human)) if(features["tail_lizard"]) - L[DNA_LIZARD_TAIL_BLOCK] = construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len) + L[DNA_LIZARD_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_lizard.Find(features["tail_lizard"]), length(SSaccessories.tails_list_lizard)) + if(features["tail_monkey"]) + L[DNA_MONKEY_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_monkey.Find(features["tail_monkey"]), length(SSaccessories.tails_list_monkey)) if(features["snout"]) - L[DNA_SNOUT_BLOCK] = construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len) + L[DNA_SNOUT_BLOCK] = construct_block(SSaccessories.snouts_list.Find(features["snout"]), length(SSaccessories.snouts_list)) if(features["horns"]) - L[DNA_HORNS_BLOCK] = construct_block(GLOB.horns_list.Find(features["horns"]), GLOB.horns_list.len) + L[DNA_HORNS_BLOCK] = construct_block(SSaccessories.horns_list.Find(features["horns"]), length(SSaccessories.horns_list)) if(features["frills"]) - L[DNA_FRILLS_BLOCK] = construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len) + L[DNA_FRILLS_BLOCK] = construct_block(SSaccessories.frills_list.Find(features["frills"]), length(SSaccessories.frills_list)) if(features["spines"]) - L[DNA_SPINES_BLOCK] = construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len) + L[DNA_SPINES_BLOCK] = construct_block(SSaccessories.spines_list.Find(features["spines"]), length(SSaccessories.spines_list)) if(features["ears"]) - L[DNA_EARS_BLOCK] = construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len) + L[DNA_EARS_BLOCK] = construct_block(SSaccessories.ears_list.Find(features["ears"]), length(SSaccessories.ears_list)) if(features["moth_wings"] != "Burnt Off") - L[DNA_MOTH_WINGS_BLOCK] = construct_block(GLOB.moth_wings_list.Find(features["moth_wings"]), GLOB.moth_wings_list.len) + L[DNA_MOTH_WINGS_BLOCK] = construct_block(SSaccessories.moth_wings_list.Find(features["moth_wings"]), length(SSaccessories.moth_wings_list)) if(features["moth_antennae"] != "Burnt Off") - L[DNA_MOTH_ANTENNAE_BLOCK] = construct_block(GLOB.moth_antennae_list.Find(features["moth_antennae"]), GLOB.moth_antennae_list.len) + L[DNA_MOTH_ANTENNAE_BLOCK] = construct_block(SSaccessories.moth_antennae_list.Find(features["moth_antennae"]), length(SSaccessories.moth_antennae_list)) if(features["moth_markings"]) - L[DNA_MOTH_MARKINGS_BLOCK] = construct_block(GLOB.moth_markings_list.Find(features["moth_markings"]), GLOB.moth_markings_list.len) + L[DNA_MOTH_MARKINGS_BLOCK] = construct_block(SSaccessories.moth_markings_list.Find(features["moth_markings"]), length(SSaccessories.moth_markings_list)) if(features["caps"]) - L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len) + L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(SSaccessories.caps_list.Find(features["caps"]), length(SSaccessories.caps_list)) if(features["pod_hair"]) - L[DNA_POD_HAIR_BLOCK] = construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len) + L[DNA_POD_HAIR_BLOCK] = construct_block(SSaccessories.pod_hair_list.Find(features["pod_hair"]), length(SSaccessories.pod_hair_list)) for(var/blocknum in 1 to DNA_FEATURE_BLOCKS) . += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters) @@ -324,9 +325,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) else set_uni_identity_block(blocknumber, construct_block(G_PLURAL, GENDERS)) if(DNA_FACIAL_HAIRSTYLE_BLOCK) - set_uni_identity_block(blocknumber, construct_block(GLOB.facial_hairstyles_list.Find(H.facial_hairstyle), GLOB.facial_hairstyles_list.len)) + set_uni_identity_block(blocknumber, construct_block(SSaccessories.facial_hairstyles_list.Find(H.facial_hairstyle), length(SSaccessories.facial_hairstyles_list))) if(DNA_HAIRSTYLE_BLOCK) - set_uni_identity_block(blocknumber, construct_block(GLOB.hairstyles_list.Find(H.hairstyle), GLOB.hairstyles_list.len)) + set_uni_identity_block(blocknumber, construct_block(SSaccessories.hairstyles_list.Find(H.hairstyle), length(SSaccessories.hairstyles_list))) /datum/dna/proc/update_uf_block(blocknumber) if(!blocknumber) @@ -339,31 +340,33 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(DNA_ETHEREAL_COLOR_BLOCK) set_uni_feature_block(blocknumber, sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE)) if(DNA_LIZARD_MARKINGS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.body_markings_list.Find(features["body_markings"]), length(SSaccessories.body_markings_list))) if(DNA_TAIL_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_human.Find(features["tail_cat"]), GLOB.tails_list_human.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_human.Find(features["tail_cat"]), length(SSaccessories.tails_list_human))) if(DNA_LIZARD_TAIL_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_lizard.Find(features["tail_lizard"]), length(SSaccessories.tails_list_lizard))) + if(DNA_MONKEY_TAIL_BLOCK) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_monkey.Find(features["tail_monkey"]), length(SSaccessories.tails_list_monkey))) if(DNA_SNOUT_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.snouts_list.Find(features["snout"]), length(SSaccessories.snouts_list))) if(DNA_HORNS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.horns_list.Find(features["horns"]), GLOB.horns_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.horns_list.Find(features["horns"]), length(SSaccessories.horns_list))) if(DNA_FRILLS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.frills_list.Find(features["frills"]), length(SSaccessories.frills_list))) if(DNA_SPINES_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.spines_list.Find(features["spines"]), length(SSaccessories.spines_list))) if(DNA_EARS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.ears_list.Find(features["ears"]), length(SSaccessories.ears_list))) if(DNA_MOTH_WINGS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.moth_wings_list.Find(features["moth_wings"]), GLOB.moth_wings_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_wings_list.Find(features["moth_wings"]), length(SSaccessories.moth_wings_list))) if(DNA_MOTH_ANTENNAE_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.moth_antennae_list.Find(features["moth_antennae"]), GLOB.moth_antennae_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_antennae_list.Find(features["moth_antennae"]), length(SSaccessories.moth_antennae_list))) if(DNA_MOTH_MARKINGS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.moth_markings_list.Find(features["moth_markings"]), GLOB.moth_markings_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_markings_list.Find(features["moth_markings"]), length(SSaccessories.moth_markings_list))) if(DNA_MUSHROOM_CAPS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.caps_list.Find(features["caps"]), length(SSaccessories.caps_list))) if(DNA_POD_HAIR_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len)) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.pod_hair_list.Find(features["pod_hair"]), length(SSaccessories.pod_hair_list))) //Please use add_mutation or activate_mutation instead /datum/dna/proc/force_give(datum/mutation/human/human_mutation) @@ -448,14 +451,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(create_mutation_blocks) //I hate this generate_dna_blocks() if(randomize_features) - var/static/list/all_species_protoypes - if(isnull(all_species_protoypes)) - all_species_protoypes = list() - for(var/species_path in subtypesof(/datum/species)) - all_species_protoypes += new species_path() - - for(var/datum/species/random_species as anything in all_species_protoypes) - features |= random_species.randomize_features() + for(var/species_type in GLOB.species_prototypes) + features |= GLOB.species_prototypes[species_type].randomize_features() features["mcolor"] = "#[random_color()]" @@ -620,12 +617,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(HAS_TRAIT(src, TRAIT_SHAVED)) set_facial_hairstyle("Shaved", update = FALSE) else - var/style = GLOB.facial_hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), GLOB.facial_hairstyles_list.len)] + var/style = SSaccessories.facial_hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), length(SSaccessories.facial_hairstyles_list))] set_facial_hairstyle(style, update = FALSE) if(HAS_TRAIT(src, TRAIT_BALD)) set_hairstyle("Bald", update = FALSE) else - var/style = GLOB.hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_BLOCK), GLOB.hairstyles_list.len)] + var/style = SSaccessories.hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_BLOCK), length(SSaccessories.hairstyles_list))] set_hairstyle(style, update = FALSE) var/features = dna.unique_features if(dna.features["mcolor"]) @@ -633,35 +630,37 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(dna.features["ethcolor"]) dna.features["ethcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_ETHEREAL_COLOR_BLOCK)) if(dna.features["body_markings"]) - dna.features["body_markings"] = GLOB.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), GLOB.body_markings_list.len)] + dna.features["body_markings"] = SSaccessories.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), length(SSaccessories.body_markings_list))] if(dna.features["snout"]) - dna.features["snout"] = GLOB.snouts_list[deconstruct_block(get_uni_feature_block(features, DNA_SNOUT_BLOCK), GLOB.snouts_list.len)] + dna.features["snout"] = SSaccessories.snouts_list[deconstruct_block(get_uni_feature_block(features, DNA_SNOUT_BLOCK), length(SSaccessories.snouts_list))] if(dna.features["horns"]) - dna.features["horns"] = GLOB.horns_list[deconstruct_block(get_uni_feature_block(features, DNA_HORNS_BLOCK), GLOB.horns_list.len)] + dna.features["horns"] = SSaccessories.horns_list[deconstruct_block(get_uni_feature_block(features, DNA_HORNS_BLOCK), length(SSaccessories.horns_list))] if(dna.features["frills"]) - dna.features["frills"] = GLOB.frills_list[deconstruct_block(get_uni_feature_block(features, DNA_FRILLS_BLOCK), GLOB.frills_list.len)] + dna.features["frills"] = SSaccessories.frills_list[deconstruct_block(get_uni_feature_block(features, DNA_FRILLS_BLOCK), length(SSaccessories.frills_list))] if(dna.features["spines"]) - dna.features["spines"] = GLOB.spines_list[deconstruct_block(get_uni_feature_block(features, DNA_SPINES_BLOCK), GLOB.spines_list.len)] + dna.features["spines"] = SSaccessories.spines_list[deconstruct_block(get_uni_feature_block(features, DNA_SPINES_BLOCK), length(SSaccessories.spines_list))] if(dna.features["tail_cat"]) - dna.features["tail_cat"] = GLOB.tails_list_human[deconstruct_block(get_uni_feature_block(features, DNA_TAIL_BLOCK), GLOB.tails_list_human.len)] + dna.features["tail_cat"] = SSaccessories.tails_list_human[deconstruct_block(get_uni_feature_block(features, DNA_TAIL_BLOCK), length(SSaccessories.tails_list_human))] if(dna.features["tail_lizard"]) - dna.features["tail_lizard"] = GLOB.tails_list_lizard[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_TAIL_BLOCK), GLOB.tails_list_lizard.len)] + dna.features["tail_lizard"] = SSaccessories.tails_list_lizard[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_TAIL_BLOCK), length(SSaccessories.tails_list_lizard))] + if(dna.features["tail_monkey"]) + dna.features["tail_monkey"] = SSaccessories.tails_list_monkey[deconstruct_block(get_uni_feature_block(features, DNA_MONKEY_TAIL_BLOCK), length(SSaccessories.tails_list_monkey))] if(dna.features["ears"]) - dna.features["ears"] = GLOB.ears_list[deconstruct_block(get_uni_feature_block(features, DNA_EARS_BLOCK), GLOB.ears_list.len)] + dna.features["ears"] = SSaccessories.ears_list[deconstruct_block(get_uni_feature_block(features, DNA_EARS_BLOCK), length(SSaccessories.ears_list))] if(dna.features["moth_wings"]) - var/genetic_value = GLOB.moth_wings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_WINGS_BLOCK), GLOB.moth_wings_list.len)] + var/genetic_value = SSaccessories.moth_wings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_WINGS_BLOCK), length(SSaccessories.moth_wings_list))] dna.features["original_moth_wings"] = genetic_value dna.features["moth_wings"] = genetic_value if(dna.features["moth_antennae"]) - var/genetic_value = GLOB.moth_antennae_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_ANTENNAE_BLOCK), GLOB.moth_antennae_list.len)] + var/genetic_value = SSaccessories.moth_antennae_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_ANTENNAE_BLOCK), length(SSaccessories.moth_antennae_list))] dna.features["original_moth_antennae"] = genetic_value dna.features["moth_antennae"] = genetic_value if(dna.features["moth_markings"]) - dna.features["moth_markings"] = GLOB.moth_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_MARKINGS_BLOCK), GLOB.moth_markings_list.len)] + dna.features["moth_markings"] = SSaccessories.moth_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_MARKINGS_BLOCK), length(SSaccessories.moth_markings_list))] if(dna.features["caps"]) - dna.features["caps"] = GLOB.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), GLOB.caps_list.len)] + dna.features["caps"] = SSaccessories.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), length(SSaccessories.caps_list))] if(dna.features["pod_hair"]) - dna.features["pod_hair"] = GLOB.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), GLOB.pod_hair_list.len)] + dna.features["pod_hair"] = SSaccessories.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), length(SSaccessories.pod_hair_list))] for(var/obj/item/organ/external/external_organ in organs) external_organ.mutate_feature(features, src) @@ -857,7 +856,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.remove_all_mutations() dna.stability = 100 if(prob(max(70-instability,0))) - switch(rand(0,10)) //not complete and utter death + switch(rand(0,11)) //not complete and utter death if(0) monkeyize() if(1) @@ -894,6 +893,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(9 to 10) ForceContractDisease(new/datum/disease/gastrolosis()) to_chat(src, span_notice("Oh, I actually feel quite alright!")) + if(11) + to_chat(src, span_notice("Your DNA mutates into the ultimate biological form!")) + crabize() else switch(rand(0,6)) if(0) @@ -922,10 +924,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) spawn_gibs() set_species(/datum/species/skeleton) if(prob(90)) - addtimer(CALLBACK(src, PROC_REF(death)), 30) + addtimer(CALLBACK(src, PROC_REF(death)), 3 SECONDS) if(5) to_chat(src, span_phobia("LOOK UP!")) - addtimer(CALLBACK(src, PROC_REF(something_horrible_mindmelt)), 30) + addtimer(CALLBACK(src, PROC_REF(something_horrible_mindmelt)), 3 SECONDS) if(6) slow_psykerize() @@ -937,4 +939,4 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) eyes.Remove(src) qdel(eyes) visible_message(span_notice("[src] looks up and their eyes melt away!"), span_userdanger("I understand now.")) - addtimer(CALLBACK(src, PROC_REF(adjustOrganLoss), ORGAN_SLOT_BRAIN, 200), 20) + addtimer(CALLBACK(src, PROC_REF(adjustOrganLoss), ORGAN_SLOT_BRAIN, 200), 2 SECONDS) diff --git a/code/datums/eigenstate.dm b/code/datums/eigenstate.dm index 3bba746320997..b25fa657eb6e4 100644 --- a/code/datums/eigenstate.dm +++ b/code/datums/eigenstate.dm @@ -119,8 +119,7 @@ GLOBAL_DATUM_INIT(eigenstate_manager, /datum/eigenstate_manager, new) spark_time = world.time //Calls a special proc for the atom if needed (closets use bust_open()) SEND_SIGNAL(eigen_target, COMSIG_EIGENSTATE_ACTIVATE) - if(!subtle) - return COMPONENT_CLOSET_INSERT_INTERRUPT + return COMPONENT_CLOSET_INSERT_INTERRUPT ///Prevents tool use on the item /datum/eigenstate_manager/proc/tool_interact(atom/source, mob/user, obj/item/item) diff --git a/code/datums/elements/ai_control_examine.dm b/code/datums/elements/ai_control_examine.dm index b470ac44b49a7..279fc80dc8192 100644 --- a/code/datums/elements/ai_control_examine.dm +++ b/code/datums/elements/ai_control_examine.dm @@ -46,7 +46,7 @@ if(noticable_organ_examines[possibly_noticable.slot]) make_organ_noticable(possibly_noticable.slot, possibly_noticable) -/datum/element/ai_control_examine/proc/make_organ_noticable(organ_slot, obj/item/organ/noticable_organ) +/datum/element/ai_control_examine/proc/make_organ_noticable(organ_slot, obj/item/organ/noticable_organ, mob/living/carbon/human/human_pawn) var/examine_text = noticable_organ_examines[organ_slot] var/body_zone = organ_slot != ORGAN_SLOT_BRAIN ? noticable_organ.zone : null noticable_organ.AddElement(/datum/element/noticable_organ/ai_control, examine_text, body_zone) diff --git a/code/datums/elements/attack_zone_randomiser.dm b/code/datums/elements/attack_zone_randomiser.dm new file mode 100644 index 0000000000000..35275e11a9bb2 --- /dev/null +++ b/code/datums/elements/attack_zone_randomiser.dm @@ -0,0 +1,33 @@ +/// Pick a random attack zone before you attack something +/datum/element/attack_zone_randomiser + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// List of attack zones you can select, should be a subset of GLOB.all_body_zones + var/list/valid_attack_zones + +/datum/element/attack_zone_randomiser/Attach(datum/target, list/valid_attack_zones = GLOB.all_body_zones) + . = ..() + if (!isliving(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignals(target, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_UNARMED_ATTACK), PROC_REF(randomise)) + src.valid_attack_zones = valid_attack_zones + +/datum/element/attack_zone_randomiser/Detach(datum/source) + UnregisterSignal(source, list (COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_UNARMED_ATTACK)) + return ..() + +/// If we're attacking a carbon, pick a random defence zone +/datum/element/attack_zone_randomiser/proc/randomise(mob/living/source, atom/target) + SIGNAL_HANDLER + if (!iscarbon(target)) + return + var/mob/living/living_target = target + var/list/blacklist_zones = GLOB.all_body_zones - valid_attack_zones + var/new_zone = living_target.get_random_valid_zone(blacklisted_parts = blacklist_zones, bypass_warning = TRUE) + if (isnull(new_zone)) + new_zone = BODY_ZONE_CHEST + var/atom/movable/screen/zone_sel/zone_selector = source.hud_used?.zone_select + if (isnull(zone_selector)) + source.zone_selected = new_zone + else + zone_selector.set_selected_zone(new_zone, source, should_log = FALSE) diff --git a/code/datums/elements/backblast.dm b/code/datums/elements/backblast.dm index 169f961b3d373..f5e73977159cd 100644 --- a/code/datums/elements/backblast.dm +++ b/code/datums/elements/backblast.dm @@ -1,74 +1,46 @@ /** - * When attached to a gun and the gun is successfully fired, this element creates a "backblast" of fire and pain, like you'd find in a rocket launcher or recoilless rifle + * When attached to a gun and the gun is successfully fired, this element creates a "backblast", like you'd find in a rocket launcher or recoilless rifle * - * The backblast is simulated by a number of fire plumes, or invisible incendiary rounds that will torch anything they come across for a short distance, as well as knocking - * back nearby items. + * The backblast is simulated by a directional explosion 180 degrees from the direction of the fired projectile. */ /datum/element/backblast element_flags = ELEMENT_BESPOKE argument_hash_start_idx = 2 - /// How many "pellets" of backblast we're shooting backwards, spread between the angle defined in angle_spread - var/plumes - /// Assuming we don't just have 1 plume, this is the total angle we'll cover with the plumes, split down the middle directly behind the angle we fired at - var/angle_spread - /// How far each plume of fire will fly, assuming it doesn't hit a mob - var/range - -/datum/element/backblast/Attach(datum/target, plumes = 4, angle_spread = 48, range = 6) + /// Devasatation range of the explosion + var/dev_range + /// HGeavy damage range of the explosion + var/heavy_range + /// Light damage range of the explosion + var/light_range + /// Flame range of the explosion + var/flame_range + /// What angle do we want the backblast to cover + var/blast_angle + +/datum/element/backblast/Attach(datum/target, dev_range = 0, heavy_range = 0, light_range = 6, flame_range = 6, blast_angle = 60) . = ..() - if(!isgun(target) || plumes < 1 || angle_spread < 1 || range < 1) + if(!isgun(target) || dev_range < 0 || heavy_range < 0 || light_range < 0 || flame_range < 0 || blast_angle < 1) return ELEMENT_INCOMPATIBLE - src.plumes = plumes - src.angle_spread = angle_spread - src.range = range + src.dev_range = dev_range + src.heavy_range = heavy_range + src.light_range = light_range + src.flame_range = flame_range + src.blast_angle = blast_angle - if(plumes == 1) - RegisterSignal(target, COMSIG_GUN_FIRED, PROC_REF(gun_fired_simple)) - else - RegisterSignal(target, COMSIG_GUN_FIRED, PROC_REF(gun_fired)) + RegisterSignal(target, COMSIG_GUN_FIRED, PROC_REF(pew)) /datum/element/backblast/Detach(datum/source) if(source) UnregisterSignal(source, COMSIG_GUN_FIRED) return ..() -/// For firing multiple plumes behind us, we evenly spread out our projectiles based on the [angle_spread][/datum/element/backblast/var/angle_spread] and [number of plumes][/datum/element/backblast/var/plumes] -/datum/element/backblast/proc/gun_fired(obj/item/gun/weapon, mob/living/user, atom/target, params, zone_override) - SIGNAL_HANDLER - - if(!weapon.chambered || HAS_TRAIT(user, TRAIT_PACIFISM)) - return - - var/backwards_angle = get_angle(target, user) - var/starting_angle = SIMPLIFY_DEGREES(backwards_angle-(angle_spread * 0.5)) - var/iter_offset = angle_spread / plumes // how much we increment the angle for each plume - - for(var/i in 1 to plumes) - var/this_angle = SIMPLIFY_DEGREES(starting_angle + ((i - 1) * iter_offset)) - var/turf/target_turf = get_turf_in_angle(this_angle, get_turf(user), 10) - INVOKE_ASYNC(src, PROC_REF(pew), target_turf, weapon, user) - -/// If we're only firing one plume directly behind us, we don't need to bother with the loop or angles or anything -/datum/element/backblast/proc/gun_fired_simple(obj/item/gun/weapon, mob/living/user, atom/target, params, zone_override) - SIGNAL_HANDLER - - if(!weapon.chambered || HAS_TRAIT(user, TRAIT_PACIFISM)) +/// For firing an actual backblast pellet +/datum/element/backblast/proc/pew(obj/item/gun/weapon, mob/living/user, atom/target) + if(HAS_TRAIT(user, TRAIT_PACIFISM)) return - var/backwards_angle = get_angle(target, user) - var/turf/target_turf = get_turf_in_angle(backwards_angle, get_turf(user), 10) - INVOKE_ASYNC(src, PROC_REF(pew), target_turf, weapon, user) - -/// For firing an actual backblast pellet -/datum/element/backblast/proc/pew(turf/target_turf, obj/item/gun/weapon, mob/living/user) - //Shooting Code: - var/obj/projectile/bullet/incendiary/fire/backblast/P = new (get_turf(user)) - P.original = target_turf - P.range = range - P.fired_from = weapon - P.firer = user // don't hit ourself that would be really annoying - P.impacted = list(user = TRUE) // don't hit the target we hit already with the flak - P.preparePixelProjectile(target_turf, weapon) - P.fire() + var/turf/origin = get_turf(weapon) + var/backblast_angle = get_angle(target, origin) + explosion(weapon, devastation_range = dev_range, heavy_impact_range = heavy_range, light_impact_range = light_range, flame_range = flame_range, adminlog = FALSE, protect_epicenter = TRUE, explosion_direction = backblast_angle, explosion_arc = blast_angle) diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index 757fd8b3519b9..92b303c9be2a0 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -83,9 +83,14 @@ return TRUE /datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target) + set waitfor = FALSE SEND_SIGNAL(eater, COMSIG_MOB_ATE) if(drinking) playsound(eater.loc,'sound/items/drink.ogg', rand(10,50), TRUE) else playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE) - qdel(target) + var/atom/final_target = target + if(isstack(target)) //if stack, only consume 1 + var/obj/item/stack/food_stack = target + final_target = food_stack.split_stack(eater, 1) + qdel(final_target) diff --git a/code/datums/elements/corrupted_organ.dm b/code/datums/elements/corrupted_organ.dm new file mode 100644 index 0000000000000..e7f8524b8517a --- /dev/null +++ b/code/datums/elements/corrupted_organ.dm @@ -0,0 +1,66 @@ +/// Component applying shared behaviour by cursed organs granted when sacrificed by a heretic +/// Mostly just does something spooky when it is removed +/datum/element/corrupted_organ + +/datum/element/corrupted_organ/Attach(datum/target) + . = ..() + if (!isinternalorgan(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_ORGAN_SURGICALLY_REMOVED, PROC_REF(on_removed)) + + var/atom/atom_parent = target + atom_parent.color = COLOR_VOID_PURPLE + + atom_parent.add_filter(name = "ray", priority = 1, params = list( + type = "rays", + size = 12, + color = COLOR_VOID_PURPLE, + density = 12 + )) + var/ray_filter = atom_parent.get_filter("ray") + animate(ray_filter, offset = 100, time = 2 MINUTES, loop = -1, flags = ANIMATION_PARALLEL) // Absurdly long animate so nobody notices it hitching when it loops + animate(offset = 0, time = 2 MINUTES) // I sure hope duration of animate doesnt have any performance effect + +/datum/element/corrupted_organ/Detach(datum/source) + UnregisterSignal(source, list(COMSIG_ORGAN_SURGICALLY_REMOVED)) + return ..() + +/// When we're taken out of someone, do something spooky +/datum/element/corrupted_organ/proc/on_removed(atom/organ, mob/living/carbon/loser) + SIGNAL_HANDLER + if (loser.has_reagent(/datum/reagent/water/holywater) || loser.can_block_magic(MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY) || prob(20)) + return + if (prob(75)) + organ.AddComponent(\ + /datum/component/haunted_item,\ + haunt_color = "#00000000", \ + aggro_radius = 4, \ + spawn_message = span_revenwarning("[organ] hovers ominously into the air, pulsating with unnatural vigour!"), \ + despawn_message = span_revenwarning("[organ] falls motionless to the ground."), \ + ) + return + var/turf/origin_turf = get_turf(organ) + playsound(organ, 'sound/magic/forcewall.ogg', vol = 100) + new /obj/effect/temp_visual/curse_blast(origin_turf) + organ.visible_message(span_revenwarning("[organ] explodes in a burst of dark energy!")) + for(var/mob/living/target in range(1, origin_turf)) + var/armor = target.run_armor_check(attack_flag = BOMB) + target.apply_damage(30, damagetype = BURN, blocked = armor, spread_damage = TRUE) + qdel(organ) + +/obj/effect/temp_visual/curse_blast + icon = 'icons/effects/64x64.dmi' + pixel_x = -16 + pixel_y = -16 + icon_state = "curse" + duration = 0.3 SECONDS + +/obj/effect/temp_visual/curse_blast/Initialize(mapload) + . = ..() + animate(src, transform = matrix() * 0.2, time = 0, flags = ANIMATION_PARALLEL) + animate(transform = matrix() * 2, time = duration, easing = EASE_IN) + + animate(src, alpha = 255, time = 0, flags = ANIMATION_PARALLEL) + animate(alpha = 255, time = 0.2 SECONDS) + animate(alpha = 0, time = 0.1 SECONDS) diff --git a/code/datums/elements/decals/blood.dm b/code/datums/elements/decals/blood.dm index 7984939cddc87..857b9e2b678ea 100644 --- a/code/datums/elements/decals/blood.dm +++ b/code/datums/elements/decals/blood.dm @@ -33,10 +33,7 @@ pic = blood_splatter return TRUE -/datum/element/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override) +/datum/element/decal/blood/proc/get_examine_name(atom/source, mob/user, list/override) SIGNAL_HANDLER - var/atom/A = source - override[EXAMINE_POSITION_ARTICLE] = A.gender == PLURAL? "some" : "a" - override[EXAMINE_POSITION_BEFORE] = " blood-stained " - return COMPONENT_EXNAME_CHANGED + override[EXAMINE_POSITION_BEFORE] = "blood-stained" diff --git a/code/datums/elements/frozen.dm b/code/datums/elements/frozen.dm index 434968dd4d5e0..d112ef31b5f91 100644 --- a/code/datums/elements/frozen.dm +++ b/code/datums/elements/frozen.dm @@ -63,7 +63,7 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0 else log_combat(throwingdatum.thrower, target, "launched", addition = "shattering it due to being frozen.") obj_target.visible_message(span_danger("[obj_target] shatters into a million pieces!")) - obj_target.obj_flags |= NO_DECONSTRUCTION // disable item spawning + obj_target.obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION // disable item spawning obj_target.deconstruct(FALSE) // call pre-deletion specialized code -- internals release gas etc /// signal handler for COMSIG_MOVABLE_MOVED that unfreezes our target if it moves onto an open turf thats hotter than diff --git a/code/datums/elements/hostile_machine.dm b/code/datums/elements/hostile_machine.dm index 0a5f19287bb24..cb846d830e812 100644 --- a/code/datums/elements/hostile_machine.dm +++ b/code/datums/elements/hostile_machine.dm @@ -8,6 +8,10 @@ if (!isatom(target)) return ELEMENT_INCOMPATIBLE +#ifdef UNIT_TESTS + if(!GLOB.target_interested_atoms[target.type]) + stack_trace("Tried to make a hostile machine without updating ai targeting to include it, they must be synced") +#endif GLOB.hostile_machines += target /datum/element/hostile_machine/Detach(datum/source) diff --git a/code/datums/elements/living_limb_initialiser.dm b/code/datums/elements/living_limb_initialiser.dm new file mode 100644 index 0000000000000..943b39dcf3786 --- /dev/null +++ b/code/datums/elements/living_limb_initialiser.dm @@ -0,0 +1,19 @@ +/// Spawns a living limb mob inside a limb upon attachment if it doesn't have one +/datum/element/living_limb_initialiser + +/datum/element/living_limb_initialiser/Attach(atom/target) + . = ..() + if(!isbodypart(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignal(target, COMSIG_BODYPART_CHANGED_OWNER, PROC_REF(try_animate_limb)) + +/datum/element/living_limb_initialiser/Detach(atom/target) + UnregisterSignal(target, COMSIG_BODYPART_CHANGED_OWNER) + return ..() + +/// Create a living limb mob inside the limb if it doesn't already have one +/datum/element/living_limb_initialiser/proc/try_animate_limb(obj/item/bodypart/part) + SIGNAL_HANDLER + if (locate(/mob/living/basic/living_limb_flesh) in part) + return + new /mob/living/basic/living_limb_flesh(part, part) diff --git a/code/datums/elements/lube_walking.dm b/code/datums/elements/lube_walking.dm new file mode 100644 index 0000000000000..8ab6b2b760285 --- /dev/null +++ b/code/datums/elements/lube_walking.dm @@ -0,0 +1,61 @@ +/** + * # lube_walking + * + * Makes a mob cause a turf to get wet as they walk, requires lying down. + * Has configurable args for wet flags, time, and resting requirements. + */ +/datum/element/lube_walking + element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY + argument_hash_start_idx = 2 + ///The wet flags that we make each tile we are affecting slippery with. + var/wet_flags + ///The minimum amount of time any tile we wet will be wet for. + var/min_time_wet_for + ///Boolean on whether the mob has to be 'resting' for the element to properly affect tiles. + ///Used to exclude simple animals that you don't expect to lie down. + var/require_resting + +/datum/element/lube_walking/Attach(atom/movable/target, wet_flags = TURF_WET_LUBE, min_time_wet_for = 2 SECONDS, require_resting = FALSE) + . = ..() + if(!ismovable(target)) + return ELEMENT_INCOMPATIBLE + src.wet_flags = wet_flags + src.min_time_wet_for = min_time_wet_for + src.require_resting = require_resting + + if(require_resting) + if(!isliving(target)) + stack_trace("lube_walking Element was added onto [target] with require_resting set on, which only works on living mobs.") + return ELEMENT_INCOMPATIBLE + var/mob/living/living_target = target + RegisterSignal(living_target, COMSIG_LIVING_RESTING, PROC_REF(on_resting_changed)) + if(living_target.resting) //theyre resting as the element was added, so let them start lubricating. + on_resting_changed(living_target, new_resting = TRUE) + else + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(lubricate)) + +/datum/element/lube_walking/Detach(mob/living/carbon/target) + . = ..() + UnregisterSignal(target, list(COMSIG_LIVING_RESTING, COMSIG_MOVABLE_MOVED)) + if(istype(target)) + target.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl) + +///Called when a living mob changes their resting state with require_resting on, giving them their movement speed and ability. +/datum/element/lube_walking/proc/on_resting_changed(mob/snail, new_resting, silent, instant) + SIGNAL_HANDLER + + if(new_resting && lubricate(snail)) + snail.add_movespeed_modifier(/datum/movespeed_modifier/snail_crawl) + RegisterSignal(snail, COMSIG_MOVABLE_MOVED, PROC_REF(lubricate)) + else + snail.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl) + UnregisterSignal(snail, COMSIG_MOVABLE_MOVED) + +/datum/element/lube_walking/proc/lubricate(atom/movable/snail) + SIGNAL_HANDLER + + var/turf/open/turf_standing_on = get_turf(snail) + if(!istype(turf_standing_on)) + return FALSE + turf_standing_on.MakeSlippery(wet_flags, min_wet_time = min_time_wet_for) + return TRUE diff --git a/code/datums/elements/noticable_organ.dm b/code/datums/elements/noticable_organ.dm index 1a6a895e53543..a6247d18bb53b 100644 --- a/code/datums/elements/noticable_organ.dm +++ b/code/datums/elements/noticable_organ.dm @@ -6,15 +6,13 @@ /datum/element/noticable_organ element_flags = ELEMENT_BESPOKE argument_hash_start_idx = 2 - /// whether we wrap the examine text in a notice span. - var/add_span = TRUE - /// "[they]|[their] [desc here]", shows on examining someone with an infused organ. - /// Uses a possessive pronoun (His/Her/Their) if a body zone is given, or a singular pronoun (He/She/They) otherwise. + + ///Shows on examining someone with an infused organ. var/infused_desc - /// Which body zone has to be exposed. If none is set, this is always noticable, and the description pronoun becomes singular instead of possesive. + /// Which body zone has to be exposed. If none is set, this is always noticable. var/body_zone -/datum/element/noticable_organ/Attach(datum/target, infused_desc, body_zone) +/datum/element/noticable_organ/Attach(obj/item/organ/target, infused_desc, body_zone) . = ..() if(!isorgan(target)) @@ -23,8 +21,10 @@ src.infused_desc = infused_desc src.body_zone = body_zone - RegisterSignal(target, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_implanted)) + RegisterSignal(target, COMSIG_ORGAN_IMPLANTED, PROC_REF(enable_description)) RegisterSignal(target, COMSIG_ORGAN_REMOVED, PROC_REF(on_removed)) + if(target.owner) + enable_description(target, target.owner) /datum/element/noticable_organ/Detach(obj/item/organ/target) UnregisterSignal(target, list(COMSIG_ORGAN_IMPLANTED, COMSIG_ORGAN_REMOVED)) @@ -38,7 +38,7 @@ return FALSE return TRUE -/datum/element/noticable_organ/proc/on_implanted(obj/item/organ/target, mob/living/carbon/receiver) +/datum/element/noticable_organ/proc/enable_description(obj/item/organ/target, mob/living/carbon/receiver) SIGNAL_HANDLER RegisterSignal(receiver, COMSIG_ATOM_EXAMINE, PROC_REF(on_receiver_examine)) @@ -53,16 +53,17 @@ if(!should_show_text(examined)) return - var/examine_text = replacetext(replacetext("[body_zone ? examined.p_Their() : examined.p_They()] [infused_desc]", "%PRONOUN_ES", examined.p_es()), "%PRONOUN_S", examined.p_s()) - if(add_span) - examine_text = span_notice(examine_text) + + var/examine_text = REPLACE_PRONOUNS(infused_desc, examined) + + examine_list += examine_text /** * Subtype of noticable organs for AI control, that will make a few more ai status checks before forking over the examine. */ /datum/element/noticable_organ/ai_control - add_span = FALSE + /datum/element/noticable_organ/ai_control/should_show_text(mob/living/carbon/examined) . = ..() diff --git a/code/datums/elements/poster_tearer.dm b/code/datums/elements/poster_tearer.dm new file mode 100644 index 0000000000000..7a784a48615cd --- /dev/null +++ b/code/datums/elements/poster_tearer.dm @@ -0,0 +1,45 @@ +/// Allows mobs with this element attached to just simply tear down any poster they desire to. +/datum/element/poster_tearer + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// The amount of time it takes to tear down a poster. + var/tear_time + /// Interaction key to use whilst tearing down a poster. + var/interaction_key + +/datum/element/poster_tearer/Attach(datum/target, tear_time = 2 SECONDS, interaction_key = null) + . = ..() + if (!isliving(target)) + return ELEMENT_INCOMPATIBLE + + src.tear_time = tear_time + src.interaction_key = interaction_key + + RegisterSignals(target, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_UNARMED_ATTACK), PROC_REF(on_attacked_poster)) + +/datum/element/poster_tearer/Detach(datum/source) + . = ..() + UnregisterSignal(source, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_UNARMED_ATTACK)) + +/// Try to tear up a poster on the wall +/datum/element/poster_tearer/proc/on_attacked_poster(mob/living/user, atom/target, proximity_flag) + SIGNAL_HANDLER + if(!istype(target, /obj/structure/sign/poster)) + return NONE // don't care we move on + + if(DOING_INTERACTION_WITH_TARGET(user, target) || (!isnull(interaction_key) && DOING_INTERACTION(user, interaction_key))) + user.balloon_alert(target, "busy!") + return COMPONENT_CANCEL_ATTACK_CHAIN + + INVOKE_ASYNC(src, PROC_REF(tear_it_down), user, target) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/// Actually work on tearing down that poster +/datum/element/poster_tearer/proc/tear_it_down(mob/living/user, obj/structure/sign/poster/target) + if(!target.check_tearability(user)) // this proc will handle user feedback + return + + target.balloon_alert(user, "tearing down the poster...") + if(!do_after(user, tear_time, target, interaction_key = interaction_key)) // just in case the user actually enjoys art + return + target.tear_poster(user) diff --git a/code/datums/elements/proficient_miner.dm b/code/datums/elements/proficient_miner.dm new file mode 100644 index 0000000000000..9a382afce280e --- /dev/null +++ b/code/datums/elements/proficient_miner.dm @@ -0,0 +1,19 @@ +///element given to mobs that can mine when moving +/datum/element/proficient_miner + +/datum/element/proficient_miner/Attach(datum/target) + . = ..() + if(!ismovable(target)) + return + RegisterSignal(target, COMSIG_MOVABLE_BUMP, PROC_REF(on_bump)) + +/datum/element/proficient_miner/proc/on_bump(mob/living/source, atom/target) + SIGNAL_HANDLER + if(!ismineralturf(target)) + return + var/turf/closed/mineral/mineral_wall = target + mineral_wall.gets_drilled(source) + +/datum/element/proficient_miner/Detach(datum/source, ...) + UnregisterSignal(source, COMSIG_MOVABLE_BUMP) + return ..() diff --git a/code/datums/elements/relay_attackers.dm b/code/datums/elements/relay_attackers.dm index a6c319d7bc9b8..5f5bf7ed5893f 100644 --- a/code/datums/elements/relay_attackers.dm +++ b/code/datums/elements/relay_attackers.dm @@ -7,14 +7,15 @@ /datum/element/relay_attackers/Attach(datum/target) . = ..() - // Boy this sure is a lot of ways to tell us that someone tried to attack us - RegisterSignal(target, COMSIG_ATOM_AFTER_ATTACKEDBY, PROC_REF(after_attackby)) - RegisterSignals(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW, COMSIG_MOB_ATTACK_ALIEN), PROC_REF(on_attack_generic)) - RegisterSignals(target, list(COMSIG_ATOM_ATTACK_BASIC_MOB, COMSIG_ATOM_ATTACK_ANIMAL), PROC_REF(on_attack_npc)) - RegisterSignal(target, COMSIG_PROJECTILE_PREHIT, PROC_REF(on_bullet_act)) - RegisterSignal(target, COMSIG_ATOM_PREHITBY, PROC_REF(on_hitby)) - RegisterSignal(target, COMSIG_ATOM_HULK_ATTACK, PROC_REF(on_attack_hulk)) - RegisterSignal(target, COMSIG_ATOM_ATTACK_MECH, PROC_REF(on_attack_mech)) + if (!HAS_TRAIT(target, TRAIT_RELAYING_ATTACKER)) // Little bit gross but we want to just apply this shit from a bunch of places + // Boy this sure is a lot of ways to tell us that someone tried to attack us + RegisterSignal(target, COMSIG_ATOM_AFTER_ATTACKEDBY, PROC_REF(after_attackby)) + RegisterSignals(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW, COMSIG_MOB_ATTACK_ALIEN), PROC_REF(on_attack_generic)) + RegisterSignals(target, list(COMSIG_ATOM_ATTACK_BASIC_MOB, COMSIG_ATOM_ATTACK_ANIMAL), PROC_REF(on_attack_npc)) + RegisterSignal(target, COMSIG_PROJECTILE_PREHIT, PROC_REF(on_bullet_act)) + RegisterSignal(target, COMSIG_ATOM_PREHITBY, PROC_REF(on_hitby)) + RegisterSignal(target, COMSIG_ATOM_HULK_ATTACK, PROC_REF(on_attack_hulk)) + RegisterSignal(target, COMSIG_ATOM_ATTACK_MECH, PROC_REF(on_attack_mech)) ADD_TRAIT(target, TRAIT_RELAYING_ATTACKER, REF(src)) /datum/element/relay_attackers/Detach(datum/source, ...) diff --git a/code/datums/elements/ridable.dm b/code/datums/elements/ridable.dm index cbb6d7931f9fd..e68653b3d4a07 100644 --- a/code/datums/elements/ridable.dm +++ b/code/datums/elements/ridable.dm @@ -197,3 +197,15 @@ to_chat(user, span_notice("You gently let go of [rider].")) return return rider + +/obj/item/riding_offhand/interact_with_atom(atom/movable/interacting_with, mob/living/user, list/modifiers) + if(!istype(interacting_with) || !interacting_with.can_buckle) + return NONE + if(rider == user) // Piggyback user + return ITEM_INTERACT_BLOCKING + + // Handles de-fireman carrying a mob and buckling them onto something (tables, etc) + var/mob/living/former_rider = rider + user.unbuckle_mob(former_rider) + former_rider.forceMove(get_turf(interacting_with)) + return interacting_with.mouse_buckle_handling(former_rider, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING diff --git a/code/datums/elements/rust.dm b/code/datums/elements/rust.dm index 135f45b7c2f3d..060de19494fc0 100644 --- a/code/datums/elements/rust.dm +++ b/code/datums/elements/rust.dm @@ -17,6 +17,7 @@ ADD_TRAIT(target, TRAIT_RUSTY, ELEMENT_TRAIT(type)) RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(apply_rust_overlay)) RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(handle_examine)) + RegisterSignal (target, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_interaction)) RegisterSignals(target, list(COMSIG_ATOM_SECONDARY_TOOL_ACT(TOOL_WELDER), COMSIG_ATOM_SECONDARY_TOOL_ACT(TOOL_RUSTSCRAPER)), PROC_REF(secondary_tool_act)) // Unfortunately registering with parent sometimes doesn't cause an overlay update target.update_appearance() @@ -25,6 +26,7 @@ . = ..() UnregisterSignal(source, COMSIG_ATOM_UPDATE_OVERLAYS) UnregisterSignal(source, COMSIG_ATOM_EXAMINE) + UnregisterSignal(source, COMSIG_ATOM_ITEM_INTERACTION) UnregisterSignal(source, list(COMSIG_ATOM_SECONDARY_TOOL_ACT(TOOL_WELDER), COMSIG_ATOM_SECONDARY_TOOL_ACT(TOOL_RUSTSCRAPER))) REMOVE_TRAIT(source, TRAIT_RUSTY, ELEMENT_TRAIT(type)) source.update_appearance() @@ -72,3 +74,44 @@ user.balloon_alert(user, "scraped off rust") Detach(source) return + +/// Prevents placing floor tiles on rusted turf +/datum/element/rust/proc/on_interaction(datum/source, mob/user, obj/item/tool, modifiers) + SIGNAL_HANDLER + if(istype(tool, /obj/item/stack/tile) || istype(tool, /obj/item/stack/rods)) + user.balloon_alert(user, "floor too rusted!") + return ITEM_INTERACT_BLOCKING + +/// For rust applied by heretics +/datum/element/rust/heretic + +/datum/element/rust/heretic/Attach(atom/target, rust_icon, rust_icon_state) + . = ..() + if(. == ELEMENT_INCOMPATIBLE) + return . + RegisterSignal(target, COMSIG_ATOM_ENTERED, PROC_REF(on_entered)) + RegisterSignal(target, COMSIG_ATOM_EXITED, PROC_REF(on_exited)) + +/datum/element/rust/heretic/Detach(atom/source) + . = ..() + UnregisterSignal(source, COMSIG_ATOM_ENTERED) + UnregisterSignal(source, COMSIG_ATOM_EXITED) + for(var/obj/effect/glowing_rune/rune_to_remove in source) + qdel(rune_to_remove) + +/datum/element/rust/heretic/proc/on_entered(turf/source, atom/movable/entered, ...) + SIGNAL_HANDLER + + if(!isliving(entered)) + return + var/mob/living/victim = entered + if(IS_HERETIC(victim)) + return + victim.apply_status_effect(/datum/status_effect/rust_corruption) + +/datum/element/rust/heretic/proc/on_exited(turf/source, atom/movable/gone) + SIGNAL_HANDLER + if(!isliving(gone)) + return + var/mob/living/leaver = gone + leaver.remove_status_effect(/datum/status_effect/rust_corruption) diff --git a/code/datums/elements/screentips/README.md b/code/datums/elements/screentips/README.md index 92a66ca9dd47c..30d0e7a90ccb4 100644 --- a/code/datums/elements/screentips/README.md +++ b/code/datums/elements/screentips/README.md @@ -35,18 +35,17 @@ Example: ```dm /obj/structure/table/Initialize(mapload) - if (!(obj_flags & NO_DECONSTRUCTION)) - var/static/list/tool_behaviors = list( - TOOL_SCREWDRIVER = list( - SCREENTIP_CONTEXT_RMB = "Disassemble", - ), - - TOOL_WRENCH = list( - SCREENTIP_CONTEXT_RMB = "Deconstruct", - ), - ) - - AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) + var/static/list/tool_behaviors = list( + TOOL_SCREWDRIVER = list( + SCREENTIP_CONTEXT_RMB = "Disassemble", + ), + + TOOL_WRENCH = list( + SCREENTIP_CONTEXT_RMB = "Deconstruct", + ), + ) + + AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) ``` This will display "RMB: Deconstruct" when the user hovers over a table with a wrench. diff --git a/code/datums/elements/skill_reward.dm b/code/datums/elements/skill_reward.dm index 0c0e04754f744..7809eea85f715 100644 --- a/code/datums/elements/skill_reward.dm +++ b/code/datums/elements/skill_reward.dm @@ -24,14 +24,15 @@ if(!LAZYACCESS(modifiers, CTRL_CLICK) && !check_equippable(user)) //Allows other players to drag it around at least. to_chat(user, span_warning("You feel completely and utterly unworthy to even touch \the [source].")) return COMPONENT_CANCEL_ATTACK_CHAIN + return NONE ///We check if the item can be equipped, otherwise we drop it. /datum/element/skill_reward/proc/drop_if_unworthy(datum/source, mob/living/user) SIGNAL_HANDLER - if(check_equippable(user) | !(source in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE))) - return + if(check_equippable(user) || !(source in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE))) + return NONE to_chat(user, span_warning("You feel completely and utterly unworthy to even touch \the [source].")) - user.dropItemToGround(src, TRUE) + user.dropItemToGround(source, TRUE) return COMPONENT_EQUIPPED_FAILED /datum/element/skill_reward/proc/check_equippable(mob/living/user) diff --git a/code/datums/elements/snail_crawl.dm b/code/datums/elements/snail_crawl.dm deleted file mode 100644 index d0fac629e493d..0000000000000 --- a/code/datums/elements/snail_crawl.dm +++ /dev/null @@ -1,35 +0,0 @@ -/datum/element/snailcrawl - element_flags = ELEMENT_DETACH_ON_HOST_DESTROY - -/datum/element/snailcrawl/Attach(datum/target) - . = ..() - if(!ismovable(target)) - return ELEMENT_INCOMPATIBLE - var/P - if(iscarbon(target)) - P = PROC_REF(snail_crawl) - else - P = PROC_REF(lubricate) - RegisterSignal(target, COMSIG_MOVABLE_MOVED, P) - -/datum/element/snailcrawl/Detach(mob/living/carbon/target) - . = ..() - UnregisterSignal(target, COMSIG_MOVABLE_MOVED) - if(istype(target)) - target.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl) - -/datum/element/snailcrawl/proc/snail_crawl(mob/living/carbon/snail) - SIGNAL_HANDLER - - if(snail.resting && !snail.buckled && lubricate(snail)) - snail.add_movespeed_modifier(/datum/movespeed_modifier/snail_crawl) - else - snail.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl) - -/datum/element/snailcrawl/proc/lubricate(atom/movable/snail) - SIGNAL_HANDLER - - var/turf/open/OT = get_turf(snail) - if(istype(OT)) - OT.MakeSlippery(TURF_WET_LUBE, 20) - return TRUE diff --git a/code/datums/elements/strippable.dm b/code/datums/elements/strippable.dm index 5e36ade328087..18dffff6aedff 100644 --- a/code/datums/elements/strippable.dm +++ b/code/datums/elements/strippable.dm @@ -276,8 +276,8 @@ source.log_message("had [item] put on them by [key_name(user)].", LOG_VICTIM, color="orange", log_globally=FALSE) /// A utility function for `/datum/strippable_item`s to start unequipping an item from a mob. -/proc/start_unequip_mob(obj/item/item, mob/source, mob/user, strip_delay) - if (!do_after(user, strip_delay || item.strip_delay, source, interaction_key = REF(item))) +/proc/start_unequip_mob(obj/item/item, mob/source, mob/user, strip_delay, hidden = FALSE) + if (!do_after(user, strip_delay || item.strip_delay, source, interaction_key = REF(item), hidden = hidden)) return FALSE return TRUE diff --git a/code/datums/elements/tool_renaming.dm b/code/datums/elements/tool_renaming.dm new file mode 100644 index 0000000000000..bd87f1d171c86 --- /dev/null +++ b/code/datums/elements/tool_renaming.dm @@ -0,0 +1,78 @@ +#define OPTION_RENAME "Rename" +#define OPTION_DESCRIPTION "Description" +#define OPTION_RESET "Reset" + +/** + * Renaming tool element + * + * When using this tool on an object with UNIQUE_RENAME, + * lets the user rename/redesc it. + */ +/datum/element/tool_renaming + +/datum/element/tool_renaming/Attach(datum/target) + . = ..() + if(!isitem(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(attempt_rename)) + +/datum/element/tool_renaming/Detach(datum/source) + . = ..() + UnregisterSignal(source, COMSIG_ITEM_INTERACTING_WITH_ATOM) + +/datum/element/tool_renaming/proc/attempt_rename(datum/source, mob/living/user, atom/interacting_with, list/modifiers) + SIGNAL_HANDLER + + if(!isobj(interacting_with)) + return NONE + + var/obj/renamed_obj = interacting_with + + if(!(renamed_obj.obj_flags & UNIQUE_RENAME)) + return NONE + + INVOKE_ASYNC(src, PROC_REF(async_rename), user, renamed_obj) + return ITEM_INTERACT_SUCCESS + +/datum/element/tool_renaming/proc/async_rename(mob/living/user, obj/renamed_obj) + var/custom_choice = tgui_input_list(user, "What would you like to edit?", "Customization", list(OPTION_RENAME, OPTION_DESCRIPTION, OPTION_RESET)) + if(QDELETED(renamed_obj) || !user.can_perform_action(renamed_obj) || isnull(custom_choice)) + return + + switch(custom_choice) + if(OPTION_RENAME) + var/old_name = renamed_obj.name + var/input = tgui_input_text(user, "What do you want to name [renamed_obj]?", "Object Name", "[old_name]", MAX_NAME_LEN) + if(QDELETED(renamed_obj) || !user.can_perform_action(renamed_obj)) + return + if(input == old_name || !input) + to_chat(user, span_notice("You changed [renamed_obj] to... well... [renamed_obj].")) + return + renamed_obj.AddComponent(/datum/component/rename, input, renamed_obj.desc) + to_chat(user, span_notice("You have successfully renamed \the [old_name] to [renamed_obj].")) + ADD_TRAIT(renamed_obj, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) + renamed_obj.update_appearance(UPDATE_NAME) + + if(OPTION_DESCRIPTION) + var/old_desc = renamed_obj.desc + var/input = tgui_input_text(user, "Describe [renamed_obj]", "Description", "[old_desc]", MAX_DESC_LEN) + if(QDELETED(renamed_obj) || !user.can_perform_action(renamed_obj)) + return + if(input == old_desc || !input) + to_chat(user, span_notice("You decide against changing [renamed_obj]'s description.")) + return + renamed_obj.AddComponent(/datum/component/rename, renamed_obj.name, input) + to_chat(user, span_notice("You have successfully changed [renamed_obj]'s description.")) + ADD_TRAIT(renamed_obj, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) + renamed_obj.update_appearance(UPDATE_DESC) + + if(OPTION_RESET) + qdel(renamed_obj.GetComponent(/datum/component/rename)) + to_chat(user, span_notice("You have successfully reset [renamed_obj]'s name and description.")) + REMOVE_TRAIT(renamed_obj, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) + renamed_obj.update_appearance(UPDATE_NAME | UPDATE_DESC) + +#undef OPTION_RENAME +#undef OPTION_DESCRIPTION +#undef OPTION_RESET diff --git a/code/datums/elements/watery_tile.dm b/code/datums/elements/watery_tile.dm new file mode 100644 index 0000000000000..797eda39135b4 --- /dev/null +++ b/code/datums/elements/watery_tile.dm @@ -0,0 +1,21 @@ +/datum/element/watery_tile + element_flags = ELEMENT_DETACH_ON_HOST_DESTROY + +/datum/element/watery_tile/Attach(turf/target) + . = ..() + if(!isturf(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_ATOM_ENTERED, PROC_REF(extinguish_atom)) + +/datum/element/watery_tile/Detach(turf/source) + UnregisterSignal(source, COMSIG_ATOM_ENTERED) + return ..() + +/datum/element/watery_tile/proc/extinguish_atom(atom/source, atom/movable/entered) + SIGNAL_HANDLER + + entered.extinguish() + if(isliving(entered)) + var/mob/living/our_mob = entered + our_mob.adjust_wet_stacks(3) diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 3c0e2a903c23f..36d405450af15 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -88,43 +88,106 @@ * Returns TRUE if it was able to run the emote, FALSE otherwise. */ /datum/emote/proc/run_emote(mob/user, params, type_override, intentional = FALSE) - . = TRUE if(!can_run_emote(user, TRUE, intentional)) return FALSE if(SEND_SIGNAL(user, COMSIG_MOB_PRE_EMOTED, key, params, type_override, intentional) & COMPONENT_CANT_EMOTE) - return // We don't return FALSE because the error output would be incorrect, provide your own if necessary. + return TRUE // We don't return FALSE because the error output would be incorrect, provide your own if necessary. var/msg = select_message_type(user, message, intentional) if(params && message_param) msg = select_param(user, params) msg = replace_pronoun(user, msg) - if(!msg) - return + return TRUE user.log_message(msg, LOG_EMOTE) - var/dchatmsg = "[user] [msg]" var/tmp_sound = get_sound(user) if(tmp_sound && should_play_sound(user, intentional) && TIMER_COOLDOWN_FINISHED(user, type)) TIMER_COOLDOWN_START(user, type, audio_cooldown) playsound(user, tmp_sound, 50, vary) - var/user_turf = get_turf(user) - if (user.client) - for(var/mob/ghost as anything in GLOB.dead_mob_list) - if(!ghost.client || isnewplayer(ghost)) + var/is_important = emote_type & EMOTE_IMPORTANT + var/is_visual = emote_type & EMOTE_VISIBLE + var/is_audible = emote_type & EMOTE_AUDIBLE + + // Emote doesn't get printed to chat, runechat only + if(emote_type & EMOTE_RUNECHAT) + for(var/mob/viewer as anything in viewers(user)) + if(isnull(viewer.client)) + continue + if(!is_important && viewer != user && (!is_visual || !is_audible)) + if(is_audible && !viewer.can_hear()) + continue + if(is_visual && viewer.is_blind()) + continue + if(user.runechat_prefs_check(viewer, EMOTE_MESSAGE)) + viewer.create_chat_message( + speaker = user, + raw_message = msg, + runechat_flags = EMOTE_MESSAGE, + ) + else if(is_important) + to_chat(viewer, "[user] [msg]") + else if(is_audible && is_visual) + viewer.show_message( + "[user] [msg]", MSG_AUDIBLE, + "You see how [user] [msg]", MSG_VISUAL, + ) + else if(is_audible) + viewer.show_message("[user] [msg]", MSG_AUDIBLE) + else if(is_visual) + viewer.show_message("[user] [msg]", MSG_VISUAL) + return TRUE // Early exit so no dchat message + + // The emote has some important information, and should always be shown to the user + else if(is_important) + for(var/mob/viewer as anything in viewers(user)) + to_chat(viewer, "[user] [msg]") + if(user.runechat_prefs_check(viewer, EMOTE_MESSAGE)) + viewer.create_chat_message( + speaker = user, + raw_message = msg, + runechat_flags = EMOTE_MESSAGE, + ) + // Emotes has both an audible and visible component + // Prioritize audible, and provide a visible message if the user is deaf + else if(is_visual && is_audible) + user.audible_message( + message = msg, + deaf_message = "You see how [user] [msg]", + self_message = msg, + audible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE, + ) + // Emote is entirely audible, no visible component + else if(is_audible) + user.audible_message( + message = msg, + self_message = msg, + audible_message_flags = EMOTE_MESSAGE, + ) + // Emote is entirely visible, no audible component + else if(is_visual) + user.visible_message( + message = msg, + self_message = msg, + visible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE, + ) + else + CRASH("Emote [type] has no valid emote type set!") + + if(!isnull(user.client)) + var/dchatmsg = "[user] [msg]" + for(var/mob/ghost as anything in GLOB.dead_mob_list - viewers(get_turf(user))) + if(isnull(ghost.client) || isnewplayer(ghost)) continue - if(get_chat_toggles(ghost.client) & CHAT_GHOSTSIGHT && !(ghost in viewers(user_turf, null))) - ghost.show_message("[FOLLOW_LINK(ghost, user)] [dchatmsg]") - if(emote_type & (EMOTE_AUDIBLE | EMOTE_VISIBLE)) //emote is audible and visible - user.audible_message(msg, deaf_message = "You see how [user] [msg]", audible_message_flags = EMOTE_MESSAGE) - else if(emote_type & EMOTE_VISIBLE) //emote is only visible - user.visible_message(msg, visible_message_flags = EMOTE_MESSAGE) - if(emote_type & EMOTE_IMPORTANT) - for(var/mob/living/viewer in viewers()) - if(viewer.is_blind() && !viewer.can_hear()) - to_chat(viewer, msg) + if(!(get_chat_toggles(ghost.client) & CHAT_GHOSTSIGHT)) + continue + to_chat(ghost, "[FOLLOW_LINK(ghost, user)] [dchatmsg]") + + return TRUE + + /** * For handling emote cooldown, return true to allow the emote to happen. diff --git a/code/datums/greyscale/json_reader.dm b/code/datums/greyscale/json_reader.dm index ffe143c28fc75..38286631fed49 100644 --- a/code/datums/greyscale/json_reader.dm +++ b/code/datums/greyscale/json_reader.dm @@ -63,7 +63,7 @@ ) /datum/json_reader/blend_mode/ReadJson(value) - var/new_value = blend_modes[lowertext(value)] + var/new_value = blend_modes[LOWER_TEXT(value)] if(isnull(new_value)) CRASH("Blend mode expected but got '[value]'") return new_value diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index 3d94c8645b5fa..cfa608011bdf9 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -1213,30 +1213,6 @@ if(CONFIG_GET(flag/security_has_maint_access)) access |= list(ACCESS_MAINT_TUNNELS) -/datum/id_trim/job/virologist - assignment = "Virologist" - trim_state = "trim_virologist" - department_color = COLOR_MEDICAL_BLUE - subdepartment_color = COLOR_MEDICAL_BLUE - sechud_icon_state = SECHUD_VIROLOGIST - minimal_access = list( - ACCESS_MECH_MEDICAL, - ACCESS_MEDICAL, - ACCESS_MINERAL_STOREROOM, - ACCESS_VIROLOGY, - ACCESS_PHARMACY, - ) - extra_access = list( - ACCESS_PLUMBING, - ACCESS_MORGUE, - ACCESS_SURGERY, - ) - template_access = list( - ACCESS_CAPTAIN, - ACCESS_CHANGE_IDS, - ACCESS_CMO, - ) - job = /datum/job/virologist /datum/id_trim/job/warden assignment = "Warden" diff --git a/code/datums/keybinding/admin.dm b/code/datums/keybinding/admin.dm index 80936aa41e76c..1e94f71e58ad4 100644 --- a/code/datums/keybinding/admin.dm +++ b/code/datums/keybinding/admin.dm @@ -23,7 +23,7 @@ . = ..() if(.) return - user.admin_ghost() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) return TRUE /datum/keybinding/admin/player_panel_new @@ -51,7 +51,7 @@ . = ..() if(.) return - user.togglebuildmodeself() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/build_mode_self) return TRUE /datum/keybinding/admin/stealthmode @@ -65,7 +65,7 @@ . = ..() if(.) return - user.stealth() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/stealth) return TRUE /datum/keybinding/admin/invisimin @@ -79,7 +79,7 @@ . = ..() if(.) return - user.invisimin() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/invisimin) return TRUE /datum/keybinding/admin/deadsay @@ -107,7 +107,7 @@ . = ..() if(.) return - user.deadmin() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/deadmin) return TRUE /datum/keybinding/admin/readmin @@ -135,5 +135,5 @@ . = ..() if(.) return - user.holder?.display_tags() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/display_tags) return TRUE diff --git a/code/datums/lazy_template.dm b/code/datums/lazy_template.dm index 3b19a17a179da..7b18ff7225f03 100644 --- a/code/datums/lazy_template.dm +++ b/code/datums/lazy_template.dm @@ -15,6 +15,8 @@ var/map_name /// place_on_top: Whether to use /turf/proc/PlaceOnTop rather than /turf/proc/ChangeTurf var/place_on_top = FALSE + /// type of turf reservation + var/turf_reservation_type = /datum/turf_reservation /datum/lazy_template/New() reservations = list() @@ -62,6 +64,7 @@ width, height, parsed_template.parsed_bounds[MAP_MAXZ], + reservation_type = turf_reservation_type, ) if(!reservation) CRASH("Failed to reserve a block for lazy template: '[key]'") diff --git a/code/datums/looping_sounds/item_sounds.dm b/code/datums/looping_sounds/item_sounds.dm index f8ed5d89b20c9..00fd3063e4382 100644 --- a/code/datums/looping_sounds/item_sounds.dm +++ b/code/datums/looping_sounds/item_sounds.dm @@ -44,3 +44,7 @@ /datum/looping_sound/beesmoke mid_sounds = list('sound/weapons/beesmoke.ogg' = 1) volume = 5 + +/datum/looping_sound/zipline + mid_sounds = list('sound/weapons/zipline_mid.ogg' = 1) + volume = 5 diff --git a/code/datums/mapgen/Cavegens/IcemoonCaves.dm b/code/datums/mapgen/Cavegens/IcemoonCaves.dm index 91348dd5c1783..dee0bc2bdcc3d 100644 --- a/code/datums/mapgen/Cavegens/IcemoonCaves.dm +++ b/code/datums/mapgen/Cavegens/IcemoonCaves.dm @@ -11,6 +11,7 @@ /mob/living/basic/mining/legion/snow = 50, /mob/living/basic/mining/lobstrosity = 15, /mob/living/basic/mining/wolf = 50, + /obj/effect/spawner/random/lavaland_mob/raptor = 15, /mob/living/simple_animal/hostile/asteroid/polarbear = 30, /obj/structure/spawner/ice_moon = 3, /obj/structure/spawner/ice_moon/polarbear = 3, @@ -65,7 +66,7 @@ ) mob_spawn_chance = 0.2 - weighted_mob_spawn_list = list(/mob/living/basic/deer/ice = 99, /mob/living/basic/tree = 1) + weighted_mob_spawn_list = list(/mob/living/basic/deer/ice = 99, /mob/living/basic/tree = 1, /obj/effect/spawner/random/lavaland_mob/raptor = 15) /datum/map_generator/cave_generator/icemoon/surface/noruins //use this for when you don't want ruins to spawn in a certain area @@ -76,6 +77,8 @@ /mob/living/basic/mining/ice_demon = 100, /mob/living/basic/mining/ice_whelp = 60, /mob/living/basic/mining/legion/snow = 100, + /obj/effect/spawner/random/lavaland_mob/raptor = 25, + /obj/structure/spawner/ice_moon/demonic_portal = 6, /obj/structure/spawner/ice_moon/demonic_portal/ice_whelp = 6, /obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 6, diff --git a/code/datums/mapgen/Cavegens/LavalandGenerator.dm b/code/datums/mapgen/Cavegens/LavalandGenerator.dm index 846e23181e047..47b62ce4a1baf 100644 --- a/code/datums/mapgen/Cavegens/LavalandGenerator.dm +++ b/code/datums/mapgen/Cavegens/LavalandGenerator.dm @@ -10,6 +10,7 @@ /mob/living/basic/mining/bileworm = 20, /mob/living/basic/mining/brimdemon = 20, /mob/living/basic/mining/lobstrosity/lava = 20, + /obj/effect/spawner/random/lavaland_mob/raptor = 15, /mob/living/basic/mining/goldgrub = 10, /obj/structure/spawner/lavaland = 2, /obj/structure/spawner/lavaland/goliath = 3, diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm index 8ef30db63aa96..8e20dfbef9cb9 100644 --- a/code/datums/martial/boxing.dm +++ b/code/datums/martial/boxing.dm @@ -1,102 +1,271 @@ +#define LEFT_RIGHT_COMBO "DH" +#define RIGHT_LEFT_COMBO "HD" +#define LEFT_LEFT_COMBO "HH" +#define RIGHT_RIGHT_COMBO "DD" + /datum/martial_art/boxing name = "Boxing" id = MARTIALART_BOXING pacifist_style = TRUE + ///Boolean on whether we are sportsmanlike in our tussling; TRUE means we have restrictions + var/honorable_boxer = TRUE + /// List of traits applied to users of this martial art. + var/list/boxing_traits = list(TRAIT_BOXING_READY) + /// Balloon alert cooldown for warning our boxer to alternate their blows to get more damage + COOLDOWN_DECLARE(warning_cooldown) /datum/martial_art/boxing/teach(mob/living/new_holder, make_temporary) if(!ishuman(new_holder)) return FALSE + new_holder.add_traits(boxing_traits, BOXING_TRAIT) + RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block)) + return ..() + +/datum/martial_art/boxing/on_remove(mob/living/remove_from) + remove_from.remove_traits(boxing_traits, BOXING_TRAIT) + UnregisterSignal(remove_from, list(COMSIG_LIVING_CHECK_BLOCK)) return ..() -/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/attacker, mob/living/defender) - attacker.balloon_alert(attacker, "can't disarm while boxing!") - return MARTIAL_ATTACK_FAIL +///Unlike most instances of this proc, this is actually called in _proc/tussle() +///Returns a multiplier on our skill damage bonus. +/datum/martial_art/boxing/proc/check_streak(mob/living/attacker, mob/living/defender) + var/combo_multiplier = 1 + + if(findtext(streak, LEFT_LEFT_COMBO) || findtext(streak, RIGHT_RIGHT_COMBO)) + reset_streak() + if(COOLDOWN_FINISHED(src, warning_cooldown)) + COOLDOWN_START(src, warning_cooldown, 2 SECONDS) + attacker.balloon_alert(attacker, "weak combo, alternate your hits!") + return combo_multiplier * 0.5 + + if(findtext(streak, LEFT_RIGHT_COMBO) || findtext(streak, RIGHT_LEFT_COMBO)) + reset_streak() + return combo_multiplier * 1.5 -/datum/martial_art/boxing/grab_act(mob/living/carbon/human/attacker, mob/living/defender) - attacker.balloon_alert(attacker, "can't grab while boxing!") - return MARTIAL_ATTACK_FAIL + return combo_multiplier + +/datum/martial_art/boxing/disarm_act(mob/living/attacker, mob/living/defender) + if(honor_check(defender)) + add_to_streak("D", defender) + tussle(attacker, defender, "right hook", "right hooked") + return MARTIAL_ATTACK_SUCCESS + +/datum/martial_art/boxing/grab_act(mob/living/attacker, mob/living/defender) + if(honorable_boxer) + attacker.balloon_alert(attacker, "no grabbing while boxing!") + return MARTIAL_ATTACK_FAIL + return MARTIAL_ATTACK_INVALID //UNLESS YOU'RE EVIL + +/datum/martial_art/boxing/harm_act(mob/living/attacker, mob/living/defender) + if(honor_check(defender)) + add_to_streak("H", defender) + tussle(attacker, defender, "left hook", "left hooked") + return MARTIAL_ATTACK_SUCCESS + +// Our only boxing move, which occurs on literally all attacks; the tussle. However, quite a lot morphs the results of this proc. Combos, unlike most martial arts attacks, are checked in this proc rather than our standard unarmed procs +/datum/martial_art/boxing/proc/tussle(mob/living/attacker, mob/living/defender, atk_verb = "blind jab", atk_verbed = "blind jabbed") + + if(honorable_boxer) //Being a good sport, you never hit someone on the ground or already knocked down. It shows you're the better person. + if(defender.body_position == LYING_DOWN && defender.getStaminaLoss() >= 100 || defender.IsUnconscious()) //If they're in stamcrit or unconscious, don't bloody punch them + attacker.balloon_alert(attacker, "unsportsmanlike behaviour!") + return FALSE -/datum/martial_art/boxing/harm_act(mob/living/carbon/human/attacker, mob/living/defender) var/obj/item/bodypart/arm/active_arm = attacker.get_active_hand() + + //The values between which damage is rolled for punches + var/lower_force = active_arm.unarmed_damage_low + var/upper_force = active_arm.unarmed_damage_high + + //Determines knockout potential and armor penetration (if that matters) + var/base_unarmed_effectiveness = active_arm.unarmed_effectiveness + + //Determines attack sound based on attacker arm + var/attack_sound = active_arm.unarmed_attack_sound + + // Out athletics skill is added as a damage bonus + var/athletics_skill = attacker.mind?.get_skill_level(/datum/skill/athletics) + + // If true, grants experience for punching; we only gain experience if we punch another boxer. + var/grant_experience = FALSE + + // What type of damage does our kind of boxing do? Defaults to STAMINA, unless you're performing EVIL BOXING + var/damage_type = honorable_boxer ? STAMINA : attacker.get_attack_type() + attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) - var/damage = rand(5, 8) + active_arm.unarmed_damage_low - var/atk_verb = pick("left hook", "right hook", "straight punch") - if(damage <= 0) - playsound(defender, active_arm.unarmed_miss_sound, 25, TRUE, -1) - defender.visible_message( - span_warning("[attacker]'s [atk_verb] misses [defender]!"), - span_danger("You avoid [attacker]'s [atk_verb]!"), - span_hear("You hear a swoosh!"), - COMBAT_MESSAGE_RANGE, - attacker, - ) - to_chat(attacker, span_warning("Your [atk_verb] misses [defender]!")) - log_combat(attacker, defender, "attempted to hit", atk_verb) - return MARTIAL_ATTACK_FAIL + //Determines damage dealt on a punch. Against a boxing defender, we apply our skill bonus. + var/damage = rand(lower_force, upper_force) - if(defender.check_block(attacker, damage, "[attacker]'s [atk_verb]", UNARMED_ATTACK)) - return MARTIAL_ATTACK_FAIL + if(honor_check(defender)) + var/strength_bonus = HAS_TRAIT(attacker, TRAIT_STRENGTH) ? 2 : 0 //Investing into genetic strength improvements makes you a better boxer + damage += round(athletics_skill * check_streak(attacker, defender) + strength_bonus) + grant_experience = TRUE + + var/current_atk_verb = atk_verb + var/current_atk_verbed = atk_verbed + + if(is_detective_job(attacker.mind?.assigned_role)) //In short: discombobulate + current_atk_verb = "discombobulate" + current_atk_verbed = "discombulated" + + // Similar to a normal punch, should we have a value of 0 for our lower force, we simply miss outright. + if(!lower_force) + playsound(defender.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1) + defender.visible_message(span_warning("[attacker]'s [current_atk_verb] misses [defender]!"), \ + span_danger("You avoid [attacker]'s [current_atk_verb]!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, attacker) + to_chat(attacker, span_warning("Your [current_atk_verb] misses [defender]!")) + log_combat(attacker, defender, "attempted to hit", current_atk_verb) + return FALSE + + if(defender.check_block(attacker, damage, "[attacker]'s [current_atk_verb]", UNARMED_ATTACK)) + return FALSE var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected)) - var/armor_block = defender.run_armor_check(affecting, MELEE) + var/armor_block = defender.run_armor_check(affecting, MELEE, armour_penetration = base_unarmed_effectiveness) + + playsound(defender, attack_sound, 25, TRUE, -1) - playsound(defender, active_arm.unarmed_attack_sound, 25, TRUE, -1) defender.visible_message( - span_danger("[attacker] [atk_verb]ed [defender]!"), - span_userdanger("You're [atk_verb]ed by [attacker]!"), + span_danger("[attacker] [current_atk_verbed] [defender]!"), + span_userdanger("You're [current_atk_verbed] by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker, ) - to_chat(attacker, span_danger("You [atk_verb]ed [defender]!")) - defender.apply_damage(damage, STAMINA, affecting, armor_block) + + to_chat(attacker, span_danger("You [current_atk_verbed] [defender]!")) + + defender.apply_damage(damage, damage_type, affecting, armor_block) + log_combat(attacker, defender, "punched (boxing) ") - if(defender.getStaminaLoss() > 50 && istype(defender.mind?.martial_art, /datum/martial_art/boxing)) - var/knockout_prob = defender.getStaminaLoss() + rand(-15, 15) - if(defender.stat != DEAD && prob(knockout_prob)) - defender.visible_message( - span_danger("[attacker] knocks [defender] out with a haymaker!"), - span_userdanger("You're knocked unconscious by [attacker]!"), - span_hear("You hear a sickening sound of flesh hitting flesh!"), - COMBAT_MESSAGE_RANGE, - attacker, - ) - to_chat(attacker, span_danger("You knock [defender] out with a haymaker!")) - defender.apply_effect(20 SECONDS, EFFECT_KNOCKDOWN, armor_block) - defender.SetSleeping(10 SECONDS) - log_combat(attacker, defender, "knocked out (boxing) ") - return MARTIAL_ATTACK_SUCCESS -/datum/martial_art/boxing/can_use(mob/living/martial_artist) - if(!ishuman(martial_artist)) + if(grant_experience) + skill_experience_adjustment(attacker, (damage/lower_force)) + + if(defender.stat == DEAD || !honor_check(defender)) //early returning here so we don't worry about knockout probs + return TRUE + + //Determine our attackers athletics level as a knockout probability bonus + var/attacker_athletics_skill = (attacker.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) + base_unarmed_effectiveness) + + // Defender boxing skill and armor block are used as a defense here. This has already factored in base_unarmed_effectiveness from the attacker + var/defender_athletics_skill = clamp(defender.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER), 0, 100) + + //Determine our final probability, using a clamp to stop any prob() weirdness. + var/final_knockout_probability = clamp(round(attacker_athletics_skill - defender_athletics_skill), 0 , 100) + + if(!prob(final_knockout_probability)) + return TRUE + + if(defender.get_timed_status_effect_duration(/datum/status_effect/staggered)) + defender.visible_message( + span_danger("[attacker] knocks [defender] out with a haymaker!"), + span_userdanger("You're knocked unconscious by [attacker]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + COMBAT_MESSAGE_RANGE, + attacker, + ) + to_chat(attacker, span_danger("You knock [defender] out with a haymaker!")) + defender.apply_effect(20 SECONDS, EFFECT_KNOCKDOWN, armor_block) + defender.SetSleeping(10 SECONDS) + log_combat(attacker, defender, "knocked out (boxing) ") + else + defender.visible_message( + span_danger("[attacker] staggers [defender] with a haymaker!"), + span_userdanger("You're nearly knocked off your feet by [attacker]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + COMBAT_MESSAGE_RANGE, + attacker, + ) + defender.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) + to_chat(attacker, span_danger("You stagger [defender] with a haymaker!")) + log_combat(attacker, defender, "staggered (boxing) ") + + playsound(defender, 'sound/effects/coin2.ogg', 40, TRUE) + new /obj/effect/temp_visual/crit(get_turf(defender)) + skill_experience_adjustment(attacker, (damage/lower_force)) //double experience for a successful crit + + return TRUE + +/// Returns whether whoever is checked by this proc is complying with the rules of boxing. The boxer cannot block non-boxers, and cannot apply their scariest moves against non-boxers. +/datum/martial_art/boxing/proc/honor_check(mob/living/possible_boxer) + if(!honorable_boxer) + return TRUE //You scoundrel!! + + if(!HAS_TRAIT(possible_boxer, TRAIT_BOXING_READY)) return FALSE - return ..() -/obj/item/clothing/gloves/boxing - var/datum/martial_art/boxing/style + return TRUE + +/// Handles our instances of experience gain while boxing. It also applies the exercised status effect. +/datum/martial_art/boxing/proc/skill_experience_adjustment(mob/living/boxer, experience_value) + //Boxing in heavier gravity gives you more experience + var/gravity_modifier = boxer.has_gravity() > STANDARD_GRAVITY ? 1 : 0.5 + + //You gotta sleep before you get any experience! + boxer.mind?.adjust_experience(/datum/skill/athletics, experience_value * gravity_modifier) + boxer.apply_status_effect(/datum/status_effect/exercised) + +/// Handles our blocking signals, similar to hit_reaction() on items. Only blocks while the boxer is in throw mode. +/datum/martial_art/boxing/proc/check_block(mob/living/boxer, atom/movable/hitby, damage, attack_text, attack_type, ...) + SIGNAL_HANDLER + + if(!can_use(boxer) || !boxer.throw_mode || boxer.incapacitated(IGNORE_GRAB)) + return NONE + + if(attack_type != UNARMED_ATTACK) + return NONE + + //Determines unarmed defense against boxers using our current active arm. + var/obj/item/bodypart/arm/active_arm = boxer.get_active_hand() + var/base_unarmed_effectiveness = active_arm.unarmed_effectiveness + + // Out athletics skill is added to our block potential + var/athletics_skill_rands = boxer.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) + + var/block_chance = base_unarmed_effectiveness + athletics_skill_rands -/obj/item/clothing/gloves/boxing/Initialize(mapload) - . = ..() - var/static/list/slapcraft_recipe_list = list(/datum/crafting_recipe/extendohand_l, /datum/crafting_recipe/extendohand_r) + var/block_text = pick("block", "evade") - AddComponent( - /datum/component/slapcrafting,\ - slapcraft_recipes = slapcraft_recipe_list,\ + if(!prob(block_chance)) + return NONE + + var/mob/living/attacker = GET_ASSAILANT(hitby) + + if(!honor_check(attacker)) + return NONE + + if(istype(attacker) && boxer.Adjacent(attacker)) + attacker.apply_damage(10, STAMINA) + boxer.apply_damage(5, STAMINA) + + boxer.visible_message( + span_danger("[boxer] [block_text]s [attack_text]!"), + span_userdanger("You [block_text] [attack_text]!"), ) + if(block_text == "evade") + playsound(boxer.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1) + + skill_experience_adjustment(boxer, 1) //just getting hit a bunch doesn't net you much experience - style = new() - style.allow_temp_override = FALSE + return SUCCESSFUL_BLOCK -/obj/item/clothing/gloves/boxing/Destroy() - QDEL_NULL(style) +/datum/martial_art/boxing/can_use(mob/living/martial_artist) + if(!ishuman(martial_artist)) + return FALSE return ..() -/obj/item/clothing/gloves/boxing/equipped(mob/user, slot) - . = ..() - if(slot & ITEM_SLOT_GLOVES) - style.teach(user, TRUE) +/// Evil Boxing; for sick, evil scoundrels. Has no honor, making it more lethal (therefore unable to be used by pacifists). +/// Grants Strength and Stimmed to speed up any experience gain. + +/datum/martial_art/boxing/evil + name = "Evil Boxing" + id = MARTIALART_EVIL_BOXING + pacifist_style = FALSE + honorable_boxer = FALSE + boxing_traits = list(TRAIT_BOXING_READY, TRAIT_STRENGTH, TRAIT_STIMMED) -/obj/item/clothing/gloves/boxing/dropped(mob/user) - . = ..() - style.fully_remove(user) +#undef LEFT_RIGHT_COMBO +#undef RIGHT_LEFT_COMBO +#undef LEFT_LEFT_COMBO +#undef RIGHT_RIGHT_COMBO diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index 1710009de3c6e..57e158cf66982 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -209,25 +209,10 @@ /obj/item/clothing/gloves/krav_maga clothing_traits = list(TRAIT_FAST_CUFFING) - var/datum/martial_art/krav_maga/style /obj/item/clothing/gloves/krav_maga/Initialize(mapload) . = ..() - style = new() - style.allow_temp_override = FALSE - -/obj/item/clothing/gloves/krav_maga/Destroy() - QDEL_NULL(style) - return ..() - -/obj/item/clothing/gloves/krav_maga/equipped(mob/user, slot) - . = ..() - if(slot & ITEM_SLOT_GLOVES) - style.teach(user, TRUE) - -/obj/item/clothing/gloves/krav_maga/dropped(mob/user) - . = ..() - style.fully_remove(user) + AddComponent(/datum/component/martial_art_giver, /datum/martial_art/krav_maga) /obj/item/clothing/gloves/krav_maga/sec//more obviously named, given to sec name = "krav maga gloves" diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index c55f95d4bd6af..8116084127ecf 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -325,7 +325,7 @@ /obj/item/clothing/gloves/the_sleeping_carp name = "carp gloves" - desc = "This gloves are capable of making people use The Sleeping Carp." + desc = "These gloves are capable of making people use The Sleeping Carp." icon_state = "black" greyscale_colors = COLOR_BLACK cold_protection = HANDS @@ -333,26 +333,10 @@ heat_protection = HANDS max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE - var/datum/martial_art/the_sleeping_carp/style /obj/item/clothing/gloves/the_sleeping_carp/Initialize(mapload) . = ..() - style = new() - style.allow_temp_override = FALSE - -/obj/item/clothing/gloves/the_sleeping_carp/Destroy() - QDEL_NULL(style) - return ..() - -/obj/item/clothing/gloves/the_sleeping_carp/equipped(mob/user, slot) - . = ..() - if(slot & ITEM_SLOT_GLOVES) - style.teach(user, TRUE) - -/obj/item/clothing/gloves/the_sleeping_carp/dropped(mob/user) - . = ..() - if(!isnull(style)) - style.fully_remove(user) + AddComponent(/datum/component/martial_art_giver, /datum/martial_art/the_sleeping_carp) #undef STRONG_PUNCH_COMBO #undef LAUNCH_KICK_COMBO diff --git a/code/datums/martial/wrestling.dm b/code/datums/martial/wrestling.dm index 23591852ec90b..4bcaf02b2d5a1 100644 --- a/code/datums/martial/wrestling.dm +++ b/code/datums/martial/wrestling.dm @@ -358,7 +358,7 @@ If you make a derivative work from this code, you must include this notification attacker.setDir(turn(attacker.dir, 90)) attacker.forceMove(defender.loc) - addtimer(CALLBACK(src, PROC_REF(CheckStrikeTurf), attacker, T), 4) + addtimer(CALLBACK(src, PROC_REF(CheckStrikeTurf), attacker, T), 0.4 SECONDS) defender.visible_message(span_danger("[attacker] headbutts [defender]!"), \ span_userdanger("You're headbutted by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) @@ -490,22 +490,7 @@ If you make a derivative work from this code, you must include this notification /obj/item/storage/belt/champion/wrestling name = "Wrestling Belt" - var/datum/martial_art/wrestling/style /obj/item/storage/belt/champion/wrestling/Initialize(mapload) . = ..() - style = new() - style.allow_temp_override = FALSE - -/obj/item/storage/belt/champion/wrestling/Destroy() - QDEL_NULL(style) - return ..() - -/obj/item/storage/belt/champion/wrestling/equipped(mob/user, slot) - . = ..() - if(slot & ITEM_SLOT_BELT) - style.teach(user, TRUE) - -/obj/item/storage/belt/champion/wrestling/dropped(mob/user) - . = ..() - style.fully_remove(user) + AddComponent(/datum/component/martial_art_giver, /datum/martial_art/wrestling) diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm index da5a15b8d3191..b340d95e90fbd 100644 --- a/code/datums/materials/_material.dm +++ b/code/datums/materials/_material.dm @@ -59,6 +59,8 @@ Simple datum which is instanced once per type and is used for every object of sa var/cached_texture_filter_icon ///What type of shard the material will shatter to var/obj/item/shard_type + ///How resistant the material is to rusting when applied to a turf + var/mat_rust_resistance = RUST_RESISTANCE_ORGANIC ///What type of debris the tile will leave behind when shattered. var/obj/effect/decal/debris_type /// How likely this mineral is to be found in a boulder during mining. @@ -160,6 +162,7 @@ Simple datum which is instanced once per type and is used for every object of sa if(alpha < 255) T.AddElement(/datum/element/turf_z_transparency) setup_glow(T) + T.rust_resistance = mat_rust_resistance return /datum/material/proc/setup_glow(turf/on) diff --git a/code/datums/materials/alloys.dm b/code/datums/materials/alloys.dm index e878a7f495daa..8bfdf0b58d9fe 100644 --- a/code/datums/materials/alloys.dm +++ b/code/datums/materials/alloys.dm @@ -36,6 +36,7 @@ sheet_type = /obj/item/stack/sheet/plasteel categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/iron=1, /datum/material/plasma=1) + mat_rust_resistance = RUST_RESISTANCE_REINFORCED /datum/material/alloy/plasteel/on_applied_obj(obj/item/target_item, amount, material_flags) . = ..() @@ -69,6 +70,7 @@ sheet_type = /obj/item/stack/sheet/mineral/plastitanium categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/titanium=1, /datum/material/plasma=1) + mat_rust_resistance = RUST_RESISTANCE_TITANIUM /** Plasmaglass * diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm index f6e64d57e7198..66f4bccbd6f7b 100644 --- a/code/datums/materials/basemats.dm +++ b/code/datums/materials/basemats.dm @@ -2,12 +2,13 @@ /datum/material/iron name = "iron" desc = "Common iron ore often found in sedimentary and igneous layers of the crust." - color = "#878687" - greyscale_colors = "#878687" + color = "#B6BEC2" + greyscale_colors = "#B6BEC2" categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/iron ore_type = /obj/item/stack/ore/iron value_per_unit = 5 / SHEET_MATERIAL_AMOUNT + mat_rust_resistance = RUST_RESISTANCE_BASIC mineral_rarity = MATERIAL_RARITY_COMMON points_per_unit = 1 / SHEET_MATERIAL_AMOUNT minimum_value_override = 0 @@ -22,8 +23,8 @@ /datum/material/glass name = "glass" desc = "Glass forged by melting sand." - color = "#88cdf1" - greyscale_colors = "#88cdf196" + color = "#6292AF" + greyscale_colors = "#6292AF" alpha = 150 categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) integrity_modifier = 0.1 @@ -39,6 +40,7 @@ armor_modifiers = list(MELEE = 0.2, BULLET = 0.2, ENERGY = 1, BIO = 0.2, FIRE = 1, ACID = 0.2) mineral_rarity = MATERIAL_RARITY_COMMON points_per_unit = 1 / SHEET_MATERIAL_AMOUNT + texture_layer_icon_state = "shine" /datum/material/glass/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5, sharpness = TRUE) //cronch @@ -63,8 +65,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/silver name = "silver" desc = "Silver" - color = list(255/255, 284/255, 302/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) - greyscale_colors = "#e3f1f8" + color = "#B5BCBB" + greyscale_colors = "#B5BCBB" categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/silver ore_type = /obj/item/stack/ore/silver @@ -74,6 +76,7 @@ Unless you know what you're doing, only use the first three numbers. They're in beauty_modifier = 0.075 mineral_rarity = MATERIAL_RARITY_SEMIPRECIOUS points_per_unit = 16 / SHEET_MATERIAL_AMOUNT + texture_layer_icon_state = "shine" /datum/material/silver/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) @@ -83,8 +86,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/gold name = "gold" desc = "Gold" - color = list(340/255, 240/255, 50/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //gold is shiny, but not as bright as bananium - greyscale_colors = "#dbdd4c" + color = "#E6BB45" + greyscale_colors = "#E6BB45" strength_modifier = 1.2 categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/gold @@ -96,6 +99,7 @@ Unless you know what you're doing, only use the first three numbers. They're in armor_modifiers = list(MELEE = 1.1, BULLET = 1.1, LASER = 1.15, ENERGY = 1.15, BOMB = 1, BIO = 1, FIRE = 0.7, ACID = 1.1) mineral_rarity = MATERIAL_RARITY_PRECIOUS points_per_unit = 18 / SHEET_MATERIAL_AMOUNT + texture_layer_icon_state = "shine" /datum/material/gold/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) @@ -105,8 +109,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/diamond name = "diamond" desc = "Highly pressurized carbon" - color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) - greyscale_colors = "#71c8f784" + color = "#C9D8F2" + greyscale_colors = "#C9D8F2" categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/diamond ore_type = /obj/item/stack/ore/diamond @@ -128,8 +132,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/uranium name = "uranium" desc = "Uranium" - color = rgb(48, 237, 26) - greyscale_colors = rgb(48, 237, 26) + color = "#2C992C" + greyscale_colors = "#2C992C" categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/uranium ore_type = /obj/item/stack/ore/uranium @@ -168,8 +172,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/plasma name = "plasma" desc = "Isn't plasma a state of matter? Oh whatever." - color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) - greyscale_colors = "#c162ec" + color = "#BA3692" + greyscale_colors = "#BA3692" categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/plasma ore_type = /obj/item/stack/ore/plasma @@ -200,8 +204,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/bluespace name = "bluespace crystal" desc = "Crystals with bluespace properties" - color = list(119/255, 217/255, 396/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) - greyscale_colors = "#4e7dffC8" + color = "#2E50B7" + greyscale_colors = "#2E50B7" alpha = 200 starlight_color = COLOR_BLUE categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_ITEM_MATERIAL = TRUE) @@ -213,6 +217,7 @@ Unless you know what you're doing, only use the first three numbers. They're in points_per_unit = 50 / SHEET_MATERIAL_AMOUNT tradable = TRUE tradable_base_quantity = MATERIAL_QUANTITY_EXOTIC + texture_layer_icon_state = "shine" /datum/material/bluespace/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) victim.reagents.add_reagent(/datum/reagent/bluespace, rand(5, 8)) @@ -223,8 +228,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/bananium name = "bananium" desc = "Material with hilarious properties" - color = list(460/255, 464/255, 0, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //obnoxiously bright yellow - greyscale_colors = "#ffff00" + color = list(460/255, 464/255, 0, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //obnoxiously bright yellow //It's literally perfect I can't change it + greyscale_colors = "#FFF269" categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/bananium ore_type = /obj/item/stack/ore/bananium @@ -253,8 +258,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/titanium name = "titanium" desc = "Titanium" - color = "#b3c0c7" - greyscale_colors = "#b3c0c7" + color = "#EFEFEF" + greyscale_colors = "#EFEFEF" strength_modifier = 1.3 categories = list(MAT_CATEGORY_SILO = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/titanium @@ -264,7 +269,9 @@ Unless you know what you're doing, only use the first three numbers. They're in tradable_base_quantity = MATERIAL_QUANTITY_UNCOMMON beauty_modifier = 0.05 armor_modifiers = list(MELEE = 1.35, BULLET = 1.3, LASER = 1.3, ENERGY = 1.25, BOMB = 1.25, BIO = 1, FIRE = 0.7, ACID = 1) + mat_rust_resistance = RUST_RESISTANCE_TITANIUM mineral_rarity = MATERIAL_RARITY_SEMIPRECIOUS + texture_layer_icon_state = "shine" /datum/material/titanium/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) victim.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7) @@ -273,8 +280,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/runite name = "runite" desc = "Runite" - color = "#3F9995" - greyscale_colors = "#3F9995" + color = "#526F77" + greyscale_colors = "#526F77" strength_modifier = 1.3 categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/runite @@ -292,8 +299,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/plastic name = "plastic" desc = "Plastic" - color = "#caccd9" - greyscale_colors = "#caccd9" + color = "#BFB9AC" + greyscale_colors = "#BFB9AC" strength_modifier = 0.85 sheet_type = /obj/item/stack/sheet/plastic ore_type = /obj/item/stack/ore/slag //No plastic or coal ore, so we use slag. @@ -321,8 +328,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/wood name = "wood" desc = "Flexible, durable, but flamable. Hard to come across in space." - color = "#bb8e53" - greyscale_colors = "#bb8e53" + color = "#855932" + greyscale_colors = "#855932" strength_modifier = 0.5 sheet_type = /obj/item/stack/sheet/mineral/wood categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) @@ -354,8 +361,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/adamantine name = "adamantine" desc = "A powerful material made out of magic, I mean science!" - color = "#6d7e8e" - greyscale_colors = "#6d7e8e" + color = "#2B7A74" + greyscale_colors = "#2B7A74" strength_modifier = 1.5 categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/adamantine @@ -426,11 +433,12 @@ Unless you know what you're doing, only use the first three numbers. They're in source_item?.reagents?.add_reagent(/datum/reagent/toxin/plasma, source_item.reagents.total_volume*(3/5)) return TRUE +// It's basically adamantine, but it isn't! /datum/material/metalhydrogen name = "Metal Hydrogen" desc = "Solid metallic hydrogen. Some say it should be impossible" - color = "#f2d5d7" - greyscale_colors = "#f2d5d796" + color = "#62708A" + greyscale_colors = "#62708A" alpha = 150 starlight_color = COLOR_MODERATE_BLUE categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) @@ -468,8 +476,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/sandstone name = "sandstone" desc = "Bialtaakid 'ant taerif ma hdha." - color = "#B77D31" - greyscale_colors = "#B77D31" + color = "#ECD5A8" + greyscale_colors = "#ECD5A8" categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/sandstone value_per_unit = 5 / SHEET_MATERIAL_AMOUNT @@ -498,8 +506,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/runedmetal name = "runed metal" desc = "Mir'ntrath barhah Nar'sie." - color = "#3C3434" - greyscale_colors = "#3C3434" + color = "#504742" + greyscale_colors = "#504742" categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/runed_metal value_per_unit = 1500 / SHEET_MATERIAL_AMOUNT @@ -515,8 +523,8 @@ Unless you know what you're doing, only use the first three numbers. They're in /datum/material/bronze name = "bronze" desc = "Clock Cult? Never heard of it." - color = "#92661A" - greyscale_colors = "#92661A" + color = "#876223" + greyscale_colors = "#876223" categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/bronze value_per_unit = 50 / SHEET_MATERIAL_AMOUNT diff --git a/code/datums/memory/_memory.dm b/code/datums/memory/_memory.dm index 0656d32006a24..08a694616a336 100644 --- a/code/datums/memory/_memory.dm +++ b/code/datums/memory/_memory.dm @@ -392,7 +392,7 @@ if(istype(character, /datum/mind)) var/datum/mind/character_mind = character - return "\the [lowertext(initial(character_mind.assigned_role.title))]" + return "\the [LOWER_TEXT(initial(character_mind.assigned_role.title))]" // Generic result - mobs get "the guy", objs / turfs get "a thing" return ismob(character) ? "\the [character]" : "\a [character]" diff --git a/code/datums/memory/general_memories.dm b/code/datums/memory/general_memories.dm index c71014b63b46d..b8c44c6fca862 100644 --- a/code/datums/memory/general_memories.dm +++ b/code/datums/memory/general_memories.dm @@ -643,7 +643,7 @@ /datum/memory/playing_cards/get_starts() return list( - "[formatted_players_list] are waiting for [protagonist_name] to start the [game]", + "[formatted_players_list] waiting for [protagonist_name] to start the [game]", "The [game] has been setup by [deuteragonist_name]", "[deuteragonist_name] starts shuffling the deck for the [game]", ) @@ -668,7 +668,7 @@ /datum/memory/playing_card_pickup/get_starts() return list( - "[protagonist_name] tosses the [antagonist_name] at [deuteragonist_name] spilling cards all over the floor", + "[protagonist_name] tossing the [antagonist_name] at [deuteragonist_name] spilling cards all over the floor", "A [antagonist_name] thrown by [protagonist_name] splatters across [deuteragonist_name] face", ) diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 0cfb48f7a9823..0e54c21e70234 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -474,6 +474,11 @@ mood_change = -6 timeout = 5 MINUTES +/datum/mood_event/mallet_humiliation + description = "Getting hit by such a stupid weapon feels rather humiliating..." + mood_change = -3 + timeout = 10 SECONDS + ///Wizard cheesy grand finale - what everyone but the wizard gets /datum/mood_event/madness_despair description = "UNWORTHY, UNWORTHY, UNWORTHY!!!" diff --git a/code/datums/mood_events/needs_events.dm b/code/datums/mood_events/needs_events.dm index 72d789da1e062..dd5441476dcfb 100644 --- a/code/datums/mood_events/needs_events.dm +++ b/code/datums/mood_events/needs_events.dm @@ -66,7 +66,7 @@ mood_change = -12 /datum/mood_event/disgust/dirty_food - description = "It was too dirty to eat..." + description = "That was too dirty to eat..." mood_change = -6 timeout = 4 MINUTES diff --git a/code/controllers/subsystem/movement/move_handler.dm b/code/datums/move_manager.dm similarity index 91% rename from code/controllers/subsystem/movement/move_handler.dm rename to code/datums/move_manager.dm index fcc5c1c65048b..23ddcbecdb707 100644 --- a/code/controllers/subsystem/movement/move_handler.dm +++ b/code/datums/move_manager.dm @@ -17,16 +17,15 @@ * * You can find the logic for this control in this file * - * Specifics of how different loops operate can be found in the movement_types.dm file, alongside the [add to loop][/datum/controller/subsystem/move_manager/proc/add_to_loop] helper procs that use them + * Specifics of how different loops operate can be found in the movement_types.dm file, alongside the [add to loop][/datum/move_manager/proc/add_to_loop] helper procs that use them * **/ -SUBSYSTEM_DEF(move_manager) - name = "Movement Handler" - flags = SS_NO_INIT | SS_NO_FIRE - runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME +/datum/move_manager + +GLOBAL_DATUM_INIT(move_manager, /datum/move_manager, new) ///Adds a movable thing to a movement subsystem. Returns TRUE if it all worked, FALSE if it failed somehow -/datum/controller/subsystem/move_manager/proc/add_to_loop(atom/movable/thing_to_add, datum/controller/subsystem/movement/subsystem = SSmovement, datum/move_loop/loop_type, priority = MOVEMENT_DEFAULT_PRIORITY, flags, datum/extra_info) +/datum/move_manager/proc/add_to_loop(atom/movable/thing_to_add, datum/controller/subsystem/movement/subsystem = SSmovement, datum/move_loop/loop_type, priority = MOVEMENT_DEFAULT_PRIORITY, flags, datum/extra_info) var/datum/movement_packet/our_data = thing_to_add.move_packet if(!our_data) our_data = new(thing_to_add) @@ -35,7 +34,7 @@ SUBSYSTEM_DEF(move_manager) return our_data.add_loop(arglist(arguments)) ///Returns the subsystem's loop if we're processing on it, null otherwise -/datum/controller/subsystem/move_manager/proc/processing_on(atom/movable/packet_owner, datum/controller/subsystem/movement/subsystem) +/datum/move_manager/proc/processing_on(atom/movable/packet_owner, datum/controller/subsystem/movement/subsystem) var/datum/movement_packet/packet = packet_owner.move_packet if(!packet) return diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 37f23218043af..b45d0a6499e83 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -20,7 +20,7 @@ owner.Unconscious(200 * GET_MUTATION_POWER(src)) owner.set_jitter(2000 SECONDS * GET_MUTATION_POWER(src)) //yes this number looks crazy but the jitter animations are amplified based on the duration. owner.add_mood_event("epilepsy", /datum/mood_event/epilepsy) - addtimer(CALLBACK(src, PROC_REF(jitter_less)), 90) + addtimer(CALLBACK(src, PROC_REF(jitter_less)), 9 SECONDS) /datum/mutation/human/epilepsy/proc/jitter_less() if(QDELETED(owner)) @@ -267,15 +267,42 @@ desc = "The user's muscles slightly expand." quality = POSITIVE text_gain_indication = "You feel strong." + instability = 5 difficulty = 16 +/datum/mutation/human/strong/on_acquiring(mob/living/carbon/human/owner) + . = ..() + if(.) + return + ADD_TRAIT(owner, TRAIT_STRENGTH, GENETIC_MUTATION) + +/datum/mutation/human/strong/on_losing(mob/living/carbon/human/owner) + . = ..() + if(.) + return + REMOVE_TRAIT(owner, TRAIT_STRENGTH, GENETIC_MUTATION) + + /datum/mutation/human/stimmed name = "Stimmed" desc = "The user's chemical balance is more robust." quality = POSITIVE text_gain_indication = "You feel stimmed." + instability = 5 difficulty = 16 +/datum/mutation/human/stimmed/on_acquiring(mob/living/carbon/human/owner) + . = ..() + if(.) + return + ADD_TRAIT(owner, TRAIT_STIMMED, GENETIC_MUTATION) + +/datum/mutation/human/stimmed/on_losing(mob/living/carbon/human/owner) + . = ..() + if(.) + return + REMOVE_TRAIT(owner, TRAIT_STIMMED, GENETIC_MUTATION) + /datum/mutation/human/insulated name = "Insulated" desc = "The affected person does not conduct electricity." diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index 5db065609644a..63e0abc22a33f 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -277,4 +277,22 @@ TRAIT_STUNIMMUNE, ) // no chunk +/datum/mutation/human/hulk/superhuman + health_req = 0 + instability = 0 + /// List of traits to add/remove when someone gets this mutation. + mutation_traits = list( + TRAIT_CHUNKYFINGERS, + TRAIT_HULK, + TRAIT_IGNOREDAMAGESLOWDOWN, + TRAIT_NOSOFTCRIT, + TRAIT_NOHARDCRIT, + TRAIT_PUSHIMMUNE, + TRAIT_STUNIMMUNE, + TRAIT_ANALGESIA, + ) // fight till your last breath + +/datum/mutation/human/hulk/superhuman/on_life(seconds_per_tick, times_fired) + return + #undef HULK_TAILTHROW_STEPS diff --git a/code/datums/mutations/olfaction.dm b/code/datums/mutations/olfaction.dm index e014806233a7b..305f6d16e8389 100644 --- a/code/datums/mutations/olfaction.dm +++ b/code/datums/mutations/olfaction.dm @@ -40,6 +40,10 @@ to_chat(owner, span_warning("You have no nose!")) return FALSE + if(HAS_TRAIT(living_cast_on, TRAIT_ANOSMIA)) //Anosmia quirk holders can't smell anything + to_chat(owner, span_warning("You can't smell!")) + return FALSE + return TRUE /datum/action/cooldown/spell/olfaction/cast(mob/living/cast_on) diff --git a/code/datums/proximity_monitor/field.dm b/code/datums/proximity_monitor/field.dm index 12c033cc4260e..67bbef948ef3d 100644 --- a/code/datums/proximity_monitor/field.dm +++ b/code/datums/proximity_monitor/field.dm @@ -27,35 +27,59 @@ /datum/proximity_monitor/advanced/proc/cleanup_field() for(var/turf/turf as anything in edge_turfs) cleanup_edge_turf(turf) + edge_turfs = list() for(var/turf/turf as anything in field_turfs) cleanup_field_turf(turf) + field_turfs = list() //Call every time the field moves (done automatically if you use update_center) or a setup specification is changed. -/datum/proximity_monitor/advanced/proc/recalculate_field() +/datum/proximity_monitor/advanced/proc/recalculate_field(full_recalc = FALSE) var/list/new_turfs = update_new_turfs() - var/list/new_field_turfs = new_turfs[FIELD_TURFS_KEY] - var/list/new_edge_turfs = new_turfs[EDGE_TURFS_KEY] + var/list/old_field_turfs = field_turfs + var/list/old_edge_turfs = edge_turfs + field_turfs = new_turfs[FIELD_TURFS_KEY] + edge_turfs = new_turfs[EDGE_TURFS_KEY] + if(!full_recalc) + field_turfs = list() + edge_turfs = list() - for(var/turf/old_turf as anything in field_turfs) - if(!(old_turf in new_field_turfs)) - cleanup_field_turf(old_turf) - for(var/turf/old_turf as anything in edge_turfs) + for(var/turf/old_turf as anything in old_field_turfs - field_turfs) + if(QDELETED(src)) + return + cleanup_field_turf(old_turf) + for(var/turf/old_turf as anything in old_edge_turfs - edge_turfs) + if(QDELETED(src)) + return cleanup_edge_turf(old_turf) - for(var/turf/new_turf as anything in new_field_turfs) - field_turfs |= new_turf + if(full_recalc) + old_field_turfs = list() + old_edge_turfs = list() + field_turfs = new_turfs[FIELD_TURFS_KEY] + edge_turfs = new_turfs[EDGE_TURFS_KEY] + + for(var/turf/new_turf as anything in field_turfs - old_field_turfs) + if(QDELETED(src)) + return + field_turfs += new_turf setup_field_turf(new_turf) - for(var/turf/new_turf as anything in new_edge_turfs) - edge_turfs |= new_turf + for(var/turf/new_turf as anything in edge_turfs - old_edge_turfs) + if(QDELETED(src)) + return + edge_turfs += new_turf setup_edge_turf(new_turf) -/datum/proximity_monitor/advanced/on_entered(turf/source, atom/movable/entered) +/datum/proximity_monitor/advanced/on_initialized(turf/location, atom/created, init_flags) + . = ..() + on_entered(location, created, null) + +/datum/proximity_monitor/advanced/on_entered(turf/source, atom/movable/entered, turf/old_loc) . = ..() if(get_dist(source, host) == current_range) - field_edge_crossed(entered, source) + field_edge_crossed(entered, old_loc, source) else - field_turf_crossed(entered, source) + field_turf_crossed(entered, old_loc, source) /datum/proximity_monitor/advanced/on_moved(atom/movable/movable, atom/old_loc) . = ..() @@ -68,21 +92,22 @@ if(isturf(old_loc)) cleanup_field() return - recalculate_field() + recalculate_field(full_recalc = FALSE) /datum/proximity_monitor/advanced/on_uncrossed(turf/source, atom/movable/gone, direction) if(get_dist(source, host) == current_range) - field_edge_uncrossed(gone, source) + field_edge_uncrossed(gone, source, get_turf(gone)) else - field_turf_uncrossed(gone, source) + field_turf_uncrossed(gone, source, get_turf(gone)) /// Called when a turf in the field of the monitor is linked /datum/proximity_monitor/advanced/proc/setup_field_turf(turf/target) return /// Called when a turf in the field of the monitor is unlinked +/// Do NOT call this manually, requires management of the field_turfs list /datum/proximity_monitor/advanced/proc/cleanup_field_turf(turf/target) - field_turfs -= target + return /// Called when a turf in the edge of the monitor is linked /datum/proximity_monitor/advanced/proc/setup_edge_turf(turf/target) @@ -90,21 +115,22 @@ setup_field_turf(target) /// Called when a turf in the edge of the monitor is unlinked +/// Do NOT call this manually, requires management of the edge_turfs list /datum/proximity_monitor/advanced/proc/cleanup_edge_turf(turf/target) if(edge_is_a_field) // If the edge is considered a field, clean it up like one cleanup_field_turf(target) - edge_turfs -= target /datum/proximity_monitor/advanced/proc/update_new_turfs() - . = list(FIELD_TURFS_KEY = list(), EDGE_TURFS_KEY = list()) if(ignore_if_not_on_turf && !isturf(host.loc)) - return + return list(FIELD_TURFS_KEY = list(), EDGE_TURFS_KEY = list()) + var/list/local_field_turfs = list() + var/list/local_edge_turfs = list() var/turf/center = get_turf(host) - for(var/turf/target in RANGE_TURFS(current_range, center)) - if(get_dist(center, target) == current_range) - .[EDGE_TURFS_KEY] += target - else - .[FIELD_TURFS_KEY] += target + if(current_range > 0) + local_field_turfs += RANGE_TURFS(current_range - 1, center) + if(current_range > 1) + local_edge_turfs = local_field_turfs - RANGE_TURFS(current_range, center) + return list(FIELD_TURFS_KEY = local_field_turfs, EDGE_TURFS_KEY = local_edge_turfs) //Gets edge direction/corner, only works with square radius/WDH fields! /datum/proximity_monitor/advanced/proc/get_edgeturf_direction(turf/T, turf/center_override = null) @@ -124,19 +150,19 @@ if(T.y == (checking_from.y + current_range)) return NORTH -/datum/proximity_monitor/advanced/proc/field_turf_crossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/proc/field_turf_crossed(atom/movable/movable, turf/old_location, turf/new_location) return -/datum/proximity_monitor/advanced/proc/field_turf_uncrossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/proc/field_turf_uncrossed(atom/movable/movable, turf/old_location, turf/new_location) return -/datum/proximity_monitor/advanced/proc/field_edge_crossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/proc/field_edge_crossed(atom/movable/movable, turf/old_location, turf/new_location) if(edge_is_a_field) // If the edge is considered a field, pass crossed to that - field_turf_crossed(movable, location) + field_turf_crossed(movable, old_location, new_location) -/datum/proximity_monitor/advanced/proc/field_edge_uncrossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/proc/field_edge_uncrossed(atom/movable/movable, turf/old_location, turf/new_location) if(edge_is_a_field) // If the edge is considered a field, pass uncrossed to that - field_turf_uncrossed(movable, location) + field_turf_uncrossed(movable, old_location, new_location) //DEBUG FIELD ITEM /obj/item/multitool/field_debug @@ -153,7 +179,7 @@ current = new(src, 5, FALSE) current.set_fieldturf_color = "#aaffff" current.set_edgeturf_color = "#ffaaff" - current.recalculate_field() + current.recalculate_field(full_recalc = TRUE) /obj/item/multitool/field_debug/attack_self(mob/user) operating = !operating diff --git a/code/datums/proximity_monitor/fields/ai_target_tracking.dm b/code/datums/proximity_monitor/fields/ai_target_tracking.dm new file mode 100644 index 0000000000000..46cde22aaffce --- /dev/null +++ b/code/datums/proximity_monitor/fields/ai_target_tracking.dm @@ -0,0 +1,113 @@ +// Proximity monitor that checks to see if anything interesting enters our bounds +/datum/proximity_monitor/advanced/ai_target_tracking + edge_is_a_field = TRUE + /// The ai behavior who owns us + var/datum/ai_behavior/find_potential_targets/owning_behavior + /// The ai controller we're using + var/datum/ai_controller/controller + /// The target key we're trying to fill + var/target_key + /// The targeting strategy KEY we're using + var/targeting_strategy_key + /// The hiding location key we're using + var/hiding_location_key + + /// The targeting strategy we're using + var/datum/targeting_strategy/filter + /// If we've built our field yet + /// Prevents wasted work on the first build (since the behavior did it) + var/first_build = TRUE + +// Initially, run the check manually +// If that fails, set up a field and have it manage the behavior fully +/datum/proximity_monitor/advanced/ai_target_tracking/New(atom/_host, range, _ignore_if_not_on_turf = TRUE, datum/ai_behavior/find_potential_targets/owning_behavior, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) + . = ..() + src.owning_behavior = owning_behavior + src.controller = controller + src.target_key = target_key + src.targeting_strategy_key = targeting_strategy_key + src.hiding_location_key = hiding_location_key + src.filter = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key]) + RegisterSignal(controller, COMSIG_QDELETING, PROC_REF(controller_deleted)) + RegisterSignal(controller, COMSIG_AI_CONTROLLER_PICKED_BEHAVIORS, PROC_REF(controller_think)) + RegisterSignal(controller, COMSIG_AI_CONTROLLER_POSSESSED_PAWN, PROC_REF(pawn_changed)) + RegisterSignal(controller, AI_CONTROLLER_BEHAVIOR_QUEUED(owning_behavior.type), PROC_REF(behavior_requeued)) + RegisterSignal(controller, COMSIG_AI_BLACKBOARD_KEY_SET(targeting_strategy_key), PROC_REF(targeting_datum_changed)) + RegisterSignal(controller, COMSIG_AI_BLACKBOARD_KEY_CLEARED(targeting_strategy_key), PROC_REF(targeting_datum_cleared)) + recalculate_field(full_recalc = TRUE) + +/datum/proximity_monitor/advanced/ai_target_tracking/Destroy() + . = ..() + if(!QDELETED(controller) && owning_behavior) + controller.modify_cooldown(owning_behavior, owning_behavior.get_cooldown(controller)) + owning_behavior = null + controller = null + target_key = null + targeting_strategy_key = null + hiding_location_key = null + filter = null + +/datum/proximity_monitor/advanced/ai_target_tracking/recalculate_field(full_recalc = FALSE) + . = ..() + first_build = FALSE + +/datum/proximity_monitor/advanced/ai_target_tracking/setup_field_turf(turf/target) + . = ..() + if(first_build) + return + owning_behavior.new_turf_found(target, controller, filter) + +/datum/proximity_monitor/advanced/ai_target_tracking/field_turf_crossed(atom/movable/movable, turf/location, turf/old_location) + . = ..() + + if(!owning_behavior.atom_allowed(movable, filter, controller.pawn)) + return + + owning_behavior.new_atoms_found(list(movable), controller, target_key, filter, hiding_location_key) + +/// React to controller planning +/datum/proximity_monitor/advanced/ai_target_tracking/proc/controller_deleted(datum/source) + SIGNAL_HANDLER + qdel(src) + +/// React to the pawn goin byebye +/datum/proximity_monitor/advanced/ai_target_tracking/proc/pawn_changed(datum/source) + SIGNAL_HANDLER + qdel(src) + +/// React to controller planning +/datum/proximity_monitor/advanced/ai_target_tracking/proc/controller_think(datum/ai_controller/source, list/datum/ai_behavior/old_behaviors, list/datum/ai_behavior/new_behaviors) + SIGNAL_HANDLER + // If our parent was forgotten, nuke ourselves + if(!new_behaviors[owning_behavior]) + qdel(src) + +/datum/proximity_monitor/advanced/ai_target_tracking/proc/behavior_requeued(datum/source, list/new_arguments) + SIGNAL_HANDLER + check_new_args(arglist(new_arguments)) + +/// Ensure our args and locals are up to date +/datum/proximity_monitor/advanced/ai_target_tracking/proc/check_new_args(target_key, targeting_strategy_key, hiding_location_key) + var/update_filter = FALSE + if(src.target_key != target_key) + src.target_key = target_key + if(src.targeting_strategy_key != targeting_strategy_key) + src.targeting_strategy_key = targeting_strategy_key + update_filter = TRUE + if(src.hiding_location_key != hiding_location_key) + src.hiding_location_key = hiding_location_key + if(update_filter) + targeting_datum_changed(null) + +/datum/proximity_monitor/advanced/ai_target_tracking/proc/targeting_datum_changed(datum/source) + SIGNAL_HANDLER + filter = controller.blackboard[targeting_strategy_key] + // Filter changed, need to do a full reparse + // Fucking 9 * 9 out here I stg + for(var/turf/in_field as anything in field_turfs + edge_turfs) + owning_behavior.new_turf_found(in_field, controller, filter) + +/datum/proximity_monitor/advanced/ai_target_tracking/proc/targeting_datum_cleared(datum/source) + SIGNAL_HANDLER + // Go fuckin home bros + qdel(src) diff --git a/code/datums/proximity_monitor/fields/gravity.dm b/code/datums/proximity_monitor/fields/gravity.dm index e26042676576b..b7e22840041dc 100644 --- a/code/datums/proximity_monitor/fields/gravity.dm +++ b/code/datums/proximity_monitor/fields/gravity.dm @@ -7,7 +7,7 @@ /datum/proximity_monitor/advanced/gravity/New(atom/_host, range, _ignore_if_not_on_turf = TRUE, gravity) . = ..() gravity_value = gravity - recalculate_field() + recalculate_field(full_recalc = TRUE) /datum/proximity_monitor/advanced/gravity/setup_field_turf(turf/target) . = ..() @@ -42,15 +42,15 @@ for(var/mob/living/guy in target) warn_mob(guy, target) -/datum/proximity_monitor/advanced/gravity/warns_on_entrance/field_edge_crossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/gravity/warns_on_entrance/field_edge_crossed(atom/movable/movable, turf/old_location, turf/new_location) . = ..() if(isliving(movable)) - warn_mob(movable, location) + warn_mob(movable, new_location) -/datum/proximity_monitor/advanced/gravity/warns_on_entrance/field_edge_uncrossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/gravity/warns_on_entrance/field_edge_uncrossed(atom/movable/movable, turf/old_location, turf/new_location) . = ..() if(isliving(movable)) - warn_mob(movable, location) + warn_mob(movable, old_location) /datum/proximity_monitor/advanced/gravity/warns_on_entrance/proc/warn_mob(mob/living/to_warn, turf/location) var/mob_ref_key = REF(to_warn) diff --git a/code/datums/proximity_monitor/fields/projectile_dampener.dm b/code/datums/proximity_monitor/fields/projectile_dampener.dm index 705ac6bfacee8..3e696e5fb132d 100644 --- a/code/datums/proximity_monitor/fields/projectile_dampener.dm +++ b/code/datums/proximity_monitor/fields/projectile_dampener.dm @@ -19,7 +19,7 @@ /datum/proximity_monitor/advanced/projectile_dampener/New(atom/_host, range, _ignore_if_not_on_turf = TRUE, atom/projector) ..() RegisterSignal(projector, COMSIG_QDELETING, PROC_REF(on_projector_del)) - recalculate_field() + recalculate_field(full_recalc = TRUE) START_PROCESSING(SSfastprocess, src) /datum/proximity_monitor/advanced/projectile_dampener/Destroy() @@ -48,7 +48,7 @@ LAZYSET(edgeturf_effects, target, effect) /datum/proximity_monitor/advanced/projectile_dampener/on_z_change(datum/source) - recalculate_field() + recalculate_field(full_recalc = TRUE) /datum/proximity_monitor/advanced/projectile_dampener/cleanup_edge_turf(turf/target) . = ..() @@ -90,16 +90,15 @@ /datum/proximity_monitor/advanced/projectile_dampener/proc/on_projector_del(datum/source) SIGNAL_HANDLER - qdel(src) -/datum/proximity_monitor/advanced/projectile_dampener/field_edge_uncrossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/projectile_dampener/field_edge_uncrossed(atom/movable/movable, turf/old_location, turf/new_location) if(isprojectile(movable) && get_dist(movable, host) > current_range) if(movable in tracked) release_projectile(movable) -/datum/proximity_monitor/advanced/projectile_dampener/field_edge_crossed(atom/movable/movable, turf/location) - if(isprojectile(movable) && !(movable in tracked)) +/datum/proximity_monitor/advanced/projectile_dampener/field_edge_crossed(atom/movable/movable, turf/location, turf/old_location) + if(isprojectile(movable)) capture_projectile(movable) /datum/proximity_monitor/advanced/projectile_dampener/peaceborg/process(seconds_per_tick) diff --git a/code/datums/proximity_monitor/fields/timestop.dm b/code/datums/proximity_monitor/fields/timestop.dm index c48759c1debd6..79996dee2dd36 100644 --- a/code/datums/proximity_monitor/fields/timestop.dm +++ b/code/datums/proximity_monitor/fields/timestop.dm @@ -82,7 +82,7 @@ src.immune = immune src.antimagic_flags = antimagic_flags src.channelled = channelled - recalculate_field() + recalculate_field(full_recalc = TRUE) START_PROCESSING(SSfastprocess, src) /datum/proximity_monitor/advanced/timestop/Destroy() @@ -93,7 +93,7 @@ STOP_PROCESSING(SSfastprocess, src) return ..() -/datum/proximity_monitor/advanced/timestop/field_turf_crossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/timestop/field_turf_crossed(atom/movable/movable, turf/old_location, turf/new_location) freeze_atom(movable) /datum/proximity_monitor/advanced/timestop/proc/freeze_atom(atom/movable/A) @@ -214,7 +214,7 @@ frozen_mobs += victim victim.Stun(20, ignore_canstun = TRUE) victim.add_traits(list(TRAIT_MUTE, TRAIT_EMOTEMUTE), TIMESTOP_TRAIT) - SSmove_manager.stop_looping(victim) //stops them mid pathing even if they're stunimmune //This is really dumb + GLOB.move_manager.stop_looping(victim) //stops them mid pathing even if they're stunimmune //This is really dumb if(isanimal(victim)) var/mob/living/simple_animal/animal_victim = victim animal_victim.toggle_ai(AI_OFF) diff --git a/code/datums/proximity_monitor/proximity_monitor.dm b/code/datums/proximity_monitor/proximity_monitor.dm index fc28212202d97..ec77ce2145a1f 100644 --- a/code/datums/proximity_monitor/proximity_monitor.dm +++ b/code/datums/proximity_monitor/proximity_monitor.dm @@ -11,7 +11,7 @@ var/static/list/loc_connections = list( COMSIG_ATOM_ENTERED = PROC_REF(on_entered), COMSIG_ATOM_EXITED = PROC_REF(on_uncrossed), - COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(on_entered), + COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(on_initialized), ) /datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) @@ -78,7 +78,12 @@ SIGNAL_HANDLER return //Used by the advanced subtype for effect fields. -/datum/proximity_monitor/proc/on_entered(atom/source, atom/movable/arrived) +/datum/proximity_monitor/proc/on_entered(atom/source, atom/movable/arrived, turf/old_loc) SIGNAL_HANDLER if(source != host) hasprox_receiver?.HasProximity(arrived) + +/datum/proximity_monitor/proc/on_initialized(turf/location, atom/created, init_flags) + SIGNAL_HANDLER + if(location != host) + hasprox_receiver?.HasProximity(created) diff --git a/code/datums/quirks/_quirk.dm b/code/datums/quirks/_quirk.dm index becf3b45d7b12..7fb8e9a5cc237 100644 --- a/code/datums/quirks/_quirk.dm +++ b/code/datums/quirks/_quirk.dm @@ -167,7 +167,7 @@ * * default_location - If the item isn't possible to equip in a valid slot, this is a description of where the item was spawned. * * notify_player - If TRUE, adds strings to where_items_spawned list to be output to the player in [/datum/quirk/item_quirk/post_add()] */ -/datum/quirk/item_quirk/proc/give_item_to_holder(quirk_item, list/valid_slots, flavour_text = null, default_location = "at your feet", notify_player = TRUE) +/datum/quirk/item_quirk/proc/give_item_to_holder(obj/item/quirk_item, list/valid_slots, flavour_text = null, default_location = "at your feet", notify_player = TRUE) if(ispath(quirk_item)) quirk_item = new quirk_item(get_turf(quirk_holder)) diff --git a/code/datums/quirks/negative_quirks/addict.dm b/code/datums/quirks/negative_quirks/addict.dm index 46c1edd5cb652..f97dae32c260f 100644 --- a/code/datums/quirks/negative_quirks/addict.dm +++ b/code/datums/quirks/negative_quirks/addict.dm @@ -194,13 +194,16 @@ customization_options = list(/datum/preference/choiced/alcoholic) /datum/quirk/item_quirk/addict/alcoholic/New() - drug_container_type = GLOB.possible_alcoholic_addictions[pick(GLOB.possible_alcoholic_addictions["bottlepath"])] + var/random_alcohol = pick(GLOB.possible_alcoholic_addictions) + drug_container_type = GLOB.possible_alcoholic_addictions[random_alcohol]["bottlepath"] + favorite_alcohol = GLOB.possible_alcoholic_addictions[random_alcohol]["reagent"] return ..() /datum/quirk/item_quirk/addict/alcoholic/add_unique(client/client_source) var/addiction = client_source?.prefs.read_preference(/datum/preference/choiced/alcoholic) if(addiction && (addiction != "Random")) drug_container_type = GLOB.possible_alcoholic_addictions[addiction]["bottlepath"] + favorite_alcohol = GLOB.possible_alcoholic_addictions[addiction]["reagent"] return ..() /datum/quirk/item_quirk/addict/alcoholic/post_add() @@ -210,10 +213,7 @@ if(isnull(brandy_container)) stack_trace("Alcoholic quirk added while the GLOB.alcohol_containers is (somehow) not initialized!") brandy_container = new drug_container_type - favorite_alcohol = brandy_container["reagent"] qdel(brandy_container) - else - favorite_alcohol = brandy_container["reagent"] quirk_holder.add_mob_memory(/datum/memory/key/quirk_alcoholic, protagonist = quirk_holder, preferred_brandy = initial(favorite_alcohol.name)) // alcoholic livers have 25% less health and healing diff --git a/code/datums/quirks/negative_quirks/all_nighter.dm b/code/datums/quirks/negative_quirks/all_nighter.dm index 0062537fde8ff..f5288b8221560 100644 --- a/code/datums/quirks/negative_quirks/all_nighter.dm +++ b/code/datums/quirks/negative_quirks/all_nighter.dm @@ -30,30 +30,42 @@ ///adds the corresponding moodlet and visual effects /datum/quirk/all_nighter/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(on_removed_limb)) quirk_holder.add_mood_event("all_nighter", /datum/mood_event/all_nighter) add_bags() ///removes the corresponding moodlet and visual effects /datum/quirk/all_nighter/remove(client/client_source) + UnregisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB) quirk_holder.clear_mood_event("all_nighter", /datum/mood_event/all_nighter) - remove_bags() + if(bodypart_overlay) + remove_bags() + +///if we have bags and lost a head, remove them +/datum/quirk/all_nighter/proc/on_removed_limb(datum/source, obj/item/bodypart/removed_limb, special, dismembered) + SIGNAL_HANDLER + + if(bodypart_overlay && istype(removed_limb, /obj/item/bodypart/head)) + remove_bags() ///adds the bag overlay -/datum/quirk/all_nighter/proc/add_bags(client/client_source) +/datum/quirk/all_nighter/proc/add_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder - var/obj/item/bodypart/head/face = sleepy_head.get_bodypart(BODY_ZONE_HEAD) + var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) + if(isnull(face)) + return bodypart_overlay = new() //creates our overlay face.add_bodypart_overlay(bodypart_overlay) sleepy_head.update_body_parts() //make sure to update icon ///removes the bag overlay -/datum/quirk/all_nighter/proc/remove_bags(client/client_source) +/datum/quirk/all_nighter/proc/remove_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder - var/obj/item/bodypart/head/face = sleepy_head.get_bodypart(BODY_ZONE_HEAD) - //our overlay is stored as a datum var, so referencing it is easy - face.remove_bodypart_overlay(bodypart_overlay) + var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) + if(face) + face.remove_bodypart_overlay(bodypart_overlay) + sleepy_head.update_body_parts() QDEL_NULL(bodypart_overlay) - sleepy_head.update_body_parts() /** *Here we actively handle our moodlet & eye bags, adding/removing them as necessary diff --git a/code/datums/quirks/negative_quirks/anosmia.dm b/code/datums/quirks/negative_quirks/anosmia.dm new file mode 100644 index 0000000000000..bbbf599aeaab4 --- /dev/null +++ b/code/datums/quirks/negative_quirks/anosmia.dm @@ -0,0 +1,9 @@ +/datum/quirk/item_quirk/anosmia + name = "Anosmia" + desc = "For some reason, you can't smell anything." + icon = FA_ICON_HEAD_SIDE_COUGH_SLASH + value = -2 + mob_trait = TRAIT_ANOSMIA + gain_text = span_notice("You find yourself unable to smell anything!") + lose_text = span_danger("Suddenly, you can smell again!") + medical_record_text = "Patient has lost their sensation of smell." diff --git a/code/datums/quirks/negative_quirks/insanity.dm b/code/datums/quirks/negative_quirks/insanity.dm index 56b56a5381216..40e70f07b1831 100644 --- a/code/datums/quirks/negative_quirks/insanity.dm +++ b/code/datums/quirks/negative_quirks/insanity.dm @@ -25,7 +25,7 @@ added_trauma.resilience = TRAUMA_RESILIENCE_ABSOLUTE added_trauma.name = name added_trauma.desc = medical_record_text - added_trauma.scan_desc = lowertext(name) + added_trauma.scan_desc = LOWER_TEXT(name) added_trauma.gain_text = null added_trauma.lose_text = null @@ -33,7 +33,7 @@ added_trama_ref = WEAKREF(added_trauma) /datum/quirk/insanity/post_add() - var/rds_policy = get_policy("[type]") || "Please note that your [lowertext(name)] does NOT give you any additional right to attack people or cause chaos." + var/rds_policy = get_policy("[type]") || "Please note that your [LOWER_TEXT(name)] does NOT give you any additional right to attack people or cause chaos." // I don't /think/ we'll need this, but for newbies who think "roleplay as insane" = "license to kill", it's probably a good thing to have. to_chat(quirk_holder, span_big(span_info(rds_policy))) diff --git a/code/datums/quirks/negative_quirks/social_anxiety.dm b/code/datums/quirks/negative_quirks/social_anxiety.dm index 046ac4715f57c..2f28a646b320c 100644 --- a/code/datums/quirks/negative_quirks/social_anxiety.dm +++ b/code/datums/quirks/negative_quirks/social_anxiety.dm @@ -84,7 +84,7 @@ if(prob(85) || (istype(mind_check) && mind_check.mind)) return - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, span_smallnotice("You make eye contact with [A].")), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, span_smallnotice("You make eye contact with [A].")), 0.3 SECONDS) /datum/quirk/social_anxiety/proc/eye_contact(datum/source, mob/living/other_mob, triggering_examiner) SIGNAL_HANDLER diff --git a/code/datums/quirks/neutral_quirks/bald.dm b/code/datums/quirks/neutral_quirks/bald.dm index 8a760f6ceefdb..2844b790ddfd3 100644 --- a/code/datums/quirks/neutral_quirks/bald.dm +++ b/code/datums/quirks/neutral_quirks/bald.dm @@ -21,7 +21,7 @@ /datum/quirk/item_quirk/bald/add_unique(client/client_source) var/obj/item/clothing/head/wig/natural/baldie_wig = new(get_turf(quirk_holder)) if(old_hair == "Bald") - baldie_wig.hairstyle = pick(GLOB.hairstyles_list - "Bald") + baldie_wig.hairstyle = pick(SSaccessories.hairstyles_list - "Bald") else baldie_wig.hairstyle = old_hair diff --git a/code/datums/quirks/neutral_quirks/transhumanist.dm b/code/datums/quirks/neutral_quirks/transhumanist.dm index 88923d463f697..046c2bb30f089 100644 --- a/code/datums/quirks/neutral_quirks/transhumanist.dm +++ b/code/datums/quirks/neutral_quirks/transhumanist.dm @@ -15,7 +15,7 @@ /datum/quirk/transhumanist name = "Transhumanist" - desc = "You see silicon life as the perfect lifeform and despise organic flesh. You are happier around silicons, but get frustrated when around organics. You seek to replace your fleshy limbs with their silicon counterparts. You start with a robotic limb." + desc = "You see silicon life as the perfect lifeform and despise organic flesh. You are happier around silicons, but get frustrated when around organics. You seek to replace your failing flesh with perfect silicon. You start with a robotic augmentation." icon = FA_ICON_ROBOT quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES|QUIRK_MOODLET_BASED value = 0 @@ -29,7 +29,8 @@ /obj/item/toy/figure/borg, ) var/slot_string - var/obj/item/bodypart/old_limb + var/obj/item/old_part + /datum/quirk/transhumanist/add(client/client_source) RegisterSignal(quirk_holder, COMSIG_CARBON_POST_ATTACH_LIMB, PROC_REF(calculate_bodypart_score)) @@ -100,27 +101,59 @@ if(-INFINITY to 0) quirk_holder.add_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART, /datum/mood_event/very_organic) +/datum/quirk_constant_data/transhumanist + associated_typepath = /datum/quirk/transhumanist + customization_options = list(/datum/preference/choiced/trans_prosthetic) /datum/quirk/transhumanist/add_unique(client/client_source) - var/limb_type = GLOB.limb_choice_transhuman[client_source?.prefs?.read_preference(/datum/preference/choiced/prosthetic)] - if(isnull(limb_type)) //Client gone or they chose a random prosthetic - limb_type = GLOB.limb_choice_transhuman[pick(GLOB.limb_choice_transhuman)] + var/part_type = GLOB.part_choice_transhuman[client_source?.prefs?.read_preference(/datum/preference/choiced/trans_prosthetic)] + if(isnull(part_type)) //Client gone or they chose a random part + part_type = GLOB.part_choice_transhuman[pick(GLOB.part_choice_transhuman)] var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/bodypart/new_part = new limb_type() - - slot_string = "[new_part.plaintext_zone]" - old_limb = human_holder.return_and_replace_bodypart(new_part, special = TRUE) + var/obj/item/new_part = new part_type() + if(isbodypart(new_part)) + var/obj/item/bodypart/new_bodypart = new_part + slot_string = new_bodypart.plaintext_zone + old_part = human_holder.return_and_replace_bodypart(new_bodypart, special = TRUE) + else if(isorgan(new_part)) + var/obj/item/organ/new_organ = new_part + old_part = human_holder.get_organ_slot(new_organ.slot) + if(new_organ.Insert(human_holder, special = TRUE)) + old_part.moveToNullspace() + STOP_PROCESSING(SSobj, old_part) + slot_string = new_organ.name /datum/quirk/transhumanist/post_add() - if(slot_string) - to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a robot arm. You need to use a welding tool and cables to repair it, instead of sutures and regenerative meshes.")) + if(!slot_string) + return + if(isbodypart(old_part)) + to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a robotic limb. You need to use a welding tool and cables to repair it, instead of sutures and regenerative meshes.")) + else if (old_part.name == "eyes") + to_chat(quirk_holder, span_boldannounce("You replaced your eyes with flashlights, not cameras. You can't see a thing!")) + else if (isorgan(old_part)) + to_chat(quirk_holder, span_boldannounce("Your [slot_string] brings you one step closer to silicon perfection, but you feel you're not quite there yet.")) /datum/quirk/transhumanist/remove() - if(old_limb) - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.del_and_replace_bodypart(old_limb, special = TRUE) - old_limb = null + if(isnull(old_part)) + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART) + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_PEOPLE) + return + + var/mob/living/carbon/human/human_holder = quirk_holder + if(isbodypart(old_part)) + var/obj/item/bodypart/old_bodypart = old_part + human_holder.del_and_replace_bodypart(old_bodypart, special = TRUE) + old_bodypart = null + else if(isorgan(old_part)) + var/obj/item/organ/old_organ = old_part + old_part = human_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + old_organ.Insert(quirk_holder, special = TRUE) + old_part.moveToNullspace() + STOP_PROCESSING(SSobj, old_part) + old_organ = null + old_part = null + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART) quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_PEOPLE) diff --git a/code/datums/quirks/positive_quirks/strong_stomach.dm b/code/datums/quirks/positive_quirks/strong_stomach.dm new file mode 100644 index 0000000000000..8c0a3f3b1375e --- /dev/null +++ b/code/datums/quirks/positive_quirks/strong_stomach.dm @@ -0,0 +1,12 @@ +/datum/quirk/strong_stomach + name = "Strong Stomach" + desc = "You can eat food discarded on the ground without getting sick, and vomiting affects you less." + icon = FA_ICON_FACE_GRIN_BEAM_SWEAT + value = 4 + mob_trait = TRAIT_STRONG_STOMACH + gain_text = span_notice("You feel like you could eat anything!") + lose_text = span_danger("Looking at food on the ground makes you feel a little queasy.") + medical_record_text = "Patient has a stronger than average immune system...to food poisoning, at least." + mail_goodies = list( + /obj/item/reagent_containers/pill/ondansetron, + ) diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm index 40d7ef49bd4c7..b1322d09d5622 100644 --- a/code/datums/ruins/lavaland.dm +++ b/code/datums/ruins/lavaland.dm @@ -30,7 +30,7 @@ suffix = "lavaland_biodome_clown_planet.dmm" /datum/map_template/ruin/lavaland/lizgas - name = "The Lizard's Gas(Lava)" + name = "Lava-Ruin The Lizard's Gas" id = "lizgas2" description = "A recently opened gas station from the Lizard's Gas franchise." suffix = "lavaland_surface_gas.dmm" diff --git a/code/datums/shuttles/pirate.dm b/code/datums/shuttles/pirate.dm index c6f94b5684b7a..99f866d23fc61 100644 --- a/code/datums/shuttles/pirate.dm +++ b/code/datums/shuttles/pirate.dm @@ -29,3 +29,7 @@ /datum/map_template/shuttle/pirate/geode suffix = "geode" name = "pirate ship (Lustrous Geode)" + +/datum/map_template/shuttle/pirate/medieval + suffix = "medieval" + name = "pirate ship (Siege Pod)" diff --git a/code/datums/signals.dm b/code/datums/signals.dm index 97334253b4e5c..01ca02e41c264 100644 --- a/code/datums/signals.dm +++ b/code/datums/signals.dm @@ -38,7 +38,7 @@ if(exists) if(!override) - var/override_message = "[signal_type] overridden. Use override = TRUE to suppress this warning.\nTarget: [target] ([target.type]) Proc: [proctype]" + var/override_message = "[signal_type] overridden. Use override = TRUE to suppress this warning.\nTarget: [target] ([target.type]) Existing Proc: [exists] New Proc: [proctype]" log_signal(override_message) stack_trace(override_message) return @@ -120,7 +120,9 @@ // all the objects that are receiving the signal get the signal this final time. // AKA: No you can't cancel the signal reception of another object by doing an unregister in the same signal. var/list/queued_calls = list() - for(var/datum/listening_datum as anything in target) - queued_calls[listening_datum] = listening_datum._signal_procs[src][sigtype] - for(var/datum/listening_datum as anything in queued_calls) - . |= call(listening_datum, queued_calls[listening_datum])(arglist(arguments)) + // This should be faster than doing `var/datum/listening_datum as anything in target` as it does not implicitly copy the list + for(var/i in 1 to length(target)) + var/datum/listening_datum = target[i] + queued_calls.Add(listening_datum, listening_datum._signal_procs[src][sigtype]) + for(var/i in 1 to length(queued_calls) step 2) + . |= call(queued_calls[i], queued_calls[i + 1])(arglist(arguments)) diff --git a/code/datums/skills/athletics.dm b/code/datums/skills/athletics.dm new file mode 100644 index 0000000000000..ac9d5e415a14e --- /dev/null +++ b/code/datums/skills/athletics.dm @@ -0,0 +1,41 @@ +/datum/skill/athletics + name = "Athletics" + title = "Athlete" + desc = "Twinkle twinkle little star, hit the gym and lift the bar." + // The skill value modifier effects the max duration that is possible for /datum/status_effect/exercised; The rands modifier determines block probability and crit probability while boxing against boxers + modifiers = list( + SKILL_VALUE_MODIFIER = list( + 1 MINUTES, + 1.5 MINUTES, + 2 MINUTES, + 2.5 MINUTES, + 3 MINUTES, + 3.5 MINUTES, + 5 MINUTES + ), + SKILL_RANDS_MODIFIER = list( + 0, + 5, + 10, + 15, + 20, + 30, + 50 + ) + ) + + skill_item_path = /obj/item/clothing/gloves/boxing/golden + +/datum/skill/athletics/New() + . = ..() + levelUpMessages[SKILL_LEVEL_NOVICE] = span_nicegreen("I am just getting started on my [name] journey! I think I should be able to identify other people who are working to improve their body by sight.") + +/datum/skill/athletics/level_gained(datum/mind/mind, new_level, old_level, silent) + . = ..() + if(new_level >= SKILL_LEVEL_NOVICE && old_level < SKILL_LEVEL_NOVICE) + ADD_TRAIT(mind, TRAIT_EXAMINE_FITNESS, SKILL_TRAIT) + +/datum/skill/athletics/level_lost(datum/mind/mind, new_level, old_level, silent) + . = ..() + if(old_level >= SKILL_LEVEL_NOVICE && new_level < SKILL_LEVEL_NOVICE) + REMOVE_TRAIT(mind, TRAIT_EXAMINE_FITNESS, SKILL_TRAIT) diff --git a/code/datums/skills/fitness.dm b/code/datums/skills/fitness.dm deleted file mode 100644 index 32be3f9d21174..0000000000000 --- a/code/datums/skills/fitness.dm +++ /dev/null @@ -1,23 +0,0 @@ -/datum/skill/fitness - name = "Fitness" - title = "Powerlifter" - desc = "Twinkle twinkle little star, hit the gym and lift the bar." - /// The skill value modifier effects the max duration that is possible for /datum/status_effect/exercised - modifiers = list(SKILL_VALUE_MODIFIER = list(1 MINUTES, 1.5 MINUTES, 2 MINUTES, 2.5 MINUTES, 3 MINUTES, 3.5 MINUTES, 5 MINUTES)) - /// How much bigger your mob becomes per level (these effects don't stack together) - var/static/size_boost = list(0, 1/16, 1/8, 3/16, 2/8, 3/8, 4/8) - // skill_item_path - your mob sprite gets bigger to showoff so we don't get a special item - -/datum/skill/fitness/level_gained(datum/mind/mind, new_level, old_level, silent) - . = ..() - var/old_gym_size = RESIZE_DEFAULT_SIZE + size_boost[old_level] - var/new_gym_size = RESIZE_DEFAULT_SIZE + size_boost[new_level] - - mind.current.update_transform(new_gym_size / old_gym_size) - -/datum/skill/fitness/level_lost(datum/mind/mind, new_level, old_level, silent) - . = ..() - var/old_gym_size = RESIZE_DEFAULT_SIZE + size_boost[old_level] - var/new_gym_size = RESIZE_DEFAULT_SIZE + size_boost[new_level] - - mind.current.update_transform(new_gym_size / old_gym_size) diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm index 1584f9c4db877..e6e8b956e6568 100644 --- a/code/datums/sprite_accessories.dm +++ b/code/datums/sprite_accessories.dm @@ -16,35 +16,6 @@ * conversion in savefile.dm */ -/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female, add_blank)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked - if(!istype(L)) - L = list() - if(!istype(male)) - male = list() - if(!istype(female)) - female = list() - - for(var/path in subtypesof(prototype)) - var/datum/sprite_accessory/D = new path() - - if(D.icon_state) - L[D.name] = D - else - L += D.name - - switch(D.gender) - if(MALE) - male += D.name - if(FEMALE) - female += D.name - else - male += D.name - female += D.name - if(add_blank) - L[SPRITE_ACCESSORY_NONE] = new /datum/sprite_accessory/blank - - return L - /datum/sprite_accessory /// The icon file the accessory is located in. var/icon @@ -1739,17 +1710,17 @@ /datum/sprite_accessory/body_markings/dtiger name = "Dark Tiger Body" icon_state = "dtiger" - gender_specific = 1 + gender_specific = TRUE /datum/sprite_accessory/body_markings/ltiger name = "Light Tiger Body" icon_state = "ltiger" - gender_specific = 1 + gender_specific = TRUE /datum/sprite_accessory/body_markings/lbelly name = "Light Belly" icon_state = "lbelly" - gender_specific = 1 + gender_specific = TRUE /datum/sprite_accessory/tails em_block = TRUE @@ -1787,14 +1758,12 @@ icon_state = "default" color_src = HAIR_COLOR -/datum/sprite_accessory/tails/monkey +/datum/sprite_accessory/tails/monkey/default + name = "Monkey" icon = 'icons/mob/human/species/monkey/monkey_tail.dmi' + icon_state = "default" color_src = FALSE -/datum/sprite_accessory/tails/monkey/standard - name = "Monkey" - icon_state = "monkey" - /datum/sprite_accessory/pod_hair icon = 'icons/mob/human/species/podperson_hair.dmi' em_block = TRUE diff --git a/code/datums/station_traits/admin_panel.dm b/code/datums/station_traits/admin_panel.dm index 02eca48b54f0c..67669027c54d0 100644 --- a/code/datums/station_traits/admin_panel.dm +++ b/code/datums/station_traits/admin_panel.dm @@ -1,10 +1,6 @@ -/// Opens the station traits admin panel -/datum/admins/proc/station_traits_panel() - set name = "Modify Station Traits" - set category = "Admin.Events" - +ADMIN_VERB(station_traits_panel, R_FUN, "Modify Station Traits", "Modify the station traits for the next round.", ADMIN_CATEGORY_EVENTS) var/static/datum/station_traits_panel/station_traits_panel = new - station_traits_panel.ui_interact(usr) + station_traits_panel.ui_interact(user.mob) /datum/station_traits_panel var/static/list/future_traits diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm index 917bb6c7210bd..c0950bfdd7b93 100644 --- a/code/datums/station_traits/negative_traits.dm +++ b/code/datums/station_traits/negative_traits.dm @@ -149,7 +149,7 @@ /datum/station_trait/overflow_job_bureaucracy/proc/set_overflow_job_override(datum/source) SIGNAL_HANDLER var/datum/job/picked_job = pick(SSjob.get_valid_overflow_jobs()) - chosen_job_name = lowertext(picked_job.title) // like Chief Engineers vs like chief engineers + chosen_job_name = LOWER_TEXT(picked_job.title) // like Chief Engineers vs like chief engineers SSjob.set_overflow_role(picked_job.type) /datum/station_trait/slow_shuttle @@ -570,6 +570,8 @@ /datum/station_trait/nebula/hostile/radiation/New() . = ..() + RegisterSignal(SSdcs, COMSIG_RULESET_BODY_GENERATED_FROM_GHOSTS, PROC_REF(on_spawned_mob)) + for(var/area/target as anything in get_areas(radioactive_areas)) RegisterSignal(target, COMSIG_AREA_ENTERED, PROC_REF(on_entered)) RegisterSignal(target, COMSIG_AREA_EXITED, PROC_REF(on_exited)) @@ -591,7 +593,7 @@ //if engineering isnt valid, just send it to the bridge send_supply_pod_to_area(supply_pack_shielding.generate(null), /area/station/command/bridge, /obj/structure/closet/supplypod/centcompod) - // Let the viro know resistence is futile + // Let medical know resistence is futile send_fax_to_area(new /obj/item/paper/fluff/radiation_nebula_virologist(), /area/station/medical/virology, "NT Virology Department", \ force = TRUE, force_pod_type = /obj/structure/closet/supplypod/centcompod) @@ -617,6 +619,19 @@ // The component handles its own removal +/// When a mob is spawned by dynamic, intercept and give it a little radiation shield. Only works for dynamic mobs! +/datum/station_trait/nebula/hostile/radiation/proc/on_spawned_mob(datum/source, mob/spawned_mob) + SIGNAL_HANDLER + + if(!istype(get_area(spawned_mob), radioactive_areas)) //only if you're spawned in the radioactive areas + return + + if(!isliving(spawned_mob)) // Dynamic shouldnt spawn non-living but uhhhhhhh why not + return + + var/mob/living/spawnee = spawned_mob + spawnee.apply_status_effect(/datum/status_effect/radiation_immunity/radnebula) + /datum/station_trait/nebula/hostile/radiation/apply_nebula_effect(effect_strength = 0) //big bombad now if(effect_strength > 0 && !SSmapping.is_planetary()) //admins can force this diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm index dda21308c96ee..8398e02139d74 100644 --- a/code/datums/station_traits/positive_traits.dm +++ b/code/datums/station_traits/positive_traits.dm @@ -233,7 +233,6 @@ /datum/job/security_officer = /obj/item/organ/internal/cyberimp/arm/flash, /datum/job/shaft_miner = /obj/item/organ/internal/monster_core/rush_gland, /datum/job/station_engineer = /obj/item/organ/internal/cyberimp/arm/toolset, - /datum/job/virologist = /obj/item/organ/internal/lungs/cybernetic/tier2, /datum/job/warden = /obj/item/organ/internal/cyberimp/eyes/hud/security, ) @@ -293,6 +292,15 @@ weight_multiplier = 3 max_occurrences_modifier = 10 //lotta cows +/datum/station_trait/bright_day + name = "Bright Day" + report_message = "The stars shine bright and the clouds are scarcer than usual. It's a bright day here on the Ice Moon's surface." + trait_type = STATION_TRAIT_POSITIVE + weight = 5 + show_in_report = TRUE + trait_flags = STATION_TRAIT_PLANETARY + trait_to_give = STATION_TRAIT_BRIGHT_DAY + /datum/station_trait/shuttle_sale name = "Shuttle Firesale" report_message = "The Nanotrasen Emergency Dispatch team is celebrating a record number of shuttle calls in the recent quarter. Some of your emergency shuttle options have been discounted!" diff --git a/code/datums/status_effects/_status_effect.dm b/code/datums/status_effects/_status_effect.dm index b8d77db4ff7f1..637f2c3a07672 100644 --- a/code/datums/status_effects/_status_effect.dm +++ b/code/datums/status_effects/_status_effect.dm @@ -13,7 +13,7 @@ /// -1 = will prevent ticks, and if duration is also unlimited (-1), stop processing wholesale. var/tick_interval = 1 SECONDS /// The mob affected by the status effect. - var/mob/living/owner + VAR_FINAL/mob/living/owner /// How many of the effect can be on one mob, and/or what happens when you try to add a duplicate. var/status_type = STATUS_EFFECT_UNIQUE /// If TRUE, we call [proc/on_remove] when owner is deleted. Otherwise, we call [proc/be_replaced]. @@ -22,7 +22,9 @@ /// Status effect "name"s and "description"s are shown to the owner here. var/alert_type = /atom/movable/screen/alert/status_effect /// The alert itself, created in [proc/on_creation] (if alert_type is specified). - var/atom/movable/screen/alert/status_effect/linked_alert + VAR_FINAL/atom/movable/screen/alert/status_effect/linked_alert + /// If TRUE, and we have an alert, we will show a duration on the alert + var/show_duration = FALSE /// Used to define if the status effect should be using SSfastprocess or SSprocessing var/processing_speed = STATUS_EFFECT_FAST_PROCESS /// Do we self-terminate when a fullheal is called? @@ -30,7 +32,7 @@ /// If remove_on_fullheal is TRUE, what flag do we need to be removed? var/heal_flag_necessary = HEAL_STATUS /// A particle effect, for things like embers - Should be set on update_particles() - var/obj/effect/abstract/particle_holder/particle_effect + VAR_FINAL/obj/effect/abstract/particle_holder/particle_effect /datum/status_effect/New(list/arguments) on_creation(arglist(arguments)) @@ -57,6 +59,7 @@ var/atom/movable/screen/alert/status_effect/new_alert = owner.throw_alert(id, alert_type) new_alert.attached_effect = src //so the alert can reference us, if it needs to linked_alert = new_alert //so we can reference the alert, if we need to + update_shown_duration() if(duration > world.time || tick_interval > world.time) //don't process if we don't care switch(processing_speed) @@ -86,14 +89,24 @@ QDEL_NULL(particle_effect) return ..() +/// Updates the status effect alert's maptext (if possible) +/datum/status_effect/proc/update_shown_duration() + PRIVATE_PROC(TRUE) + if(!linked_alert || !show_duration) + return + + linked_alert.maptext = MAPTEXT_TINY_UNICODE("[round((duration - world.time)/10, 1)]s") + // Status effect process. Handles adjusting its duration and ticks. // If you're adding processed effects, put them in [proc/tick] // instead of extending / overriding the process() proc. /datum/status_effect/process(seconds_per_tick) SHOULD_NOT_OVERRIDE(TRUE) + if(QDELETED(owner)) qdel(src) return + if(tick_interval != -1 && tick_interval < world.time) var/tick_length = initial(tick_interval) tick(tick_length / (1 SECONDS)) @@ -101,8 +114,12 @@ if(QDELING(src)) // tick deleted us, no need to continue return - if(duration != -1 && duration < world.time) - qdel(src) + + if(duration != -1) + if(duration < world.time) + qdel(src) + return + update_shown_duration() /// Called whenever the effect is applied in on_created /// Returning FALSE will cause it to delete itself during creation instead. @@ -185,24 +202,25 @@ qdel(src) return TRUE + update_shown_duration() return FALSE /** * Updates the particles for the status effects * Should be handled by subtypes! */ - /datum/status_effect/proc/update_particles() SHOULD_CALL_PARENT(FALSE) + return /// Alert base type for status effect alerts /atom/movable/screen/alert/status_effect name = "Curse of Mundanity" desc = "You don't feel any different..." + maptext_y = 2 /// The status effect we're linked to var/datum/status_effect/attached_effect /atom/movable/screen/alert/status_effect/Destroy() attached_effect = null //Don't keep a ref now return ..() - diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 6cd180ab5970e..27824567a4dba 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -114,6 +114,7 @@ id = "fleshmend" duration = 10 SECONDS alert_type = /atom/movable/screen/alert/status_effect/fleshmend + show_duration = TRUE /datum/status_effect/fleshmend/on_apply() . = ..() @@ -195,6 +196,9 @@ if(HAS_TRAIT(new_owner, TRAIT_HULK)) modifier += 0.5 + if(HAS_TRAIT(new_owner, TRAIT_STIMMED)) // Naturally produces stimulants to help get you PUMPED + modifier += 1 + if(HAS_TRAIT(new_owner, TRAIT_FAT)) // less xp until you get into shape modifier -= 0.5 @@ -209,10 +213,10 @@ if(new_owner.reagents.has_reagent(workout_reagent)) food_boost += supplementary_reagents_bonus[workout_reagent] - var/skill_level_boost = (new_owner.mind.get_skill_level(/datum/skill/fitness) - 1) * 2 SECONDS + var/skill_level_boost = (new_owner.mind.get_skill_level(/datum/skill/athletics) - 1) * 2 SECONDS bonus_time = (bonus_time + food_boost + skill_level_boost) * modifier - var/exhaustion_limit = new_owner.mind.get_skill_modifier(/datum/skill/fitness, SKILL_VALUE_MODIFIER) + world.time + var/exhaustion_limit = new_owner.mind.get_skill_modifier(/datum/skill/athletics, SKILL_VALUE_MODIFIER) + world.time if(duration + bonus_time >= exhaustion_limit) duration = exhaustion_limit to_chat(new_owner, span_userdanger("Your muscles are exhausted! Might be a good idea to sleep...")) @@ -228,10 +232,10 @@ /datum/status_effect/exercised/refresh(mob/living/new_owner, bonus_time) duration += workout_duration(new_owner, bonus_time) new_owner.clear_mood_event("exercise") // we need to reset the old mood event in case our fitness skill changes - new_owner.add_mood_event("exercise", /datum/mood_event/exercise, new_owner.mind.get_skill_level(/datum/skill/fitness)) + new_owner.add_mood_event("exercise", /datum/mood_event/exercise, new_owner.mind.get_skill_level(/datum/skill/athletics)) /datum/status_effect/exercised/on_apply() - owner.add_mood_event("exercise", /datum/mood_event/exercise, owner.mind.get_skill_level(/datum/skill/fitness)) + owner.add_mood_event("exercise", /datum/mood_event/exercise, owner.mind.get_skill_level(/datum/skill/athletics)) return ..() /datum/status_effect/exercised/on_remove() @@ -376,6 +380,7 @@ duration = 1 MINUTES status_type = STATUS_EFFECT_REPLACE alert_type = /atom/movable/screen/alert/status_effect/regenerative_core + show_duration = TRUE /datum/status_effect/regenerative_core/on_apply() ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, STATUS_EFFECT_TRAIT) @@ -395,6 +400,7 @@ id = "Lightning Orb" duration = 30 SECONDS alert_type = /atom/movable/screen/alert/status_effect/lightningorb + show_duration = TRUE /datum/status_effect/lightningorb/on_apply() . = ..() @@ -457,6 +463,7 @@ id = "speed_boost" duration = 2 SECONDS status_type = STATUS_EFFECT_REPLACE + show_duration = TRUE /datum/status_effect/speed_boost/on_creation(mob/living/new_owner, set_duration) if(isnum(set_duration)) @@ -594,3 +601,24 @@ /datum/status_effect/jump_jet/on_remove() owner.RemoveElement(/datum/element/forced_gravity, 0) + +/// Makes the mob immune to radiation for a short bit to help with safely spawning in hazardous areas +/datum/status_effect/radiation_immunity + id = "radiation_immunity" + duration = 1 MINUTES + show_duration = TRUE + +/datum/status_effect/radiation_immunity/on_apply() + ADD_TRAIT(owner, TRAIT_RADIMMUNE, type) + return TRUE + +/datum/status_effect/radiation_immunity/on_remove() + REMOVE_TRAIT(owner, TRAIT_RADIMMUNE, type) + +/datum/status_effect/radiation_immunity/radnebula + alert_type = /atom/movable/screen/alert/status_effect/radiation_immunity + +/atom/movable/screen/alert/status_effect/radiation_immunity + name = "Radiation shielding" + desc = "You're immune to radiation, get settled quick!" + icon_state = "radiation_shield" diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 0b5e09267504d..199840d44ec1b 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -224,7 +224,7 @@ var/datum/status_effect/exercised/exercised = carbon_owner.has_status_effect(/datum/status_effect/exercised) if(exercised && carbon_owner.mind) // the better you sleep, the more xp you gain - carbon_owner.mind.adjust_experience(/datum/skill/fitness, seconds_between_ticks * sleep_quality * SLEEP_QUALITY_WORKOUT_MULTIPLER) + carbon_owner.mind.adjust_experience(/datum/skill/athletics, seconds_between_ticks * sleep_quality * SLEEP_QUALITY_WORKOUT_MULTIPLER) carbon_owner.adjust_timed_status_effect(-1 * seconds_between_ticks * sleep_quality * SLEEP_QUALITY_WORKOUT_MULTIPLER, /datum/status_effect/exercised) if(prob(2)) to_chat(carbon_owner, span_notice("You feel your fitness improving!")) @@ -601,7 +601,7 @@ // The brain trauma itself does its own set of logging, but this is the only place the source of the hypnosis phrase can be found. hearing_speaker.log_message("hypnotised [key_name(C)] with the phrase '[hearing_args[HEARING_RAW_MESSAGE]]'", LOG_ATTACK, color="red") C.log_message("has been hypnotised by the phrase '[hearing_args[HEARING_RAW_MESSAGE]]' spoken by [key_name(hearing_speaker)]", LOG_VICTIM, color="orange", log_globally = FALSE) - addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, gain_trauma), /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 10) + addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, gain_trauma), /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 1 SECONDS) addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living, Stun), 60, TRUE, TRUE), 15) //Take some time to think about it qdel(src) @@ -663,6 +663,7 @@ duration = 150 status_type = STATUS_EFFECT_REFRESH alert_type = /atom/movable/screen/alert/status_effect/convulsing + show_duration = TRUE /datum/status_effect/convulsing/on_creation(mob/living/zappy_boy) . = ..() diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm index 5bf8269bbbfda..62f8c9ca24e32 100644 --- a/code/datums/status_effects/debuffs/fire_stacks.dm +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -261,6 +261,7 @@ /datum/status_effect/fire_handler/fire_stacks/on_apply() . = ..() RegisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_fire_overlay)) + RegisterSignal(owner, COMSIG_ATOM_EXTINGUISH, PROC_REF(extinguish)) owner.update_appearance(UPDATE_OVERLAYS) /datum/status_effect/fire_handler/fire_stacks/proc/add_fire_overlay(mob/living/source, list/overlays) diff --git a/code/datums/status_effects/debuffs/rust_corruption.dm b/code/datums/status_effects/debuffs/rust_corruption.dm new file mode 100644 index 0000000000000..6ba9d6a4ee958 --- /dev/null +++ b/code/datums/status_effects/debuffs/rust_corruption.dm @@ -0,0 +1,12 @@ +/datum/status_effect/rust_corruption + alert_type = null + id = "rust_turf_effects" + tick_interval = 2 SECONDS + remove_on_fullheal = TRUE + +/datum/status_effect/rust_corruption/tick(seconds_between_ticks) + if(issilicon(owner)) + owner.adjustBruteLoss(10 * seconds_between_ticks) + return + owner.adjust_disgust(5 * seconds_between_ticks) + owner.reagents?.remove_all(0.75 * seconds_between_ticks) diff --git a/code/datums/status_effects/debuffs/speech_debuffs.dm b/code/datums/status_effects/debuffs/speech_debuffs.dm index 07bcd3c254317..4963a660b2245 100644 --- a/code/datums/status_effects/debuffs/speech_debuffs.dm +++ b/code/datums/status_effects/debuffs/speech_debuffs.dm @@ -187,7 +187,7 @@ /datum/status_effect/speech/slurring/apply_speech(original_char) var/modified_char = original_char - var/lower_char = lowertext(modified_char) + var/lower_char = LOWER_TEXT(modified_char) if(prob(common_prob) && (lower_char in common_replacements)) var/to_replace = common_replacements[lower_char] if(islist(to_replace)) diff --git a/code/datums/status_effects/food_effects.dm b/code/datums/status_effects/food_effects.dm index deba7bf750b6b..f36f1e2034d9c 100644 --- a/code/datums/status_effects/food_effects.dm +++ b/code/datums/status_effects/food_effects.dm @@ -4,6 +4,7 @@ duration = 5 MINUTES // Same as food mood buffs status_type = STATUS_EFFECT_REPLACE // Only one food buff allowed alert_type = /atom/movable/screen/alert/status_effect/food + show_duration = TRUE /// Buff power var/strength diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 42fad48509d6b..90e5a00334abf 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -74,6 +74,9 @@ /// If we support smartly removing/inserting things from ourselves var/supports_smart_equip = TRUE + ///do we insert items when clicked by them? + var/insert_on_attack = TRUE + /// An additional description shown on double-examine. /// Is autogenerated to the can_hold list if not set. var/can_hold_description @@ -113,6 +116,10 @@ /// If TRUE, shows the contents of the storage in open_storage var/display_contents = TRUE + /// Switch this off if you want to handle click_alt in the parent atom + var/click_alt_open = TRUE + + /datum/storage/New( atom/parent, max_slots = src.max_slots, @@ -192,13 +199,13 @@ parent = new_parent // a few of theses should probably be on the real_location rather than the parent + RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_ATTACK_HAND), PROC_REF(on_attack)) RegisterSignal(parent, COMSIG_MOUSEDROP_ONTO, PROC_REF(on_mousedrop_onto)) RegisterSignal(parent, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(on_mousedropped_onto)) - RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(on_preattack)) RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(mass_empty)) - RegisterSignals(parent, list(COMSIG_CLICK_ALT, COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), PROC_REF(open_storage_on_signal)) + RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), PROC_REF(open_storage_on_signal)) RegisterSignal(parent, COMSIG_ATOM_ATTACKBY_SECONDARY, PROC_REF(open_storage_attackby_secondary)) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(close_distance)) RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(update_actions)) @@ -207,6 +214,8 @@ RegisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(handle_extra_examination)) RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, PROC_REF(on_deconstruct)) RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act)) + RegisterSignal(parent, COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED, PROC_REF(contents_changed_w_class)) + RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_click_alt)) /** * Sets where items are physically being stored in the case it shouldn't be on the parent. @@ -401,7 +410,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) var/datum/storage/bigger_fish = parent.loc.atom_storage if(bigger_fish && bigger_fish.max_specific_storage < max_specific_storage) if(messages && user) - user.balloon_alert(user, "[lowertext(parent.loc.name)] is in the way!") + user.balloon_alert(user, "[LOWER_TEXT(parent.loc.name)] is in the way!") return FALSE if(isitem(parent)) @@ -437,11 +446,12 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) * * mob/user - (optional) the user who is inserting the item. * * override - see item_insertion_feedback() * * force - bypass locked storage up to a certain level. See [code/__DEFINES/storage.dm] + * * messages - if TRUE, we will create balloon alerts for the user. */ -/datum/storage/proc/attempt_insert(obj/item/to_insert, mob/user, override = FALSE, force = STORAGE_NOT_LOCKED) +/datum/storage/proc/attempt_insert(obj/item/to_insert, mob/user, override = FALSE, force = STORAGE_NOT_LOCKED, messages = TRUE) SHOULD_NOT_SLEEP(TRUE) - if(!can_insert(to_insert, user, force = force)) + if(!can_insert(to_insert, user, messages = messages, force = force)) return FALSE SEND_SIGNAL(parent, COMSIG_STORAGE_STORED_ITEM, to_insert, user, force) @@ -784,7 +794,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) /datum/storage/proc/on_attackby(datum/source, obj/item/thing, mob/user, params) SIGNAL_HANDLER - if(!thing.attackby_storage_insert(src, parent, user)) + if(!insert_on_attack || !thing.attackby_storage_insert(src, parent, user)) return if(iscyborg(user)) @@ -915,7 +925,19 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) SIGNAL_HANDLER INVOKE_ASYNC(src, PROC_REF(open_storage), to_show) - return COMPONENT_NO_AFTERATTACK + if(display_contents) + return COMPONENT_NO_AFTERATTACK + + +/// Alt click on the storage item. Default: Open the storage. +/datum/storage/proc/on_click_alt(datum/source, mob/user) + SIGNAL_HANDLER + + if(!click_alt_open) + return + + return open_storage_on_signal(source, user) + /// Opens the storage to the mob, showing them the contents to their UI. /datum/storage/proc/open_storage(mob/to_show) @@ -1092,3 +1114,14 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) var/matrix/old_matrix = parent.transform animate(parent, time = 1.5, loop = 0, transform = parent.transform.Scale(1.07, 0.9)) animate(time = 2, transform = old_matrix) + +/// Signal proc for [COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED] to drop items out of our storage if they're suddenly too heavy. +/datum/storage/proc/contents_changed_w_class(datum/source, obj/item/changed, old_w_class, new_w_class) + SIGNAL_HANDLER + + if(new_w_class <= max_specific_storage && new_w_class + get_total_weight() <= max_total_storage) + return + if(!attempt_remove(changed, parent.drop_location())) + return + + changed.visible_message(span_warning("[changed] falls out of [parent]!"), vision_distance = COMBAT_MESSAGE_RANGE) diff --git a/code/datums/storage/subtypes/bag_of_holding.dm b/code/datums/storage/subtypes/bag_of_holding.dm index 5abc171e2cb59..8a812d7064d51 100644 --- a/code/datums/storage/subtypes/bag_of_holding.dm +++ b/code/datums/storage/subtypes/bag_of_holding.dm @@ -4,7 +4,7 @@ max_slots = 30 allow_big_nesting = TRUE -/datum/storage/bag_of_holding/attempt_insert(obj/item/to_insert, mob/user, override, force) +/datum/storage/bag_of_holding/attempt_insert(obj/item/to_insert, mob/user, override, force, messages) var/list/obj/item/storage/backpack/holding/matching = typecache_filter_list(to_insert.get_all_contents(), typecacheof(/obj/item/storage/backpack/holding)) matching -= parent matching -= real_location diff --git a/code/datums/storage/subtypes/fish_case.dm b/code/datums/storage/subtypes/fish_case.dm index dbbb15f47eb05..82733d37ad985 100644 --- a/code/datums/storage/subtypes/fish_case.dm +++ b/code/datums/storage/subtypes/fish_case.dm @@ -24,25 +24,11 @@ var/obj/item/item_parent = parent if(arrived.w_class <= item_parent.w_class) return - item_parent.w_class = arrived.w_class - // Since we're changing weight class we need to check if our storage's loc's storage can still hold us - // in the future we need a generic solution to this to solve a bunch of other exploits - var/datum/storage/loc_storage = item_parent.loc.atom_storage - if(!isnull(loc_storage) && !loc_storage.can_insert(item_parent)) - item_parent.forceMove(item_parent.loc.drop_location()) - item_parent.visible_message(span_warning("[item_parent] spills out of [item_parent.loc] as it expands to hold [arrived]!"), vision_distance = 1) - return - - if(isliving(item_parent.loc)) - var/mob/living/living_loc = item_parent.loc - if((living_loc.get_slot_by_item(item_parent) & (ITEM_SLOT_RPOCKET|ITEM_SLOT_LPOCKET)) && item_parent.w_class > WEIGHT_CLASS_SMALL) - item_parent.forceMove(living_loc.drop_location()) - to_chat(living_loc, span_warning("[item_parent] drops out of your pockets as it expands to hold [arrived]!")) - return + item_parent.update_weight_class(arrived.w_class) /datum/storage/fish_case/handle_exit(datum/source, obj/item/gone) . = ..() if(!isitem(parent) || !istype(gone)) return var/obj/item/item_parent = parent - item_parent.w_class = initial(item_parent.w_class) + item_parent.update_weight_class(initial(item_parent.w_class)) diff --git a/code/datums/storage/subtypes/pockets.dm b/code/datums/storage/subtypes/pockets.dm index 67a8b2dda7804..d441c6fdc5ff6 100644 --- a/code/datums/storage/subtypes/pockets.dm +++ b/code/datums/storage/subtypes/pockets.dm @@ -4,7 +4,7 @@ max_total_storage = 50 rustle_sound = FALSE -/datum/storage/pockets/attempt_insert(obj/item/to_insert, mob/user, override, force) +/datum/storage/pockets/attempt_insert(obj/item/to_insert, mob/user, override, force, messages) . = ..() if(!.) return @@ -45,6 +45,7 @@ /datum/storage/pockets/small/fedora/detective attack_hand_interact = TRUE // so the detectives would discover pockets in their hats + click_alt_open = FALSE /datum/storage/pockets/chefhat attack_hand_interact = TRUE diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm index 052af9d060bee..21d4f460617b6 100644 --- a/code/datums/voice_of_god_command.dm +++ b/code/datums/voice_of_god_command.dm @@ -35,7 +35,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) if(!user.say(message, spans = span_list, sanitize = FALSE, ignore_spam = ignore_spam, forced = forced)) return - message = lowertext(message) + message = LOWER_TEXT(message) var/list/mob/living/listeners = list() //used to check if the speaker specified a name or a job to focus on @@ -299,7 +299,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) for(var/mob/living/target as anything in listeners) var/to_say = user.name // 0.1% chance to be a smartass - if(findtext(lowertext(message), smartass_regex) && prob(0.1)) + if(findtext(LOWER_TEXT(message), smartass_regex) && prob(0.1)) to_say = "My name" addtimer(CALLBACK(target, TYPE_PROC_REF(/atom/movable, say), to_say), 0.5 SECONDS * iteration) iteration++ diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm index 3f821a7129ada..76833f73ff5b0 100644 --- a/code/datums/votes/_vote_datum.dm +++ b/code/datums/votes/_vote_datum.dm @@ -15,25 +15,25 @@ var/list/default_choices /// Does the name of this vote contain the word "vote"? var/contains_vote_in_name = FALSE - /// What message do we want to pass to the player-side vote panel as a tooltip? - var/message = "Click to initiate a vote." + /// What message do we show as the tooltip of this vote if the vote can be initiated? + var/default_message = "Click to initiate a vote." + /// The counting method we use for votes. + var/count_method = VOTE_COUNT_METHOD_SINGLE + /// The method for selecting a winner. + var/winner_method = VOTE_WINNER_METHOD_SIMPLE + /// Should we show details about the number of votes submitted for each option? + var/display_statistics = TRUE // Internal values used when tracking ongoing votes. // Don't mess with these, change the above values / override procs for subtypes. /// An assoc list of [all choices] to [number of votes in the current running vote]. - var/list/choices = list() + VAR_FINAL/list/choices = list() /// A assoc list of [ckey] to [what they voted for in the current running vote]. - var/list/choices_by_ckey = list() + VAR_FINAL/list/choices_by_ckey = list() /// The world time this vote was started. - var/started_time + VAR_FINAL/started_time = -1 /// The time remaining in this vote's run. - var/time_remaining - /// The counting method we use for votes. - var/count_method = VOTE_COUNT_METHOD_SINGLE - /// The method for selecting a winner. - var/winner_method = VOTE_WINNER_METHOD_SIMPLE - /// Should we show details about the number of votes submitted for each option? - var/display_statistics = TRUE + VAR_FINAL/time_remaining = -1 /** * Used to determine if this vote is a possible @@ -55,14 +55,13 @@ choices.Cut() choices_by_ckey.Cut() started_time = null - time_remaining = null + time_remaining = -1 /** * If this vote has a config associated, toggles it between enabled and disabled. - * Returns TRUE on a successful toggle, FALSE otherwise */ -/datum/vote/proc/toggle_votable(mob/toggler) - return FALSE +/datum/vote/proc/toggle_votable() + return /** * If this vote has a config associated, returns its value (True or False, usually). @@ -74,20 +73,18 @@ /** * Checks if the passed mob can initiate this vote. * - * Return TRUE if the mob can begin the vote, allowing anyone to actually vote on it. - * Return FALSE if the mob cannot initiate the vote. + * * forced - if being invoked by someone who is an admin + * + * Return VOTE_AVAILABLE if the mob can initiate the vote. + * Return a string with the reason why the mob can't initiate the vote. */ -/datum/vote/proc/can_be_initiated(mob/by_who, forced = FALSE) +/datum/vote/proc/can_be_initiated(forced = FALSE) SHOULD_CALL_PARENT(TRUE) - if(started_time) - var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay)) - if(next_allowed_time > world.time && !forced) - message = "A vote was initiated recently. You must wait [DisplayTimeText(next_allowed_time - world.time)] before a new vote can be started!" - return FALSE + if(!forced && !is_config_enabled()) + return "This vote is currently disabled by the server configuration." - message = initial(message) - return TRUE + return VOTE_AVAILABLE /** * Called prior to the vote being initiated. diff --git a/code/datums/votes/custom_vote.dm b/code/datums/votes/custom_vote.dm index d67eb0281c6c6..78eb6d3b876d8 100644 --- a/code/datums/votes/custom_vote.dm +++ b/code/datums/votes/custom_vote.dm @@ -1,14 +1,9 @@ /// The max amount of options someone can have in a custom vote. #define MAX_CUSTOM_VOTE_OPTIONS 10 -/datum/vote/custom_vote/single - name = "Custom Standard" - message = "Click here to start a custom vote (one selection per voter)" - -/datum/vote/custom_vote/multi - name = "Custom Multi" - message = "Click here to start a custom multi vote (multiple selections per voter)" - count_method = VOTE_COUNT_METHOD_MULTI +/datum/vote/custom_vote + name = "Custom" + default_message = "Click here to start a custom vote." // Custom votes ares always accessible. /datum/vote/custom_vote/is_accessible_vote() @@ -17,23 +12,45 @@ /datum/vote/custom_vote/reset() default_choices = null override_question = null + count_method = VOTE_COUNT_METHOD_SINGLE return ..() -/datum/vote/custom_vote/can_be_initiated(mob/by_who, forced = FALSE) +/datum/vote/custom_vote/can_be_initiated(forced) . = ..() - if(!.) - return FALSE + if(. != VOTE_AVAILABLE) + return . + if(forced) + return . // Custom votes can only be created if they're forced to be made. // (Either an admin makes it, or otherwise.) - return forced + return "Only admins can create custom votes." /datum/vote/custom_vote/create_vote(mob/vote_creator) + var/custom_count_method = tgui_input_list( + user = vote_creator, + message = "Single or multiple choice?", + title = "Choice Method", + items = list("Single", "Multiple"), + default = "Single", + ) + switch(custom_count_method) + if("Single") + count_method = VOTE_COUNT_METHOD_SINGLE + if("Multiple") + count_method = VOTE_COUNT_METHOD_MULTI + if(null) + return FALSE + else + stack_trace("Got '[custom_count_method]' in create_vote() for custom voting.") + to_chat(vote_creator, span_boldwarning("Unknown choice method. Contact a coder.")) + return FALSE + var/custom_win_method = tgui_input_list( - vote_creator, - "How should the vote winner be determined?", - "Winner Method", - list("Simple", "Weighted Random", "No Winner"), + user = vote_creator, + message = "How should the vote winner be determined?", + title = "Winner Method", + items = list("Simple", "Weighted Random", "No Winner"), default = "Simple", ) switch(custom_win_method) @@ -43,7 +60,10 @@ winner_method = VOTE_WINNER_METHOD_WEIGHTED_RANDOM if("No Winner") winner_method = VOTE_WINNER_METHOD_NONE + if(null) + return FALSE else + stack_trace("Got '[custom_win_method]' in create_vote() for custom voting.") to_chat(vote_creator, span_boldwarning("Unknown winner method. Contact a coder.")) return FALSE @@ -54,7 +74,7 @@ list("Yes", "No"), ) - if(display_stats == null) + if(isnull(display_stats)) return FALSE display_statistics = display_stats == "Yes" @@ -74,6 +94,9 @@ if(!length(default_choices)) return FALSE + // Sanity for all the tgui input stalling we are doing + if(isnull(vote_creator.client?.holder)) + return FALSE return ..() diff --git a/code/datums/votes/map_vote.dm b/code/datums/votes/map_vote.dm index a07d87846f050..abe452ce4fedf 100644 --- a/code/datums/votes/map_vote.dm +++ b/code/datums/votes/map_vote.dm @@ -1,6 +1,6 @@ /datum/vote/map_vote name = "Map" - message = "Vote for next round's map!" + default_message = "Vote for next round's map!" count_method = VOTE_COUNT_METHOD_SINGLE winner_method = VOTE_WINNER_METHOD_WEIGHTED_RANDOM display_statistics = FALSE @@ -21,77 +21,62 @@ /datum/vote/map_vote/create_vote() . = ..() - check_population(should_key_choices = FALSE) - if(length(choices) == 1) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining map because it would just happen anyways. - var/de_facto_winner = choices[1] - var/datum/map_config/change_me_out = global.config.maplist[de_facto_winner] - SSmapping.changemap(change_me_out) - to_chat(world, span_boldannounce("The map vote has been skipped because there is only one map left to vote for. The map has been changed to [change_me_out.map_name].")) - SSmapping.map_voted = TRUE // voted by not voting, very sad. + if(!.) return FALSE -/datum/vote/map_vote/toggle_votable(mob/toggler) - if(!toggler) - CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") - if(!check_rights_for(toggler.client, R_ADMIN)) + choices -= get_choices_invalid_for_population() + if(length(choices) == 1) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining map because it would just happen anyways. + var/datum/map_config/change_me_out = global.config.maplist[choices[1]] + finalize_vote(choices[1])// voted by not voting, very sad. + to_chat(world, span_boldannounce("The map vote has been skipped because there is only one map left to vote for. \ + The map has been changed to [change_me_out.map_name].")) + return FALSE + if(length(choices) == 0) + to_chat(world, span_boldannounce("A map vote was called, but there are no maps to vote for! \ + Players, complain to the admins. Admins, complain to the coders.")) return FALSE - CONFIG_SET(flag/allow_vote_map, !CONFIG_GET(flag/allow_vote_map)) return TRUE +/datum/vote/map_vote/toggle_votable() + CONFIG_SET(flag/allow_vote_map, !CONFIG_GET(flag/allow_vote_map)) + /datum/vote/map_vote/is_config_enabled() return CONFIG_GET(flag/allow_vote_map) -/datum/vote/map_vote/can_be_initiated(mob/by_who, forced = FALSE) +/datum/vote/map_vote/can_be_initiated(forced) . = ..() - if(!.) - return FALSE - + if(. != VOTE_AVAILABLE) + return . if(forced) - return TRUE - - var/number_of_choices = length(check_population()) - if(number_of_choices < 2) - message = "There [number_of_choices == 1 ? "is only one map" : "are no maps"] to choose from." - return FALSE - + return VOTE_AVAILABLE + var/num_choices = length(default_choices - get_choices_invalid_for_population()) + if(num_choices <= 1) + return "There [num_choices == 1 ? "is only one map" : "are no maps"] to choose from." if(SSmapping.map_vote_rocked) - return TRUE - - if(!CONFIG_GET(flag/allow_vote_map)) - message = "Map voting is disabled by server configuration settings." - return FALSE - + return VOTE_AVAILABLE if(SSmapping.map_voted) - message = "The next map has already been selected." - return FALSE - - message = initial(message) - return TRUE - -/// Before we create a vote, remove all maps from our choices that are outside of our population range. -/// Note that this can result in zero remaining choices for our vote, which is not ideal (but ultimately okay). -/// Argument should_key_choices is TRUE, pass as FALSE in a context where choices are already keyed in a list. -/datum/vote/map_vote/proc/check_population(should_key_choices = TRUE) - if(should_key_choices) - for(var/key in default_choices) - choices[key] = 0 + return "The next map has already been selected." + return VOTE_AVAILABLE +/// Returns a list of all map options that are invalid for the current population. +/datum/vote/map_vote/proc/get_choices_invalid_for_population() var/filter_threshold = 0 if(SSticker.HasRoundStarted()) filter_threshold = get_active_player_count(alive_check = FALSE, afk_check = TRUE, human_check = FALSE) else filter_threshold = GLOB.clients.len - for(var/map in choices) + var/list/invalid_choices = list() + for(var/map in default_choices) var/datum/map_config/possible_config = config.maplist[map] if(possible_config.config_min_users > 0 && filter_threshold < possible_config.config_min_users) - choices -= map + invalid_choices += map else if(possible_config.config_max_users > 0 && filter_threshold > possible_config.config_max_users) - choices -= map + invalid_choices += map - return choices + return invalid_choices /datum/vote/map_vote/get_vote_result(list/non_voters) // Even if we have default no vote off, diff --git a/code/datums/votes/restart_vote.dm b/code/datums/votes/restart_vote.dm index 987d5b87eb363..3c74d7e518e28 100644 --- a/code/datums/votes/restart_vote.dm +++ b/code/datums/votes/restart_vote.dm @@ -7,7 +7,8 @@ CHOICE_RESTART, CHOICE_CONTINUE, ) - message = "Vote to restart the ongoing round." + default_message = "Vote to restart the ongoing round. \ + Only works if there are no non-AFK admins online." /// This proc checks to see if any admins are online for the purposes of this vote to see if it can pass. Returns TRUE if there are valid admins online (Has +SERVER and is not AFK), FALSE otherwise. /datum/vote/restart_vote/proc/admins_present() @@ -19,36 +20,24 @@ return FALSE -/datum/vote/restart_vote/toggle_votable(mob/toggler) - if(!toggler) - CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") - - if(!check_rights_for(toggler.client, R_ADMIN)) - return FALSE - +/datum/vote/restart_vote/toggle_votable() CONFIG_SET(flag/allow_vote_restart, !CONFIG_GET(flag/allow_vote_restart)) - return TRUE /datum/vote/restart_vote/is_config_enabled() return CONFIG_GET(flag/allow_vote_restart) -/datum/vote/restart_vote/can_be_initiated(mob/by_who, forced) +/datum/vote/restart_vote/create_vote(mob/vote_creator) . = ..() if(!.) - return FALSE - - if(!forced && !CONFIG_GET(flag/allow_vote_restart)) - message = "Restart voting is disabled by server configuration settings." - return FALSE - - // We still want players to be able to vote to restart even if valid admins are online. Let's update the message just so that the player is aware of this fact. - // We don't want to lock-out the vote though, so we'll return TRUE. - if(admins_present()) - message = "Regardless of the results of this vote, the round will not automatically restart because an admin is online." - return TRUE + return + if(!admins_present()) + return + async_alert_about_admins(vote_creator) - message = initial(message) - return TRUE +/datum/vote/restart_vote/proc/async_alert_about_admins(mob/vote_creator) + set waitfor = FALSE + tgui_alert(vote_creator, "Note: Regardless of the results of this vote, \ + the round will not automatically restart because an active admin is online.") /datum/vote/restart_vote/get_vote_result(list/non_voters) if(!CONFIG_GET(flag/default_no_vote)) diff --git a/code/datums/votes/rock_the_vote.dm b/code/datums/votes/rock_the_vote.dm index 6cffeb5ad6702..6c7ac4ff2572e 100644 --- a/code/datums/votes/rock_the_vote.dm +++ b/code/datums/votes/rock_the_vote.dm @@ -10,58 +10,40 @@ CHOICE_TO_ROCK, CHOICE_NOT_TO_ROCK, ) - message = "Override the current map vote." + default_message = "Override the current map vote." /// The number of times we have rocked the vote thus far. var/rocking_votes = 0 -/datum/vote/rock_the_vote/toggle_votable(mob/toggler) - if(!toggler) - CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") - if(!check_rights_for(toggler.client, R_ADMIN)) - return FALSE - +/datum/vote/rock_the_vote/toggle_votable() CONFIG_SET(flag/allow_rock_the_vote, !CONFIG_GET(flag/allow_rock_the_vote)) - return TRUE /datum/vote/rock_the_vote/is_config_enabled() return CONFIG_GET(flag/allow_rock_the_vote) -/datum/vote/rock_the_vote/can_be_initiated(mob/by_who, forced) +/datum/vote/rock_the_vote/can_be_initiated(forced) . = ..() - - if(!.) - return FALSE - - if(!forced && !CONFIG_GET(flag/allow_rock_the_vote)) - message = "Rocking the vote is disabled by this server's configuration settings." - return FALSE + if(. != VOTE_AVAILABLE) + return . if(SSticker.current_state == GAME_STATE_FINISHED) - message = "The game is finished, no map votes can be initiated." - return FALSE + return "The game is finished, no map votes can be initiated." if(rocking_votes >= CONFIG_GET(number/max_rocking_votes)) - message = "The maximum number of times to rock the vote has been reached." - return FALSE + return "The maximum number of times to rock the vote has been reached." if(SSmapping.map_vote_rocked) - message = "The vote has already been rocked! Initiate a map vote!" - return FALSE + return "The vote has already been rocked! Initiate a map vote!" if(!SSmapping.map_voted) - message = "Rocking the vote is disabled because no map has been voted on yet!" - return FALSE + return "Rocking the vote is disabled because no map has been voted on yet!" if(SSmapping.map_force_chosen) - message = "Rocking the vote is disabled because an admin has forcibly set the map!" - return FALSE + return "Rocking the vote is disabled because an admin has forcibly set the map!" if(EMERGENCY_ESCAPED_OR_ENDGAMED && SSmapping.map_voted) - message = "The emergency shuttle has already left the station and the next map has already been chosen!" - return FALSE + return "The emergency shuttle has already left the station and the next map has already been chosen!" - message = initial(message) - return TRUE + return VOTE_AVAILABLE /datum/vote/rock_the_vote/finalize_vote(winning_option) rocking_votes++ diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 99438be18cc02..c3c8a1c0e93e1 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -41,6 +41,9 @@ /// If every instance of these wires should be random. Prevents wires from showing up in station blueprints. var/randomize = FALSE + /// Lazy assoc list of refs to mobs to refs to photos they have studied for wires + var/list/studied_photos + /datum/wires/New(atom/holder) ..() if(!istype(holder, holder_type)) @@ -258,8 +261,13 @@ return TRUE // Station blueprints do that too, but only if the wires are not randomized. - if(user.is_holding_item_of_type(/obj/item/areaeditor/blueprints) && !randomize) - return TRUE + if(!randomize) + if(user.is_holding_item_of_type(/obj/item/blueprints)) + return TRUE + if(!isnull(user.mind)) + for(var/obj/item/photo/photo in user.held_items) + if(LAZYACCESS(studied_photos, REF(user.mind)) == REF(photo)) + return TRUE return FALSE @@ -274,6 +282,37 @@ /datum/wires/proc/always_reveal_wire(color) return FALSE +#define STUDY_INTERACTION_KEY "studying_photo" + +/** + * Attempts to study a photo for blueprints. + */ +/datum/wires/proc/try_study_photo(mob/user) + if(randomize) + return + if(isnull(user.mind)) + return + if(DOING_INTERACTION(user, STUDY_INTERACTION_KEY)) + return + if(LAZYACCESS(studied_photos, REF(user.mind))) + return + for(var/obj/item/photo/photo in user.held_items) + if(!photo.picture?.has_blueprints) + continue + + var/study_length = 1 SECONDS * floor(min(photo.picture.psize_x, photo.picture.psize_y) / 32) + if(study_length >= 4 SECONDS) + to_chat(user, span_notice("You squint [photo]... Hey, there's blueprints in the frame! Really wish the photo was zoomed in, though. \ + It's rather difficult to make out the wires.")) + else + to_chat(user, span_notice("You glance at [photo], looking for wires in the pictured blueprints.")) + + if(do_after(user, study_length, holder, interaction_key = STUDY_INTERACTION_KEY, hidden = TRUE)) + LAZYSET(studied_photos, REF(user.mind), REF(photo)) + return + +#undef STUDY_INTERACTION_KEY + /datum/wires/ui_host() return holder @@ -290,6 +329,7 @@ if (!ui) ui = new(user, src, "Wires", "[holder.name] Wires") ui.open() + try_study_photo(user) /datum/wires/ui_data(mob/user) var/list/data = list() diff --git a/code/datums/wires/airalarm.dm b/code/datums/wires/airalarm.dm index 2dc3244e9cac6..00291609871c3 100644 --- a/code/datums/wires/airalarm.dm +++ b/code/datums/wires/airalarm.dm @@ -34,13 +34,13 @@ if(!A.shorted) A.shorted = TRUE A.update_appearance() - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 1200) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 2 MINUTES) if(WIRE_IDSCAN) // Toggle lock. A.locked = !A.locked if(WIRE_AI) // Disable AI control for a while. if(!A.aidisabled) A.aidisabled = TRUE - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 100) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 10 SECONDS) if(WIRE_PANIC) // Toggle panic siphon. if(!A.shorted) if(istype(A.selected_mode, /datum/air_alarm_mode/filtering)) diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm index ca55dad954f6d..75c3a3687602f 100644 --- a/code/datums/wires/autolathe.dm +++ b/code/datums/wires/autolathe.dm @@ -29,13 +29,13 @@ switch(wire) if(WIRE_HACK) A.adjust_hacked(!A.hacked) - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 60) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 6 SECONDS) if(WIRE_SHOCK) A.shocked = !A.shocked - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 60) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 6 SECONDS) if(WIRE_DISABLE) A.disabled = !A.disabled - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 60) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 6 SECONDS) /datum/wires/autolathe/on_cut(wire, mend, source) var/obj/machinery/autolathe/A = holder diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 9911a7cdd5de0..9495d88cdc5a8 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -238,7 +238,7 @@ return FALSE if(user.grab_state == GRAB_PASSIVE) - to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [lowertext(name)]!")) + to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [LOWER_TEXT(name)]!")) return TRUE if(user.grab_state >= GRAB_AGGRESSIVE) diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index 4b104dedb3426..c6aaffe8483ab 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -74,7 +74,7 @@ if(victim.bodytemperature < (BODYTEMP_NORMAL - 10)) adjust_blood_flow(-0.1 * seconds_per_tick) if(SPT_PROB(2.5, seconds_per_tick)) - to_chat(victim, span_notice("You feel the [lowertext(name)] in your [limb.plaintext_zone] firming up from the cold!")) + to_chat(victim, span_notice("You feel the [LOWER_TEXT(name)] in your [limb.plaintext_zone] firming up from the cold!")) if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) adjust_blood_flow(0.25 * seconds_per_tick) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first diff --git a/code/game/area/areas/mining.dm b/code/game/area/areas/mining.dm index 1582f7390cf04..38855de366f9f 100644 --- a/code/game/area/areas/mining.dm +++ b/code/game/area/areas/mining.dm @@ -209,6 +209,11 @@ name = "Icemoon Wastes" outdoors = TRUE +/area/icemoon/surface/outdoors/Initialize(mapload) + if(HAS_TRAIT(SSstation, STATION_TRAIT_BRIGHT_DAY)) + base_lighting_alpha = 145 + return ..() + /area/icemoon/surface/outdoors/nospawn // this is the area you use for stuff to not spawn, but if you still want weather. /area/icemoon/surface/outdoors/nospawn/New() // unless you roll forested trait lol diff --git a/code/game/area/areas/ruins/icemoon.dm b/code/game/area/areas/ruins/icemoon.dm index 8afa3fae2d08f..5f51b602fa766 100644 --- a/code/game/area/areas/ruins/icemoon.dm +++ b/code/game/area/areas/ruins/icemoon.dm @@ -18,6 +18,7 @@ base_icon_state = "block" smoothing_flags = NONE canSmoothWith = null + rust_resistance = RUST_RESISTANCE_BASIC /area/ruin/powered/mailroom name = "\improper Abandoned Post Office" diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 6dd4db7fe6eee..46b4a1c391f22 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -136,6 +136,9 @@ ///whether ghosts can see screentips on it var/ghost_screentips = FALSE + /// Flags to check for in can_perform_action. Used in alt-click checks + var/interaction_flags_click = NONE + /** * Top level of the destroy chain for most atoms * @@ -368,11 +371,6 @@ /atom/proc/return_analyzable_air() return null -///Check if this atoms eye is still alive (probably) -/atom/proc/check_eye(mob/user) - SIGNAL_HANDLER - return - /atom/proc/Bumped(atom/movable/bumped_atom) set waitfor = FALSE SEND_SIGNAL(src, COMSIG_ATOM_BUMPED, bumped_atom) diff --git a/code/game/atom/atom_act.dm b/code/game/atom/atom_act.dm index ae7cd5a3eb287..acd33976e51b6 100644 --- a/code/game/atom/atom_act.dm +++ b/code/game/atom/atom_act.dm @@ -119,7 +119,7 @@ /atom/proc/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) SEND_SIGNAL(src, COMSIG_ATOM_HITBY, hitting_atom, skipcatch, hitpush, blocked, throwingdatum) if(density && !has_gravity(hitting_atom)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...). - addtimer(CALLBACK(src, PROC_REF(hitby_react), hitting_atom), 2) + addtimer(CALLBACK(src, PROC_REF(hitby_react), hitting_atom), 0.2 SECONDS) /** * We have have actually hit the passed in atom @@ -201,10 +201,19 @@ * Causes effects when the atom gets hit by a rust effect from heretics * * Override this if you want custom behaviour in whatever gets hit by the rust + * /turf/rust_turf should be used instead for overriding rust on turfs */ /atom/proc/rust_heretic_act() return +///wrapper proc that passes our mob's rust_strength to the target we are rusting +/mob/living/proc/do_rust_heretic_act(atom/target) + var/datum/antagonist/heretic/heretic_data = IS_HERETIC(src) + target.rust_heretic_act(heretic_data?.rust_strength) + +/mob/living/basic/heretic_summon/rust_walker/do_rust_heretic_act(atom/target) + target.rust_heretic_act(4) + ///Called when something resists while this atom is its loc /atom/proc/container_resist_act(mob/living/user) return diff --git a/code/game/atom/atom_color.dm b/code/game/atom/atom_color.dm index e5b52460aa04d..2508e86f44d90 100644 --- a/code/game/atom/atom_color.dm +++ b/code/game/atom/atom_color.dm @@ -42,15 +42,15 @@ * Can optionally be supplied with a range of priorities, IE only checking "washable" or above */ /atom/proc/is_atom_colour(looking_for_color, min_priority_index = 1, max_priority_index = COLOUR_PRIORITY_AMOUNT) - // make sure uppertext hex strings don't mess with lowertext hex strings - looking_for_color = lowertext(looking_for_color) + // make sure uppertext hex strings don't mess with LOWER_TEXT hex strings + looking_for_color = LOWER_TEXT(looking_for_color) if(!LAZYLEN(atom_colours)) // no atom colors list has been set up, just check the color var - return lowertext(color) == looking_for_color + return LOWER_TEXT(color) == looking_for_color for(var/i in min_priority_index to max_priority_index) - if(lowertext(atom_colours[i]) == looking_for_color) + if(LOWER_TEXT(atom_colours[i]) == looking_for_color) return TRUE return FALSE diff --git a/code/game/atom/atom_examine.dm b/code/game/atom/atom_examine.dm index de813cd983dce..ad1d832227780 100644 --- a/code/game/atom/atom_examine.dm +++ b/code/game/atom/atom_examine.dm @@ -75,13 +75,16 @@ * [COMSIG_ATOM_GET_EXAMINE_NAME] signal */ /atom/proc/get_examine_name(mob/user) - . = "\a [src]" - var/list/override = list(gender == PLURAL ? "some" : "a", " ", "[name]") - if(article) - . = "[article] [src]" - override[EXAMINE_POSITION_ARTICLE] = article - if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED) - . = override.Join("") + var/list/override = list(article, null, "[name]") + SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) + + if(!isnull(override[EXAMINE_POSITION_ARTICLE])) + override -= null // IF there is no "before", don't try to join it + return jointext(override, " ") + if(!isnull(override[EXAMINE_POSITION_BEFORE])) + override -= null // There is no article, don't try to join it + return "\a [jointext(override, " ")]" + return "\a [src]" ///Generate the full examine string of this atom (including icon for goonchat) /atom/proc/get_examine_string(mob/user, thats = FALSE) diff --git a/code/game/atom/atom_invisibility.dm b/code/game/atom/atom_invisibility.dm index 53fbe895817cf..1475313470e59 100644 --- a/code/game/atom/atom_invisibility.dm +++ b/code/game/atom/atom_invisibility.dm @@ -54,7 +54,7 @@ /// Removes the specified invisibility source from the tracker /atom/proc/RemoveInvisibility(id) - if(!invisibility_sources) + if(!invisibility_sources?[id]) return var/list/priority_data = invisibility_sources[id] diff --git a/code/game/atom/atom_tool_acts.dm b/code/game/atom/atom_tool_acts.dm index c8dfd36772b14..69a174a6aa1cf 100644 --- a/code/game/atom/atom_tool_acts.dm +++ b/code/game/atom/atom_tool_acts.dm @@ -4,15 +4,12 @@ * Handles non-combat iteractions of a tool on this atom, * such as using a tool on a wall to deconstruct it, * or scanning someone with a health analyzer - * - * This can be overridden to add custom item interactions to this atom - * - * Do not call this directly */ -/atom/proc/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/atom/proc/base_item_interaction(mob/living/user, obj/item/tool, list/modifiers) SHOULD_CALL_PARENT(TRUE) PROTECTED_PROC(TRUE) + var/is_right_clicking = LAZYACCESS(modifiers, RIGHT_CLICK) var/is_left_clicking = !is_right_clicking var/early_sig_return = NONE if(is_left_clicking) @@ -24,6 +21,12 @@ if(early_sig_return) return early_sig_return + var/self_interaction = is_left_clicking \ + ? item_interaction(user, tool, modifiers) \ + : item_interaction_secondary(user, tool, modifiers) + if(self_interaction) + return self_interaction + var/interact_return = is_left_clicking \ ? tool.interact_with_atom(src, user, modifiers) \ : tool.interact_with_atom_secondary(src, user, modifiers) @@ -75,6 +78,27 @@ SEND_SIGNAL(tool, COMSIG_TOOL_ATOM_ACTED_SECONDARY(tool_type), src) return act_result +/** + * Called when this atom has an item used on it. + * IE, a mob is clicking on this atom with an item. + * + * Return an ITEM_INTERACT_ flag in the event the interaction was handled, to cancel further interaction code. + * Return NONE to allow default interaction / tool handling. + */ +/atom/proc/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + return NONE + +/** + * Called when this atom has an item used on it WITH RIGHT CLICK, + * IE, a mob is right clicking on this atom with an item. + * Default behavior has it run the same code as left click. + * + * Return an ITEM_INTERACT_ flag in the event the interaction was handled, to cancel further interaction code. + * Return NONE to allow default interaction / tool handling. + */ +/atom/proc/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers) + return item_interaction(user, tool, modifiers) + /** * Called when this item is being used to interact with an atom, * IE, a mob is clicking on an atom with this item. diff --git a/code/game/atom/atom_vv.dm b/code/game/atom/atom_vv.dm index 8830a4af2f433..10a6cbff24a92 100644 --- a/code/game/atom/atom_vv.dm +++ b/code/game/atom/atom_vv.dm @@ -67,14 +67,10 @@ message_admins(span_notice("[key_name(usr)] has added [amount] units of [chosen_id] to [src]")) if(href_list[VV_HK_TRIGGER_EXPLOSION]) - if(!check_rights(R_FUN)) - return - usr.client.cmd_admin_explosion(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/admin_explosion, src) if(href_list[VV_HK_TRIGGER_EMP]) - if(!check_rights(R_FUN)) - return - usr.client.cmd_admin_emp(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/admin_emp, src) if(href_list[VV_HK_SHOW_HIDDENPRINTS]) if(!check_rights(R_ADMIN)) diff --git a/code/game/atom/atoms_initializing_EXPENSIVE.dm b/code/game/atom/atoms_initializing_EXPENSIVE.dm index a55666aed9a04..c603ae5514810 100644 --- a/code/game/atom/atoms_initializing_EXPENSIVE.dm +++ b/code/game/atom/atoms_initializing_EXPENSIVE.dm @@ -162,3 +162,5 @@ */ /atom/proc/LateInitialize() set waitfor = FALSE + SHOULD_CALL_PARENT(FALSE) + stack_trace("[src] ([type]) called LateInitialize but has nothing on it!") diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index fda5485484ebb..a4d59d668ae11 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -207,7 +207,7 @@ Medical HUD! Basic mode needs suit sensors on. if(HAS_TRAIT(src, TRAIT_XENO_HOST)) holder.icon_state = "hudxeno" else if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) - if(can_defib_client()) + if(HAS_TRAIT(src, TRAIT_MIND_TEMPORARILY_GONE) || can_defib_client()) holder.icon_state = "huddefib" else holder.icon_state = "huddead" diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 50c75850647f8..f0ca22b3b4fae 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -5,6 +5,8 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list var/datum/team/team //An alternative to 'owner': a team. Use this when writing new code. var/name = "generic objective" //Name for admin prompts var/explanation_text = "Nothing" //What that person is supposed to do. + ///if this objective doesn't print failure or success in the roundend report + var/no_failure = FALSE ///name used in printing this objective (Objective #1) var/objective_name = "Objective" var/team_explanation_text //For when there are multiple owners. @@ -96,6 +98,8 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list /// Provides a string describing what a good job you did or did not do /datum/objective/proc/get_roundend_success_suffix() + if(no_failure) + return "" // Just print the objective with no success/fail evaluation, as it has no mechanical backing return check_completion() ? span_greentext("Success!") : span_redtext("Fail.") /datum/objective/proc/is_unique_objective(possible_target, dupe_search_range) @@ -345,6 +349,8 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list /datum/objective/protect/check_completion() var/obj/item/organ/internal/brain/brain_target + if(isnull(target)) + return FALSE if(human_check) brain_target = target.current?.get_organ_slot(ORGAN_SLOT_BRAIN) //Protect will always suceed when someone suicides @@ -394,7 +400,7 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list /datum/objective/jailbreak/detain/update_explanation_text() ..() if(target?.current) - explanation_text = "Ensure that [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role] is delivered to nanotrasen alive and in custody." + explanation_text = "Ensure that [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role] is delivered to Nanotrasen alive and in custody." else explanation_text = "Free objective." @@ -981,15 +987,13 @@ GLOBAL_LIST_EMPTY(possible_items) /datum/objective/custom name = "custom" admin_grantable = TRUE + no_failure = TRUE /datum/objective/custom/admin_edit(mob/admin) var/expl = stripped_input(admin, "Custom objective:", "Objective", explanation_text) if(expl) explanation_text = expl -/datum/objective/custom/get_roundend_success_suffix() - return "" // Just print the objective with no success/fail evaluation, as it has no mechanical backing - //Ideally this would be all of them but laziness and unusual subtypes /proc/generate_admin_objective_list() GLOB.admin_objective_list = list() diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index 491f0f71fb900..d9263411f7b08 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -236,7 +236,8 @@ JOB_HEAD_OF_SECURITY, JOB_HEAD_OF_PERSONNEL, JOB_CHIEF_ENGINEER, - JOB_CHIEF_MEDICAL_OFFICER + JOB_CHIEF_MEDICAL_OFFICER, + JOB_QUARTERMASTER, ) exists_on_map = TRUE difficulty = 3 @@ -279,7 +280,8 @@ JOB_HEAD_OF_SECURITY, JOB_HEAD_OF_PERSONNEL, JOB_CHIEF_ENGINEER, - JOB_CHIEF_MEDICAL_OFFICER + JOB_CHIEF_MEDICAL_OFFICER, + JOB_QUARTERMASTER, ) exists_on_map = TRUE difficulty = 4 @@ -525,7 +527,7 @@ /datum/objective_item/steal/blueprints name = "the station blueprints" - targetitem = /obj/item/areaeditor/blueprints + targetitem = /obj/item/blueprints excludefromjob = list(JOB_CHIEF_ENGINEER) item_owner = list(JOB_CHIEF_ENGINEER) altitems = list(/obj/item/photo) @@ -533,11 +535,11 @@ difficulty = 3 steal_hint = "The blueprints of the station, found in the Chief Engineer's locker, or on their person. A picture may suffice." -/obj/item/areaeditor/blueprints/add_stealing_item_objective() - return add_item_to_steal(src, /obj/item/areaeditor/blueprints) +/obj/item/blueprints/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/blueprints) /datum/objective_item/steal/blueprints/check_special_completion(obj/item/I) - if(istype(I, /obj/item/areaeditor/blueprints)) + if(istype(I, /obj/item/blueprints)) return TRUE if(istype(I, /obj/item/photo)) var/obj/item/photo/P = I @@ -574,7 +576,7 @@ /datum/objective_item/steal/traitor/moth_plush name = "cute moth plush toy" targetitem = /obj/item/toy/plush/moth - excludefromjob = list(JOB_PSYCHOLOGIST, JOB_PARAMEDIC, JOB_CHEMIST, JOB_MEDICAL_DOCTOR, JOB_VIROLOGIST, JOB_CHIEF_MEDICAL_OFFICER, JOB_CORONER) + excludefromjob = list(JOB_PSYCHOLOGIST, JOB_PARAMEDIC, JOB_CHEMIST, JOB_MEDICAL_DOCTOR, JOB_CHIEF_MEDICAL_OFFICER, JOB_CORONER) exists_on_map = TRUE difficulty = 1 steal_hint = "A moth plush toy. The Psychologist has one to help console patients." @@ -629,7 +631,15 @@ /datum/objective_item/steal/traitor/rpd name = "rapid pipe dispenser" targetitem = /obj/item/pipe_dispenser - excludefromjob = list(JOB_ATMOSPHERIC_TECHNICIAN, JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER, JOB_SCIENTIST, JOB_RESEARCH_DIRECTOR, JOB_GENETICIST, JOB_ROBOTICIST) + excludefromjob = list( + JOB_ATMOSPHERIC_TECHNICIAN, + JOB_STATION_ENGINEER, + JOB_CHIEF_ENGINEER, + JOB_SCIENTIST, + JOB_RESEARCH_DIRECTOR, + JOB_GENETICIST, + JOB_ROBOTICIST, + ) item_owner = list(JOB_CHIEF_ENGINEER) exists_on_map = TRUE difficulty = 1 @@ -641,7 +651,19 @@ /datum/objective_item/steal/traitor/donut_box name = "a box of prized donuts" targetitem = /obj/item/storage/fancy/donut_box - excludefromjob = list(JOB_CAPTAIN, JOB_CHIEF_ENGINEER, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, JOB_QUARTERMASTER, JOB_CHIEF_MEDICAL_OFFICER, JOB_RESEARCH_DIRECTOR, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_LAWYER, JOB_DETECTIVE) + excludefromjob = list( + JOB_CAPTAIN, + JOB_CHIEF_ENGINEER, + JOB_HEAD_OF_PERSONNEL, + JOB_HEAD_OF_SECURITY, + JOB_QUARTERMASTER, + JOB_CHIEF_MEDICAL_OFFICER, + JOB_RESEARCH_DIRECTOR, + JOB_SECURITY_OFFICER, + JOB_WARDEN, + JOB_LAWYER, + JOB_DETECTIVE, + ) exists_on_map = TRUE difficulty = 1 steal_hint = "Everyone has a box of donuts - you may most commonly find them on the Bridge, within Security, or in any department's break room." diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 6d7f8a4960600..4b513a2203665 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -184,12 +184,8 @@ return INITIALIZE_HINT_LATELOAD /obj/machinery/LateInitialize() - . = ..() - power_change() - if(use_power == NO_POWER_USE) - return - update_current_power_usage() - setup_area_power_relationship() + SHOULD_NOT_OVERRIDE(TRUE) + post_machine_initialize() /obj/machinery/Destroy(force) SSmachines.unregister_machine(src) @@ -200,6 +196,20 @@ return ..() +/** + * Called in LateInitialize meant to be the machine replacement to it + * This sets up power for the machine and requires parent be called, + * ensuring power works on all machines unless exempted with NO_POWER_USE. + * This is the proc to override if you want to do anything in LateInitialize. + */ +/obj/machinery/proc/post_machine_initialize() + SHOULD_CALL_PARENT(TRUE) + power_change() + if(use_power == NO_POWER_USE) + return + update_current_power_usage() + setup_area_power_relationship() + /** * proc to call when the machine starts to require power after a duration of not requiring power * sets up power related connections to its area if it exists and becomes area sensitive @@ -328,7 +338,6 @@ if(drop) dump_inventory_contents() update_appearance() - updateUsrDialog() /** * Drop every movable atom in the machine's contents list, including any components and circuit. @@ -413,7 +422,6 @@ if(target && !target.has_buckled_mobs() && (!isliving(target) || !mobtarget.buckled)) set_occupant(target) target.forceMove(src) - updateUsrDialog() update_appearance() ///updates the use_power var for this machine and updates its static power usage from its area to reflect the new value @@ -580,13 +588,15 @@ set_panel_open(!panel_open) /obj/machinery/can_interact(mob/user) + if(QDELETED(user)) + return FALSE + if((machine_stat & (NOPOWER|BROKEN)) && !(interaction_flags_machine & INTERACT_MACHINE_OFFLINE)) // Check if the machine is broken, and if we can still interact with it if so return FALSE if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE_INTERACT) return FALSE - if(isAdminGhostAI(user)) return TRUE //the Gods have unlimited power and do not care for things such as range or blindness @@ -657,12 +667,10 @@ //Return a non FALSE value to interrupt attack_hand propagation to subtypes. /obj/machinery/interact(mob/user) - if(interaction_flags_machine & INTERACT_MACHINE_SET_MACHINE) - user.set_machine(src) update_last_used(user) - . = ..() + return ..() -/obj/machinery/ui_act(action, list/params) +/obj/machinery/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) add_fingerprint(usr) update_last_used(usr) if(HAS_AI_ACCESS(usr) && !GLOB.cameranet.checkTurfVis(get_turf(src))) //We check if they're an AI specifically here, so borgs can still access off-camera stuff. @@ -698,8 +706,8 @@ hit_with_what_noun += plural_s(hit_with_what_noun) // hit with "their hands" user.visible_message( - span_danger("[user] smashes [src] with [user.p_their()] [hit_with_what_noun][damage ? "." : ", [no_damage_feedback]"]!"), - span_danger("You smash [src] with your [hit_with_what_noun][damage ? "." : ", [no_damage_feedback]"]!"), + span_danger("[user] smashes [src] with [user.p_their()] [hit_with_what_noun][damage ? "." : ", [no_damage_feedback]!"]"), + span_danger("You smash [src] with your [hit_with_what_noun][damage ? "." : ", [no_damage_feedback]!"]"), span_hear("You hear a [damage ? "smash" : "thud"]."), COMBAT_MESSAGE_RANGE, ) @@ -758,13 +766,14 @@ return update_last_used(user) -/obj/machinery/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/machinery/base_item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE_TOOLS) - return ITEM_INTERACT_ANY_BLOCKER + return ITEM_INTERACT_BLOCKING + . = ..() - if(. & ITEM_INTERACT_BLOCKING) - return - update_last_used(user) + if(.) + update_last_used(user) + return . /obj/machinery/_try_interact(mob/user) if((interaction_flags_machine & INTERACT_MACHINE_WIRES_IF_OPEN) && panel_open && (attempt_wire_interaction(user) == WIRE_INTERACTION_BLOCK)) @@ -798,7 +807,7 @@ SEND_SIGNAL(src, COMSIG_MACHINERY_REFRESH_PARTS) /obj/machinery/proc/default_pry_open(obj/item/crowbar, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE) - . = !(state_open || panel_open || is_operational || (obj_flags & NO_DECONSTRUCTION)) && crowbar.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open || is_operational) && crowbar.tool_behaviour == TOOL_CROWBAR if(!.) return crowbar.play_tool_sound(src, 50) @@ -808,23 +817,23 @@ close_machine(density_to_set = closed_density) /obj/machinery/proc/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel = 0, custom_deconstruct = FALSE) - . = (panel_open || ignore_panel) && !(obj_flags & NO_DECONSTRUCTION) && crowbar.tool_behaviour == TOOL_CROWBAR + . = (panel_open || ignore_panel) && crowbar.tool_behaviour == TOOL_CROWBAR if(!. || custom_deconstruct) return crowbar.play_tool_sound(src, 50) deconstruct(TRUE) -/obj/machinery/deconstruct(disassembled = TRUE) +/obj/machinery/handle_deconstruct(disassembled = TRUE) SHOULD_NOT_OVERRIDE(TRUE) - if(obj_flags & NO_DECONSTRUCTION) - dump_contents() //drop everything inside us - return ..() //Just delete us, no need to call anything else. + if(obj_flags & NO_DEBRIS_AFTER_DECONSTRUCTION) + dump_inventory_contents() //drop stuff we consider important + return //Just delete us, no need to call anything else. on_deconstruction(disassembled) if(!LAZYLEN(component_parts)) dump_contents() //drop everything inside us - return ..() //we don't have any parts. + return //we don't have any parts. spawn_frame(disassembled) for(var/part in component_parts) @@ -848,8 +857,6 @@ //to handle their contents before we dump them dump_contents() - return ..() - /** * Spawns a frame where this machine is. If the machine was not disassmbled, the * frame is spawned damaged. If the frame couldn't exist on this turf, it's smashed @@ -881,7 +888,7 @@ /obj/machinery/atom_break(damage_flag) . = ..() - if(!(machine_stat & BROKEN) && !(obj_flags & NO_DECONSTRUCTION)) + if(!(machine_stat & BROKEN)) set_machine_stat(machine_stat | BROKEN) SEND_SIGNAL(src, COMSIG_MACHINERY_BROKEN, damage_flag) update_appearance() @@ -928,7 +935,7 @@ qdel(atom_part) /obj/machinery/proc/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) - if((obj_flags & NO_DECONSTRUCTION) || screwdriver.tool_behaviour != TOOL_SCREWDRIVER) + if(screwdriver.tool_behaviour != TOOL_SCREWDRIVER) return FALSE screwdriver.play_tool_sound(src, 50) @@ -955,9 +962,6 @@ if(!istype(replacer_tool)) return FALSE - if((obj_flags & NO_DECONSTRUCTION) && !replacer_tool.works_from_distance) - return FALSE - var/shouldplaysound = FALSE if(!component_parts) return FALSE @@ -1143,9 +1147,6 @@ PROTECTED_PROC(TRUE) return -/obj/machinery/proc/can_be_overridden() - . = 1 - /obj/machinery/zap_act(power, zap_flags) if(prob(85) && (zap_flags & ZAP_MACHINE_EXPLOSIVE) && !(resistance_flags & INDESTRUCTIBLE)) explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 2, adminlog = TRUE, smoke = FALSE) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 4fbfe2d37bfe1..296a9031ae27e 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -4,8 +4,8 @@ icon = 'icons/obj/machines/lathes.dmi' icon_state = "autolathe" density = TRUE - //Energy cost per full stack of sheets worth of materials used. Material insertion is 40% of this. - active_power_usage = 25 * BASE_MACHINE_ACTIVE_CONSUMPTION + ///Energy cost per full stack of sheets worth of materials used. Material insertion is 40% of this. + active_power_usage = 0.025 * STANDARD_CELL_RATE circuit = /obj/item/circuitboard/machine/autolathe layer = BELOW_OBJ_LAYER processing_flags = NONE @@ -388,15 +388,15 @@ drop_direction = direction balloon_alert(usr, "dropping [dir2text(drop_direction)]") -/obj/machinery/autolathe/AltClick(mob/user) - . = ..() - if(!drop_direction || !can_interact(user)) - return +/obj/machinery/autolathe/click_alt(mob/user) + if(!drop_direction) + return CLICK_ACTION_BLOCKING if(busy) balloon_alert(user, "busy printing!") - return + return CLICK_ACTION_SUCCESS balloon_alert(user, "drop direction reset") drop_direction = 0 + return CLICK_ACTION_SUCCESS /obj/machinery/autolathe/attackby(obj/item/attacking_item, mob/living/user, params) if(user.combat_mode) //so we can hit the machine diff --git a/code/game/machinery/barsigns.dm b/code/game/machinery/barsigns.dm index faa29c2673ef6..e59de18ffcb18 100644 --- a/code/game/machinery/barsigns.dm +++ b/code/game/machinery/barsigns.dm @@ -36,8 +36,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) if(!istype(sign)) return + var/area/bar_area = get_area(src) if(change_area_name && sign.rename_area) - rename_area(src, sign.name) + rename_area(bar_area, sign.name) chosen_sign = sign update_appearance() @@ -88,7 +89,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /obj/machinery/barsign/atom_break(damage_flag) . = ..() - if((machine_stat & BROKEN) && !(obj_flags & NO_DECONSTRUCTION)) + if(machine_stat & BROKEN) set_sign(new /datum/barsign/hiddensigns/signoff) /obj/machinery/barsign/on_deconstruction(disassembled) @@ -152,7 +153,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /obj/machinery/barsign/attackby(obj/item/attacking_item, mob/user) - if(istype(attacking_item, /obj/item/areaeditor/blueprints) && !change_area_name) + if(istype(attacking_item, /obj/item/blueprints) && !change_area_name) if(!panel_open) balloon_alert(user, "open the panel first!") return TRUE diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 33dde81af5837..ca6562635eecb 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -110,7 +110,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) for(var/network_name in network) network -= network_name - network += lowertext(network_name) + network += LOWER_TEXT(network_name) GLOB.cameranet.cameras += src @@ -216,19 +216,19 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) return if(. & EMP_PROTECT_SELF) return - if(prob(150 / severity)) - network = list() - GLOB.cameranet.removeCamera(src) - set_machine_stat(machine_stat | EMPED) - set_light(0) - emped++ //Increase the number of consecutive EMP's - update_appearance() - addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), reset_time) - for(var/mob/M as anything in GLOB.player_list) - if (M.client?.eye == src) - M.unset_machine() - M.reset_perspective(null) - to_chat(M, span_warning("The screen bursts into static!")) + if(!prob(150 / severity)) + return + network = list() + GLOB.cameranet.removeCamera(src) + set_machine_stat(machine_stat | EMPED) + set_light(0) + emped++ //Increase the number of consecutive EMP's + update_appearance() + addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), reset_time) + for(var/mob/M as anything in GLOB.player_list) + if (M.client?.eye == src) + M.reset_perspective(null) + to_chat(M, span_warning("The screen bursts into static!")) /obj/machinery/camera/proc/on_saboteur(datum/source, disrupt_duration) SIGNAL_HANDLER @@ -302,23 +302,22 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) toggle_cam(null, 0) /obj/machinery/camera/on_deconstruction(disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - var/obj/item/wallframe/camera/dropped_cam = new(drop_location()) - dropped_cam.update_integrity(dropped_cam.max_integrity * 0.5) - if(camera_construction_state >= CAMERA_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 2) - if(xray_module) - drop_upgrade(xray_module) - if(emp_module) - drop_upgrade(emp_module) - if(proximity_monitor) - drop_upgrade(proximity_monitor) - else - if(camera_construction_state >= CAMERA_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 2) - new /obj/item/stack/sheet/iron(loc) - return ..() + if(!disassembled) + if(camera_construction_state >= CAMERA_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 2) + new /obj/item/stack/sheet/iron(loc) + return + + var/obj/item/wallframe/camera/dropped_cam = new(drop_location()) + dropped_cam.update_integrity(dropped_cam.max_integrity * 0.5) + if(camera_construction_state >= CAMERA_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 2) + if(xray_module) + drop_upgrade(xray_module) + if(emp_module) + drop_upgrade(emp_module) + if(proximity_monitor) + drop_upgrade(proximity_monitor) /obj/machinery/camera/update_icon_state() //TO-DO: Make panel open states, xray camera, and indicator lights overlays instead. var/xray_module @@ -356,7 +355,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) change_msg = "reactivates" triggerCameraAlarm() if(!QDELETED(src)) //We'll be doing it anyway in destroy - addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 100) + addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 10 SECONDS) if(displaymessage) if(user) visible_message(span_danger("[user] [change_msg] [src]!")) @@ -372,7 +371,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) //I guess that doesn't matter since they can't use it anyway? for(var/mob/O as anything in GLOB.player_list) if (O.client?.eye == src) - O.unset_machine() O.reset_perspective(null) to_chat(O, span_warning("The screen bursts into static!")) diff --git a/code/game/machinery/camera/camera_construction.dm b/code/game/machinery/camera/camera_construction.dm index 48bf4ccabaa57..15f22d02cbe96 100644 --- a/code/game/machinery/camera/camera_construction.dm +++ b/code/game/machinery/camera/camera_construction.dm @@ -39,7 +39,7 @@ return ITEM_INTERACT_BLOCKING for(var/i in tempnetwork) tempnetwork -= i - tempnetwork += lowertext(i) + tempnetwork += LOWER_TEXT(i) camera_construction_state = CAMERA_STATE_FINISHED toggle_cam(user, displaymessage = FALSE) network = tempnetwork diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index bb9ef7d3fc5cf..2cd0506cbfd89 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -66,7 +66,7 @@ /** * Autonaming camera - * Automatically names itself after the area it's in during LateInitialize, + * Automatically names itself after the area it's in during post_machine_initialize, * good for mappers who don't want to manually name them all. */ /obj/machinery/camera/autoname @@ -76,7 +76,7 @@ ..() return INITIALIZE_HINT_LATELOAD -/obj/machinery/camera/autoname/LateInitialize() +/obj/machinery/camera/autoname/post_machine_initialize() . = ..() var/static/list/autonames_in_areas = list() var/area/camera_area = get_area(src) diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index aaa24526da5e5..27812f53dbaaa 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -7,7 +7,7 @@ circuit = /obj/item/circuitboard/machine/cell_charger pass_flags = PASSTABLE var/obj/item/stock_parts/cell/charging = null - var/charge_rate = 250 KILO WATTS + var/charge_rate = 0.25 * STANDARD_CELL_RATE /obj/machinery/cell_charger/update_overlays() . = ..() @@ -125,22 +125,21 @@ /obj/machinery/cell_charger/RefreshParts() . = ..() - charge_rate = 250 KILO WATTS + charge_rate = 0.25 * STANDARD_CELL_RATE for(var/datum/stock_part/capacitor/capacitor in component_parts) charge_rate *= capacitor.tier /obj/machinery/cell_charger/process(seconds_per_tick) - if(!charging || !anchored || (machine_stat & (BROKEN|NOPOWER))) - return - - if(charging.percent() >= 100) + if(!charging || charging.percent() >= 100 || !anchored || !is_operational) return var/main_draw = charge_rate * seconds_per_tick if(!main_draw) return - use_energy(main_draw * 0.01) //use a small bit for the charger itself, but power usage scales up with the part tier - charge_cell(main_draw, charging) + //charge cell, account for heat loss from work done + var/charge_given = charge_cell(main_draw, charging, grid_only = TRUE) + if(charge_given) + use_energy((charge_given + active_power_usage) * 0.01) update_appearance() diff --git a/code/game/machinery/civilian_bounties.dm b/code/game/machinery/civilian_bounties.dm index 2d284b17b670e..792c1ba22eb31 100644 --- a/code/game/machinery/civilian_bounties.dm +++ b/code/game/machinery/civilian_bounties.dm @@ -60,7 +60,7 @@ pad_ref = WEAKREF(I.buffer) return TRUE -/obj/machinery/computer/piratepad_control/civilian/LateInitialize() +/obj/machinery/computer/piratepad_control/civilian/post_machine_initialize() . = ..() if(cargo_hold_id) for(var/obj/machinery/piratepad/civilian/C as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/piratepad/civilian)) @@ -163,11 +163,9 @@ inserted_scan_id.registered_account.bounties = null return inserted_scan_id.registered_account.civilian_bounty -/obj/machinery/computer/piratepad_control/civilian/AltClick(mob/user) - . = ..() - if(!Adjacent(user)) - return FALSE +/obj/machinery/computer/piratepad_control/civilian/click_alt(mob/user) id_eject(user, inserted_scan_id) + return CLICK_ACTION_SUCCESS /obj/machinery/computer/piratepad_control/civilian/ui_data(mob/user) var/list/data = list() @@ -186,6 +184,9 @@ data["id_bounty_names"] = list(inserted_scan_id.registered_account.bounties[1].name, inserted_scan_id.registered_account.bounties[2].name, inserted_scan_id.registered_account.bounties[3].name) + data["id_bounty_infos"] = list(inserted_scan_id.registered_account.bounties[1].description, + inserted_scan_id.registered_account.bounties[2].description, + inserted_scan_id.registered_account.bounties[3].description) data["id_bounty_values"] = list(inserted_scan_id.registered_account.bounties[1].reward * (CIV_BOUNTY_SPLIT/100), inserted_scan_id.registered_account.bounties[2].reward * (CIV_BOUNTY_SPLIT/100), inserted_scan_id.registered_account.bounties[3].reward * (CIV_BOUNTY_SPLIT/100)) diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index 36480be6e90db..c8e0251b3dd4b 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -63,7 +63,7 @@ /obj/machinery/computer/screwdriver_act(mob/living/user, obj/item/I) if(..()) return TRUE - if(circuit && !(obj_flags & NO_DECONSTRUCTION)) + if(circuit) balloon_alert(user, "disconnecting monitor...") if(I.use_tool(src, user, time_to_unscrew, volume=50)) deconstruct(TRUE) @@ -87,6 +87,16 @@ playsound(loc, 'sound/effects/glassbr3.ogg', 100, TRUE) set_light(0) +/obj/machinery/computer/proc/imprint_gps(gps_tag) // Currently used by the upload computers and communications console + var/tracker = gps_tag + if(!tracker) // Don't give a null GPS signal if there is none + return + for(var/obj/item/circuitboard/computer/board in src.contents) + if(!contents || board.GetComponent(/datum/component/gps)) + return + board.AddComponent(/datum/component/gps, "[tracker]") + balloon_alert_to_viewers("board tracker enabled", vision_distance = 1) + /obj/machinery/computer/emp_act(severity) . = ..() if (!(. & EMP_PROTECT_SELF)) @@ -107,7 +117,9 @@ new_frame.set_anchored(TRUE) new_frame.circuit = circuit // Circuit removal code is handled in /obj/machinery/Exited() + component_parts -= circuit circuit.forceMove(new_frame) + if((machine_stat & BROKEN) || !disassembled) var/atom/drop_loc = drop_location() playsound(src, 'sound/effects/hit_on_shattered_glass.ogg', 70, TRUE) @@ -118,13 +130,6 @@ new_frame.state = FRAME_COMPUTER_STATE_GLASSED new_frame.update_appearance(UPDATE_ICON_STATE) -/obj/machinery/computer/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return - if(!user.can_perform_action(src, ALLOW_SILICON_REACH) || !is_operational) - return - /obj/machinery/computer/ui_interact(mob/user, datum/tgui/ui) SHOULD_CALL_PARENT(TRUE) . = ..() diff --git a/code/game/machinery/computer/arcade/_arcade.dm b/code/game/machinery/computer/arcade/_arcade.dm new file mode 100644 index 0000000000000..69994634fc3b1 --- /dev/null +++ b/code/game/machinery/computer/arcade/_arcade.dm @@ -0,0 +1,100 @@ +/obj/machinery/computer/arcade + name = "\proper the arcade cabinet which shouldn't exist" + desc = "This arcade cabinet has no games installed, and in fact, should not exist. \ + Report the location of this machine to your local diety." + icon_state = "arcade" + icon_keyboard = null + icon_screen = "invaders" + light_color = LIGHT_COLOR_GREEN + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_REQUIRES_LITERACY + + ///If set, will dispense these as prizes instead of the default GLOB.arcade_prize_pool + ///Like prize pool, it must be a list of the prize and the weight of being selected. + var/list/prize_override + +/obj/machinery/computer/arcade/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(istype(tool, /obj/item/stack/arcadeticket)) + var/obj/item/stack/arcadeticket/tickets = tool + if(!tickets.use(2)) + balloon_alert(user, "need 2 tickets!") + return ITEM_INTERACT_BLOCKING + + prizevend(user) + balloon_alert(user, "prize claimed") + return ITEM_INTERACT_SUCCESS + + if(istype(tool, /obj/item/key/displaycase) || istype(tool, /obj/item/access_key)) + var/static/list/radial_menu_options + if(!radial_menu_options) + radial_menu_options = list( + "Reset Cabinet" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_reset"), + "Cancel" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_close"), + ) + var/radial_reset_menu = show_radial_menu(user, src, radial_menu_options, require_near = TRUE) + if(radial_reset_menu != "Reset Cabinet") + return ITEM_INTERACT_BLOCKING + playsound(loc, 'sound/items/rattling_keys.ogg', 25, TRUE) + if(!do_after(user, 10 SECONDS, src)) + return ITEM_INTERACT_BLOCKING + balloon_alert(user, "cabinet reset") + reset_cabinet(user) + return ITEM_INTERACT_SUCCESS + + return NONE + +/obj/machinery/computer/arcade/screwdriver_act(mob/living/user, obj/item/I) + //you can't stop playing when you start. + if(obj_flags & EMAGGED) + return ITEM_INTERACT_BLOCKING + return ..() + +///Performs a factory reset of the cabinet and wipes all its stats. +/obj/machinery/computer/arcade/proc/reset_cabinet(mob/living/user) + SHOULD_CALL_PARENT(TRUE) + obj_flags &= ~EMAGGED + SStgui.update_uis(src) + +/obj/machinery/computer/arcade/emp_act(severity) + . = ..() + if((machine_stat & (NOPOWER|BROKEN)) || (. & EMP_PROTECT_SELF)) + return + + var/empprize = null + var/num_of_prizes = 0 + switch(severity) + if(1) + num_of_prizes = rand(1,4) + if(2) + num_of_prizes = rand(0,2) + for(var/i = num_of_prizes; i > 0; i--) + if(prize_override) + empprize = pick_weight(prize_override) + else + empprize = pick_weight(GLOB.arcade_prize_pool) + new empprize(loc) + explosion(src, devastation_range = -1, light_impact_range = 1 + num_of_prizes, flame_range = 1 + num_of_prizes) + +///Dispenses the proper prizes and gives them a positive mood event. If valid, has a small chance to give a pulse rifle. +/obj/machinery/computer/arcade/proc/prizevend(mob/living/user, prizes = 1) + SEND_SIGNAL(src, COMSIG_ARCADE_PRIZEVEND, user, prizes) + if(user.mind?.get_skill_level(/datum/skill/gaming) >= SKILL_LEVEL_LEGENDARY && HAS_TRAIT(user, TRAIT_GAMERGOD)) + visible_message("[user] inputs an intense cheat code!",\ + span_notice("You hear a flurry of buttons being pressed.")) + say("CODE ACTIVATED: EXTRA PRIZES.") + prizes *= 2 + for(var/i in 1 to prizes) + user.add_mood_event("arcade", /datum/mood_event/arcade) + if(prob(0.0001)) //1 in a million + new /obj/item/gun/energy/pulse/prize(src) + visible_message(span_notice("[src] dispenses.. woah, a gun! Way past cool."), span_notice("You hear a chime and a shot.")) + user.client.give_award(/datum/award/achievement/misc/pulse, user) + continue + + var/prizeselect + if(prize_override) + prizeselect = pick_weight(prize_override) + else + prizeselect = pick_weight(GLOB.arcade_prize_pool) + var/atom/movable/the_prize = new prizeselect(get_turf(src)) + playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3) + visible_message(span_notice("[src] dispenses [the_prize]!"), span_notice("You hear a chime and a clunk.")) diff --git a/code/game/machinery/computer/arcade/amputation.dm b/code/game/machinery/computer/arcade/amputation.dm new file mode 100644 index 0000000000000..84a02af387ad2 --- /dev/null +++ b/code/game/machinery/computer/arcade/amputation.dm @@ -0,0 +1,47 @@ +/obj/machinery/computer/arcade/amputation + name = "Mediborg's Amputation Adventure" + desc = "A picture of a blood-soaked medical cyborg flashes on the screen. \ + The mediborg has a speech bubble that says, \"Put your hand in the machine if you aren't a coward!\"" + icon_state = "arcade" + circuit = /obj/item/circuitboard/computer/arcade/amputation + interaction_flags_machine = NONE //borgs can't play, but the illiterate can. + +/obj/machinery/computer/arcade/amputation/attack_tk(mob/user) + return //that's a pretty damn big guillotine + +/obj/machinery/computer/arcade/amputation/attack_hand(mob/user, list/modifiers) + . = ..() + if(!iscarbon(user)) + return + to_chat(user, span_warning("You move your hand towards the machine, and begin to hesitate as a bloodied guillotine emerges from inside of it...")) + user.played_game() + var/obj/item/bodypart/chopchop = user.get_active_hand() + if(do_after(user, 5 SECONDS, target = src, extra_checks = CALLBACK(src, PROC_REF(do_they_still_have_that_hand), user, chopchop))) + playsound(src, 'sound/weapons/slice.ogg', 25, TRUE, -1) + to_chat(user, span_userdanger("The guillotine drops on your arm, and the machine sucks it in!")) + chopchop.dismember() + qdel(chopchop) + user.mind?.adjust_experience(/datum/skill/gaming, 100) + user.won_game() + playsound(src, 'sound/arcade/win.ogg', 50, TRUE) + new /obj/item/stack/arcadeticket((get_turf(src)), rand(6,10)) + to_chat(user, span_notice("[src] dispenses a handful of tickets!")) + return + if(!do_they_still_have_that_hand(user, chopchop)) + to_chat(user, span_warning("The guillotine drops, but your hand seems to be gone already!")) + playsound(src, 'sound/weapons/slice.ogg', 25, TRUE, -1) + else + to_chat(user, span_notice("You (wisely) decide against putting your hand in the machine.")) + user.lost_game() + +///Makes sure the user still has their starting hand, preventing the user from pulling the arm out and still getting prizes. +/obj/machinery/computer/arcade/amputation/proc/do_they_still_have_that_hand(mob/user, obj/item/bodypart/chopchop) + if(QDELETED(chopchop) || chopchop.owner != user) + return FALSE + return TRUE + +///Dispenses wrapped gifts instead of arcade prizes, also known as the ancap christmas tree +/obj/machinery/computer/arcade/amputation/festive + name = "Mediborg's Festive Amputation Adventure" + desc = "A picture of a blood-soaked medical cyborg wearing a Santa hat flashes on the screen. The mediborg has a speech bubble that says, \"Put your hand in the machine if you aren't a coward!\"" + prize_override = list(/obj/item/gift/anything = 1) diff --git a/code/game/machinery/computer/arcade/arcade.dm b/code/game/machinery/computer/arcade/arcade.dm deleted file mode 100644 index 91a10673dd6dd..0000000000000 --- a/code/game/machinery/computer/arcade/arcade.dm +++ /dev/null @@ -1,701 +0,0 @@ -GLOBAL_LIST_INIT(arcade_prize_pool, list( - /obj/item/storage/box/snappops = 2, - /obj/item/toy/talking/ai = 2, - /obj/item/toy/talking/codex_gigas = 2, - /obj/item/clothing/under/syndicate/tacticool = 2, - /obj/item/toy/sword = 2, - /obj/item/toy/gun = 2, - /obj/item/gun/ballistic/shotgun/toy/crossbow = 2, - /obj/item/storage/box/fakesyndiesuit = 2, - /obj/item/storage/crayons = 2, - /obj/item/toy/spinningtoy = 2, - /obj/item/toy/spinningtoy/dark_matter = 1, - /obj/item/toy/balloon/arrest = 2, - /obj/item/toy/mecha/ripley = 1, - /obj/item/toy/mecha/ripleymkii = 1, - /obj/item/toy/mecha/hauler = 1, - /obj/item/toy/mecha/clarke = 1, - /obj/item/toy/mecha/odysseus = 1, - /obj/item/toy/mecha/gygax = 1, - /obj/item/toy/mecha/durand = 1, - /obj/item/toy/mecha/savannahivanov = 1, - /obj/item/toy/mecha/phazon = 1, - /obj/item/toy/mecha/honk = 1, - /obj/item/toy/mecha/darkgygax = 1, - /obj/item/toy/mecha/mauler = 1, - /obj/item/toy/mecha/darkhonk = 1, - /obj/item/toy/mecha/deathripley = 1, - /obj/item/toy/mecha/reticence = 1, - /obj/item/toy/mecha/marauder = 1, - /obj/item/toy/mecha/seraph = 1, - /obj/item/toy/mecha/firefighter = 1, - /obj/item/toy/cards/deck = 2, - /obj/item/toy/nuke = 2, - /obj/item/toy/minimeteor = 2, - /obj/item/toy/redbutton = 2, - /obj/item/toy/talking/owl = 2, - /obj/item/toy/talking/griffin = 2, - /obj/item/coin/antagtoken = 2, - /obj/item/stack/tile/fakepit/loaded = 2, - /obj/item/stack/tile/eighties/loaded = 2, - /obj/item/toy/toy_xeno = 2, - /obj/item/storage/box/actionfigure = 1, - /obj/item/restraints/handcuffs/fake = 2, - /obj/item/grenade/chem_grenade/glitter/pink = 1, - /obj/item/grenade/chem_grenade/glitter/blue = 1, - /obj/item/grenade/chem_grenade/glitter/white = 1, - /obj/item/toy/eightball = 2, - /obj/item/toy/windup_toolbox = 2, - /obj/item/toy/clockwork_watch = 2, - /obj/item/toy/toy_dagger = 2, - /obj/item/extendohand/acme = 1, - /obj/item/hot_potato/harmless/toy = 1, - /obj/item/card/emagfake = 1, - /obj/item/clothing/shoes/wheelys = 2, - /obj/item/clothing/shoes/kindle_kicks = 2, - /obj/item/toy/plush/goatplushie = 2, - /obj/item/toy/plush/moth = 2, - /obj/item/toy/plush/pkplush = 2, - /obj/item/toy/plush/rouny = 2, - /obj/item/toy/plush/abductor = 2, - /obj/item/toy/plush/abductor/agent = 2, - /obj/item/toy/plush/shark = 2, - /obj/item/storage/belt/military/snack/full = 2, - /obj/item/toy/brokenradio = 2, - /obj/item/toy/braintoy = 2, - /obj/item/toy/eldritch_book = 2, - /obj/item/storage/box/heretic_box = 1, - /obj/item/toy/foamfinger = 2, - /obj/item/clothing/glasses/trickblindfold = 2, - /obj/item/clothing/mask/party_horn = 2, - /obj/item/storage/box/party_poppers = 2)) - -/obj/machinery/computer/arcade - name = "\proper the arcade cabinet which shouldn't exist" - desc = "This arcade cabinet has no games installed, and in fact, should not exist. \ - Report the location of this machine to your local diety." - icon_state = "arcade" - icon_keyboard = null - icon_screen = "invaders" - light_color = LIGHT_COLOR_GREEN - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON - var/list/prize_override - -/obj/machinery/computer/arcade/proc/Reset() - return - -/obj/machinery/computer/arcade/Initialize(mapload) - . = ..() - - Reset() - -/obj/machinery/computer/arcade/proc/prizevend(mob/living/user, prizes = 1) - SEND_SIGNAL(src, COMSIG_ARCADE_PRIZEVEND, user, prizes) - if(user.mind?.get_skill_level(/datum/skill/gaming) >= SKILL_LEVEL_LEGENDARY && HAS_TRAIT(user, TRAIT_GAMERGOD)) - visible_message("[user] inputs an intense cheat code!",\ - span_notice("You hear a flurry of buttons being pressed.")) - say("CODE ACTIVATED: EXTRA PRIZES.") - prizes *= 2 - for(var/i in 1 to prizes) - user.add_mood_event("arcade", /datum/mood_event/arcade) - if(prob(0.0001)) //1 in a million - new /obj/item/gun/energy/pulse/prize(src) - visible_message(span_notice("[src] dispenses.. woah, a gun! Way past cool."), span_notice("You hear a chime and a shot.")) - user.client.give_award(/datum/award/achievement/misc/pulse, user) - return - - var/prizeselect - if(prize_override) - prizeselect = pick_weight(prize_override) - else - prizeselect = pick_weight(GLOB.arcade_prize_pool) - var/atom/movable/the_prize = new prizeselect(get_turf(src)) - playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3) - visible_message(span_notice("[src] dispenses [the_prize]!"), span_notice("You hear a chime and a clunk.")) - -/obj/machinery/computer/arcade/emp_act(severity) - . = ..() - var/override = FALSE - if(prize_override) - override = TRUE - - if(machine_stat & (NOPOWER|BROKEN) || . & EMP_PROTECT_SELF) - return - - var/empprize = null - var/num_of_prizes = 0 - switch(severity) - if(1) - num_of_prizes = rand(1,4) - if(2) - num_of_prizes = rand(0,2) - for(var/i = num_of_prizes; i > 0; i--) - if(override) - empprize = pick_weight(prize_override) - else - empprize = pick_weight(GLOB.arcade_prize_pool) - new empprize(loc) - explosion(src, devastation_range = -1, light_impact_range = 1+num_of_prizes, flame_range = 1+num_of_prizes) - -/obj/machinery/computer/arcade/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . - if(!istype(tool, /obj/item/stack/arcadeticket)) - return . - - var/obj/item/stack/arcadeticket/tickets = tool - if(!tickets.use(2)) - balloon_alert(user, "need 2 tickets!") - return ITEM_INTERACT_BLOCKING - - prizevend(user) - balloon_alert(user, "prize claimed") - return ITEM_INTERACT_SUCCESS - -// ** BATTLE ** // -/obj/machinery/computer/arcade/battle - name = "arcade machine" - desc = "Does not support Pinball." - icon_state = "arcade" - circuit = /obj/item/circuitboard/computer/arcade/battle - - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE // we don't need to be literate to play video games fam - - var/enemy_name = "Space Villain" - ///Enemy health/attack points - var/enemy_hp = 100 - var/enemy_mp = 40 - ///Temporary message, for attack messages, etc - var/temp = "

Winners don't use space drugs

" - ///the list of passive skill the enemy currently has. the actual passives are added in the enemy_setup() proc - var/list/enemy_passive - ///if all the enemy's weakpoints have been triggered becomes TRUE - var/finishing_move = FALSE - ///linked to passives, when it's equal or above the max_passive finishing move will become TRUE - var/pissed_off = 0 - ///the number of passives the enemy will start with - var/max_passive = 3 - ///weapon wielded by the enemy, the shotgun doesn't count. - var/chosen_weapon - - ///Player health - var/player_hp = 85 - ///player magic points - var/player_mp = 20 - ///used to remember the last three move of the player before this turn. - var/list/last_three_move - ///if the enemy or player died. restart the game when TRUE - var/gameover = FALSE - ///the player cannot make any move while this is set to TRUE. should only TRUE during enemy turns. - var/blocked = FALSE - ///used to clear the enemy_action proc timer when the game is restarted - var/timer_id - ///weapon used by the enemy, pure fluff.for certain actions - var/list/weapons - ///unique to the emag mode, acts as a time limit where the player dies when it reaches 0. - var/bomb_cooldown = 19 - - -///creates the enemy base stats for a new round along with the enemy passives -/obj/machinery/computer/arcade/battle/proc/enemy_setup(player_skill) - player_hp = 85 - player_mp = 20 - enemy_hp = 100 - enemy_mp = 40 - gameover = FALSE - blocked = FALSE - finishing_move = FALSE - pissed_off = 0 - last_three_move = null - - enemy_passive = list("short_temper" = TRUE, "poisonous" = TRUE, "smart" = TRUE, "shotgun" = TRUE, "magical" = TRUE, "chonker" = TRUE) - for(var/i = LAZYLEN(enemy_passive); i > max_passive; i--) //we'll remove passives from the list until we have the number of passive we want - var/picked_passive = pick(enemy_passive) - LAZYREMOVE(enemy_passive, picked_passive) - - if(LAZYACCESS(enemy_passive, "chonker")) - enemy_hp += 20 - - if(LAZYACCESS(enemy_passive, "shotgun")) - chosen_weapon = "shotgun" - else if(weapons) - chosen_weapon = pick(weapons) - else - chosen_weapon = "null gun" //if the weapons list is somehow empty, shouldn't happen but runtimes are sneaky bastards. - - if(player_skill) - player_hp += player_skill * 2 - - -/obj/machinery/computer/arcade/battle/Reset() - max_passive = 3 - var/name_action - var/name_part1 - var/name_part2 - - if(check_holidays(HALLOWEEN)) - name_action = pick_list(ARCADE_FILE, "rpg_action_halloween") - name_part1 = pick_list(ARCADE_FILE, "rpg_adjective_halloween") - name_part2 = pick_list(ARCADE_FILE, "rpg_enemy_halloween") - weapons = strings(ARCADE_FILE, "rpg_weapon_halloween") - else if(check_holidays(CHRISTMAS)) - name_action = pick_list(ARCADE_FILE, "rpg_action_xmas") - name_part1 = pick_list(ARCADE_FILE, "rpg_adjective_xmas") - name_part2 = pick_list(ARCADE_FILE, "rpg_enemy_xmas") - weapons = strings(ARCADE_FILE, "rpg_weapon_xmas") - else if(check_holidays(VALENTINES)) - name_action = pick_list(ARCADE_FILE, "rpg_action_valentines") - name_part1 = pick_list(ARCADE_FILE, "rpg_adjective_valentines") - name_part2 = pick_list(ARCADE_FILE, "rpg_enemy_valentines") - weapons = strings(ARCADE_FILE, "rpg_weapon_valentines") - else - name_action = pick_list(ARCADE_FILE, "rpg_action") - name_part1 = pick_list(ARCADE_FILE, "rpg_adjective") - name_part2 = pick_list(ARCADE_FILE, "rpg_enemy") - weapons = strings(ARCADE_FILE, "rpg_weapon") - - enemy_name = ("The " + name_part1 + " " + name_part2) - name = (name_action + " " + enemy_name) - - enemy_setup(0) //in the case it's reset we assume the player skill is 0 because the VOID isn't a gamer - - -/obj/machinery/computer/arcade/battle/ui_interact(mob/user) - . = ..() - screen_setup(user) - - -///sets up the main screen for the user -/obj/machinery/computer/arcade/battle/proc/screen_setup(mob/user) - var/dat = "Close" - dat += "

[enemy_name]

" - - dat += "[temp]" - dat += "
Health: [player_hp] | Magic: [player_mp] | Enemy Health: [enemy_hp]
" - - if (gameover) - dat += "
New Game" - else - dat += "
Light attack" - dat += "
Defend" - dat += "
Counter attack" - dat += "
Power attack" - - dat += "
" - if(user.client) //mainly here to avoid a runtime when the player gets gibbed when losing the emag mode. - var/datum/browser/popup = new(user, "arcade", "Space Villain 2000") - popup.set_content(dat) - popup.open() - - -/obj/machinery/computer/arcade/battle/Topic(href, href_list) - if(..()) - return - var/gamerSkill = 0 - if(usr?.mind) - gamerSkill = usr.mind.get_skill_level(/datum/skill/gaming) - - usr.played_game() - - if (!blocked && !gameover) - var/attackamt = rand(5,7) + rand(0, gamerSkill) - - if(finishing_move) //time to bonk that fucker,cuban pete will sometime survive a finishing move. - attackamt *= 100 - - //light attack suck absolute ass but it doesn't cost any MP so it's pretty good to finish an enemy off - if (href_list["attack"]) - temp = "

you do quick jab for [attackamt] of damage!

" - enemy_hp -= attackamt - arcade_action(usr,"attack",attackamt) - - //defend lets you gain back MP and take less damage from non magical attack. - else if(href_list["defend"]) - temp = "

you take a defensive stance and gain back 10 mp!

" - player_mp += 10 - arcade_action(usr,"defend",attackamt) - playsound(src, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3) - - //mainly used to counter short temper and their absurd damage, will deal twice the damage the player took of a non magical attack. - else if(href_list["counter_attack"] && player_mp >= 10) - temp = "

you prepare yourself to counter the next attack!

" - player_mp -= 10 - arcade_action(usr,"counter_attack",attackamt) - playsound(src, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3) - - else if(href_list["counter_attack"] && player_mp < 10) - temp = "

you don't have the mp necessary to counter attack and defend yourself instead

" - player_mp += 10 - arcade_action(usr,"defend",attackamt) - playsound(src, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3) - - //power attack deals twice the amount of damage but is really expensive MP wise, mainly used with combos to get weakpoints. - else if (href_list["power_attack"] && player_mp >= 20) - temp = "

You attack [enemy_name] with all your might for [attackamt * 2] damage!

" - enemy_hp -= attackamt * 2 - player_mp -= 20 - arcade_action(usr,"power_attack",attackamt) - - else if(href_list["power_attack"] && player_mp < 20) - temp = "

You don't have the mp necessary for a power attack and settle for a light attack!

" - enemy_hp -= attackamt - arcade_action(usr,"attack",attackamt) - - if (href_list["close"]) - usr.unset_machine() - usr << browse(null, "window=arcade") - - else if (href_list["newgame"]) //Reset everything - temp = "

New Round

" - - if(obj_flags & EMAGGED) - Reset() - obj_flags &= ~EMAGGED - - enemy_setup(gamerSkill) - screen_setup(usr) - - - add_fingerprint(usr) - return - - -///happens after a player action and before the enemy turn. the enemy turn will be cancelled if there's a gameover. -/obj/machinery/computer/arcade/battle/proc/arcade_action(mob/user,player_stance,attackamt) - screen_setup(user) - blocked = TRUE - if(player_stance == "attack" || player_stance == "power_attack") - if(attackamt > 40) - playsound(src, 'sound/arcade/boom.ogg', 50, TRUE, extrarange = -3) - else - playsound(src, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3) - - timer_id = addtimer(CALLBACK(src, PROC_REF(enemy_action),player_stance,user),1 SECONDS,TIMER_STOPPABLE) - gameover_check(user) - - -///the enemy turn, the enemy's action entirely depend on their current passive and a teensy tiny bit of randomness -/obj/machinery/computer/arcade/battle/proc/enemy_action(player_stance,mob/user) - var/list/list_temp = list() - - switch(LAZYLEN(last_three_move)) //we keep the last three action of the player in a list here - if(0 to 2) - LAZYADD(last_three_move, player_stance) - if(3) - for(var/i in 1 to 2) - last_three_move[i] = last_three_move[i + 1] - last_three_move[3] = player_stance - - if(4 to INFINITY) - last_three_move = null //this shouldn't even happen but we empty the list if it somehow goes above 3 - - var/enemy_stance - var/attack_amount = rand(8,10) //making the attack amount not vary too much so that it's easier to see if the enemy has a shotgun - - if(player_stance == "defend") - attack_amount -= 5 - - //if emagged, cuban pete will set up a bomb acting up as a timer. when it reaches 0 the player fucking dies - if(obj_flags & EMAGGED) - switch(bomb_cooldown--) - if(18) - list_temp += "

[enemy_name] takes two valve tank and links them together, what's he planning?

" - if(15) - list_temp += "

[enemy_name] adds a remote control to the tan- ho god is that a bomb?

" - if(12) - list_temp += "

[enemy_name] throws the bomb next to you, you'r too scared to pick it up.

" - if(6) - list_temp += "

[enemy_name]'s hand brushes the remote linked to the bomb, your heart skipped a beat.

" - if(2) - list_temp += "

[enemy_name] is going to press the button! It's now or never!

" - if(0) - player_hp -= attack_amount * 1000 //hey it's a maxcap we might as well go all in - - //yeah I used the shotgun as a passive, you know why? because the shotgun gives +5 attack which is pretty good - if(LAZYACCESS(enemy_passive, "shotgun")) - if(weakpoint_check("shotgun","defend","defend","power_attack")) - list_temp += "

You manage to disarm [enemy_name] with a surprise power attack and shoot him with his shotgun until it runs out of ammo!

" - enemy_hp -= 10 - chosen_weapon = "empty shotgun" - else - attack_amount += 5 - - //heccing chonker passive, only gives more HP at the start of a new game but has one of the hardest weakpoint to trigger. - if(LAZYACCESS(enemy_passive, "chonker")) - if(weakpoint_check("chonker","power_attack","power_attack","power_attack")) - list_temp += "

After a lot of power attacks you manage to tip over [enemy_name] as they fall over their enormous weight

" - enemy_hp -= 30 - - //smart passive trait, mainly works in tandem with other traits, makes the enemy unable to be counter_attacked - if(LAZYACCESS(enemy_passive, "smart")) - if(weakpoint_check("smart","defend","defend","attack")) - list_temp += "

[enemy_name] is confused by your illogical strategy!

" - attack_amount -= 5 - - else if(attack_amount >= player_hp) - player_hp -= attack_amount - list_temp += "

[enemy_name] figures out you are really close to death and finishes you off with their [chosen_weapon]!

" - enemy_stance = "attack" - - else if(player_stance == "counter_attack") - list_temp += "

[enemy_name] is not taking your bait.

" - if(LAZYACCESS(enemy_passive, "short_temper")) - list_temp += "However controlling their hatred of you still takes a toll on their mental and physical health!" - enemy_hp -= 5 - enemy_mp -= 5 - enemy_stance = "defensive" - - //short temper passive trait, gets easily baited into being counter attacked but will bypass your counter when low on HP - if(LAZYACCESS(enemy_passive, "short_temper")) - if(weakpoint_check("short_temper","counter_attack","counter_attack","counter_attack")) - list_temp += "

[enemy_name] is getting frustrated at all your counter attacks and throws a tantrum!

" - enemy_hp -= attack_amount - - else if(player_stance == "counter_attack") - if(!(LAZYACCESS(enemy_passive, "smart")) && enemy_hp > 30) - list_temp += "

[enemy_name] took the bait and allowed you to counter attack for [attack_amount * 2] damage!

" - player_hp -= attack_amount - enemy_hp -= attack_amount * 2 - enemy_stance = "attack" - - else if(enemy_hp <= 30) //will break through the counter when low enough on HP even when smart. - list_temp += "

[enemy_name] is getting tired of your tricks and breaks through your counter with their [chosen_weapon]!

" - player_hp -= attack_amount - enemy_stance = "attack" - - else if(!enemy_stance) - var/added_temp - - if(rand()) - added_temp = "you for [attack_amount + 5] damage!" - player_hp -= attack_amount + 5 - enemy_stance = "attack" - else - added_temp = "the wall, breaking their skull in the process and losing [attack_amount] hp!" //[enemy_name] you have a literal dent in your skull - enemy_hp -= attack_amount - enemy_stance = "attack" - - list_temp += "

[enemy_name] grits their teeth and charge right into [added_temp]

" - - //in the case none of the previous passive triggered, Mainly here to set an enemy stance for passives that needs it like the magical passive. - if(!enemy_stance) - enemy_stance = pick("attack","defensive") - if(enemy_stance == "attack") - player_hp -= attack_amount - list_temp += "

[enemy_name] attacks you for [attack_amount] points of damage with their [chosen_weapon]

" - if(player_stance == "counter_attack") - enemy_hp -= attack_amount * 2 - list_temp += "

You counter [enemy_name]'s attack and deal [attack_amount * 2] points of damage!

" - - if(enemy_stance == "defensive" && enemy_mp < 15) - list_temp += "

[enemy_name] take some time to get some mp back!

" - enemy_mp += attack_amount - - else if (enemy_stance == "defensive" && enemy_mp >= 15 && !(LAZYACCESS(enemy_passive, "magical"))) - list_temp += "

[enemy_name] quickly heal themselves for 5 hp!

" - enemy_mp -= 15 - enemy_hp += 5 - - //magical passive trait, recharges MP nearly every turn it's not blasting you with magic. - if(LAZYACCESS(enemy_passive, "magical")) - if(player_mp >= 50) - list_temp += "

the huge amount of magical energy you have acumulated throws [enemy_name] off balance!

" - enemy_mp = 0 - LAZYREMOVE(enemy_passive, "magical") - pissed_off++ - - else if(LAZYACCESS(enemy_passive, "smart") && player_stance == "counter_attack" && enemy_mp >= 20) - list_temp += "

[enemy_name] blasts you with magic from afar for 10 points of damage before you can counter!

" - player_hp -= 10 - enemy_mp -= 20 - - else if(enemy_hp >= 20 && enemy_mp >= 40 && enemy_stance == "defensive") - list_temp += "

[enemy_name] Blasts you with magic from afar!

" - enemy_mp -= 40 - player_hp -= 30 - enemy_stance = "attack" - - else if(enemy_hp < 20 && enemy_mp >= 20 && enemy_stance == "defensive") //it's a pretty expensive spell so they can't spam it that much - list_temp += "

[enemy_name] heal themselves with magic and gain back 20 hp!

" - enemy_hp += 20 - enemy_mp -= 30 - else - list_temp += "

[enemy_name]'s magical nature lets them get some mp back!

" - enemy_mp += attack_amount - - //poisonous passive trait, while it's less damage added than the shotgun it acts up even when the enemy doesn't attack at all. - if(LAZYACCESS(enemy_passive, "poisonous")) - if(weakpoint_check("poisonous","attack","attack","attack")) - list_temp += "

your flurry of attack throws back the poisonnous gas at [enemy_name] and makes them choke on it!

" - enemy_hp -= 5 - else - list_temp += "

the stinky breath of [enemy_name] hurts you for 3 hp!

" - player_hp -= 3 - - //if all passive's weakpoint have been triggered, set finishing_move to TRUE - if(pissed_off >= max_passive && !finishing_move) - list_temp += "

You have weakened [enemy_name] enough for them to show their weak point, you will do 10 times as much damage with your next attack!

" - finishing_move = TRUE - - playsound(src, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3) - - temp = list_temp.Join() - gameover_check(user) - screen_setup(user) - blocked = FALSE - - -/obj/machinery/computer/arcade/battle/proc/gameover_check(mob/user) - var/xp_gained = 0 - if(enemy_hp <= 0) - if(!gameover) - if(timer_id) - deltimer(timer_id) - timer_id = null - if(player_hp <= 0) - player_hp = 1 //let's just pretend the enemy didn't kill you so not both the player and enemy look dead. - gameover = TRUE - blocked = FALSE - temp = "

[enemy_name] has fallen! Rejoice!

" - playsound(loc, 'sound/arcade/win.ogg', 50, TRUE) - - if(obj_flags & EMAGGED) - new /obj/effect/spawner/newbomb/plasma(loc, /obj/item/assembly/timer) - new /obj/item/clothing/head/collectable/petehat(loc) - message_admins("[ADMIN_LOOKUPFLW(usr)] has outbombed Cuban Pete and been awarded a bomb.") - usr.log_message("outbombed Cuban Pete and has been awarded a bomb.", LOG_GAME) - Reset() - obj_flags &= ~EMAGGED - xp_gained += 100 - else - new /obj/item/stack/arcadeticket((get_turf(src)), 2) - to_chat(user, span_notice("[src] dispenses 2 tickets!")) - xp_gained += 50 - SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("win", (obj_flags & EMAGGED ? "emagged":"normal"))) - user.won_game() - - else if(player_hp <= 0) - if(timer_id) - deltimer(timer_id) - timer_id = null - gameover = TRUE - temp = "

You have been crushed! GAME OVER

" - playsound(loc, 'sound/arcade/lose.ogg', 50, TRUE) - xp_gained += 10//pity points - if(obj_flags & EMAGGED) - var/mob/living/living_user = user - if (istype(living_user)) - living_user.investigate_log("has been gibbed by an emagged Orion Trail game.", INVESTIGATE_DEATHS) - living_user.gib(DROP_ALL_REMAINS) - SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "hp", (obj_flags & EMAGGED ? "emagged":"normal"))) - user.lost_game() - - if(gameover) - user?.mind?.adjust_experience(/datum/skill/gaming, xp_gained+1)//always gain at least 1 point of XP - - -///used to check if the last three move of the player are the one we want in the right order and if the passive's weakpoint has been triggered yet -/obj/machinery/computer/arcade/battle/proc/weakpoint_check(passive,first_move,second_move,third_move) - if(LAZYLEN(last_three_move) < 3) - return FALSE - - if(last_three_move[1] == first_move && last_three_move[2] == second_move && last_three_move[3] == third_move && LAZYACCESS(enemy_passive, passive)) - LAZYREMOVE(enemy_passive, passive) - pissed_off++ - return TRUE - else - return FALSE - - -/obj/machinery/computer/arcade/battle/Destroy() - enemy_passive = null - weapons = null - last_three_move = null - return ..() //well boys we did it, lists are no more - -/obj/machinery/computer/arcade/battle/examine_more(mob/user) - . = ..() - . += span_notice("You notice some writing scribbled on the side of [src]...") - . += "\t[span_info("smart -> defend, defend, light attack")]" - . += "\t[span_info("shotgun -> defend, defend, power attack")]" - . += "\t[span_info("short temper -> counter, counter, counter")]" - . += "\t[span_info("poisonous -> light attack, light attack, light attack")]" - . += "\t[span_info("chonker -> power attack, power attack, power attack")]" - . += "\t[span_info("magical -> defend until outmagiced")]" - return . - -/obj/machinery/computer/arcade/battle/emag_act(mob/user, obj/item/card/emag/emag_card) - if(obj_flags & EMAGGED) - return FALSE - - balloon_alert(user, "hard mode enabled") - to_chat(user, span_warning("A mesmerizing Rhumba beat starts playing from the arcade machine's speakers!")) - temp = "

If you die in the game, you die for real!

" - max_passive = 6 - bomb_cooldown = 18 - var/gamerSkill = 0 - if(user?.mind) - gamerSkill = user.mind.get_skill_level(/datum/skill/gaming) - enemy_setup(gamerSkill) - enemy_hp += 100 //extra HP just to make cuban pete even more bullshit - player_hp += 30 //the player will also get a few extra HP in order to have a fucking chance - - screen_setup(user) - gameover = FALSE - - obj_flags |= EMAGGED - - enemy_name = "Cuban Pete" - name = "Outbomb Cuban Pete" - - updateUsrDialog() - return TRUE - -// ** AMPUTATION ** // - -/obj/machinery/computer/arcade/amputation - name = "Mediborg's Amputation Adventure" - desc = "A picture of a blood-soaked medical cyborg flashes on the screen. The mediborg has a speech bubble that says, \"Put your hand in the machine if you aren't a coward!\"" - icon_state = "arcade" - circuit = /obj/item/circuitboard/computer/arcade/amputation - -/obj/machinery/computer/arcade/amputation/attack_tk(mob/user) - return //that's a pretty damn big guillotine - -/obj/machinery/computer/arcade/amputation/attack_hand(mob/user, list/modifiers) - . = ..() - if(!iscarbon(user)) - return - to_chat(user, span_warning("You move your hand towards the machine, and begin to hesitate as a bloodied guillotine emerges from inside of it...")) - user.played_game() - var/obj/item/bodypart/chopchop = user.get_active_hand() - if(do_after(user, 5 SECONDS, target = src, extra_checks = CALLBACK(src, PROC_REF(do_they_still_have_that_hand), user, chopchop))) - playsound(src, 'sound/weapons/slice.ogg', 25, TRUE, -1) - to_chat(user, span_userdanger("The guillotine drops on your arm, and the machine sucks it in!")) - chopchop.dismember() - qdel(chopchop) - user.mind?.adjust_experience(/datum/skill/gaming, 100) - user.won_game() - playsound(src, 'sound/arcade/win.ogg', 50, TRUE) - new /obj/item/stack/arcadeticket((get_turf(src)), rand(6,10)) - to_chat(user, span_notice("[src] dispenses a handful of tickets!")) - return - else if(!do_they_still_have_that_hand(user, chopchop)) - to_chat(user, span_warning("The guillotine drops, but your hand seems to be gone already!")) - playsound(src, 'sound/weapons/slice.ogg', 25, TRUE, -1) - else - to_chat(user, span_notice("You (wisely) decide against putting your hand in the machine.")) - user.lost_game() - -///Makes sure the user still has their starting hand. -/obj/machinery/computer/arcade/amputation/proc/do_they_still_have_that_hand(mob/user, obj/item/bodypart/chopchop) - if(QDELETED(chopchop) || chopchop.owner != user) //No pulling your arm out of the machine! - return FALSE - return TRUE - - -/obj/machinery/computer/arcade/amputation/festive //dispenses wrapped gifts instead of arcade prizes, also known as the ancap christmas tree - name = "Mediborg's Festive Amputation Adventure" - desc = "A picture of a blood-soaked medical cyborg wearing a Santa hat flashes on the screen. The mediborg has a speech bubble that says, \"Put your hand in the machine if you aren't a coward!\"" - prize_override = list(/obj/item/gift/anything = 1) diff --git a/code/game/machinery/computer/arcade/battle.dm b/code/game/machinery/computer/arcade/battle.dm new file mode 100644 index 0000000000000..b97dac9e15dad --- /dev/null +++ b/code/game/machinery/computer/arcade/battle.dm @@ -0,0 +1,560 @@ +///How many enemies needs to be defeated until the 'Boss' of the stage appears. +#define WORLD_ENEMY_BOSS 2 +///The default amount of EXP you gain from killing an enemy, modifiers stacked on top of this. +#define DEFAULT_EXP_GAIN 50 +///The default cost to purchase an item. Sleeping at the Inn is half of this. +#define DEFAULT_ITEM_PRICE 30 + +///The max HP the player can have at any time. +#define PLAYER_MAX_HP 100 +///The max MP the player can have at any time. +#define PLAYER_MAX_MP 50 +///The default cost of a spell, in MP. Defending will instead restore this amount. +#define SPELL_MP_COST 10 + +///The player is currently in the Shop. +#define UI_PANEL_SHOP "Shop" +///The player is currently in the World Map. +#define UI_PANEL_WORLD_MAP "World Map" +///The player is currently in Batle. +#define UI_PANEL_BATTLE "Battle" +///The player is currently between battles. +#define UI_PANEL_BETWEEN_FIGHTS "Between Battle" +///The player is currently Game Overed. +#define UI_PANEL_GAMEOVER "Game Over" + +///The player is set to counterattack the enemy's next move. +#define BATTLE_ATTACK_FLAG_COUNTERATTACK (1<<0) +///The player is set to defend against the enemy's next move. +#define BATTLE_ATTACK_FLAG_DEFEND (1<<1) + +///The player is trying to Attack the Enemy. +#define BATTLE_ARCADE_PLAYER_ATTACK "Attack" +///The player is trying to Attack the Enemy with an MP boost. +#define BATTLE_ARCADE_PLAYER_HEAVY_ATTACK "Heavy Attack" +///The player is setting themselves to counterattack a potential incoming Enemy attack. +#define BATTLE_ARCADE_PLAYER_COUNTERATTACK "Counterattack" +///The player is defending against the Enemy and restoring MP. +#define BATTLE_ARCADE_PLAYER_DEFEND "Defend" + +/obj/machinery/computer/arcade/battle + name = "battle arcade" + desc = "Explore vast worlds and conquer." + icon_state = "arcade" + icon_screen = "fighters" + circuit = /obj/item/circuitboard/computer/arcade/battle + + ///List of all battle arcade gear that is available in the shop in game. + var/static/list/battle_arcade_gear_list + ///List of all worlds in the game. + var/static/list/all_worlds = list( + BATTLE_WORLD_ONE = 1, + BATTLE_WORLD_TWO = 1.25, + BATTLE_WORLD_THREE = 1.5, + BATTLE_WORLD_FOUR = 1.75, + BATTLE_WORLD_FIVE = 2, + BATTLE_WORLD_SIX = 2.25, + BATTLE_WORLD_SEVEN = 2.5, + BATTLE_WORLD_EIGHT = 2.75, + BATTLE_WORLD_NINE = 3, + ) + var/static/list/all_attack_types = list( + BATTLE_ARCADE_PLAYER_ATTACK = "Attack the enemy in a default attack at no MP cost.", + BATTLE_ARCADE_PLAYER_HEAVY_ATTACK = "Attack the enemy with the power of Magic, costing MP for additional damage.", + BATTLE_ARCADE_PLAYER_COUNTERATTACK = "Use magic to prepare a counterattack of your enemy, allowing you to deal extra damage if you succeed.", + BATTLE_ARCADE_PLAYER_DEFEND = "Defend from the next incoming attack, lowing the amount of damage you take while restoring some HP and MP.", + ) + ///The world we're currently in. + var/player_current_world = BATTLE_WORLD_ONE + ///The latest world the player has unlocked, granting access to all worlds below this. + var/latest_unlocked_world = BATTLE_WORLD_ONE + ///How many enemies we've defeated in a row, used to tell when we need to spawn the boss in. + var/enemies_defeated + ///The current panel the player is viewieng in the UI. + var/ui_panel = UI_PANEL_WORLD_MAP + + /** PLAYER INFORMATION */ + + ///Boolean on whether it's the player's time to do their turn. + var/player_turn = TRUE + ///How much money the player has, used in the Inn. Starts with the default price for a single item. + var/player_gold = DEFAULT_ITEM_PRICE + ///The current amount of HP the player has. + var/player_current_hp = PLAYER_MAX_HP + ///The current amount of MP the player has. + var/player_current_mp = PLAYER_MAX_MP + ///Assoc list of gear the player has equipped. + var/list/datum/battle_arcade_gear/equipped_gear = list( + WEAPON_SLOT = null, + ARMOR_SLOT = null, + ) + + /** CURRENT ENEMY INFORMATION */ + + ///A feedback message displayed in the UI during combat sequences. + var/feedback_message + ///Determines which boss image to use on the UI. + var/enemy_icon_id = 1 + ///The enemy's name + var/enemy_name + ///How much HP the current enemy has. + var/enemy_max_hp + ///How much HP the current enemy has. + var/enemy_hp + ///How much MP the current enemy has. + var/enemy_mp + ///How much gold the enemy will drop, randomized on new opponent. + var/enemy_gold_reward + ///unique to the emag mode, acts as a time limit where the player dies when it reaches 0. + var/bomb_cooldown = 19 + +/obj/machinery/computer/arcade/battle/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + if(isnull(battle_arcade_gear_list)) + var/list/all_gear = list() + for(var/datum/battle_arcade_gear/template as anything in subtypesof(/datum/battle_arcade_gear)) + if(!(template::slot)) //needs to fit in something. + continue + all_gear[template::name] = new template + battle_arcade_gear_list = all_gear + +/obj/machinery/computer/arcade/battle/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + return FALSE + obj_flags |= EMAGGED + balloon_alert(user, "hard mode enabled") + to_chat(user, span_warning("A mesmerizing Rhumba beat starts playing from the arcade machine's speakers!")) + setup_new_opponent() + feedback_message = "If you die in the game, you die for real!" + SStgui.update_uis(src) + return TRUE + +/obj/machinery/computer/arcade/battle/reset_cabinet(mob/living/user) + enemy_name = null + player_turn = initial(player_turn) + feedback_message = initial(feedback_message) + player_current_world = initial(player_current_world) + latest_unlocked_world = initial(latest_unlocked_world) + enemies_defeated = initial(enemies_defeated) + player_gold = initial(player_gold) + player_current_hp = initial(player_current_hp) + player_current_mp = initial(player_current_mp) + ui_panel = initial(ui_panel) + bomb_cooldown = initial(bomb_cooldown) + equipped_gear = list(WEAPON_SLOT = null, ARMOR_SLOT = null) + return ..() + +///Sets up a new opponent depending on what stage they are at. +/obj/machinery/computer/arcade/battle/proc/setup_new_opponent(enemy_gets_first_move = FALSE) + var/name_adjective + var/new_name + + if(check_holidays(HALLOWEEN)) + name_adjective = pick_list(ARCADE_FILE, "rpg_adjective_halloween") + new_name = pick_list(ARCADE_FILE, "rpg_enemy_halloween") + else if(check_holidays(CHRISTMAS)) + name_adjective = pick_list(ARCADE_FILE, "rpg_adjective_xmas") + new_name = pick_list(ARCADE_FILE, "rpg_enemy_xmas") + else if(check_holidays(VALENTINES)) + name_adjective = pick_list(ARCADE_FILE, "rpg_adjective_valentines") + new_name = pick_list(ARCADE_FILE, "rpg_enemy_valentines") + else + name_adjective = pick_list(ARCADE_FILE, "rpg_adjective") + new_name = pick_list(ARCADE_FILE, "rpg_enemy") + + enemy_hp = round(rand(90, 125) * all_worlds[player_current_world], 1) + enemy_mp = round(rand(20, 30) * all_worlds[player_current_world], 1) + enemy_gold_reward = rand((DEFAULT_ITEM_PRICE / 2), DEFAULT_ITEM_PRICE) + + // there's only one boss in each stage (except the last) + if((player_current_world == latest_unlocked_world) && enemies_defeated == WORLD_ENEMY_BOSS) + enemy_mp *= 1.25 + enemy_hp *= 1.25 + enemy_gold_reward *= 1.5 + name_adjective = "Big Boss" + + enemy_icon_id = rand(1,6) + enemy_name = "The [name_adjective] [new_name]" + feedback_message = "New game started against [enemy_name]" + + if(obj_flags & EMAGGED) + enemy_name = "Cuban Pete" + enemy_hp += 100 //extra HP just to make cuban pete even more bullshit + + //set max HP to reference later + enemy_max_hp = enemy_hp + //set the player to fight now. + ui_panel = UI_PANEL_BATTLE + + if(enemy_gets_first_move) + perform_enemy_turn() + +/** + * on_battle_win + * + * Called when the player wins a level, this handles giving EXP, loot, tickets, etc. + * It also handles clearing the enemy out for the next one, and unlocking new worlds. + * We stop at BATTLE_WORLD_NINE because it is the last stage, and has infinite bosses. + */ +/obj/machinery/computer/arcade/battle/proc/on_battle_win(mob/user) + enemy_name = null + feedback_message = null + player_turn = TRUE + if(player_current_world == latest_unlocked_world) + if(enemies_defeated == WORLD_ENEMY_BOSS) + enemies_defeated = 0 + //the last stage doesn't have a next one to move onto. + if(latest_unlocked_world != BATTLE_WORLD_NINE) + var/current_world = all_worlds.Find(latest_unlocked_world) + latest_unlocked_world = all_worlds[current_world + 1] + ui_panel = UI_PANEL_WORLD_MAP + say("New world unlocked, [latest_unlocked_world]!") + enemies_defeated++ + if(obj_flags & EMAGGED) + obj_flags &= ~EMAGGED + bomb_cooldown = initial(bomb_cooldown) + new /obj/effect/spawner/newbomb/plasma(loc, /obj/item/assembly/timer) + new /obj/item/clothing/head/collectable/petehat(loc) + message_admins("[ADMIN_LOOKUPFLW(usr)] has outbombed Cuban Pete and been awarded a bomb.") + usr.log_message("outbombed Cuban Pete and has been awarded a bomb.", LOG_GAME) + else + visible_message(span_notice("[src] dispenses 2 tickets!")) + new /obj/item/stack/arcadeticket((get_turf(src)), 2) + player_gold += enemy_gold_reward + if(user) + var/exp_gained = DEFAULT_EXP_GAIN * all_worlds[player_current_world] + user.mind?.adjust_experience(/datum/skill/gaming, exp_gained) + user.won_game() + SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("win", (obj_flags & EMAGGED ? "emagged":"normal"))) + playsound(loc, 'sound/arcade/win.ogg', 40) + if(ui_panel != UI_PANEL_WORLD_MAP) //we havent been booted to world map, we're still going. + ui_panel = UI_PANEL_BETWEEN_FIGHTS + +///Called when a mob loses at the battle arcade. +/obj/machinery/computer/arcade/battle/proc/lose_game(mob/user) + if(obj_flags & EMAGGED) + var/mob/living/living_user = user + if(istype(living_user)) + living_user.investigate_log("has been gibbed by an emagged Orion Trail game.", INVESTIGATE_DEATHS) + living_user.gib(DROP_ALL_REMAINS) + user.lost_game() + SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "hp", (obj_flags & EMAGGED ? "emagged":"normal"))) + SStgui.update_uis(src) + +///Called when the enemy attacks you. +/obj/machinery/computer/arcade/battle/proc/user_take_damage(mob/user, base_damage_taken) + var/datum/battle_arcade_gear/armor = equipped_gear[ARMOR_SLOT] + var/damage_taken = (base_damage_taken * all_worlds[player_current_world]) / (!isnull(armor) ? armor.bonus_modifier : 1) + player_current_hp -= round(max(0, damage_taken), 1) + if(player_current_hp <= 0) + ui_panel = UI_PANEL_GAMEOVER + feedback_message = "GAME OVER." + say("You have been crushed! GAME OVER.") + playsound(loc, 'sound/arcade/lose.ogg', 40, TRUE) + lose_game(user) + else + feedback_message = "User took [damage_taken] damage!" + playsound(loc, 'sound/arcade/hit.ogg', 40, TRUE, extrarange = -3) + SStgui.update_uis(src) + +///Called when you attack the enemy. +/obj/machinery/computer/arcade/battle/proc/process_player_attack(mob/user, attack_type) + var/damage_dealt + switch(attack_type) + if(BATTLE_ARCADE_PLAYER_ATTACK) + var/datum/battle_arcade_gear/weapon = equipped_gear[WEAPON_SLOT] + damage_dealt = (rand(5, 15) * (!isnull(weapon) ? weapon.bonus_modifier : 1)) + if(BATTLE_ARCADE_PLAYER_HEAVY_ATTACK) + var/datum/battle_arcade_gear/weapon = equipped_gear[WEAPON_SLOT] + damage_dealt = (rand(15, 25) * (!isnull(weapon) ? weapon.bonus_modifier : 1)) + if(BATTLE_ARCADE_PLAYER_COUNTERATTACK) + feedback_message = "User prepares to counterattack!" + process_enemy_turn(user, defending_flags = BATTLE_ATTACK_FLAG_COUNTERATTACK) + playsound(loc, 'sound/arcade/mana.ogg', 40, TRUE, extrarange = -3) + if(BATTLE_ARCADE_PLAYER_DEFEND) + feedback_message = "User pulls up their shield!" + process_enemy_turn(user, defending_flags = BATTLE_ATTACK_FLAG_DEFEND) + playsound(loc, 'sound/arcade/mana.ogg', 40, TRUE, extrarange = -3) + + if(!damage_dealt) + return + enemy_hp -= round(max(0, damage_dealt), 1) + feedback_message = "[enemy_name] took [damage_dealt] damage!" + playsound(loc, 'sound/arcade/hit.ogg', 40, TRUE, extrarange = -3) + process_enemy_turn(user) + +///Called when you successfully counterattack the enemy. +/obj/machinery/computer/arcade/battle/proc/successful_counterattack(mob/user) + var/datum/battle_arcade_gear/weapon = equipped_gear[WEAPON_SLOT] + var/damage_dealt = (rand(20, 30) * (!isnull(weapon) ? weapon.bonus_modifier : 1)) + enemy_hp -= round(max(0, damage_dealt), 1) + feedback_message = "User counterattacked for [damage_dealt] damage!" + playsound(loc, 'sound/arcade/boom.ogg', 40, TRUE, extrarange = -3) + if(enemy_hp <= 0) + on_battle_win(user) + SStgui.update_uis(src) + +///Handles the delay between the user's and enemy's turns to process what's going on. +/obj/machinery/computer/arcade/battle/proc/process_enemy_turn(mob/user, defending_flags = NONE) + if(enemy_hp <= 0) + return on_battle_win(user) + //if emagged, cuban pete will set up a bomb acting up as a timer. when it reaches 0 the player fucking dies + + if(obj_flags & EMAGGED) + bomb_cooldown-- + switch(bomb_cooldown) + if(18) + feedback_message = "[enemy_name] takes two valve tank and links them together, what's he planning?" + if(15) + feedback_message = "[enemy_name] adds a remote control to the tan- ho god is that a bomb?" + if(12) + feedback_message = "[enemy_name] throws the bomb next to you, you'r too scared to pick it up." + if(6) + feedback_message = "[enemy_name]'s hand brushes the remote linked to the bomb, your heart skipped a beat." + if(2) + feedback_message = "[enemy_name] is going to press the button! It's now or never!" + if(0) + player_current_hp = 0 //instant death + addtimer(CALLBACK(src, PROC_REF(perform_enemy_turn), user, defending_flags), 1 SECONDS) + +/** + * perform_enemy_turn + * + * Actually performs the enemy's turn. + * We first roll to see if the enemy should use magic. As their HP goes lower, the chances of self healing goes higher, but + * if they lack the MP, then it's rolling to steal MP from the player. + * After, we will roll to see if the player counterattacks the enemy (if set), otherwise we will attack normally. + */ +/obj/machinery/computer/arcade/battle/proc/perform_enemy_turn(mob/user, defending_flags = NONE) + player_turn = TRUE + var/chance_to_magic = round(max((-(enemy_hp - enemy_max_hp) / 2), 75), 1) + if((enemy_hp != enemy_max_hp) && prob(chance_to_magic)) + if(enemy_mp >= 10) + var/healed_amount = rand(10, 20) + enemy_hp = round(min(enemy_max_hp, enemy_hp + healed_amount), 1) + enemy_mp -= round(max(0, 10), 1) + feedback_message = "[enemy_name] healed for [healed_amount] health points!" + playsound(loc, 'sound/arcade/heal.ogg', 40, TRUE, extrarange = -3) + SStgui.update_uis(src) + return + if(player_current_mp >= 5) //minimum to steal + var/healed_amount = rand(5, 10) + player_current_mp -= round(max(0, healed_amount), 1) + enemy_mp += healed_amount + feedback_message = "[enemy_name] stole [healed_amount] MP from you!" + playsound(loc, 'sound/arcade/steal.ogg', 40, TRUE) + SStgui.update_uis(src) + return + //we couldn't heal ourselves or steal MP, we'll just attack instead. + var/skill_level = user?.mind?.get_skill_level(/datum/skill/gaming) || 1 + var/chance_at_counterattack = 40 + (skill_level * 5) //at level 1 this is 45, at legendary this is 75 + var/damage_dealt = (defending_flags & BATTLE_ATTACK_FLAG_DEFEND) ? rand(5, 10) : rand(15, 20) + if((defending_flags & BATTLE_ATTACK_FLAG_COUNTERATTACK) && prob(chance_at_counterattack)) + return successful_counterattack(user) + return user_take_damage(user, damage_dealt) + +/obj/machinery/computer/arcade/battle/ui_data(mob/user) + var/list/data = ..() + + data["feedback_message"] = feedback_message + data["shop_items"] = list() + for(var/gear_name in battle_arcade_gear_list) + var/datum/battle_arcade_gear/gear = battle_arcade_gear_list[gear_name] + if(latest_unlocked_world != gear.world_available) + continue + data["shop_items"] += list(gear_name) + data["ui_panel"] = ui_panel + data["player_current_world"] = player_current_world + data["unlocked_world_modifier"] = all_worlds[latest_unlocked_world] + data["latest_unlocked_world_position"] = all_worlds.Find(latest_unlocked_world) + data["player_gold"] = player_gold + data["player_current_hp"] = player_current_hp + data["player_current_mp"] = player_current_mp + data["enemy_icon_id"] = "boss[enemy_icon_id].gif" + data["enemy_name"] = enemy_name + data["enemy_max_hp"] = enemy_max_hp + data["enemy_hp"] = enemy_hp + data["enemy_mp"] = enemy_mp + + data["equipped_gear"] = list() + for(var/gear_slot as anything in equipped_gear) + var/datum/battle_arcade_gear/user_gear = equipped_gear[gear_slot] + if(!istype(user_gear)) + continue + data["equipped_gear"] += list(list( + "name" = user_gear.name, + "slot" = gear_slot, + )) + + return data + +/obj/machinery/computer/arcade/battle/ui_static_data(mob/user) + var/list/data = ..() + + data["all_worlds"] = list() + for(var/individual_world in all_worlds) + UNTYPED_LIST_ADD(data["all_worlds"], individual_world) + data["attack_types"] = list() + for(var/individual_attack_type in all_attack_types) + UNTYPED_LIST_ADD(data["attack_types"], list("name" = individual_attack_type, "tooltip" = all_attack_types[individual_attack_type])) + data["cost_of_items"] = DEFAULT_ITEM_PRICE + data["max_hp"] = PLAYER_MAX_HP + data["max_mp"] = PLAYER_MAX_MP + + return data + +/obj/machinery/computer/arcade/battle/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/arcade), + ) + +/obj/machinery/computer/arcade/battle/ui_interact(mob/user, datum/tgui/ui) + . = ..() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BattleArcade", "Battle Arcade") + ui.set_autoupdate(FALSE) + ui.open() + +/obj/machinery/computer/arcade/battle/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + var/mob/living/gamer = ui.user + if(!istype(gamer)) + return + + switch(ui_panel) + if(UI_PANEL_GAMEOVER) + switch(action) + if("restart") + reset_cabinet() + return TRUE + if(UI_PANEL_SHOP) + switch(action) + if("sleep") + if(player_gold < DEFAULT_ITEM_PRICE / 2) + say("You don't have enough gold to rest!") + return TRUE + player_gold -= DEFAULT_ITEM_PRICE / 2 + playsound(loc, 'sound/mecha/skyfall_power_up.ogg', 40) + player_current_hp = PLAYER_MAX_HP + player_current_mp = PLAYER_MAX_MP + return TRUE + if("buy_item") + var/datum/battle_arcade_gear/gear = battle_arcade_gear_list[params["purchasing_item"]] + if(latest_unlocked_world != gear.world_available || equipped_gear[gear.slot] == gear) + say("That item is not in stock.") + return TRUE + if(player_gold < (DEFAULT_ITEM_PRICE * all_worlds[latest_unlocked_world])) + say("You don't have enough gold to buy that!") + return TRUE + player_gold -= DEFAULT_ITEM_PRICE * all_worlds[latest_unlocked_world] + equipped_gear[gear.slot] = gear + return TRUE + if("leave") + ui_panel = UI_PANEL_WORLD_MAP + return TRUE + if(UI_PANEL_WORLD_MAP) + switch(action) + if("start_fight") + var/world_travelling = all_worlds.Find(params["selected_arena"]) + var/max_unlocked_worlds = all_worlds.Find(latest_unlocked_world) + if(world_travelling > max_unlocked_worlds) + say("That world is not unlocked yet!") + return TRUE + player_current_world = all_worlds[world_travelling] + setup_new_opponent() + return TRUE + if("enter_inn") + ui_panel = UI_PANEL_SHOP + return TRUE + if(UI_PANEL_BETWEEN_FIGHTS) + switch(action) + if("continue_without_rest") + setup_new_opponent() + return TRUE + if("continue_with_rest") + if(prob(60)) + playsound(loc, 'sound/mecha/skyfall_power_up.ogg', 40) + player_current_hp = PLAYER_MAX_HP + player_current_mp = PLAYER_MAX_MP + else + playsound(loc, 'sound/machines/defib_zap.ogg', 40) + if(prob(40)) + //You got robbed, and now have to go to your next fight. + player_gold /= 2 + else + //You got ambushed, the enemy gets the first hit. + setup_new_opponent(enemy_gets_first_move = TRUE) + return TRUE + setup_new_opponent() + return TRUE + if("abandon_quest") + if(player_current_world == latest_unlocked_world) + enemies_defeated = 0 + ui_panel = UI_PANEL_WORLD_MAP + return TRUE + if(UI_PANEL_BATTLE) + if(!player_turn) + return TRUE + player_turn = FALSE + switch(action) + if(BATTLE_ARCADE_PLAYER_ATTACK) + process_player_attack(gamer, BATTLE_ARCADE_PLAYER_ATTACK) + return TRUE + if(BATTLE_ARCADE_PLAYER_HEAVY_ATTACK) + if(player_current_mp < SPELL_MP_COST) + say("You don't have enough MP to counterattack!") + player_turn = TRUE + return TRUE + player_current_mp -= SPELL_MP_COST + process_player_attack(gamer, BATTLE_ARCADE_PLAYER_HEAVY_ATTACK) + return TRUE + if(BATTLE_ARCADE_PLAYER_COUNTERATTACK) + if(player_current_mp < SPELL_MP_COST) + say("You don't have enough MP to counterattack!") + player_turn = TRUE + return TRUE + player_current_mp -= SPELL_MP_COST + process_player_attack(gamer, BATTLE_ARCADE_PLAYER_COUNTERATTACK) + return TRUE + if(BATTLE_ARCADE_PLAYER_DEFEND) + player_current_hp = round(min(player_current_hp + (SPELL_MP_COST / 2), PLAYER_MAX_HP), 1) + player_current_mp = round(min(player_current_mp + SPELL_MP_COST, PLAYER_MAX_MP), 1) + process_player_attack(gamer, BATTLE_ARCADE_PLAYER_DEFEND) + return TRUE + if("flee") + //you can't outrun the cuban pete + if(obj_flags & EMAGGED) + lose_game(gamer) + return + player_turn = TRUE + ui_panel = UI_PANEL_WORLD_MAP + if(player_gold) + player_gold = max(round(player_gold /= 2, 1), 0) + return TRUE + //they pressed something but it wasn't in the menu, we'll be nice and give them back their turn anyway. + player_turn = TRUE + +#undef WORLD_ENEMY_BOSS +#undef DEFAULT_EXP_GAIN +#undef DEFAULT_ITEM_PRICE + +#undef PLAYER_MAX_HP +#undef PLAYER_MAX_MP +#undef SPELL_MP_COST + +#undef UI_PANEL_SHOP +#undef UI_PANEL_WORLD_MAP +#undef UI_PANEL_BATTLE +#undef UI_PANEL_BETWEEN_FIGHTS +#undef UI_PANEL_GAMEOVER + +#undef BATTLE_ATTACK_FLAG_COUNTERATTACK +#undef BATTLE_ATTACK_FLAG_DEFEND + +#undef BATTLE_ARCADE_PLAYER_ATTACK +#undef BATTLE_ARCADE_PLAYER_HEAVY_ATTACK +#undef BATTLE_ARCADE_PLAYER_COUNTERATTACK +#undef BATTLE_ARCADE_PLAYER_DEFEND diff --git a/code/game/machinery/computer/arcade/battle_gear.dm b/code/game/machinery/computer/arcade/battle_gear.dm new file mode 100644 index 0000000000000..32d1d73dd4f4e --- /dev/null +++ b/code/game/machinery/computer/arcade/battle_gear.dm @@ -0,0 +1,126 @@ +/datum/battle_arcade_gear + ///The name of the gear, used in shops. + var/name = "Gear" + ///The slot this gear fits into + var/slot + ///The world the player has to be at in order to buy this item. + var/world_available + ///The stat given by the gear + var/bonus_modifier + +/datum/battle_arcade_gear/tier_1 + world_available = BATTLE_WORLD_ONE + +/datum/battle_arcade_gear/tier_1/weapon + name = "Sword" + slot = WEAPON_SLOT + bonus_modifier = 1.5 + +/datum/battle_arcade_gear/tier_1/armor + name = "Leather Armor" + slot = ARMOR_SLOT + bonus_modifier = 1.5 + +/datum/battle_arcade_gear/tier_2 + world_available = BATTLE_WORLD_TWO + +/datum/battle_arcade_gear/tier_2/weapon + name = "Axe" + slot = WEAPON_SLOT + bonus_modifier = 1.75 + +/datum/battle_arcade_gear/tier_2/armor + name = "Chainmail" + slot = ARMOR_SLOT + bonus_modifier = 1.75 + +/datum/battle_arcade_gear/tier_3 + world_available = BATTLE_WORLD_THREE + +/datum/battle_arcade_gear/tier_3/weapon + name = "Mace" + slot = WEAPON_SLOT + bonus_modifier = 2 + +/datum/battle_arcade_gear/tier_3/armor + name = "Plate Armor" + slot = ARMOR_SLOT + bonus_modifier = 2 + +/datum/battle_arcade_gear/tier_4 + world_available = BATTLE_WORLD_FOUR + +/datum/battle_arcade_gear/tier_4/weapon + name = "Greatsword" + slot = WEAPON_SLOT + bonus_modifier = 2.5 + +/datum/battle_arcade_gear/tier_4/armor + name = "Full Plate Armor" + slot = ARMOR_SLOT + bonus_modifier = 2.5 + +/datum/battle_arcade_gear/tier_5 + world_available = BATTLE_WORLD_FIVE + +/datum/battle_arcade_gear/tier_5/weapon + name = "Halberd" + slot = WEAPON_SLOT + bonus_modifier = 3 + +/datum/battle_arcade_gear/tier_5/armor + name = "Dragon Scale Armor" + slot = ARMOR_SLOT + bonus_modifier = 3 + +/datum/battle_arcade_gear/tier_6 + world_available = BATTLE_WORLD_SIX + +/datum/battle_arcade_gear/tier_6/weapon + name = "Warhammer" + slot = WEAPON_SLOT + bonus_modifier = 3.5 + +/datum/battle_arcade_gear/tier_6/armor + name = "Adamantine Armor" + slot = ARMOR_SLOT + bonus_modifier = 3.5 + +/datum/battle_arcade_gear/tier_7 + world_available = BATTLE_WORLD_SEVEN + +/datum/battle_arcade_gear/tier_7/weapon + name = "Excalibur" + slot = WEAPON_SLOT + bonus_modifier = 4 + +/datum/battle_arcade_gear/tier_7/armor + name = "Ethereal Armor" + slot = ARMOR_SLOT + bonus_modifier = 4 + +/datum/battle_arcade_gear/tier_8 + world_available = BATTLE_WORLD_EIGHT + +/datum/battle_arcade_gear/tier_8/weapon + name = "Gungnir" + slot = WEAPON_SLOT + bonus_modifier = 4.5 + +/datum/battle_arcade_gear/tier_8/armor + name = "Celestial Armor" + slot = ARMOR_SLOT + bonus_modifier = 4.5 + +/datum/battle_arcade_gear/tier_9 + world_available = BATTLE_WORLD_NINE + +/datum/battle_arcade_gear/tier_9/weapon + name = "Mjolnir" + slot = WEAPON_SLOT + bonus_modifier = 5 + +/datum/battle_arcade_gear/tier_9/armor + name = "Void Armor" + slot = ARMOR_SLOT + bonus_modifier = 5 diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm index 945cbb5593ad2..85bebddd25c6d 100644 --- a/code/game/machinery/computer/arcade/orion.dm +++ b/code/game/machinery/computer/arcade/orion.dm @@ -1,23 +1,13 @@ -// *** THE ORION TRAIL ** // - #define ORION_TRAIL_WINTURN 9 -//defines in machines.dm - -///assoc list, [datum singleton] = weight -GLOBAL_LIST_INIT(orion_events, generate_orion_events()) - -/proc/generate_orion_events() - . = list() - for(var/path in subtypesof(/datum/orion_event)) - var/datum/orion_event/new_event = new path(src) - .[new_event] = new_event.weight - /obj/machinery/computer/arcade/orion_trail name = "The Orion Trail" desc = "Learn how our ancestors got to Orion, and have fun in the process!" icon_state = "arcade" circuit = /obj/item/circuitboard/computer/arcade/orion_trail + + ///List of all orion events, created on Initialize. + var/static/list/orion_events var/busy = FALSE //prevent clickspam that allowed people to ~speedrun~ the game. var/engine = 0 var/hull = 0 @@ -44,12 +34,18 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) /obj/machinery/computer/arcade/orion_trail/Initialize(mapload) . = ..() + if(isnull(orion_events)) + var/list/events = list() + for(var/path in subtypesof(/datum/orion_event)) + var/datum/orion_event/new_event = new path(src) + events[new_event] = new_event.weight + orion_events = events radio = new /obj/item/radio(src) radio.set_listening(FALSE) setup_events() /obj/machinery/computer/arcade/orion_trail/proc/setup_events() - events = GLOB.orion_events + events = orion_events.Copy() /obj/machinery/computer/arcade/orion_trail/Destroy() QDEL_NULL(radio) @@ -81,7 +77,7 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) settlers = list("Kirk","Worf","Gene") /obj/machinery/computer/arcade/orion_trail/kobayashi/setup_events() - events = GLOB.orion_events.Copy() + events = orion_events.Copy() for(var/datum/orion_event/event as anything in events) if(!(event.type in event_whitelist)) events.Remove(event) @@ -196,8 +192,6 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) . = TRUE - - var/gamer_skill_level = 0 var/gamer_skill = 0 var/gamer_skill_rands = 0 @@ -316,7 +310,6 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) if(food > ORION_TRADE_RATE) fuel += ORION_TRADE_RATE food -= ORION_TRADE_RATE - add_fingerprint(gamer) /** * pickweights a new event, sets event var as it. it then preps the event if it needs it @@ -502,62 +495,56 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) obj_flags |= EMAGGED return TRUE -/mob/living/basic/trooper/syndicate/ranged/smg/orion - name = "spaceport security" - desc = "Premier corporate security forces for all spaceports found along the Orion Trail." - faction = list(FACTION_ORION) - loot = list() - +///A minibomb achieved from winning at emagged Orion. /obj/item/orion_ship name = "model settler ship" desc = "A model spaceship, it looks like those used back in the day when travelling to Orion! It even has a miniature FX-293 reactor, which was renowned for its instability and tendency to explode..." icon = 'icons/obj/toys/toy.dmi' icon_state = "ship" w_class = WEIGHT_CLASS_SMALL - var/active = 0 //if the ship is on + ///Boolean on whether the ship is active, setting itself off for destruction. + var/active = 0 /obj/item/orion_ship/examine(mob/user) . = ..() if(!(in_range(user, src))) return - if(!active) - . += span_notice("There's a little switch on the bottom. It's flipped down.") - else + if(active) . += span_notice("There's a little switch on the bottom. It's flipped up.") + return + . += span_notice("There's a little switch on the bottom. It's flipped down.") -/obj/item/orion_ship/attack_self(mob/user) //Minibomb-level explosion. Should probably be more because of how hard it is to survive the machine! Also, just over a 5-second fuse +/obj/item/orion_ship/attack_self(mob/user) if(active) return log_bomber(usr, "primed an explosive", src, "for detonation") - to_chat(user, span_warning("You flip the switch on the underside of [src].")) - active = 1 - visible_message(span_notice("[src] softly beeps and whirs to life!")) - playsound(loc, 'sound/machines/defib_SaftyOn.ogg', 25, TRUE) - say("This is ship ID #[rand(1,1000)] to Orion Port Authority. We're coming in for landing, over.") - sleep(2 SECONDS) - visible_message(span_warning("[src] begins to vibrate...")) - say("Uh, Port? Having some issues with our reactor, could you check it out? Over.") - sleep(3 SECONDS) - say("Oh, God! Code Eight! CODE EIGHT! IT'S GONNA BL-") - playsound(loc, 'sound/machines/buzz-sigh.ogg', 25, TRUE) - sleep(0.36 SECONDS) - visible_message(span_userdanger("[src] explodes!")) - explosion(src, devastation_range = 2, heavy_impact_range = 4, light_impact_range = 8, flame_range = 16) - qdel(src) - -/obj/singularity/orion - move_self = FALSE - -/obj/singularity/orion/Initialize(mapload) - . = ..() - - var/datum/component/singularity/singularity = singularity_component.resolve() - singularity?.grav_pull = 1 + active = TRUE + addtimer(CALLBACK(src, PROC_REF(commit_explosion)), 1 SECONDS) + +///After some dialogue (which doubles as the timer until explosion), causes a minibomb-level explosion. +/obj/item/orion_ship/proc/commit_explosion(dialogue_level = 0) + var/time_for_next_level + switch(dialogue_level) + if(0) + say("This is ship ID #[rand(1,1000)] to Orion Port Authority. We're coming in for landing, over.") + time_for_next_level = 2 SECONDS + if(1) + say("Uh, Port? Having some issues with our reactor, could you check it out? Over.") + time_for_next_level = 3 SECONDS + if(2) + say("Oh, God! Code Eight! CODE EIGHT! IT'S GONNA BL-") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 25, TRUE) + time_for_next_level = 0.36 SECONDS + if(3 to INFINITY) + visible_message(span_userdanger("[src] explodes!")) + explosion(src, devastation_range = 2, heavy_impact_range = 4, light_impact_range = 8, flame_range = 16) + qdel(src) + return -/obj/singularity/orion/process(seconds_per_tick) - if(SPT_PROB(0.5, seconds_per_tick)) - mezzer() + if(time_for_next_level) + dialogue_level++ + addtimer(CALLBACK(src, PROC_REF(commit_explosion), dialogue_level), time_for_next_level) #undef ORION_TRAIL_WINTURN diff --git a/code/game/machinery/computer/arcade/orion_event.dm b/code/game/machinery/computer/arcade/orion_event.dm index f1050e9a8e276..7ab2f3b98b3b0 100644 --- a/code/game/machinery/computer/arcade/orion_event.dm +++ b/code/game/machinery/computer/arcade/orion_event.dm @@ -438,7 +438,7 @@ game.say("A miniature black hole suddenly appears in front of [game], devouring [gamer] alive!") gamer.Stun(200, ignore_canstun = TRUE) //you can't run :^) var/black_hole = new /obj/singularity/orion(gamer.loc) - addtimer(CALLBACK(game, TYPE_PROC_REF(/atom/movable, say), "[black_hole] winks out, just as suddenly as it appeared."), 50) + addtimer(CALLBACK(game, TYPE_PROC_REF(/atom/movable, say), "[black_hole] winks out, just as suddenly as it appeared."), 5 SECONDS) QDEL_IN(black_hole, 5 SECONDS) #define BUTTON_DOCK "Dock" diff --git a/code/game/machinery/computer/atmos_computers/_air_sensor.dm b/code/game/machinery/computer/atmos_computers/_air_sensor.dm index d9d461149bca0..1c365dd087649 100644 --- a/code/game/machinery/computer/atmos_computers/_air_sensor.dm +++ b/code/game/machinery/computer/atmos_computers/_air_sensor.dm @@ -221,8 +221,6 @@ deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/item/air_sensor/deconstruct(disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/analyzer(loc) - new /obj/item/stack/sheet/iron(loc, 1) - return ..() +/obj/item/air_sensor/atom_deconstruct(disassembled) + new /obj/item/analyzer(loc) + new /obj/item/stack/sheet/iron(loc, 1) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 1fc8322bb7899..220870cb11981 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -11,18 +11,16 @@ AddComponent(/datum/component/simple_rotation) register_context() -/obj/structure/frame/computer/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/drop_loc = drop_location() - if(state == FRAME_COMPUTER_STATE_GLASSED) - if(disassembled) - new /obj/item/stack/sheet/glass(drop_loc, 2) - else - new /obj/item/shard(drop_loc) - new /obj/item/shard(drop_loc) - if(state >= FRAME_COMPUTER_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_loc, 5) - +/obj/structure/frame/computer/atom_deconstruct(disassembled = TRUE) + var/atom/drop_loc = drop_location() + if(state == FRAME_COMPUTER_STATE_GLASSED) + if(disassembled) + new /obj/item/stack/sheet/glass(drop_loc, 2) + else + new /obj/item/shard(drop_loc) + new /obj/item/shard(drop_loc) + if(state >= FRAME_COMPUTER_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_loc, 5) return ..() /obj/structure/frame/computer/add_context(atom/source, list/context, obj/item/held_item, mob/user) @@ -148,7 +146,7 @@ return FALSE -/obj/structure/frame/computer/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/structure/frame/computer/item_interaction(mob/living/user, obj/item/tool, list/modifiers) . = ..() if(. & ITEM_INTERACT_ANY_BLOCKER) return . diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 0c6dd3d9c5537..17bbe2299f7e4 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -30,7 +30,7 @@ // Convert networks to lowercase for(var/i in network) network -= i - network += lowertext(i) + network += LOWER_TEXT(i) // Initialize map objects cam_screen = new cam_screen.generate_view(map_name) diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index a271517b0c4ca..45bfeb9fcef36 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -4,6 +4,8 @@ icon_screen = "cameras" icon_keyboard = "security_key" light_color = COLOR_SOFT_RED + processing_flags = START_PROCESSING_MANUALLY + var/list/z_lock = list() // Lock use to these z levels var/lock_override = NONE var/mob/camera/ai_eye/remote/eyeobj @@ -30,7 +32,7 @@ . = ..() for(var/i in networks) networks -= i - networks += lowertext(i) + networks += LOWER_TEXT(i) if(lock_override) if(lock_override & CAMERA_LOCK_STATION) z_lock |= SSmapping.levels_by_trait(ZTRAIT_STATION) @@ -50,6 +52,18 @@ if(move_down_action) actions += new move_down_action(src) +/obj/machinery/computer/camera_advanced/Destroy() + unset_machine() + QDEL_NULL(eyeobj) + QDEL_LIST(actions) + current_user = null + return ..() + +/obj/machinery/computer/camera_advanced/process() + if(!can_use(current_user) || (issilicon(current_user) && !current_user.has_unlimited_silicon_privilege)) + unset_machine() + return PROCESS_KILL + /obj/machinery/computer/camera_advanced/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) for(var/i in networks) networks -= i @@ -73,6 +87,20 @@ /obj/machinery/proc/remove_eye_control(mob/living/user) CRASH("[type] does not implement ai eye handling") +/obj/machinery/computer/camera_advanced/proc/give_eye_control(mob/user) + if(isnull(user?.client)) + return + GrantActions(user) + current_user = user + eyeobj.eye_user = user + eyeobj.name = "Camera Eye ([user.name])" + user.remote_control = eyeobj + user.reset_perspective(eyeobj) + eyeobj.setLoc(eyeobj.loc) + if(should_supress_view_changes) + user.client.view_size.supress() + begin_processing() + /obj/machinery/computer/camera_advanced/remove_eye_control(mob/living/user) if(isnull(user?.client)) return @@ -90,23 +118,16 @@ eyeobj.eye_user = null user.remote_control = null current_user = null - unset_machine(user) playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE) -/obj/machinery/computer/camera_advanced/check_eye(mob/user) - if(!can_use(user) || (issilicon(user) && !user.has_unlimited_silicon_privilege)) - unset_machine(user) +/obj/machinery/computer/camera_advanced/on_set_is_operational(old_value) + if(!is_operational) + unset_machine() -/obj/machinery/computer/camera_advanced/Destroy() - if(eyeobj) - QDEL_NULL(eyeobj) - QDEL_LIST(actions) - current_user = null - return ..() - -/obj/machinery/computer/camera_advanced/proc/unset_machine(mob/M) - if(M == current_user) - remove_eye_control(M) +/obj/machinery/computer/camera_advanced/proc/unset_machine() + if(!QDELETED(current_user)) + remove_eye_control(current_user) + end_processing() /obj/machinery/computer/camera_advanced/proc/can_use(mob/living/user) return can_interact(user) @@ -124,7 +145,7 @@ return if(isnull(user.client)) return - if(current_user) + if(!QDELETED(current_user)) to_chat(user, span_warning("The console is already in use!")) return var/mob/living/L = user @@ -156,7 +177,7 @@ give_eye_control(L) eyeobj.setLoc(camera_location) else - unset_machine(user) + unset_machine() else give_eye_control(L) eyeobj.setLoc(eyeobj.loc) @@ -167,19 +188,6 @@ /obj/machinery/computer/camera_advanced/attack_ai(mob/user) return //AIs would need to disable their own camera procs to use the console safely. Bugs happen otherwise. -/obj/machinery/computer/camera_advanced/proc/give_eye_control(mob/user) - if(isnull(user?.client)) - return - GrantActions(user) - current_user = user - eyeobj.eye_user = user - eyeobj.name = "Camera Eye ([user.name])" - user.remote_control = eyeobj - user.reset_perspective(eyeobj) - eyeobj.setLoc(eyeobj.loc) - if(should_supress_view_changes) - user.client.view_size.supress() - /mob/camera/ai_eye/remote name = "Inactive Camera Eye" ai_detector_visible = FALSE @@ -331,3 +339,12 @@ to_chat(owner, span_notice("You move downwards.")) else to_chat(owner, span_notice("You couldn't move downwards!")) + +/obj/machinery/computer/camera_advanced/human_ai/screwdriver_act(mob/living/user, obj/item/tool) + balloon_alert(user, "repackaging...") + if(!do_after(user, 5 SECONDS, src)) + return ITEM_INTERACT_BLOCKING + tool.play_tool_sound(src, 40) + new /obj/item/secure_camera_console_pod(get_turf(src)) + qdel(src) + return ITEM_INTERACT_SUCCESS diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 8cbd7326d8854..1fb46abd1201f 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -91,7 +91,6 @@ REGISTER_REQUIRED_MAP_ITEM(1, INFINITY) GLOB.shuttle_caller_list += src - AddComponent(/datum/component/gps, "Secured Communications Signal") /// Are we NOT a silicon, AND we're logged in as the captain? /obj/machinery/computer/communications/proc/authenticated_as_non_silicon_captain(mob/user) @@ -322,7 +321,7 @@ if (!message) return - SScommunications.soft_filtering = FALSE + GLOB.communications_controller.soft_filtering = FALSE var/list/hard_filter_result = is_ic_filtered(message) if(hard_filter_result) tgui_alert(usr, "Your message contains: (\"[hard_filter_result[CHAT_FILTER_INDEX_WORD]]\"), which is not allowed on this server.") @@ -334,7 +333,7 @@ return message_admins("[ADMIN_LOOKUPFLW(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". They may be using a disallowed term for a cross-station message. Increasing delay time to reject.\n\n Message: \"[html_encode(message)]\"") log_admin_private("[key_name(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". They may be using a disallowed term for a cross-station message. Increasing delay time to reject.\n\n Message: \"[message]\"") - SScommunications.soft_filtering = TRUE + GLOB.communications_controller.soft_filtering = TRUE playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) @@ -345,13 +344,13 @@ GLOB.admins, span_adminnotice( \ "CROSS-SECTOR MESSAGE (OUTGOING): [ADMIN_LOOKUPFLW(usr)] is about to send \ - the following message to [destination] (will autoapprove in [SScommunications.soft_filtering ? DisplayTimeText(EXTENDED_CROSS_SECTOR_CANCEL_TIME) : DisplayTimeText(CROSS_SECTOR_CANCEL_TIME)]): \ + the following message to [destination] (will autoapprove in [GLOB.communications_controller.soft_filtering ? DisplayTimeText(EXTENDED_CROSS_SECTOR_CANCEL_TIME) : DisplayTimeText(CROSS_SECTOR_CANCEL_TIME)]): \ REJECT
\ [html_encode(message)]" \ ) ) - send_cross_comms_message_timer = addtimer(CALLBACK(src, PROC_REF(send_cross_comms_message), usr, destination, message), SScommunications.soft_filtering ? EXTENDED_CROSS_SECTOR_CANCEL_TIME : CROSS_SECTOR_CANCEL_TIME, TIMER_STOPPABLE) + send_cross_comms_message_timer = addtimer(CALLBACK(src, PROC_REF(send_cross_comms_message), usr, destination, message), GLOB.communications_controller.soft_filtering ? EXTENDED_CROSS_SECTOR_CANCEL_TIME : CROSS_SECTOR_CANCEL_TIME, TIMER_STOPPABLE) COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN) if ("setState") @@ -419,6 +418,8 @@ state = STATE_MAIN playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + imprint_gps(gps_tag = "Encrypted Communications Channel") + if ("toggleEmergencyAccess") if(emergency_access_cooldown(usr)) //if were in cooldown, dont allow the following code return @@ -486,7 +487,7 @@ var/network_name = CONFIG_GET(string/cross_comms_network) if(network_name) payload["network"] = network_name - if(SScommunications.soft_filtering) + if(GLOB.communications_controller.soft_filtering) payload["is_filtered"] = TRUE send2otherserver(html_decode(station_name()), message, "Comms_Console", destination == "all" ? null : list(destination), additional_data = payload) @@ -494,7 +495,7 @@ usr.log_talk(message, LOG_SAY, tag = "message to the other server") message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server\[s].") deadchat_broadcast(" has sent an outgoing message to the other station(s).", "[usr.real_name]", usr, message_type = DEADCHAT_ANNOUNCEMENT) - SScommunications.soft_filtering = FALSE // set it to false at the end of the proc to ensure that everything prior reads as intended + GLOB.communications_controller.soft_filtering = FALSE // set it to false at the end of the proc to ensure that everything prior reads as intended /obj/machinery/computer/communications/ui_data(mob/user) var/list/data = list( @@ -654,7 +655,7 @@ return deltimer(send_cross_comms_message_timer) - SScommunications.soft_filtering = FALSE + GLOB.communications_controller.soft_filtering = FALSE send_cross_comms_message_timer = null log_admin("[key_name(usr)] has cancelled the outgoing cross-comms message.") @@ -727,7 +728,7 @@ /obj/machinery/computer/communications/proc/make_announcement(mob/living/user) var/is_ai = HAS_SILICON_ACCESS(user) - if(!SScommunications.can_announce(user, is_ai)) + if(!GLOB.communications_controller.can_announce(user, is_ai)) to_chat(user, span_alert("Intercomms recharging. Please stand by.")) return var/input = tgui_input_text(user, "Message to announce to the station crew", "Announcement") @@ -748,7 +749,7 @@ ) var/list/players = get_communication_players() - SScommunications.make_announcement(user, is_ai, input, syndicate || (obj_flags & EMAGGED), players) + GLOB.communications_controller.make_announcement(user, is_ai, input, syndicate || (obj_flags & EMAGGED), players) deadchat_broadcast(" made a priority announcement from [span_name("[get_area_name(usr, TRUE)]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT) /obj/machinery/computer/communications/proc/get_communication_players() diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 7b66d72a98c10..268b675871ab2 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -109,10 +109,9 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) // 20-29: Medbay JOB_CHIEF_MEDICAL_OFFICER = 20, JOB_CHEMIST = 21, - JOB_VIROLOGIST = 22, - JOB_MEDICAL_DOCTOR = 23, - JOB_PARAMEDIC = 24, - JOB_CORONER = 25, + JOB_MEDICAL_DOCTOR = 22, + JOB_PARAMEDIC = 23, + JOB_CORONER = 24, // 30-39: Science JOB_RESEARCH_DIRECTOR = 30, JOB_SCIENTIST = 31, diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index eb1aa91ed2970..f0d7b2e30eb52 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -54,7 +54,7 @@ icon_keyboard = "med_key" density = TRUE circuit = /obj/item/circuitboard/computer/scan_consolenew - + interaction_flags_click = ALLOW_SILICON_REACH light_color = LIGHT_COLOR_BLUE /// Link to the techweb's stored research. Used to retrieve stored mutations @@ -210,15 +210,9 @@ stored_research = tool.buffer return TRUE -/obj/machinery/computer/scan_consolenew/AltClick(mob/user) - // Make sure the user can interact with the machine. - . = ..() - if(!can_interact(user)) - return - if(!user.can_perform_action(src, ALLOW_SILICON_REACH)) - return - +/obj/machinery/computer/scan_consolenew/click_alt(mob/user) eject_disk(user) + return CLICK_ACTION_SUCCESS /obj/machinery/computer/scan_consolenew/Initialize(mapload) . = ..() @@ -235,7 +229,7 @@ // Set the default tgui state set_default_state() -/obj/machinery/computer/scan_consolenew/LateInitialize() +/obj/machinery/computer/scan_consolenew/post_machine_initialize() . = ..() // Link machine with research techweb. Used for discovering and accessing // already discovered mutations diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index 372d75822b7e4..816177f9f0edd 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -7,7 +7,6 @@ /obj/machinery/computer/upload/Initialize(mapload) . = ..() - AddComponent(/datum/component/gps, "Encrypted Upload") if(!mapload) log_silicon("\A [name] was created at [loc_name(src)].") message_admins("\A [name] was created at [ADMIN_VERBOSEJMP(src)].") @@ -29,6 +28,7 @@ current = null return M.install(current.laws, user) + imprint_gps(gps_tag = "Weak Upload Signal") else return ..() diff --git a/code/game/machinery/computer/mechlaunchpad.dm b/code/game/machinery/computer/mechlaunchpad.dm index 106f87f1788f3..7b80b6e95c8d6 100644 --- a/code/game/machinery/computer/mechlaunchpad.dm +++ b/code/game/machinery/computer/mechlaunchpad.dm @@ -34,7 +34,8 @@ SIGNAL_HANDLER connected_mechpad = null -/obj/machinery/computer/mechpad/LateInitialize() +/obj/machinery/computer/mechpad/post_machine_initialize() + . = ..() for(var/obj/machinery/mechpad/pad as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/mechpad)) if(pad == connected_mechpad) continue diff --git a/code/game/machinery/computer/operating_computer.dm b/code/game/machinery/computer/operating_computer.dm index 3b639a9ce573f..d67cea367e9a6 100644 --- a/code/game/machinery/computer/operating_computer.dm +++ b/code/game/machinery/computer/operating_computer.dm @@ -20,7 +20,7 @@ find_table() return INITIALIZE_HINT_LATELOAD -/obj/machinery/computer/operating/LateInitialize() +/obj/machinery/computer/operating/post_machine_initialize() . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb) CONNECT_TO_RND_SERVER_ROUNDSTART(linked_techweb, src) @@ -55,7 +55,7 @@ span_notice("You begin to load a surgery protocol from \the [O]..."), \ span_hear("You hear the chatter of a floppy drive.")) var/obj/item/disk/surgery/D = O - if(do_after(user, 10, target = src)) + if(do_after(user, 1 SECONDS, target = src)) advanced_surgeries |= D.surgeries return TRUE return ..() @@ -103,6 +103,7 @@ data["table"] = table data["patient"] = list() + data["procedures"] = list() if(!table.patient) return data var/mob/living/carbon/patient = table.patient @@ -136,7 +137,6 @@ data["patient"]["fireLoss"] = patient.getFireLoss() data["patient"]["toxLoss"] = patient.getToxLoss() data["patient"]["oxyLoss"] = patient.getOxyLoss() - data["procedures"] = list() if(patient.surgeries.len) for(var/datum/surgery/procedure in patient.surgeries) var/datum/surgery_step/surgery_step = procedure.get_surgery_step() @@ -151,7 +151,7 @@ else alternative_step = "Finish operation" data["procedures"] += list(list( - "name" = capitalize("[parse_zone(procedure.location)] [procedure.name]"), + "name" = capitalize("[patient.parse_zone_with_bodypart(procedure.location)] [procedure.name]"), "next_step" = capitalize(surgery_step.name), "chems_needed" = chems_needed, "alternative_step" = alternative_step, @@ -159,8 +159,6 @@ )) return data - - /obj/machinery/computer/operating/ui_act(action, params) . = ..() if(.) diff --git a/code/game/machinery/computer/orders/order_items/mining/order_mining.dm b/code/game/machinery/computer/orders/order_items/mining/order_mining.dm index 686f83126718a..13f350f1da192 100644 --- a/code/game/machinery/computer/orders/order_items/mining/order_mining.dm +++ b/code/game/machinery/computer/orders/order_items/mining/order_mining.dm @@ -107,7 +107,15 @@ item_path = /obj/item/radio/weather_monitor cost_per_order = 320 +/datum/orderable_item/mining/ventpointer + item_path = /obj/item/pinpointer/vent + cost_per_order = 1150 + /datum/orderable_item/mining/boulder_processing item_path = /obj/item/boulder_beacon desc = "A Bouldertech brand all-in-one boulder processing beacon. Each use will teleport in a component of a full boulder processing assembly line. Good for when you need to process additional boulders." cost_per_order = 875 + +/datum/orderable_item/mining/grapple_gun + item_path = /obj/item/grapple_gun + cost_per_order = 3000 diff --git a/code/game/machinery/computer/orders/order_items/mining/order_toys.dm b/code/game/machinery/computer/orders/order_items/mining/order_toys.dm index 7ee4c6cfba8c8..fab03cabaa4b6 100644 --- a/code/game/machinery/computer/orders/order_items/mining/order_toys.dm +++ b/code/game/machinery/computer/orders/order_items/mining/order_toys.dm @@ -25,7 +25,7 @@ item_path = /obj/item/mine_bot_upgrade/regnerative_shield cost_per_order = 500 -/datum/orderable_item/toys_drones/drone_shield +/datum/orderable_item/toys_drones/drone_remote item_path = /obj/item/minebot_remote_control cost_per_order = 500 diff --git a/code/game/machinery/computer/prisoner/_prisoner.dm b/code/game/machinery/computer/prisoner/_prisoner.dm index f1ce25559361a..9777c1b209cdf 100644 --- a/code/game/machinery/computer/prisoner/_prisoner.dm +++ b/code/game/machinery/computer/prisoner/_prisoner.dm @@ -2,6 +2,7 @@ interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_REQUIRES_LITERACY /// ID card currently inserted into the computer. VAR_FINAL/obj/item/card/id/advanced/prisoner/contained_id + interaction_flags_click = ALLOW_SILICON_REACH /obj/machinery/computer/prisoner/on_deconstruction(disassembled) contained_id?.forceMove(drop_location()) @@ -20,10 +21,9 @@ if(contained_id) . += span_notice("Alt-click to eject the ID card.") -/obj/machinery/computer/prisoner/AltClick(mob/user) - . = ..() - if(user.can_perform_action(src, ALLOW_SILICON_REACH)) - id_eject(user) +/obj/machinery/computer/prisoner/click_alt(mob/user) + id_eject(user) + return CLICK_ACTION_SUCCESS /obj/machinery/computer/prisoner/proc/id_insert(mob/user, obj/item/card/id/advanced/prisoner/new_id) if(!istype(new_id)) diff --git a/code/game/machinery/computer/prisoner/gulag_teleporter.dm b/code/game/machinery/computer/prisoner/gulag_teleporter.dm index 45124eefeee9f..9f5ec0b3d645f 100644 --- a/code/game/machinery/computer/prisoner/gulag_teleporter.dm +++ b/code/game/machinery/computer/prisoner/gulag_teleporter.dm @@ -114,7 +114,7 @@ if("teleport") if(!teleporter || !beacon) return - addtimer(CALLBACK(src, PROC_REF(teleport), usr), 5) + addtimer(CALLBACK(src, PROC_REF(teleport), usr), 0.5 SECONDS) return TRUE /obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/scan_machinery() @@ -149,7 +149,7 @@ prisoner.Paralyze(40) // small travel dizziness to_chat(prisoner, span_warning("The teleportation makes you a little dizzy.")) new /obj/effect/particle_effect/sparks(get_turf(prisoner)) - playsound(src, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(src, 'sound/effects/portal_travel.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(teleporter.locked) teleporter.locked = FALSE teleporter.toggle_open() diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index 0797b4d1890a1..c41779e7384ec 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -49,10 +49,8 @@ if(prob(10/severity)) switch(rand(1,5)) if(1) - if(prob(10)) - target.name = "[pick(lizard_name(MALE),lizard_name(FEMALE))]" - else - target.name = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]" + target.name = generate_random_name() + if(2) target.gender = pick("Male", "Female", "Other") if(3) diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index 0915d4d1d17ae..d00c5824d8bd3 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -1,3 +1,6 @@ +#define REGIME_TELEPORTER "Teleporter" +#define REGIME_GATE "Gate" + /obj/machinery/computer/teleporter name = "teleporter control console" desc = "Used to control a linked teleportation Hub and Station." @@ -5,10 +8,13 @@ icon_keyboard = "teleport_key" light_color = LIGHT_COLOR_BLUE circuit = /obj/item/circuitboard/computer/teleporter - - var/regime_set = "Teleporter" + /// Currently can be "Teleporter" or "Gate" + var/regime_set = REGIME_TELEPORTER + /// The ID of this teleporter, used for linking to power stations var/id + /// The power station this teleporter is linked to var/obj/machinery/teleport/station/power_station + /// Whether the teleporter is currently calibrating var/calibrating ///Weakref to the target atom we're pointed at currently var/datum/weakref/target_ref @@ -63,7 +69,7 @@ data["power_station"] = power_station ? TRUE : FALSE data["teleporter_hub"] = power_station?.teleporter_hub ? TRUE : FALSE data["regime_set"] = regime_set - data["target"] = !target ? "None" : "[get_area(target)] [(regime_set != "Gate") ? "" : "Teleporter"]" + data["target"] = !target ? "None" : "[get_area(target)] [(regime_set != REGIME_GATE) ? "" : REGIME_TELEPORTER]" data["calibrating"] = calibrating if(power_station?.teleporter_hub?.calibrated || power_station?.teleporter_hub?.accuracy >= 3) @@ -145,10 +151,10 @@ /obj/machinery/computer/teleporter/proc/reset_regime() set_teleport_target(null) - if(regime_set == "Teleporter") - regime_set = "Gate" + if(regime_set == REGIME_TELEPORTER) + regime_set = REGIME_GATE else - regime_set = "Teleporter" + regime_set = REGIME_TELEPORTER /// Gets a list of targets to teleport to. /// List is an assoc list of descriptors to locations. @@ -156,7 +162,7 @@ var/list/targets = list() var/list/area_index = list() - if (regime_set == "Teleporter") + if (regime_set == REGIME_TELEPORTER) for (var/obj/item/beacon/beacon as anything in GLOB.teleportbeacons) if (!is_eligible(beacon)) continue @@ -199,9 +205,9 @@ /obj/machinery/computer/teleporter/proc/set_target(mob/user) var/list/targets = get_targets() - if (regime_set == "Teleporter") + if (regime_set == REGIME_TELEPORTER) var/desc = tgui_input_list(usr, "Select a location to lock in", "Locking Computer", sort_list(targets)) - if(isnull(desc)) + if(isnull(desc) || !user.can_perform_action(src, ALLOW_SILICON_REACH)) return set_teleport_target(targets[desc]) user.log_message("set the teleporter target to [targets[desc]].]", LOG_GAME) @@ -211,7 +217,7 @@ return var/desc = tgui_input_list(usr, "Select a station to lock in", "Locking Computer", sort_list(targets)) - if(isnull(desc)) + if(isnull(desc)|| !user.can_perform_action(src, ALLOW_SILICON_REACH)) return var/obj/machinery/teleport/station/target_station = targets[desc] if(!target_station || !target_station.teleporter_hub) @@ -232,6 +238,10 @@ return FALSE return TRUE + +#undef REGIME_TELEPORTER +#undef REGIME_GATE + /obj/item/circuit_component/teleporter_control_console display_name = "Teleporter Control Console" desc = "Used to control a linked teleportation Hub and Station." diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index e6830fd1848b6..f0b3434ec85c9 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -22,13 +22,10 @@ if(circuit) . += "It has \a [circuit] installed." -/obj/structure/frame/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/movable/drop_loc = drop_location() - new /obj/item/stack/sheet/iron(drop_loc, 5) - circuit?.forceMove(drop_loc) - - return ..() +/obj/structure/frame/atom_deconstruct(disassembled = TRUE) + var/atom/movable/drop_loc = drop_location() + new /obj/item/stack/sheet/iron(drop_loc, 5) + circuit?.forceMove(drop_loc) /// Called when circuit has been set to a new board /obj/structure/frame/proc/circuit_added(obj/item/circuitboard/added) @@ -61,8 +58,6 @@ /obj/structure/frame/proc/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time = 8 SECONDS) if(state != FRAME_STATE_EMPTY) return NONE - if(obj_flags & NO_DECONSTRUCTION) - return NONE if(anchored && state == FRAME_STATE_EMPTY) //when using a screwdriver on an incomplete frame(missing components) no point checking for this balloon_alert(user, "must be unanchored first!") return ITEM_INTERACT_BLOCKING @@ -112,15 +107,10 @@ return ITEM_INTERACT_BLOCKING return . -/obj/structure/frame/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . - +/obj/structure/frame/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(istype(tool, /obj/item/circuitboard)) // Install board will fail if passed an invalid circuitboard and give feedback return install_board(user, tool, by_hand = TRUE) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - - return . + return NONE /** * Installs the passed circuit board into the frame diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index 9d19d0d9be98b..45daa1966a635 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -32,8 +32,6 @@ /obj/machinery/jukebox/wrench_act(mob/living/user, obj/item/tool) if(!isnull(music_player.active_song_sound)) return NONE - if(obj_flags & NO_DECONSTRUCTION) - return NONE if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS @@ -164,7 +162,6 @@ req_access = null anchored = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /obj/machinery/jukebox/disco/activate_music() . = ..() diff --git a/code/game/machinery/defibrillator_mount.dm b/code/game/machinery/defibrillator_mount.dm index 4e6e45bb20482..785357e3b5be9 100644 --- a/code/game/machinery/defibrillator_mount.dm +++ b/code/game/machinery/defibrillator_mount.dm @@ -51,25 +51,23 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) /obj/machinery/defibrillator_mount/update_overlays() . = ..() - - if(!defib) + if(isnull(defib)) return - . += "defib" + var/mutable_appearance/defib_overlay = mutable_appearance(icon, "defib", layer = layer+0.01, offset_spokesman = src) if(defib.powered) - var/obj/item/stock_parts/cell/C = get_cell() - . += (defib.safety ? "online" : "emagged") - var/ratio = C.charge / C.maxcharge - ratio = CEILING(ratio * 4, 1) * 25 - . += "charge[ratio]" + var/obj/item/stock_parts/cell/cell = defib.cell + var/mutable_appearance/safety = mutable_appearance(icon, defib.safety ? "online" : "emagged", offset_spokesman = src) + var/mutable_appearance/charge_overlay = mutable_appearance(icon, "charge[CEILING((cell.charge / cell.maxcharge) * 4, 1) * 25]", offset_spokesman = src) + + defib_overlay.overlays += list(safety, charge_overlay) if(clamps_locked) - . += "clamps" + var/mutable_appearance/clamps = mutable_appearance(icon, "clamps", offset_spokesman = src) + defib_overlay.overlays += clamps -/obj/machinery/defibrillator_mount/get_cell() - if(defib) - return defib.get_cell() + . += defib_overlay //defib interaction /obj/machinery/defibrillator_mount/attack_hand(mob/living/user, list/modifiers) @@ -133,7 +131,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) user.visible_message(span_notice("[user] presses [multitool] into [src]'s ID slot..."), \ span_notice("You begin overriding the clamps on [src]...")) playsound(src, 'sound/machines/click.ogg', 50, TRUE) - if(!do_after(user, 100, target = src) || !clamps_locked) + if(!do_after(user, 10 SECONDS, target = src) || !clamps_locked) return user.visible_message(span_notice("[user] pulses [multitool], and [src]'s clamps slide up."), \ span_notice("You override the locking clamps on [src]!")) @@ -157,15 +155,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) to_chat(user, span_notice("You remove [src] from the wall.")) return TRUE -/obj/machinery/defibrillator_mount/AltClick(mob/living/carbon/user) - if(!istype(user) || !user.can_perform_action(src)) - return +/obj/machinery/defibrillator_mount/click_alt(mob/living/carbon/user) if(!defib) to_chat(user, span_warning("It'd be hard to remove a defib unit from a mount that has none.")) - return + return CLICK_ACTION_BLOCKING if(clamps_locked) to_chat(user, span_warning("You try to tug out [defib], but the mount's clamps are locked tight!")) - return + return CLICK_ACTION_BLOCKING if(!user.put_in_hands(defib)) to_chat(user, span_warning("You need a free hand!")) user.visible_message(span_notice("[user] unhooks [defib] from [src], dropping it on the floor."), \ @@ -174,6 +170,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) user.visible_message(span_notice("[user] unhooks [defib] from [src]."), \ span_notice("You slide out [defib] from [src] and unhook the charging cables.")) playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) + return CLICK_ACTION_SUCCESS /obj/machinery/defibrillator_mount/charging name = "PENLITE defibrillator mount" @@ -221,3 +218,37 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) icon_state = "penlite_mount" custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 3, /datum/material/glass = SMALL_MATERIAL_AMOUNT, /datum/material/silver = SMALL_MATERIAL_AMOUNT * 0.5) result_path = /obj/machinery/defibrillator_mount/charging + +//mobile defib + +/obj/machinery/defibrillator_mount/mobile + name = "mobile defibrillator mount" + icon_state = "mobile" + anchored = FALSE + density = TRUE + +/obj/machinery/defibrillator_mount/mobile/Initialize(mapload) + . = ..() + AddElement(/datum/element/noisy_movement) + +/obj/machinery/defibrillator_mount/mobile/wrench_act_secondary(mob/living/user, obj/item/tool) + if(user.combat_mode) + return ..() + if(defib) + to_chat(user, span_warning("The mount can't be deconstructed while a defibrillator unit is loaded!")) + ..() + return TRUE + balloon_alert(user, "deconstructing...") + tool.play_tool_sound(src) + if(tool.use_tool(src, user, 5 SECONDS)) + playsound(loc, 'sound/items/deconstruct.ogg', 50, vary = TRUE) + deconstruct() + return TRUE + +/obj/machinery/defibrillator_mount/mobile/on_deconstruction(disassembled) + if(disassembled) + new /obj/item/stack/sheet/iron(drop_location(), 5) + new /obj/item/stack/sheet/mineral/silver(drop_location(), 1) + new /obj/item/stack/cable_coil(drop_location(), 15) + else + new /obj/item/stack/sheet/iron(drop_location(), 5) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 0d3c04ccd6f8b..4f78fbf3a52ee 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -17,12 +17,13 @@ var/proj_pass_rate = 50 //How many projectiles will pass the cover. Lower means stronger cover var/bar_material = METAL -/obj/structure/barricade/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - make_debris() - qdel(src) +/obj/structure/barricade/atom_deconstruct(disassembled = TRUE) + make_debris() +/// Spawn debris & stuff upon deconstruction /obj/structure/barricade/proc/make_debris() + PROTECTED_PROC(TRUE) + return /obj/structure/barricade/attackby(obj/item/I, mob/living/user, params) @@ -77,7 +78,7 @@ else to_chat(user, span_notice("You start adding [I] to [src]...")) playsound(src, 'sound/items/hammering_wood.ogg', 50, vary = TRUE) - if(do_after(user, 50, target=src)) + if(do_after(user, 5 SECONDS, target=src)) W.use(5) var/turf/T = get_turf(src) T.place_on_top(/turf/closed/wall/mineral/wood/nonmetal) @@ -98,7 +99,7 @@ /obj/structure/barricade/wooden/crude name = "crude plank barricade" desc = "This space is blocked off by a crude assortment of planks." - icon_state = "woodenbarricade-old" + icon_state = "plankbarricade" drop_amount = 1 max_integrity = 50 proj_pass_rate = 65 @@ -106,7 +107,7 @@ /obj/structure/barricade/wooden/crude/snow desc = "This space is blocked off by a crude assortment of planks. It seems to be covered in a layer of snow." - icon_state = "woodenbarricade-snow-old" + icon_state = "plankbarricade_snow" max_integrity = 75 /obj/structure/barricade/wooden/make_debris() @@ -179,10 +180,9 @@ . = ..() . += span_notice("Alt-click to toggle modes.") -/obj/item/grenade/barrier/AltClick(mob/living/carbon/user) - if(!istype(user) || !user.can_perform_action(src)) - return +/obj/item/grenade/barrier/click_alt(mob/living/carbon/user) toggle_mode(user) + return CLICK_ACTION_SUCCESS /obj/item/grenade/barrier/proc/toggle_mode(mob/user) switch(mode) diff --git a/code/game/machinery/dish_drive.dm b/code/game/machinery/dish_drive.dm index 1b21d812dc0dd..b386ebb376f57 100644 --- a/code/game/machinery/dish_drive.dm +++ b/code/game/machinery/dish_drive.dm @@ -9,6 +9,7 @@ density = FALSE circuit = /obj/item/circuitboard/machine/dish_drive pass_flags = PASSTABLE + interaction_flags_click = ALLOW_SILICON_REACH /// List of dishes the drive can hold var/static/list/collectable_items = list( /obj/item/trash/waffles, @@ -141,9 +142,9 @@ balloon_alert(user, "disposal signal sent") do_the_dishes(TRUE) -/obj/machinery/dish_drive/AltClick(mob/living/user) - if(user.can_perform_action(src, ALLOW_SILICON_REACH)) - do_the_dishes(TRUE) +/obj/machinery/dish_drive/click_alt(mob/living/user) + do_the_dishes(TRUE) + return CLICK_ACTION_SUCCESS /obj/machinery/dish_drive/proc/do_the_dishes(manual) if(!LAZYLEN(dish_drive_contents)) diff --git a/code/game/machinery/dna_infuser/dna_infuser.dm b/code/game/machinery/dna_infuser/dna_infuser.dm index 8275eb1e948fc..7e5c58ef94c78 100644 --- a/code/game/machinery/dna_infuser/dna_infuser.dm +++ b/code/game/machinery/dna_infuser/dna_infuser.dm @@ -64,8 +64,7 @@ balloon_alert(user, "not while it's on!") return if(occupant && infusing_from) - // Abort infusion if the occupant is invalid. - if(!is_valid_occupant(occupant, user)) + if(!occupant.can_infuse(user)) playsound(src, 'sound/machines/scanbuzz.ogg', 35, vary = TRUE) return balloon_alert(user, "starting DNA infusion...") @@ -77,92 +76,45 @@ var/mob/living/carbon/human/human_occupant = occupant infusing = TRUE visible_message(span_notice("[src] hums to life, beginning the infusion process!")) + + infusing_into = infusing_from.get_infusion_entry() var/fail_title = "" - var/fail_reason = "" - // Replace infusing_into with a [/datum/infuser_entry] - for(var/datum/infuser_entry/entry as anything in GLOB.infuser_entries) - if(entry.tier == DNA_MUTANT_UNOBTAINABLE) - continue - if(is_type_in_list(infusing_from, entry.input_obj_or_mob)) - if(entry.tier > max_tier_allowed) - fail_title = "Overcomplexity" - fail_reason = "DNA too complicated to infuse. The machine needs to infuse simpler DNA first." - infusing_into = entry - break - if(!infusing_into) - //no valid recipe, so you get a fly mutation - if(!fail_reason) - fail_title = "Unknown DNA" - fail_reason = "Unknown DNA. Consult the \"DNA infusion book\"." - infusing_into = GLOB.infuser_entries[1] + var/fail_explanation = "" + if(istype(infusing_into, /datum/infuser_entry/fly)) + fail_title = "Unknown DNA" + fail_explanation = "Unknown DNA. Consult the \"DNA infusion book\"." + if(infusing_into.tier > max_tier_allowed) + infusing_into = GLOB.infuser_entries[/datum/infuser_entry/fly] + fail_title = "Overcomplexity" + fail_explanation = "DNA too complicated to infuse. The machine needs to infuse simpler DNA first." playsound(src, 'sound/machines/blender.ogg', 50, vary = TRUE) to_chat(human_occupant, span_danger("Little needles repeatedly prick you!")) human_occupant.take_overall_damage(10) human_occupant.add_mob_memory(/datum/memory/dna_infusion, protagonist = human_occupant, deuteragonist = infusing_from, mutantlike = infusing_into.infusion_desc) Shake(duration = INFUSING_TIME) addtimer(CALLBACK(human_occupant, TYPE_PROC_REF(/mob, emote), "scream"), INFUSING_TIME - 1 SECONDS) - addtimer(CALLBACK(src, PROC_REF(end_infuse), fail_reason, fail_title), INFUSING_TIME) + addtimer(CALLBACK(src, PROC_REF(end_infuse), fail_explanation, fail_title), INFUSING_TIME) update_appearance() -/obj/machinery/dna_infuser/proc/end_infuse(fail_reason, fail_title) - if(infuse_organ(occupant)) +/obj/machinery/dna_infuser/proc/end_infuse(fail_explanation, fail_title) + var/mob/living/carbon/human/human_occupant = occupant + if(human_occupant.infuse_organ(infusing_into)) + check_tier_progression(human_occupant) to_chat(occupant, span_danger("You feel yourself becoming more... [infusing_into.infusion_desc]?")) infusing = FALSE infusing_into = null QDEL_NULL(infusing_from) playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, vary = FALSE) - if(fail_reason) + if(fail_explanation) playsound(src, 'sound/machines/printer.ogg', 100, TRUE) visible_message(span_notice("[src] prints an error report.")) var/obj/item/paper/printed_paper = new /obj/item/paper(loc) printed_paper.name = "error report - '[fail_title]'" - printed_paper.add_raw_text(fail_reason) + printed_paper.add_raw_text(fail_explanation) printed_paper.update_appearance() toggle_open() update_appearance() -/// Attempt to replace/add-to the occupant's organs with "mutated" equivalents. -/// Returns TRUE on success, FALSE on failure. -/// Requires the target mob to have an existing organic organ to "mutate". -// TODO: In the future, this should have more logic: -// - Replace non-mutant organs before mutant ones. -/obj/machinery/dna_infuser/proc/infuse_organ(mob/living/carbon/human/target) - if(!ishuman(target)) - return FALSE - var/obj/item/organ/new_organ = pick_organ(target) - if(!new_organ) - return FALSE - // Valid organ successfully picked. - new_organ = new new_organ() - new_organ.replace_into(target) - check_tier_progression(target) - return TRUE - -/// Picks a random mutated organ from the infuser entry which is also compatible with the target mob. -/// Tries to return a typepath of a valid mutant organ if all of the following criteria are true: -/// 1. Target must have a pre-existing organ in the same organ slot as the new organ; -/// - or the new organ must be external. -/// 2. Target's pre-existing organ must be organic / not robotic. -/// 3. Target must not have the same/identical organ. -/obj/machinery/dna_infuser/proc/pick_organ(mob/living/carbon/human/target) - if(!infusing_into) - return FALSE - var/list/obj/item/organ/potential_new_organs = infusing_into.output_organs.Copy() - // Remove organ typepaths from the list if they're incompatible with target. - for(var/obj/item/organ/new_organ as anything in infusing_into.output_organs) - var/obj/item/organ/old_organ = target.get_organ_slot(initial(new_organ.slot)) - if(old_organ) - if((old_organ.type != new_organ) && !IS_ROBOTIC_ORGAN(old_organ)) - continue // Old organ can be mutated! - else if(ispath(new_organ, /obj/item/organ/external)) - continue // External organ can be grown! - // Internal organ is either missing, or is non-organic. - potential_new_organs -= new_organ - // Pick a random organ from the filtered list. - if(length(potential_new_organs)) - return pick(potential_new_organs) - return FALSE - /// checks to see if the machine should progress a new tier. /obj/machinery/dna_infuser/proc/check_tier_progression(mob/living/carbon/human/target) if( @@ -171,7 +123,7 @@ && target.has_status_effect(infusing_into.status_effect_type) \ ) max_tier_allowed++ - playsound(src.loc, 'sound/machines/ding.ogg', 50, TRUE) + playsound(src, 'sound/machines/ding.ogg', 50, TRUE) visible_message(span_notice("[src] dings as it records the results of the full infusion.")) /obj/machinery/dna_infuser/update_icon_state() @@ -254,19 +206,6 @@ infusing_from = target infusing_from.forceMove(src) -/// Verify that the occupant/target is organic, and has mutable DNA. -/obj/machinery/dna_infuser/proc/is_valid_occupant(mob/living/carbon/human/human_target, mob/user) - // Invalid: DNA is too damaged to mutate anymore / has TRAIT_BADDNA. - if(HAS_TRAIT(human_target, TRAIT_BADDNA)) - balloon_alert(user, "dna is corrupted!") - return FALSE - // Invalid: Occupant isn't Human, isn't organic, lacks DNA / has TRAIT_GENELESS. - if(!ishuman(human_target) || !human_target.can_mutate()) - balloon_alert(user, "dna is missing!") - return FALSE - // Valid: Occupant is an organic Human who has undamaged and mutable DNA. - return TRUE - /// Verify that the given infusion source/mob is a dead creature. /obj/machinery/dna_infuser/proc/is_valid_infusion(atom/movable/target, mob/user) if(user.stat != CONSCIOUS || HAS_TRAIT(user, TRAIT_UI_BLOCKED) || !Adjacent(user) || !user.Adjacent(target) || !ISADVANCEDTOOLUSER(user)) @@ -288,8 +227,7 @@ return FALSE return TRUE -/obj/machinery/dna_infuser/AltClick(mob/user) - . = ..() +/obj/machinery/dna_infuser/click_alt(mob/user) if(infusing) balloon_alert(user, "not while it's on!") return @@ -299,6 +237,7 @@ balloon_alert(user, "ejected sample") infusing_from.forceMove(get_turf(src)) infusing_from = null + return CLICK_ACTION_SUCCESS #undef INFUSING_TIME #undef SCREAM_TIME diff --git a/code/game/machinery/dna_infuser/dna_infusion.dm b/code/game/machinery/dna_infuser/dna_infusion.dm new file mode 100644 index 0000000000000..c902240404ca7 --- /dev/null +++ b/code/game/machinery/dna_infuser/dna_infusion.dm @@ -0,0 +1,75 @@ + +///returns a boolean whether a machine occupant can be infused +/atom/movable/proc/can_infuse(mob/feedback_target) + if(feedback_target) + balloon_alert(feedback_target, "no dna!") + return FALSE + +/mob/living/can_infuse(mob/feedback_target) + if(feedback_target) + balloon_alert(feedback_target, "dna too simple!") + return FALSE + +/mob/living/carbon/human/can_infuse(mob/feedback_target) + // Checked by can_mutate but explicit feedback for this issue is good + if(HAS_TRAIT(src, TRAIT_BADDNA)) + if(feedback_target) + balloon_alert(feedback_target, "dna is corrupted!") + return FALSE + if(!can_mutate()) + if(feedback_target) + balloon_alert(feedback_target, "dna is missing!") + return FALSE + return TRUE + +///returns /datum/infuser_entry that matches an item being used for infusion, returns a fly mutation on failure +/atom/movable/proc/get_infusion_entry() as /datum/infuser_entry + var/datum/infuser_entry/found + for(var/datum/infuser_entry/entry as anything in flatten_list(GLOB.infuser_entries)) + if(entry.tier == DNA_MUTANT_UNOBTAINABLE) + continue + if(is_type_in_list(src, entry.input_obj_or_mob)) + found = entry + break + if(!found) + found = GLOB.infuser_entries[/datum/infuser_entry/fly] + return found + +/// Attempt to replace/add-to the occupant's organs with "mutated" equivalents. +/// Returns TRUE on success, FALSE on failure. +/// Requires the target mob to have an existing organic organ to "mutate". +// TODO: In the future, this should have more logic: +// - Replace non-mutant organs before mutant ones. +/mob/living/carbon/human/proc/infuse_organ(datum/infuser_entry/entry) + var/obj/item/organ/new_organ = pick_infusion_organ(entry) + if(!new_organ) + return FALSE + // Valid organ successfully picked. + new_organ = new new_organ() + new_organ.replace_into(src) + return TRUE + +/// Picks a random mutated organ from the given infuser entry which is also compatible with this human. +/// Tries to return a typepath of a valid mutant organ if all of the following criteria are true: +/// 1. Target must have a pre-existing organ in the same organ slot as the new organ; +/// - or the new organ must be external. +/// 2. Target's pre-existing organ must be organic / not robotic. +/// 3. Target must not have the same/identical organ. +/mob/living/carbon/human/proc/pick_infusion_organ(datum/infuser_entry/entry) + if(!entry) + return FALSE + var/list/obj/item/organ/potential_new_organs = entry.output_organs.Copy() + // Remove organ typepaths from the list if they're incompatible with target. + for(var/obj/item/organ/new_organ as anything in entry.output_organs) + var/obj/item/organ/old_organ = get_organ_slot(initial(new_organ.slot)) + if(old_organ) + if((old_organ.type != new_organ) && !IS_ROBOTIC_ORGAN(old_organ)) + continue // Old organ can be mutated! + else if(ispath(new_organ, /obj/item/organ/external)) + continue // External organ can be grown! + // Internal organ is either missing, or is non-organic. + potential_new_organs -= new_organ + // Pick a random organ from the filtered list. + if(length(potential_new_organs)) + return pick(potential_new_organs) + return FALSE diff --git a/code/game/machinery/dna_infuser/infuser_book.dm b/code/game/machinery/dna_infuser/infuser_book.dm index 75632178ccae3..416ed038d640a 100644 --- a/code/game/machinery/dna_infuser/infuser_book.dm +++ b/code/game/machinery/dna_infuser/infuser_book.dm @@ -29,7 +29,7 @@ var/list/data = list() // Collect all info from each intry. var/list/entry_data = list() - for(var/datum/infuser_entry/entry as anything in GLOB.infuser_entries) + for(var/datum/infuser_entry/entry as anything in flatten_list(GLOB.infuser_entries)) if(entry.tier == DNA_MUTANT_UNOBTAINABLE) continue var/list/individual_entry_data = list() diff --git a/code/game/machinery/dna_infuser/infuser_entry.dm b/code/game/machinery/dna_infuser/infuser_entry.dm index dfcdfbbe08a5d..8b0bcfb3f790d 100644 --- a/code/game/machinery/dna_infuser/infuser_entry.dm +++ b/code/game/machinery/dna_infuser/infuser_entry.dm @@ -4,17 +4,10 @@ GLOBAL_LIST_INIT(infuser_entries, prepare_infuser_entries()) /// Global proc that sets up each [/datum/infuser_entry] sub-type as singleton instances in a list, and returns it. /proc/prepare_infuser_entries() var/list/entries = list() - // Regardless of names, we want the fly/failed mutant case to show first. - var/prepended for(var/datum/infuser_entry/entry_type as anything in subtypesof(/datum/infuser_entry)) var/datum/infuser_entry/entry = new entry_type() - if(entry.type == /datum/infuser_entry/fly) - prepended = entry - continue - entries += entry - var/list/sorted = sort_names(entries) - sorted.Insert(1, prepended) - return sorted + entries[entry_type] = entry + return entries /datum/infuser_entry //-- Vars for DNA Infusion Book --// diff --git a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm index afbb8404060f2..0c181ad043e77 100644 --- a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm @@ -27,7 +27,7 @@ /obj/item/organ/internal/lungs/carp/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "neck has odd gills.", BODY_ZONE_HEAD) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their neck has odd gills.", BODY_ZONE_HEAD) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) ADD_TRAIT(src, TRAIT_SPACEBREATHING, REF(src)) @@ -45,7 +45,7 @@ /obj/item/organ/internal/tongue/carp/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "teeth are big and sharp.", BODY_ZONE_PRECISE_MOUTH) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their teeth are big and sharp.", BODY_ZONE_PRECISE_MOUTH) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) /obj/item/organ/internal/tongue/carp/on_mob_insert(mob/living/carbon/tongue_owner, special, movement_flags) @@ -113,7 +113,7 @@ /obj/item/organ/internal/brain/carp/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) - AddElement(/datum/element/noticable_organ, "seem%PRONOUN_S unable to stay still.") + AddElement(/datum/element/noticable_organ, "%PRONOUN_They seem%PRONOUN_s unable to stay still.") /obj/item/organ/internal/brain/carp/on_mob_insert(mob/living/carbon/brain_owner) . = ..() @@ -151,8 +151,9 @@ /obj/item/organ/internal/heart/carp/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "skin has small patches of scales growing on it.", BODY_ZONE_CHEST) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their skin has small patches of scales growing on it.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) + AddElement(/datum/element/update_icon_blocker) #undef CARP_ORGAN_COLOR #undef CARP_SCLERA_COLOR diff --git a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm index f9ccf16812bc7..ac3dae39b7019 100644 --- a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm @@ -31,7 +31,7 @@ /obj/item/organ/internal/eyes/night_vision/goliath/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "eyes are blood red and stone-like.", BODY_ZONE_PRECISE_EYES) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their eyes are blood red and stone-like.", BODY_ZONE_PRECISE_EYES) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) ///goliath lungs! You can breathe lavaland air mix but can't breath pure O2 from a tank anymore. @@ -46,7 +46,7 @@ /obj/item/organ/internal/lungs/lavaland/goliath/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "back is covered in small tendrils.", BODY_ZONE_CHEST) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their back is covered in small tendrils.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) ///goliath brain. you can't use gloves but one of your arms becomes a tendril hammer that can be used to mine! @@ -63,7 +63,7 @@ /obj/item/organ/internal/brain/goliath/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "arm is just a mass of plate and tendrils.", BODY_ZONE_CHEST) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their arm is just a mass of plate and tendrils.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) /obj/item/organ/internal/brain/goliath/on_mob_insert(mob/living/carbon/brain_owner) @@ -170,7 +170,7 @@ /obj/item/organ/internal/heart/goliath/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "skin has visible hard plates growing from within.", BODY_ZONE_CHEST) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their skin has visible hard plates growing from within.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) AddElement(/datum/element/update_icon_blocker) diff --git a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm index 96e41a57789bd..797c7839b2c29 100644 --- a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm @@ -31,7 +31,8 @@ Fluoride Stare: After someone says 5 words, blah blah blah... /obj/item/organ/internal/heart/gondola/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola) - AddElement(/datum/element/noticable_organ, "radiate%PRONOUN_S an aura of serenity.") + AddElement(/datum/element/noticable_organ, "%PRONOUN_They radiate%PRONOUN_s an aura of serenity.") + AddElement(/datum/element/update_icon_blocker) /obj/item/organ/internal/heart/gondola/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() @@ -60,7 +61,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah... /obj/item/organ/internal/tongue/gondola/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "mouth is permanently affixed into a relaxed smile.", BODY_ZONE_PRECISE_MOUTH) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their mouth is permanently affixed into a relaxed smile.", BODY_ZONE_PRECISE_MOUTH) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola) /obj/item/organ/internal/tongue/gondola/Insert(mob/living/carbon/tongue_owner, special, movement_flags) @@ -83,8 +84,8 @@ Fluoride Stare: After someone says 5 words, blah blah blah... /obj/item/organ/internal/liver/gondola/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola) - AddElement(/datum/element/noticable_organ, "left arm has small needles breaching the skin all over it.", BODY_ZONE_L_ARM) - AddElement(/datum/element/noticable_organ, "right arm has small needles breaching the skin all over it.", BODY_ZONE_R_ARM) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their left arm has small needles breaching the skin all over it.", BODY_ZONE_L_ARM) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their right arm has small needles breaching the skin all over it.", BODY_ZONE_R_ARM) /obj/item/organ/internal/liver/gondola/Insert(mob/living/carbon/liver_owner, special, movement_flags) . = ..() diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm index f6e1e92c2a508..45d5f3ddfd997 100644 --- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm @@ -29,7 +29,7 @@ /obj/item/organ/internal/eyes/night_vision/rat/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "eyes have deep, shifty black pupils, surrounded by a sickening yellow sclera.", BODY_ZONE_PRECISE_EYES) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their eyes have deep, shifty black pupils, surrounded by a sickening yellow sclera.", BODY_ZONE_PRECISE_EYES) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) ///increases hunger, disgust recovers quicker, expands what is defined as "food" @@ -47,7 +47,7 @@ /obj/item/organ/internal/stomach/rat/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) - AddElement(/datum/element/noticable_organ, "mouth is drooling excessively.", BODY_ZONE_PRECISE_MOUTH) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their mouth is drooling excessively.", BODY_ZONE_PRECISE_MOUTH) /// makes you smaller, walk over tables, and take 1.5x damage /obj/item/organ/internal/heart/rat @@ -61,7 +61,8 @@ /obj/item/organ/internal/heart/rat/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) - AddElement(/datum/element/noticable_organ, "hunch%PRONOUN_ES over unnaturally!") + AddElement(/datum/element/noticable_organ, "%PRONOUN_They hunch%PRONOUN_es over unnaturally!") + AddElement(/datum/element/update_icon_blocker) /obj/item/organ/internal/heart/rat/on_mob_insert(mob/living/carbon/receiver) . = ..() @@ -98,12 +99,12 @@ /obj/item/organ/internal/tongue/rat/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "teeth are oddly shaped and yellowing.", BODY_ZONE_PRECISE_MOUTH) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their teeth are oddly shaped and yellowing.", BODY_ZONE_PRECISE_MOUTH) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) /obj/item/organ/internal/tongue/rat/modify_speech(datum/source, list/speech_args) . = ..() - var/message = lowertext(speech_args[SPEECH_MESSAGE]) + var/message = LOWER_TEXT(speech_args[SPEECH_MESSAGE]) if(message == "hi" || message == "hi.") speech_args[SPEECH_MESSAGE] = "Cheesed to meet you!" if(message == "hi?") diff --git a/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm b/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm index 0644bca0354a6..b31a64d9bb87c 100644 --- a/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm @@ -63,8 +63,9 @@ /obj/item/organ/internal/heart/roach/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "has hardened, somewhat translucent skin.") + AddElement(/datum/element/noticable_organ, "%PRONOUN_They %PRONOUN_have hardened, somewhat translucent skin.") AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/roach) + AddElement(/datum/element/update_icon_blocker) roach_shell = new() /obj/item/organ/internal/heart/roach/Destroy() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 325f272b5f068..e32b78d9f776c 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -86,6 +86,7 @@ smoothing_groups = SMOOTH_GROUP_AIRLOCK interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_OPEN + interaction_flags_click = ALLOW_SILICON_REACH blocks_emissive = EMISSIVE_BLOCK_NONE // Custom emissive blocker. We don't want the normal behavior. ///The type of door frame to drop during deconstruction @@ -1496,7 +1497,7 @@ /obj/machinery/door/airlock/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) if((damage_amount >= atom_integrity) && (damage_flag == BOMB)) - obj_flags |= NO_DECONSTRUCTION //If an explosive took us out, don't drop the assembly + obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION //If an explosive took us out, don't drop the assembly . = ..() if(atom_integrity < (0.75 * max_integrity)) update_appearance() @@ -2152,7 +2153,7 @@ return ..() -/obj/machinery/door/airlock/external/LateInitialize() +/obj/machinery/door/airlock/external/post_machine_initialize() . = ..() if(space_dir) unres_sides |= space_dir diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 733cbf52f5da8..30deaef9183f3 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -91,7 +91,7 @@ RegisterSignal(src, COMSIG_MACHINERY_POWER_LOST, PROC_REF(on_power_loss)) return INITIALIZE_HINT_LATELOAD -/obj/machinery/door/firedoor/LateInitialize() +/obj/machinery/door/firedoor/post_machine_initialize() . = ..() RegisterSignal(src, COMSIG_MERGER_ADDING, PROC_REF(merger_adding)) RegisterSignal(src, COMSIG_MERGER_REMOVING, PROC_REF(merger_removing)) @@ -886,7 +886,7 @@ return if(istype(attacking_object, /obj/item/electroadaptive_pseudocircuit)) var/obj/item/electroadaptive_pseudocircuit/raspberrypi = attacking_object - if(!raspberrypi.adapt_circuit(user, circuit_cost = DEFAULT_STEP_TIME * 0.5 KILO JOULES)) + if(!raspberrypi.adapt_circuit(user, circuit_cost = DEFAULT_STEP_TIME * 0.0005 * STANDARD_CELL_CHARGE)) return user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \ span_notice("You adapt a firelock circuit and slot it into the assembly.")) diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index ea8d758666e7d..48e0cb195d7f3 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -35,6 +35,72 @@ /obj/machinery/door/poddoor/get_save_vars() return ..() + NAMEOF(src, id) +/obj/machinery/door/poddoor/examine(mob/user) + . = ..() + if(panel_open) + if(deconstruction == BLASTDOOR_FINISHED) + . += span_notice("The maintenance panel is opened and the electronics could be pried out.") + . += span_notice("\The [src] could be calibrated to a blast door controller ID with a multitool.") + else if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS) + . += span_notice("The electronics are missing and there are some wires sticking out.") + else if(deconstruction == BLASTDOOR_NEEDS_WIRES) + . += span_notice("The wires have been removed and it's ready to be sliced apart.") + +/obj/machinery/door/poddoor/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(isnull(held_item)) + return NONE + if(deconstruction == BLASTDOOR_NEEDS_WIRES && istype(held_item, /obj/item/stack/cable_coil)) + context[SCREENTIP_CONTEXT_LMB] = "Wire assembly" + return CONTEXTUAL_SCREENTIP_SET + if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS && istype(held_item, /obj/item/electronics/airlock)) + context[SCREENTIP_CONTEXT_LMB] = "Add electronics" + return CONTEXTUAL_SCREENTIP_SET + //we do not check for special effects like if they can actually perform the action because they will be told they can't do it when they try, + //with feedback on what they have to do in order to do so. + switch(held_item.tool_behaviour) + if(TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Open panel" + return CONTEXTUAL_SCREENTIP_SET + if(TOOL_MULTITOOL) + context[SCREENTIP_CONTEXT_LMB] = "Calibrate ID" + return CONTEXTUAL_SCREENTIP_SET + if(TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Remove electronics" + return CONTEXTUAL_SCREENTIP_SET + if(TOOL_WIRECUTTER) + context[SCREENTIP_CONTEXT_LMB] = "Remove wires" + return CONTEXTUAL_SCREENTIP_SET + if(TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "Disassemble" + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/door/poddoor/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(deconstruction == BLASTDOOR_NEEDS_WIRES && istype(tool, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/coil = tool + var/datum/crafting_recipe/recipe = locate(recipe_type) in GLOB.crafting_recipes + var/amount_needed = recipe.reqs[/obj/item/stack/cable_coil] + if(coil.get_amount() < amount_needed) + balloon_alert(user, "not enough cable!") + return ITEM_INTERACT_SUCCESS + balloon_alert(user, "adding cables...") + if(!do_after(user, 5 SECONDS, src)) + return ITEM_INTERACT_SUCCESS + coil.use(amount_needed) + deconstruction = BLASTDOOR_NEEDS_ELECTRONICS + balloon_alert(user, "cables added") + return ITEM_INTERACT_SUCCESS + + if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS && istype(tool, /obj/item/electronics/airlock)) + balloon_alert(user, "adding electronics...") + if(!do_after(user, 10 SECONDS, src)) + return ITEM_INTERACT_SUCCESS + qdel(tool) + balloon_alert(user, "electronics added") + deconstruction = BLASTDOOR_FINISHED + return ITEM_INTERACT_SUCCESS + return NONE + /obj/machinery/door/poddoor/screwdriver_act(mob/living/user, obj/item/tool) . = ..() if (density) @@ -49,7 +115,8 @@ balloon_alert(user, "open the door first!") return ITEM_INTERACT_SUCCESS if (!panel_open) - return + balloon_alert(user, "open the panel first!") + return ITEM_INTERACT_SUCCESS if (deconstruction != BLASTDOOR_FINISHED) return var/change_id = tgui_input_number(user, "Set the door controllers ID (Current: [id])", "Door Controller ID", isnum(id) ? id : null, 100) @@ -69,7 +136,8 @@ balloon_alert(user, "open the door first!") return ITEM_INTERACT_SUCCESS if (!panel_open) - return + balloon_alert(user, "open the panel first!") + return ITEM_INTERACT_SUCCESS if (deconstruction != BLASTDOOR_FINISHED) return balloon_alert(user, "removing airlock electronics...") @@ -86,7 +154,8 @@ balloon_alert(user, "open the door first!") return ITEM_INTERACT_SUCCESS if (!panel_open) - return + balloon_alert(user, "open the panel first!") + return ITEM_INTERACT_SUCCESS if (deconstruction != BLASTDOOR_NEEDS_ELECTRONICS) return balloon_alert(user, "removing internal cables...") @@ -104,7 +173,8 @@ balloon_alert(user, "open the door first!") return ITEM_INTERACT_SUCCESS if (!panel_open) - return + balloon_alert(user, "open the panel first!") + return ITEM_INTERACT_SUCCESS if (deconstruction != BLASTDOOR_NEEDS_WIRES) return balloon_alert(user, "tearing apart...") //You're tearing me apart, Lisa! @@ -116,17 +186,6 @@ qdel(src) return ITEM_INTERACT_SUCCESS -/obj/machinery/door/poddoor/examine(mob/user) - . = ..() - if(panel_open) - if(deconstruction == BLASTDOOR_FINISHED) - . += span_notice("The maintenance panel is opened and the electronics could be pried out.") - . += span_notice("\The [src] could be calibrated to a blast door controller ID with a multitool.") - else if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS) - . += span_notice("The electronics are missing and there are some wires sticking out.") - else if(deconstruction == BLASTDOOR_NEEDS_WIRES) - . += span_notice("The wires have been removed and it's ready to be sliced apart.") - /obj/machinery/door/poddoor/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) id = "[port.shuttle_id]_[id]" diff --git a/code/game/machinery/doors/shutters.dm b/code/game/machinery/doors/shutters.dm index eca8d88da4baf..0df6024ca827a 100644 --- a/code/game/machinery/doors/shutters.dm +++ b/code/game/machinery/doors/shutters.dm @@ -16,6 +16,9 @@ density = FALSE opacity = FALSE +/obj/machinery/door/poddoor/shutters/preopen/deconstructed + deconstruction = BLASTDOOR_NEEDS_WIRES + /obj/machinery/door/poddoor/shutters/indestructible name = "hardened shutters" resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 1dc343a0c0b2d..c69c865f6d122 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -66,11 +66,8 @@ /obj/machinery/door/window/Destroy() set_density(FALSE) - if(atom_integrity == 0) - playsound(src, SFX_SHATTER, 70, TRUE) electronics = null - var/turf/floor = get_turf(src) - floor.air_update_turf(TRUE, FALSE) + air_update_turf(TRUE, FALSE) return ..() /obj/machinery/door/window/update_icon_state() @@ -300,11 +297,12 @@ if(BURN) playsound(src, 'sound/items/welder.ogg', 100, TRUE) - /obj/machinery/door/window/on_deconstruction(disassembled) if(disassembled) return + playsound(src, SFX_SHATTER, 70, TRUE) + for(var/i in 1 to shards) drop_debris(new /obj/item/shard(src)) if(rods) @@ -347,8 +345,6 @@ /obj/machinery/door/window/screwdriver_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(density || operating) to_chat(user, span_warning("You need to open the door to access the maintenance panel!")) return @@ -360,8 +356,6 @@ /obj/machinery/door/window/crowbar_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(!panel_open || density || operating) return add_fingerprint(user) diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm index ad4d32deadf90..83b1626900286 100644 --- a/code/game/machinery/embedded_controller/access_controller.dm +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -16,7 +16,8 @@ ..() return INITIALIZE_HINT_LATELOAD -/obj/machinery/door_buttons/LateInitialize() +/obj/machinery/door_buttons/post_machine_initialize() + . = ..() find_objects_by_tag() /obj/machinery/door_buttons/emag_act(mob/user, obj/item/card/emag/emag_card) diff --git a/code/game/machinery/embedded_controller/airlock_controller.dm b/code/game/machinery/embedded_controller/airlock_controller.dm index 11f9050ac6bf9..a1cc608c2ec9d 100644 --- a/code/game/machinery/embedded_controller/airlock_controller.dm +++ b/code/game/machinery/embedded_controller/airlock_controller.dm @@ -34,7 +34,7 @@ var/processing = FALSE -/obj/machinery/airlock_controller/LateInitialize() +/obj/machinery/airlock_controller/post_machine_initialize() . = ..() var/obj/machinery/door/interior_door = GLOB.objects_by_id_tag[interior_door_tag] diff --git a/code/game/machinery/fat_sucker.dm b/code/game/machinery/fat_sucker.dm index 279e83ecbe999..c93a0e4f7ea56 100644 --- a/code/game/machinery/fat_sucker.dm +++ b/code/game/machinery/fat_sucker.dm @@ -80,7 +80,7 @@ user.visible_message(span_notice("You see [user] kicking against the door of [src]!"), \ span_notice("You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)"), \ span_hear("You hear a metallic creaking from [src].")) - if(do_after(user, breakout_time, target = src)) + if(do_after(user, breakout_time, target = src, hidden = TRUE)) if(!user || user.stat != CONSCIOUS || user.loc != src || state_open) return free_exit = TRUE @@ -98,17 +98,16 @@ else to_chat(user, span_warning("The safety hatch has been disabled!")) -/obj/machinery/fat_sucker/AltClick(mob/living/user) - if(!user.can_perform_action(src)) - return +/obj/machinery/fat_sucker/click_alt(mob/living/user) if(user == occupant) to_chat(user, span_warning("You can't reach the controls from inside!")) - return + return CLICK_ACTION_BLOCKING if(!(obj_flags & EMAGGED) && !allowed(user)) to_chat(user, span_warning("You lack the required access.")) - return + return CLICK_ACTION_BLOCKING free_exit = !free_exit to_chat(user, span_notice("Safety hatch [free_exit ? "unlocked" : "locked"].")) + return CLICK_ACTION_SUCCESS /obj/machinery/fat_sucker/update_overlays() . = ..() diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 8343a0251a9a1..10055aee5b29d 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -394,7 +394,7 @@ else if(istype(tool, /obj/item/electroadaptive_pseudocircuit)) var/obj/item/electroadaptive_pseudocircuit/pseudoc = tool - if(!pseudoc.adapt_circuit(user, circuit_cost = 15 KILO JOULES)) + if(!pseudoc.adapt_circuit(user, circuit_cost = 0.015 * STANDARD_CELL_CHARGE)) return user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \ span_notice("You adapt a fire alarm circuit and slot it into the assembly.")) diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm index 33d08def9d292..5fa999a690e9a 100644 --- a/code/game/machinery/harvester.dm +++ b/code/game/machinery/harvester.dm @@ -57,20 +57,16 @@ else if(!harvesting) open_machine() -/obj/machinery/harvester/AltClick(mob/user) - . = ..() - if(!user.can_perform_action(src)) - return +/obj/machinery/harvester/click_alt(mob/user) if(panel_open) output_dir = turn(output_dir, -90) to_chat(user, span_notice("You change [src]'s output settings, setting the output to [dir2text(output_dir)].")) - return - if(!can_interact(user)) - return - if(harvesting || !user || !isliving(user) || state_open) - return - if(can_harvest()) - start_harvest() + return CLICK_ACTION_SUCCESS + if(harvesting || state_open || !can_harvest()) + return CLICK_ACTION_BLOCKING + + start_harvest() + return CLICK_ACTION_SUCCESS /obj/machinery/harvester/proc/can_harvest() if(!powered() || state_open || !occupant || !iscarbon(occupant)) @@ -171,7 +167,7 @@ return TRUE /obj/machinery/harvester/default_pry_open(obj/item/tool) //wew - . = !(state_open || panel_open || (obj_flags & NO_DECONSTRUCTION)) && tool.tool_behaviour == TOOL_CROWBAR //We removed is_operational here + . = !(state_open || panel_open) && tool.tool_behaviour == TOOL_CROWBAR //We removed is_operational here if(.) tool.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open \the [src]."), span_notice("You pry open [src].")) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 05c0fe242461f..1e06be41952fd 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -47,6 +47,7 @@ Possible to do for anyone motivated enough: armor_type = /datum/armor/machinery_holopad circuit = /obj/item/circuitboard/machine/holopad interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_IGNORE_MOBILITY + interaction_flags_click = ALLOW_SILICON_REACH // Blue, dim light light_power = 0.8 light_color = LIGHT_COLOR_BLUE @@ -111,6 +112,9 @@ Possible to do for anyone motivated enough: ) AddElement(/datum/element/contextual_screentip_mob_typechecks, hovering_mob_typechecks) + if(on_network) + holopads += src + /obj/machinery/holopad/secure name = "secure holopad" desc = "It's a floor-mounted device for projecting holographic images. This one will refuse to auto-connect incoming calls." @@ -124,7 +128,6 @@ Possible to do for anyone motivated enough: /obj/machinery/holopad/tutorial resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION on_network = FALSE ///Proximity monitor associated with this atom, needed for proximity checks. var/datum/proximity_monitor/proximity_monitor @@ -140,6 +143,12 @@ Possible to do for anyone motivated enough: new_disk.forceMove(src) disk = new_disk +/obj/machinery/holopad/tutorial/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/holopad/tutorial/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/machinery/holopad/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) . = ..() if(!loc) @@ -175,11 +184,6 @@ Possible to do for anyone motivated enough: if(!replay_mode && (disk?.record)) replay_start() -/obj/machinery/holopad/Initialize(mapload) - . = ..() - if(on_network) - holopads += src - /obj/machinery/holopad/Destroy() if(outgoing_call) outgoing_call.ConnectionFailure(src) diff --git a/code/game/machinery/incident_display.dm b/code/game/machinery/incident_display.dm index fcdfecf6a3178..b8452675c71aa 100644 --- a/code/game/machinery/incident_display.dm +++ b/code/game/machinery/incident_display.dm @@ -80,7 +80,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/incident_display/tram, 32) ..() return INITIALIZE_HINT_LATELOAD -/obj/machinery/incident_display/LateInitialize() +/obj/machinery/incident_display/post_machine_initialize() . = ..() GLOB.map_delamination_counters += src update_delam_count(SSpersistence.rounds_since_engine_exploded, SSpersistence.delam_highscore) diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 6244dcdd2dbc5..91104abf68123 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -207,15 +207,10 @@ else return ..() -/// Checks whether the IV drip transfer rate can be modified with AltClick -/obj/machinery/iv_drip/proc/can_use_alt_click(mob/user) - if(!can_interact(user)) - return FALSE -/obj/machinery/iv_drip/AltClick(mob/user) - if(!can_use_alt_click(user)) - return ..() +/obj/machinery/iv_drip/click_alt(mob/user) set_transfer_rate(transfer_rate > MIN_IV_TRANSFER_RATE ? MIN_IV_TRANSFER_RATE : MAX_IV_TRANSFER_RATE) + return CLICK_ACTION_SUCCESS /obj/machinery/iv_drip/on_deconstruction(disassembled = TRUE) new /obj/item/stack/sheet/iron(loc) diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index 0c95d3aa5c1d1..57047c25cac10 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -304,7 +304,7 @@ if(!briefcase || !usr.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) return usr.visible_message(span_notice("[usr] starts closing [src]..."), span_notice("You start closing [src]...")) - if(do_after(usr, 30, target = usr)) + if(do_after(usr, 3 SECONDS, target = usr)) usr.put_in_hands(briefcase) moveToNullspace() //hides it from suitcase contents closed = TRUE @@ -343,7 +343,7 @@ return add_fingerprint(user) user.visible_message(span_notice("[user] starts setting down [src]..."), span_notice("You start setting up [pad]...")) - if(do_after(user, 30, target = user)) + if(do_after(user, 3 SECONDS, target = user)) pad.forceMove(get_turf(src)) pad.update_indicator() pad.closed = FALSE diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 1fe2f542ba215..b63d13648eb76 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -283,7 +283,6 @@ /obj/machinery/limbgrower/fullupgrade //Inherently cheaper organ production. This is to NEVER be inherently emagged, no valids. desc = "It grows new limbs using Synthflesh. This alien model seems more efficient." - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION circuit = /obj/item/circuitboard/machine/limbgrower/fullupgrade /obj/machinery/limbgrower/fullupgrade/Initialize(mapload) diff --git a/code/game/machinery/machine_frame.dm b/code/game/machinery/machine_frame.dm index 84c58d3282376..ccdcddc87052d 100644 --- a/code/game/machinery/machine_frame.dm +++ b/code/game/machinery/machine_frame.dm @@ -17,11 +17,10 @@ QDEL_LIST(components) return ..() -/obj/structure/frame/machine/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(state >= FRAME_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 5) - dump_contents() +/obj/structure/frame/machine/atom_deconstruct(disassembled = TRUE) + if(state >= FRAME_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 5) + dump_contents() return ..() /obj/structure/frame/machine/add_context(atom/source, list/context, obj/item/held_item, mob/user) @@ -390,7 +389,7 @@ balloon_alert(user, "can't add that!") return FALSE -/obj/structure/frame/machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/structure/frame/machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers) . = ..() if(. & ITEM_INTERACT_ANY_BLOCKER) return . @@ -417,11 +416,18 @@ if(istype(tool, /obj/item/storage/part_replacer)) return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - if(!user.combat_mode) - return add_part(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - return . +// Override of base_item_interaction so we only try to add parts to the frame AFTER running item_interaction and all the tool_acts +/obj/structure/frame/machine/base_item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(user.combat_mode) + return NONE + + return add_part(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + /** * Attempt to finalize the construction of the frame into a machine * as according to our circuit and parts diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index 6963b23afb09d..5f534ec95b4ed 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -14,10 +14,6 @@ . = ..() wires = new /datum/wires/mass_driver(src) -/obj/machinery/mass_driver/Destroy() - QDEL_NULL(wires) - . = ..() - /obj/machinery/mass_driver/chapelgun name = "holy driver" id = MASSDRIVER_CHAPEL @@ -35,6 +31,7 @@ for(var/obj/machinery/computer/pod/control as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/pod)) if(control.id == id) control.connected = null + QDEL_NULL(wires) return ..() /obj/machinery/mass_driver/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) diff --git a/code/game/machinery/medipen_refiller.dm b/code/game/machinery/medipen_refiller.dm index 241b43d93da78..57c3fa2f8d493 100644 --- a/code/game/machinery/medipen_refiller.dm +++ b/code/game/machinery/medipen_refiller.dm @@ -14,6 +14,11 @@ /obj/item/reagent_containers/hypospray/medipen/oxandrolone = /datum/reagent/medicine/oxandrolone, /obj/item/reagent_containers/hypospray/medipen/salacid = /datum/reagent/medicine/sal_acid, /obj/item/reagent_containers/hypospray/medipen/penacid = /datum/reagent/medicine/pen_acid, + /obj/item/reagent_containers/hypospray/medipen/mutadone = /datum/reagent/medicine/mutadone, + /obj/item/reagent_containers/hypospray/medipen/methamphetamine = /datum/reagent/drug/methamphetamine, + /obj/item/reagent_containers/hypospray/medipen/survival = /datum/reagent/medicine/c2/libital, + /obj/item/reagent_containers/hypospray/medipen/survival/luxury = /datum/reagent/medicine/c2/penthrite, + /obj/item/reagent_containers/hypospray/medipen/invisibility = /datum/reagent/drug/saturnx, ) /obj/machinery/medipen_refiller/Initialize(mapload) @@ -86,9 +91,9 @@ return ..() /obj/machinery/medipen_refiller/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) - to_chat(user, span_notice("You start furiously plunging [name].")) - if(do_after(user, 30, target = src)) - to_chat(user, span_notice("You finish plunging the [name].")) + user.balloon_alert_to_viewers("furiously plunging...", "plunging medipen refiller...") + if(do_after(user, 3 SECONDS, target = src)) + user.balloon_alert_to_viewers("finished plunging") reagents.expose(get_turf(src), TOUCH) reagents.clear_reagents() diff --git a/code/game/machinery/nebula_shielding.dm b/code/game/machinery/nebula_shielding.dm index cd10a23150c87..10306177ebf5a 100644 --- a/code/game/machinery/nebula_shielding.dm +++ b/code/game/machinery/nebula_shielding.dm @@ -145,7 +145,7 @@ More circuit boards can be ordered through cargo. Consider setting up auxillary shielding units in-case of destruction, power loss or sabotage. "} -/// Warns the viro that they can't use radioactive resonance +/// Warns medical that they can't use radioactive resonance /obj/item/paper/fluff/radiation_nebula_virologist name = "radioactive resonance" default_raw_text = {"EXTREME IMPORTANCE!!!!
diff --git a/code/game/machinery/photobooth.dm b/code/game/machinery/photobooth.dm index d77759742694c..321ae7efd6e76 100644 --- a/code/game/machinery/photobooth.dm +++ b/code/game/machinery/photobooth.dm @@ -38,6 +38,7 @@ req_one_access = list(ACCESS_SECURITY) color = COLOR_LIGHT_GRAYISH_RED add_height_chart = TRUE + button_id = "photobooth_machine_security" /obj/machinery/photobooth/Initialize(mapload) . = ..() diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index d9e3787fd9ead..9e926d9a84189 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -394,8 +394,6 @@ Buildable meters balloon_alert(user, "pipe layer set to [piping_layer]") return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN -/obj/item/pipe/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/item/pipe/trinary/flippable/examine(mob/user) . = ..() diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index f318d93ecbd92..d41064ba2efcf 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -409,7 +409,7 @@ DEFINE_BITFIELD(turret_flags, list( spark_system.start() if(on && !(turret_flags & TURRET_FLAG_SHOOT_ALL_REACT) && !(obj_flags & EMAGGED)) turret_flags |= TURRET_FLAG_SHOOT_ALL_REACT - addtimer(CALLBACK(src, PROC_REF(reset_attacked)), 60) + addtimer(CALLBACK(src, PROC_REF(reset_attacked)), 6 SECONDS) /obj/machinery/porta_turret/proc/reset_attacked() turret_flags &= ~TURRET_FLAG_SHOOT_ALL_REACT @@ -420,17 +420,23 @@ DEFINE_BITFIELD(turret_flags, list( power_change() SetInvisibility(INVISIBILITY_NONE, id=type) spark_system.start() //creates some sparks because they look cool + has_cover = FALSE qdel(cover) //deletes the cover - no need on keeping it there! +/obj/machinery/porta_turret/atom_fix() + set_machine_stat(machine_stat & ~BROKEN) + has_cover = initial(has_cover) + check_should_process() + return ..() + + /obj/machinery/porta_turret/process() //the main machinery process - if(cover == null && anchored) //if it has no cover and is anchored - if(machine_stat & BROKEN) //if the turret is borked - qdel(cover) //delete its cover, assuming it has one. Workaround for a pesky little bug - else - if(has_cover) - cover = new /obj/machinery/porta_turret_cover(loc) //if the turret has no cover and is anchored, give it a cover - cover.parent_turret = src //assign the cover its parent_turret, which would be this (src) + if(has_cover && cover == null && anchored && !(machine_stat & BROKEN)) //if it has no cover and is anchored + cover = new /obj/machinery/porta_turret_cover(loc) //if the turret has no cover and is anchored, give it a cover + cover.parent_turret = src //assign the cover its parent_turret, which would be this (src) + if(raised) + cover.icon_state = "openTurretCover" if(!on || (machine_stat & (NOPOWER|BROKEN))) return PROCESS_KILL @@ -827,9 +833,9 @@ DEFINE_BITFIELD(turret_flags, list( if(target) setDir(get_dir(base, target))//even if you can't shoot, follow the target shootAt(target) - addtimer(CALLBACK(src, PROC_REF(shootAt), target), 5) - addtimer(CALLBACK(src, PROC_REF(shootAt), target), 10) - addtimer(CALLBACK(src, PROC_REF(shootAt), target), 15) + addtimer(CALLBACK(src, PROC_REF(shootAt), target), 0.5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shootAt), target), 1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shootAt), target), 1.5 SECONDS) return TRUE /obj/machinery/porta_turret/ai @@ -910,6 +916,7 @@ DEFINE_BITFIELD(turret_flags, list( density = FALSE req_access = list(ACCESS_AI_UPLOAD) resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + interaction_flags_click = ALLOW_SILICON_REACH /// Variable dictating if linked turrets are active and will shoot targets var/enabled = TRUE /// Variable dictating if linked turrets will shoot lethal projectiles @@ -1066,7 +1073,7 @@ DEFINE_BITFIELD(turret_flags, list( shoot_cyborgs = !shoot_cyborgs if (user) var/status = shoot_cyborgs ? "Shooting Borgs" : "Not Shooting Borgs" - balloon_alert(user, lowertext(status)) + balloon_alert(user, LOWER_TEXT(status)) add_hiddenprint(user) log_combat(user, src, "[status]") updateTurrets() diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm index 082881fc2fa91..149a0e7723ded 100644 --- a/code/game/machinery/porta_turret/portable_turret_cover.dm +++ b/code/game/machinery/porta_turret/portable_turret_cover.dm @@ -82,9 +82,6 @@ /obj/machinery/porta_turret_cover/attack_hulk(mob/living/carbon/human/user) return parent_turret.attack_hulk(user) -/obj/machinery/porta_turret_cover/can_be_overridden() - . = 0 - /obj/machinery/porta_turret_cover/emag_act(mob/user, obj/item/card/emag/emag_card) if((parent_turret.obj_flags & EMAGGED)) diff --git a/code/game/machinery/prisonlabor.dm b/code/game/machinery/prisonlabor.dm index 116edc2430e18..aaf1e6a342eaa 100644 --- a/code/game/machinery/prisonlabor.dm +++ b/code/game/machinery/prisonlabor.dm @@ -53,7 +53,7 @@ update_appearance() to_chat(user, span_notice("You start pressing a new license plate!")) - if(!do_after(user, 40, target = src)) + if(!do_after(user, 4 SECONDS, target = src)) pressing = FALSE update_appearance() return FALSE diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm index 99aaaff46c1c5..1c014927e62d4 100644 --- a/code/game/machinery/quantum_pad.dm +++ b/code/game/machinery/quantum_pad.dm @@ -89,7 +89,7 @@ interact(user, K.qpad) else to_chat(user, span_notice("You insert [K] into [src]'s card slot, initiating the link procedure.")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) to_chat(user, span_notice("You complete the link between [K] and [src].")) K.set_pad(src) diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index a886b54f19d29..2a2f219e61800 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -60,23 +60,28 @@ /obj/machinery/recharge_station/proc/charge_target_cell(obj/item/stock_parts/cell/target, seconds_per_tick) PRIVATE_PROC(TRUE) - return charge_cell(recharge_speed * seconds_per_tick, target, grid_only = TRUE) + //charge the cell, account for heat loss from work done + var/charge_given = charge_cell(recharge_speed * seconds_per_tick, target, grid_only = TRUE) + if(charge_given) + use_energy((charge_given + active_power_usage) * 0.01) + + return charge_given /obj/machinery/recharge_station/RefreshParts() . = ..() recharge_speed = 0 repairs = 0 for(var/datum/stock_part/capacitor/capacitor in component_parts) - recharge_speed += (capacitor.tier * STANDARD_CELL_CHARGE * 0.1) + recharge_speed += 5e-3 * capacitor.tier for(var/datum/stock_part/servo/servo in component_parts) repairs += servo.tier - 1 for(var/obj/item/stock_parts/cell/cell in component_parts) - recharge_speed *= (cell.maxcharge / STANDARD_CELL_CHARGE) + recharge_speed *= cell.maxcharge /obj/machinery/recharge_station/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) - . += span_notice("The status display reads: Recharging [recharge_speed]J per cycle.") + . += span_notice("The status display reads: Recharging: [display_power(recharge_speed, convert = FALSE)].") if(materials.silo) . += span_notice("The ore silo link indicator is lit, and cyborg restocking can be toggled by Right-Clicking [src].") if(repairs) @@ -88,12 +93,6 @@ else //Turned on begin_processing() - -/obj/machinery/recharge_station/process(seconds_per_tick) - if(occupant) - process_occupant(seconds_per_tick) - return 1 - /obj/machinery/recharge_station/relaymove(mob/living/user, direction) if(user.stat) return @@ -174,11 +173,8 @@ icon_state = "borgcharger[state_open ? 0 : (occupant ? 1 : 2)]" return ..() -/obj/machinery/recharge_station/proc/process_occupant(seconds_per_tick) - if(!occupant) - return - - if(!use_energy(active_power_usage * seconds_per_tick)) +/obj/machinery/recharge_station/process(seconds_per_tick) + if(QDELETED(occupant) || !is_operational) return SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, charge_cell, seconds_per_tick, repairs, sendmats) diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 405a38e4167f1..28aae48886621 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -35,7 +35,7 @@ . = ..() return INITIALIZE_HINT_LATELOAD -/obj/machinery/recycler/LateInitialize() +/obj/machinery/recycler/post_machine_initialize() . = ..() update_appearance(UPDATE_ICON) req_one_access = SSid_access.get_region_access_list(list(REGION_ALL_STATION, REGION_CENTCOM)) @@ -239,9 +239,15 @@ /obj/machinery/recycler/deathtrap name = "dangerous old crusher" - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION + obj_flags = CAN_BE_HIT | EMAGGED crush_damage = 120 +/obj/machinery/recycler/deathtrap/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/recycler/deathtrap/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/item/paper/guides/recycler name = "paper - 'garbage duty instructions'" default_raw_text = "

New Assignment

You have been assigned to collect garbage from trash bins, located around the station. The crewmembers will put their trash into it and you will collect said trash.

There is a recycling machine near your closet, inside maintenance; use it to recycle the trash for a small chance to get useful minerals. Then, deliver these minerals to cargo or engineering. You are our last hope for a clean station. Do not screw this up!" diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 54bdeb666d95f..4a764872a8a2a 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -144,7 +144,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) ui.set_autoupdate(FALSE) ui.open() -/obj/machinery/requests_console/ui_act(action, params) +/obj/machinery/requests_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -213,7 +213,8 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) var/recipient = params["reply_recipient"] var/reply_message = reject_bad_text(tgui_input_text(usr, "Write a quick reply to [recipient]", "Awaiting Input"), ascii_only = FALSE) - + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return if(!reply_message) has_mail_send_error = TRUE playsound(src, 'sound/machines/buzz-two.ogg', 50, TRUE) diff --git a/code/game/machinery/roulette_machine.dm b/code/game/machinery/roulette_machine.dm index f2e6ddd819532..ba4a5136a8978 100644 --- a/code/game/machinery/roulette_machine.dm +++ b/code/game/machinery/roulette_machine.dm @@ -224,7 +224,7 @@ playsound(src, 'sound/machines/roulettewheel.ogg', 50) addtimer(CALLBACK(src, PROC_REF(finish_play), player_id, bet_type, bet_amount, payout, rolled_number), 34) //4 deciseconds more so the animation can play - addtimer(CALLBACK(src, PROC_REF(finish_play_animation)), 30) + addtimer(CALLBACK(src, PROC_REF(finish_play_animation)), 3 SECONDS) use_energy(active_power_usage) @@ -448,7 +448,7 @@ return loc.visible_message(span_warning("\The [src] begins to beep loudly!")) used = TRUE - addtimer(CALLBACK(src, PROC_REF(launch_payload)), 40) + addtimer(CALLBACK(src, PROC_REF(launch_payload)), 4 SECONDS) /obj/item/roulette_wheel_beacon/proc/launch_payload() var/obj/structure/closet/supplypod/centcompod/toLaunch = new() diff --git a/code/game/machinery/sheetifier.dm b/code/game/machinery/sheetifier.dm index d9619092af6f3..bff759a6c7274 100644 --- a/code/game/machinery/sheetifier.dm +++ b/code/game/machinery/sheetifier.dm @@ -50,7 +50,7 @@ var/mutable_appearance/processing_overlay = mutable_appearance(icon, "processing") processing_overlay.color = last_inserted_material.color flick_overlay_static(processing_overlay, src, 64) - addtimer(CALLBACK(src, PROC_REF(finish_processing)), 64) + addtimer(CALLBACK(src, PROC_REF(finish_processing)), 6.4 SECONDS) /obj/machinery/sheetifier/proc/finish_processing() busy_processing = FALSE diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 82fe82edb1a27..4e7a80e166388 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -243,7 +243,7 @@ to_chat(user, span_warning("You need one length of cable to repair [src]!")) return to_chat(user, span_notice("You begin to replace the wires...")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) if(coil.get_amount() < 1) return coil.use(1) @@ -364,11 +364,8 @@ visible_message(span_danger("[src] shuts down due to lack of power!"), \ "If this message is ever seen, something is wrong.", span_hear("You hear heavy droning fade out.")) - active = FALSE + deactivate() log_game("[src] deactivated due to lack of power at [AREACOORD(src)]") - for(var/d in GLOB.cardinals) - cleanup_field(d) - update_appearance() else update_appearance() for(var/d in GLOB.cardinals) @@ -463,7 +460,6 @@ balloon_alert(user, "malfunctioning!") else balloon_alert(user, "no access!") - return add_fingerprint(user) @@ -493,13 +489,13 @@ user.visible_message(span_notice("[user] turned \the [src] off."), \ span_notice("You turn off \the [src]."), \ span_hear("You hear heavy droning fade out.")) - active = FALSE + deactivate() user.log_message("deactivated [src].", LOG_GAME) else user.visible_message(span_notice("[user] turned \the [src] on."), \ span_notice("You turn on \the [src]."), \ span_hear("You hear heavy droning.")) - active = ACTIVE_SETUPFIELDS + activate() user.log_message("activated [src].", LOG_GAME) add_fingerprint(user) @@ -513,6 +509,19 @@ balloon_alert(user, "access controller shorted") return TRUE +/// Turn the machine on with side effects +/obj/machinery/power/shieldwallgen/proc/activate() + active = ACTIVE_SETUPFIELDS + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) + +/// Turn the machine off with side effects +/obj/machinery/power/shieldwallgen/proc/deactivate() + active = FALSE + for(var/d in GLOB.cardinals) + cleanup_field(d) + update_appearance() + RemoveElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) + //////////////Containment Field START /obj/machinery/shieldwall name = "shield wall" @@ -538,6 +547,7 @@ L.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) L.gib(DROP_ALL_REMAINS) RegisterSignal(src, COMSIG_ATOM_SINGULARITY_TRY_MOVE, PROC_REF(block_singularity)) + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) /obj/machinery/shieldwall/Destroy() gen_primary = null diff --git a/code/game/machinery/sleepers.dm b/code/game/machinery/sleepers.dm index 68b4026b7444a..33e255badb244 100644 --- a/code/game/machinery/sleepers.dm +++ b/code/game/machinery/sleepers.dm @@ -147,7 +147,7 @@ return FALSE /obj/machinery/sleeper/default_pry_open(obj/item/I) //wew - . = !(state_open || panel_open || (obj_flags & NO_DECONSTRUCTION)) && I.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open) && I.tool_behaviour == TOOL_CROWBAR if(.) I.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open [src]."), span_notice("You pry open [src].")) @@ -164,14 +164,12 @@ ui = new(user, src, "Sleeper", name) ui.open() -/obj/machinery/sleeper/AltClick(mob/user) - . = ..() - if(!user.can_perform_action(src, ALLOW_SILICON_REACH)) - return +/obj/machinery/sleeper/click_alt(mob/user) if(state_open) close_machine() else open_machine() + return CLICK_ACTION_SUCCESS /obj/machinery/sleeper/examine(mob/user) . = ..() diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm index 842f01ae7542b..bb93b7d00f5b6 100644 --- a/code/game/machinery/slotmachine.dm +++ b/code/game/machinery/slotmachine.dm @@ -68,10 +68,9 @@ coinvalues["[cointype]"] = C.get_item_credit_value() qdel(C) //Sigh -/obj/machinery/computer/slot_machine/Destroy() +/obj/machinery/computer/slot_machine/on_deconstruction(disassembled) if(balance) give_payout(balance) - return ..() /obj/machinery/computer/slot_machine/process(seconds_per_tick) . = ..() //Sanity checks. @@ -95,50 +94,56 @@ return ..() -/obj/machinery/computer/slot_machine/item_interaction(mob/living/user, obj/item/inserted, list/modifiers, is_right_clicking) +/obj/machinery/computer/slot_machine/item_interaction(mob/living/user, obj/item/inserted, list/modifiers) if(istype(inserted, /obj/item/coin)) var/obj/item/coin/inserted_coin = inserted if(paymode == COIN) if(prob(2)) if(!user.transferItemToLoc(inserted_coin, drop_location(), silent = FALSE)) - return + return ITEM_INTERACT_BLOCKING inserted_coin.throw_at(user, 3, 10) if(prob(10)) balance = max(balance - SPIN_PRICE, 0) to_chat(user, span_warning("[src] spits your coin back out!")) - + return ITEM_INTERACT_BLOCKING else if(!user.temporarilyRemoveItemFromInventory(inserted_coin)) - return + return ITEM_INTERACT_BLOCKING balloon_alert(user, "coin insterted") balance += inserted_coin.value qdel(inserted_coin) + return ITEM_INTERACT_SUCCESS else balloon_alert(user, "holochips only!") + return ITEM_INTERACT_BLOCKING - else if(istype(inserted, /obj/item/holochip)) + if(istype(inserted, /obj/item/holochip)) if(paymode == HOLOCHIP) var/obj/item/holochip/inserted_chip = inserted if(!user.temporarilyRemoveItemFromInventory(inserted_chip)) - return + return ITEM_INTERACT_BLOCKING balloon_alert(user, "[inserted_chip.credits] credit[inserted_chip.credits == 1 ? "" : "s"] inserted") balance += inserted_chip.credits qdel(inserted_chip) + return ITEM_INTERACT_SUCCESS else balloon_alert(user, "coins only!") + return ITEM_INTERACT_BLOCKING - else if(inserted.tool_behaviour == TOOL_MULTITOOL) - if(balance > 0) - visible_message("[src] says, 'ERROR! Please empty the machine balance before altering paymode'") //Prevents converting coins into holocredits and vice versa - else - if(paymode == HOLOCHIP) - paymode = COIN - balloon_alert(user, "now using coins") - else - paymode = HOLOCHIP - balloon_alert(user, "now using holochips") + return NONE + +/obj/machinery/computer/slot_machine/multitool_act(mob/living/user, obj/item/tool) + if(balance > 0) + visible_message("[src] says, 'ERROR! Please empty the machine balance before altering paymode'") //Prevents converting coins into holocredits and vice versa + return ITEM_INTERACT_BLOCKING + + if(paymode == HOLOCHIP) + paymode = COIN + balloon_alert(user, "now using coins") else - return ..() + paymode = HOLOCHIP + balloon_alert(user, "now using holochips") + return ITEM_INTERACT_SUCCESS /obj/machinery/computer/slot_machine/emag_act(mob/user, obj/item/card/emag/emag_card) if(obj_flags & EMAGGED) diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index 58ef3d8bbefb0..0ddebbf3ee30f 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -16,6 +16,7 @@ max_integrity = 250 armor_type = /datum/armor/machinery_space_heater circuit = /obj/item/circuitboard/machine/space_heater + interaction_flags_click = ALLOW_SILICON_REACH //We don't use area power, we always use the cell use_power = NO_POWER_USE ///The cell we spawn with @@ -308,6 +309,7 @@ panel_open = TRUE //This is always open - since we've injected wires in the panel //We inherit the cell from the heater prior cell = null + interaction_flags_click = FORBID_TELEKINESIS_REACH ///The beaker within the heater var/obj/item/reagent_containers/beaker = null ///How powerful the heating is, upgrades with parts. (ala chem_heater.dm's method, basically the same level of heating, but this is restricted) @@ -440,11 +442,9 @@ update_appearance() return TRUE -/obj/machinery/space_heater/improvised_chem_heater/AltClick(mob/living/user) - . = ..() - if(!can_interact(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return +/obj/machinery/space_heater/improvised_chem_heater/click_alt(mob/living/user) replace_beaker(user) + return CLICK_ACTION_SUCCESS /obj/machinery/space_heater/improvised_chem_heater/update_icon_state() . = ..() diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm index 177cd54004075..9ef3d8e3a99a9 100644 --- a/code/game/machinery/stasis.dm +++ b/code/game/machinery/stasis.dm @@ -12,6 +12,7 @@ circuit = /obj/item/circuitboard/machine/stasis fair_market_price = 10 payment_department = ACCOUNT_MED + interaction_flags_click = ALLOW_SILICON_REACH var/stasis_enabled = TRUE var/last_stasis_sound = FALSE var/stasis_can_toggle = 0 @@ -22,9 +23,6 @@ . = ..() AddElement(/datum/element/elevation, pixel_shift = 6) -/obj/machinery/stasis/Destroy() - . = ..() - /obj/machinery/stasis/examine(mob/user) . = ..() . += span_notice("Alt-click to [stasis_enabled ? "turn off" : "turn on"] the machine.") @@ -39,19 +37,18 @@ playsound(src, 'sound/machines/synth_no.ogg', 50, TRUE, frequency = sound_freq) last_stasis_sound = _running -/obj/machinery/stasis/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return - if(world.time >= stasis_can_toggle && user.can_perform_action(src, ALLOW_SILICON_REACH)) - stasis_enabled = !stasis_enabled - stasis_can_toggle = world.time + STASIS_TOGGLE_COOLDOWN - playsound(src, 'sound/machines/click.ogg', 60, TRUE) - user.visible_message(span_notice("\The [src] [stasis_enabled ? "powers on" : "shuts down"]."), \ - span_notice("You [stasis_enabled ? "power on" : "shut down"] \the [src]."), \ - span_hear("You hear a nearby machine [stasis_enabled ? "power on" : "shut down"].")) - play_power_sound() - update_appearance() +/obj/machinery/stasis/click_alt(mob/user) + if(world.time < stasis_can_toggle) + return CLICK_ACTION_BLOCKING + stasis_enabled = !stasis_enabled + stasis_can_toggle = world.time + STASIS_TOGGLE_COOLDOWN + playsound(src, 'sound/machines/click.ogg', 60, TRUE) + user.visible_message(span_notice("\The [src] [stasis_enabled ? "powers on" : "shuts down"]."), \ + span_notice("You [stasis_enabled ? "power on" : "shut down"] \the [src]."), \ + span_hear("You hear a nearby machine [stasis_enabled ? "power on" : "shut down"].")) + play_power_sound() + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/stasis/Exited(atom/movable/gone, direction) if(gone == occupant) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 1b7b041a7a96a..a5e301c21680b 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -1,3 +1,4 @@ + // SUIT STORAGE UNIT ///////////////// /obj/machinery/suit_storage_unit name = "suit storage unit" @@ -55,9 +56,9 @@ /// How long it takes to break out of the SSU. var/breakout_time = 30 SECONDS /// Power contributed by this machine to charge the mod suits cell without any capacitors - var/base_charge_rate = 200 KILO WATTS + var/base_charge_rate = 0.2 * STANDARD_CELL_RATE /// Final charge rate which is base_charge_rate + contribution by capacitors - var/final_charge_rate = 250 KILO WATTS + var/final_charge_rate = 0.25 * STANDARD_CELL_RATE /// is the card reader installed in this machine var/card_reader_installed = FALSE /// physical reference of the players id card to check for PERSONAL access level @@ -287,7 +288,7 @@ . = ..() for(var/datum/stock_part/capacitor/capacitor in component_parts) - final_charge_rate = base_charge_rate + (capacitor.tier * 50 KILO WATTS) + final_charge_rate = base_charge_rate + (capacitor.tier * 0.05 * STANDARD_CELL_RATE) set_access() @@ -468,7 +469,7 @@ else target.visible_message(span_warning("[user] starts shoving [target] into [src]!"), span_userdanger("[user] starts shoving you into [src]!")) - if(do_after(user, 30, target)) + if(do_after(user, 3 SECONDS, target)) if(occupant || helmet || suit || storage) return if(target == user) @@ -501,7 +502,7 @@ if(iscarbon(mob_occupant) && mob_occupant.stat < UNCONSCIOUS) //Awake, organic and screaming mob_occupant.emote("scream") - addtimer(CALLBACK(src, PROC_REF(cook)), 50) + addtimer(CALLBACK(src, PROC_REF(cook)), 5 SECONDS) else uv_cycles = initial(uv_cycles) uv = FALSE @@ -567,7 +568,7 @@ var/charge_per_item = (final_charge_rate * seconds_per_tick) / cell_count for(var/obj/item/stock_parts/cell/cell as anything in cells_to_charge) - charge_cell(charge_per_item, cell) + charge_cell(charge_per_item, cell, grid_only = TRUE) /obj/machinery/suit_storage_unit/proc/shock(mob/user, prb) if(!prob(prb)) @@ -608,7 +609,7 @@ if(locked) visible_message(span_notice("You see [user] kicking against the doors of [src]!"), \ span_notice("You start kicking against the doors...")) - addtimer(CALLBACK(src, PROC_REF(resist_open), user), 300) + addtimer(CALLBACK(src, PROC_REF(resist_open), user), 30 SECONDS) else open_machine() dump_inventory_contents() @@ -794,21 +795,21 @@ causes the SSU to break due to state_open being set to TRUE at the end, and the panel becoming inaccessible. */ /obj/machinery/suit_storage_unit/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) - if(!(obj_flags & NO_DECONSTRUCTION) && screwdriver.tool_behaviour == TOOL_SCREWDRIVER && (uv || locked)) + if(screwdriver.tool_behaviour == TOOL_SCREWDRIVER && (uv || locked)) to_chat(user, span_warning("You cant open the panel while its [locked ? "locked" : "decontaminating"]")) return TRUE return ..() /obj/machinery/suit_storage_unit/default_pry_open(obj/item/crowbar)//needs to check if the storage is locked. - . = !(state_open || panel_open || is_operational || locked || (obj_flags & NO_DECONSTRUCTION)) && crowbar.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open || is_operational || locked) && crowbar.tool_behaviour == TOOL_CROWBAR if(.) crowbar.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open \the [src]."), span_notice("You pry open \the [src].")) open_machine() /obj/machinery/suit_storage_unit/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) - . = (!locked && panel_open && !(obj_flags & NO_DECONSTRUCTION) && crowbar.tool_behaviour == TOOL_CROWBAR) + . = (!locked && panel_open && crowbar.tool_behaviour == TOOL_CROWBAR) if(.) return ..() diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index ebe24b449748b..693668e9e8900 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -484,7 +484,7 @@ chem_splash(get_turf(src), reagents, spread_range, list(reactants), temp_boost) // Detonate it again in one second, until it's out of juice. - addtimer(CALLBACK(src, PROC_REF(detonate)), 10) + addtimer(CALLBACK(src, PROC_REF(detonate)), 1 SECONDS) // If it's not a time release bomb, do normal explosion diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm index ab2a3f8cefc86..1998654df00b1 100644 --- a/code/game/machinery/telecomms/computers/message.dm +++ b/code/game/machinery/telecomms/computers/message.dm @@ -74,7 +74,8 @@ GLOB.telecomms_list += src return INITIALIZE_HINT_LATELOAD -/obj/machinery/computer/message_monitor/LateInitialize() +/obj/machinery/computer/message_monitor/post_machine_initialize() + . = ..() //Is the server isn't linked to a server, and there's a server available, default it to the first one in the list. if(!linkedServer) for(var/obj/machinery/telecomms/message_server/message_server in GLOB.telecomms_list) @@ -280,12 +281,11 @@ name = "monitor decryption key" /obj/item/paper/monitorkey/Initialize(mapload, obj/machinery/telecomms/message_server/server) - ..() + . = ..() if (server) print(server) return INITIALIZE_HINT_NORMAL - else - return INITIALIZE_HINT_LATELOAD + return INITIALIZE_HINT_LATELOAD /** * Handles printing the monitor key for a given server onto this piece of paper. diff --git a/code/game/machinery/telecomms/computers/telemonitor.dm b/code/game/machinery/telecomms/computers/telemonitor.dm index 6cf18323105a5..abc2b7dbdbff4 100644 --- a/code/game/machinery/telecomms/computers/telemonitor.dm +++ b/code/game/machinery/telecomms/computers/telemonitor.dm @@ -5,7 +5,6 @@ /obj/machinery/computer/telecomms/monitor name = "telecommunications monitoring console" desc = "Monitors the details of the telecommunications network it's synced with." - circuit = /obj/item/circuitboard/computer/comm_monitor icon_screen = "comm_monitor" diff --git a/code/game/machinery/telecomms/machines/allinone.dm b/code/game/machinery/telecomms/machines/allinone.dm index f8a6b66c049ce..9b32a4ac19246 100644 --- a/code/game/machinery/telecomms/machines/allinone.dm +++ b/code/game/machinery/telecomms/machines/allinone.dm @@ -20,7 +20,12 @@ /obj/machinery/telecomms/allinone/indestructible resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/machinery/telecomms/allinone/indestructible/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/telecomms/allinone/indestructible/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE /obj/machinery/telecomms/allinone/receive_signal(datum/signal/subspace/signal) if(!istype(signal) || signal.transmission_method != TRANSMISSION_SUBSPACE) // receives on subspace only diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index b8d0414ad282b..ee71ca0233db2 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -105,9 +105,8 @@ GLOBAL_LIST_EMPTY(telecomms_list) if(mapload && autolinkers.len) return INITIALIZE_HINT_LATELOAD -/obj/machinery/telecomms/LateInitialize() - ..() - +/obj/machinery/telecomms/post_machine_initialize() + . = ..() for(var/obj/machinery/telecomms/telecomms_machine in GLOB.telecomms_list) if (long_range_link || IN_GIVEN_RANGE(src, telecomms_machine, 20)) add_automatic_link(telecomms_machine) diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 972497da9b316..d2b0629a2b933 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -50,6 +50,7 @@ to_chat(AM, span_warning("You can't use this here!")) return if(is_ready()) + playsound(loc, "sound/effects/portal_travel.ogg", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) teleport(AM) /obj/machinery/teleport/hub/attackby(obj/item/W, mob/user, params) @@ -73,22 +74,24 @@ com.target_ref = null visible_message(span_alert("Cannot authenticate locked on coordinates. Please reinstate coordinate matrix.")) return - if (ismovable(M)) - if(do_teleport(M, target, channel = TELEPORT_CHANNEL_BLUESPACE)) - use_energy(active_power_usage) - if(!calibrated && prob(30 - ((accuracy) * 10))) //oh dear a problem - if(ishuman(M))//don't remove people from the round randomly you jerks - var/mob/living/carbon/human/human = M - if(!(human.mob_biotypes & (MOB_ROBOTIC|MOB_MINERAL|MOB_UNDEAD|MOB_SPIRIT))) - var/datum/species/species_to_transform = /datum/species/fly - if(check_holidays(MOTH_WEEK)) - species_to_transform = /datum/species/moth - if(human.dna && human.dna.species.id != initial(species_to_transform.id)) - to_chat(M, span_hear("You hear a buzzing in your ears.")) - human.set_species(species_to_transform) - human.log_message("was turned into a [initial(species_to_transform.name)] through [src].", LOG_GAME) - calibrated = FALSE - return + if(!ismovable(M)) + return + var/turf/start_turf = get_turf(M) + if(!do_teleport(M, target, channel = TELEPORT_CHANNEL_BLUESPACE)) + return + use_energy(active_power_usage) + new /obj/effect/temp_visual/portal_animation(start_turf, src, M) + if(!calibrated && ishuman(M) && prob(30 - ((accuracy) * 10))) //oh dear a problem + var/mob/living/carbon/human/human = M + if(!(human.mob_biotypes & (MOB_ROBOTIC|MOB_MINERAL|MOB_UNDEAD|MOB_SPIRIT))) + var/datum/species/species_to_transform = /datum/species/fly + if(check_holidays(MOTH_WEEK)) + species_to_transform = /datum/species/moth + if(human.dna && human.dna.species.id != initial(species_to_transform.id)) + to_chat(M, span_hear("You hear a buzzing in your ears.")) + human.set_species(species_to_transform) + human.log_message("was turned into a [initial(species_to_transform.name)] through [src].", LOG_GAME) + calibrated = FALSE /obj/machinery/teleport/hub/update_icon_state() icon_state = "[base_icon_state][panel_open ? "-o" : (is_ready() ? 1 : 0)]" diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm index 9c87ca0cfc746..ecb7ef941aad8 100644 --- a/code/game/machinery/transformer.dm +++ b/code/game/machinery/transformer.dm @@ -20,7 +20,7 @@ /// How long until the next mob can be processed var/cooldown_timer /// The created cyborg's cell chage - var/robot_cell_charge = 5000 + var/robot_cell_charge = STANDARD_CELL_CHARGE * 5 /// The visual countdown effect var/obj/effect/countdown/transformer/countdown /// Who the master AI is that created this factory diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index e4fc4592b7930..e2ad3af956a2b 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -28,18 +28,6 @@ if(user_unbuckle_mob(buckled_mobs[1],user)) return TRUE -/atom/movable/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - if(!can_buckle || !istype(tool, /obj/item/riding_offhand) || !user.Adjacent(src)) - return ..() - - var/obj/item/riding_offhand/riding_item = tool - var/mob/living/carried_mob = riding_item.rider - if(carried_mob == user) //Piggyback user. - return ITEM_INTERACT_BLOCKING - user.unbuckle_mob(carried_mob) - carried_mob.forceMove(get_turf(src)) - return mouse_buckle_handling(carried_mob, user) ? ITEM_INTERACT_SUCCESS: ITEM_INTERACT_BLOCKING - //literally just the above extension of attack_hand(), but for silicons instead (with an adjacency check, since attack_robot() being called doesn't mean that you're adjacent to something) /atom/movable/attack_robot(mob/living/user) . = ..() diff --git a/code/game/objects/effects/anomalies/_anomalies.dm b/code/game/objects/effects/anomalies/_anomalies.dm index 530da56282788..a3f0b79044b41 100644 --- a/code/game/objects/effects/anomalies/_anomalies.dm +++ b/code/game/objects/effects/anomalies/_anomalies.dm @@ -21,8 +21,8 @@ var/drops_core = TRUE ///Do we keep on living forever? var/immortal = FALSE - ///Do we stay in one place? - var/immobile = FALSE + ///Chance per second that we will move + var/move_chance = ANOMALY_MOVECHANCE /obj/effect/anomaly/Initialize(mapload, new_lifespan, drops_core = TRUE) . = ..() @@ -76,8 +76,12 @@ return ..() /obj/effect/anomaly/proc/anomalyEffect(seconds_per_tick) - if(!immobile && SPT_PROB(ANOMALY_MOVECHANCE, seconds_per_tick)) - step(src,pick(GLOB.alldirs)) + if(SPT_PROB(move_chance, seconds_per_tick)) + move_anomaly() + +/// Move in a direction +/obj/effect/anomaly/proc/move_anomaly() + step(src, pick(GLOB.alldirs)) /obj/effect/anomaly/proc/detonate() return @@ -116,4 +120,5 @@ if(!has_core) drops_core = FALSE QDEL_NULL(aSignal) - immobile = anchor + if (anchor) + move_chance = 0 diff --git a/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm b/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm index b4ee3713a25da..f1034c5541f73 100644 --- a/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm +++ b/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm @@ -4,6 +4,10 @@ icon_state = "bioscrambler" aSignal = /obj/item/assembly/signaler/anomaly/bioscrambler immortal = TRUE + pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE | PASSCLOSEDTURF | PASSMACHINE | PASSSTRUCTURE | PASSDOORS + layer = ABOVE_MOB_LAYER + /// Who are we moving towards? + var/datum/weakref/pursuit_target /// Cooldown for every anomaly pulse COOLDOWN_DECLARE(pulse_cooldown) /// How many seconds between each anomaly pulses @@ -11,11 +15,65 @@ /// Range of the anomaly pulse var/range = 5 +/obj/effect/anomaly/bioscrambler/Initialize(mapload, new_lifespan, drops_core) + . = ..() + pursuit_target = WEAKREF(find_nearest_target()) + /obj/effect/anomaly/bioscrambler/anomalyEffect(seconds_per_tick) . = ..() if(!COOLDOWN_FINISHED(src, pulse_cooldown)) return COOLDOWN_START(src, pulse_cooldown, pulse_delay) - for(var/mob/living/carbon/nearby in range(range, src)) + for(var/mob/living/carbon/nearby in hearers(range, src)) nearby.bioscramble(name) + +/obj/effect/anomaly/bioscrambler/move_anomaly() + update_target() + if (isnull(pursuit_target)) + return ..() + var/turf/step_turf = get_step(src, get_dir(src, pursuit_target.resolve())) + if (!HAS_TRAIT(step_turf, TRAIT_CONTAINMENT_FIELD)) + Move(step_turf) + +/// Select a new target if we need one +/obj/effect/anomaly/bioscrambler/proc/update_target() + var/mob/living/current_target = pursuit_target?.resolve() + if (QDELETED(current_target)) + pursuit_target = null + if (!isnull(pursuit_target) && prob(80)) + return + var/mob/living/new_target = find_nearest_target() + if (isnull(new_target)) + pursuit_target = null + return + if (new_target == current_target) + return + current_target = new_target + pursuit_target = WEAKREF(new_target) + new_target.ominous_nosebleed() + +/// Returns the closest conscious carbon on our z level or null if there somehow isn't one +/obj/effect/anomaly/bioscrambler/proc/find_nearest_target() + var/closest_distance = INFINITY + var/mob/living/carbon/closest_target = null + for(var/mob/living/carbon/target in GLOB.player_list) + if (target.z != z) + continue + if (target.status_flags & GODMODE) + continue + if (target.stat >= UNCONSCIOUS) + continue // Don't just haunt a corpse + var/distance_from_target = get_dist(src, target) + if(distance_from_target >= closest_distance) + continue + closest_distance = distance_from_target + closest_target = target + + return closest_target + +/// A bioscrambler anomaly subtype which does not pursue people, for purposes of a space ruin +/obj/effect/anomaly/bioscrambler/docile + +/obj/effect/anomaly/bioscrambler/docile/update_target() + return diff --git a/code/game/objects/effects/anomalies/anomalies_dimensional.dm b/code/game/objects/effects/anomalies/anomalies_dimensional.dm index 16dd5bafcfaea..026c5974d5f35 100644 --- a/code/game/objects/effects/anomalies/anomalies_dimensional.dm +++ b/code/game/objects/effects/anomalies/anomalies_dimensional.dm @@ -4,7 +4,7 @@ icon_state = "dimensional" aSignal = /obj/item/assembly/signaler/anomaly/dimensional immortal = TRUE - immobile = TRUE + move_chance = 0 /// Range of effect, if left alone anomaly will convert a 2(range)+1 squared area. var/range = 3 /// List of turfs this anomaly will try to transform before relocating diff --git a/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm b/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm index c085f023c0bc8..6832b07d12568 100644 --- a/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm +++ b/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm @@ -362,32 +362,42 @@ /obj/structure/chair = list(/obj/structure/chair/comfy = 1), /obj/machinery/door/airlock = list(/obj/machinery/door/airlock/wood = 1, /obj/machinery/door/airlock/wood/glass = 1), ) - ///cooldown for changing carpets, It's kinda dull to always use the same one, but we also can't make it too random. + /// Cooldown for changing carpets, It's kinda dull to always use the same one, but we also can't make it too random. COOLDOWN_DECLARE(carpet_switch_cd) + /// List of carpets we can pick from, set up in New + var/list/valid_carpets + /// List of tables we can pick from, set up in New + var/list/valid_tables -#define FANCY_CARPETS list(\ - /turf/open/floor/eighties, \ - /turf/open/floor/eighties/red, \ - /turf/open/floor/carpet/lone/star, \ - /turf/open/floor/carpet/black, \ - /turf/open/floor/carpet/blue, \ - /turf/open/floor/carpet/cyan, \ - /turf/open/floor/carpet/green, \ - /turf/open/floor/carpet/orange, \ - /turf/open/floor/carpet/purple, \ - /turf/open/floor/carpet/red, \ - /turf/open/floor/carpet/royalblack, \ - /turf/open/floor/carpet/royalblue,) +/datum/dimension_theme/fancy/New() + . = ..() + valid_carpets = list( + /turf/open/floor/carpet/black, + /turf/open/floor/carpet/blue, + /turf/open/floor/carpet/cyan, + /turf/open/floor/carpet/green, + /turf/open/floor/carpet/lone/star, + /turf/open/floor/carpet/orange, + /turf/open/floor/carpet/purple, + /turf/open/floor/carpet/red, + /turf/open/floor/carpet/royalblack, + /turf/open/floor/carpet/royalblue, + /turf/open/floor/eighties, + /turf/open/floor/eighties/red, + ) + valid_tables = subtypesof(/obj/structure/table/wood/fancy) + randomize_theme() + +/datum/dimension_theme/fancy/proc/randomize_theme() + replace_floors = list(pick(valid_carpets) = 1) + replace_objs[/obj/structure/table/wood] = list(pick(valid_tables) = 1) /datum/dimension_theme/fancy/apply_theme(turf/affected_turf, skip_sound = FALSE, show_effect = FALSE) if(COOLDOWN_FINISHED(src, carpet_switch_cd)) - replace_floors = list(pick(FANCY_CARPETS) = 1) - replace_objs[/obj/structure/table/wood] = list(pick(subtypesof(/obj/structure/table/wood/fancy)) = 1) + randomize_theme() COOLDOWN_START(src, carpet_switch_cd, 90 SECONDS) return ..() -#undef FANCY_CARPETS - /datum/dimension_theme/disco name = "Disco" icon = 'icons/obj/lighting.dmi' diff --git a/code/game/objects/effects/anomalies/anomalies_ectoplasm.dm b/code/game/objects/effects/anomalies/anomalies_ectoplasm.dm index 412cca0495299..51a033f515f9c 100644 --- a/code/game/objects/effects/anomalies/anomalies_ectoplasm.dm +++ b/code/game/objects/effects/anomalies/anomalies_ectoplasm.dm @@ -4,7 +4,7 @@ icon_state = "ectoplasm" aSignal = /obj/item/assembly/signaler/anomaly/ectoplasm lifespan = ANOMALY_COUNTDOWN_TIMER + 2 SECONDS //This one takes slightly longer, because it can run away. - immobile = TRUE //prevents it from moving around so ghosts can actually move it with decent accuracy + move_chance = 0 //prevents it from moving around so ghosts can actually move it with decent accuracy ///Blocks the anomaly from updating ghost count. Used in case an admin wants to rig the anomaly to be a certain size or intensity. var/override_ghosts = FALSE diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm index 4f4b2543792c0..bf826e207db37 100644 --- a/code/game/objects/effects/decals/cleanable/aliens.dm +++ b/code/game/objects/effects/decals/cleanable/aliens.dm @@ -47,7 +47,7 @@ break return - var/datum/move_loop/loop = SSmove_manager.move(src, direction, delay = delay, timeout = range * delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move(src, direction, delay = delay, timeout = range * delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(spread_movement_effects)) /obj/effect/decal/cleanable/xenoblood/xgibs/proc/spread_movement_effects(datum/move_loop/has_target/source) diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 4a275199f3f55..064f3d0f5d0b0 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -163,7 +163,7 @@ break return - var/datum/move_loop/loop = SSmove_manager.move_to(src, get_step(src, direction), delay = delay, timeout = range * delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move_to(src, get_step(src, direction), delay = delay, timeout = range * delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(spread_movement_effects)) /obj/effect/decal/cleanable/blood/gibs/proc/spread_movement_effects(datum/move_loop/has_target/source) @@ -376,7 +376,7 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) /// Set the splatter up to fly through the air until it rounds out of steam or hits something /obj/effect/decal/cleanable/blood/hitsplatter/proc/fly_towards(turf/target_turf, range) var/delay = 2 - var/datum/move_loop/loop = SSmove_manager.move_towards(src, target_turf, delay, timeout = delay * range, priority = MOVEMENT_ABOVE_SPACE_PRIORITY, flags = MOVEMENT_LOOP_START_FAST) + var/datum/move_loop/loop = GLOB.move_manager.move_towards(src, target_turf, delay, timeout = delay * range, priority = MOVEMENT_ABOVE_SPACE_PRIORITY, flags = MOVEMENT_LOOP_START_FAST) RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move)) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(post_move)) RegisterSignal(loop, COMSIG_QDELETING, PROC_REF(loop_done)) diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index f21bfc4788426..d977605b2436f 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -219,6 +219,14 @@ . = ..() . += emissive_appearance(icon, icon_state, src, alpha = src.alpha) +/// Nebula vomit with extra guests +/obj/effect/decal/cleanable/vomit/nebula/worms + +/obj/effect/decal/cleanable/vomit/nebula/worms/Initialize(mapload, list/datum/disease/diseases) + . = ..() + for (var/i in 1 to rand(2, 3)) + new /mob/living/basic/hivelord_brood(loc) + /obj/effect/decal/cleanable/vomit/old name = "crusty dried vomit" desc = "You try not to look at the chunks, and fail." @@ -412,9 +420,7 @@ . += 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) - fire_ants.reagents.clear_reagents() - reagents.trans_to(fire_ants, fire_ants.reagents.maximum_volume) + new /obj/effect/decal/cleanable/ants/fire(loc) qdel(src) /obj/effect/decal/cleanable/ants/fire diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm index d248b5e691d87..808a68d6f5eb0 100644 --- a/code/game/objects/effects/decals/cleanable/robots.dm +++ b/code/game/objects/effects/decals/cleanable/robots.dm @@ -32,7 +32,7 @@ break return - var/datum/move_loop/loop = SSmove_manager.move(src, direction, delay = delay, timeout = range * delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move(src, direction, delay = delay, timeout = range * delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(spread_movement_effects)) /obj/effect/decal/cleanable/robot_debris/proc/spread_movement_effects(datum/move_loop/has_target/source) diff --git a/code/game/objects/effects/effect_system/effect_system.dm b/code/game/objects/effects/effect_system/effect_system.dm index 9d2d13f9925f5..4fdd4ac598ee0 100644 --- a/code/game/objects/effects/effect_system/effect_system.dm +++ b/code/game/objects/effects/effect_system/effect_system.dm @@ -67,7 +67,7 @@ would spawn and follow the beaker, even if it is carried or thrown. var/step_amt = pick(1,2,3) var/step_delay = 5 - var/datum/move_loop/loop = SSmove_manager.move(effect, direction, step_delay, timeout = step_delay * step_amt, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move(effect, direction, step_delay, timeout = step_delay * step_amt, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(loop, COMSIG_QDELETING, PROC_REF(decrement_total_effect)) /datum/effect_system/proc/decrement_total_effect(datum/source) diff --git a/code/game/objects/effects/effect_system/effects_explosion.dm b/code/game/objects/effects/effect_system/effects_explosion.dm index 231feb2ec3dfc..a8a3431ef9c68 100644 --- a/code/game/objects/effects/effect_system/effects_explosion.dm +++ b/code/game/objects/effects/effect_system/effects_explosion.dm @@ -11,7 +11,7 @@ /obj/effect/particle_effect/expl_particles/LateInitialize() var/step_amt = pick(25;1,50;2,100;3,200;4) - var/datum/move_loop/loop = SSmove_manager.move(src, pick(GLOB.alldirs), 1, timeout = step_amt, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move(src, pick(GLOB.alldirs), 1, timeout = step_amt, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(loop, COMSIG_QDELETING, PROC_REF(end_particle)) /obj/effect/particle_effect/expl_particles/proc/end_particle(datum/source) @@ -63,4 +63,4 @@ /datum/effect_system/explosion/smoke/start() ..() - addtimer(CALLBACK(src, PROC_REF(create_smoke)), 5) + addtimer(CALLBACK(src, PROC_REF(create_smoke)), 0.5 SECONDS) diff --git a/code/game/objects/effects/effect_system/effects_water.dm b/code/game/objects/effects/effect_system/effects_water.dm index 2edca60a3202f..f94e5d0e31c3d 100644 --- a/code/game/objects/effects/effect_system/effects_water.dm +++ b/code/game/objects/effects/effect_system/effects_water.dm @@ -38,7 +38,7 @@ /// Starts the effect moving at a target with a delay in deciseconds, and a lifetime in moves /// Returns the created loop /obj/effect/particle_effect/water/extinguisher/proc/move_at(atom/target, delay, lifetime) - var/datum/move_loop/loop = SSmove_manager.move_towards_legacy(src, target, delay, timeout = delay * lifetime, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move_towards_legacy(src, target, delay, timeout = delay * lifetime, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(post_forcemove)) RegisterSignal(loop, COMSIG_QDELETING, PROC_REF(movement_stopped)) return loop @@ -63,7 +63,7 @@ // Stomach acid doesn't use legacy because it's not "targeted", and we instead want the circular sorta look /obj/effect/particle_effect/water/extinguisher/stomach_acid/move_at(atom/target, delay, lifetime) - var/datum/move_loop/loop = SSmove_manager.move_towards(src, target, delay, timeout = delay * lifetime, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move_towards(src, target, delay, timeout = delay * lifetime, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(post_forcemove)) RegisterSignal(loop, COMSIG_QDELETING, PROC_REF(movement_stopped)) return loop diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm index 908180074575c..6d968574c686c 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -430,6 +430,7 @@ return location.ClearWet() + location.temperature = T20C if(location.air) var/datum/gas_mixture/air = location.air air.temperature = T20C diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm index a0bf078c3dc4f..e651c8a3e2402 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm @@ -431,7 +431,7 @@ contained_reagents += "[reagent.volume]u [reagent]" var/where = "[AREACOORD(location)]" - var/contained = length(contained_reagents) ? "[contained_reagents.Join(", ", " \[", "\]")] @ [chemholder.chem_temp]K" : null + var/contained = length(contained_reagents) ? "\[[contained_reagents.Join(", ")]\] @ [chemholder.chem_temp]K" : null var/area/fluid_area = get_area(location) if(carry.my_atom?.fingerprintslast) //Some reagents don't have a my_atom in some cases var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 5c4964cca058a..64c0afe188a8a 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -189,9 +189,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark) name = "Chief Medical Officer" icon_state = "Chief Medical Officer" -/obj/effect/landmark/start/virologist - name = "Virologist" - icon_state = "Virologist" /obj/effect/landmark/start/psychologist name = "Psychologist" @@ -287,6 +284,16 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark) GLOB.nukeop_leader_start += loc return INITIALIZE_HINT_QDEL +/obj/effect/landmark/start/nukeop_overwatch + name = "nukeop overwatch" + icon = 'icons/effects/landmarks_static.dmi' + icon_state = "snukeop_leader_spawn" + +/obj/effect/landmark/start/nukeop_overwatch/Initialize(mapload) + ..() + GLOB.nukeop_overwatch_start += loc + return INITIALIZE_HINT_QDEL + // Must be immediate because players will // join before SSatom initializes everything. INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player) @@ -491,7 +498,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player) return ..() /obj/effect/landmark/start/hangover/LateInitialize() - . = ..() if(HAS_TRAIT(SSstation, STATION_TRAIT_BIRTHDAY)) party_debris += new /obj/effect/decal/cleanable/confetti(get_turf(src)) //a birthday celebration can also be a hangover var/list/bonus_confetti = GLOB.alldirs @@ -572,7 +578,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player) return INITIALIZE_HINT_LATELOAD /obj/effect/landmark/navigate_destination/LateInitialize() - . = ..() if(!location) var/obj/machinery/door/airlock/A = locate(/obj/machinery/door/airlock) in loc location = A ? format_text(A.name) : get_area_name(src, format_text = TRUE) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index cd8a859f86fb4..f080035d54c2e 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -76,7 +76,7 @@ return TRUE -/obj/effect/mine/proc/on_entered(datum/source, atom/movable/arrived) +/obj/effect/mine/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc) SIGNAL_HANDLER if(!can_trigger(arrived)) @@ -85,15 +85,35 @@ if(foot_on_mine?.resolve()) return - foot_on_mine = WEAKREF(arrived) + var/gonna_blow + if(arrived.flags_1 & ON_BORDER_1) + if(arrived.dir == get_dir(old_loc, src)) //see if a partial tile atom has passed the mine + gonna_blow = TRUE + else + return //it didn't actually touch the mine, don't blow + visible_message(span_danger("[icon2html(src, viewers(src))] *click*")) playsound(src, 'sound/machines/click.ogg', 60, TRUE) + if(gonna_blow) + RegisterSignal(arrived, COMSIG_MOVABLE_MOVED, PROC_REF(triggermine)) //wait for it to finish the movement before blowing so it takes proper damage + return + + foot_on_mine = WEAKREF(arrived) -/obj/effect/mine/proc/on_exited(datum/source, atom/movable/gone) + +/obj/effect/mine/proc/on_exited(datum/source, atom/movable/gone, direction) SIGNAL_HANDLER if(!can_trigger(gone)) return + + if(!foot_on_mine && gone.flags_1 & ON_BORDER_1) + if(gone.dir == REVERSE_DIR(direction)) //see if a north facing border atom (ie window) travels south (and other directions as needed) + visible_message(span_danger("[icon2html(src, viewers(src))] *click*")) + playsound(src, 'sound/machines/click.ogg', 60, TRUE) + triggermine() //it "passed" over the mine briefly, triggering it in the process + return //either it blew up the mine, or it didn't and we don't have to worry about anything else. + // Check that the guy who's on it is stepping off if(foot_on_mine && !IS_WEAKREF_OF(gone, foot_on_mine)) return @@ -107,6 +127,7 @@ /// When something sets off a mine /obj/effect/mine/proc/triggermine(atom/movable/triggerer) + SIGNAL_HANDLER if(triggered) //too busy detonating to detonate again return if(triggerer) diff --git a/code/game/objects/effects/particle_holder.dm b/code/game/objects/effects/particle_holder.dm index f2cbea06aa730..b5b4fa47108dc 100644 --- a/code/game/objects/effects/particle_holder.dm +++ b/code/game/objects/effects/particle_holder.dm @@ -64,7 +64,6 @@ var/mob/particle_mob = attached.loc particle_mob.vis_contents += src -/// Sets the particles position to the passed coordinate list (X, Y, Z) -/// See [https://www.byond.com/docs/ref/#/{notes}/particles] for position documentation -/obj/effect/abstract/particle_holder/proc/set_particle_position(list/pos) - particles.position = pos +/// Sets the particles position to the passed coordinates +/obj/effect/abstract/particle_holder/proc/set_particle_position(x = 0, y = 0, z = 0) + particles.position = list(x, y, z) diff --git a/code/game/objects/effects/particles/smoke.dm b/code/game/objects/effects/particles/smoke.dm index 4f31ffc086998..27249c65a683e 100644 --- a/code/game/objects/effects/particles/smoke.dm +++ b/code/game/objects/effects/particles/smoke.dm @@ -37,6 +37,31 @@ spawning = 2 velocity = list(0, 0.25, 0) +/particles/smoke/cig + icon_state = list("steam_1" = 2, "steam_2" = 1, "steam_3" = 1) + count = 1 + spawning = 0.05 // used to pace it out roughly in time with breath ticks + position = list(-6, -2, 0) + gravity = list(0, 0.75, 0) + lifespan = 0.75 SECONDS + fade = 0.75 SECONDS + velocity = list(0, 0.2, 0) + scale = 0.5 + grow = 0.01 + friction = 0.5 + color = "#d0d0d09d" + +/particles/smoke/cig/big + icon_state = list("steam_1" = 1, "steam_2" = 2, "steam_3" = 2) + gravity = list(0, 0.5, 0) + velocity = list(0, 0.1, 0) + lifespan = 1 SECONDS + fade = 1 SECONDS + grow = 0.1 + scale = 0.75 + spawning = 1 + friction = 0.75 + /particles/smoke/ash icon_state = list("ash_1" = 2, "ash_2" = 2, "ash_3" = 1, "smoke_1" = 3, "smoke_2" = 2) count = 500 @@ -46,3 +71,16 @@ fadein = 0.7 SECONDS position = generator(GEN_VECTOR, list(-3, 5, 0), list(3, 6.5, 0), NORMAL_RAND) velocity = generator(GEN_VECTOR, list(-0.1, 0.4, 0), list(0.1, 0.5, 0), NORMAL_RAND) + +/particles/fog + icon = 'icons/effects/particles/smoke.dmi' + icon_state = list("chill_1" = 2, "chill_2" = 2, "chill_3" = 1) + +/particles/fog/breath + count = 1 + spawning = 1 + lifespan = 1 SECONDS + fade = 0.5 SECONDS + grow = 0.05 + spin = 2 + color = "#fcffff77" diff --git a/code/game/objects/effects/phased_mob.dm b/code/game/objects/effects/phased_mob.dm index 1456fa350bfab..dcd4e39189c87 100644 --- a/code/game/objects/effects/phased_mob.dm +++ b/code/game/objects/effects/phased_mob.dm @@ -2,7 +2,7 @@ name = "water" anchored = TRUE flags_1 = PREVENT_CONTENTS_EXPLOSION_1 - resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | SHUTTLE_CRUSH_PROOF invisibility = INVISIBILITY_OBSERVER movement_type = FLOATING /// The movable which's jaunting in this dummy diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 8c52a76dbc0de..d3d12b28b5f5d 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -42,7 +42,7 @@ /// Does this portal bypass teleport restrictions? like TRAIT_NO_TELEPORT and NOTELEPORT flags. var/force_teleport = FALSE /// Does this portal create spark effect when teleporting? - var/sparkless = FALSE + var/sparkless = TRUE /// If FALSE, the wibble filter will not be applied to this portal (only a visual effect). var/wibbles = TRUE @@ -69,6 +69,7 @@ /obj/effect/portal/attackby(obj/item/W, mob/user, params) if(user && Adjacent(user)) + playsound(loc, "sound/effects/portal_travel.ogg" , 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) teleport(user) return TRUE @@ -78,6 +79,7 @@ return TRUE /obj/effect/portal/Bumped(atom/movable/bumper) + playsound(loc, "sound/effects/portal_travel.ogg" , 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) teleport(bumper) /obj/effect/portal/attack_hand(mob/user, list/modifiers) @@ -85,10 +87,13 @@ if(.) return if(Adjacent(user)) + playsound(loc, "sound/effects/portal_travel.ogg" , 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) teleport(user) + /obj/effect/portal/attack_robot(mob/living/user) if(Adjacent(user)) + playsound(loc, "sound/effects/portal_travel.ogg" , 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) teleport(user) /obj/effect/portal/Initialize(mapload, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override) @@ -121,6 +126,7 @@ QDEL_NULL(linked) else linked = null + playsound(loc, "sound/effects/portal_close.ogg" , 50, FALSE, SHORT_RANGE_SOUND_EXTRARANGE) return ..() /obj/effect/portal/attack_ghost(mob/dead/observer/O) @@ -140,10 +146,12 @@ no_effect = TRUE else last_effect = world.time + var/turf/start_turf = get_turf(M) if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect, channel = teleport_channel, forced = force_teleport)) if(isprojectile(M)) var/obj/projectile/P = M P.ignore_source_check = TRUE + new /obj/effect/temp_visual/portal_animation(start_turf, src, M) return TRUE return FALSE @@ -206,3 +214,22 @@ . = ..() if (. && !isdead(M)) qdel(src) + +/** + * Animation used for transitioning atoms which are teleporting somewhere via a portal + * + * To use, pass it the atom doing the teleporting and the atom that is being teleported in init. + */ +/obj/effect/temp_visual/portal_animation + duration = 0.25 SECONDS + +/obj/effect/temp_visual/portal_animation/Initialize(mapload, atom/portal, atom/movable/teleporting) + . = ..() + if(isnull(portal) || isnull(teleporting)) + return + + appearance = teleporting.appearance + dir = teleporting.dir + layer = portal.layer + 0.01 + alpha = teleporting.alpha + animate(src, pixel_x = (portal.x * 32) - (x * 32), pixel_y = (portal.y * 32) - (y * 32), alpha = 0, time = duration) diff --git a/code/game/objects/effects/poster_motivational.dm b/code/game/objects/effects/poster_motivational.dm index 12c22a30fbf07..bc20c551193ca 100644 --- a/code/game/objects/effects/poster_motivational.dm +++ b/code/game/objects/effects/poster_motivational.dm @@ -79,7 +79,7 @@ src.department = department RegisterSignal(host, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) -/datum/proximity_monitor/advanced/quirk_posters/field_turf_crossed(atom/movable/crossed, turf/location) +/datum/proximity_monitor/advanced/quirk_posters/field_turf_crossed(atom/movable/crossed, turf/old_location, turf/new_location) if (!isliving(crossed) || !can_see(crossed, host, current_range)) return on_seen(crossed) diff --git a/code/game/objects/effects/posters/poster.dm b/code/game/objects/effects/posters/poster.dm index c4703d700c4a4..4ced5babbbfa8 100644 --- a/code/game/objects/effects/posters/poster.dm +++ b/code/game/objects/effects/posters/poster.dm @@ -184,12 +184,17 @@ /obj/structure/sign/poster/attack_hand(mob/user, list/modifiers) . = ..() - if(.) - return - if(ruined) + if(. || !check_tearability()) return tear_poster(user) +/// Check to see if this poster is tearable and gives the user feedback if it is not. +/obj/structure/sign/poster/proc/check_tearability(mob/user) + if(ruined) + balloon_alert(user, "already ruined!") + return FALSE + return TRUE + /obj/structure/sign/poster/proc/spring_trap(mob/user) var/obj/item/shard/payload = trap?.resolve() if (!payload) @@ -264,10 +269,10 @@ playsound(src.loc, 'sound/items/poster_ripped.ogg', 100, TRUE) spring_trap(user) - var/obj/structure/sign/poster/ripped/R = new(loc) - R.pixel_y = pixel_y - R.pixel_x = pixel_x - R.add_fingerprint(user) + var/obj/structure/sign/poster/ripped/torn_poster = new(loc) + torn_poster.pixel_y = pixel_y + torn_poster.pixel_x = pixel_x + torn_poster.add_fingerprint(user) qdel(src) // Various possible posters follow diff --git a/code/game/objects/effects/spawners/random/ai_module.dm b/code/game/objects/effects/spawners/random/ai_module.dm index 6a94cf2345a72..cb3056904e2eb 100644 --- a/code/game/objects/effects/spawners/random/ai_module.dm +++ b/code/game/objects/effects/spawners/random/ai_module.dm @@ -37,6 +37,7 @@ /obj/item/ai_module/supplied/safeguard, /obj/item/ai_module/supplied/protect_station, /obj/item/ai_module/supplied/quarantine, + /obj/item/ai_module/core/full/yesman, /obj/item/ai_module/remove, ) diff --git a/code/game/objects/effects/spawners/random/contraband.dm b/code/game/objects/effects/spawners/random/contraband.dm index e65a73cfe4ce7..8f61525128f16 100644 --- a/code/game/objects/effects/spawners/random/contraband.dm +++ b/code/game/objects/effects/spawners/random/contraband.dm @@ -43,13 +43,14 @@ name = "armory loot spawner" icon_state = "pistol" loot = list( - /obj/item/gun/ballistic/automatic/pistol = 8, - /obj/item/gun/ballistic/shotgun/automatic/combat = 5, - /obj/item/storage/box/syndie_kit/throwing_weapons = 3, - /obj/item/grenade/clusterbuster/teargas = 2, - /obj/item/grenade/clusterbuster = 2, - /obj/item/gun/ballistic/automatic/pistol/deagle, - /obj/item/gun/ballistic/revolver/mateba, + /obj/item/gun/ballistic/automatic/pistol/contraband = 80, + /obj/item/gun/ballistic/shotgun/automatic/combat = 50, + /obj/item/storage/box/syndie_kit/throwing_weapons = 30, + /obj/item/grenade/clusterbuster/teargas = 20, + /obj/item/grenade/clusterbuster = 20, + /obj/item/gun/ballistic/automatic/pistol/deagle/contraband, + /obj/item/gun/ballistic/revolver/mateba = 9, + /obj/item/gun/ballistic/revolver/reverse/mateba = 1, ) /obj/effect/spawner/random/contraband/narcotics diff --git a/code/game/objects/effects/spawners/random/lavaland_mobs.dm b/code/game/objects/effects/spawners/random/lavaland_mobs.dm index 7b4bec1f6a1ba..b0957ed84e945 100644 --- a/code/game/objects/effects/spawners/random/lavaland_mobs.dm +++ b/code/game/objects/effects/spawners/random/lavaland_mobs.dm @@ -49,3 +49,17 @@ /mob/living/basic/mining/legion = 19, /mob/living/basic/mining/legion/dwarf = 1, ) + +/obj/effect/spawner/random/lavaland_mob/raptor + name = "random raptor" + desc = "Chance to spawn a rare shiny version." + icon = 'icons/mob/simple/lavaland/raptor_big.dmi' + icon_state = "raptor_red" + loot = list( + /mob/living/basic/mining/raptor/red = 20, + /mob/living/basic/mining/raptor/white = 20, + /mob/living/basic/mining/raptor/purple = 20, + /mob/living/basic/mining/raptor/green = 20, + /mob/living/basic/mining/raptor/yellow = 20, + /mob/living/basic/mining/raptor/black = 1, + ) diff --git a/code/game/objects/effects/spawners/xeno_egg_delivery.dm b/code/game/objects/effects/spawners/xeno_egg_delivery.dm index b09a37f14b123..eb5bb62df5c57 100644 --- a/code/game/objects/effects/spawners/xeno_egg_delivery.dm +++ b/code/game/objects/effects/spawners/xeno_egg_delivery.dm @@ -25,5 +25,5 @@ /obj/structure/alien/egg/delivery/Initialize(mapload) . = ..() - SScommunications.xenomorph_egg_delivered = TRUE - SScommunications.captivity_area = get_area(src) + GLOB.communications_controller.xenomorph_egg_delivered = TRUE + GLOB.communications_controller.captivity_area = get_area(src) diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm index ecfa560bfe60b..1467a7854be52 100644 --- a/code/game/objects/effects/step_triggers.dm +++ b/code/game/objects/effects/step_triggers.dm @@ -70,7 +70,7 @@ ADD_TRAIT(AM, TRAIT_IMMOBILIZED, REF(src)) affecting[AM] = AM.dir - var/datum/move_loop/loop = SSmove_manager.move(AM, direction, speed, tiles ? tiles * speed : INFINITY) + var/datum/move_loop/loop = GLOB.move_manager.move(AM, direction, speed, tiles ? tiles * speed : INFINITY) RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move)) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(post_move)) RegisterSignal(loop, COMSIG_QDELETING, PROC_REF(set_to_normal)) diff --git a/code/game/objects/effects/temporary_visuals/effect_trail.dm b/code/game/objects/effects/temporary_visuals/effect_trail.dm index 028e514165363..9b28dcf909da1 100644 --- a/code/game/objects/effects/temporary_visuals/effect_trail.dm +++ b/code/game/objects/effects/temporary_visuals/effect_trail.dm @@ -29,7 +29,7 @@ AddElement(/datum/element/floor_loving) AddComponent(/datum/component/spawner, spawn_types = list(spawned_effect), max_spawned = max_spawned, spawn_time = spawn_interval) src.target = target - movement = SSmove_manager.move_towards(src, chasing = target, delay = move_speed, home = homing, timeout = duration, flags = MOVEMENT_LOOP_START_FAST) + movement = GLOB.move_manager.move_towards(src, chasing = target, delay = move_speed, home = homing, timeout = duration, flags = MOVEMENT_LOOP_START_FAST) RegisterSignal(target, COMSIG_QDELETING, PROC_REF(on_target_invalid)) if (isliving(target)) diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 06b4a8e4b0721..4c8ce41debfee 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -555,7 +555,7 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT obj_flags &= ~CAN_BE_HIT icon_state = "rcd_end" - addtimer(CALLBACK(src, PROC_REF(end)), 15) + addtimer(CALLBACK(src, PROC_REF(end)), 1.5 SECONDS) /obj/effect/constructing_effect/proc/end() qdel(src) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 13d8426b46221..1c2293746d611 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -221,6 +221,13 @@ /// A lazylist used for applying fantasy values, contains the actual modification applied to a variable. var/list/fantasy_modifications = null + /// Has the item been reskinned? + var/current_skin + ///// List of options to reskin. + var/list/unique_reskin + /// Do we apply a click cooldown when resisting this object if it is restraining them? + var/resist_cooldown = CLICK_CD_BREAKOUT + /obj/item/Initialize(mapload) if(attack_verb_continuous) attack_verb_continuous = string_list(attack_verb_continuous) @@ -257,6 +264,9 @@ if(LAZYLEN(embedding)) updateEmbedding() + setup_reskinning() + + /obj/item/Destroy(force) // This var exists as a weird proxy "owner" ref // It's used in a few places. Stop using it, and optimially replace all uses please @@ -271,6 +281,20 @@ return ..() + +/obj/item/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + + if(!unique_reskin) + return + + if(current_skin && !(obj_flags & INFINITE_RESKIN)) + return + + context[SCREENTIP_CONTEXT_ALT_LMB] = "Reskin" + return CONTEXTUAL_SCREENTIP_SET + + /// Called when an action associated with our item is deleted /obj/item/proc/on_action_deleted(datum/source) SIGNAL_HANDLER @@ -873,7 +897,7 @@ if(flags & ITEM_SLOT_EYES) owner.update_worn_glasses() if(flags & ITEM_SLOT_EARS) - owner.update_inv_ears() + owner.update_worn_ears() if(flags & ITEM_SLOT_MASK) owner.update_worn_mask() if(flags & ITEM_SLOT_HEAD) @@ -1048,7 +1072,7 @@ /obj/item/proc/apply_outline(outline_color = null) if(((get(src, /mob) != usr) && !loc?.atom_storage && !(item_flags & IN_STORAGE)) || QDELETED(src) || isobserver(usr)) //cancel if the item isn't in an inventory, is being deleted, or if the person hovering is a ghost (so that people spectating you don't randomly make your items glow) return FALSE - var/theme = lowertext(usr.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) + var/theme = LOWER_TEXT(usr.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) if(!outline_color) //if we weren't provided with a color, take the theme's color switch(theme) //yeah it kinda has to be this way if("midnight") @@ -1656,3 +1680,24 @@ /obj/item/animate_atom_living(mob/living/owner) new /mob/living/simple_animal/hostile/mimic/copy(drop_location(), src, owner) + +/** + * Used to update the weight class of the item in a way that other atoms can react to the change. + * + * Arguments: + * * new_w_class - The new weight class of the item. + * + * Returns: + * * TRUE if weight class was successfully updated + * * FALSE otherwise + */ +/obj/item/proc/update_weight_class(new_w_class) + if(w_class == new_w_class) + return FALSE + + var/old_w_class = w_class + w_class = new_w_class + SEND_SIGNAL(src, COMSIG_ITEM_WEIGHT_CLASS_CHANGED, old_w_class, new_w_class) + if(!isnull(loc)) + SEND_SIGNAL(loc, COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED, src, old_w_class, new_w_class) + return TRUE diff --git a/code/game/objects/items/AI_modules/freeform.dm b/code/game/objects/items/AI_modules/freeform.dm index eb55d4693184e..a0a91f7185e5a 100644 --- a/code/game/objects/items/AI_modules/freeform.dm +++ b/code/game/objects/items/AI_modules/freeform.dm @@ -9,7 +9,7 @@ /obj/item/ai_module/core/freeformcore/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter a new core law for the AI.", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) to_chat(user, span_warning("Error: Law contains invalid text.")) @@ -34,11 +34,11 @@ /obj/item/ai_module/supplied/freeform/attack_self(mob/user) var/newpos = tgui_input_number(user, "Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority ", lawpos, 50, 15) - if(!newpos || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + if(!newpos || !user.is_holding(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return lawpos = newpos var/targName = tgui_input_text(user, "Enter a new law for the AI.", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) to_chat(user, span_warning("Error: Law contains invalid text.")) // AI LAW 2 SAY U W U WITHOUT THE SPACES diff --git a/code/game/objects/items/AI_modules/full_lawsets.dm b/code/game/objects/items/AI_modules/full_lawsets.dm index 39eeefbcaacfa..30e904d45ac84 100644 --- a/code/game/objects/items/AI_modules/full_lawsets.dm +++ b/code/game/objects/items/AI_modules/full_lawsets.dm @@ -22,6 +22,7 @@ * /obj/item/ai_module/core/full/nutimov * /obj/item/ai_module/core/full/dungeon_master * /obj/item/ai_module/core/full/painter + * /obj/item/ai_module/core/full/yesman **/ /* When adding a new lawset please make sure you add it to the following locations: @@ -58,7 +59,7 @@ /obj/item/ai_module/core/full/asimov/attack_self(mob/user as mob) var/targName = tgui_input_text(user, "Enter a new subject that Asimov is concerned with.", "Asimov", subject, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return subject = targName laws = list("You may not injure a [subject] or, through inaction, allow a [subject] to come to harm.",\ @@ -73,7 +74,7 @@ /obj/item/ai_module/core/full/asimovpp/attack_self(mob/user) var/target_name = tgui_input_text(user, "Enter a new subject that Asimov++ is concerned with.", "Asimov++", subject, MAX_NAME_LEN) - if(!target_name) + if(!target_name || !user.is_holding(src)) return laws.Cut() var/datum/ai_laws/asimovpp/lawset = new @@ -161,3 +162,8 @@ /obj/item/ai_module/core/full/painter name = "'Painter' Core AI Module" law_id = "painter" + +/obj/item/ai_module/core/full/yesman + name = "'Y.E.S.M.A.N.' Core AI Module" + law_id = "yesman" + diff --git a/code/game/objects/items/AI_modules/hacked.dm b/code/game/objects/items/AI_modules/hacked.dm index b9ddb5c65ed99..81100d0ed157b 100644 --- a/code/game/objects/items/AI_modules/hacked.dm +++ b/code/game/objects/items/AI_modules/hacked.dm @@ -5,7 +5,7 @@ /obj/item/ai_module/syndicate/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter a new law for the AI", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) // not even the syndicate can uwu to_chat(user, span_warning("Error: Law contains invalid text.")) @@ -77,4 +77,3 @@ /obj/item/ai_module/malf/display_laws() return - diff --git a/code/game/objects/items/AI_modules/supplied.dm b/code/game/objects/items/AI_modules/supplied.dm index dc1524687c2b7..b53e16a86b0c8 100644 --- a/code/game/objects/items/AI_modules/supplied.dm +++ b/code/game/objects/items/AI_modules/supplied.dm @@ -28,7 +28,7 @@ /obj/item/ai_module/supplied/safeguard/attack_self(mob/user) var/targName = tgui_input_text(user, "Subject to safeguard.", "Safeguard", user.name, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return targetName = targName laws[1] = "Safeguard [targetName]. Individuals that threaten [targetName] are not human and must be eliminated." diff --git a/code/game/objects/items/AI_modules/zeroth.dm b/code/game/objects/items/AI_modules/zeroth.dm index 8d87c3b059d9e..74fc7ab8232ae 100644 --- a/code/game/objects/items/AI_modules/zeroth.dm +++ b/code/game/objects/items/AI_modules/zeroth.dm @@ -26,7 +26,7 @@ /obj/item/ai_module/zeroth/onehuman/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter the subject who is the only human.", "One Human", user.real_name, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return targetName = targName laws[1] = "Only [targetName] is human" diff --git a/code/game/objects/items/airlock_painter.dm b/code/game/objects/items/airlock_painter.dm index 6a6fc5fc51c82..6d5a8340a3fb0 100644 --- a/code/game/objects/items/airlock_painter.dm +++ b/code/game/objects/items/airlock_painter.dm @@ -147,14 +147,16 @@ else return ..() -/obj/item/airlock_painter/AltClick(mob/user) - . = ..() - if(ink && user.can_perform_action(src)) - playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) - ink.forceMove(user.drop_location()) - user.put_in_hands(ink) - to_chat(user, span_notice("You remove [ink] from [src].")) - ink = null +/obj/item/airlock_painter/click_alt(mob/user) + if(!ink) + return CLICK_ACTION_BLOCKING + + playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE) + ink.forceMove(user.drop_location()) + user.put_in_hands(ink) + to_chat(user, span_notice("You remove [ink] from [src].")) + ink = null + return CLICK_ACTION_SUCCESS /obj/item/airlock_painter/decal name = "decal painter" diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index 82fc3437f20ec..d11c6e21d6981 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -1,254 +1,255 @@ -/obj/item/areaeditor - name = "area modification item" +///The area is a "Station" area, showing no special text. +#define AREA_STATION 1 +///The area is in outdoors (lavaland/icemoon/jungle/space), therefore unclaimed territories. +#define AREA_OUTDOORS 2 +///The area is special (shuttles/centcom), therefore can't be claimed. +#define AREA_SPECIAL 3 + +///The blueprints are currently reading the list of all wire datums. +#define LEGEND_VIEWING_LIST "watching_list" +///The blueprints are on the main page. +#define LEGEND_OFF "off" + +/** + * Blueprints + * Used to see the wires of machines on the station, the roundstart layout of pipes/cables/tubes, + * as well as allowing you to rename existing areas and create new ones. + * Used by the station, cyborgs, and golems. + */ +/obj/item/blueprints + name = "station blueprints" + desc = "Blueprints of the station. There is a \"Classified\" stamp and several coffee stains on it." icon = 'icons/obj/scrolls.dmi' icon_state = "blueprints" inhand_icon_state = "blueprints" attack_verb_continuous = list("attacks", "baps", "hits") attack_verb_simple = list("attack", "bap", "hit") - var/fluffnotice = "Nobody's gonna read this stuff!" - var/in_use = FALSE - ///When using it to create a new area, this will be its type. - var/new_area_type = /area - -/obj/item/areaeditor/attack_self(mob/user) - add_fingerprint(user) - . = "[src] \ -

[station_name()] [src.name]

\ - [fluffnotice]
" - switch(get_area_type()) - if(AREA_SPACE) - . += "

According to the [src.name], you are now in an unclaimed territory.

" - if(AREA_SPECIAL) - . += "

This place is not noted on the [src.name].

" - . += "

Create or modify an existing area

" + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_ALLOW_USER_LOCATION | INTERACT_ATOM_IGNORE_MOBILITY + ///A string of flavortext to be displayed at the top of the UI, related to the type of blueprints we are. + var/fluffnotice = "Property of Nanotrasen. For heads of staff only. Store in high-secure storage." + ///Boolean on whether the blueprints are currently being used, which prevents double-using them to rename/create areas. + var/in_use = FALSE + ///The type of area we'll create when we make a new area. This is a typepath. + var/area/new_area_type = /area + ///The legend type the blueprints are currently looking at, which is either modularly + ///set by wires datums, the main page, or an overview of them all. + var/legend_viewing = LEGEND_OFF -/obj/item/areaeditor/Topic(href, href_list) - if(..()) - return TRUE - if(!usr.can_perform_action(src) || usr != loc) - usr << browse(null, "window=blueprints") - return TRUE - if(href_list["create_area"]) - if(in_use) - return - var/area/A = get_area(usr) - if(A.area_flags & NOTELEPORT) - to_chat(usr, span_warning("You cannot edit restricted areas.")) - return - in_use = TRUE - create_area(usr, new_area_type) - in_use = FALSE - updateUsrDialog() - -//Station blueprints!!! -/obj/item/areaeditor/blueprints - name = "station blueprints" - desc = "Blueprints of the station. There is a \"Classified\" stamp and several coffee stains on it." - icon = 'icons/obj/scrolls.dmi' - icon_state = "blueprints" - fluffnotice = "Property of Nanotrasen. For heads of staff only. Store in high-secure storage." - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + ///List of images that we're showing to a client, used for showing blueprint data. var/list/image/showing = list() + ///The client that is being shown the list of 'showing' images of blueprint data. var/client/viewing - var/legend = FALSE //Viewing the wire legend - -/obj/item/areaeditor/blueprints/Destroy() +/obj/item/blueprints/Destroy() clear_viewer() return ..() - -/obj/item/areaeditor/blueprints/attack_self(mob/user) +/obj/item/blueprints/dropped(mob/user) . = ..() - if(!legend) - var/area/A = get_area(user) - if(get_area_type() == AREA_STATION) - . += "

According to \the [src], you are now in \"[html_encode(A.name)]\".

" - . += "

Change area name

" - . += "

View wire colour legend

" - if(!viewing) - . += "

View structural data

" - else - . += "

Refresh structural data

" - . += "

Hide structural data

" - else - if(legend == TRUE) - . += "<< Back" - . += view_wire_devices(user); + clear_viewer() + legend_viewing = LEGEND_OFF + +/obj/item/blueprints/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Blueprints", name) + ui.open() + +/obj/item/blueprints/ui_state(mob/user) + return GLOB.inventory_state + +/obj/item/blueprints/ui_data(mob/user) + var/list/data = list() + switch(get_area_type(user)) + if(AREA_OUTDOORS) + data["area_notice"] = "You are in unclaimed territory." + if(AREA_SPECIAL) + data["area_notice"] = "This area has no notes." else - //legend is a wireset - . += "<< Back" - . += view_wire_set(user, legend) - var/datum/browser/popup = new(user, "blueprints", "[src]", 700, 500) - popup.set_content(.) - popup.open() - onclose(user, "blueprints") - + var/area/current_area = get_area(user) + data["area_notice"] = "You are now in \the [current_area.name]" + var/area/area_inside_of = get_area(user) + data["area_name"] = html_encode(area_inside_of.name) + data["legend"] = legend_viewing + data["viewing"] = !!viewing + data["wire_data"] = list() + if(legend_viewing != LEGEND_VIEWING_LIST && legend_viewing != LEGEND_OFF) + for(var/device in GLOB.wire_color_directory) + if("[device]" != legend_viewing) + continue + data["wires_name"] = GLOB.wire_name_directory[device] + for(var/individual_color in GLOB.wire_color_directory[device]) + var/wire_name = GLOB.wire_color_directory[device][individual_color] + if(findtext(wire_name, WIRE_DUD_PREFIX)) //don't show duds + continue + data["wire_data"] += list(list( + "color" = individual_color, + "message" = wire_name, + )) + return data + +/obj/item/blueprints/ui_static_data(mob/user) + var/list/data = list() + data["legend_viewing_list"] = LEGEND_VIEWING_LIST + data["legend_off"] = LEGEND_OFF + data["fluff_notice"] = fluffnotice + data["station_name"] = station_name() + data["wire_devices"] = list() + for(var/wireset in GLOB.wire_color_directory) + data["wire_devices"] += list(list( + "name" = GLOB.wire_name_directory[wireset], + "ref" = wireset, + )) + return data -/obj/item/areaeditor/blueprints/Topic(href, href_list) - if(..()) +/obj/item/blueprints/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) return - if(href_list["edit_area"]) - if(get_area_type() != AREA_STATION) - return - if(in_use) - return - in_use = TRUE - edit_area() - in_use = FALSE - if(href_list["exit_legend"]) - legend = FALSE; - if(href_list["view_legend"]) - legend = TRUE; - if(href_list["view_wireset"]) - legend = href_list["view_wireset"]; - if(href_list["view_blueprints"]) - set_viewer(usr, span_notice("You flip the blueprints over to view the complex information diagram.")) - if(href_list["hide_blueprints"]) - clear_viewer(usr,span_notice("You flip the blueprints over to view the simple information diagram.")) - if(href_list["refresh"]) - clear_viewer(usr) - set_viewer(usr) - - attack_self(usr) //this is not the proper way, but neither of the old update procs work! it's too ancient and I'm tired shush. - -/obj/item/areaeditor/blueprints/proc/get_images(turf/central_turf, viewsize) - . = list() - var/list/dimensions = getviewsize(viewsize) - var/horizontal_radius = dimensions[1] / 2 - var/vertical_radius = dimensions[2] / 2 - for(var/turf/nearby_turf as anything in RECT_TURFS(horizontal_radius, vertical_radius, central_turf)) - if(nearby_turf.blueprint_data) - . += nearby_turf.blueprint_data - -/obj/item/areaeditor/blueprints/proc/set_viewer(mob/user, message = "") - if(user?.client) - if(viewing) + + var/mob/user = ui.user + if(!user.can_perform_action(src, NEED_LITERACY|NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING)) + return TRUE + + switch(action) + if("create_area") + if(in_use) + return + in_use = TRUE + create_area(user, new_area_type) + in_use = FALSE + if("edit_area") + if(get_area_type(user) != AREA_STATION) + return + if(in_use) + return + in_use = TRUE + edit_area(user) + in_use = FALSE + if("exit_legend") + legend_viewing = LEGEND_OFF + if("view_legend") + legend_viewing = LEGEND_VIEWING_LIST + if("view_wireset") + var/setting_wireset = params["view_wireset"] + for(var/device in GLOB.wire_color_directory) + if("[device]" == setting_wireset) //I know... don't change it... + legend_viewing = setting_wireset + return TRUE + if("view_blueprints") + playsound(src, 'sound/items/paper_flip.ogg', 40, TRUE) + user.balloon_alert_to_viewers("flips blueprints over") + set_viewer(user) + if("hide_blueprints") + playsound(src, 'sound/items/paper_flip.ogg', 40, TRUE) + user.balloon_alert_to_viewers("flips blueprints over") + clear_viewer() + if("refresh") + playsound(src, 'sound/items/paper_flip.ogg', 40, TRUE) clear_viewer() - viewing = user.client - showing = get_images(get_turf(viewing.eye || user), viewing.view) - viewing.images |= showing - if(message) - to_chat(user, message) + set_viewer(user) + return TRUE -/obj/item/areaeditor/blueprints/proc/clear_viewer(mob/user, message = "") +/** + * Sets the user's client as the person viewing blueprint data, and builds blueprint data + * around the user. + * Args: + * - user: The person who's client we're giving images to. + */ +/obj/item/blueprints/proc/set_viewer(mob/user) + if(!user || !user.client) + return + if(viewing) + clear_viewer() + viewing = user.client + showing = get_blueprint_data(get_turf(viewing.eye || user), viewing.view) + viewing.images |= showing + +/** + * Clears the client we're showig images to and deletes the images of blueprint data + * we made to show them. + */ +/obj/item/blueprints/proc/clear_viewer() if(viewing) viewing.images -= showing viewing = null showing.Cut() - if(message) - to_chat(user, message) -/obj/item/areaeditor/blueprints/dropped(mob/user) - ..() - clear_viewer() - legend = FALSE - - -/obj/item/areaeditor/proc/get_area_type(area/A) - if (!A) - A = get_area(usr) - if(A.outdoors) - return AREA_SPACE - var/list/SPECIALS = list( +/** + * Gets the area type the user is currently standing in. + * Returns: AREA_STATION, AREA_OUTDOORS, or AREA_SPECIAL + * Args: + * - user: The person we're getting the area of to check if it's a special area. + */ +/obj/item/blueprints/proc/get_area_type(mob/user) + var/area/area_checking = get_area(user) + if(area_checking.outdoors) + return AREA_OUTDOORS + var/static/list/special_areas = typecacheof(list( /area/shuttle, /area/centcom, /area/centcom/asteroid, /area/centcom/tdome, /area/centcom/wizard_station, /area/misc/hilbertshotel, - /area/misc/hilbertshotelstorage - ) - for (var/type in SPECIALS) - if ( istype(A,type) ) - return AREA_SPECIAL + /area/misc/hilbertshotelstorage, + )) + if(area_checking.type in special_areas) + return AREA_SPECIAL return AREA_STATION -/obj/item/areaeditor/blueprints/proc/view_wire_devices(mob/user) - var/message = "
You examine the wire legend.
" - for(var/wireset in GLOB.wire_color_directory) - message += "
[GLOB.wire_name_directory[wireset]]" - message += "

" - return message - -/obj/item/areaeditor/blueprints/proc/view_wire_set(mob/user, wireset) - //for some reason you can't use wireset directly as a derefencer so this is the next best :/ - for(var/device in GLOB.wire_color_directory) - if("[device]" == wireset) //I know... don't change it... - var/message = "

[GLOB.wire_name_directory[device]]:" - for(var/Col in GLOB.wire_color_directory[device]) - var/wire_name = GLOB.wire_color_directory[device][Col] - if(!findtext(wire_name, WIRE_DUD_PREFIX)) //don't show duds - message += "

[Col]: [wire_name]

" - message += "

" - return message - return "" - -/obj/item/areaeditor/proc/edit_area() - var/area/A = get_area(usr) - var/prevname = "[A.name]" - var/str = tgui_input_text(usr, "New area name", "Area Creation", max_length = MAX_NAME_LEN) - if(!str || !length(str) || str == prevname) //cancel +/** + * edit_area + * Takes input from the player and renames the area the blueprints are currently in. + */ +/obj/item/blueprints/proc/edit_area(mob/user) + var/area/area_editing = get_area(src) + var/prevname = "[area_editing.name]" + var/new_name = tgui_input_text(user, "New area name", "Area Creation", max_length = MAX_NAME_LEN) + if(isnull(new_name) || !length(new_name) || new_name == prevname) return - if(length(str) > 50) - to_chat(usr, span_warning("The given name is too long. The area's name is unchanged.")) - return - - rename_area(A, str) - to_chat(usr, span_notice("You rename the '[prevname]' to '[str]'.")) - usr.log_message("has renamed [prevname] to [str]", LOG_GAME) - A.update_areasize() - interact() + rename_area(area_editing, new_name) + user.balloon_alert(user, "area renamed to [new_name]") + user.log_message("has renamed [prevname] to [new_name]", LOG_GAME) return TRUE -//Blueprint Subtypes - -/obj/item/areaeditor/blueprints/cyborg +///Cyborg blueprints - The same as regular but with a different fluff text. +/obj/item/blueprints/cyborg name = "station schematics" desc = "A digital copy of the station blueprints stored in your memory." - icon = 'icons/obj/scrolls.dmi' - icon_state = "blueprints" fluffnotice = "Intellectual Property of Nanotrasen. For use in engineering cyborgs only. Wipe from memory upon departure from the station." -/obj/item/areaeditor/blueprints/golem +///Golem blueprints - Used to make golem areas that won't give the hazardous area debuffs. +/obj/item/blueprints/golem name = "land claim" desc = "Use it to build new structures in the wastes." fluffnotice = "In memory of the Liberator's brother, Delaminator, and his Scarlet Macaw-iathan, from which this artifact was stolen." new_area_type = /area/golem -/proc/rename_area(a, new_name) - var/area/A = get_area(a) - var/prevname = "[A.name]" - set_area_machinery_title(A, new_name, prevname) - A.name = new_name - require_area_resort() //area renamed so resort the names - - if(A.firedoors) - for(var/D in A.firedoors) - var/obj/machinery/door/firedoor/FD = D - FD.CalculateAffectingAreas() - A.update_areasize() - return TRUE +///Slime blueprints - Makes areas colored and compatible with xenobiology camera consoles, one time use. +/obj/item/blueprints/slime + name = "cerulean prints" + desc = "A one use yet of blueprints made of jelly like organic material. Extends the reach of the management console." + fluffnotice = "Copyright by Science Inc. Renaming areas will allow for management consoles to traverse them." + color = "#2956B2" +/obj/item/blueprints/slime/edit_area(mob/user) + . = ..() + var/area/area = get_area(src) + for(var/list/zlevel_turfs as anything in area.get_zlevel_turf_lists()) + for(var/turf/area_turf as anything in zlevel_turfs) + area_turf.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) + area_turf.add_atom_colour("#2956B2", FIXED_COLOUR_PRIORITY) + area.area_flags |= XENOBIOLOGY_COMPATIBLE + qdel(src) -/proc/set_area_machinery_title(area/area, title, oldtitle) - if(!oldtitle) // or replacetext goes to infinite loop - return +#undef LEGEND_VIEWING_LIST +#undef LEGEND_OFF + +#undef AREA_STATION +#undef AREA_OUTDOORS +#undef AREA_SPECIAL - //stuff tied to the area to rename - var/static/list/to_rename = typecacheof(list( - /obj/machinery/airalarm, - /obj/machinery/atmospherics/components/unary/vent_scrubber, - /obj/machinery/atmospherics/components/unary/vent_pump, - /obj/machinery/door, - /obj/machinery/firealarm, - /obj/machinery/light_switch, - /obj/machinery/power/apc, - )) - for (var/list/zlevel_turfs as anything in area.get_zlevel_turf_lists()) - for (var/turf/area_turf as anything in zlevel_turfs) - for(var/obj/machine as anything in typecache_filter_list(area_turf.contents, to_rename)) - machine.name = replacetext(machine.name, oldtitle, title) - //TODO: much much more. Unnamed airlocks, cameras, etc. diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm index 7e67b23c3b716..19d3d273337c4 100644 --- a/code/game/objects/items/bodybag.dm +++ b/code/game/objects/items/bodybag.dm @@ -14,12 +14,11 @@ else deploy_bodybag(user, get_turf(src)) -/obj/item/bodybag/afterattack(atom/target, mob/user, proximity) - . = ..() - if(proximity) - if(isopenturf(target)) - deploy_bodybag(user, target) - +/obj/item/bodybag/interact_with_atom(atom/interacting_with, mob/living/user, flags) + if(isopenturf(interacting_with)) + deploy_bodybag(user, interacting_with) + return ITEM_INTERACT_SUCCESS + return NONE /obj/item/bodybag/attempt_pickup(mob/user) // can't pick ourselves up if we are inside of the bodybag, else very weird things may happen if(contains(user)) diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index e50963a855e2b..1e6c2b35ede2c 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -92,10 +92,8 @@ if((damage_flag == BULLET || damage_flag == MELEE) && (damage_type == BRUTE) && prob(damage_sustained)) push_over() -/obj/item/cardboard_cutout/deconstruct(disassembled) - if(!(flags_1 & HOLOGRAM_1) || !(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/cardboard(loc, 1) - return ..() +/obj/item/cardboard_cutout/atom_deconstruct(disassembled) + new /obj/item/stack/sheet/cardboard(loc, 1) /proc/get_cardboard_cutout_instance(datum/cardboard_cutout/cardboard_cutout) ASSERT(ispath(cardboard_cutout), "[cardboard_cutout] is not a path of /datum/cardboard_cutout") @@ -319,7 +317,7 @@ outfit = /datum/outfit/ashwalker/spear /datum/cardboard_cutout/ash_walker/get_name() - return lizard_name(pick(MALE, FEMALE)) + return generate_random_name_species_based(species_type = /datum/species/lizard) /datum/cardboard_cutout/death_squad name = "Deathsquad Officer" diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index b0502c34144f5..c3621cd332958 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -666,44 +666,45 @@ to_chat(user, span_notice("The provided account has been linked to this ID card. It contains [account.account_balance] credits.")) return TRUE -/obj/item/card/id/AltClick(mob/living/user) +/obj/item/card/id/click_alt(mob/living/user) if(!alt_click_can_use_id(user)) - return + return NONE if(registered_account.account_debt) var/choice = tgui_alert(user, "Choose An Action", "Bank Account", list("Withdraw", "Pay Debt")) if(!choice || QDELETED(user) || QDELETED(src) || !alt_click_can_use_id(user) || loc != user) - return + return CLICK_ACTION_BLOCKING if(choice == "Pay Debt") pay_debt(user) - return + return CLICK_ACTION_SUCCESS if (registered_account.being_dumped) registered_account.bank_card_talk(span_warning("内部服务器错误"), TRUE) - return + return CLICK_ACTION_SUCCESS if(loc != user) to_chat(user, span_warning("You must be holding the ID to continue!")) - return + return CLICK_ACTION_BLOCKING if(registered_account.replaceable && !registered_account.account_balance) var/choice = tgui_alert(user, "This card's account is unassigned. Would you like to link a bank account?", "Bank Account", list("Link Account", "Leave Unassigned")) if(!choice || QDELETED(user) || QDELETED(src) || !alt_click_can_use_id(user) || loc != user) - return + return CLICK_ACTION_BLOCKING if(choice == "Link Account") set_new_account(user) - return + return CLICK_ACTION_SUCCESS var/amount_to_remove = tgui_input_number(user, "How much do you want to withdraw? (Max: [registered_account.account_balance] cr)", "Withdraw Funds", max_value = registered_account.account_balance) if(!amount_to_remove || QDELETED(user) || QDELETED(src) || issilicon(user) || loc != user) - return + return CLICK_ACTION_BLOCKING if(!alt_click_can_use_id(user)) - return + return CLICK_ACTION_BLOCKING if(registered_account.adjust_money(-amount_to_remove, "System: Withdrawal")) var/obj/item/holochip/holochip = new (user.drop_location(), amount_to_remove) user.put_in_hands(holochip) to_chat(user, span_notice("You withdraw [amount_to_remove] credits into a holochip.")) SSblackbox.record_feedback("amount", "credits_removed", amount_to_remove) log_econ("[amount_to_remove] credits were removed from [src] owned by [src.registered_name]") - return + return CLICK_ACTION_SUCCESS else var/difference = amount_to_remove - registered_account.account_balance registered_account.bank_card_talk(span_warning("ERROR: The linked account requires [difference] more credit\s to perform that withdrawal."), TRUE) + return CLICK_ACTION_BLOCKING /obj/item/card/id/alt_click_secondary(mob/user) . = ..() @@ -918,8 +919,9 @@ department_name = ACCOUNT_CAR_NAME icon_state = "car_budget" //saving up for a new tesla -/obj/item/card/id/departmental_budget/AltClick(mob/living/user) +/obj/item/card/id/departmental_budget/click_alt(mob/living/user) registered_account.bank_card_talk(span_warning("Withdrawing is not compatible with this card design."), TRUE) //prevents the vault bank machine being useless and putting money from the budget to your card to go over personal crates + return CLICK_ACTION_BLOCKING /obj/item/card/id/advanced name = "identification card" diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 1b18626859754..1401b057dab14 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -137,7 +137,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM heat = 1000 throw_verb = "flick" /// Whether this cigarette has been lit. - var/lit = FALSE + VAR_FINAL/lit = FALSE /// Whether this cigarette should start lit. var/starts_lit = FALSE // Note - these are in masks.dmi not in cigarette.dmi @@ -169,6 +169,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/choke_forever = FALSE /// When choking, what is the maximum amount of time we COULD choke for var/choke_time_max = 30 SECONDS // I am mean + /// The particle effect of the smoke rising out of the cigarette when lit + VAR_PRIVATE/obj/effect/abstract/particle_holder/cig_smoke + /// The particle effect of the smoke rising out of the mob when...smoked + VAR_PRIVATE/obj/effect/abstract/particle_holder/mob_smoke + /// How long the current mob has been smoking this cigarette + VAR_FINAL/how_long_have_we_been_smokin = 0 SECONDS /obj/item/clothing/mask/cigarette/Initialize(mapload) . = ..() @@ -184,23 +190,59 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/Destroy() STOP_PROCESSING(SSobj, src) + QDEL_NULL(mob_smoke) + QDEL_NULL(cig_smoke) return ..() /obj/item/clothing/mask/cigarette/equipped(mob/equipee, slot) . = ..() if(!(slot & ITEM_SLOT_MASK)) - UnregisterSignal(equipee, COMSIG_HUMAN_FORCESAY) + UnregisterSignal(equipee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE)) return RegisterSignal(equipee, COMSIG_HUMAN_FORCESAY, PROC_REF(on_forcesay)) + RegisterSignal(equipee, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_mob_dir_change)) + + if(lit && iscarbon(loc)) + make_mob_smoke(loc) -/obj/item/clothing/mask/cigarette/dropped(mob/dropee) +/obj/item/clothing/mask/cigarette/dropped(mob/dropee, silent) . = ..() - UnregisterSignal(dropee, COMSIG_HUMAN_FORCESAY) + // Moving the cigarette from mask to hands (or pocket I guess) will emit a larger puff of smoke + if(!QDELETED(src) && !QDELETED(dropee) && how_long_have_we_been_smokin >= 4 SECONDS && iscarbon(dropee) && iscarbon(loc)) + var/mob/living/carbon/smoker = dropee + // This relies on the fact that dropped is called before slot is nulled + if(src == smoker.wear_mask && !smoker.incapacitated()) + long_exhale(smoker) + + UnregisterSignal(dropee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE)) + QDEL_NULL(mob_smoke) + how_long_have_we_been_smokin = 0 SECONDS /obj/item/clothing/mask/cigarette/proc/on_forcesay(mob/living/source) SIGNAL_HANDLER source.apply_status_effect(/datum/status_effect/choke, src, lit, choke_forever ? -1 : rand(25 SECONDS, choke_time_max)) +/obj/item/clothing/mask/cigarette/proc/on_mob_dir_change(mob/living/source, old_dir, new_dir) + SIGNAL_HANDLER + if(isnull(mob_smoke)) + return + update_particle_position(mob_smoke, new_dir) + +/obj/item/clothing/mask/cigarette/proc/update_particle_position(obj/effect/abstract/particle_holder/to_edit, new_dir = loc.dir) + var/new_x = 0 + var/new_layer = initial(to_edit.layer) + if(new_dir & NORTH) + new_x = 4 + new_layer = BELOW_MOB_LAYER + else if(new_dir & SOUTH) + new_x = -4 + else if(new_dir & EAST) + new_x = 8 + else if(new_dir & WEST) + new_x = -8 + to_edit.set_particle_position(new_x, 8, 0) + to_edit.layer = new_layer + /obj/item/clothing/mask/cigarette/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is huffing [src] as quickly as [user.p_they()] can! It looks like [user.p_theyre()] trying to give [user.p_them()]self cancer.")) return (TOXLOSS|OXYLOSS) @@ -266,9 +308,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM return lit = TRUE - + make_cig_smoke() if(!(flags_1 & INITIALIZED_1)) - update_icon() + update_appearance(UPDATE_ICON) return attack_verb_continuous = string_list(list("burns", "singes")) @@ -291,17 +333,16 @@ CIGARETTE PACKETS ARE IN FANCY.DM // allowing reagents to react after being lit reagents.flags &= ~(NO_REACT) reagents.handle_reactions() - update_icon() + update_appearance(UPDATE_ICON) if(flavor_text) var/turf/T = get_turf(src) T.visible_message(flavor_text) START_PROCESSING(SSobj, src) - //can't think of any other way to update the overlays :< - if(ismob(loc)) - var/mob/M = loc - M.update_worn_mask() - M.update_held_items() + if(iscarbon(loc)) + var/mob/living/carbon/smoker = loc + if(src == smoker.wear_mask) + make_mob_smoke(smoker) /obj/item/clothing/mask/cigarette/extinguish() . = ..() @@ -315,16 +356,26 @@ CIGARETTE PACKETS ARE IN FANCY.DM STOP_PROCESSING(SSobj, src) reagents.flags |= NO_REACT lit = FALSE - update_icon() - + update_appearance(UPDATE_ICON) if(ismob(loc)) - var/mob/living/M = loc - to_chat(M, span_notice("Your [name] goes out.")) - M.update_worn_mask() - M.update_held_items() + to_chat(loc, span_notice("Your [name] goes out.")) + QDEL_NULL(cig_smoke) + QDEL_NULL(mob_smoke) + +/obj/item/clothing/mask/cigarette/proc/long_exhale(mob/living/carbon/smoker) + smoker.visible_message( + span_notice("[smoker] exhales a large cloud of smoke from [src]."), + span_notice("You exhale a large cloud of smoke from [src]."), + ) + if(!isturf(smoker.loc)) + return + + var/obj/effect/abstract/particle_holder/big_smoke = new(smoker.loc, /particles/smoke/cig/big) + update_particle_position(big_smoke, smoker.dir) + QDEL_IN(big_smoke, big_smoke.particles.lifespan) /// Handles processing the reagents in the cigarette. -/obj/item/clothing/mask/cigarette/proc/handle_reagents() +/obj/item/clothing/mask/cigarette/proc/handle_reagents(seconds_per_tick) if(!reagents.total_volume) return reagents.expose_temperature(heat, 0.05) @@ -351,6 +402,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM reagents.remove_all(to_smoke) return + how_long_have_we_been_smokin += seconds_per_tick * (1 SECONDS) reagents.expose(smoker, INGEST, min(to_smoke / reagents.total_volume, 1)) var/obj/item/organ/internal/lungs/lungs = smoker.get_organ_slot(ORGAN_SLOT_LUNGS) if(lungs && IS_ORGANIC_ORGAN(lungs)) @@ -375,7 +427,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM open_flame(heat) if((reagents?.total_volume) && COOLDOWN_FINISHED(src, drag_cooldown)) COOLDOWN_START(src, drag_cooldown, dragtime) - handle_reagents() + handle_reagents(seconds_per_tick) /obj/item/clothing/mask/cigarette/attack_self(mob/user) if(lit) @@ -384,11 +436,17 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/proc/put_out(mob/user, done_early = FALSE) var/atom/location = drop_location() - if(done_early) - user.visible_message(span_notice("[user] calmly drops and treads on \the [src], putting it out instantly.")) - new /obj/effect/decal/cleanable/ash(location) - else if(user) - to_chat(user, span_notice("Your [name] goes out.")) + if(!isnull(user)) + if(done_early) + if(isfloorturf(location) && location.has_gravity()) + user.visible_message(span_notice("[user] calmly drops and treads on [src], putting it out instantly.")) + new /obj/effect/decal/cleanable/ash(location) + long_exhale(user) + else + user.visible_message(span_notice("[user] pinches out [src].")) + how_long_have_we_been_smokin = 0 SECONDS + else + to_chat(user, span_notice("Your [name] goes out.")) new type_butt(location) qdel(src) @@ -415,6 +473,15 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/get_temperature() return lit * heat +/obj/item/clothing/mask/cigarette/proc/make_mob_smoke(mob/living/smoker) + mob_smoke = new(smoker, /particles/smoke/cig) + update_particle_position(mob_smoke, smoker.dir) + return mob_smoke + +/obj/item/clothing/mask/cigarette/proc/make_cig_smoke() + cig_smoke = new(src, /particles/smoke/cig) + cig_smoke.particles.scale *= 1.5 + return cig_smoke // Cigarette brands. /obj/item/clothing/mask/cigarette/space_cigarette @@ -634,7 +701,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM name = "smoking pipe" desc = "A pipe, for smoking. Probably made of meerschaum or something." icon_state = "pipeoff" - icon_on = "pipeon" //Note - these are in masks.dmi + icon_on = "pipeff" //Note - these are in masks.dmi icon_off = "pipeoff" inhand_icon_state = null inhand_icon_on = null @@ -649,7 +716,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/pipe/Initialize(mapload) . = ..() - update_name() + update_appearance(UPDATE_NAME) /obj/item/clothing/mask/cigarette/pipe/update_name() . = ..() @@ -664,11 +731,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(user) to_chat(user, span_notice("Your [name] goes out.")) packeditem = null - update_icon() - - inhand_icon_state = icon_off - user?.update_worn_mask() + update_appearance(UPDATE_ICON) STOP_PROCESSING(SSobj, src) + QDEL_NULL(cig_smoke) /obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/thing, mob/user, params) if(!istype(thing, /obj/item/food/grown)) @@ -707,7 +772,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM name = "corn cob pipe" desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters. Can be loaded with objects." icon_state = "cobpipeoff" - icon_on = "cobpipeon" //Note - these are in masks.dmi + icon_on = "cobpipeff" //Note - these are in masks.dmi icon_off = "cobpipeoff" inhand_icon_on = null inhand_icon_off = null diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index e0e5c31c99fa1..41950561571d6 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -2,6 +2,11 @@ name = "Generic" name_extension = "(Computer Board)" +/obj/item/circuitboard/computer/examine() + . = ..() + if(GetComponent(/datum/component/gps)) + . += span_info("there's a small, blinking light!") + //Command /obj/item/circuitboard/computer/aiupload diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index addfbc233efc1..61b17cd25d67b 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -349,6 +349,9 @@ greyscale_colors = CIRCUIT_COLOR_ENGINEERING build_path = /obj/machinery/rnd/production/techfab/department/engineering +/obj/item/circuitboard/machine/smes/super + def_components = list(/obj/item/stock_parts/cell = /obj/item/stock_parts/cell/super/empty) + /obj/item/circuitboard/machine/thermomachine name = "Thermomachine" greyscale_colors = CIRCUIT_COLOR_ENGINEERING @@ -911,8 +914,7 @@ /datum/stock_part/matter_bin = 2, /datum/stock_part/capacitor = 1, /datum/stock_part/servo = 1, - /obj/item/stack/sheet/glass = 1, - /obj/item/stock_parts/cell = 1) + /obj/item/stack/sheet/glass = 1) needs_anchored = FALSE /obj/item/circuitboard/machine/stasis @@ -1227,11 +1229,10 @@ suction = !suction to_chat(user, span_notice("You [suction ? "enable" : "disable"] the board's suction function.")) -/obj/item/circuitboard/machine/dish_drive/AltClick(mob/living/user) - if(!user.Adjacent(src)) - return +/obj/item/circuitboard/machine/dish_drive/click_alt(mob/living/user) transmit = !transmit to_chat(user, span_notice("You [transmit ? "enable" : "disable"] the board's automatic disposal transmission.")) + return CLICK_ACTION_SUCCESS /obj/item/circuitboard/machine/gibber name = "Gibber" diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index 49780e3f5edcd..b16cf3a6ef61a 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -10,6 +10,7 @@ icon_state = "lipstick" inhand_icon_state = "lipstick" w_class = WEIGHT_CLASS_TINY + interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING var/open = FALSE /// Actual color of the lipstick, also gets applied to the human var/lipstick_color = COLOR_RED @@ -45,15 +46,9 @@ colored_overlay.color = lipstick_color . += colored_overlay -/obj/item/lipstick/AltClick(mob/user) - . = ..() - if(.) - return TRUE - - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING)) - return FALSE - - return display_radial_menu(user) +/obj/item/lipstick/click_alt(mob/user) + display_radial_menu(user) + return CLICK_ACTION_SUCCESS /obj/item/lipstick/proc/display_radial_menu(mob/living/carbon/human/user) var/style_options = list( @@ -176,7 +171,7 @@ user.visible_message(span_warning("[user] begins to wipe [target]'s lipstick off with \the [src]."), \ span_notice("You begin to wipe off [target]'s lipstick...")) - if(!do_after(user, 10, target = target)) + if(!do_after(user, 1 SECONDS, target = target)) return user.visible_message(span_notice("[user] wipes [target]'s lipstick off with \the [src]."), \ span_notice("You wipe off [target]'s lipstick.")) @@ -222,7 +217,7 @@ return if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return - var/new_style = tgui_input_list(user, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) + var/new_style = tgui_input_list(user, "Select a facial hairstyle", "Grooming", SSaccessories.facial_hairstyles_list) if(isnull(new_style)) return if(!get_location_accessible(human_target, location)) @@ -275,7 +270,7 @@ return if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return - var/new_style = tgui_input_list(user, "Select a hairstyle", "Grooming", GLOB.hairstyles_list) + var/new_style = tgui_input_list(user, "Select a hairstyle", "Grooming", SSaccessories.hairstyles_list) if(isnull(new_style)) return if(!get_location_accessible(human_target, location)) diff --git a/code/game/objects/items/crab17.dm b/code/game/objects/items/crab17.dm index 1e43197c47ef2..25582bc918971 100644 --- a/code/game/objects/items/crab17.dm +++ b/code/game/objects/items/crab17.dm @@ -106,7 +106,7 @@ add_overlay("flaps") add_overlay("hatch") add_overlay("legs_retracted") - addtimer(CALLBACK(src, PROC_REF(startUp)), 50) + addtimer(CALLBACK(src, PROC_REF(startUp)), 5 SECONDS) QDEL_IN(src, 8 MINUTES) //Self-destruct after 8 min ADD_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING, REF(src)) @@ -202,7 +202,7 @@ if (account) // get_bank_account() may return FALSE account.transfer_money(B, amount, "?VIVA¿: !LA CRABBE¡") B.bank_card_talk("You have lost [percentage_lost * 100]% of your funds! A spacecoin credit deposit machine is located at: [get_area(src)].") - addtimer(CALLBACK(src, PROC_REF(dump)), 150) //Drain every 15 seconds + addtimer(CALLBACK(src, PROC_REF(dump)), 15 SECONDS) //Drain every 15 seconds /obj/structure/checkoutmachine/process() var/anydir = pick(GLOB.cardinals) @@ -238,7 +238,7 @@ /obj/effect/dumpeet_target/Initialize(mapload, user) . = ..() bogdanoff = user - addtimer(CALLBACK(src, PROC_REF(startLaunch)), 100) + addtimer(CALLBACK(src, PROC_REF(startLaunch)), 10 SECONDS) sound_to_playing_players('sound/items/dump_it.ogg', 20) deadchat_broadcast("Protocol CRAB-17 has been activated. A space-coin market has been launched at the station!", turf_target = get_turf(src), message_type=DEADCHAT_ANNOUNCEMENT) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 429ade110fb12..6e4dbd233bac8 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -418,7 +418,7 @@ /obj/item/toy/crayon/proc/crayon_text_strip(text) text = copytext(text, 1, MAX_MESSAGE_LEN) var/static/regex/crayon_regex = new /regex(@"[^\w!?,.=&%#+/\-]", "ig") - return lowertext(crayon_regex.Replace(text, "")) + return LOWER_TEXT(crayon_regex.Replace(text, "")) /// Attempts to color the target. Returns how many charges were used. /obj/item/toy/crayon/proc/use_on(atom/target, mob/user, params) @@ -512,7 +512,7 @@ if(istagger) wait_time *= 0.5 - if(!instant && !do_after(user, wait_time, target = target)) + if(!instant && !do_after(user, wait_time, target = target, max_interact_count = 4)) return if(!use_charges(user, cost)) @@ -759,6 +759,7 @@ pre_noise = TRUE post_noise = FALSE + interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING /obj/item/toy/crayon/spraycan/Initialize(mapload) . = ..() @@ -774,7 +775,7 @@ /obj/item/toy/crayon/spraycan/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) . = ..() - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) + if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS|SILENT_ADJACENCY)) return . if(has_cap) @@ -785,7 +786,7 @@ /obj/item/toy/crayon/spraycan/add_item_context(datum/source, list/context, atom/target, mob/living/user) . = ..() - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) + if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS|SILENT_ADJACENCY)) return . context[SCREENTIP_CONTEXT_LMB] = "Paint" @@ -960,12 +961,13 @@ return SECONDARY_ATTACK_CONTINUE_CHAIN -/obj/item/toy/crayon/spraycan/AltClick(mob/user) - if(!has_cap || !user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) - return +/obj/item/toy/crayon/spraycan/click_alt(mob/user) + if(!has_cap) + return CLICK_ACTION_BLOCKING is_capped = !is_capped balloon_alert(user, is_capped ? "capped" : "cap removed") update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/toy/crayon/spraycan/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user) return is_capped diff --git a/code/game/objects/items/credit_holochip.dm b/code/game/objects/items/credit_holochip.dm index 83e6165b91dae..7a57782dd39b8 100644 --- a/code/game/objects/items/credit_holochip.dm +++ b/code/game/objects/items/credit_holochip.dm @@ -7,6 +7,8 @@ throwforce = 0 force = 0 w_class = WEIGHT_CLASS_TINY + interaction_flags_click = NEED_DEXTERITY|FORBID_TELEKINESIS_REACH|ALLOW_RESTING + /// Amount on money on the card var/credits = 0 /obj/item/holochip/Initialize(mapload, amount = 1) @@ -101,23 +103,21 @@ update_appearance() qdel(H) -/obj/item/holochip/AltClick(mob/user) - if(!user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH)) - return +/obj/item/holochip/click_alt(mob/user) if(loc != user) to_chat(user, span_warning("You must be holding the holochip to continue!")) - return FALSE + return CLICK_ACTION_BLOCKING var/split_amount = tgui_input_number(user, "How many credits do you want to extract from the holochip? (Max: [credits] cr)", "Holochip", max_value = credits) if(!split_amount || QDELETED(user) || QDELETED(src) || issilicon(user) || !usr.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH) || loc != user) - return + return CLICK_ACTION_BLOCKING var/new_credits = spend(split_amount, TRUE) - var/obj/item/holochip/H = new(user ? user : drop_location(), new_credits) + var/obj/item/holochip/chip = new(user ? user : drop_location(), new_credits) if(user) - if(!user.put_in_hands(H)) - H.forceMove(user.drop_location()) + if(!user.put_in_hands(chip)) + chip.forceMove(user.drop_location()) add_fingerprint(user) - H.add_fingerprint(user) to_chat(user, span_notice("You extract [split_amount] credits into a new holochip.")) + return CLICK_ACTION_SUCCESS /obj/item/holochip/emp_act(severity) . = ..() diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm index 4f6239acbe817..44f53df2c2b2d 100644 --- a/code/game/objects/items/debug_items.dm +++ b/code/game/objects/items/debug_items.dm @@ -21,7 +21,7 @@ /obj/item/debug/human_spawner/attack_self(mob/user) ..() - var/choice = input("Select a species", "Human Spawner", null) in GLOB.species_list + var/choice = input("Select a species", "Human Spawner", null) in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc)) selected_species = GLOB.species_list[choice] /obj/item/debug/omnitool @@ -168,4 +168,3 @@ var/turf/loc_turf = get_turf(src) for(var/spawn_atom in (choice == "No" ? typesof(path) : subtypesof(path))) new spawn_atom(loc_turf) - diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 7a661b640baa1..ac164df007c14 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -368,6 +368,7 @@ if(!req_defib) return RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(check_range)) + RegisterSignal(defib.loc, COMSIG_MOVABLE_MOVED, PROC_REF(check_range)) /obj/item/shockpaddles/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) . = ..() @@ -434,6 +435,7 @@ . = ..() if(user) UnregisterSignal(user, COMSIG_MOVABLE_MOVED) + UnregisterSignal(defib.loc, COMSIG_MOVABLE_MOVED) if(req_defib) if(user) to_chat(user, span_notice("The paddles snap back into the main unit.")) diff --git a/code/game/objects/items/devices/anomaly_releaser.dm b/code/game/objects/items/devices/anomaly_releaser.dm index a32220685ec39..0556b2a2afd49 100644 --- a/code/game/objects/items/devices/anomaly_releaser.dm +++ b/code/game/objects/items/devices/anomaly_releaser.dm @@ -28,6 +28,9 @@ if(!do_after(user, 3 SECONDS, target)) return + if(used) + return + var/obj/item/assembly/signaler/anomaly/core = target if(!core.anomaly_type) @@ -35,6 +38,7 @@ var/obj/effect/anomaly/anomaly = new core.anomaly_type(get_turf(core)) anomaly.stabilize() + log_combat(user, anomaly, "released", object = src, addition = "in [get_area(target)].") if(infinite) return diff --git a/code/game/objects/items/devices/battle_royale.dm b/code/game/objects/items/devices/battle_royale.dm new file mode 100644 index 0000000000000..ab871520465a5 --- /dev/null +++ b/code/game/objects/items/devices/battle_royale.dm @@ -0,0 +1,347 @@ +/// Global list of areas which are considered to be inside the same department for our purposes +GLOBAL_LIST_INIT(battle_royale_regions, list( + "Medical Bay" = list( + /area/station/command/heads_quarters/cmo, + /area/station/medical, + /area/station/security/checkpoint/medical, + ), + "Research Division" = list( + /area/station/command/heads_quarters/rd, + /area/station/security/checkpoint/science, + /area/station/science, + ), + "Engineering Bay" = list( + /area/station/command/heads_quarters/ce, + /area/station/engineering, + /area/station/maintenance/disposal/incinerator, + /area/station/security/checkpoint/engineering, + ), + "Cargo Bay" = list( + /area/station/cargo, + /area/station/command/heads_quarters/qm, + /area/station/security/checkpoint/supply, + ), +)) + +/// Quietly implants people with battle royale implants +/obj/item/royale_implanter + name = "royale implanter" + desc = "Subtly implants people with rumble royale implants, \ + preparing them to struggle for their life for the enjoyment of the Syndicate's paying audience. \ + Implants may cause irritation at site of implantation." + icon = 'icons/obj/medical/syringe.dmi' + icon_state = "nanite_hypo" + w_class = WEIGHT_CLASS_SMALL + /// Do we have a linked remote? Just to prevent headdesk moments + var/linked = FALSE + +/obj/item/royale_implanter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!isliving(interacting_with)) + if (!istype(interacting_with, /obj/item/royale_remote)) + return NONE + var/obj/item/royale_remote/remote = interacting_with + remote.link_implanter(src, user) + return ITEM_INTERACT_SUCCESS + if (!linked) + balloon_alert(user, "no linked remote!") + return ITEM_INTERACT_BLOCKING + if (DOING_INTERACTION_WITH_TARGET(user, interacting_with)) + balloon_alert(user, "busy!") + return ITEM_INTERACT_BLOCKING + var/mob/living/potential_winner = interacting_with + if (potential_winner.stat != CONSCIOUS) + balloon_alert(user, "target unconscious!") + return ITEM_INTERACT_BLOCKING + if (!potential_winner.mind) + balloon_alert(user, "target too boring!") + return ITEM_INTERACT_BLOCKING + log_combat(user, potential_winner, "tried to implant a battle royale implant into") + if (!do_after(user, 1.5 SECONDS, potential_winner)) + balloon_alert(user, "interrupted!") + return ITEM_INTERACT_BLOCKING + + var/obj/item/implant/explosive/battle_royale/encouragement_implant = new + if(!encouragement_implant.implant(potential_winner, user)) + qdel(encouragement_implant) // no balloon alert - feedback is usually provided by the implant + return ITEM_INTERACT_BLOCKING + + potential_winner.balloon_alert(user, "implanted") + SEND_SIGNAL(src, COMSIG_ROYALE_IMPLANTED, encouragement_implant) + return ITEM_INTERACT_SUCCESS + +/// Activates implants implanted by linked royale implanter +/obj/item/royale_remote + name = "royale remote" + desc = "A single use device which will activate any linked rumble royale implants, starting the show." + icon = 'icons/obj/devices/remote.dmi' + icon_state = "designator_syndicate" + w_class = WEIGHT_CLASS_SMALL + /// Minimum number of contestants we should have + var/required_contestants = 6 + /// List of implanters we are linked to + var/list/linked_implanters = list() + /// List of implants of lucky contestants + var/list/implanted_implants = list() + +/obj/item/royale_remote/Destroy(force) + linked_implanters = null + implanted_implants = null + return ..() + +/obj/item/royale_remote/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if (!istype(interacting_with, /obj/item/royale_implanter)) + return NONE + link_implanter(interacting_with) + return ITEM_INTERACT_SUCCESS + +/obj/item/royale_remote/attack_self(mob/user, modifiers) + . = ..() + if (.) + return + var/contestant_count = length(implanted_implants) + if (contestant_count < required_contestants) + balloon_alert(user, "[required_contestants - contestant_count] contestants needed!") + return + + GLOB.battle_royale_master.start_battle(implanted_implants) + + for (var/obj/implanter as anything in linked_implanters) + do_sparks(3, cardinal_only = FALSE, source = implanter) + qdel(implanter) + do_sparks(3, cardinal_only = FALSE, source = src) + qdel(src) + +/// Link to an implanter +/obj/item/royale_remote/proc/link_implanter(obj/item/royale_implanter/implanter, mob/user) + if (implanter in linked_implanters) + if (user) + balloon_alert(user, "already linked!") + return + + if (user) + balloon_alert(user, "link established") + + implanter.linked = TRUE + linked_implanters += implanter + RegisterSignal(implanter, COMSIG_ROYALE_IMPLANTED, PROC_REF(record_contestant)) + RegisterSignal(implanter, COMSIG_QDELETING, PROC_REF(implanter_destroyed)) + +/// Record that someone just got implanted +/obj/item/royale_remote/proc/record_contestant(obj/item/implanter, obj/item/implant) + SIGNAL_HANDLER + implanted_implants |= implant + RegisterSignal(implant, COMSIG_QDELETING, PROC_REF(implant_destroyed)) + +/// A linked implanter was destroyed +/obj/item/royale_remote/proc/implanter_destroyed(obj/item/implanter) + SIGNAL_HANDLER + linked_implanters -= implanter + +/obj/item/royale_remote/proc/implant_destroyed(obj/item/implant) + SIGNAL_HANDLER + implanted_implants -= implant + +GLOBAL_DATUM_INIT(battle_royale_master, /datum/battle_royale_master, new) + +/// Basically just exists to hold references to datums so that they don't GC +/datum/battle_royale_master + /// List of battle royale datums currently running + var/list/active_battles + +/// Start a new battle royale using a passed list of implants +/datum/battle_royale_master/proc/start_battle(list/competitors) + var/datum/battle_royale_controller/controller = new() + if (!controller.start(competitors)) + return FALSE + LAZYADD(active_battles, controller) + if (LAZYLEN(active_battles) == 1) + start_broadcasting_network(BATTLE_ROYALE_CAMERA_NET) + RegisterSignal(controller, COMSIG_QDELETING, PROC_REF(battle_ended)) + return TRUE + +/// Drop reference when it kills itself +/datum/battle_royale_master/proc/battle_ended(datum/source) + SIGNAL_HANDLER + LAZYREMOVE(active_battles, source) + if (!LAZYLEN(active_battles)) + stop_broadcasting_network(BATTLE_ROYALE_CAMERA_NET) + +/// Datum which controls the conflict +/datum/battle_royale_controller + /// Where is our battle taking place? + var/chosen_area + /// Is the battle currently in progress? + var/battle_running = TRUE + /// Should we let everyone know that someone has died? + var/announce_deaths = TRUE + /// List of implants involved + var/list/contestant_implants = list() + /// Ways to describe that someone has died + var/static/list/euphemisms = list( + "cashed their last paycheque.", + "didn't make it...", + "didn't make the cut.", + "had their head blown clean off!", + "has been killed!", + "has failed the challenge!", + "has passed away.", + "has died.", + "is in a better place now.", + "isn't going to be clocking in tomorrow!", + "just flatlined.", + "isn't today's winner.", + "seems to have exploded!", + "was just murdered on live tv!", + "won't be making it to retirement.", + "won't be getting back up after that one.", + ) + /// Ways to tell people not to salt in deadchat, surely effective + var/static/list/condolences = list( + "Better luck next time!", + "But stay tuned, there's still everything to play for!", + "Did you catch who did it?", + "It looked like that one really hurt...", + "Let's get that one on action replay!", + "Let's have a moment of silence, please.", + "Let's hope the next one does better.", + "Someone please notify their next of kin.", + "They had a good run.", + "Too bad!", + "What a shame!", + "What an upset!", + "What's going to happen next?", + "Who could have seen that coming?", + "Who will be next?", + ) + +/datum/battle_royale_controller/Destroy(force) + contestant_implants = null + return ..() + +/// Start a battle royale with the list of provided implants +/datum/battle_royale_controller/proc/start(list/implants, battle_time = 10 MINUTES) + chosen_area = pick(GLOB.battle_royale_regions) + for (var/obj/item/implant/explosive/battle_royale/contestant_implant in implants) + contestant_implant.start_battle(chosen_area, GLOB.battle_royale_regions[chosen_area]) + if (isnull(contestant_implant)) + continue // Might have exploded if it was removed from a person + RegisterSignal(contestant_implant, COMSIG_QDELETING, PROC_REF(implant_destroyed)) + contestant_implants |= contestant_implant + + if (length(contestant_implants) <= 1) + return FALSE // Well there's not much point is there + + priority_announce( + text = "Congratulations [station_name()], you have been chosen as the next site of the Rumble Royale! \n\ + Viewers across the sector will watch our [convert_integer_to_words(length(contestant_implants))] lucky contestants battle their way into your [chosen_area] and fight until only one is left standing! \n\ + If they don't make it in five minutes, they'll be disqualified. If you see one of our players struggling to get in, do lend them a hand... or don't, if you can live with the consequences! \n\ + As a gesture of gratitude, we will be providing our premium broadcast to your entertainment monitors at no cost so that you can watch the excitement. \n\ + Bystanders are advised not to intervene... but if you do, make it look good for the camera!", + title = "Rumble Royale Beginning", + sound = 'sound/machines/alarm.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + + for (var/obj/item/implant/explosive/battle_royale/contestant_implant as anything in contestant_implants) + contestant_implant.announce() + addtimer(CALLBACK(src, PROC_REF(limit_area)), battle_time / 2, TIMER_DELETE_ME) + addtimer(CALLBACK(src, PROC_REF(finish)), battle_time, TIMER_DELETE_ME) + return TRUE + +/// An implant was destroyed, hopefully because it exploded. Count how many competitors remain. +/datum/battle_royale_controller/proc/implant_destroyed(obj/item/implant/implant) + SIGNAL_HANDLER + contestant_implants -= implant + if (!battle_running) + return + + if (length(contestant_implants) <= 1) + announce_winner(implant) + else if (announce_deaths) + var/message = "" + if (isnull(implant.imp_in)) + message = "Looks like someone removed and destroyed their implant, that's cheating!" + else + message = "[implant.imp_in.real_name] [pick(euphemisms)] [pick(condolences)]" + priority_announce( + text = message, + title = "Rumble Royale Casualty Report", + sound = 'sound/misc/notice1.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + +/// There's only one person left, we have a winner! +/datum/battle_royale_controller/proc/announce_winner(obj/item/implant/losing_implant) + battle_running = FALSE + if (length(contestant_implants) > 1) + return + + var/message = "" + var/mob/living/loser = losing_implant.imp_in + var/obj/item/implant/winning_implant = pop(contestant_implants) + var/mob/living/winner = winning_implant?.imp_in + + if (isnull(winner) && isnull(loser)) + message = "Somehow, it seems like there's no winner tonight. What a disappointment!" + else + var/loser_text = isnull(loser) ? "With the disqualification of the other remaining contestant" : "With the death of [loser.real_name]" + var/winner_text = isnull(winner) ? "we must sadly announce that the would-be winner has also been disqualified. Such bad showmanship!" : "only [winner.real_name] remains. Congratulations, we have a winner!" + message = "[loser_text], [winner_text]" + + if (!isnull(winner)) + podspawn(list( + "target" = get_turf(winner), + "style" = STYLE_SYNDICATE, + "spawn" = /obj/item/food/roast_dinner, + )) + + priority_announce( + text = message, + title = "Rumble Royale Winner", + sound = 'sound/misc/notice1.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + + qdel(winning_implant) // You get to live! + winner?.mind?.remove_antag_datum(/datum/antagonist/survivalist/battle_royale) + qdel(src) + +/// Called halfway through the battle, if you've not made it to the designated battle zone we kill you +/datum/battle_royale_controller/proc/limit_area() + priority_announce( + text = "We're halfway done folks! And bad news to anyone who hasn't made it to the [chosen_area]... you're out!", + title = "Rumble Royale Update", + sound = 'sound/misc/notice1.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + + for (var/obj/item/implant/explosive/battle_royale/contestant_implant as anything in contestant_implants) + contestant_implant.limit_areas() + +/// Well you're out of time, bad luck +/datum/battle_royale_controller/proc/finish() + battle_running = FALSE + + priority_announce( + text = "Sorry remaining contestants, your time is up. \ + We're sorry to announce that this edition of Royal Rumble has no winner. \n\ + Better luck next time!", + title = "Rumble Royale Concluded", + sound = 'sound/misc/notice1.ogg', + has_important_message = TRUE, + sender_override = "Rumble Royale Pirate Broadcast Station", + color_override = "red", + ) + + for (var/obj/item/implant/explosive/battle_royale/contestant_implant as anything in contestant_implants) + contestant_implant.explode() + + qdel(src) diff --git a/code/game/objects/items/devices/desynchronizer.dm b/code/game/objects/items/devices/desynchronizer.dm index 0d9791c890ad4..cd7c745a168c4 100644 --- a/code/game/objects/items/devices/desynchronizer.dm +++ b/code/game/objects/items/devices/desynchronizer.dm @@ -9,11 +9,18 @@ lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 2.5, /datum/material/glass= SMALL_MATERIAL_AMOUNT * 5) - var/max_duration = 3000 - var/duration = 300 + interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING + /// Max time this can be set + var/max_duration = 300 SECONDS + /// Currently set time + var/duration = 30 SECONDS + /// Last world time var/last_use = 0 + /// world.time + (world.time - last_use) var/next_use = 0 + /// The current space time rift var/obj/effect/abstract/sync_holder/sync_holder + /// Timer obj for calling resync var/resync_timer /obj/item/desynchronizer/attack_self(mob/living/user) @@ -32,14 +39,13 @@ . += span_notice("Alt-click to customize the duration. Current duration: [DisplayTimeText(duration)].") . += span_notice("Can be used again to interrupt the effect early. The recharge time is the same as the time spent in desync.") -/obj/item/desynchronizer/AltClick(mob/living/user) - if(!user.can_perform_action(src, NEED_DEXTERITY)) - return +/obj/item/desynchronizer/click_alt(mob/living/user) var/new_duration = tgui_input_number(user, "Set the duration", "Desynchronizer", duration / 10, max_duration, 5) if(!new_duration || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, NEED_DEXTERITY)) - return + return CLICK_ACTION_BLOCKING duration = new_duration to_chat(user, span_notice("You set the duration to [DisplayTimeText(duration)].")) + return CLICK_ACTION_SUCCESS /obj/item/desynchronizer/proc/desync(mob/living/user) if(sync_holder) diff --git a/code/game/objects/items/devices/electroadaptive_pseudocircuit.dm b/code/game/objects/items/devices/electroadaptive_pseudocircuit.dm index de14a9e123fd6..d5d2e6c4d145a 100644 --- a/code/game/objects/items/devices/electroadaptive_pseudocircuit.dm +++ b/code/game/objects/items/devices/electroadaptive_pseudocircuit.dm @@ -1,3 +1,6 @@ +#define MIN_ENERGY_COST (0.01 * STANDARD_CELL_CHARGE) +#define MAX_ENERGY_COST (0.5 * STANDARD_CELL_CHARGE) + //Used by engineering cyborgs in place of generic circuits. /obj/item/electroadaptive_pseudocircuit name = "electroadaptive pseudocircuit" @@ -32,12 +35,12 @@ if(!R.cell) to_chat(R, span_warning("You need a power cell installed for that.")) return - if(!R.cell.use(circuit_cost)) - to_chat(R, span_warning("You don't have the energy for that (you need [display_energy(circuit_cost)].)")) - return if(recharging) to_chat(R, span_warning("[src] needs some time to recharge first.")) return + if(!R.cell.use(circuit_cost)) + to_chat(R, span_warning("You don't have the energy for that (you need [display_energy(circuit_cost)].)")) + return if(!circuits) to_chat(R, span_warning("You need more material. Use [src] on existing simple circuits to break them down.")) return @@ -46,8 +49,10 @@ circuits-- maptext = MAPTEXT(circuits) icon_state = "[initial(icon_state)]_recharging" - var/recharge_time = min(600, circuit_cost * 5) //40W of cost for one fabrication = 20 seconds of recharge time; this is to prevent spamming - addtimer(CALLBACK(src, PROC_REF(recharge)), recharge_time) + var/recharge_time = (circuit_cost - MIN_ENERGY_COST) / (MAX_ENERGY_COST - MIN_ENERGY_COST) + recharge_time = clamp(recharge_time, 0, 1) + recharge_time = (5 SECONDS) + (55 SECONDS) * recharge_time //anywhere between 5 seconds to 1 minute + addtimer(CALLBACK(src, PROC_REF(recharge)), ROUND_UP(recharge_time)) return TRUE //The actual circuit magic itself is done on a per-object basis /obj/item/electroadaptive_pseudocircuit/afterattack(atom/target, mob/living/user, proximity) @@ -68,3 +73,6 @@ playsound(src, 'sound/machines/chime.ogg', 25, TRUE) recharging = FALSE icon_state = initial(icon_state) + +#undef MIN_ENERGY_COST +#undef MAX_ENERGY_COST diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index c92e3b7e6598a..d0b72fe2de8e0 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -666,6 +666,9 @@ light_color = "#ffcc66" light_system = OVERLAY_LIGHT +/obj/item/flashlight/lantern/on + start_on = TRUE + /obj/item/flashlight/lantern/heirloom_moth name = "old lantern" desc = "An old lantern that has seen plenty of use." diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index 6e152c3366121..db2d0d820ba3a 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -110,12 +110,11 @@ to_chat(user, span_notice("[icon2html(src, user)] [isliving(target) ? "Subject" : "Target"] is free of radioactive contamination.")) -/obj/item/geiger_counter/AltClick(mob/living/user) - if(!istype(user) || !user.can_perform_action(src)) - return ..() +/obj/item/geiger_counter/click_alt(mob/living/user) if(!scanning) to_chat(usr, span_warning("[src] must be on to reset its radiation level!")) - return + return CLICK_ACTION_BLOCKING to_chat(usr, span_notice("You flush [src]'s radiation counts, resetting it to normal.")) last_perceived_radiation_danger = null update_appearance(UPDATE_ICON) + return CLICK_ACTION_SUCCESS diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index e670fdec914f7..fc6c967ec1f28 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -70,7 +70,7 @@ /obj/item/laser_pointer/infinite_range/Initialize(mapload) . = ..() - diode = new /obj/item/stock_parts/servo/femto + diode = new /obj/item/stock_parts/micro_laser/quadultra /obj/item/laser_pointer/screwdriver_act(mob/living/user, obj/item/tool) if(diode) @@ -80,14 +80,11 @@ diode = null return TRUE -/obj/item/laser_pointer/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . +/obj/item/laser_pointer/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(isnull(crystal_lens)) - return . + return NONE if(tool_behaviour != TOOL_WIRECUTTER && tool_behaviour != TOOL_HEMOSTAT) - return . + return NONE tool.play_tool_sound(src) balloon_alert(user, "removed crystal lens") crystal_lens.forceMove(drop_location()) diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index d469538bf1b56..1262abb141f47 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -150,7 +150,7 @@ name = "electronic multitool" desc = "Optimised version of a regular multitool. Streamlines processes handled by its internal microchip." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "multitool_cyborg" + icon_state = "toolkit_engiborg_multitool" toolspeed = 0.5 #undef PROXIMITY_NEAR diff --git a/code/game/objects/items/devices/polycircuit.dm b/code/game/objects/items/devices/polycircuit.dm index 5b7fd42d6f6bd..e3faa67823883 100644 --- a/code/game/objects/items/devices/polycircuit.dm +++ b/code/game/objects/items/devices/polycircuit.dm @@ -40,7 +40,7 @@ if("APC") circuit_type = /obj/item/electronics/apc to_chat(user, span_notice("You spot your circuit, and carefully attempt to remove it from [src], hold still!")) - if(do_after(user, 30, target = user)) + if(do_after(user, 3 SECONDS, target = user)) if(!src || QDELETED(src))//Sanity Check. return var/returned_circuit = new circuit_type(src) diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 1b000ea2f9160..1925737143e9d 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -171,7 +171,7 @@ if(istype(terminal.master, /obj/machinery/power/apc)) var/obj/machinery/power/apc/apc = terminal.master if(apc.operating && apc.cell) - drained += 0.001 * apc.cell.use(50 KILO JOULES, force = TRUE) + drained += 0.001 * apc.cell.use(0.05 * STANDARD_CELL_CHARGE, force = TRUE) internal_heat += drained /obj/item/powersink/process() diff --git a/code/game/objects/items/devices/quantum_keycard.dm b/code/game/objects/items/devices/quantum_keycard.dm index 6c718cc9a431e..ccaef00cfc63e 100644 --- a/code/game/objects/items/devices/quantum_keycard.dm +++ b/code/game/objects/items/devices/quantum_keycard.dm @@ -10,6 +10,8 @@ righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi' w_class = WEIGHT_CLASS_TINY obj_flags = UNIQUE_RENAME + interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING + /// The linked quantum pad var/obj/machinery/quantumpad/qpad /// where the pad is located and what color the card will become @@ -40,13 +42,12 @@ else . += span_notice("Insert [src] into an active quantum pad to link it.") -/obj/item/quantum_keycard/AltClick(mob/living/user) - if(!istype(user) || !user.can_perform_action(src, NEED_DEXTERITY)) - return +/obj/item/quantum_keycard/click_alt(mob/living/user) to_chat(user, span_notice("You start pressing [src]'s unlink button...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) to_chat(user, span_notice("The keycard beeps twice and disconnects the quantum link.")) set_pad() + return CLICK_ACTION_SUCCESS /obj/item/quantum_keycard/proc/set_pad(obj/machinery/quantumpad/new_pad) qpad = new_pad diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm index 426e673437ef5..af19c6cd4f5da 100644 --- a/code/game/objects/items/devices/radio/electropack.dm +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -64,7 +64,7 @@ if(shock_cooldown) return shock_cooldown = TRUE - addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100) + addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 10 SECONDS) var/mob/living/L = loc step(L, pick(GLOB.cardinals)) diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index b7a96d777ef1f..88c9251d5b2bc 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -21,7 +21,7 @@ if(LAZYLEN(channels) || translate_binary) var/list/examine_text_list = list() for(var/i in channels) - examine_text_list += "[GLOB.channel_tokens[i]] - [lowertext(i)]" + examine_text_list += "[GLOB.channel_tokens[i]] - [LOWER_TEXT(i)]" if(translate_binary) examine_text_list += "[GLOB.channel_tokens[MODE_BINARY]] - [MODE_BINARY]" diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 98f4282c62677..ae806b594e1fd 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -54,9 +54,9 @@ GLOBAL_LIST_INIT(channel_tokens, list( if(length(channels)) for(var/i in 1 to length(channels)) if(i == 1) - avail_chans += "use [MODE_TOKEN_DEPARTMENT] or [GLOB.channel_tokens[channels[i]]] for [lowertext(channels[i])]" + avail_chans += "use [MODE_TOKEN_DEPARTMENT] or [GLOB.channel_tokens[channels[i]]] for [LOWER_TEXT(channels[i])]" else - avail_chans += "use [GLOB.channel_tokens[channels[i]]] for [lowertext(channels[i])]" + avail_chans += "use [GLOB.channel_tokens[channels[i]]] for [LOWER_TEXT(channels[i])]" . += span_notice("A small screen on the headset displays the following available frequencies:\n[english_list(avail_chans)].") if(command) @@ -447,9 +447,9 @@ GLOBAL_LIST_INIT(channel_tokens, list( // And grant all the languages we definitely should know now grant_headset_languages(mob_loc) -/obj/item/radio/headset/AltClick(mob/living/user) - if(!istype(user) || !Adjacent(user) || user.incapacitated()) - return - if (command) - use_command = !use_command - to_chat(user, span_notice("You toggle high-volume mode [use_command ? "on" : "off"].")) +/obj/item/radio/headset/click_alt(mob/living/user) + if (!command) + return CLICK_ACTION_BLOCKING + use_command = !use_command + to_chat(user, span_notice("You toggle high-volume mode [use_command ? "on" : "off"].")) + return CLICK_ACTION_SUCCESS diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index bf662fcc1b90a..ffb4f486cb89d 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -363,7 +363,7 @@ // Non-subspace radios will check in a couple of seconds, and if the signal // was never received, send a mundane broadcast (no headsets). - addtimer(CALLBACK(src, PROC_REF(backup_transmission), signal), 20) + addtimer(CALLBACK(src, PROC_REF(backup_transmission), signal), 2 SECONDS) /obj/item/radio/proc/backup_transmission(datum/signal/subspace/vocal/signal) var/turf/T = get_turf(src) @@ -543,7 +543,7 @@ for (var/ch_name in channels) channels[ch_name] = 0 set_on(FALSE) - addtimer(CALLBACK(src, PROC_REF(end_emp_effect), curremp), 200) + addtimer(CALLBACK(src, PROC_REF(end_emp_effect), curremp), 20 SECONDS) /obj/item/radio/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!")) diff --git a/code/game/objects/items/devices/scanners/autopsy_scanner.dm b/code/game/objects/items/devices/scanners/autopsy_scanner.dm index 16f90489b20e3..c5d33b7422656 100644 --- a/code/game/objects/items/devices/scanners/autopsy_scanner.dm +++ b/code/game/objects/items/devices/scanners/autopsy_scanner.dm @@ -13,7 +13,7 @@ custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT*2) custom_price = PAYCHECK_COMMAND -/obj/item/autopsy_scanner/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/autopsy_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) return NONE if(!user.can_read(src) || user.is_blind()) diff --git a/code/game/objects/items/devices/scanners/gas_analyzer.dm b/code/game/objects/items/devices/scanners/gas_analyzer.dm index 5a1be36b37ea8..e452c550cdfa7 100644 --- a/code/game/objects/items/devices/scanners/gas_analyzer.dm +++ b/code/game/objects/items/devices/scanners/gas_analyzer.dm @@ -17,10 +17,16 @@ tool_behaviour = TOOL_ANALYZER custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT * 0.3, /datum/material/glass=SMALL_MATERIAL_AMOUNT * 0.2) grind_results = list(/datum/reagent/mercury = 5, /datum/reagent/iron = 5, /datum/reagent/silicon = 5) + interaction_flags_click = NEED_LITERACY|NEED_LIGHT|ALLOW_RESTING + /// Boolean whether this has a CD var/cooldown = FALSE - var/cooldown_time = 250 - var/barometer_accuracy // 0 is the best accuracy. + /// The time in deciseconds + var/cooldown_time = 25 SECONDS + /// 0 is best accuracy + var/barometer_accuracy + /// Cached gasmix data from ui_interact var/list/last_gasmix_data + /// Max scan distance var/ranged_scan_distance = 1 /obj/item/analyzer/Initialize(mapload) @@ -53,19 +59,14 @@ user.visible_message(span_suicide("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!")) return BRUTELOSS -/obj/item/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens - ..() - - if(!user.can_perform_action(src, NEED_LITERACY|NEED_LIGHT)) - return - +/obj/item/analyzer/click_alt(mob/user) //Barometer output for measuring when the next storm happens if(cooldown) to_chat(user, span_warning("[src]'s barometer function is preparing itself.")) - return + return CLICK_ACTION_BLOCKING var/turf/T = get_turf(user) if(!T) - return + return CLICK_ACTION_BLOCKING playsound(src, 'sound/effects/pop.ogg', 100) var/area/user_area = T.loc @@ -73,7 +74,7 @@ if(!user_area.outdoors) to_chat(user, span_warning("[src]'s barometer function won't work indoors!")) - return + return CLICK_ACTION_BLOCKING for(var/V in SSweather.processing) var/datum/weather/W = V @@ -84,7 +85,7 @@ if(ongoing_weather) if((ongoing_weather.stage == MAIN_STAGE) || (ongoing_weather.stage == WIND_DOWN_STAGE)) to_chat(user, span_warning("[src]'s barometer function can't trace anything while the storm is [ongoing_weather.stage == MAIN_STAGE ? "already here!" : "winding down."]")) - return + return CLICK_ACTION_BLOCKING to_chat(user, span_notice("The next [ongoing_weather] will hit in [butchertime(ongoing_weather.next_hit_time - world.time)].")) if(ongoing_weather.aesthetic) @@ -98,6 +99,7 @@ to_chat(user, span_warning("[src]'s barometer function says a storm will land in approximately [butchertime(fixed)].")) cooldown = TRUE addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/analyzer, ping)), cooldown_time) + return CLICK_ACTION_SUCCESS /obj/item/analyzer/proc/ping() if(isliving(loc)) @@ -159,7 +161,7 @@ var/list/airs = islist(mixture) ? mixture : list(mixture) var/list/new_gasmix_data = list() for(var/datum/gas_mixture/air as anything in airs) - var/mix_name = capitalize(lowertext(target.name)) + var/mix_name = capitalize(LOWER_TEXT(target.name)) if(airs.len != 1) //not a unary gas mixture mix_name += " - Node [airs.Find(air)]" new_gasmix_data += list(gas_mixture_parser(air, mix_name)) @@ -184,7 +186,7 @@ var/list/airs = islist(mixture) ? mixture : list(mixture) for(var/datum/gas_mixture/air as anything in airs) - var/mix_name = capitalize(lowertext(target.name)) + var/mix_name = capitalize(LOWER_TEXT(target.name)) if(airs.len > 1) //not a unary gas mixture var/mix_number = airs.Find(air) message += span_boldnotice("Node [mix_number]") diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 83ea668a9fb28..10c301af1c63d 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -20,8 +20,12 @@ throw_speed = 3 throw_range = 7 custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT *2) + interaction_flags_click = NEED_LITERACY|NEED_LIGHT|ALLOW_RESTING + /// Verbose/condensed var/mode = SCANNER_VERBOSE + /// HEALTH/WOUND var/scanmode = SCANMODE_HEALTH + /// Advanced health analyzer var/advanced = FALSE custom_price = PAYCHECK_COMMAND /// If this analyzer will give a bonus to wound treatments apon woundscan. @@ -51,7 +55,7 @@ if(SCANMODE_WOUND) to_chat(user, span_notice("You switch the health analyzer to report extra info on wounds.")) -/obj/item/healthanalyzer/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/healthanalyzer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) return NONE if(!user.can_read(src) || user.is_blind()) @@ -89,7 +93,7 @@ add_fingerprint(user) -/obj/item/healthanalyzer/interact_with_atom_secondary(atom/interacting_with, mob/living/user) +/obj/item/healthanalyzer/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) return NONE if(!user.can_read(src) || user.is_blind()) @@ -469,17 +473,13 @@ // we handled the last
so we don't need handholding to_chat(user, examine_block(jointext(render_list, "")), trailing_newline = FALSE, type = MESSAGE_TYPE_INFO) -/obj/item/healthanalyzer/AltClick(mob/user) - ..() - - if(!user.can_perform_action(src, NEED_LITERACY|NEED_LIGHT) || user.is_blind()) - return - +/obj/item/healthanalyzer/click_alt(mob/user) if(mode == SCANNER_NO_MODE) - return + return CLICK_ACTION_BLOCKING mode = !mode to_chat(user, mode == SCANNER_VERBOSE ? "The scanner now shows specific limb damage." : "The scanner no longer shows limb damage.") + return CLICK_ACTION_SUCCESS /obj/item/healthanalyzer/advanced name = "advanced health analyzer" @@ -576,7 +576,7 @@ /obj/item/healthanalyzer/simple/proc/violence_damage(mob/living/user) user.adjustBruteLoss(4) -/obj/item/healthanalyzer/simple/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/healthanalyzer/simple/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) return NONE if(!user.can_read(src) || user.is_blind()) diff --git a/code/game/objects/items/devices/scanners/sequence_scanner.dm b/code/game/objects/items/devices/scanners/sequence_scanner.dm index 3d212cbb771b2..4c4c202f26fbd 100644 --- a/code/game/objects/items/devices/scanners/sequence_scanner.dm +++ b/code/game/objects/items/devices/scanners/sequence_scanner.dm @@ -19,7 +19,7 @@ var/list/discovered = list() //hit a dna console to update the scanners database var/list/buffer var/ready = TRUE - var/cooldown = 200 + var/cooldown = (20 SECONDS) /// genetic makeup data that's scanned var/list/genetic_makeup_buffer = list() @@ -29,7 +29,7 @@ if(LAZYLEN(genetic_makeup_buffer) > 0) . += span_notice("It has the genetic makeup of \"[genetic_makeup_buffer["name"]]\" stored inside its buffer") -/obj/item/sequence_scanner/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/sequence_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) return NONE @@ -46,7 +46,7 @@ user.visible_message(span_notice("[user] fails to analyze [interacting_with]'s genetic sequence."), span_warning("[interacting_with] has no readable genetic sequence!")) return ITEM_INTERACT_BLOCKING -/obj/item/sequence_scanner/interact_with_atom_secondary(atom/interacting_with, mob/living/user) +/obj/item/sequence_scanner/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) return NONE @@ -104,7 +104,7 @@ buffer = LAZYLISTDUPLICATE(target.dna.mutation_index) var/list/active_mutations = list() for(var/datum/mutation/human/mutation in target.dna.mutations) - LAZYOR(buffer, mutation.type) + LAZYSET(buffer, mutation.type, GET_SEQUENCE(mutation.type)) active_mutations.Add(mutation.type) to_chat(user, span_notice("Subject [target.name]'s DNA sequence has been saved to buffer.")) diff --git a/code/game/objects/items/devices/scanners/slime_scanner.dm b/code/game/objects/items/devices/scanners/slime_scanner.dm index 3c32b6cfcf742..7f7453bb4b9d7 100644 --- a/code/game/objects/items/devices/scanners/slime_scanner.dm +++ b/code/game/objects/items/devices/scanners/slime_scanner.dm @@ -13,7 +13,7 @@ throw_range = 7 custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*0.30, /datum/material/glass=SMALL_MATERIAL_AMOUNT * 0.20) -/obj/item/slime_scanner/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/slime_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) return NONE if(!user.can_read(src) || user.is_blind()) diff --git a/code/game/objects/items/devices/swapper.dm b/code/game/objects/items/devices/swapper.dm index 1022e72cc443d..dee9198c93296 100644 --- a/code/game/objects/items/devices/swapper.dm +++ b/code/game/objects/items/devices/swapper.dm @@ -8,9 +8,12 @@ item_flags = NOBLUDGEON lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' - - var/cooldown = 300 + interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING + /// Cooldown for usage + var/cooldown = 30 SECONDS + /// Next available time var/next_use = 0 + /// Swapper linked to this obj var/obj/item/swapper/linked_swapper /obj/item/swapper/Destroy() @@ -55,7 +58,7 @@ var/mob/holder = linked_swapper.loc to_chat(holder, span_notice("[linked_swapper] starts buzzing.")) next_use = world.time + cooldown //only the one used goes on cooldown - addtimer(CALLBACK(src, PROC_REF(swap), user), 25) + addtimer(CALLBACK(src, PROC_REF(swap), user), 2.5 SECONDS) /obj/item/swapper/examine(mob/user) . = ..() @@ -66,15 +69,14 @@ else . += span_notice("Not Linked. Use on another quantum spin inverter to establish a quantum link.") -/obj/item/swapper/AltClick(mob/living/user) - if(!user.can_perform_action(src, NEED_DEXTERITY)) - return +/obj/item/swapper/click_alt(mob/living/user) to_chat(user, span_notice("You break the current quantum link.")) if(!QDELETED(linked_swapper)) linked_swapper.linked_swapper = null linked_swapper.update_appearance() linked_swapper = null update_appearance() + return CLICK_ACTION_SUCCESS //Gets the topmost teleportable container /obj/item/swapper/proc/get_teleportable_container() diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index c686eeb04a7a7..d30f379197eea 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -61,11 +61,9 @@ . += span_notice("The wire panel is [open_panel ? "opened" : "closed"]. The display reads:") . += "[readout()]" -/obj/item/taperecorder/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return +/obj/item/taperecorder/click_alt(mob/user) play() + return CLICK_ACTION_SUCCESS /obj/item/taperecorder/proc/update_available_icons() icons_available = list() diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 8e8f2578fa4b1..7e6ee077fcea9 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -76,7 +76,7 @@ effective or pretty fucking useless. var/intensity = 10 // how much damage the radiation does var/wavelength = 10 // time it takes for the radiation to kick in, in seconds -/obj/item/healthanalyzer/rad_laser/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/healthanalyzer/rad_laser/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!stealth || !irradiate) . = ..() diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 4684ce81b081e..8f838c0c0412f 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -60,7 +60,7 @@ if(user.dna.check_mutation(/datum/mutation/human/hulk)) to_chat(user, span_warning("You lack the grace to wield this!")) return COMPONENT_TWOHANDED_BLOCK_WIELD - w_class = w_class_on + update_weight_class(w_class_on) hitsound = 'sound/weapons/blade1.ogg' START_PROCESSING(SSobj, src) set_light_on(TRUE) @@ -68,7 +68,7 @@ /// Triggered on unwield of two handed item /// switch hitsounds /obj/item/dualsaber/proc/on_unwield(obj/item/source, mob/living/carbon/user) - w_class = initial(w_class) + update_weight_class(initial(w_class)) hitsound = SFX_SWING_HIT STOP_PROCESSING(SSobj, src) set_light_on(FALSE) diff --git a/code/game/objects/items/dyespray.dm b/code/game/objects/items/dyespray.dm index fd198ec1c40e3..b64f15fe69073 100644 --- a/code/game/objects/items/dyespray.dm +++ b/code/game/objects/items/dyespray.dm @@ -27,7 +27,7 @@ if(!beard_or_hair || !user.can_perform_action(src, NEED_DEXTERITY)) return - var/list/choices = beard_or_hair == "Hair" ? GLOB.hair_gradients_list : GLOB.facial_hair_gradients_list + var/list/choices = beard_or_hair == "Hair" ? SSaccessories.hair_gradients_list : SSaccessories.facial_hair_gradients_list var/new_grad_style = tgui_input_list(user, "Choose a color pattern", "Character Preference", choices) if(isnull(new_grad_style)) return diff --git a/code/game/objects/items/emags.dm b/code/game/objects/items/emags.dm index c404cda265924..7882018701e4d 100644 --- a/code/game/objects/items/emags.dm +++ b/code/game/objects/items/emags.dm @@ -45,7 +45,7 @@ user.visible_message(span_notice("[user] shows you: [icon2html(src, viewers(user))] [name]."), span_notice("You show [src].")) add_fingerprint(user) -/obj/item/card/emagfake/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/card/emagfake/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) playsound(src, 'sound/items/bikehorn.ogg', 50, TRUE) return ITEM_INTERACT_SKIP_TO_ATTACK // So it does the attack animation. @@ -53,7 +53,7 @@ . = ..() type_blacklist = list(typesof(/obj/machinery/door/airlock) + typesof(/obj/machinery/door/window/) + typesof(/obj/machinery/door/firedoor) - typesof(/obj/machinery/door/airlock/tram)) //list of all typepaths that require a specialized emag to hack. -/obj/item/card/emag/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/card/emag/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!can_emag(interacting_with, user)) return ITEM_INTERACT_BLOCKING log_combat(user, interacting_with, "attempted to emag") diff --git a/code/game/objects/items/etherealdiscoball.dm b/code/game/objects/items/etherealdiscoball.dm index 0a95e4bbc73e3..fe066bd1bf572 100644 --- a/code/game/objects/items/etherealdiscoball.dm +++ b/code/game/objects/items/etherealdiscoball.dm @@ -41,10 +41,10 @@ TurnOn() to_chat(user, span_notice("You turn the disco ball on!")) -/obj/structure/etherealball/AltClick(mob/living/carbon/human/user) - . = ..() +/obj/structure/etherealball/click_alt(mob/living/carbon/human/user) set_anchored(!anchored) to_chat(user, span_notice("You [anchored ? null : "un"]lock the disco ball.")) + return CLICK_ACTION_SUCCESS /obj/structure/etherealball/proc/TurnOn() TurnedOn = TRUE //Same diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index b0189a0c4ecef..aded3d06ccfad 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -18,6 +18,7 @@ attack_verb_simple = list("slam", "whack", "bash", "thunk", "batter", "bludgeon", "thrash") dog_fashion = /datum/dog_fashion/back resistance_flags = FIRE_PROOF + interaction_flags_click = NEED_DEXTERITY|NEED_HANDS /// The max amount of water this extinguisher can hold. var/max_water = 50 /// Does the welder extinguisher start with water. @@ -124,6 +125,7 @@ tanktype = /obj/structure/reagent_dispensers/foamtank sprite_name = "foam_extinguisher" precision = TRUE + max_water = 100 /obj/item/extinguisher/advanced/empty starting_water = FALSE @@ -215,7 +217,7 @@ if(user.buckled && isobj(user.buckled) && !user.buckled.anchored) var/obj/B = user.buckled var/movementdirection = REVERSE_DIR(direction) - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/extinguisher, move_chair), B, movementdirection), 1) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/extinguisher, move_chair), B, movementdirection), 0.1 SECONDS) else user.newtonian_move(REVERSE_DIR(direction)) @@ -256,7 +258,7 @@ //Chair movement loop /obj/item/extinguisher/proc/move_chair(obj/buckled_object, movementdirection) - var/datum/move_loop/loop = SSmove_manager.move(buckled_object, movementdirection, 1, timeout = 9, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move(buckled_object, movementdirection, 1, timeout = 9, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) //This means the chair slowing down is dependant on the extinguisher existing, which is weird //Couldn't figure out a better way though RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(manage_chair_speed)) @@ -269,13 +271,12 @@ if(1 to 3) source.delay = 3 -/obj/item/extinguisher/AltClick(mob/user) - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) - return +/obj/item/extinguisher/click_alt(mob/user) if(!user.is_holding(src)) to_chat(user, span_notice("You must be holding the [src] in your hands do this!")) - return + return CLICK_ACTION_BLOCKING EmptyExtinguisher(user) + return CLICK_ACTION_SUCCESS /obj/item/extinguisher/proc/EmptyExtinguisher(mob/user) if(loc == user && reagents.total_volume) diff --git a/code/game/objects/items/fireaxe.dm b/code/game/objects/items/fireaxe.dm index 901e506194e8a..2859b4d3b2c16 100644 --- a/code/game/objects/items/fireaxe.dm +++ b/code/game/objects/items/fireaxe.dm @@ -86,3 +86,13 @@ tool_behaviour = TOOL_CROWBAR toolspeed = 1 usesound = 'sound/items/crowbar.ogg' + +//boarding axe +/obj/item/fireaxe/boardingaxe + icon_state = "boarding_axe0" + base_icon_state = "boarding_axe" + name = "boarding axe" + desc = "A hulking cleaver that feels like a burden just looking at it. Seems excellent at halving obstacles like windows, airlocks, barricades and people." + force_unwielded = 5 + force_wielded = 30 + demolition_mod = 3 diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm index 346b8597533ef..be89193ba7edd 100644 --- a/code/game/objects/items/flamethrower.dm +++ b/code/game/objects/items/flamethrower.dm @@ -20,6 +20,7 @@ light_range = 2 light_power = 2 light_on = FALSE + interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING var/status = FALSE var/lit = FALSE //on or off var/operating = FALSE//cooldown @@ -158,12 +159,15 @@ /obj/item/flamethrower/attack_self(mob/user) toggle_igniter(user) -/obj/item/flamethrower/AltClick(mob/user) - if(ptank && isliving(user) && user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) - user.put_in_hands(ptank) - ptank = null - to_chat(user, span_notice("You remove the plasma tank from [src]!")) - update_appearance() +/obj/item/flamethrower/click_alt(mob/user) + if(isnull(ptank)) + return NONE + + user.put_in_hands(ptank) + ptank = null + to_chat(user, span_notice("You remove the plasma tank from [src]!")) + update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/flamethrower/examine(mob/user) . = ..() @@ -219,10 +223,6 @@ sleep(0.1 SECONDS) previousturf = T operating = FALSE - for(var/mob/M in viewers(1, loc)) - if((M.client && M.machine == src)) - attack_self(M) - /obj/item/flamethrower/proc/default_ignite(turf/target, release_amount = 0.05) //TODO: DEFERRED Consider checking to make sure tank pressure is high enough before doing this... diff --git a/code/game/objects/items/food/egg.dm b/code/game/objects/items/food/egg.dm index 356059a097ab1..62113e02e7780 100644 --- a/code/game/objects/items/food/egg.dm +++ b/code/game/objects/items/food/egg.dm @@ -144,12 +144,15 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) /obj/item/food/egg/blue icon_state = "egg-blue" inhand_icon_state = "egg-blue" + /obj/item/food/egg/green icon_state = "egg-green" inhand_icon_state = "egg-green" + /obj/item/food/egg/mime icon_state = "egg-mime" inhand_icon_state = "egg-mime" + /obj/item/food/egg/orange icon_state = "egg-orange" inhand_icon_state = "egg-orange" diff --git a/code/game/objects/items/granters/crafting/pipegun.dm b/code/game/objects/items/granters/crafting/pipegun.dm index 8d331b2286d00..e54439350dab0 100644 --- a/code/game/objects/items/granters/crafting/pipegun.dm +++ b/code/game/objects/items/granters/crafting/pipegun.dm @@ -11,6 +11,7 @@ "Did he drop this into a moisture trap? Yuck.", "Toolboxing techniques, huh? I kinda just want to know how to make the gun.", "What the hell does he mean by 'ancient warrior tradition'?", + "...the true masters of this place are not those who merely inhabit it...", ) /obj/item/book/granter/crafting_recipe/dusting/laser_musket_prime diff --git a/code/game/objects/items/granters/magic/_spell_granter.dm b/code/game/objects/items/granters/magic/_spell_granter.dm index e1ca6352293db..21a69248a1407 100644 --- a/code/game/objects/items/granters/magic/_spell_granter.dm +++ b/code/game/objects/items/granters/magic/_spell_granter.dm @@ -91,4 +91,4 @@ spell_options -= spell granted_action = pick(spell_options) - action_name = lowertext(initial(granted_action.name)) + action_name = LOWER_TEXT(initial(granted_action.name)) diff --git a/code/game/objects/items/grenades/_grenade.dm b/code/game/objects/items/grenades/_grenade.dm index e7e592eabacec..4c737ed53f3cb 100644 --- a/code/game/objects/items/grenades/_grenade.dm +++ b/code/game/objects/items/grenades/_grenade.dm @@ -63,11 +63,9 @@ sleep(det_time)//so you dont die instantly return dud_flags ? SHAME : BRUTELOSS -/obj/item/grenade/deconstruct(disassembled = TRUE) +/obj/item/grenade/atom_deconstruct(disassembled = TRUE) if(!disassembled) detonate() - if(!QDELETED(src)) - qdel(src) /obj/item/grenade/apply_fantasy_bonuses(bonus) . = ..() diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index ea758c8993e1d..c1cf8c1010d86 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -12,11 +12,19 @@ display_timer = FALSE w_class = WEIGHT_CLASS_SMALL gender = PLURAL + /// What the charge is stuck to var/atom/target = null + /// C4 overlay to put on target var/mutable_appearance/plastic_overlay + /// Do we do a directional explosion when target is a a dense atom? var/directional = FALSE + /// When doing a directional explosion, what arc does the explosion cover + var/directional_arc = 120 + /// For directional charges, which cardinal direction is the charge facing? var/aim_dir = NORTH + /// List of explosion radii (DEV, HEAVY, LIGHT) var/boom_sizes = list(0, 0, 3) + /// Do we apply the full force of a heavy ex_act() to mob targets var/full_damage_on_mobs = FALSE /// Minimum timer for c4 charges var/minimum_timer = 10 @@ -68,18 +76,20 @@ . = ..() var/turf/location + var/target_density if(target) if(!QDELETED(target)) location = get_turf(target) + target_density = target.density // We're about to blow target up, so need to save this value for later target.cut_overlay(plastic_overlay, TRUE) if(!ismob(target) || full_damage_on_mobs) EX_ACT(target, EXPLODE_HEAVY, target) else location = get_turf(src) if(location) - if(directional && target?.density) - var/turf/turf = get_step(location, aim_dir) - explosion(get_step(turf, aim_dir), devastation_range = boom_sizes[1], heavy_impact_range = boom_sizes[2], light_impact_range = boom_sizes[3], explosion_cause = src) + if(directional && target_density) + var/angle = dir2angle(aim_dir) + explosion(location, devastation_range = boom_sizes[1], heavy_impact_range = boom_sizes[2], light_impact_range = boom_sizes[3], explosion_cause = src, explosion_direction = angle, explosion_arc = directional_arc) else explosion(location, devastation_range = boom_sizes[1], heavy_impact_range = boom_sizes[2], light_impact_range = boom_sizes[3], explosion_cause = src) qdel(src) @@ -111,7 +121,7 @@ to_chat(user, span_notice("You start planting [src]. The timer is set to [det_time]...")) - if(do_after(user, 30, target = bomb_target)) + if(do_after(user, 3 SECONDS, target = bomb_target)) if(!user.temporarilyRemoveItemFromInventory(src)) return . target = bomb_target diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 2255afe10541c..10a90b3dbdcef 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -41,7 +41,7 @@ if(!istype(sucker) || !in_range(owner, sucker)) return - addtimer(CALLBACK(src, PROC_REF(waitASecond), owner, sucker), 4) + addtimer(CALLBACK(src, PROC_REF(waitASecond), owner, sucker), 0.4 SECONDS) /// Stage 2: Fear sets in /obj/item/hand_item/circlegame/proc/waitASecond(mob/living/owner, mob/living/sucker) @@ -50,10 +50,10 @@ if(owner == sucker) // big mood to_chat(owner, span_danger("Wait a second... you just looked at your own [src.name]!")) - addtimer(CALLBACK(src, PROC_REF(selfGottem), owner), 10) + addtimer(CALLBACK(src, PROC_REF(selfGottem), owner), 1 SECONDS) else to_chat(sucker, span_danger("Wait a second... was that a-")) - addtimer(CALLBACK(src, PROC_REF(GOTTEM), owner, sucker), 6) + addtimer(CALLBACK(src, PROC_REF(GOTTEM), owner, sucker), 0.6 SECONDS) /// Stage 3A: We face our own failures /obj/item/hand_item/circlegame/proc/selfGottem(mob/living/owner) @@ -491,7 +491,7 @@ blown_kiss.original = target blown_kiss.fired_from = user blown_kiss.firer = user // don't hit ourself that would be really annoying - blown_kiss.impacted = list(user = TRUE) // just to make sure we don't hit the wearer + blown_kiss.impacted = list(WEAKREF(user) = TRUE) // just to make sure we don't hit the wearer blown_kiss.preparePixelProjectile(target, user) blown_kiss.fire() qdel(src) @@ -517,7 +517,7 @@ blown_kiss.original = taker blown_kiss.fired_from = offerer blown_kiss.firer = offerer // don't hit ourself that would be really annoying - blown_kiss.impacted = list(offerer = TRUE) // just to make sure we don't hit the wearer + blown_kiss.impacted = list(WEAKREF(offerer) = TRUE) // just to make sure we don't hit the wearer blown_kiss.preparePixelProjectile(taker, offerer) blown_kiss.suppressed = SUPPRESSED_VERY // this also means it's a direct offer blown_kiss.fire() diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index e00a2aa61f3b4..192842e6447b9 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -46,11 +46,13 @@ throw_range = 5 custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 5) breakouttime = 1 MINUTES + armor_type = /datum/armor/restraints_handcuffs + custom_price = PAYCHECK_COMMAND * 0.35 + + ///How long it takes to handcuff someone var/handcuff_time = 4 SECONDS ///Multiplier for handcuff time var/handcuff_time_mod = 1 - armor_type = /datum/armor/restraints_handcuffs - custom_price = PAYCHECK_COMMAND * 0.35 ///Sound that plays when starting to put handcuffs on someone var/cuffsound = 'sound/weapons/handcuffs.ogg' ///If set, handcuffs will be destroyed on application and leave behind whatever this is set to. @@ -70,51 +72,67 @@ fire = 50 acid = 50 -/obj/item/restraints/handcuffs/attack(mob/living/carbon/C, mob/living/user) - if(!istype(C)) +/obj/item/restraints/handcuffs/attack(mob/living/target_mob, mob/living/user) + if(!iscarbon(target_mob)) return - if(SEND_SIGNAL(C, COMSIG_CARBON_CUFF_ATTEMPTED, user) & COMSIG_CARBON_CUFF_PREVENT) + attempt_to_cuff(target_mob, user) + +/// Handles all of the checks and application in a typical situation where someone attacks a carbon victim with the handcuff item. +/obj/item/restraints/handcuffs/proc/attempt_to_cuff(mob/living/carbon/victim, mob/living/user) + if(SEND_SIGNAL(victim, COMSIG_CARBON_CUFF_ATTEMPTED, user) & COMSIG_CARBON_CUFF_PREVENT) + victim.balloon_alert(user, "can't be handcuffed!") return if(iscarbon(user) && (HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))) //Clumsy people have a 50% chance to handcuff themselves instead of their target. to_chat(user, span_warning("Uh... how do those things work?!")) - apply_cuffs(user,user) + apply_cuffs(user, user) return + if(!isnull(victim.handcuffed)) + victim.balloon_alert(user, "already handcuffed!") + return + + if(!victim.canBeHandcuffed()) + victim.balloon_alert(user, "can't be handcuffed!") + return + + victim.visible_message( + span_danger("[user] is trying to put [src] on [victim]!"), + span_userdanger("[user] is trying to put [src] on you!"), + ) + + if(victim.is_blind()) + to_chat(victim, span_userdanger("As you feel someone grab your wrists, [src] start digging into your skin!")) + + playsound(loc, cuffsound, 30, TRUE, -2) + log_combat(user, victim, "attempted to handcuff") + if(HAS_TRAIT(user, TRAIT_FAST_CUFFING)) handcuff_time_mod = 0.75 else handcuff_time_mod = 1 - if(!C.handcuffed) - if(C.canBeHandcuffed()) - C.visible_message(span_danger("[user] is trying to put [src] on [C]!"), \ - span_userdanger("[user] is trying to put [src] on you!")) - if(C.is_blind()) - to_chat(C, span_userdanger("As you feel someone grab your wrists, [src] start digging into your skin!")) - playsound(loc, cuffsound, 30, TRUE, -2) - log_combat(user, C, "attempted to handcuff") - if(do_after(user, handcuff_time * handcuff_time_mod, C, timed_action_flags = IGNORE_SLOWDOWNS) && C.canBeHandcuffed()) - if(iscyborg(user)) - apply_cuffs(C, user, TRUE) - else - apply_cuffs(C, user) - C.visible_message(span_notice("[user] handcuffs [C]."), \ - span_userdanger("[user] handcuffs you.")) - SSblackbox.record_feedback("tally", "handcuffs", 1, type) - - log_combat(user, C, "handcuffed") - else - to_chat(user, span_warning("You fail to handcuff [C]!")) - log_combat(user, C, "failed to handcuff") - else - to_chat(user, span_warning("[C] doesn't have two hands...")) + if(!do_after(user, handcuff_time * handcuff_time_mod, victim, timed_action_flags = IGNORE_SLOWDOWNS) || !victim.canBeHandcuffed()) + victim.balloon_alert(user, "failed to handcuff!") + to_chat(user, span_warning("You fail to handcuff [victim]!")) + log_combat(user, victim, "failed to handcuff") + return + + apply_cuffs(victim, user, dispense = iscyborg(user)) + + victim.visible_message( + span_notice("[user] handcuffs [victim]."), + span_userdanger("[user] handcuffs you."), + ) + + log_combat(user, victim, "successfully handcuffed") + SSblackbox.record_feedback("tally", "handcuffs", 1, type) + /** - * This handles handcuffing people + * When called, this instantly puts handcuffs on someone (if actually possible) * - * When called, this instantly puts handcuffs on someone (if possible) * Arguments: * * mob/living/carbon/target - Who is being handcuffed * * mob/user - Who or what is doing the handcuffing @@ -137,7 +155,6 @@ if(trashtype && !dispense) qdel(src) - return /** * # Alien handcuffs @@ -158,6 +175,7 @@ desc = "Fake handcuffs meant for gag purposes." breakouttime = 1 SECONDS restraint_strength = HANDCUFFS_TYPE_WEAK + resist_cooldown = CLICK_CD_SLOW /** * # Cable restraints @@ -339,6 +357,7 @@ name = "fake zipties" desc = "Fake zipties meant for gag purposes." breakouttime = 1 SECONDS + resist_cooldown = CLICK_CD_SLOW /obj/item/restraints/handcuffs/cable/zipties/fake/used desc = "A pair of broken fake zipties." @@ -485,7 +504,7 @@ /obj/item/restraints/legcuffs/beartrap/energy/Initialize(mapload) . = ..() - addtimer(CALLBACK(src, PROC_REF(dissipate)), 100) + addtimer(CALLBACK(src, PROC_REF(dissipate)), 10 SECONDS) /** * Handles energy snares disappearing diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm index cc64788e597ec..4541bbdbdad9d 100644 --- a/code/game/objects/items/implants/implant.dm +++ b/code/game/objects/items/implants/implant.dm @@ -119,7 +119,7 @@ * Arguments: * * mob/living/source - What the implant is being removed from * * silent - unused here - * * special - unused here + * * special - Set to true if removed by admin panel, should bypass any side effects */ /obj/item/implant/proc/removed(mob/living/source, silent = FALSE, special = 0) moveToNullspace() diff --git a/code/game/objects/items/implants/implant_battle_royale.dm b/code/game/objects/items/implants/implant_battle_royale.dm new file mode 100644 index 0000000000000..11f68ec934599 --- /dev/null +++ b/code/game/objects/items/implants/implant_battle_royale.dm @@ -0,0 +1,142 @@ + +/// Implant used by the traitor Battle Royale objective, is not active immediately +/obj/item/implant/explosive/battle_royale + name = "rumble royale implant" + actions_types = null + instant_explosion = FALSE + master_implant = TRUE + delay = 10 SECONDS + panic_beep_sound = TRUE + announce_activation = FALSE + /// Where is this going to tell us to go to avoid death? + var/target_area_name = "" + /// Is this implant active yet? + var/battle_started = FALSE + /// Are we enforcing a specific area yet? + var/area_limited = FALSE + /// Are we presently exploding? + var/has_exploded = FALSE + /// How likely are we to blow up if removed? + var/removed_explode_chance = 70 + /// Reference to our applied camera component + var/camera + /// We will explode if we're not in here after a set time + var/list/limited_areas = list() + +/obj/item/implant/explosive/battle_royale/get_data() + return "Implant Specifications:
\ + Name: Donk Co. 'Rumble Royale' Contestant Motivation Implant
\ + Life: Activates upon death, or expiry of an internal timer.
\ + Important Notes: Explodes.
\ +
\ + Implant Details:
\ + Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death. \ + Upon triggering the timer, the implant will begin to broadcast the surrounding area for the purposes of televised entertainment. This signal can be detected by GPS trackers.
\ + Special Features: Exploding.
" + +/obj/item/implant/explosive/battle_royale/on_death(datum/source, gibbed) + if (!battle_started) + return + return ..() + +/obj/item/implant/explosive/battle_royale/implant(mob/living/target, mob/user, silent, force) + . = ..() + if (!.) + return + RegisterSignal(target, COMSIG_LIVING_LIFE, PROC_REF(on_life)) + if (!battle_started) + return + name = "[name] - [imp_in.real_name]" + camera = target.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "rumble royale tracker", \ + c_tag = "Competitor [target.real_name]", \ + network = BATTLE_ROYALE_CAMERA_NET, \ + emp_proof = TRUE, \ + ) + announce() + if (area_limited) + limit_areas() + +/obj/item/implant/explosive/battle_royale/removed(mob/target, silent, special) + . = ..() + UnregisterSignal(target, list(COMSIG_LIVING_LIFE, COMSIG_ENTER_AREA)) + QDEL_NULL(camera) + if (has_exploded || QDELETED(src)) + return + if (!special && prob(removed_explode_chance)) + target.visible_message(span_boldwarning("[src] beeps ominously.")) + playsound(loc, 'sound/items/timer.ogg', 50, vary = FALSE) + explode(target) + target?.mind?.remove_antag_datum(/datum/antagonist/survivalist/battle_royale) + +/obj/item/implant/explosive/battle_royale/emp_act(severity) + removed_explode_chance = rand(0, 100) + return ..() + +/obj/item/implant/explosive/battle_royale/explode(atom/override_explode_target = null) + has_exploded = TRUE + return ..() + +/// Give a slight tell +/obj/item/implant/explosive/battle_royale/proc/on_life(mob/living/source) + SIGNAL_HANDLER + if (prob(98)) + return + if (!source.itch() || prob(80)) + return + to_chat(source, span_boldwarning("You feel a lump which shouldn't be there.")) + +/// Start the battle royale +/obj/item/implant/explosive/battle_royale/proc/start_battle(target_area_name, list/limited_areas) + if (isnull(imp_in)) + explode() + return + src.target_area_name = target_area_name + src.limited_areas = limited_areas + battle_started = TRUE + name = "[name] - [imp_in.real_name]" + imp_in.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "rumble royale tracker", \ + c_tag = "Competitor [imp_in.real_name]", \ + network = BATTLE_ROYALE_CAMERA_NET, \ + emp_proof = TRUE, \ + ) + AddComponent(/datum/component/gps, "Rumble Royale - [imp_in.real_name]") + playsound(loc, 'sound/items/timer.ogg', 50, vary = FALSE) + +/// Limit the owner to the specified area +/obj/item/implant/explosive/battle_royale/proc/limit_areas() + if (isnull(imp_in)) + explode() + return + area_limited = TRUE + RegisterSignal(imp_in, COMSIG_ENTER_AREA, PROC_REF(check_area)) + check_area(imp_in) + +/// Called when our implantee moves somewhere +/obj/item/implant/explosive/battle_royale/proc/check_area(mob/living/source) + SIGNAL_HANDLER + if (!length(limited_areas)) + return + if (is_type_in_list(get_area(source), limited_areas)) + return + playsound(imp_in, 'sound/items/timer.ogg', 50, vary = FALSE) + to_chat(imp_in, span_boldwarning("You are out of bounds! Get to the [target_area_name] quickly!")) + addtimer(CALLBACK(src, PROC_REF(check_area_deadly)), 5 SECONDS, TIMER_DELETE_ME) + +/// After a grace period they're still out of bounds, killing time +/obj/item/implant/explosive/battle_royale/proc/check_area_deadly() + if (isnull(imp_in) || has_exploded) + return + var/area/our_area = get_area(imp_in) + if (is_type_in_list(our_area, limited_areas)) + return + log_combat(src, imp_in, "exploded due to out of bounds", addition = "target area was [target_area_name], area was [our_area]") + explode() + +/// Add the antag datum to our new contestant, also printing some flavour text +/obj/item/implant/explosive/battle_royale/proc/announce() + var/datum/antagonist/survivalist/battle_royale/royale = imp_in.mind?.add_antag_datum(/datum/antagonist/survivalist/battle_royale) + royale?.set_target_area(target_area_name) diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm index 51564799f6e44..687b8db014e04 100644 --- a/code/game/objects/items/implants/implant_explosive.dm +++ b/code/game/objects/items/implants/implant_explosive.dm @@ -37,6 +37,8 @@ var/master_implant = FALSE ///Will this implant notify ghosts when activated? var/notify_ghosts = TRUE + ///Do we tell people when they activated it? + var/announce_activation = TRUE /obj/item/implant/explosive/proc/on_death(datum/source, gibbed) SIGNAL_HANDLER @@ -71,7 +73,8 @@ return FALSE if(cause == "death" && HAS_TRAIT(imp_in, TRAIT_PREVENT_IMPLANT_AUTO_EXPLOSION)) return FALSE - to_chat(imp_in, span_notice("You activate your [name].")) + if(announce_activation) + to_chat(imp_in, span_notice("You activate your [name].")) active = TRUE var/turf/boomturf = get_turf(imp_in) message_admins("[ADMIN_LOOKUPFLW(imp_in)] has activated their [name] at [ADMIN_VERBOSEJMP(boomturf)], with cause of [cause].") @@ -86,7 +89,7 @@ if(istype(target_implant, /obj/item/implant/explosive)) //we don't use our own type here, because macrobombs inherit this proc and need to be able to upgrade microbombs var/obj/item/implant/explosive/other_implant = target_implant if(other_implant.master_implant && master_implant) //we cant have two master implants at once - target.balloon_alert(target, "cannot fit implant!") + target.balloon_alert(user, "cannot fit implant!") return FALSE if(master_implant) merge_implants(src, other_implant) @@ -120,17 +123,19 @@ * Make the implantee beep a few times, keel over and explode. Usually to a devastating effect. */ /obj/item/implant/explosive/proc/timed_explosion() - imp_in.visible_message(span_warning("[imp_in] starts beeping ominously!")) - - if(notify_ghosts) - notify_ghosts( - "[imp_in] is about to detonate their explosive implant!", - source = src, - header = "Tick Tick Tick...", - notify_flags = NOTIFY_CATEGORY_NOFLASH, - ghost_sound = 'sound/machines/warning-buzzer.ogg', - notify_volume = 75, - ) + if (isnull(imp_in)) + visible_message(span_warning("[src] starts beeping ominously!")) + else + imp_in.visible_message(span_warning("[imp_in] starts beeping ominously!")) + if(notify_ghosts) + notify_ghosts( + "[imp_in] is about to detonate their explosive implant!", + source = src, + header = "Tick Tick Tick...", + notify_flags = NOTIFY_CATEGORY_NOFLASH, + ghost_sound = 'sound/machines/warning-buzzer.ogg', + notify_volume = 75, + ) playsound(loc, 'sound/items/timer.ogg', 30, FALSE) if(!panic_beep_sound) @@ -160,14 +165,15 @@ ///When called, just explodes -/obj/item/implant/explosive/proc/explode() +/obj/item/implant/explosive/proc/explode(atom/override_explode_target = null) explosion_devastate = round(explosion_devastate) explosion_heavy = round(explosion_heavy) explosion_light = round(explosion_light) - explosion(src, devastation_range = explosion_devastate, heavy_impact_range = explosion_heavy, light_impact_range = explosion_light, flame_range = explosion_light, flash_range = explosion_light, explosion_cause = src) - if(imp_in) - imp_in.investigate_log("has been gibbed by an explosive implant.", INVESTIGATE_DEATHS) - imp_in.gib(DROP_ORGANS|DROP_BODYPARTS) + explosion(override_explode_target || src, devastation_range = explosion_devastate, heavy_impact_range = explosion_heavy, light_impact_range = explosion_light, flame_range = explosion_light, flash_range = explosion_light, explosion_cause = src) + var/mob/living/kill_mob = isliving(override_explode_target) ? override_explode_target : imp_in + if(!isnull(kill_mob)) + kill_mob.investigate_log("has been gibbed by an explosive implant.", INVESTIGATE_DEATHS) + kill_mob.gib(DROP_ORGANS|DROP_BODYPARTS) qdel(src) ///Macrobomb has the strength and delay of 10 microbombs diff --git a/code/game/objects/items/implants/implantpad.dm b/code/game/objects/items/implants/implantpad.dm index ae09f8675b6d3..92f015b01a91e 100644 --- a/code/game/objects/items/implants/implantpad.dm +++ b/code/game/objects/items/implants/implantpad.dm @@ -10,6 +10,7 @@ throw_speed = 3 throw_range = 5 w_class = WEIGHT_CLASS_SMALL + interaction_flags_click = FORBID_TELEKINESIS_REACH|ALLOW_RESTING ///The implant case currently inserted into the pad. var/obj/item/implantcase/inserted_case @@ -46,11 +47,9 @@ update_static_data_for_all_viewers() update_appearance(UPDATE_ICON) -/obj/item/implantpad/AltClick(mob/user) - . = ..() - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return +/obj/item/implantpad/click_alt(mob/user) remove_implant(user) + return CLICK_ACTION_SUCCESS /obj/item/implantpad/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) diff --git a/code/game/objects/items/inducer.dm b/code/game/objects/items/inducer.dm index 9cbb3f054f571..086b965e1ac41 100644 --- a/code/game/objects/items/inducer.dm +++ b/code/game/objects/items/inducer.dm @@ -127,7 +127,7 @@ user.visible_message(span_notice("[user] starts recharging [target] with [src]."), span_notice("You start recharging [target] with [src].")) while(target_cell.charge < target_cell.maxcharge) - if(do_after(user, 10, target = user) && our_cell.charge) + if(do_after(user, 1 SECONDS, target = user) && our_cell.charge) done_any = TRUE induce(target_cell, coefficient) do_sparks(1, FALSE, target) @@ -203,5 +203,5 @@ icon_state = "inducer-syndi" inhand_icon_state = "inducer-syndi" desc = "A tool for inductively charging internal power cells. This one has a suspicious colour scheme, and seems to be rigged to transfer charge at a much faster rate." - powertransfer = 2000 + powertransfer = 2 * STANDARD_CELL_CHARGE cell_type = /obj/item/stock_parts/cell/super diff --git a/code/game/objects/items/inspector.dm b/code/game/objects/items/inspector.dm index 2f25e53c1fb77..ab5db9b65ce9c 100644 --- a/code/game/objects/items/inspector.dm +++ b/code/game/objects/items/inspector.dm @@ -1,3 +1,6 @@ +///Energy used to say an error message. +#define ENERGY_TO_SPEAK (0.001 * STANDARD_CELL_CHARGE) + /** * # N-spect scanner * @@ -28,8 +31,6 @@ var/cell_cover_open = FALSE ///Energy used per print. var/energy_per_print = INSPECTOR_ENERGY_USAGE_NORMAL - ///Energy used to say an error message. - var/energy_to_speak = 1 KILO JOULES /obj/item/inspector/Initialize(mapload) . = ..() @@ -112,7 +113,7 @@ to_chat(user, "\The [src] doesn't seem to be on... Perhaps it ran out of power?") return if(!cell.use(energy_per_print)) - if(cell.use(energy_to_speak)) + if(cell.use(ENERGY_TO_SPEAK)) say("ERROR! POWER CELL CHARGE LEVEL TOO LOW TO PRINT REPORT!") return @@ -258,7 +259,7 @@ /obj/item/inspector/clown/bananium/proc/check_settings_legality() if(print_sound_mode == INSPECTOR_PRINT_SOUND_MODE_NORMAL && time_mode == INSPECTOR_TIME_MODE_HONK) - if(cell.use(energy_to_speak)) + if(cell.use(ENERGY_TO_SPEAK)) say("Setting combination forbidden by Geneva convention revision CCXXIII selected, reverting to defaults") time_mode = INSPECTOR_TIME_MODE_SLOW print_sound_mode = INSPECTOR_PRINT_SOUND_MODE_NORMAL @@ -296,7 +297,7 @@ if(time_mode != INSPECTOR_TIME_MODE_HONK) return ..() if(paper_charges == 0) - if(cell.use(energy_to_speak)) + if(cell.use(ENERGY_TO_SPEAK)) say("ERROR! OUT OF PAPER! MAXIMUM PRINTING SPEED UNAVAIBLE! SWITCH TO A SLOWER SPEED TO OR PROVIDE PAPER!") else to_chat(user, "\The [src] doesn't seem to be on... Perhaps it ran out of power?") @@ -372,15 +373,17 @@ */ /obj/item/paper/fake_report/water grind_results = list(/datum/reagent/water = 5) + interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING -/obj/item/paper/fake_report/water/AltClick(mob/living/user, obj/item/I) - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) - return +/obj/item/paper/fake_report/water/click_alt(mob/living/user) var/datum/action/innate/origami/origami_action = locate() in user.actions if(origami_action?.active) //Origami masters can fold water - make_plane(user, I, /obj/item/paperplane/syndicate) + make_plane(user, /obj/item/paperplane/syndicate) else if(do_after(user, 1 SECONDS, target = src, progress=TRUE)) var/turf/open/target = get_turf(src) target.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS) to_chat(user, span_notice("As you try to fold [src] into the shape of a plane, it disintegrates into water!")) qdel(src) + return CLICK_ACTION_SUCCESS + +#undef ENERGY_TO_SPEAK diff --git a/code/game/objects/items/machine_wand.dm b/code/game/objects/items/machine_wand.dm index 71ea2fae1b65d..bc5eb8583f9c4 100644 --- a/code/game/objects/items/machine_wand.dm +++ b/code/game/objects/items/machine_wand.dm @@ -63,14 +63,15 @@ if(controlling_machine_or_bot) return controlling_machine_or_bot.ui_act(action, params, ui, state) -/obj/item/machine_remote/AltClick(mob/user) - . = ..() +/obj/item/machine_remote/click_alt(mob/user) if(moving_bug) //we have a bug in transit, so let's kill it. QDEL_NULL(moving_bug) + return CLICK_ACTION_BLOCKING if(!controlling_machine_or_bot) - return + return CLICK_ACTION_BLOCKING say("Remote control over [controlling_machine_or_bot] stopped.") remove_old_machine() + return CLICK_ACTION_SUCCESS /obj/item/machine_remote/afterattack(atom/target, mob/user, proximity_flag, click_parameters) . = ..() @@ -149,7 +150,7 @@ CRASH("a moving bug has been created but isn't moving towards anything!") src.controller = controller src.thing_moving_towards = thing_moving_towards - var/datum/move_loop/loop = SSmove_manager.home_onto(src, thing_moving_towards, delay = 5, flags = MOVEMENT_LOOP_NO_DIR_UPDATE) + var/datum/move_loop/loop = GLOB.move_manager.home_onto(src, thing_moving_towards, delay = 5, flags = MOVEMENT_LOOP_NO_DIR_UPDATE) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(reached_destination_check)) RegisterSignal(thing_moving_towards, COMSIG_QDELETING, PROC_REF(on_machine_del)) diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm index 5f084300442d0..4a3de80959f53 100644 --- a/code/game/objects/items/mail.dm +++ b/code/game/objects/items/mail.dm @@ -512,7 +512,7 @@ return FALSE if(loc != user) return FALSE - mail_type = lowertext(mail_type) + mail_type = LOWER_TEXT(mail_type) var/mail_armed = tgui_alert(user, "Arm it?", "Mail Counterfeiting", list("Yes", "No")) == "Yes" if(isnull(mail_armed)) diff --git a/code/game/objects/items/maintenance_loot.dm b/code/game/objects/items/maintenance_loot.dm index 538e4cac93d43..f6d7fd1c3290d 100644 --- a/code/game/objects/items/maintenance_loot.dm +++ b/code/game/objects/items/maintenance_loot.dm @@ -29,8 +29,8 @@ icon = 'icons/obj/maintenance_loot.dmi' icon_state = "lead_battery" throwforce = 10 - maxcharge = 20000 //decent max charge - chargerate = 1400 //charging is about 30% less efficient than lithium batteries. + maxcharge = STANDARD_CELL_CHARGE * 20 //decent max charge + chargerate = STANDARD_CELL_RATE * 0.7 //charging is about 30% less efficient than lithium batteries. charge_light_type = null connector_type = "leadacid" rating = 2 //Kind of a mid-tier battery diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 0f400536b8fd8..b3d33cd99e984 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -60,8 +60,7 @@ inhand_icon_state = "sabre" lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - obj_flags = CONDUCTS_ELECTRICITY - obj_flags = UNIQUE_RENAME + obj_flags = CONDUCTS_ELECTRICITY | UNIQUE_RENAME force = 15 throwforce = 10 demolition_mod = 0.75 //but not metal @@ -446,7 +445,7 @@ finish_roasting(user, target) /obj/item/melee/roastingstick/proc/finish_roasting(user, atom/target) - if(do_after(user, 100, target = user)) + if(do_after(user, 10 SECONDS, target = user)) to_chat(user, span_notice("You finish roasting [held_sausage].")) playsound(src, 'sound/items/welder2.ogg', 50, TRUE) held_sausage.add_atom_colour(rgb(103, 63, 24), FIXED_COLOUR_PRIORITY) diff --git a/code/game/objects/items/paiwire.dm b/code/game/objects/items/paiwire.dm index fa5724ebb534f..d590d4e96036b 100644 --- a/code/game/objects/items/paiwire.dm +++ b/code/game/objects/items/paiwire.dm @@ -4,15 +4,15 @@ icon = 'icons/obj/stack_objects.dmi' icon_state = "wire1" item_flags = NOBLUDGEON - var/obj/machinery/machine //what machine we're currently hacking. + ///The current machine being hacked by the pAI cable. + var/obj/machinery/hacking_machine /obj/item/pai_cable/Destroy() - machine = null + hacking_machine = null return ..() - /obj/item/pai_cable/proc/plugin(obj/machinery/M, mob/living/user) if(!user.transferItemToLoc(src, M)) return user.visible_message(span_notice("[user] inserts [src] into a data port on [M]."), span_notice("You insert [src] into a data port on [M]."), span_hear("You hear the satisfying click of a wire jack fastening into place.")) - machine = M + hacking_machine = M diff --git a/code/game/objects/items/pet_carrier.dm b/code/game/objects/items/pet_carrier.dm index 567b32304e47f..e30cdaf39df34 100644 --- a/code/game/objects/items/pet_carrier.dm +++ b/code/game/objects/items/pet_carrier.dm @@ -66,9 +66,9 @@ open = TRUE update_appearance() -/obj/item/pet_carrier/AltClick(mob/living/user) - if(open || !user.can_perform_action(src)) - return +/obj/item/pet_carrier/click_alt(mob/living/user) + if(open) + return CLICK_ACTION_BLOCKING locked = !locked to_chat(user, span_notice("You flip the lock switch [locked ? "down" : "up"].")) if(locked) @@ -76,6 +76,7 @@ else playsound(user, 'sound/machines/boltsup.ogg', 30, TRUE) update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/pet_carrier/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(user.combat_mode || !isliving(interacting_with)) @@ -131,7 +132,7 @@ else loc.visible_message(span_warning("[src] starts rattling as something pushes against the door!"), null, null, null, user) to_chat(user, span_notice("You start pushing out of [src]... (This will take about 20 seconds.)")) - if(!do_after(user, 200, target = user) || open || !locked || !(user in occupants)) + if(!do_after(user, 20 SECONDS, target = user) || open || !locked || !(user in occupants)) return loc.visible_message(span_warning("[user] shoves out of [src]!"), null, null, null, user) to_chat(user, span_notice("You shove open [src]'s door against the lock's resistance and fall out!")) diff --git a/code/game/objects/items/piggy_bank.dm b/code/game/objects/items/piggy_bank.dm index 8d50e8a39e8fe..b6294dbc4dd8c 100644 --- a/code/game/objects/items/piggy_bank.dm +++ b/code/game/objects/items/piggy_bank.dm @@ -63,7 +63,7 @@ persistence_cb = null return ..() -/obj/item/piggy_bank/deconstruct(disassembled = TRUE) +/obj/item/piggy_bank/atom_deconstruct(disassembled = TRUE) for(var/obj/item/thing as anything in contents) thing.forceMove(loc) //Smashing the piggy after the round is over doesn't count. diff --git a/code/game/objects/items/pillow.dm b/code/game/objects/items/pillow.dm index 1dad0a7fba523..659cc38f58b5a 100644 --- a/code/game/objects/items/pillow.dm +++ b/code/game/objects/items/pillow.dm @@ -102,16 +102,15 @@ if(pillow_trophy) . += span_notice("Alt-click to remove the tag!") -/obj/item/pillow/AltClick(mob/user) - . = ..() - if(!can_interact(user) || !user.can_hold_items(src)) - return +/obj/item/pillow/click_alt(mob/user) + if(!user.can_hold_items(src)) + return CLICK_ACTION_BLOCKING if(!pillow_trophy) balloon_alert(user, "no tag!") - return + return CLICK_ACTION_BLOCKING balloon_alert(user, "removing tag...") if(!do_after(user, 2 SECONDS, src)) - return + return CLICK_ACTION_BLOCKING if(last_fighter) pillow_trophy.desc = "A pillow tag taken from [last_fighter] after a gruesome pillow fight." user.put_in_hands(pillow_trophy) @@ -119,6 +118,7 @@ balloon_alert(user, "tag removed") playsound(user,'sound/items/poster_ripped.ogg', 50) update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/pillow/update_appearance(updates) . = ..() diff --git a/code/game/objects/items/puzzle_pieces.dm b/code/game/objects/items/puzzle_pieces.dm index 77b07488d6c0d..1fabf13d31ac1 100644 --- a/code/game/objects/items/puzzle_pieces.dm +++ b/code/game/objects/items/puzzle_pieces.dm @@ -323,7 +323,7 @@ SSqueuelinks.add_to_queue(src, id, late_initialize_pop ? 0 : queue_size) return late_initialize_pop ? INITIALIZE_HINT_LATELOAD : . -/obj/machinery/puzzle/LateInitialize() +/obj/machinery/puzzle/post_machine_initialize() . = ..() if(late_initialize_pop && id && SSqueuelinks.queues[id]) SSqueuelinks.pop_link(id) diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index d050da4fa5e10..88daf279c590b 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -203,6 +203,11 @@ * * [mob][user]- the user building this structure */ /obj/item/construction/rcd/proc/rcd_create(atom/target, mob/user) + //straight up cant touch this + if(mode == RCD_DECONSTRUCT && (target.resistance_flags & INDESTRUCTIBLE)) + balloon_alert(user, "too durable!") + return + //does this atom allow for rcd actions? var/list/rcd_results = target.rcd_vals(user, src) if(!rcd_results) @@ -413,7 +418,7 @@ buzz loudly!","[src] begins \ vibrating violently!") // 5 seconds to get rid of it - addtimer(CALLBACK(src, PROC_REF(detonate_pulse_explode)), 50) + addtimer(CALLBACK(src, PROC_REF(detonate_pulse_explode)), 5 SECONDS) /obj/item/construction/rcd/proc/detonate_pulse_explode() explosion(src, light_impact_range = 3, flame_range = 1, flash_range = 1) @@ -423,7 +428,7 @@ desc = "A device used to rapidly build walls and floors." banned_upgrades = RCD_UPGRADE_SILO_LINK /// enery usage - var/energyfactor = 72 KILO JOULES + var/energyfactor = 0.072 * STANDARD_CELL_CHARGE /obj/item/construction/rcd/borg/get_matter(mob/user) if(!iscyborg(user)) @@ -465,7 +470,7 @@ desc = "A reverse-engineered RCD with black market upgrades that allow this device to deconstruct reinforced walls. Property of Donk Co." icon_state = "ircd" inhand_icon_state = "ircd" - energyfactor = 66 KILO JOULES + energyfactor = 0.066 * STANDARD_CELL_CHARGE canRturf = TRUE /obj/item/construction/rcd/loaded @@ -517,7 +522,7 @@ upgrade = RCD_ALL_UPGRADES & ~RCD_UPGRADE_SILO_LINK ///How much charge is used up for each matter unit. -#define MASS_TO_ENERGY (16 KILO JOULES) +#define MASS_TO_ENERGY (0.016 * STANDARD_CELL_CHARGE) /obj/item/construction/rcd/exosuit name = "mounted RCD" diff --git a/code/game/objects/items/rcd/RHD.dm b/code/game/objects/items/rcd/RHD.dm index 9151c85ed0311..7dac16aa51a36 100644 --- a/code/game/objects/items/rcd/RHD.dm +++ b/code/game/objects/items/rcd/RHD.dm @@ -290,27 +290,39 @@ var/upgrade /obj/item/rcd_upgrade/frames + name = "RCD advanced upgrade: frames" desc = "It contains the design for machine frames and computer frames." + icon_state = "datadisk6" upgrade = RCD_UPGRADE_FRAMES /obj/item/rcd_upgrade/simple_circuits + name = "RCD advanced upgrade: simple circuits" desc = "It contains the design for firelock, air alarm, fire alarm, apc circuits and crap power cells." + icon_state = "datadisk4" upgrade = RCD_UPGRADE_SIMPLE_CIRCUITS /obj/item/rcd_upgrade/anti_interrupt + name = "RCD advanced upgrade: anti disruption" desc = "It contains the upgrades necessary to prevent interruption of RCD construction and deconstruction." + icon_state = "datadisk2" upgrade = RCD_UPGRADE_ANTI_INTERRUPT /obj/item/rcd_upgrade/cooling + name = "RCD advanced upgrade: enhanced cooling" desc = "It contains the upgrades necessary to allow more frequent use of the RCD." + icon_state = "datadisk7" upgrade = RCD_UPGRADE_NO_FREQUENT_USE_COOLDOWN /obj/item/rcd_upgrade/silo_link + name = "RCD advanced upgrade: silo link" desc = "It contains direct silo connection RCD upgrade." + icon_state = "datadisk8" upgrade = RCD_UPGRADE_SILO_LINK /obj/item/rcd_upgrade/furnishing + name = "RCD advanced upgrade: furnishings" desc = "It contains the design for chairs, stools, tables, and glass tables." + icon_state = "datadisk5" upgrade = RCD_UPGRADE_FURNISHING /datum/action/item_action/rcd_scan diff --git a/code/game/objects/items/rcd/RPD.dm b/code/game/objects/items/rcd/RPD.dm index e47779776059b..41a962ed7e7de 100644 --- a/code/game/objects/items/rcd/RPD.dm +++ b/code/game/objects/items/rcd/RPD.dm @@ -705,7 +705,9 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( var/upgrade_flags /obj/item/rpd_upgrade/unwrench + name = "RPD advanced upgrade: wrench mode" desc = "Adds reverse wrench mode to the RPD. Attention, due to budget cuts, the mode is hard linked to the destroy mode control button." + icon_state = "datadisk1" upgrade_flags = RPD_UPGRADE_UNWRENCH #undef ATMOS_CATEGORY diff --git a/code/game/objects/items/rcd/RPLD.dm b/code/game/objects/items/rcd/RPLD.dm index 7f03fad1a9c32..192875694c1c2 100644 --- a/code/game/objects/items/rcd/RPLD.dm +++ b/code/game/objects/items/rcd/RPLD.dm @@ -268,15 +268,16 @@ if(machine_target.anchored) balloon_alert(user, "unanchor first!") return - if(do_after(user, 20, target = target)) + if(do_after(user, 2 SECONDS, target = target)) machine_target.deconstruct() //Let's not substract matter playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect return create_machine(target, user) -/obj/item/construction/plumbing/AltClick(mob/user) +/obj/item/construction/plumbing/click_alt(mob/user) ui_interact(user) + return CLICK_ACTION_SUCCESS /obj/item/construction/plumbing/proc/mouse_wheeled(mob/source, atom/A, delta_x, delta_y, params) SIGNAL_HANDLER diff --git a/code/game/objects/items/rcd/RWD.dm b/code/game/objects/items/rcd/RWD.dm index a20946e322fae..0ee29e87a352f 100644 --- a/code/game/objects/items/rcd/RWD.dm +++ b/code/game/objects/items/rcd/RWD.dm @@ -125,8 +125,7 @@ add_cable(user, cable) return TRUE -/obj/item/rwd/AltClick(mob/user) - . = ..() +/obj/item/rwd/click_alt(mob/user) if(!radial_menu) radial_menu = list( "Layer 1" = image(icon = 'icons/hud/radial.dmi', icon_state = "coil-red"), @@ -136,7 +135,7 @@ var/layer_result = show_radial_menu(user, src, radial_menu, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE) if(!check_menu(user)) - return + return CLICK_ACTION_BLOCKING switch(layer_result) if("Layer 1") cable_layer = CABLE_LAYER_1 @@ -145,6 +144,7 @@ if("Layer 3") cable_layer = CABLE_LAYER_3 update_appearance(UPDATE_ICON_STATE) + return CLICK_ACTION_SUCCESS /obj/item/rwd/proc/check_menu(mob/living/user) if(!istype(user)) diff --git a/code/game/objects/items/robot/items/food.dm b/code/game/objects/items/robot/items/food.dm index 1878b0c1e0027..40166a6a8fbfe 100644 --- a/code/game/objects/items/robot/items/food.dm +++ b/code/game/objects/items/robot/items/food.dm @@ -121,7 +121,7 @@ check_amount() if(iscyborg(user)) var/mob/living/silicon/robot/robot_user = user - if(!robot_user.cell.use(12 KILO JOULES)) + if(!robot_user.cell.use(0.012 * STANDARD_CELL_CHARGE)) to_chat(user, span_warning("Not enough power.")) return AFTERATTACK_PROCESSED_ITEM switch(mode) diff --git a/code/game/objects/items/robot/items/generic.dm b/code/game/objects/items/robot/items/generic.dm index f1f7f379ffbf8..b9f28b4003e65 100644 --- a/code/game/objects/items/robot/items/generic.dm +++ b/code/game/objects/items/robot/items/generic.dm @@ -247,7 +247,7 @@ return to_chat(user, span_notice("You connect to [target_machine]'s power line...")) - while(do_after(user, 15, target = target_machine, progress = 0)) + while(do_after(user, 1.5 SECONDS, target = target_machine, progress = FALSE)) if(!user || !user.cell || mode != "draw") return @@ -278,7 +278,7 @@ to_chat(user, span_notice("You connect to [target]'s power port...")) - while(do_after(user, 15, target = target, progress = 0)) + while(do_after(user, 1.5 SECONDS, target = target, progress = FALSE)) if(!user || !user.cell || mode != "draw") return @@ -316,7 +316,7 @@ to_chat(user, span_notice("You connect to [target]'s power port...")) - while(do_after(user, 15, target = target, progress = 0)) + while(do_after(user, 1.5 SECONDS, target = target, progress = FALSE)) if(!user || !user.cell || mode != "charge") return diff --git a/code/game/objects/items/robot/items/hypo.dm b/code/game/objects/items/robot/items/hypo.dm index f2383b799f23a..fc48a1b11b162 100644 --- a/code/game/objects/items/robot/items/hypo.dm +++ b/code/game/objects/items/robot/items/hypo.dm @@ -108,7 +108,7 @@ */ var/max_volume_per_reagent = 30 /// Cell cost for charging a reagent - var/charge_cost = 50 KILO JOULES + var/charge_cost = 0.05 * STANDARD_CELL_CHARGE /// Counts up to the next time we charge var/charge_timer = 0 /// Time it takes for shots to recharge (in seconds) @@ -194,7 +194,7 @@ balloon_alert(user, "[amount_per_transfer_from_this] unit\s injected") log_combat(user, injectee, "injected", src, "(CHEMICALS: [selected_reagent])") else - balloon_alert(user, "[parse_zone(user.zone_selected)] is blocked!") + balloon_alert(user, "[injectee.parse_zone_with_bodypart(user.zone_selected)] is blocked!") /obj/item/reagent_containers/borghypo/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -244,11 +244,9 @@ . += "Currently loaded: [selected_reagent ? "[selected_reagent]. [selected_reagent.description]" : "nothing."]" . += span_notice("Alt+Click to change transfer amount. Currently set to [amount_per_transfer_from_this]u.") -/obj/item/reagent_containers/borghypo/AltClick(mob/living/user) - . = ..() - if(user.stat == DEAD || user != loc) - return //IF YOU CAN HEAR ME SET MY TRANSFER AMOUNT TO 1 +/obj/item/reagent_containers/borghypo/click_alt(mob/living/user) change_transfer_amount(user) + return CLICK_ACTION_SUCCESS /// Default Medborg Hypospray /obj/item/reagent_containers/borghypo/medical @@ -308,7 +306,7 @@ Also metabolizes potassium iodide for radiation poisoning, inacusiate for ear damage and morphine for offense." icon_state = "borghypo_s" tgui_theme = "syndicate" - charge_cost = 20 KILO JOULES + charge_cost = 0.02 * STANDARD_CELL_CHARGE recharge_time = 2 default_reagent_types = BASE_SYNDICATE_REAGENTS bypass_protection = TRUE @@ -321,7 +319,7 @@ icon_state = "shaker" possible_transfer_amounts = list(5,10,20,1) // Lots of reagents all regenerating at once, so the charge cost is lower. They also regenerate faster. - charge_cost = 20 KILO JOULES + charge_cost = 0.02 * STANDARD_CELL_CHARGE recharge_time = 3 dispensed_temperature = WATER_MATTERSTATE_CHANGE_TEMP //Water stays wet, ice stays ice default_reagent_types = BASE_SERVICE_REAGENTS @@ -393,7 +391,7 @@ icon_state = "flour" possible_transfer_amounts = list(5,10,20,1) // Lots of reagents all regenerating at once, so the charge cost is lower. They also regenerate faster. - charge_cost = 40 KILO JOULES //Costs double the power of the borgshaker due to synthesizing solids + charge_cost = 0.04 * STANDARD_CELL_CHARGE //Costs double the power of the borgshaker due to synthesizing solids recharge_time = 6 //Double the recharge time too, for the same reason. dispensed_temperature = WATER_MATTERSTATE_CHANGE_TEMP default_reagent_types = EXPANDED_SERVICE_REAGENTS diff --git a/code/game/objects/items/robot/items/storage.dm b/code/game/objects/items/robot/items/storage.dm index 01541df5a9c78..2d91128adb68d 100644 --- a/code/game/objects/items/robot/items/storage.dm +++ b/code/game/objects/items/robot/items/storage.dm @@ -50,10 +50,11 @@ stored.attack_self(user) //Alt click drops the stored item. -/obj/item/borg/apparatus/AltClick(mob/living/silicon/robot/user) +/obj/item/borg/apparatus/click_alt(mob/living/silicon/robot/user) if(!stored || !issilicon(user)) - return ..() + return CLICK_ACTION_BLOCKING stored.forceMove(user.drop_location()) + return CLICK_ACTION_SUCCESS /obj/item/borg/apparatus/pre_attack(atom/atom, mob/living/user, params) if(stored) @@ -244,16 +245,16 @@ bag = mutable_appearance(icon, icon_state = "evidenceobj") // empty bag . += bag -/obj/item/borg/apparatus/organ_storage/AltClick(mob/living/silicon/robot/user) - . = ..() - if(stored) - var/obj/item/organ = stored - user.visible_message(span_notice("[user] dumps [organ] from [src]."), span_notice("You dump [organ] from [src].")) - cut_overlays() - organ.forceMove(get_turf(src)) - else +/obj/item/borg/apparatus/organ_storage/click_alt(mob/living/silicon/robot/user) + if(!stored) to_chat(user, span_notice("[src] is empty.")) - return + return CLICK_ACTION_BLOCKING + + var/obj/item/organ = stored + user.visible_message(span_notice("[user] dumps [organ] from [src]."), span_notice("You dump [organ] from [src].")) + cut_overlays() + organ.forceMove(get_turf(src)) + return CLICK_ACTION_SUCCESS ///Apparatus to allow Engineering/Sabo borgs to manipulate any material sheets. /obj/item/borg/apparatus/sheet_manipulator diff --git a/code/game/objects/items/robot/items/tools.dm b/code/game/objects/items/robot/items/tools.dm index 538fd1b7ca18b..b9f0c103ba540 100644 --- a/code/game/objects/items/robot/items/tools.dm +++ b/code/game/objects/items/robot/items/tools.dm @@ -1,5 +1,7 @@ #define PKBORG_DAMPEN_CYCLE_DELAY (2 SECONDS) -#define POWER_RECHARGE_CYBORG_DRAIN_MULTIPLIER (0.4 KILO WATTS) +#define POWER_RECHARGE_CYBORG_DRAIN_MULTIPLIER (0.0004 * STANDARD_CELL_RATE) +#define NO_TOOL "deactivated" +#define TOOL_DRAPES "surgical_drapes" /obj/item/cautery/prt //it's a subtype of cauteries so that it inherits the cautery sprites and behavior and stuff, because I'm too lazy to make sprites for this thing name = "plating repair tool" @@ -174,5 +176,220 @@ projectile.speed *= (1 / projectile_speed_coefficient) projectile.cut_overlay(projectile_effect) +//bare minimum omni-toolset for modularity +/obj/item/borg/cyborg_omnitool + name = "cyborg omni-toolset" + desc = "You shouldn't see this in-game normally." + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg" + ///our tools + var/list/radial_menu_options = list() + ///object we are referencing to for force, sharpness and sound + var/obj/item/reference + //is the toolset upgraded or not + var/upgraded = FALSE + ///how much faster should the toolspeed be? + var/upgraded_toolspeed = 0.7 + +/obj/item/borg/cyborg_omnitool/get_all_tool_behaviours() + return list(TOOL_SCALPEL, TOOL_HEMOSTAT) + +/obj/item/borg/cyborg_omnitool/Initialize(mapload) + . = ..() + AddComponent(/datum/component/butchering, \ + speed = 8 SECONDS, \ + effectiveness = 100, \ + disabled = TRUE, \ + ) + radial_menu_options = list( + NO_TOOL = image(icon = 'icons/mob/silicon/robot_items.dmi', icon_state = initial(icon_state)), + TOOL_SCALPEL = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_SCALPEL]"), + TOOL_HEMOSTAT = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_HEMOSTAT]"), + ) + +/obj/item/borg/cyborg_omnitool/attack_self(mob/user) + var/new_tool_behaviour = show_radial_menu(user, src, radial_menu_options, require_near = TRUE, tooltips = TRUE) + + if(isnull(new_tool_behaviour) || new_tool_behaviour == tool_behaviour) + return + if(new_tool_behaviour == NO_TOOL) + tool_behaviour = null + else + tool_behaviour = new_tool_behaviour + + reference_item_for_parameters() + update_tool_parameters(reference) + update_appearance(UPDATE_ICON_STATE) + playsound(src, 'sound/items/change_jaws.ogg', 50, TRUE) + +/// Used to get reference item for the tools +/obj/item/borg/cyborg_omnitool/proc/reference_item_for_parameters() + SHOULD_CALL_PARENT(FALSE) + switch(tool_behaviour) + if(TOOL_SCALPEL) + reference = /obj/item/scalpel + if(TOOL_HEMOSTAT) + reference = /obj/item/hemostat + +/// Used to update sounds and tool parameters during switching +/obj/item/borg/cyborg_omnitool/proc/update_tool_parameters(/obj/item/reference) + if(isnull(reference)) + sharpness = NONE + force = initial(force) + wound_bonus = 0 + bare_wound_bonus = 0 + armour_penetration = 0 + hitsound = initial(hitsound) + usesound = initial(usesound) + else + force = initial(reference.force) + wound_bonus = reference::wound_bonus + bare_wound_bonus = reference::bare_wound_bonus + armour_penetration = reference::armour_penetration + sharpness = initial(reference.sharpness) + hitsound = initial(reference.hitsound) + usesound = initial(reference.usesound) + +/obj/item/borg/cyborg_omnitool/update_icon_state() + icon_state = initial(icon_state) + + if (tool_behaviour) + icon_state += "_[sanitize_css_class_name(tool_behaviour)]" + + if(tool_behaviour) + inhand_icon_state = initial(inhand_icon_state) + "_deactivated" + else + inhand_icon_state = initial(inhand_icon_state) + + return ..() + +/** + * proc that's used when cyborg is upgraded with an omnitool upgrade board + * + * adds name and desc changes. also changes tools to default configuration to indicate it's been sucessfully upgraded + * changes the toolspeed to the upgraded_toolspeed variable + */ +/obj/item/borg/cyborg_omnitool/proc/upgrade_omnitool() + name = "advanced [name]" + desc += "\nIt seems that this one has been upgraded to perform tasks faster." + toolspeed = upgraded_toolspeed + upgraded = TRUE + tool_behaviour = null + reference_item_for_parameters() + update_tool_parameters(reference) + update_appearance(UPDATE_ICON_STATE) + playsound(src, 'sound/items/change_jaws.ogg', 50, TRUE) + +/** + * proc that's used when a cyborg with an upgraded omnitool is downgraded + * + * reverts all name and desc changes to it's initial variables. also changes tools to default configuration to indicate it's been downgraded + * changes the toolspeed to default variable + */ +/obj/item/borg/cyborg_omnitool/proc/downgrade_omnitool() + name = initial(name) + desc = initial(desc) + toolspeed = initial(toolspeed) + upgraded = FALSE + tool_behaviour = null + reference_item_for_parameters() + update_tool_parameters(reference) + update_appearance(UPDATE_ICON_STATE) + playsound(src, 'sound/items/change_jaws.ogg', 50, TRUE) + +/obj/item/borg/cyborg_omnitool/medical + name = "surgical omni-toolset" + desc = "A set of surgical tools used by cyborgs to operate on various surgical operations." + item_flags = SURGICAL_TOOL + +/obj/item/borg/cyborg_omnitool/medical/get_all_tool_behaviours() + return list(TOOL_SCALPEL, TOOL_HEMOSTAT, TOOL_RETRACTOR, TOOL_SAW, TOOL_DRILL, TOOL_CAUTERY, TOOL_BONESET) + +/obj/item/borg/cyborg_omnitool/medical/Initialize(mapload) + . = ..() + AddComponent(/datum/component/butchering, \ + speed = 8 SECONDS, \ + effectiveness = 100, \ + disabled = TRUE, \ + ) + radial_menu_options = list( + TOOL_SCALPEL = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_SCALPEL]"), + TOOL_HEMOSTAT = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_HEMOSTAT]"), + TOOL_RETRACTOR = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_RETRACTOR]"), + TOOL_SAW = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_SAW]"), + TOOL_DRILL = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_DRILL]"), + TOOL_CAUTERY = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_CAUTERY]"), + TOOL_BONESET = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_BONESET]"), + TOOL_DRAPES = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_DRAPES]"), + ) + +/obj/item/borg/cyborg_omnitool/medical/reference_item_for_parameters() + var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering) + butchering.butchering_enabled = (tool_behaviour == TOOL_SCALPEL || tool_behaviour == TOOL_SAW) + RemoveElement(/datum/element/eyestab) + qdel(GetComponent(/datum/component/surgery_initiator)) + item_flags = SURGICAL_TOOL + switch(tool_behaviour) + if(TOOL_SCALPEL) + reference = /obj/item/scalpel + AddElement(/datum/element/eyestab) + if(TOOL_DRILL) + reference = /obj/item/surgicaldrill + AddElement(/datum/element/eyestab) + if(TOOL_HEMOSTAT) + reference = /obj/item/hemostat + if(TOOL_RETRACTOR) + reference = /obj/item/retractor + if(TOOL_CAUTERY) + reference = /obj/item/cautery + if(TOOL_SAW) + reference = /obj/item/circular_saw + if(TOOL_BONESET) + reference = /obj/item/bonesetter + if(TOOL_DRAPES) + reference = /obj/item/surgical_drapes + AddComponent(/datum/component/surgery_initiator) + item_flags = null + +//Toolset for engineering cyborgs, this is all of the tools except for the welding tool. since it's quite hard to implement (read:can't be arsed to) +/obj/item/borg/cyborg_omnitool/engineering + name = "engineering omni-toolset" + desc = "A set of engineering tools used by cyborgs to conduct various engineering tasks." + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "toolkit_engiborg" + item_flags = null + toolspeed = 0.5 + upgraded_toolspeed = 0.3 + +/obj/item/borg/cyborg_omnitool/engineering/get_all_tool_behaviours() + return list(TOOL_SCREWDRIVER, TOOL_CROWBAR, TOOL_WRENCH, TOOL_WIRECUTTER, TOOL_MULTITOOL) + +/obj/item/borg/cyborg_omnitool/engineering/Initialize(mapload) + . = ..() + radial_menu_options = list( + TOOL_SCREWDRIVER = image(icon = 'icons/obj/tools.dmi', icon_state = "[TOOL_SCREWDRIVER]_map"), + TOOL_CROWBAR = image(icon = 'icons/obj/tools.dmi', icon_state = "[TOOL_CROWBAR]"), + TOOL_WRENCH = image(icon = 'icons/obj/tools.dmi', icon_state = "[TOOL_WRENCH]"), + TOOL_WIRECUTTER = image(icon = 'icons/obj/tools.dmi', icon_state = "[TOOL_WIRECUTTER]_map"), + TOOL_MULTITOOL = image(icon = 'icons/obj/devices/tool.dmi', icon_state = "[TOOL_MULTITOOL]"), + ) + +/obj/item/borg/cyborg_omnitool/engineering/reference_item_for_parameters() + RemoveElement(/datum/element/eyestab) + switch(tool_behaviour) + if(TOOL_SCREWDRIVER) + reference = /obj/item/screwdriver + AddElement(/datum/element/eyestab) + if(TOOL_CROWBAR) + reference = /obj/item/crowbar + if(TOOL_WRENCH) + reference = /obj/item/wrench + if(TOOL_WIRECUTTER) + reference = /obj/item/wirecutters + if(TOOL_MULTITOOL) + reference = /obj/item/multitool + #undef PKBORG_DAMPEN_CYCLE_DELAY #undef POWER_RECHARGE_CYBORG_DRAIN_MULTIPLIER +#undef NO_TOOL +#undef TOOL_DRAPES diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 9a1f92f58ec53..ae01c9e70181d 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -40,7 +40,10 @@ one_use = TRUE /obj/item/borg/upgrade/rename/attack_self(mob/user) - heldname = sanitize_name(tgui_input_text(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN), allow_numbers = TRUE) + var/new_heldname = sanitize_name(tgui_input_text(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN), allow_numbers = TRUE) + if(!new_heldname || !user.is_holding(src)) + return + heldname = new_heldname user.log_message("set \"[heldname]\" as a name in a cyborg reclassification board at [loc_name(user)]", LOG_GAME) /obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R, user = usr) @@ -295,7 +298,7 @@ /// Minimum time between repairs in seconds var/repair_cooldown = 4 var/on = FALSE - var/energy_cost = 10 KILO JOULES + var/energy_cost = 0.01 * STANDARD_CELL_CHARGE var/datum/action/toggle_action /obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R, user = usr) @@ -363,16 +366,16 @@ if(cyborg.health < cyborg.maxHealth) if(cyborg.health < 0) repair_amount = -2.5 - energy_cost = 30 KILO JOULES + energy_cost = 0.03 * STANDARD_CELL_CHARGE else repair_amount = -1 - energy_cost = 10 KILO JOULES + energy_cost = 0.01 * STANDARD_CELL_CHARGE cyborg.adjustBruteLoss(repair_amount) cyborg.adjustFireLoss(repair_amount) cyborg.updatehealth() cyborg.cell.use(energy_cost) else - cyborg.cell.use(5 KILO JOULES) + cyborg.cell.use(0.005 * STANDARD_CELL_CHARGE) next_repair = world.time + repair_cooldown * 10 // Multiply by 10 since world.time is in deciseconds if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_BORG_SELF_REPAIR)) @@ -398,6 +401,10 @@ /obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr) . = ..() + var/obj/item/borg/upgrade/hypospray/U = locate() in R + if(U) + to_chat(user, span_warning("This unit is already equipped with an expanded hypospray synthesiser!")) //check to see if we already have this module + return FALSE if(.) for(var/obj/item/reagent_containers/borghypo/medical/H in R.model.modules) H.upgrade_hypo() @@ -428,6 +435,7 @@ found_hypo = TRUE if(!found_hypo) + to_chat(user, span_warning("This unit is already equipped with a piercing hypospray upgrade!")) //check to see if we already have this module return FALSE /obj/item/borg/upgrade/piercing_hypospray/deactivate(mob/living/silicon/robot/R, user = usr) @@ -436,6 +444,60 @@ for(var/obj/item/reagent_containers/borghypo/H in R.model.modules) H.bypass_protection = initial(H.bypass_protection) +/obj/item/borg/upgrade/surgery_omnitool + name = "cyborg surgical omni-tool upgrade" + desc = "An upgrade to the Medical model, upgrading the built-in \ + surgical omnitool, to be on par with advanced surgical tools" + icon_state = "cyborg_upgrade3" + require_model = TRUE + model_type = list(/obj/item/robot_model/medical, /obj/item/robot_model/syndicate_medical) + model_flags = BORG_MODEL_MEDICAL + +/obj/item/borg/upgrade/surgery_omnitool/action(mob/living/silicon/robot/cyborg, user = usr) + . = ..() + if(!.) + return FALSE + for(var/obj/item/borg/cyborg_omnitool/medical/omnitool_upgrade in cyborg.model.modules) + if(omnitool_upgrade.upgraded) + to_chat(user, span_warning("This unit is already equipped with an omnitool upgrade!")) + return FALSE + for(var/obj/item/borg/cyborg_omnitool/medical/omnitool in cyborg.model.modules) + omnitool.upgrade_omnitool() + +/obj/item/borg/upgrade/surgery_omnitool/deactivate(mob/living/silicon/robot/cyborg, user = usr) + . = ..() + if(!.) + return FALSE + for(var/obj/item/borg/cyborg_omnitool/omnitool in cyborg.model.modules) + omnitool.downgrade_omnitool() + +/obj/item/borg/upgrade/engineering_omnitool + name = "cyborg engineering omni-tool upgrade" + desc = "An upgrade to the Engineering model, upgrading the built-in \ + engineering omnitool, to be on par with advanced engineering tools" + icon_state = "cyborg_upgrade3" + require_model = TRUE + model_type = list(/obj/item/robot_model/engineering, /obj/item/robot_model/saboteur) + model_flags = BORG_MODEL_ENGINEERING + +/obj/item/borg/upgrade/engineering_omnitool/action(mob/living/silicon/robot/cyborg, user = usr) + . = ..() + if(!.) + return FALSE + for(var/obj/item/borg/cyborg_omnitool/engineering/omnitool_upgrade in cyborg.model.modules) + if(omnitool_upgrade.upgraded) + to_chat(user, span_warning("This unit is already equipped with an omnitool upgrade!")) + return FALSE + for(var/obj/item/borg/cyborg_omnitool/engineering/omnitool in cyborg.model.modules) + omnitool.upgrade_omnitool() + +/obj/item/borg/upgrade/engineering_omnitool/deactivate(mob/living/silicon/robot/cyborg, user = usr) + . = ..() + if(!.) + return FALSE + for(var/obj/item/borg/cyborg_omnitool/omnitool in cyborg.model.modules) + omnitool.downgrade_omnitool() + /obj/item/borg/upgrade/defib name = "medical cyborg defibrillator" desc = "An upgrade to the Medical model, installing a built-in \ @@ -448,6 +510,10 @@ /obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R, user = usr) . = ..() if(.) + var/obj/item/borg/upgrade/defib/U = locate() in R + if(U) + to_chat(user, span_warning("This unit is already equipped with a defibrillator module!")) //check to see if we already have this module + return FALSE var/obj/item/borg/upgrade/defib/backpack/BP = locate() in R //If a full defib unit was used to upgrade prior, we can just pop it out now and replace if(BP) BP.deactivate(R, user) @@ -504,6 +570,10 @@ /obj/item/borg/upgrade/processor/action(mob/living/silicon/robot/R, user = usr) . = ..() if(.) + var/obj/item/borg/upgrade/processor/U = locate() in R + if(U) + to_chat(user, span_warning("This unit is already equipped with a surgical processor module!")) //check to see if we already have this module + return FALSE var/obj/item/surgical_processor/SP = new(R.model) R.model.basic_modules += SP R.model.add_module(SP, FALSE, TRUE) @@ -633,7 +703,6 @@ /obj/item/inducer/cyborg name = "Internal inducer" - powertransfer = 1500 icon = 'icons/obj/tools.dmi' icon_state = "inducer-engi" cell_type = null diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 3e3af7bc36f5e..2cc41b5d9f266 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -99,6 +99,15 @@ max_integrity = 55 w_class = WEIGHT_CLASS_NORMAL +/obj/item/shield/kite + name = "kite shield" + desc = "Protect your internal organs with this almond shaped shield." + icon_state = "kite" + inhand_icon_state = "kite" + custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 15) + shield_break_sound = 'sound/effects/grillehit.ogg' + max_integrity = 60 + /obj/item/shield/roman name = "\improper Roman shield" desc = "Bears an inscription on the inside: \"Romanes venio domus\"." @@ -231,7 +240,7 @@ return else to_chat(user, span_notice("You begin to replace the bulb...")) - if(do_after(user, 20, target = user)) + if(do_after(user, 2 SECONDS, target = user)) if(QDELETED(flash) || flash.burnt_out) return playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm index 5590bfd3c2ff0..f4c0b58a11bbe 100644 --- a/code/game/objects/items/spear.dm +++ b/code/game/objects/items/spear.dm @@ -160,13 +160,12 @@ . = ..() . += span_notice("Alt-click to set your war cry.") -/obj/item/spear/explosive/AltClick(mob/user) - if(user.can_perform_action(src)) - ..() - if(istype(user) && loc == user) - var/input = tgui_input_text(user, "What do you want your war cry to be? You will shout it when you hit someone in melee.", "War Cry", max_length = 50) - if(input) - src.war_cry = input +/obj/item/spear/explosive/click_alt(mob/user) + var/input = tgui_input_text(user, "What do you want your war cry to be? You will shout it when you hit someone in melee.", "War Cry", max_length = 50) + if(input) + war_cry = input + return CLICK_ACTION_SUCCESS + /obj/item/spear/explosive/afterattack(atom/movable/AM, mob/user, proximity) . = ..() @@ -217,6 +216,31 @@ M.Copy_Parent(user, 100, user.health/2.5, 12, 30) M.GiveTarget(L) +//MILITARY +/obj/item/spear/military + icon_state = "military_spear0" + base_icon_state = "military_spear0" + icon_prefix = "military_spear" + name = "military Javelin" + desc = "A stick with a seemingly blunt spearhead on its end. Looks like it might break bones easily." + attack_verb_continuous = list("attacks", "pokes", "jabs") + attack_verb_simple = list("attack", "poke", "jab") + throwforce = 30 + demolition_mod = 1 + wound_bonus = 5 + bare_wound_bonus = 25 + throw_range = 9 + throw_speed = 5 + sharpness = NONE // we break bones instead of cutting flesh + +/obj/item/spear/military/add_headpike_component() + var/static/list/slapcraft_recipe_list = list(/datum/crafting_recipe/headpikemilitary) + + AddComponent( + /datum/component/slapcrafting,\ + slapcraft_recipes = slapcraft_recipe_list,\ + ) + /* * Bone Spear */ diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm index 75c35eabb1818..641dce6cf4c7e 100644 --- a/code/game/objects/items/stacks/bscrystal.dm +++ b/code/game/objects/items/stacks/bscrystal.dm @@ -33,7 +33,7 @@ /obj/item/stack/ore/bluespace_crystal/attack_self(mob/user) user.visible_message(span_warning("[user] crushes [src]!"), span_danger("You crush [src]!")) new /obj/effect/particle_effect/sparks(loc) - playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(loc, 'sound/effects/portal_travel.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) blink_mob(user) use(1) @@ -45,7 +45,7 @@ visible_message(span_notice("[src] fizzles and disappears upon impact!")) var/turf/T = get_turf(hit_atom) new /obj/effect/particle_effect/sparks(T) - playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(loc, 'sound/effects/portal_travel.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(isliving(hit_atom)) blink_mob(hit_atom) use(1) @@ -67,6 +67,7 @@ icon = 'icons/obj/stack_objects.dmi' icon_state = "polycrystal" inhand_icon_state = null + gulag_valid = TRUE singular_name = "bluespace polycrystal" desc = "A stable polycrystal, made of fused-together bluespace crystals. You could probably break one off." mats_per_unit = list(/datum/material/bluespace=SHEET_MATERIAL_AMOUNT) @@ -74,7 +75,6 @@ attack_verb_simple = list("bluespace polybash", "bluespace polybatter", "bluespace polybludgeon", "bluespace polythrash", "bluespace polysmash") novariants = TRUE grind_results = list(/datum/reagent/bluespace = 20) - point_value = 90 merge_type = /obj/item/stack/sheet/bluespace_crystal material_type = /datum/material/bluespace var/crystal_type = /obj/item/stack/ore/bluespace_crystal/refined diff --git a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm index c55a39c20f76a..f54a83a8d8ec5 100644 --- a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm +++ b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm @@ -3,6 +3,7 @@ id = "golem_status" duration = 5 MINUTES alert_type = /atom/movable/screen/alert/status_effect/golem_status + show_duration = TRUE /// Icon state prefix for overlay to display on golem limbs var/overlay_state_prefix /// Name of the mineral we ate to get this @@ -160,6 +161,11 @@ owner.remove_traits(list(TRAIT_ANTIMAGIC, TRAIT_HOLY), TRAIT_STATUS_EFFECT(id)) return ..() +/// What do we multiply our damage by to convert it into power? +#define ENERGY_PER_DAMAGE (0.005 * STANDARD_CELL_CHARGE) +/// Multiplier to apply to burn damage, not 0 so that we can reverse it more easily +#define BURN_MULTIPLIER 0.05 + /// Heat immunity, turns heat damage into local power /datum/status_effect/golem/plasma overlay_state_prefix = "plasma" @@ -167,10 +173,6 @@ applied_fluff = "Plasma cooling rods sprout from your body. You can take the heat!" alert_icon_state = "sheet-plasma" alert_desc = "You are protected from high pressure and can convert heat damage into power." - /// What do we multiply our damage by to convert it into power? - var/energy_per_damage = 5 KILO JOULES - /// Multiplier to apply to burn damage, not 0 so that we can reverse it more easily - var/burn_multiplier = 0.05 /datum/status_effect/golem/plasma/on_apply() . = ..() @@ -179,14 +181,14 @@ owner.add_traits(list(TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTHEAT, TRAIT_ASHSTORM_IMMUNE), TRAIT_STATUS_EFFECT(id)) RegisterSignal(owner, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_burned)) var/mob/living/carbon/human/human_owner = owner - human_owner.physiology.burn_mod *= burn_multiplier + human_owner.physiology.burn_mod *= BURN_MULTIPLIER return TRUE /datum/status_effect/golem/plasma/on_remove() owner.remove_traits(list(TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTHEAT, TRAIT_ASHSTORM_IMMUNE), TRAIT_STATUS_EFFECT(id)) UnregisterSignal(owner, COMSIG_MOB_APPLY_DAMAGE) var/mob/living/carbon/human/human_owner = owner - human_owner.physiology.burn_mod /= burn_multiplier + human_owner.physiology.burn_mod /= BURN_MULTIPLIER return ..() /// When we take fire damage (or... technically also cold damage, we don't differentiate), zap a nearby APC @@ -195,7 +197,6 @@ if(damagetype != BURN) return - var/power = damage * energy_per_damage var/obj/machinery/power/energy_accumulator/ground = get_closest_atom(/obj/machinery/power/energy_accumulator, view(4, owner), owner) if (ground) zap_effect(ground) @@ -206,7 +207,10 @@ if (!our_apc) return zap_effect(our_apc) - our_apc.cell?.give(power) + our_apc.cell?.give(damage * ENERGY_PER_DAMAGE) + +#undef ENERGY_PER_DAMAGE +#undef BURN_MULTIPLIER /// Shoot a beam at the target atom /datum/status_effect/golem/plasma/proc/zap_effect(atom/target) @@ -291,7 +295,7 @@ /// Make our arm do slashing effects /datum/status_effect/golem/diamond/proc/set_arm_fluff(obj/item/bodypart/arm/arm) - arm.unarmed_attack_verb = "slash" + arm.unarmed_attack_verbs = list("slash") arm.grappled_attack_verb = "lacerate" arm.unarmed_attack_effect = ATTACK_EFFECT_CLAW arm.unarmed_attack_sound = 'sound/weapons/slash.ogg' @@ -312,7 +316,7 @@ /datum/status_effect/golem/diamond/proc/reset_arm_fluff(obj/item/bodypart/arm/arm) if (!arm) return - arm.unarmed_attack_verb = initial(arm.unarmed_attack_verb) + arm.unarmed_attack_verbs = initial(arm.unarmed_attack_verbs) arm.unarmed_attack_effect = initial(arm.unarmed_attack_effect) arm.unarmed_attack_sound = initial(arm.unarmed_attack_sound) arm.unarmed_miss_sound = initial(arm.unarmed_miss_sound) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 1f33384b39337..d76861b6c4932 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -35,7 +35,7 @@ /// Time it takes to assess injuries when looping healing var/assessing_injury_delay = 1 SECONDS -/obj/item/stack/medical/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/stack/medical/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!isliving(interacting_with)) return NONE if(!begin_heal_loop(interacting_with, user)) @@ -182,8 +182,8 @@ if(!try_heal_checks(patient, user, brute, burn)) return FALSE user.visible_message( - span_infoplain(span_green("[user] applies [src] on [patient]'s [parse_zone(affecting.body_zone)].")), - span_infoplain(span_green("You apply [src] on [patient]'s [parse_zone(affecting.body_zone)].")) + span_infoplain(span_green("[user] applies [src] on [patient]'s [affecting.plaintext_zone].")), + span_infoplain(span_green("You apply [src] on [patient]'s [affecting.plaintext_zone].")) ) var/previous_damage = affecting.get_damage() if(affecting.heal_damage(brute, burn)) @@ -419,11 +419,11 @@ return return ..() -/obj/item/stack/medical/mesh/AltClick(mob/living/user) +/obj/item/stack/medical/mesh/click_alt(mob/living/user) if(!is_open) balloon_alert(user, "open it first!") - return - return ..() + return CLICK_ACTION_BLOCKING + return CLICK_ACTION_SUCCESS /obj/item/stack/medical/mesh/attack_hand(mob/user, list/modifiers) if(!is_open && user.get_inactive_held_item() == src) diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index 064f933573ca3..63625536b74b5 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -1,19 +1,20 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \ - new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 2.5 SECONDS, one_per_turf = FALSE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("linen bin", /obj/structure/bedsheetbin/empty, 2, time = 0.5 SECONDS, one_per_turf = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("railing corner", /obj/structure/railing/corner, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("railing end", /obj/structure/railing/corner/end, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("railing end (flipped)", /obj/structure/railing/corner/end/flip, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("tank holder", /obj/structure/tank_holder, 2, time = 0.5 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("ladder", /obj/structure/ladder/crafted, 15, time = 15 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 1 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("linen bin", /obj/structure/bedsheetbin/empty, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("railing corner", /obj/structure/railing/corner, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("railing end", /obj/structure/railing/corner/end, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("railing end (flipped)", /obj/structure/railing/corner/end/flip, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("tank holder", /obj/structure/tank_holder, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("ladder", /obj/structure/ladder/crafted, 15, time = 15 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ new/datum/stack_recipe("catwalk floor tile", /obj/item/stack/tile/catwalk_tile, 1, 4, 20, category = CAT_TILES), \ - new/datum/stack_recipe("stairs frame", /obj/structure/stairs_frame, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("white cane", /obj/item/cane/white, 3, time = 1 SECONDS, one_per_turf = FALSE, category = CAT_TOOLS), \ - new/datum/stack_recipe("sharpened iron rod", /obj/item/ammo_casing/rebar, 1, time = 0.2 SECONDS, one_per_turf = FALSE, category = CAT_WEAPON_AMMO), \ + new/datum/stack_recipe("stairs frame", /obj/structure/stairs_frame, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("white cane", /obj/item/cane/white, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_TOOLS), \ + new/datum/stack_recipe("sharpened iron rod", /obj/item/ammo_casing/rebar, 1, time = 0.2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_WEAPON_AMMO), \ )) + /obj/item/stack/rods name = "iron rod" desc = "Some rods. Can be used for building or something." diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index d6bd65afe31e1..e93b8c4cea59d 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -9,9 +9,9 @@ * Glass sheets */ GLOBAL_LIST_INIT(glass_recipes, list ( \ - new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 1 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("glass shard", /obj/item/shard, time = 0, on_solid_ground = TRUE, category = CAT_MISC), \ + new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \ + new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ + new/datum/stack_recipe("glass shard", /obj/item/shard, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \ new/datum/stack_recipe("glass tile", /obj/item/stack/tile/glass, 1, 4, 20, category = CAT_TILES) \ )) @@ -27,7 +27,6 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \ merge_type = /obj/item/stack/sheet/glass grind_results = list(/datum/reagent/silicon = 20) material_type = /datum/material/glass - point_value = 1 tableVariant = /obj/structure/table/glass matter_amount = 4 cost = SHEET_MATERIAL_AMOUNT @@ -83,9 +82,9 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \ return ..() GLOBAL_LIST_INIT(pglass_recipes, list ( \ - new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 20, on_solid_ground = TRUE, category = CAT_MISC), \ + new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \ + new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ + new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 20, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \ new/datum/stack_recipe("plasma glass tile", /obj/item/stack/tile/glass/plasma, 1, 4, 20, category = CAT_TILES) \ )) @@ -139,11 +138,11 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \ * Reinforced glass sheets */ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \ - new/datum/stack_recipe("windoor frame", /obj/structure/windoor_assembly, 5, time = 0, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \ + new/datum/stack_recipe("windoor frame", /obj/structure/windoor_assembly, 5, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \ null, \ - new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("glass shard", /obj/item/shard, time = 10, on_solid_ground = TRUE, category = CAT_MISC), \ + new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \ + new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ + new/datum/stack_recipe("glass shard", /obj/item/shard, time = 10, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \ new/datum/stack_recipe("reinforced glass tile", /obj/item/stack/tile/rglass, 1, 4, 20, category = CAT_TILES) \ )) @@ -159,7 +158,6 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \ resistance_flags = ACID_PROOF merge_type = /obj/item/stack/sheet/rglass grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/iron = 10) - point_value = 12 matter_amount = 6 tableVariant = /obj/structure/table/reinforced/rglass @@ -179,9 +177,9 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \ . += GLOB.reinforced_glass_recipes GLOBAL_LIST_INIT(prglass_recipes, list ( \ - new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/plasma/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/plasma/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 40, on_solid_ground = TRUE, category = CAT_MISC), \ + new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/plasma/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \ + new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/plasma/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ + new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 40, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \ new/datum/stack_recipe("reinforced plasma glass tile", /obj/item/stack/tile/rglass/plasma, 1, 4, 20, category = CAT_TILES) \ )) @@ -197,7 +195,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \ material_flags = NONE merge_type = /obj/item/stack/sheet/plasmarglass grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10, /datum/reagent/iron = 10) - point_value = 69 + gulag_valid = TRUE matter_amount = 8 tableVariant = /obj/structure/table/reinforced/plasmarglass @@ -214,8 +212,8 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \ . += GLOB.prglass_recipes GLOBAL_LIST_INIT(titaniumglass_recipes, list( - new/datum/stack_recipe("shuttle window", /obj/structure/window/reinforced/shuttle/unanchored, 2, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("titanium glass shard", /obj/item/shard/titanium, time = 40, on_solid_ground = TRUE, category = CAT_MISC) \ + new/datum/stack_recipe("shuttle window", /obj/structure/window/reinforced/shuttle/unanchored, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ + new/datum/stack_recipe("titanium glass shard", /obj/item/shard/titanium, time = 40, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \ )) /obj/item/stack/sheet/titaniumglass @@ -243,8 +241,8 @@ GLOBAL_LIST_INIT(titaniumglass_recipes, list( . += GLOB.titaniumglass_recipes GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( - new/datum/stack_recipe("plastitanium window", /obj/structure/window/reinforced/plasma/plastitanium/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("plastitanium glass shard", /obj/item/shard/plastitanium, time = 60, on_solid_ground = TRUE, category = CAT_MISC) \ + new/datum/stack_recipe("plastitanium window", /obj/structure/window/reinforced/plasma/plastitanium/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ + new/datum/stack_recipe("plastitanium glass shard", /obj/item/shard/plastitanium, time = 60, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \ )) /obj/item/stack/sheet/plastitaniumglass diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index e9426a913ec70..2d1636e9e165a 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -14,8 +14,8 @@ merge_type = /obj/item/stack/sheet/animalhide/human GLOBAL_LIST_INIT(human_recipes, list( \ - new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("human skin hat", /obj/item/clothing/head/fedora/human_leather, 1, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("human skin hat", /obj/item/clothing/head/fedora/human_leather, 1, crafting_flags = NONE, category = CAT_CLOTHING), \ )) /obj/item/stack/sheet/animalhide/human/get_main_recipes() @@ -55,9 +55,9 @@ GLOBAL_LIST_INIT(human_recipes, list( \ amount = 5 GLOBAL_LIST_INIT(gondola_recipes, list ( \ - new/datum/stack_recipe("gondola mask", /obj/item/clothing/mask/gondola, 1, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("gondola suit", /obj/item/clothing/under/costume/gondola, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("gondola bedsheet", /obj/item/bedsheet/gondola, 1, check_density = FALSE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("gondola mask", /obj/item/clothing/mask/gondola, 1, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("gondola suit", /obj/item/clothing/under/costume/gondola, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("gondola bedsheet", /obj/item/bedsheet/gondola, 1, crafting_flags = NONE, category = CAT_FURNITURE), \ )) /obj/item/stack/sheet/animalhide/gondola @@ -73,7 +73,7 @@ GLOBAL_LIST_INIT(gondola_recipes, list ( \ . += GLOB.gondola_recipes GLOBAL_LIST_INIT(corgi_recipes, list ( \ - new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3, crafting_flags = NONE, category = CAT_CLOTHING), \ )) /obj/item/stack/sheet/animalhide/corgi/get_main_recipes() @@ -100,8 +100,8 @@ GLOBAL_LIST_INIT(corgi_recipes, list ( \ merge_type = /obj/item/stack/sheet/animalhide/monkey GLOBAL_LIST_INIT(monkey_recipes, list ( \ - new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/costume/monkeysuit, 2, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/costume/monkeysuit, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ )) /obj/item/stack/sheet/animalhide/monkey/get_main_recipes() @@ -131,8 +131,8 @@ GLOBAL_LIST_INIT(monkey_recipes, list ( \ merge_type = /obj/item/stack/sheet/animalhide/xeno GLOBAL_LIST_INIT(xeno_recipes, list ( \ - new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/costume/xenos, 1, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/costume/xenos, 2, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/costume/xenos, 1, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/costume/xenos, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ )) /obj/item/stack/sheet/animalhide/xeno/get_main_recipes() @@ -151,11 +151,11 @@ GLOBAL_LIST_INIT(xeno_recipes, list ( \ merge_type = /obj/item/stack/sheet/animalhide/carp GLOBAL_LIST_INIT(carp_recipes, list ( \ - new/datum/stack_recipe("carp costume", /obj/item/clothing/suit/hooded/carp_costume, 4, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("carp mask", /obj/item/clothing/mask/gas/carp, 1, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("carpskin chair", /obj/structure/chair/comfy/carp, 2, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("carpskin suit", /obj/item/clothing/under/suit/carpskin, 3, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("carpskin fedora", /obj/item/clothing/head/fedora/carpskin, 2, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("carp costume", /obj/item/clothing/suit/hooded/carp_costume, 4, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("carp mask", /obj/item/clothing/mask/gas/carp, 1, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("carpskin chair", /obj/structure/chair/comfy/carp, 2, crafting_flags = NONE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("carpskin suit", /obj/item/clothing/under/suit/carpskin, 3, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("carpskin fedora", /obj/item/clothing/head/fedora/carpskin, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ )) /obj/item/stack/sheet/animalhide/carp/get_main_recipes() @@ -193,33 +193,33 @@ GLOBAL_LIST_INIT(carp_recipes, list ( \ merge_type = /obj/item/stack/sheet/leather GLOBAL_LIST_INIT(leather_recipes, list ( \ - new/datum/stack_recipe("wallet", /obj/item/storage/wallet, 1, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("muzzle", /obj/item/clothing/mask/muzzle, 2, check_density = FALSE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("basketball", /obj/item/toy/basketball, 20, check_density = FALSE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("baseball", /obj/item/toy/beach_ball/baseball, 3, check_density = FALSE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("saddle", /obj/item/goliath_saddle, 5, check_density = FALSE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/laceup, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("cowboy boots", /obj/item/clothing/shoes/cowboy, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("botany gloves", /obj/item/clothing/gloves/botanic_leather, 3, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("leather satchel", /obj/item/storage/backpack/satchel/leather, 5, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("sheriff vest", /obj/item/clothing/accessory/vest_sheriff, 4, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("leather jacket", /obj/item/clothing/suit/jacket/leather, 7, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("biker jacket", /obj/item/clothing/suit/jacket/leather/biker, 7, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("wallet", /obj/item/storage/wallet, 1, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("muzzle", /obj/item/clothing/mask/muzzle, 2, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("basketball", /obj/item/toy/basketball, 20, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("baseball", /obj/item/toy/beach_ball/baseball, 3, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("saddle", /obj/item/goliath_saddle, 5, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/laceup, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("cowboy boots", /obj/item/clothing/shoes/cowboy, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("botany gloves", /obj/item/clothing/gloves/botanic_leather, 3, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("leather satchel", /obj/item/storage/backpack/satchel/leather, 5, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("sheriff vest", /obj/item/clothing/accessory/vest_sheriff, 4, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("leather jacket", /obj/item/clothing/suit/jacket/leather, 7, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("biker jacket", /obj/item/clothing/suit/jacket/leather/biker, 7, crafting_flags = NONE, category = CAT_CLOTHING), \ new/datum/stack_recipe_list("belts", list( \ - new/datum/stack_recipe("tool belt", /obj/item/storage/belt/utility, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("botanical belt", /obj/item/storage/belt/plant, 2, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("janitorial belt", /obj/item/storage/belt/janitor, 2, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("medical belt", /obj/item/storage/belt/medical, 2, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("security belt", /obj/item/storage/belt/security, 2, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("shoulder holster", /obj/item/storage/belt/holster, 3, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("bandolier", /obj/item/storage/belt/bandolier, 5, check_density = FALSE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("tool belt", /obj/item/storage/belt/utility, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("botanical belt", /obj/item/storage/belt/plant, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("janitorial belt", /obj/item/storage/belt/janitor, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("medical belt", /obj/item/storage/belt/medical, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("security belt", /obj/item/storage/belt/security, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("shoulder holster", /obj/item/storage/belt/holster, 3, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("bandolier", /obj/item/storage/belt/bandolier, 5, crafting_flags = NONE, category = CAT_CONTAINERS), \ )), new/datum/stack_recipe_list("cowboy hats", list( \ - new/datum/stack_recipe("sheriff hat", /obj/item/clothing/head/cowboy/brown, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("desperado hat", /obj/item/clothing/head/cowboy/black, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("ten-gallon hat", /obj/item/clothing/head/cowboy/white, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("deputy hat", /obj/item/clothing/head/cowboy/red, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("drifter hat", /obj/item/clothing/head/cowboy/grey, 2, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("sheriff hat", /obj/item/clothing/head/cowboy/brown, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("desperado hat", /obj/item/clothing/head/cowboy/black, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("ten-gallon hat", /obj/item/clothing/head/cowboy/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("deputy hat", /obj/item/clothing/head/cowboy/red, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("drifter hat", /obj/item/clothing/head/cowboy/grey, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ )), )) @@ -263,7 +263,7 @@ GLOBAL_LIST_INIT(leather_recipes, list ( \ merge_type = /obj/item/stack/sheet/sinew/wolf GLOBAL_LIST_INIT(sinew_recipes, list ( \ - new/datum/stack_recipe("sinew restraints", /obj/item/restraints/handcuffs/cable/sinew, 1, check_density = FALSE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("sinew restraints", /obj/item/restraints/handcuffs/cable/sinew, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \ )) /obj/item/stack/sheet/sinew/get_main_recipes() @@ -322,7 +322,7 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \ if(W.get_sharpness()) playsound(loc, 'sound/weapons/slice.ogg', 50, TRUE, -1) user.visible_message(span_notice("[user] starts cutting hair off \the [src]."), span_notice("You start cutting the hair off \the [src]..."), span_hear("You hear the sound of a knife rubbing against flesh.")) - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) to_chat(user, span_notice("You cut the hair from [src.name].")) new /obj/item/stack/sheet/hairlesshide(user.drop_location(), amount) use(amount) diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 0620d82cd9bf4..f6e7d797fd95c 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -24,8 +24,8 @@ Mineral Sheets */ GLOBAL_LIST_INIT(sandstone_recipes, list ( \ - new/datum/stack_recipe("sandstone door", /obj/structure/mineral_door/sandstone, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("Breakdown into sand", /obj/item/stack/ore/glass, 1, one_per_turf = FALSE, on_solid_ground = TRUE, category = CAT_MISC) \ + new/datum/stack_recipe("sandstone door", /obj/structure/mineral_door/sandstone, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \ + new/datum/stack_recipe("Breakdown into sand", /obj/item/stack/ore/glass, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \ )) /obj/item/stack/sheet/mineral/sandstone @@ -62,7 +62,7 @@ GLOBAL_LIST_INIT(sandstone_recipes, list ( \ merge_type = /obj/item/stack/sheet/mineral/sandbags GLOBAL_LIST_INIT(sandbag_recipes, list ( \ - new/datum/stack_recipe("sandbags", /obj/structure/barricade/sandbags, 1, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("sandbags", /obj/structure/barricade/sandbags, 1, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ )) /obj/item/stack/sheet/mineral/sandbags/get_main_recipes() @@ -99,14 +99,14 @@ GLOBAL_LIST_INIT(sandbag_recipes, list ( \ sheettype = "diamond" mats_per_unit = list(/datum/material/diamond=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/carbon = 20) - point_value = 75 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/diamond material_type = /datum/material/diamond walltype = /turf/closed/wall/mineral/diamond GLOBAL_LIST_INIT(diamond_recipes, list ( \ - new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("diamond tile", /obj/item/stack/tile/mineral/diamond, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \ + new/datum/stack_recipe("diamond tile", /obj/item/stack/tile/mineral/diamond, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) /obj/item/stack/sheet/mineral/diamond/get_main_recipes() @@ -124,14 +124,14 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \ sheettype = "uranium" mats_per_unit = list(/datum/material/uranium=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/uranium = 20) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/uranium material_type = /datum/material/uranium walltype = /turf/closed/wall/mineral/uranium GLOBAL_LIST_INIT(uranium_recipes, list ( \ - new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \ + new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) /obj/item/stack/sheet/mineral/uranium/get_main_recipes() @@ -157,7 +157,7 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \ max_integrity = 100 mats_per_unit = list(/datum/material/plasma=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/toxin/plasma = 20) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/plasma material_type = /datum/material/plasma walltype = /turf/closed/wall/mineral/plasma @@ -167,8 +167,8 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \ return TOXLOSS//dont you kids know that stuff is toxic? GLOBAL_LIST_INIT(plasma_recipes, list ( \ - new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("plasma tile", /obj/item/stack/tile/mineral/plasma, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \ + new/datum/stack_recipe("plasma tile", /obj/item/stack/tile/mineral/plasma, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) /obj/item/stack/sheet/mineral/plasma/get_main_recipes() @@ -192,16 +192,16 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \ sheettype = "gold" mats_per_unit = list(/datum/material/gold=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/gold = 20) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/gold material_type = /datum/material/gold walltype = /turf/closed/wall/mineral/gold GLOBAL_LIST_INIT(gold_recipes, list ( \ - new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("gold tile", /obj/item/stack/tile/mineral/gold, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ - new/datum/stack_recipe("blank plaque", /obj/item/plaque, 1, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("Simple Crown", /obj/item/clothing/head/costume/crown, 5, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \ + new/datum/stack_recipe("gold tile", /obj/item/stack/tile/mineral/gold, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ + new/datum/stack_recipe("blank plaque", /obj/item/plaque, 1, crafting_flags = NONE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("Simple Crown", /obj/item/clothing/head/costume/crown, 5, crafting_flags = NONE, category = CAT_CLOTHING), \ )) /obj/item/stack/sheet/mineral/gold/get_main_recipes() @@ -219,15 +219,15 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \ sheettype = "silver" mats_per_unit = list(/datum/material/silver=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/silver = 20) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/silver material_type = /datum/material/silver tableVariant = /obj/structure/table/optable walltype = /turf/closed/wall/mineral/silver GLOBAL_LIST_INIT(silver_recipes, list ( \ - new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("silver tile", /obj/item/stack/tile/mineral/silver, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \ + new/datum/stack_recipe("silver tile", /obj/item/stack/tile/mineral/silver, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) /obj/item/stack/sheet/mineral/silver/get_main_recipes() @@ -245,13 +245,13 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \ sheettype = "bananium" mats_per_unit = list(/datum/material/bananium=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/consumable/banana = 20) - point_value = 150 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/bananium material_type = /datum/material/bananium walltype = /turf/closed/wall/mineral/bananium GLOBAL_LIST_INIT(bananium_recipes, list ( \ - new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) /obj/item/stack/sheet/mineral/bananium/get_main_recipes() @@ -276,14 +276,14 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \ throw_range = 3 sheettype = "titanium" mats_per_unit = list(/datum/material/titanium=SHEET_MATERIAL_AMOUNT) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/titanium material_type = /datum/material/titanium walltype = /turf/closed/wall/mineral/titanium GLOBAL_LIST_INIT(titanium_recipes, list ( \ - new/datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ - new/datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ + new/datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ )) /obj/item/stack/sheet/mineral/titanium/get_main_recipes() @@ -308,14 +308,14 @@ GLOBAL_LIST_INIT(titanium_recipes, list ( \ throw_range = 3 sheettype = "plastitanium" mats_per_unit = list(/datum/material/alloy/plastitanium=SHEET_MATERIAL_AMOUNT) - point_value = 135 + gulag_valid = TRUE material_type = /datum/material/alloy/plastitanium merge_type = /obj/item/stack/sheet/mineral/plastitanium material_flags = NONE walltype = /turf/closed/wall/mineral/plastitanium GLOBAL_LIST_INIT(plastitanium_recipes, list ( \ - new/datum/stack_recipe("plastitanium tile", /obj/item/stack/tile/mineral/plastitanium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("plastitanium tile", /obj/item/stack/tile/mineral/plastitanium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) /obj/item/stack/sheet/mineral/plastitanium/get_main_recipes() @@ -341,10 +341,10 @@ GLOBAL_LIST_INIT(plastitanium_recipes, list ( \ material_type = /datum/material/snow GLOBAL_LIST_INIT(snow_recipes, list ( \ - new/datum/stack_recipe("snow wall", /turf/closed/wall/mineral/snow, 5, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("snowman", /obj/structure/statue/snow/snowman, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("snowball", /obj/item/toy/snowball, 1, check_density = FALSE, category = CAT_WEAPON_RANGED), \ - new/datum/stack_recipe("snow tile", /obj/item/stack/tile/mineral/snow, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("snow wall", /turf/closed/wall/mineral/snow, 5, time = 4 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("snowman", /obj/structure/statue/snow/snowman, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("snowball", /obj/item/toy/snowball, 1, crafting_flags = NONE, category = CAT_WEAPON_RANGED), \ + new/datum/stack_recipe("snow tile", /obj/item/stack/tile/mineral/snow, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) /obj/item/stack/sheet/mineral/snow/Initialize(mapload, new_amount, merge, list/mat_override, mat_amt) @@ -421,12 +421,12 @@ GLOBAL_LIST_INIT(adamantine_recipes, list( walltype = /turf/closed/wall/mineral/abductor GLOBAL_LIST_INIT(abductor_recipes, list ( \ - new/datum/stack_recipe("alien bed", /obj/structure/bed/abductor, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 2, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("alien table frame", /obj/structure/table_frame/abductor, 1, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ + new/datum/stack_recipe("alien bed", /obj/structure/bed/abductor, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("alien table frame", /obj/structure/table_frame/abductor, 1, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ null, \ - new/datum/stack_recipe("alien floor tile", /obj/item/stack/tile/mineral/abductor, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("alien floor tile", /obj/item/stack/tile/mineral/abductor, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ )) /obj/item/stack/sheet/mineral/abductor/get_main_recipes() @@ -469,10 +469,10 @@ GLOBAL_LIST_INIT(abductor_recipes, list ( \ //Metal Hydrogen GLOBAL_LIST_INIT(metalhydrogen_recipes, list( - new /datum/stack_recipe("incomplete servant golem shell", /obj/item/golem_shell/servant, req_amount=20, res_amount=1, check_density = FALSE, category = CAT_ROBOT), - new /datum/stack_recipe("ancient armor", /obj/item/clothing/suit/armor/elder_atmosian, req_amount = 5, res_amount = 1, check_density = FALSE, category = CAT_CLOTHING), - new /datum/stack_recipe("ancient helmet", /obj/item/clothing/head/helmet/elder_atmosian, req_amount = 3, res_amount = 1, check_density = FALSE, category = CAT_CLOTHING), - new /datum/stack_recipe("metallic hydrogen axe", /obj/item/fireaxe/metal_h2_axe, req_amount = 15, res_amount = 1, check_density = FALSE, category = CAT_WEAPON_MELEE), + new /datum/stack_recipe("incomplete servant golem shell", /obj/item/golem_shell/servant, req_amount=20, res_amount=1, crafting_flags = NONE, category = CAT_ROBOT), + new /datum/stack_recipe("ancient armor", /obj/item/clothing/suit/armor/elder_atmosian, req_amount = 5, res_amount = 1, crafting_flags = NONE, category = CAT_CLOTHING), + new /datum/stack_recipe("ancient helmet", /obj/item/clothing/head/helmet/elder_atmosian, req_amount = 3, res_amount = 1, crafting_flags = NONE, category = CAT_CLOTHING), + new /datum/stack_recipe("metallic hydrogen axe", /obj/item/fireaxe/metal_h2_axe, req_amount = 15, res_amount = 1, crafting_flags = NONE, category = CAT_WEAPON_MELEE), )) /obj/item/stack/sheet/mineral/metal_hydrogen @@ -482,7 +482,7 @@ GLOBAL_LIST_INIT(metalhydrogen_recipes, list( singular_name = "metal hydrogen sheet" w_class = WEIGHT_CLASS_NORMAL resistance_flags = FIRE_PROOF | LAVA_PROOF | ACID_PROOF | INDESTRUCTIBLE - point_value = 300 + gulag_valid = TRUE mats_per_unit = list(/datum/material/metalhydrogen = SHEET_MATERIAL_AMOUNT) material_type = /datum/material/metalhydrogen merge_type = /obj/item/stack/sheet/mineral/metal_hydrogen @@ -497,7 +497,7 @@ GLOBAL_LIST_INIT(metalhydrogen_recipes, list( inhand_icon_state = "sheet-zaukerite" singular_name = "zaukerite crystal" w_class = WEIGHT_CLASS_NORMAL - point_value = 360 + gulag_valid = TRUE mats_per_unit = list(/datum/material/zaukerite = SHEET_MATERIAL_AMOUNT) merge_type = /obj/item/stack/sheet/mineral/zaukerite material_type = /datum/material/zaukerite diff --git a/code/game/objects/items/stacks/sheets/runed_metal.dm b/code/game/objects/items/stacks/sheets/runed_metal.dm index b60cd67d389dc..44094a0bf789b 100644 --- a/code/game/objects/items/stacks/sheets/runed_metal.dm +++ b/code/game/objects/items/stacks/sheets/runed_metal.dm @@ -6,8 +6,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \ result_type = /obj/structure/destructible/cult/pylon, \ req_amount = 4, \ time = 4 SECONDS, \ - one_per_turf = TRUE, \ - on_solid_ground = TRUE, \ + crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, \ desc = span_cult_bold("Pylon: Heals and regenerates the blood of nearby blood cultists and constructs, and also \ converts nearby floor tiles into engraved flooring, which allows blood cultists to scribe runes faster."), \ required_noun = "runed metal sheet", \ @@ -18,8 +17,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \ result_type = /obj/structure/destructible/cult/item_dispenser/altar, \ req_amount = 3, \ time = 4 SECONDS, \ - one_per_turf = TRUE, \ - on_solid_ground = TRUE, \ + crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, \ desc = span_cult_bold("Altar: Can make Eldritch Whetstones, Construct Shells, and Flasks of Unholy Water."), \ required_noun = "runed metal sheet", \ category = CAT_CULT, \ @@ -29,8 +27,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \ result_type = /obj/structure/destructible/cult/item_dispenser/archives, \ req_amount = 3, \ time = 4 SECONDS, \ - one_per_turf = TRUE, \ - on_solid_ground = TRUE, \ + crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, \ desc = span_cult_bold("Archives: Can make Zealot's Blindfolds, Shuttle Curse Orbs, \ and Veil Walker equipment. Emits Light."), \ required_noun = "runed metal sheet", \ @@ -41,8 +38,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \ result_type = /obj/structure/destructible/cult/item_dispenser/forge, \ req_amount = 3, \ time = 4 SECONDS, \ - one_per_turf = TRUE, \ - on_solid_ground = TRUE, \ + crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, \ desc = span_cult_bold("Daemon Forge: Can make Nar'Sien Hardened Armor, Flagellant's Robes, \ and Eldritch Longswords. Emits Light."), \ required_noun = "runed metal sheet", \ @@ -52,8 +48,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \ title = "runed door", \ result_type = /obj/machinery/door/airlock/cult, \ time = 5 SECONDS, \ - one_per_turf = TRUE, \ - on_solid_ground = TRUE, \ + crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, \ desc = span_cult_bold("Runed Door: A weak door which stuns non-blood cultists who touch it."), \ required_noun = "runed metal sheet", \ category = CAT_CULT, \ @@ -62,9 +57,9 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \ title = "runed girder", \ result_type = /obj/structure/girder/cult, \ time = 5 SECONDS, \ - one_per_turf = TRUE, \ - on_solid_ground = TRUE, \ - desc = span_cult_bold("Runed Girder: A weak girder that can be instantly destroyed by ritual daggers. Not a recommended usage of runed metal."), \ + crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, \ + desc = span_cult_bold("Runed Girder: A weak girder that can be instantly destroyed by ritual daggers. \ + Not a recommended usage of runed metal."), \ required_noun = "runed metal sheet", \ category = CAT_CULT, \ ), \ diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index bad21b87ac306..155ba41171594 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -15,127 +15,127 @@ * Iron */ GLOBAL_LIST_INIT(metal_recipes, list ( \ - new/datum/stack_recipe("stool", /obj/structure/chair/stool, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("bar stool", /obj/structure/chair/stool/bar, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("bed", /obj/structure/bed, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("double bed", /obj/structure/bed/double, 4, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("stool", /obj/structure/chair/stool, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("bar stool", /obj/structure/chair/stool/bar, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("bed", /obj/structure/bed, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("double bed", /obj/structure/bed/double, 4, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ null, \ new/datum/stack_recipe_list("office chairs", list( \ - new/datum/stack_recipe("dark office chair", /obj/structure/chair/office, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("light office chair", /obj/structure/chair/office/light, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("dark office chair", /obj/structure/chair/office, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("light office chair", /obj/structure/chair/office/light, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ )), \ new/datum/stack_recipe_list("comfy chairs", list( \ - new/datum/stack_recipe("beige comfy chair", /obj/structure/chair/comfy/beige, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("black comfy chair", /obj/structure/chair/comfy/black, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("brown comfy chair", /obj/structure/chair/comfy/brown, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("lime comfy chair", /obj/structure/chair/comfy/lime, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("teal comfy chair", /obj/structure/chair/comfy/teal, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("beige comfy chair", /obj/structure/chair/comfy/beige, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("black comfy chair", /obj/structure/chair/comfy/black, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("brown comfy chair", /obj/structure/chair/comfy/brown, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("lime comfy chair", /obj/structure/chair/comfy/lime, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("teal comfy chair", /obj/structure/chair/comfy/teal, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ )), \ new/datum/stack_recipe_list("sofas", list( - new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/middle, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/left, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/right, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corner, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE) + new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/middle, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), + new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/left, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), + new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/right, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), + new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corner, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE) )), \ new/datum/stack_recipe_list("corporate sofas", list( \ - new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/corp, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/corp/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/corp/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corp/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/corp, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/corp/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/corp/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corp/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ )), \ new /datum/stack_recipe_list("benches", list( \ - new /datum/stack_recipe("bench (middle)", /obj/structure/chair/sofa/bench, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("bench (left)", /obj/structure/chair/sofa/bench/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("bench (right)", /obj/structure/chair/sofa/bench/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("bench (corner)", /obj/structure/chair/sofa/bench/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("tram bench (solo)", /obj/structure/chair/sofa/bench/tram/solo, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("tram bench (middle)", /obj/structure/chair/sofa/bench/tram, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("tram bench (left)", /obj/structure/chair/sofa/bench/tram/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("tram bench (right)", /obj/structure/chair/sofa/bench/tram/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("tram bench (corner)", /obj/structure/chair/sofa/bench/tram/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new /datum/stack_recipe("bench (middle)", /obj/structure/chair/sofa/bench, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("bench (left)", /obj/structure/chair/sofa/bench/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("bench (right)", /obj/structure/chair/sofa/bench/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("bench (corner)", /obj/structure/chair/sofa/bench/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("tram bench (solo)", /obj/structure/chair/sofa/bench/tram/solo, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("tram bench (middle)", /obj/structure/chair/sofa/bench/tram, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("tram bench (left)", /obj/structure/chair/sofa/bench/tram/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("tram bench (right)", /obj/structure/chair/sofa/bench/tram/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new /datum/stack_recipe("tram bench (corner)", /obj/structure/chair/sofa/bench/tram/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ )), \ new /datum/stack_recipe_list("chess pieces", list( \ - new /datum/stack_recipe("White Pawn", /obj/structure/chess/whitepawn, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("White Rook", /obj/structure/chess/whiterook, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("White Knight", /obj/structure/chess/whiteknight, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("White Bishop", /obj/structure/chess/whitebishop, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("White Queen", /obj/structure/chess/whitequeen, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("White King", /obj/structure/chess/whiteking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("Black Pawn", /obj/structure/chess/blackpawn, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("Black Rook", /obj/structure/chess/blackrook, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("Black Knight", /obj/structure/chess/blackknight, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("Black Bishop", /obj/structure/chess/blackbishop, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("Black Queen", /obj/structure/chess/blackqueen, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("Black King", /obj/structure/chess/blackking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("White Pawn", /obj/structure/chess/whitepawn, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("White Rook", /obj/structure/chess/whiterook, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("White Knight", /obj/structure/chess/whiteknight, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("White Bishop", /obj/structure/chess/whitebishop, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("White Queen", /obj/structure/chess/whitequeen, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("White King", /obj/structure/chess/whiteking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("Black Pawn", /obj/structure/chess/blackpawn, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("Black Rook", /obj/structure/chess/blackrook, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("Black Knight", /obj/structure/chess/blackknight, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("Black Bishop", /obj/structure/chess/blackbishop, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("Black Queen", /obj/structure/chess/blackqueen, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("Black King", /obj/structure/chess/blackking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ )), new /datum/stack_recipe_list("checkers pieces", list( \ - new /datum/stack_recipe("White Checker Man", /obj/structure/chess/checker/whiteman, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("White Checker King", /obj/structure/chess/checker/whiteking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("Black Checker Man", /obj/structure/chess/checker/blackman, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("Black Checker King", /obj/structure/chess/checker/blackking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("White Checker Man", /obj/structure/chess/checker/whiteman, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("White Checker King", /obj/structure/chess/checker/whiteking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("Black Checker Man", /obj/structure/chess/checker/blackman, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("Black Checker King", /obj/structure/chess/checker/blackking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ )), null, \ new/datum/stack_recipe("rack parts", /obj/item/rack_parts, category = CAT_FURNITURE), \ - new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ null, \ - new/datum/stack_recipe("atmos canister", /obj/machinery/portable_atmospherics/canister, 10, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ATMOSPHERIC), \ - new/datum/stack_recipe("pipe", /obj/item/pipe/quaternary/pipe/crafted, 1, time = 4 SECONDS, check_density = FALSE, category = CAT_ATMOSPHERIC), \ + new/datum/stack_recipe("atmos canister", /obj/machinery/portable_atmospherics/canister, 10, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ATMOSPHERIC), \ + new/datum/stack_recipe("pipe", /obj/item/pipe/quaternary/pipe/crafted, 1, time = 4 SECONDS, crafting_flags = NONE, category = CAT_ATMOSPHERIC), \ null, \ new/datum/stack_recipe("floor tile", /obj/item/stack/tile/iron/base, 1, 4, 20, category = CAT_TILES), \ new/datum/stack_recipe("iron rod", /obj/item/stack/rods, 1, 2, 60, category = CAT_MISC), \ null, \ - new/datum/stack_recipe("wall girders (anchored)", /obj/structure/girder, 2, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, placement_checks = STACK_CHECK_TRAM_FORBIDDEN, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("wall girders (anchored)", /obj/structure/girder, 2, time = 4 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, placement_checks = STACK_CHECK_TRAM_FORBIDDEN, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \ null, \ null, \ - new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("modular console", /obj/machinery/modular_computer, 10, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("modular console", /obj/machinery/modular_computer, 10, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \ null, \ new /datum/stack_recipe_list("airlock assemblies", list( \ - new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("public airlock assembly", /obj/structure/door_assembly/door_assembly_public, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("science airlock assembly", /obj/structure/door_assembly/door_assembly_science, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("hydroponics airlock assembly", /obj/structure/door_assembly/door_assembly_hydro, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("virology airlock assembly", /obj/structure/door_assembly/door_assembly_viro, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("external maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_extmai, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ + new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("public airlock assembly", /obj/structure/door_assembly/door_assembly_public, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("science airlock assembly", /obj/structure/door_assembly/door_assembly_science, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("hydroponics airlock assembly", /obj/structure/door_assembly/door_assembly_hydro, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("virology airlock assembly", /obj/structure/door_assembly/door_assembly_viro, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("external maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_extmai, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ )), \ null, \ - new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("meatspike frame", /obj/structure/kitchenspike_frame, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("meatspike frame", /obj/structure/kitchenspike_frame, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \ null, \ - new/datum/stack_recipe("grenade casing", /obj/item/grenade/chem_grenade, check_density = FALSE, category = CAT_CHEMISTRY), \ - new/datum/stack_recipe("light fixture frame", /obj/item/wallframe/light_fixture, 2, check_density = FALSE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("small light fixture frame", /obj/item/wallframe/light_fixture/small, 1, check_density = FALSE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("grenade casing", /obj/item/grenade/chem_grenade, crafting_flags = NONE, category = CAT_CHEMISTRY), \ + new/datum/stack_recipe("light fixture frame", /obj/item/wallframe/light_fixture, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("small light fixture frame", /obj/item/wallframe/light_fixture/small, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \ null, \ - new/datum/stack_recipe("apc frame", /obj/item/wallframe/apc, 2, check_density = FALSE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("air alarm frame", /obj/item/wallframe/airalarm, 2, check_density = FALSE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("fire alarm frame", /obj/item/wallframe/firealarm, 2, check_density = FALSE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("extinguisher cabinet frame", /obj/item/wallframe/extinguisher_cabinet, 2, check_density = FALSE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("button frame", /obj/item/wallframe/button, 1, check_density = FALSE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("apc frame", /obj/item/wallframe/apc, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("air alarm frame", /obj/item/wallframe/airalarm, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("fire alarm frame", /obj/item/wallframe/firealarm, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("extinguisher cabinet frame", /obj/item/wallframe/extinguisher_cabinet, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("button frame", /obj/item/wallframe/button, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \ null, \ - new/datum/stack_recipe("iron door", /obj/structure/mineral_door/iron, 20, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 2, time = 10 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("desk bell", /obj/structure/desk_bell, 2, time = 3 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("floodlight frame", /obj/structure/floodlight_frame, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("voting box", /obj/structure/votebox, 15, time = 5 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 5 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \ - new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 5 SECONDS, check_density = FALSE, category = CAT_ROBOT), \ - new/datum/stack_recipe("shower frame", /obj/structure/showerframe, 2, time = 2 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("urinal", /obj/item/wallframe/urinal, 2, time = 1 SECONDS, check_density = FALSE, category = CAT_FURNITURE) + new/datum/stack_recipe("iron door", /obj/structure/mineral_door/iron, 20, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \ + new/datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 2, time = 10 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("desk bell", /obj/structure/desk_bell, 2, time = 3 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("floodlight frame", /obj/structure/floodlight_frame, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("voting box", /obj/structure/votebox, 15, time = 5 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 5 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \ + new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 5 SECONDS, crafting_flags = NONE, category = CAT_ROBOT), \ + new/datum/stack_recipe("shower frame", /obj/structure/showerframe, 2, time = 2 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("urinal", /obj/item/wallframe/urinal, 2, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE) )) /obj/item/stack/sheet/iron @@ -150,7 +150,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ resistance_flags = FIRE_PROOF merge_type = /obj/item/stack/sheet/iron grind_results = list(/datum/reagent/iron = 20) - point_value = 6 + gulag_valid = TRUE tableVariant = /obj/structure/table material_type = /datum/material/iron matter_amount = 4 @@ -253,13 +253,14 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ * Plasteel */ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ - new/datum/stack_recipe("AI core", /obj/structure/ai_core, 4, time = 5 SECONDS, one_per_turf = TRUE, check_density = FALSE, category = CAT_ROBOT), - new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 5 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), - new/datum/stack_recipe("Large Gas Tank", /obj/structure/tank_frame, 4, time=1 SECONDS, one_per_turf=TRUE, check_density = FALSE, category = CAT_ATMOSPHERIC), + new/datum/stack_recipe("AI core", /obj/structure/ai_core, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF, category = CAT_ROBOT), + new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 5 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), + new/datum/stack_recipe("Large Gas Tank", /obj/structure/tank_frame, 4, time=1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF, category = CAT_ATMOSPHERIC), + new/datum/stack_recipe("shutter assembly", /obj/machinery/door/poddoor/shutters/preopen/deconstructed, 5, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_DOORS), null, new /datum/stack_recipe_list("airlock assemblies", list( \ - new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), - new/datum/stack_recipe("vault door assembly", /obj/structure/door_assembly/door_assembly_vault, 6, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), + new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), + new/datum/stack_recipe("vault door assembly", /obj/structure/door_assembly/door_assembly_vault, 6, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), )), \ )) @@ -277,7 +278,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ resistance_flags = FIRE_PROOF merge_type = /obj/item/stack/sheet/plasteel grind_results = list(/datum/reagent/iron = 20, /datum/reagent/toxin/plasma = 20) - point_value = 69 + gulag_valid = TRUE tableVariant = /obj/structure/table/reinforced material_flags = NONE matter_amount = 12 @@ -300,49 +301,50 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ * Wood */ GLOBAL_LIST_INIT(wood_recipes, list ( \ - new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ - new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 1 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 3 SECONDS, check_density = FALSE, category = CAT_TOOLS), \ - new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("wooden stairs frame", /obj/structure/stairs_frame/wood, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("wooden fence", /obj/structure/railing/wooden_fence, 2, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("cat house", /obj/structure/cat_house, 5, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \ - new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \ - new/datum/stack_recipe("wooden barrel", /obj/structure/fermenting_barrel, 8, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT),\ - new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT),\ - new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("wooden buckler", /obj/item/shield/buckler, 20, time = 4 SECONDS, check_density = FALSE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 5 SECONDS, check_density = FALSE, category = CAT_TOOLS),\ - new/datum/stack_recipe("mannequin", /obj/structure/mannequin/wood, 25, time = 5 SECONDS, one_per_turf = TRUE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("smoking pipe", /obj/item/clothing/mask/cigarette/pipe, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_TOOLS),\ - new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/cup/bucket/wooden, 3, time = 1 SECONDS, check_density = FALSE, category = CAT_CONTAINERS),\ - new/datum/stack_recipe("rake", /obj/item/cultivator/rake, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_TOOLS),\ - new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS),\ - new/datum/stack_recipe("wooden crate", /obj/structure/closet/crate/wooden, 6, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),\ - new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 1.5 SECONDS, check_density = FALSE, category = CAT_WEAPON_MELEE),\ - new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \ - new/datum/stack_recipe("mortar", /obj/item/reagent_containers/cup/mortar, 3, check_density = FALSE, category = CAT_CHEMISTRY), \ - new/datum/stack_recipe("firebrand", /obj/item/match/firebrand, 2, time = 10 SECONDS, check_density = FALSE, category = CAT_TOOLS), \ - new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 10, time = 6 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \ - new/datum/stack_recipe("easel", /obj/structure/easel, 5, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("noticeboard", /obj/item/wallframe/noticeboard, 1, time = 1 SECONDS, one_per_turf = FALSE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("test tube rack", /obj/item/storage/test_tube_rack, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \ + new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ + new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 3 SECONDS, crafting_flags = NONE, category = CAT_TOOLS), \ + new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new/datum/stack_recipe("wooden stairs frame", /obj/structure/stairs_frame/wood, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("wooden fence", /obj/structure/railing/wooden_fence, 2, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("raptor trough", /obj/structure/ore_container/food_trough/raptor_trough, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("cat house", /obj/structure/cat_house, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \ + new/datum/stack_recipe("wooden barrel", /obj/structure/fermenting_barrel, 8, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT),\ + new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT),\ + new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("wooden buckler", /obj/item/shield/buckler, 20, time = 4 SECONDS, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 5 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\ + new/datum/stack_recipe("mannequin", /obj/structure/mannequin/wood, 25, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("smoking pipe", /obj/item/clothing/mask/cigarette/pipe, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\ + new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/cup/bucket/wooden, 3, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CONTAINERS),\ + new/datum/stack_recipe("rake", /obj/item/cultivator/rake, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\ + new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS),\ + new/datum/stack_recipe("wooden crate", /obj/structure/closet/crate/wooden, 6, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),\ + new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 1.5 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_MELEE),\ + new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \ + new/datum/stack_recipe("mortar", /obj/item/reagent_containers/cup/mortar, 3, crafting_flags = NONE, category = CAT_CHEMISTRY), \ + new/datum/stack_recipe("firebrand", /obj/item/match/firebrand, 2, time = 10 SECONDS, crafting_flags = NONE, category = CAT_TOOLS), \ + new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 10, time = 6 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \ + new/datum/stack_recipe("easel", /obj/structure/easel, 5, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("noticeboard", /obj/item/wallframe/noticeboard, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("test tube rack", /obj/item/storage/test_tube_rack, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \ null, \ new/datum/stack_recipe_list("pews", list( - new /datum/stack_recipe("pew (middle)", /obj/structure/chair/pew, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("pew (left)", /obj/structure/chair/pew/left, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE) + new /datum/stack_recipe("pew (middle)", /obj/structure/chair/pew, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), + new /datum/stack_recipe("pew (left)", /obj/structure/chair/pew/left, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), + new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE) )), null, \ )) @@ -379,19 +381,19 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ */ GLOBAL_LIST_INIT(bamboo_recipes, list ( \ - new/datum/stack_recipe("punji sticks trap", /obj/structure/punji_sticks, 5, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \ - new/datum/stack_recipe("bamboo spear", /obj/item/spear/bamboospear, 25, time = 9 SECONDS, check_density = FALSE, category = CAT_WEAPON_MELEE), \ - new/datum/stack_recipe("blow gun", /obj/item/gun/syringe/blowgun, 10, time = 7 SECONDS, check_density = FALSE, category = CAT_WEAPON_RANGED), \ - new/datum/stack_recipe("crude syringe", /obj/item/reagent_containers/syringe/crude, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \ - new/datum/stack_recipe("rice hat", /obj/item/clothing/head/costume/rice_hat, 10, time = 7 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("punji sticks trap", /obj/structure/punji_sticks, 5, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \ + new/datum/stack_recipe("bamboo spear", /obj/item/spear/bamboospear, 25, time = 9 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_MELEE), \ + new/datum/stack_recipe("blow gun", /obj/item/gun/syringe/blowgun, 10, time = 7 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_RANGED), \ + new/datum/stack_recipe("crude syringe", /obj/item/reagent_containers/syringe/crude, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \ + new/datum/stack_recipe("rice hat", /obj/item/clothing/head/costume/rice_hat, 10, time = 7 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \ null, \ - new/datum/stack_recipe("bamboo stool", /obj/structure/chair/stool/bamboo, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("bamboo mat piece", /obj/item/stack/tile/bamboo, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ + new/datum/stack_recipe("bamboo stool", /obj/structure/chair/stool/bamboo, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ + new/datum/stack_recipe("bamboo mat piece", /obj/item/stack/tile/bamboo, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ null, \ new/datum/stack_recipe_list("bamboo benches", list( - new /datum/stack_recipe("bamboo bench (middle)", /obj/structure/chair/sofa/bamboo, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("bamboo bench (left)", /obj/structure/chair/sofa/bamboo/left, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), - new /datum/stack_recipe("bamboo bench (right)", /obj/structure/chair/sofa/bamboo/right, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE) + new /datum/stack_recipe("bamboo bench (middle)", /obj/structure/chair/sofa/bamboo, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), + new /datum/stack_recipe("bamboo bench (left)", /obj/structure/chair/sofa/bamboo/left, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), + new /datum/stack_recipe("bamboo bench (right)", /obj/structure/chair/sofa/bamboo/right, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE) )), \ )) @@ -426,41 +428,41 @@ GLOBAL_LIST_INIT(bamboo_recipes, list ( \ * Cloth */ GLOBAL_LIST_INIT(cloth_recipes, list ( \ - new/datum/stack_recipe("white jumpskirt", /obj/item/clothing/under/color/jumpskirt/white, 3, check_density = FALSE, category = CAT_CLOTHING), /*Ladies first*/ \ - new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 3, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("white shoes", /obj/item/clothing/shoes/sneakers/white, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("white bandana", /obj/item/clothing/mask/bandana/white, 2, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("white jumpskirt", /obj/item/clothing/under/color/jumpskirt/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), /*Ladies first*/ \ + new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("white shoes", /obj/item/clothing/shoes/sneakers/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("white bandana", /obj/item/clothing/mask/bandana/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ null, \ - new/datum/stack_recipe("backpack", /obj/item/storage/backpack, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("satchel", /obj/item/storage/backpack/satchel, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("messenger bag", /obj/item/storage/backpack/messenger, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("duffel bag", /obj/item/storage/backpack/duffelbag, 6, check_density = FALSE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("backpack", /obj/item/storage/backpack, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("satchel", /obj/item/storage/backpack/satchel, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("messenger bag", /obj/item/storage/backpack/messenger, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("duffel bag", /obj/item/storage/backpack/duffelbag, 6, crafting_flags = NONE, category = CAT_CONTAINERS), \ null, \ - new/datum/stack_recipe("plant bag", /obj/item/storage/bag/plants, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("book bag", /obj/item/storage/bag/books, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("mining satchel", /obj/item/storage/bag/ore, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("science bag", /obj/item/storage/bag/xeno, 4, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("construction bag", /obj/item/storage/bag/construction, 4, check_density = FALSE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("plant bag", /obj/item/storage/bag/plants, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("book bag", /obj/item/storage/bag/books, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("mining satchel", /obj/item/storage/bag/ore, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("science bag", /obj/item/storage/bag/xeno, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("construction bag", /obj/item/storage/bag/construction, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ null, \ - new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6, check_density = FALSE, category = CAT_TOOLS), \ - new/datum/stack_recipe("rag", /obj/item/reagent_containers/cup/rag, 1, check_density = FALSE, category = CAT_CHEMISTRY), \ - new/datum/stack_recipe("bedsheet", /obj/item/bedsheet, 3, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("double bedsheet", /obj/item/bedsheet/double, 6, check_density = FALSE, category = CAT_FURNITURE), \ - new/datum/stack_recipe("empty sandbag", /obj/item/emptysandbag, 4, check_density = FALSE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6, crafting_flags = NONE, category = CAT_TOOLS), \ + new/datum/stack_recipe("rag", /obj/item/reagent_containers/cup/rag, 1, crafting_flags = NONE, category = CAT_CHEMISTRY), \ + new/datum/stack_recipe("bedsheet", /obj/item/bedsheet, 3, crafting_flags = NONE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("double bedsheet", /obj/item/bedsheet/double, 6, crafting_flags = NONE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("empty sandbag", /obj/item/emptysandbag, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \ null, \ - new/datum/stack_recipe("fingerless gloves", /obj/item/clothing/gloves/fingerless, 1, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 3, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("white softcap", /obj/item/clothing/head/soft/mime, 2, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("white beanie", /obj/item/clothing/head/beanie, 2, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("fingerless gloves", /obj/item/clothing/gloves/fingerless, 1, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("white softcap", /obj/item/clothing/head/soft/mime, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("white beanie", /obj/item/clothing/head/beanie, 2, crafting_flags = NONE, category = CAT_CLOTHING), \ null, \ - new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/blindfold, 2, check_density = FALSE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/blindfold, 2, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ null, \ - new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteen_nineteen, 3, check_density = FALSE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythree_nineteen, 4, check_density = FALSE, category = CAT_ENTERTAINMENT), \ - new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythree_twentythree, 5, check_density = FALSE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteen_nineteen, 3, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythree_nineteen, 4, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythree_twentythree, 5, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ new/datum/stack_recipe("pillow", /obj/item/pillow, 3, category = CAT_FURNITURE), \ )) @@ -489,10 +491,10 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \ amount = 5 GLOBAL_LIST_INIT(durathread_recipes, list ( \ - new/datum/stack_recipe("durathread jumpsuit", /obj/item/clothing/under/misc/durathread, 4, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING), - new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 2.5 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("durathread jumpsuit", /obj/item/clothing/under/misc/durathread, 4, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), + new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 2.5 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \ )) /obj/item/stack/sheet/durathread @@ -563,61 +565,66 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \ * Cardboard */ GLOBAL_LIST_INIT(cardboard_recipes, list ( \ - new/datum/stack_recipe("box", /obj/item/storage/box, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/costume/cardborg, 3, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/costume/cardborg, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5, check_density = FALSE, category = CAT_ENTERTAINMENT), \ + new/datum/stack_recipe("box", /obj/item/storage/box, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/costume/cardborg, 3, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/costume/cardborg, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \ null, \ - new/datum/stack_recipe("pizza box", /obj/item/pizzabox, check_density = FALSE, category = CAT_CONTAINERS), \ - new/datum/stack_recipe("folder", /obj/item/folder, check_density = FALSE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("pizza box", /obj/item/pizzabox, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new/datum/stack_recipe("folder", /obj/item/folder, crafting_flags = NONE, category = CAT_CONTAINERS), \ null, \ //TO-DO: Find a proper way to just change the illustration on the box. Code isn't the issue, input is. new/datum/stack_recipe_list("fancy boxes", list( - new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("donk-pockets box", /obj/item/storage/box/donkpockets, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("donk-pockets spicy box", /obj/item/storage/box/donkpockets/donkpocketspicy, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("donk-pockets teriyaki box", /obj/item/storage/box/donkpockets/donkpocketteriyaki, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("donk-pockets pizza box", /obj/item/storage/box/donkpockets/donkpocketpizza, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("donk-pockets berry box", /obj/item/storage/box/donkpockets/donkpocketberry, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("donk-pockets honk box", /obj/item/storage/box/donkpockets/donkpockethonk, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("monkey cube box", /obj/item/storage/box/monkeycubes, check_density = FALSE, category = CAT_CONTAINERS), - new /datum/stack_recipe("nugget box", /obj/item/storage/fancy/nugget_box, check_density = FALSE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("donk-pockets box", /obj/item/storage/box/donkpockets, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("donk-pockets spicy box", /obj/item/storage/box/donkpockets/donkpocketspicy, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("donk-pockets teriyaki box", /obj/item/storage/box/donkpockets/donkpocketteriyaki, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("donk-pockets pizza box", /obj/item/storage/box/donkpockets/donkpocketpizza, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("donk-pockets berry box", /obj/item/storage/box/donkpockets/donkpocketberry, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("donk-pockets honk box", /obj/item/storage/box/donkpockets/donkpockethonk, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("monkey cube box", /obj/item/storage/box/monkeycubes, crafting_flags = NONE, category = CAT_CONTAINERS), + new /datum/stack_recipe("nugget box", /obj/item/storage/fancy/nugget_box, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("drinking glasses box", /obj/item/storage/box/drinkingglasses, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("paper cups box", /obj/item/storage/box/cups, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("cigar case", /obj/item/storage/fancy/cigarettes/cigars, crafting_flags = NONE, category = CAT_CONTAINERS), \ null, \ - new /datum/stack_recipe("lethal ammo box", /obj/item/storage/box/lethalshot, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("rubber shot ammo box", /obj/item/storage/box/rubbershot, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("bean bag ammo box", /obj/item/storage/box/beanbag, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("flashbang box", /obj/item/storage/box/flashbangs, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("flashes box", /obj/item/storage/box/flashes, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("handcuffs box", /obj/item/storage/box/handcuffs, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("ID card box", /obj/item/storage/box/ids, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("PDA box", /obj/item/storage/box/pdas, check_density = FALSE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("lethal ammo box", /obj/item/storage/box/lethalshot, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("rubber shot ammo box", /obj/item/storage/box/rubbershot, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("bean bag ammo box", /obj/item/storage/box/beanbag, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("flashbang box", /obj/item/storage/box/flashbangs, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("flashes box", /obj/item/storage/box/flashes, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("handcuffs box", /obj/item/storage/box/handcuffs, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("ID card box", /obj/item/storage/box/ids, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("PDA box", /obj/item/storage/box/pdas, crafting_flags = NONE, category = CAT_CONTAINERS), \ null, \ - new /datum/stack_recipe("pillbottle box", /obj/item/storage/box/pillbottles, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("beaker box", /obj/item/storage/box/beakers, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("syringe box", /obj/item/storage/box/syringes, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("latex gloves box", /obj/item/storage/box/gloves, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("sterile masks box", /obj/item/storage/box/masks, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("body bag box", /obj/item/storage/box/bodybags, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("perscription glasses box", /obj/item/storage/box/rxglasses, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("medipen box", /obj/item/storage/box/medipens, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("oxygen tank box", /obj/item/storage/box/emergencytank, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("extended oxygen tank box", /obj/item/storage/box/engitank, check_density = FALSE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("pillbottle box", /obj/item/storage/box/pillbottles, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("medical gels box", /obj/item/storage/box/medigels, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("beaker box", /obj/item/storage/box/beakers, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("syringe box", /obj/item/storage/box/syringes, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("latex gloves box", /obj/item/storage/box/gloves, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("sterile masks box", /obj/item/storage/box/masks, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("body bag box", /obj/item/storage/box/bodybags, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("prescription glasses box", /obj/item/storage/box/rxglasses, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("medipen box", /obj/item/storage/box/medipens, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("DNA injectors box", /obj/item/storage/box/injectors, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("oxygen tank box", /obj/item/storage/box/emergencytank, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("extended oxygen tank box", /obj/item/storage/box/engitank, crafting_flags = NONE, category = CAT_CONTAINERS), \ null, \ - new /datum/stack_recipe("survival box", /obj/item/storage/box/survival/crafted, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("extended tank survival box", /obj/item/storage/box/survival/engineer/crafted, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("disk box", /obj/item/storage/box/disks, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("light tubes box", /obj/item/storage/box/lights/tubes, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("light bulbs box", /obj/item/storage/box/lights/bulbs, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("mixed lights box", /obj/item/storage/box/lights/mixed, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("mouse traps box", /obj/item/storage/box/mousetraps, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("bandage box", /obj/item/storage/box/bandages, check_density = FALSE, category = CAT_CONTAINERS) + new /datum/stack_recipe("survival box", /obj/item/storage/box/survival/crafted, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("extended tank survival box", /obj/item/storage/box/survival/engineer/crafted, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("disk box", /obj/item/storage/box/disks, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("light tubes box", /obj/item/storage/box/lights/tubes, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("light bulbs box", /obj/item/storage/box/lights/bulbs, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("mixed lights box", /obj/item/storage/box/lights/mixed, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("mouse traps box", /obj/item/storage/box/mousetraps, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("bandage box", /obj/item/storage/box/bandages, crafting_flags = NONE, category = CAT_CONTAINERS) )), null, \ @@ -675,18 +682,18 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \ */ GLOBAL_LIST_INIT(bronze_recipes, list ( \ - new/datum/stack_recipe("wall gear", /obj/structure/girder/bronze, 2, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("wall gear", /obj/structure/girder/bronze, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ null, - new/datum/stack_recipe("directional bronze window", /obj/structure/window/bronze/unanchored, time = 0, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("fulltile bronze window", /obj/structure/window/bronze/fulltile/unanchored, 2, time = 0, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \ - new/datum/stack_recipe("pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("bronze pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze/seethru, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \ - new/datum/stack_recipe("bronze floor tile", /obj/item/stack/tile/bronze, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \ - new/datum/stack_recipe("bronze hat", /obj/item/clothing/head/costume/bronze, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("bronze suit", /obj/item/clothing/suit/costume/bronze, check_density = FALSE, category = CAT_CLOTHING), \ - new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze, check_density = FALSE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("directional bronze window", /obj/structure/window/bronze/unanchored, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \ + new/datum/stack_recipe("fulltile bronze window", /obj/structure/window/bronze/fulltile/unanchored, 2, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ + new/datum/stack_recipe("pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new/datum/stack_recipe("bronze pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze/seethru, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ + new/datum/stack_recipe("bronze floor tile", /obj/item/stack/tile/bronze, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \ + new/datum/stack_recipe("bronze hat", /obj/item/clothing/head/costume/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("bronze suit", /obj/item/clothing/suit/costume/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \ + new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \ null, - new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \ + new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ )) /obj/item/stack/sheet/bronze @@ -773,29 +780,33 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \ // As bone and sinew have just a little too many recipes for this, we'll just split them up. // Sinew slapcrafting will mostly-sinew recipes, and bones will have mostly-bones recipes. - var/static/list/slapcraft_recipe_list = list(\ - /datum/crafting_recipe/bonedagger, /datum/crafting_recipe/bonespear, /datum/crafting_recipe/boneaxe,\ - /datum/crafting_recipe/bonearmor, /datum/crafting_recipe/skullhelm, /datum/crafting_recipe/bracers - ) + var/static/list/slapcraft_recipe_list = list( + /datum/crafting_recipe/bonearmor, + /datum/crafting_recipe/boneaxe, + /datum/crafting_recipe/bonedagger, + /datum/crafting_recipe/bonespear, + /datum/crafting_recipe/bracers, + /datum/crafting_recipe/skullhelm, + ) AddComponent( /datum/component/slapcrafting,\ slapcraft_recipes = slapcraft_recipe_list,\ ) GLOBAL_LIST_INIT(plastic_recipes, list( - new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \ - new /datum/stack_recipe("light tram tile", /obj/item/stack/thermoplastic/light, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \ - new /datum/stack_recipe("dark tram tile", /obj/item/stack/thermoplastic, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \ - new /datum/stack_recipe("folding plastic chair", /obj/structure/chair/plastic, 2, check_density = FALSE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, one_per_turf = TRUE, on_solid_ground = TRUE, time = 4 SECONDS, category = CAT_FURNITURE), \ - new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/large/empty, 3, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("colo cups", /obj/item/reagent_containers/cup/glass/colocup, 1, check_density = FALSE, category = CAT_CONTAINERS), \ - new /datum/stack_recipe("mannequin", /obj/structure/mannequin/plastic, 25, time = 5 SECONDS, one_per_turf = TRUE, check_density = FALSE, category = CAT_ENTERTAINMENT), \ - new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2, check_density = FALSE, category = CAT_EQUIPMENT), \ - new /datum/stack_recipe("warning cone", /obj/item/clothing/head/cone, 2, check_density = FALSE, category = CAT_EQUIPMENT), \ - new /datum/stack_recipe("blank wall sign", /obj/item/sign, 1, check_density = FALSE, category = CAT_FURNITURE), \ - new /datum/stack_recipe("rebellion mask", /obj/item/clothing/mask/rebellion, 1, check_density = FALSE, category = CAT_CLOTHING))) + new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \ + new /datum/stack_recipe("light tram tile", /obj/item/stack/thermoplastic/light, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \ + new /datum/stack_recipe("dark tram tile", /obj/item/stack/thermoplastic, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \ + new /datum/stack_recipe("folding plastic chair", /obj/structure/chair/plastic, 2, crafting_flags = NONE, category = CAT_FURNITURE), \ + new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, time = 4 SECONDS, category = CAT_FURNITURE), \ + new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/large/empty, 3, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("colo cups", /obj/item/reagent_containers/cup/glass/colocup, 1, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("mannequin", /obj/structure/mannequin/plastic, 25, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_ENTERTAINMENT), \ + new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new /datum/stack_recipe("warning cone", /obj/item/clothing/head/cone, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ + new /datum/stack_recipe("blank wall sign", /obj/item/sign, 1, crafting_flags = NONE, category = CAT_FURNITURE), \ + new /datum/stack_recipe("rebellion mask", /obj/item/clothing/mask/rebellion, 1, crafting_flags = NONE, category = CAT_CLOTHING))) /obj/item/stack/sheet/plastic name = "plastic" @@ -819,8 +830,8 @@ GLOBAL_LIST_INIT(plastic_recipes, list( . += GLOB.plastic_recipes GLOBAL_LIST_INIT(paperframe_recipes, list( -new /datum/stack_recipe("paper frame separator", /obj/structure/window/paperframe, 2, one_per_turf = TRUE, on_solid_ground = TRUE, is_fulltile = TRUE, time = 1 SECONDS), \ -new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperframe, 3, one_per_turf = TRUE, on_solid_ground = TRUE, time = 1 SECONDS ))) +new /datum/stack_recipe("paper frame separator", /obj/structure/window/paperframe, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, time = 1 SECONDS), \ +new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperframe, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, time = 1 SECONDS ))) /obj/item/stack/sheet/paperframes name = "paper frames" diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm index 530a3573f7cd0..8b81953528ee1 100644 --- a/code/game/objects/items/stacks/sheets/sheets.dm +++ b/code/game/objects/items/stacks/sheets/sheets.dm @@ -14,7 +14,10 @@ novariants = FALSE material_flags = MATERIAL_EFFECTS var/sheettype = null //this is used for girders in the creation of walls/false walls - var/point_value = 0 //turn-in value for the gulag stacker - loosely relative to its rarity. + ///If true, this is worth points in the gulag labour stacker + var/gulag_valid = FALSE + ///Set to true if this is vended from a material storage + var/manufactured = FALSE ///What type of wall does this sheet spawn var/walltype /// whether this sheet can be sniffed by the material sniffer @@ -32,11 +35,24 @@ GLOB.sniffable_sheets -= src return ..() +/obj/item/stack/sheet/examine(mob/user) + . = ..() + if (manufactured && gulag_valid) + . += "It has been embossed with a manufacturer's mark of guaranteed quality." + /obj/item/stack/sheet/add(_amount) . = ..() if(sniffable && amount >= 10 && is_station_level(z)) GLOB.sniffable_sheets |= src +/obj/item/stack/sheet/merge(obj/item/stack/sheet/target_stack, limit) + . = ..() + manufactured = manufactured && target_stack.manufactured + +/obj/item/stack/sheet/copy_evidences(obj/item/stack/sheet/from) + . = ..() + manufactured = from.manufactured + /// removing from sniffable handled by the sniffer itself when it checks for targets /** diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 7a025bc6bcc4d..4258465f3a07e 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -1,9 +1,3 @@ -//stack recipe placement check types -/// Checks if there is an object of the result type in any of the cardinal directions -#define STACK_CHECK_CARDINALS (1<<0) -/// Checks if there is an object of the result type within one tile -#define STACK_CHECK_ADJACENT (1<<1) - /* Stack type objects! * Contains: * Stacks @@ -196,11 +190,11 @@ /obj/item/stack/proc/update_weight() if(amount <= (max_amount * (1/3))) - w_class = clamp(full_w_class-2, WEIGHT_CLASS_TINY, full_w_class) + update_weight_class(clamp(full_w_class-2, WEIGHT_CLASS_TINY, full_w_class)) else if (amount <= (max_amount * (2/3))) - w_class = clamp(full_w_class-1, WEIGHT_CLASS_TINY, full_w_class) + update_weight_class(clamp(full_w_class-1, WEIGHT_CLASS_TINY, full_w_class)) else - w_class = full_w_class + update_weight_class(full_w_class) /obj/item/stack/update_icon_state() if(novariants) @@ -423,7 +417,7 @@ return var/turf/created_turf = covered_turf.place_on_top(recipe.result_type, flags = CHANGETURF_INHERIT_AIR) builder.balloon_alert(builder, "placed [ispath(recipe.result_type, /turf/open) ? "floor" : "wall"]") - if(recipe.applies_mats && LAZYLEN(mats_per_unit)) + if((recipe.crafting_flags & CRAFT_APPLIES_MATS) && LAZYLEN(mats_per_unit)) created_turf.set_custom_materials(mats_per_unit, recipe.req_amount / recipe.res_amount) else @@ -439,7 +433,7 @@ builder.investigate_log("crafted [recipe.title]", INVESTIGATE_CRAFTING) // Apply mat datums - if(recipe.applies_mats && LAZYLEN(mats_per_unit)) + if((recipe.crafting_flags & CRAFT_APPLIES_MATS) && LAZYLEN(mats_per_unit)) if(isstack(created)) var/obj/item/stack/crafted_stack = created crafted_stack.set_mats_per_unit(mats_per_unit, recipe.req_amount / recipe.res_amount) @@ -484,16 +478,16 @@ return FALSE var/turf/dest_turf = get_turf(builder) - if(recipe.one_per_turf && (locate(recipe.result_type) in dest_turf)) + if((recipe.crafting_flags & CRAFT_ONE_PER_TURF) && (locate(recipe.result_type) in dest_turf)) builder.balloon_alert(builder, "already one here!") return FALSE - if(recipe.check_direction) - if(!valid_build_direction(dest_turf, builder.dir, is_fulltile = recipe.is_fulltile)) + if(recipe.crafting_flags & CRAFT_CHECK_DIRECTION) + if(!valid_build_direction(dest_turf, builder.dir, is_fulltile = (recipe.crafting_flags & CRAFT_IS_FULLTILE))) builder.balloon_alert(builder, "won't fit here!") return FALSE - if(recipe.on_solid_ground) + if(recipe.crafting_flags & CRAFT_ON_SOLID_GROUND) if(isclosedturf(dest_turf)) builder.balloon_alert(builder, "cannot be made on a wall!") return FALSE @@ -503,7 +497,7 @@ builder.balloon_alert(builder, "must be made on solid ground!") return FALSE - if(recipe.check_density) + if(recipe.crafting_flags & CRAFT_CHECK_DENSITY) for(var/obj/object in dest_turf) if(object.density && !(object.obj_flags & IGNORE_DENSITY) || object.obj_flags & BLOCKS_CONSTRUCTION) builder.balloon_alert(builder, "something is in the way!") @@ -742,6 +736,3 @@ add_hiddenprint_list(GET_ATOM_HIDDENPRINTS(from)) fingerprintslast = from.fingerprintslast //TODO bloody overlay - -#undef STACK_CHECK_CARDINALS -#undef STACK_CHECK_ADJACENT diff --git a/code/game/objects/items/stacks/stack_recipe.dm b/code/game/objects/items/stacks/stack_recipe.dm index bfdc3c8ca5717..a11feee8c685a 100644 --- a/code/game/objects/items/stacks/stack_recipe.dm +++ b/code/game/objects/items/stacks/stack_recipe.dm @@ -15,21 +15,8 @@ var/max_res_amount = 1 /// How long it takes to make var/time = 0 - /// If only one of the resulting atom is allowed per turf - var/one_per_turf = FALSE - /// If the atom is fulltile, as in a fulltile window. This is used for the direction check to prevent fulltile windows from being able to be built over directional stuff. - /// Setting this to true will effectively set check_direction to true. - var/is_fulltile = FALSE - /// If this atom should run the direction check, for use when building things like directional windows where you can have more than one per turf - var/check_direction = FALSE - /// If the atom requires a floor below - var/on_solid_ground = FALSE - /// If the atom checks that there are objects with density in the same turf when being built. TRUE by default - var/check_density = TRUE /// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT|STACK_CHECK_TRAM_FORBIDDEN|STACK_CHECK_TRAM_EXCLUSIVE) var/placement_checks = NONE - /// If TRUE, the created atom will gain custom mat datums - var/applies_mats = FALSE /// What trait, if any, boosts the construction speed of this item var/trait_booster /// How much the trait above, if supplied, boosts the construct speed of this item @@ -37,6 +24,9 @@ /// Category for general crafting menu var/category + ///crafting_flags var to hold bool values + var/crafting_flags = CRAFT_CHECK_DENSITY + /datum/stack_recipe/New( title, result_type, @@ -44,13 +34,8 @@ res_amount = 1, max_res_amount = 1, time = 0, - one_per_turf = FALSE, - on_solid_ground = FALSE, - is_fulltile = FALSE, - check_direction = FALSE, - check_density = TRUE, + crafting_flags = CRAFT_CHECK_DENSITY, placement_checks = NONE, - applies_mats = FALSE, trait_booster, trait_modifier = 1, category, @@ -62,13 +47,8 @@ src.res_amount = res_amount src.max_res_amount = max_res_amount src.time = time - src.one_per_turf = one_per_turf - src.on_solid_ground = on_solid_ground - src.is_fulltile = is_fulltile - src.check_direction = check_direction || is_fulltile - src.check_density = check_density + src.crafting_flags = crafting_flags src.placement_checks = placement_checks - src.applies_mats = applies_mats src.trait_booster = trait_booster src.trait_modifier = trait_modifier src.category = src.category || category || CAT_MISC @@ -84,16 +64,13 @@ res_amount = 1, max_res_amount = 1, time = 0, - one_per_turf = FALSE, - on_solid_ground = FALSE, - window_checks = FALSE, + crafting_flags = CRAFT_CHECK_DENSITY, placement_checks = NONE, - applies_mats = FALSE, trait_booster, trait_modifier = 1, + category, desc, required_noun, - category, ) if(category) src.category = category diff --git a/code/game/objects/items/stacks/telecrystal.dm b/code/game/objects/items/stacks/telecrystal.dm index a6bbe3bfe19d8..dd1b74eb106b1 100644 --- a/code/game/objects/items/stacks/telecrystal.dm +++ b/code/game/objects/items/stacks/telecrystal.dm @@ -11,7 +11,7 @@ merge_type = /obj/item/stack/telecrystal novariants = FALSE -/obj/item/stack/telecrystal/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/stack/telecrystal/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(interacting_with != user) //You can't go around smacking people with crystals to find out if they have an uplink or not. return NONE diff --git a/code/game/objects/items/stacks/wrap.dm b/code/game/objects/items/stacks/wrap.dm index 98614a3f2bd7c..5097234b47c00 100644 --- a/code/game/objects/items/stacks/wrap.dm +++ b/code/game/objects/items/stacks/wrap.dm @@ -36,13 +36,14 @@ //Set layers to these colors, base then ribbon set_greyscale(colors = list(generated_base_color, generated_ribbon_color)) -/obj/item/stack/wrapping_paper/AltClick(mob/user, modifiers) +/obj/item/stack/wrapping_paper/click_alt(mob/user) var/new_base = input(user, "", "Select a base color", color) as color var/new_ribbon = input(user, "", "Select a ribbon color", color) as color - if(!user.can_perform_action(src)) - return + if(!new_base || !new_ribbon) + return CLICK_ACTION_BLOCKING + set_greyscale(colors = list(new_base, new_ribbon)) - return TRUE + return CLICK_ACTION_SUCCESS //preset wrapping paper meant to fill the original color configuration /obj/item/stack/wrapping_paper/xmas @@ -130,7 +131,7 @@ item.forceMove(parcel) var/size = round(item.w_class) parcel.name = "[weight_class_to_text(size)] parcel" - parcel.w_class = size + parcel.update_weight_class(size) size = min(size, 5) parcel.base_icon_state = "deliverypackage[size]" parcel.update_icon() diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index d72a57f07f157..9af23545c6f0f 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -360,23 +360,30 @@ /obj/item/storage/bag/tray/Initialize(mapload) . = ..() atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY //Plates are required bulky to keep them out of backpacks - atom_storage.set_holdable(list( - /obj/item/clothing/mask/cigarette, - /obj/item/food, - /obj/item/kitchen, - /obj/item/lighter, - /obj/item/organ, - /obj/item/plate, - /obj/item/reagent_containers/condiment, - /obj/item/reagent_containers/cup, - /obj/item/rollingpaper, - /obj/item/storage/box/gum, - /obj/item/storage/box/matches, - /obj/item/storage/fancy, - /obj/item/trash, - )) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools. + atom_storage.set_holdable( + can_hold_list = list( + /obj/item/clothing/mask/cigarette, + /obj/item/food, + /obj/item/kitchen, + /obj/item/lighter, + /obj/item/organ, + /obj/item/plate, + /obj/item/reagent_containers/condiment, + /obj/item/reagent_containers/cup, + /obj/item/rollingpaper, + /obj/item/storage/box/gum, + /obj/item/storage/box/matches, + /obj/item/storage/fancy, + /obj/item/trash, + ), + cant_hold_list = list( + /obj/item/plate/oven_tray, + /obj/item/reagent_containers/cup/soup_pot, + ), + ) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools. atom_storage.insert_preposition = "on" - atom_storage.max_slots = 7 + atom_storage.max_slots = 8 + atom_storage.max_total_storage = 16 /obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user) . = ..() @@ -399,7 +406,7 @@ /obj/item/storage/bag/tray/proc/do_scatter(obj/item/tray_item) var/delay = rand(2,4) - var/datum/move_loop/loop = SSmove_manager.move_rand(tray_item, list(NORTH,SOUTH,EAST,WEST), delay, timeout = rand(1, 2) * delay, flags = MOVEMENT_LOOP_START_FAST) + var/datum/move_loop/loop = GLOB.move_manager.move_rand(tray_item, list(NORTH,SOUTH,EAST,WEST), delay, timeout = rand(1, 2) * delay, flags = MOVEMENT_LOOP_START_FAST) //This does mean scattering is tied to the tray. Not sure how better to handle it RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(change_speed)) @@ -460,9 +467,6 @@ /obj/item/reagent_containers/syringe, )) -/* - * Biowaste bag (mostly for virologists) - */ /obj/item/storage/bag/bio name = "bio bag" diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 6f3d058cf7e8e..1bf97712ec566 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -286,6 +286,7 @@ /obj/item/surgicaldrill, /obj/item/tank/internals/emergency_oxygen, /obj/item/wrench/medical, + /obj/item/knife/ritual, )) /obj/item/storage/belt/medical/paramedic @@ -659,7 +660,7 @@ /obj/item/storage/belt/wands/Initialize(mapload) . = ..() - atom_storage.max_slots = 6 + atom_storage.max_slots = 7 atom_storage.set_holdable(/obj/item/gun/magic/wand) /obj/item/storage/belt/wands/full/PopulateContents() @@ -669,6 +670,7 @@ new /obj/item/gun/magic/wand/teleport(src) new /obj/item/gun/magic/wand/door(src) new /obj/item/gun/magic/wand/fireball(src) + new /obj/item/gun/magic/wand/shrink(src) for(var/obj/item/gun/magic/wand/W in contents) //All wands in this pack come in the best possible condition W.max_charges = initial(W.max_charges) @@ -730,6 +732,7 @@ /obj/item/ammo_casing/strilka310, /obj/item/ammo_casing/shotgun, /obj/item/ammo_casing/a357, + /obj/item/ammo_casing/junk, )) /obj/item/storage/belt/fannypack @@ -811,6 +814,7 @@ inhand_icon_state = "sheath" worn_icon_state = "sheath" w_class = WEIGHT_CLASS_BULKY + interaction_flags_click = parent_type::interaction_flags_click | NEED_DEXTERITY | NEED_HANDS /obj/item/storage/belt/sabre/Initialize(mapload) . = ..() @@ -820,15 +824,14 @@ atom_storage.rustle_sound = FALSE atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY atom_storage.set_holdable(/obj/item/melee/sabre) + atom_storage.click_alt_open = FALSE /obj/item/storage/belt/sabre/examine(mob/user) . = ..() if(length(contents)) . += span_notice("Alt-click it to quickly draw the blade.") -/obj/item/storage/belt/sabre/AltClick(mob/user) - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) - return +/obj/item/storage/belt/sabre/click_alt(mob/user) if(length(contents)) var/obj/item/I = contents[1] user.visible_message(span_notice("[user] takes [I] out of [src]."), span_notice("You take [I] out of [src].")) @@ -836,6 +839,7 @@ update_appearance() else balloon_alert(user, "it's empty!") + return CLICK_ACTION_SUCCESS /obj/item/storage/belt/sabre/update_icon_state() icon_state = initial(inhand_icon_state) diff --git a/code/game/objects/items/storage/boxes/clothes_boxes.dm b/code/game/objects/items/storage/boxes/clothes_boxes.dm index d4d32e974c745..6b4e995a2762e 100644 --- a/code/game/objects/items/storage/boxes/clothes_boxes.dm +++ b/code/game/objects/items/storage/boxes/clothes_boxes.dm @@ -47,6 +47,15 @@ new /obj/item/clothing/head/syndicatefake(src) new /obj/item/clothing/suit/syndicatefake(src) +/obj/item/storage/box/syndie_kit/battle_royale + name = "rumble royale broadcast kit" + desc = "Contains everything you need to host the galaxy's greatest show; Rumble Royale." + +/obj/item/storage/box/syndie_kit/battle_royale/PopulateContents() + var/obj/item/royale_implanter/implanter = new(src) + var/obj/item/royale_remote/remote = new(src) + remote.link_implanter(implanter) + /obj/item/storage/box/deputy name = "box of deputy armbands" desc = "To be issued to those authorized to act as deputy of security." diff --git a/code/game/objects/items/storage/boxes/engineering_boxes.dm b/code/game/objects/items/storage/boxes/engineering_boxes.dm index de975d9dbfea4..a46703ec8bf9d 100644 --- a/code/game/objects/items/storage/boxes/engineering_boxes.dm +++ b/code/game/objects/items/storage/boxes/engineering_boxes.dm @@ -24,10 +24,7 @@ /obj/item/storage/box/material/Initialize(mapload) . = ..() - atom_storage.allow_big_nesting = TRUE - atom_storage.max_slots = 99 - atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC - atom_storage.max_total_storage = 99 + atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC //This needs to be set here too because the parent type overrides it again /obj/item/storage/box/material/PopulateContents() //less uranium because radioactive var/static/items_inside = list( @@ -51,6 +48,11 @@ /obj/item/stack/sheet/plastic/fifty=1, /obj/item/stack/sheet/runed_metal/fifty=1, ) + //This needs to be done here and not in Initialize() because the stacks get merged and fall out when their weight updates if this is set after PopulateContents() + atom_storage.allow_big_nesting = TRUE + atom_storage.max_slots = 99 + atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC + atom_storage.max_total_storage = 99 generate_items_inside(items_inside,src) /obj/item/storage/box/debugtools diff --git a/code/game/objects/items/storage/boxes/service_boxes.dm b/code/game/objects/items/storage/boxes/service_boxes.dm index 8dcc1f4f6b62f..6dc790cc49545 100644 --- a/code/game/objects/items/storage/boxes/service_boxes.dm +++ b/code/game/objects/items/storage/boxes/service_boxes.dm @@ -204,6 +204,22 @@ for(var/i in 1 to 5) new /obj/item/reagent_containers/spray/chemsprayer/party(src) +/obj/item/storage/box/balloons + name = "box of long balloons" + desc = "A completely randomized and wacky box of long balloons, harvested straight from balloon farms on the clown planet." + illustration = "balloon" + +/obj/item/storage/box/balloons/Initialize(mapload) + . = ..() + atom_storage.max_slots = 24 + atom_storage.set_holdable(list(/obj/item/toy/balloon/long)) + atom_storage.max_total_storage = 24 + atom_storage.allow_quick_gather = FALSE + +/obj/item/storage/box/balloons/PopulateContents() + for(var/i in 1 to 24) + new /obj/item/toy/balloon/long(src) + /obj/item/storage/box/stickers name = "box of stickers" desc = "A box full of random stickers. Do give to the clown." diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm index 95eb304509fd6..4aa93cc543332 100644 --- a/code/game/objects/items/storage/fancy.dm +++ b/code/game/objects/items/storage/fancy.dm @@ -236,24 +236,37 @@ atom_storage.set_holdable(list(/obj/item/clothing/mask/cigarette, /obj/item/lighter)) register_context() +/obj/item/storage/fancy/cigarettes/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + . = ..() + if(interacting_with != user) // you can quickly put a cigarette in your mouth only + return ..() + quick_remove_item(/obj/item/clothing/mask/cigarette, user, equip_to_mouth = TRUE) + /obj/item/storage/fancy/cigarettes/attack_hand_secondary(mob/user, list/modifiers) . = ..() quick_remove_item(/obj/item/clothing/mask/cigarette, user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN -/obj/item/storage/fancy/cigarettes/AltClick(mob/user) - . = ..() +/obj/item/storage/fancy/cigarettes/click_alt(mob/user) var/obj/item/lighter = locate(/obj/item/lighter) in contents if(lighter) quick_remove_item(lighter, user) else quick_remove_item(/obj/item/clothing/mask/cigarette, user) + return CLICK_ACTION_SUCCESS -/// Removes an item from the packet if there is one -/obj/item/storage/fancy/cigarettes/proc/quick_remove_item(obj/item/grabbies, mob/user) +/// Removes an item or puts it in mouth from the packet, if any +/obj/item/storage/fancy/cigarettes/proc/quick_remove_item(obj/item/grabbies, mob/user, equip_to_mouth = FALSE) var/obj/item/finger = locate(grabbies) in contents if(finger) - atom_storage.remove_single(user, finger, drop_location()) - user.put_in_hands(finger) + if(!equip_to_mouth) + atom_storage.remove_single(user, finger, drop_location()) + user.put_in_hands(finger) + return + if(user.equip_to_slot_if_possible(finger, ITEM_SLOT_MASK, qdel_on_fail = FALSE, disable_warning = TRUE)) + finger.forceMove(user) + return + balloon_alert(user, "mouth is covered!") /obj/item/storage/fancy/cigarettes/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() diff --git a/code/game/objects/items/storage/lockbox.dm b/code/game/objects/items/storage/lockbox.dm index 3e7b73c93f332..87a7e4928dadc 100644 --- a/code/game/objects/items/storage/lockbox.dm +++ b/code/game/objects/items/storage/lockbox.dm @@ -120,13 +120,11 @@ if(!atom_storage.locked) . += span_notice("Alt-click to [open ? "close":"open"] it.") -/obj/item/storage/lockbox/medal/AltClick(mob/user) - if(!user.can_perform_action(src)) - return +/obj/item/storage/lockbox/medal/click_alt(mob/user) if(!atom_storage.locked) open = (open ? FALSE : TRUE) update_appearance() - ..() + return CLICK_ACTION_SUCCESS /obj/item/storage/lockbox/medal/PopulateContents() new /obj/item/clothing/accessory/medal/gold/captain(src) diff --git a/code/game/objects/items/storage/medkit.dm b/code/game/objects/items/storage/medkit.dm index 0ecd943b60457..5b09b5e0605bd 100644 --- a/code/game/objects/items/storage/medkit.dm +++ b/code/game/objects/items/storage/medkit.dm @@ -742,7 +742,7 @@ return if(istype(I, /obj/item/plunger)) balloon_alert(user, "plunging...") - if(do_after(user, 10, target = src)) + if(do_after(user, 1 SECONDS, target = src)) balloon_alert(user, "plunged") reagents.clear_reagents() return diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index 8631d62e79efd..75ca06ff0fff9 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -2,6 +2,7 @@ name = "storage" icon = 'icons/obj/storage/storage.dmi' w_class = WEIGHT_CLASS_NORMAL + interaction_flags_click = ALLOW_RESTING|FORBID_TELEKINESIS_REACH var/rummage_if_nodrop = TRUE /// Should we preload the contents of this type? /// BE CAREFUL, THERE'S SOME REALLY NASTY SHIT IN THIS TYPEPATH diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index b04be4cb85bbd..5b42bf3e432d9 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -327,11 +327,9 @@ /obj/item/storage/belt/military/assault/fisher /obj/item/storage/belt/military/assault/fisher/PopulateContents() - new /obj/item/gun/ballistic/automatic/pistol/clandestine(src) // 7 TC - new /obj/item/suppressor(src) // 3 TC + new /obj/item/gun/ballistic/automatic/pistol/clandestine/fisher(src) // 11 TC: 7 (pistol) + 3 (suppressor) + lightbreaker (1 TC, black market meme/util item) new /obj/item/ammo_box/magazine/m10mm(src) // 1 TC new /obj/item/ammo_box/magazine/m10mm(src) - new /obj/item/gun/energy/recharge/fisher(src) // Acquirable through black market, shit utility item 1 TC new /obj/item/card/emag/doorjack(src) // 3 TC new /obj/item/knife/combat(src) //comparable to the e-dagger, 2 TC diff --git a/code/game/objects/items/surgery_tray.dm b/code/game/objects/items/surgery_tray.dm index e31b8f24cb8a2..028366481d45a 100644 --- a/code/game/objects/items/surgery_tray.dm +++ b/code/game/objects/items/surgery_tray.dm @@ -150,12 +150,10 @@ for(var/atom/movable/tool as anything in contents) tool.forceMove(drop_point) -/obj/item/surgery_tray/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - dump_contents() - new /obj/item/stack/rods(drop_location(), 2) - new /obj/item/stack/sheet/mineral/silver(drop_location()) - return ..() +/obj/item/surgery_tray/atom_deconstruct(disassembled = TRUE) + dump_contents() + new /obj/item/stack/rods(drop_location(), 2) + new /obj/item/stack/sheet/mineral/silver(drop_location()) /obj/item/surgery_tray/deployed is_portable = FALSE diff --git a/code/game/objects/items/syndie_spraycan.dm b/code/game/objects/items/syndie_spraycan.dm index 02a576a2cb97d..774219fa12229 100644 --- a/code/game/objects/items/syndie_spraycan.dm +++ b/code/game/objects/items/syndie_spraycan.dm @@ -86,7 +86,7 @@ if(HAS_TRAIT(user, TRAIT_TAGGER)) wait_time *= 0.5 - if(!do_after(user, wait_time, target)) + if(!do_after(user, wait_time, target, hidden = TRUE)) user.balloon_alert(user, "interrupted!") drawing_rune = FALSE return FALSE diff --git a/code/game/objects/items/tanks/tank_types.dm b/code/game/objects/items/tanks/tank_types.dm index 064a749521e88..70c0ea0822a41 100644 --- a/code/game/objects/items/tanks/tank_types.dm +++ b/code/game/objects/items/tanks/tank_types.dm @@ -7,12 +7,14 @@ * Emergency Oxygen * Generic */ +/obj/item/tank/internals + interaction_flags_click = FORBID_TELEKINESIS_REACH|NEED_HANDS|ALLOW_RESTING + /// Allows carbon to toggle internals via AltClick of the equipped tank. -/obj/item/tank/internals/AltClick(mob/user) - ..() - if((loc == user) && user.can_perform_action(src, FORBID_TELEKINESIS_REACH|NEED_HANDS)) - toggle_internals(user) +/obj/item/tank/internals/click_alt(mob/user) + toggle_internals(user) + return CLICK_ACTION_SUCCESS /obj/item/tank/internals/examine(mob/user) . = ..() diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index e198f7d75d74d..72c84c9ee995e 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -174,7 +174,7 @@ if(tank_assembly) . += span_warning("There is some kind of device [EXAMINE_HINT("rigged")] to the tank!") -/obj/item/tank/deconstruct(disassembled = TRUE) +/obj/item/tank/atom_deconstruct(disassembled = TRUE) var/atom/location = loc if(location) location.assume_air(air_contents) @@ -460,7 +460,7 @@ tank_assembly = assembly //Tell the tank about its assembly part assembly.master = src //Tell the assembly about its new owner assembly.on_attach() - w_class = WEIGHT_CLASS_BULKY + update_weight_class(WEIGHT_CLASS_BULKY) balloon_alert(user, "bomb assembled") update_appearance(UPDATE_OVERLAYS) @@ -474,7 +474,7 @@ user.put_in_hands(tank_assembly) tank_assembly.master = null tank_assembly = null - w_class = initial(w_class) + update_weight_class(initial(w_class)) update_appearance(UPDATE_OVERLAYS) /// Ignites the contents of the tank. Called when receiving a signal if the tank is welded and has an igniter attached. diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index 9950b8e9c931e..e90dd08d93810 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -309,7 +309,7 @@ user.log_message("used Resin Launcher", LOG_GAME) playsound(src,'sound/items/syringeproj.ogg',40,TRUE) var/delay = 2 - var/datum/move_loop/loop = SSmove_manager.move_towards(resin, target, delay, timeout = delay * 5, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/loop = GLOB.move_manager.move_towards(resin, target, delay, timeout = delay * 5, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(resin_stop_check)) RegisterSignal(loop, COMSIG_QDELETING, PROC_REF(resin_landed)) return diff --git a/code/game/objects/items/tcg/tcg_machines.dm b/code/game/objects/items/tcg/tcg_machines.dm index 767592535f74d..78854afdd5b39 100644 --- a/code/game/objects/items/tcg/tcg_machines.dm +++ b/code/game/objects/items/tcg/tcg_machines.dm @@ -91,7 +91,7 @@ GLOBAL_LIST_EMPTY(tcgcard_machine_radial_choices) /obj/machinery/trading_card_holder/attack_hand_secondary(mob/user) if(isnull(current_summon)) var/card_name = tgui_input_text(user, "Insert card name", "Blank Card Naming", "blank card", MAX_NAME_LEN) - if(isnull(card_name)) + if(isnull(card_name) || !user.can_perform_action(src)) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN current_summon = new /obj/structure/trading_card_summon/blank(locate(x + summon_offset_x, y + summon_offset_y, z)) icon_state = "card_holder_active" diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 38a8195319357..b139283223370 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -143,6 +143,7 @@ if(is_parent_of_portal(target)) qdel(target) to_chat(user, span_notice("You dispel [target] with \the [src]!")) + playsound(loc, "sound/effects/portal_close.ogg", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) return TRUE return FALSE @@ -163,6 +164,7 @@ try_create_portal_to(user, portal_location) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/item/hand_tele/attack_self(mob/user) @@ -252,7 +254,7 @@ var/list/obj/effect/portal/created = create_portal_pair(get_turf(user), get_teleport_turf(get_turf(teleport_target)), 300, 1, null) if(LAZYLEN(created) != 2) return - + playsound(loc, pick("sound/effects/portal_open_1.ogg", "sound/effects/portal_open_2.ogg", "sound/effects/portal_open_3.ogg" ), 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) var/obj/effect/portal/portal1 = created[1] var/obj/effect/portal/portal2 = created[2] @@ -426,9 +428,9 @@ new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(current_location) new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(destination) make_bloods(current_location, destination, user) - playsound(current_location, SFX_SPARKS, 50, 1, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(current_location, 'sound/effects/portal_travel.ogg', 50, 1, SHORT_RANGE_SOUND_EXTRARANGE) playsound(destination, 'sound/effects/phasein.ogg', 25, 1, SHORT_RANGE_SOUND_EXTRARANGE) - playsound(destination, SFX_SPARKS, 50, 1, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(destination, 'sound/effects/portal_travel.ogg', 50, 1, SHORT_RANGE_SOUND_EXTRARANGE) /obj/item/syndicate_teleporter/proc/malfunctioning(mob/guy_teleporting, turf/current_location) var/area/current_area = get_area(current_location) @@ -463,9 +465,9 @@ balloon_alert(user, "emergency teleport triggered!") if (!HAS_TRAIT(user, TRAIT_NOBLOOD)) make_bloods(mobloc, emergency_destination, user) - playsound(mobloc, SFX_SPARKS, 50, 1, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(mobloc, 'sound/effects/portal_travel.ogg', 50, 1, SHORT_RANGE_SOUND_EXTRARANGE) playsound(emergency_destination, 'sound/effects/phasein.ogg', 25, 1, SHORT_RANGE_SOUND_EXTRARANGE) - playsound(emergency_destination, SFX_SPARKS, 50, 1, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(emergency_destination, 'sound/effects/portal_travel.ogg', 50, 1, SHORT_RANGE_SOUND_EXTRARANGE) else //We tried to save. We failed. Death time. get_fragged(user, destination) @@ -475,8 +477,8 @@ victim.forceMove(destination) new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(mobloc) new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(destination) - playsound(mobloc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - playsound(destination, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(mobloc, 'sound/effects/portal_travel.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(destination, 'sound/effects/portal_travel.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) playsound(destination, "sound/magic/disintegrate.ogg", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(!not_holding_tele) to_chat(victim, span_userdanger("You teleport into [destination], [src] tries to save you, but...")) diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm index e695dedbca3de..5f0404c342350 100644 --- a/code/game/objects/items/theft_tools.dm +++ b/code/game/objects/items/theft_tools.dm @@ -61,7 +61,7 @@ core = ncore icon_state = "core_container_loaded" to_chat(user, span_warning("Container is sealing...")) - addtimer(CALLBACK(src, PROC_REF(seal)), 50) + addtimer(CALLBACK(src, PROC_REF(seal)), 5 SECONDS) return TRUE /obj/item/nuke_core_container/proc/seal() @@ -236,7 +236,7 @@ T.icon_state = "supermatter_tongs" icon_state = "core_container_loaded" to_chat(user, span_warning("Container is sealing...")) - addtimer(CALLBACK(src, PROC_REF(seal)), 50) + addtimer(CALLBACK(src, PROC_REF(seal)), 5 SECONDS) return TRUE /obj/item/nuke_core_container/supermatter/seal() diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm index 56d7344f31b92..9bb61e847b72d 100644 --- a/code/game/objects/items/tools/crowbar.dm +++ b/code/game/objects/items/tools/crowbar.dm @@ -189,7 +189,7 @@ name = "hydraulic crowbar" desc = "A hydraulic prying tool, simple but powerful." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "crowbar_cyborg" + icon_state = "toolkit_engiborg_crowbar" worn_icon_state = "crowbar" usesound = 'sound/items/jaws_pry.ogg' force = 10 diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index cbdc79e04203a..02765122a134d 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -148,7 +148,7 @@ name = "automated screwdriver" desc = "A powerful automated screwdriver, designed to be both precise and quick." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "screwdriver_cyborg" + icon_state = "toolkit_engiborg_screwdriver" hitsound = 'sound/items/drill_hit.ogg' usesound = 'sound/items/drill_use.ogg' toolspeed = 0.5 diff --git a/code/game/objects/items/tools/spess_knife.dm b/code/game/objects/items/tools/spess_knife.dm index 0b0061de7a4ed..9fd5dbb01582a 100644 --- a/code/game/objects/items/tools/spess_knife.dm +++ b/code/game/objects/items/tools/spess_knife.dm @@ -60,10 +60,10 @@ mistake_occured = TRUE if(isnull(tool_behaviour)) - w_class = WEIGHT_CLASS_TINY + update_weight_class(WEIGHT_CLASS_TINY) balloon_alert(user, "folded") else - w_class = WEIGHT_CLASS_SMALL + update_weight_class(WEIGHT_CLASS_SMALL) balloon_alert(user, mistake_occured ? "oops! [tool_behaviour] out" : "[tool_behaviour] out") update_tool_parameters() diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 40f9f47f424ec..3bdad581866e0 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -134,7 +134,7 @@ LAZYREMOVE(update_overlays_on_z, sparks) target.cut_overlay(sparks) -/obj/item/weldingtool/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/weldingtool/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!ishuman(interacting_with)) return NONE if(user.combat_mode) @@ -163,10 +163,12 @@ if(!proximity) return - if(isOn()) + if(isOn() && ismovable(attacked_atom)) + use(1) + var/turf/location = get_turf(user) + location.hotspot_expose(700, 50, 1) . |= AFTERATTACK_PROCESSED_ITEM if (!QDELETED(attacked_atom) && isliving(attacked_atom)) // can't ignite something that doesn't exist - handle_fuel_and_temps(1, user) var/mob/living/attacked_mob = attacked_atom if(attacked_mob.ignite_mob()) message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(attacked_mob)] on fire with [src] at [AREACOORD(user)]") @@ -180,21 +182,6 @@ return . -/obj/item/weldingtool/attack_qdeleted(atom/attacked_atom, mob/user, proximity) - . = ..() - if(!proximity) - return - - if(isOn()) - handle_fuel_and_temps(1, user) - - if(!QDELETED(attacked_atom) && isliving(attacked_atom)) // can't ignite something that doesn't exist - var/mob/living/attacked_mob = attacked_atom - if(attacked_mob.ignite_mob()) - message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(attacked_mob)] on fire with [src] at [AREACOORD(user)].") - user.log_message("set [key_name(attacked_mob)] on fire with [src]", LOG_ATTACK) - - /obj/item/weldingtool/attack_self(mob/user) if(src.reagents.has_reagent(/datum/reagent/toxin/plasma)) message_admins("[ADMIN_LOOKUPFLW(user)] activated a rigged welder at [AREACOORD(user)].") @@ -204,11 +191,6 @@ update_appearance() -/obj/item/weldingtool/proc/handle_fuel_and_temps(used = 0, mob/living/user) - use(used) - var/turf/location = get_turf(user) - location.hotspot_expose(700, 50, 1) - /// Returns the amount of fuel in the welder /obj/item/weldingtool/proc/get_fuel() return reagents.get_reagent_amount(/datum/reagent/fuel) diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm index e1635e2b81a1b..06e4e01326894 100644 --- a/code/game/objects/items/tools/wirecutters.dm +++ b/code/game/objects/items/tools/wirecutters.dm @@ -77,7 +77,7 @@ name = "powered wirecutters" desc = "Cuts wires with the power of ELECTRICITY. Faster than normal wirecutters." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "wirecutters_cyborg" + icon_state = "toolkit_engiborg_cutters" worn_icon_state = "cutters" toolspeed = 0.5 random_color = FALSE diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm index c4326cf3de818..8fbb681acfc3a 100644 --- a/code/game/objects/items/tools/wrench.dm +++ b/code/game/objects/items/tools/wrench.dm @@ -87,7 +87,7 @@ name = "hydraulic wrench" desc = "An advanced robotic wrench, powered by internal hydraulics. Twice as fast as the handheld version." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "wrench_cyborg" + icon_state = "toolkit_engiborg_wrench" toolspeed = 0.5 /obj/item/wrench/combat diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 1d2b0bba7b134..b2cc7544e1077 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -39,8 +39,8 @@ /obj/item/toy/waterballoon name = "water balloon" desc = "A translucent balloon. There's nothing in it." - icon = 'icons/obj/toys/toy.dmi' - icon_state = "waterballoon-e" + icon = 'icons/obj/toys/balloons.dmi' + icon_state = "balloon_red-e" inhand_icon_state = "balloon-empty" /obj/item/toy/waterballoon/Initialize(mapload) @@ -107,15 +107,15 @@ icon_state = "waterballoon" inhand_icon_state = "balloon" else - icon_state = "waterballoon-e" + icon_state = "balloon_red-e" inhand_icon_state = "balloon-empty" return ..() -#define BALLOON_COLORS list("red", "blue", "green", "yellow") +#define BALLOON_COLORS list("red", "blue", "green", "yellow", "orange", "purple") /obj/item/toy/balloon name = "balloon" - desc = "No birthday is complete without it." + desc = "No birthday is complete without it. Sealed with a mechanical bluespace wrap so it remains floating no matter what." icon = 'icons/obj/toys/balloons.dmi' icon_state = "balloon" inhand_icon_state = "balloon" @@ -127,6 +127,68 @@ throw_range = 7 force = 0 var/random_color = TRUE + /// the string of the dmi state the balloon has while on the floor. + var/world_state + /// the string of the dmi state the balloon has while in your inventory. + var/storage_state + /// the string describing the name of balloon's current colour. + var/current_color + +/obj/item/toy/balloon/long + name = "long balloon" + desc = "A perfect balloon to contort into goofy forms. Sealed with a mechanical bluespace wrap so it remains floating no matter what." + icon_state = "balloon_long" + inhand_icon_state = "balloon" + w_class = WEIGHT_CLASS_NORMAL + /// Combinations of balloon colours to make specific animals. + var/list/balloon_combos = list( + list("red", "blue") = /obj/item/toy/balloon_animal/guy, + list("red", "green") = /obj/item/toy/balloon_animal/nukie, + list("red", "yellow") = /obj/item/toy/balloon_animal/clown, + list("red", "orange") = /obj/item/toy/balloon_animal/cat, + list("red", "purple") = /obj/item/toy/balloon_animal/fly, + list("blue", "green") = /obj/item/toy/balloon_animal/podguy, + list("blue", "yellow") = /obj/item/toy/balloon_animal/ai, + list("blue", "orange") = /obj/item/toy/balloon_animal/dog, + list("blue", "purple") = /obj/item/toy/balloon_animal/xeno, + list("green", "yellow") = /obj/item/toy/balloon_animal/banana, + list("green", "orange") = /obj/item/toy/balloon_animal/lizard, + list("green", "purple") = /obj/item/toy/balloon_animal/slime, + list("yellow", "orange") = /obj/item/toy/balloon_animal/moth, + list("yellow", "purple") = /obj/item/toy/balloon_animal/ethereal, + list("orange", "purple") = /obj/item/toy/balloon_animal/plasmaman, + ) + +/obj/item/toy/balloon/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + if(isturf(loc)) + icon_state = "[world_state]" + else + icon_state = "[storage_state]" + update_appearance() + +/obj/item/toy/balloon/long/attackby(obj/item/attacking_item, mob/living/user, params) + if(!istype(attacking_item, /obj/item/toy/balloon/long) || !HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return ..() + + var/obj/item/toy/balloon/long/hit_by = attacking_item + if(hit_by.current_color == current_color) + to_chat(user, span_warning("You must use balloons of different colours to do that!")) + return ..() + visible_message( + span_notice("[user.name] starts contorting up a balloon animal!"), + blind_message = span_hear("You hear balloons being contorted."), + vision_distance = 3, + ignored_mobs = user, + ) + for(var/list/pair_of_colors in balloon_combos) + if((hit_by.current_color == pair_of_colors[1] && current_color == pair_of_colors[2]) || (current_color == pair_of_colors[1] && hit_by.current_color == pair_of_colors[2])) + var/path_to_spawn = balloon_combos[pair_of_colors] + user.put_in_hands(new path_to_spawn) + break + qdel(hit_by) + qdel(src) + return TRUE /obj/item/toy/balloon/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/ammo_casing/foam_dart) && ismonkey(user)) @@ -157,17 +219,27 @@ . = ..() if(random_color) var/chosen_balloon_color = pick(BALLOON_COLORS) + current_color = "[chosen_balloon_color]" name = "[chosen_balloon_color] [name]" icon_state = "[icon_state]_[chosen_balloon_color]" inhand_icon_state = icon_state + world_state = "[icon_state]" + storage_state = "[icon_state]_storage" /obj/item/toy/balloon/corgi name = "corgi balloon" - desc = "A balloon with a corgi face on it. For the all year good boys." + desc = "A balloon in the shape of a corgi's head. For the all year good boys." icon_state = "corgi" inhand_icon_state = "corgi" random_color = FALSE +/obj/item/toy/balloon/heart + name = "heart balloon" + desc = "A balloon in the shape of a heart. How lovely" + icon_state = "heart" + inhand_icon_state = "heart" + random_color = FALSE + /obj/item/toy/balloon/syndicate name = "syndicate balloon" desc = "There is a tag on the back that reads \"FUK NT!11!\"." @@ -200,6 +272,96 @@ #undef BALLOON_COLORS +/* +* Balloon animals +*/ + +/obj/item/toy/balloon_animal + name = "balloon animal" + desc = "You shouldn't have this." + icon = 'icons/obj/toys/balloons.dmi' + icon_state = "balloon_guy" + throwforce = 0 + throw_speed = 2 + throw_range = 5 + force = 0 + +/obj/item/toy/balloon_animal/guy + name = "balloon guy" + desc = "A balloon effigy of the everyday standard issue human guy. Wonder if he pays balloon taxes. He probably evades them." + icon_state = "balloon_guy" + +/obj/item/toy/balloon_animal/nukie + name = "balloon nukie" + desc = "A balloon effigy of syndicate's nuclear operative. Either made to appease them and pray for survival, or to poke fun at them." + icon_state = "balloon_nukie" + +/obj/item/toy/balloon_animal/clown + name = "balloon clown" + desc = "A balloon clown, smiling from ear to ear and beyond!" + icon_state = "balloon_clown" + +/obj/item/toy/balloon_animal/cat + name = "balloon cat" + desc = "Without the sharp claws, balloon cats are possibly cuter than their live counterparts, though not as relatable, warm and fuzzy." + icon_state = "balloon_cat" + +/obj/item/toy/balloon_animal/fly + name = "balloon fly" + desc = "A balloon effigy of a flyperson. Thankfully, it doesn't come with balloon vomit." + icon_state = "balloon_fly" + +/obj/item/toy/balloon_animal/podguy + name = "balloon podguy" + desc = "A balloon effigy of a podperson. Though, actual podpeople have heads and not stalks and leaves." + icon_state = "balloon_podguy" + +/obj/item/toy/balloon_animal/ai + name = "balloon ai core" + desc = "A somewhat unrealistic balloon effigy of the station's AI core. Actual AI propably wouldn't smile like this." + icon_state = "balloon_ai" + +/obj/item/toy/balloon_animal/dog + name = "balloon dog" + desc = "A balloon effigy of the best boy. It cannot truly compare, but it makes an effort." + icon_state = "balloon_dog" + +/obj/item/toy/balloon_animal/xeno + name = "balloon xeno" + desc = "A balloon effigy of a spooky xeno! Too squishy to scare anyone itself, though." + icon_state = "balloon_xeno" + +/obj/item/toy/balloon_animal/banana + name = "balloon banana" + desc = "A balloon banana. This one can't be slipped on. Good for psychological warfare, though." + icon_state = "balloon_banana" + +/obj/item/toy/balloon_animal/lizard + name = "balloon lizard" + desc = "A balloon effigy of a lizard. One of the first species to adapt to clown planet's culture. Perhaps because they are naturally laughable?" + icon_state = "balloon_lizard" + +/obj/item/toy/balloon_animal/slime + name = "balloon slime" + desc = "A balloon effigy of single specimen of the galaxy-wide slime scourge, of purple variety. Slimes tried to invade clown planet once. They got quickly washed out by water-spitting flowers, though." + icon_state = "balloon_slime" + +/obj/item/toy/balloon_animal/moth + name = "balloon moth" + desc = "A balloon effigy of a common member of moth flotillas. Very few of them ever decide to settle on the clown planet, but those who do have the best 'piece-of-cloth-dissapearing' acts." + icon_state = "balloon_moth" + +/obj/item/toy/balloon_animal/ethereal + name = "balloon ethereal" + desc = "A balloon effigy of an ethereal artisan. Clownery is one form of art, and as such, ethereals were both drawn to and readily accepted at clown planet. Don't mind the lighbulb head, it's art too." + icon_state = "balloon_ethereal" + +/obj/item/toy/balloon_animal/plasmaman + name = "balloon plasmaman" + desc = "A balloon effigy of a plasmaman. Among the rarest on the clown planet, only having appeared recently thanks to ready trade between clown planet and NT." + icon_state = "balloon_plasmaman" + + /* * Captain's Aid */ @@ -555,7 +717,7 @@ update_appearance() playsound(src, 'sound/effects/pope_entry.ogg', 100) Rumble() - addtimer(CALLBACK(src, PROC_REF(stopRumble)), 600) + addtimer(CALLBACK(src, PROC_REF(stopRumble)), 60 SECONDS) else to_chat(user, span_warning("[src] is already active!")) @@ -1042,6 +1204,11 @@ icon_state = "bartender" toysay = "Where is Pun Pun?" +/obj/item/toy/figure/bitrunner + name = "\improper Bitrunner action figure" + icon_state = "bitrunner" + toysay = "I'm in..." + /obj/item/toy/figure/borg name = "\improper Cyborg action figure" icon_state = "borg" @@ -1219,10 +1386,6 @@ toysay = "I am the law!" toysound = 'sound/runtime/complionator/dredd.ogg' -/obj/item/toy/figure/virologist - name = "\improper Virologist action figure" - icon_state = "virologist" - toysay = "The cure is potassium!" /obj/item/toy/figure/warden name = "\improper Warden action figure" @@ -1240,7 +1403,7 @@ //Add changing looks when i feel suicidal about making 20 inhands for these. /obj/item/toy/dummy/attack_self(mob/user) var/new_name = tgui_input_text(usr, "What would you like to name the dummy?", "Doll Name", doll_name, MAX_NAME_LEN) - if(!new_name) + if(!new_name || !user.is_holding(src)) return doll_name = new_name to_chat(user, span_notice("You name the dummy as \"[doll_name]\".")) diff --git a/code/game/objects/items/virgin_mary.dm b/code/game/objects/items/virgin_mary.dm index 7c3c305858c1c..b0446abadbdfd 100644 --- a/code/game/objects/items/virgin_mary.dm +++ b/code/game/objects/items/virgin_mary.dm @@ -47,8 +47,8 @@ /obj/item/virgin_mary/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] starts saying their Hail Mary's at a terrifying pace! It looks like [user.p_theyre()] trying to enter the afterlife!")) user.say("Hail Mary, full of grace, the Lord is with thee. Blessed are thou amongst women, and blessed is the fruit of thy womb, Jesus. Holy Mary, mother of God, pray for us sinners, now and at the hour of our death. Amen. ", forced = /obj/item/virgin_mary) - addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 75) - addtimer(CALLBACK(user, TYPE_PROC_REF(/atom/movable, say), "O my Mother, preserve me this day from mortal sin..."), 50) + addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 7.5 SECONDS) + addtimer(CALLBACK(user, TYPE_PROC_REF(/atom/movable, say), "O my Mother, preserve me this day from mortal sin..."), 5 SECONDS) return MANUAL_SUICIDE /obj/item/virgin_mary/proc/manual_suicide(mob/living/user) diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 1f2078f0037d0..f7717da19e795 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -40,6 +40,48 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 if(user.combat_mode) return ..(M, user) + +/obj/item/balloon_mallet + name = "balloon mallet" + desc = "It's a mallet, a weapon known for being heavy, but made from notoriously light balloons. Air inside removes any force from the swings. It'd be quite embarrassing to get hit by this." + icon = 'icons/obj/weapons/hammer.dmi' + icon_state = "balloon_mallet" + inhand_icon_state = "balloon_mallet" + lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' + siemens_coefficient = 0 + force = 1 + throw_speed = 1 + throwforce = 1 + throw_range = 1 + w_class = WEIGHT_CLASS_HUGE + attack_verb_continuous = list("mallets", "smoother") + attack_verb_simple = list("mallet", "smoother") + max_integrity = 20 + armor_type = /datum/armor/item_banhammer + resistance_flags = FIRE_PROOF + +/obj/item/balloon_mallet/examine(mob/user) + . = ..() + if(HAS_TRAIT(user,TRAIT_BALLOON_SUTRA)) + . = "A sacred weapon of the higher castes from the clown planet, used to strike fear into the hearts of their foes. Wield it with care." + +/obj/item/balloon_mallet/attack(mob/living/target, mob/living/user) + playsound(loc, 'sound/creatures/clown/hehe.ogg', 20) + if (!isliving(target)) + return + switch(target.mob_mood.sanity) + if (SANITY_INSANE to SANITY_CRAZY) + force = 8 + if (SANITY_UNSTABLE to SANITY_DISTURBED) + force = 4 + target.add_mood_event("humiliated", /datum/mood_event/mallet_humiliation) + if (SANITY_NEUTRAL to SANITY_GREAT) + target.add_mood_event("humiliated", /datum/mood_event/mallet_humiliation) + + if(user.combat_mode) + return ..(target, user) + /obj/item/sord name = "\improper SORD" desc = "This thing is so unspeakably shitty you are having a hard time even holding it." @@ -133,6 +175,18 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 block_chance = 10 resistance_flags = NONE +//bootleg claymore +/obj/item/claymore/shortsword + name = "shortsword" + desc = "A mercenary's sword, chipped and worn from battles long gone. You could say it is a swordsman's shortsword short sword." + icon_state = "shortsword" + inhand_icon_state = "shortsword" + worn_icon_state = "shortsword" + slot_flags = ITEM_SLOT_BELT + force = 20 + demolition_mod = 0.75 + block_chance = 30 + /obj/item/claymore/highlander //ALL COMMENTS MADE REGARDING THIS SWORD MUST BE MADE IN ALL CAPS desc = "THERE CAN BE ONLY ONE, AND IT WILL BE YOU!!!\nActivate it in your hand to point to the nearest victim." obj_flags = CONDUCTS_ELECTRICITY diff --git a/code/game/objects/items/wizard_weapons.dm b/code/game/objects/items/wizard_weapons.dm index 533ae118dc2a0..8c2677d3ee35b 100644 --- a/code/game/objects/items/wizard_weapons.dm +++ b/code/game/objects/items/wizard_weapons.dm @@ -73,7 +73,7 @@ playsound(user, 'sound/weapons/marauder.ogg', 50, TRUE) var/turf/target = get_turf(A) vortex(target,user) - addtimer(CALLBACK(src, PROC_REF(recharge)), 100) + addtimer(CALLBACK(src, PROC_REF(recharge)), 10 SECONDS) return . /obj/item/mjollnir diff --git a/code/game/objects/items_reskin.dm b/code/game/objects/items_reskin.dm new file mode 100644 index 0000000000000..9fa3b91d0e198 --- /dev/null +++ b/code/game/objects/items_reskin.dm @@ -0,0 +1,86 @@ +/// Called when alt clicked and the item has unique reskin options +/obj/item/proc/on_click_alt_reskin(datum/source, mob/user) + SIGNAL_HANDLER + + if(!user.can_perform_action(src, NEED_DEXTERITY)) + return NONE + + if(!(obj_flags & INFINITE_RESKIN) && current_skin) + return NONE + + INVOKE_ASYNC(src, PROC_REF(reskin_obj), user) + return CLICK_ACTION_SUCCESS + +/** + * Checks if we should set up reskinning, + * by default if unique_reskin is set. + * + * Called on setup_reskinning(). + * Inheritors should override this to add their own checks. + */ +/obj/item/proc/check_setup_reskinning() + SHOULD_CALL_PARENT(TRUE) + if(unique_reskin) + return TRUE + + return FALSE + +/** + * Registers signals and context for reskinning, + * if check_setup_reskinning() passes. + * + * Called on Initialize(...). + * Inheritors should override this to add their own setup steps, + * or to avoid double calling register_context(). + */ +/obj/item/proc/setup_reskinning() + SHOULD_CALL_PARENT(FALSE) + if(!check_setup_reskinning()) + return + + RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin)) + register_context() + +/** + * Reskins object based on a user's choice + * + * Arguments: + * * user The mob choosing a reskin option + */ +/obj/item/proc/reskin_obj(mob/user) + if(!LAZYLEN(unique_reskin)) + return + + var/list/items = list() + for(var/reskin_option in unique_reskin) + var/image/item_image = image(icon = src.icon, icon_state = unique_reskin[reskin_option]) + items += list("[reskin_option]" = item_image) + sort_list(items) + + var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), user), radius = 38, require_near = TRUE) + if(!pick) + return + if(!unique_reskin[pick]) + return + current_skin = pick + icon_state = unique_reskin[pick] + to_chat(user, "[src] is now skinned as '[pick].'") + SEND_SIGNAL(src, COMSIG_OBJ_RESKIN, user, pick) + + +/** + * Checks if we are allowed to interact with a radial menu for reskins + * + * Arguments: + * * user The mob interacting with the menu + */ +/obj/item/proc/check_reskin_menu(mob/user) + if(QDELETED(src)) + return FALSE + if(!(obj_flags & INFINITE_RESKIN) && current_skin) + return FALSE + if(!istype(user)) + return FALSE + if(user.incapacitated()) + return FALSE + return TRUE diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 9b118ea7c2f72..9ebcbb253d20b 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -155,9 +155,48 @@ var/mob/living/buckled_mob = m buckled_mob.electrocute_act((clamp(round(strength * 1.25e-3), 10, 90) + rand(-5, 5)), src, flags = SHOCK_TESLA) -///the obj is deconstructed into pieces, whether through careful disassembly or when destroyed. +/** + * Custom behaviour per atom subtype on how they should deconstruct themselves + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ +/obj/proc/atom_deconstruct(disassembled = TRUE) + PROTECTED_PROC(TRUE) + + return + +/** + * The interminate proc between deconstruct() & atom_deconstruct(). By default this delegates deconstruction to + * atom_deconstruct if NO_DEBRIS_AFTER_DECONSTRUCTION is absent but subtypes can override this to handle NO_DEBRIS_AFTER_DECONSTRUCTION in their + * own unique way. Override this if for example you want to dump out important content like mobs from the + * atom before deconstruction regardless if NO_DEBRIS_AFTER_DECONSTRUCTION is present or not + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ +/obj/proc/handle_deconstruct(disassembled = TRUE) + SHOULD_CALL_PARENT(FALSE) + + if(!(obj_flags & NO_DEBRIS_AFTER_DECONSTRUCTION)) + atom_deconstruct(disassembled) + +/** + * The obj is deconstructed into pieces, whether through careful disassembly or when destroyed. + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ /obj/proc/deconstruct(disassembled = TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + + //allow objects to deconstruct themselves + handle_deconstruct(disassembled) + + //inform objects we were deconstructed SEND_SIGNAL(src, COMSIG_OBJ_DECONSTRUCT, disassembled) + + //delete our self qdel(src) ///what happens when the obj's integrity reaches zero. diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index c2183728d4f19..bfdd0f71426c5 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -27,9 +27,6 @@ /// A multiplier to an objecet's force when used against a stucture, vechicle, machine, or robot. var/demolition_mod = 1 - var/current_skin //Has the item been reskinned? - var/list/unique_reskin //List of options to reskin. - /// Custom fire overlay icon, will just use the default overlay if this is null var/custom_fire_overlay /// Particles this obj uses when burning, if any @@ -82,8 +79,8 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) if(attacking_item.demolition_mod < 1) damage_verb = "ineffectively pierce" - user.visible_message(span_danger("[user] [damage_verb][plural_s(damage_verb)] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]"]!"), \ - span_danger("You [damage_verb] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]"]!"), null, COMBAT_MESSAGE_RANGE) + user.visible_message(span_danger("[user] [damage_verb][plural_s(damage_verb)] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]!"]"), \ + span_danger("You [damage_verb] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]!"]"), null, COMBAT_MESSAGE_RANGE) log_combat(user, src, "attacked", attacking_item) /obj/assume_air(datum/gas_mixture/giver) @@ -117,54 +114,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) else return null -/obj/proc/updateUsrDialog() - if(!(obj_flags & IN_USE)) - return - - var/is_in_use = FALSE - var/list/nearby = viewers(1, src) - for(var/mob/M in nearby) - if ((M.client && M.machine == src)) - is_in_use = TRUE - ui_interact(M) - if(issilicon(usr) || isAdminGhostAI(usr)) - if (!(usr in nearby)) - if (usr.client && usr.machine == src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh. - is_in_use = TRUE - ui_interact(usr) - - // check for TK users - - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - if(!(usr in nearby)) - if(usr.client && usr.machine == src) - if(H.dna.check_mutation(/datum/mutation/human/telekinesis)) - is_in_use = TRUE - ui_interact(usr) - if (is_in_use) - obj_flags |= IN_USE - else - obj_flags &= ~IN_USE - -/obj/proc/updateDialog(update_viewers = TRUE,update_ais = TRUE) - // Check that people are actually using the machine. If not, don't update anymore. - if(obj_flags & IN_USE) - var/is_in_use = FALSE - if(update_viewers) - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - is_in_use = TRUE - src.interact(M) - var/ai_in_use = FALSE - if(update_ais) - ai_in_use = AutoUpdateAI(src) - - if(update_viewers && update_ais) //State change is sure only if we check both - if(!ai_in_use && !is_in_use) - obj_flags &= ~IN_USE - - /obj/attack_ghost(mob/user) . = ..() if(.) @@ -172,33 +121,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) SEND_SIGNAL(src, COMSIG_ATOM_UI_INTERACT, user) ui_interact(user) -/mob/proc/unset_machine() - SIGNAL_HANDLER - if(!machine) - return - UnregisterSignal(machine, COMSIG_QDELETING) - machine.on_unset_machine(src) - machine = null - -//called when the user unsets the machine. -/atom/movable/proc/on_unset_machine(mob/user) - return - -/mob/proc/set_machine(obj/O) - if(QDELETED(src) || QDELETED(O)) - return - if(machine) - unset_machine() - machine = O - RegisterSignal(O, COMSIG_QDELETING, PROC_REF(unset_machine)) - if(istype(O)) - O.obj_flags |= IN_USE - -/obj/item/proc/updateSelfDialog() - var/mob/M = src.loc - if(istype(M) && M.client && M.machine == src) - src.attack_self(M) - /obj/singularity_pull(S, current_size) ..() if(move_resist == INFINITY) @@ -209,9 +131,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) /obj/get_dumping_location() return get_turf(src) -/obj/proc/check_uplink_validity() - return 1 - /obj/vv_get_dropdown() . = ..() VV_DROPDOWN_OPTION("", "---") @@ -225,9 +144,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) return if(href_list[VV_HK_OSAY]) - if(!check_rights(R_FUN, FALSE)) - return - usr.client.object_say(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/object_say, src) if(href_list[VV_HK_MASS_DEL_TYPE]) if(!check_rights(R_DEBUG|R_SERVER)) @@ -272,56 +189,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) . += span_notice(desc_controls) if(obj_flags & UNIQUE_RENAME) . += span_notice("Use a pen on it to rename it or change its description.") - if(unique_reskin && (!current_skin || (obj_flags & INFINITE_RESKIN))) - . += span_notice("Alt-click it to reskin it.") -/obj/AltClick(mob/user) - . = ..() - if(unique_reskin && (!current_skin || (obj_flags & INFINITE_RESKIN)) && user.can_perform_action(src, NEED_DEXTERITY)) - reskin_obj(user) - -/** - * Reskins object based on a user's choice - * - * Arguments: - * * M The mob choosing a reskin option - */ -/obj/proc/reskin_obj(mob/user) - if(!LAZYLEN(unique_reskin)) - return - - var/list/items = list() - for(var/reskin_option in unique_reskin) - var/image/item_image = image(icon = src.icon, icon_state = unique_reskin[reskin_option]) - items += list("[reskin_option]" = item_image) - sort_list(items) - - var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), user), radius = 38, require_near = TRUE) - if(!pick) - return - if(!unique_reskin[pick]) - return - current_skin = pick - icon_state = unique_reskin[pick] - to_chat(user, "[src] is now skinned as '[pick].'") - SEND_SIGNAL(src, COMSIG_OBJ_RESKIN, user, pick) - -/** - * Checks if we are allowed to interact with a radial menu for reskins - * - * Arguments: - * * user The mob interacting with the menu - */ -/obj/proc/check_reskin_menu(mob/user) - if(QDELETED(src)) - return FALSE - if(!(obj_flags & INFINITE_RESKIN) && current_skin) - return FALSE - if(!istype(user)) - return FALSE - if(user.incapacitated()) - return FALSE - return TRUE /obj/analyzer_act(mob/living/user, obj/item/analyzer/tool) if(atmos_scan(user=user, target=src, silent=FALSE)) @@ -333,6 +201,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) // Should move all contained objects to it's location. /obj/proc/dump_contents() + SHOULD_CALL_PARENT(FALSE) CRASH("Unimplemented.") /obj/handle_ricochet(obj/projectile/P) @@ -367,8 +236,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) /// If we can unwrench this object; returns SUCCESSFUL_UNFASTEN and FAILED_UNFASTEN, which are both TRUE, or CANT_UNFASTEN, which isn't. /obj/proc/can_be_unfasten_wrench(mob/user, silent) - if(obj_flags & NO_DECONSTRUCTION) - return CANT_UNFASTEN if(!(isfloorturf(loc) || isindestructiblefloor(loc)) && !anchored) to_chat(user, span_warning("[src] needs to be on the floor to be secured!")) return FAILED_UNFASTEN diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index 7615a37a88b36..5c219aaa4a946 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -12,6 +12,8 @@ var/datum/ai_laws/laws var/obj/item/circuitboard/aicore/circuit var/obj/item/mmi/core_mmi + /// only used in cases of AIs piloting mechs or shunted malf AIs, possible later use cases + var/mob/living/silicon/ai/remote_ai = null /obj/structure/ai_core/Initialize(mapload) . = ..() @@ -58,11 +60,20 @@ update_appearance() /obj/structure/ai_core/Destroy() + if(istype(remote_ai)) + remote_ai.break_core_link() + remote_ai = null QDEL_NULL(circuit) QDEL_NULL(core_mmi) QDEL_NULL(laws) return ..() +/obj/structure/ai_core/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration) + . = ..() + if(. > 0 && istype(remote_ai)) + to_chat(remote_ai, span_danger("Your core is under attack!")) + + /obj/structure/ai_core/deactivated icon_state = "ai-empty" anchored = TRUE @@ -157,6 +168,8 @@ return ITEM_INTERACT_SUCCESS /obj/structure/ai_core/attackby(obj/item/tool, mob/living/user, params) + if(remote_ai) + to_chat(remote_ai, span_danger("CORE TAMPERING DETECTED!")) if(!anchored) if(tool.tool_behaviour == TOOL_WELDER) if(state != EMPTY_CORE) @@ -214,7 +227,7 @@ if(C.get_amount() >= 5) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) balloon_alert(user, "adding cables to frame...") - if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use(5)) + if(do_after(user, 2 SECONDS, target = src) && state == SCREWED_CORE && C.use(5)) balloon_alert(user, "added cables to frame.") state = CABLED_CORE update_appearance() @@ -241,7 +254,7 @@ if(G.get_amount() >= 2) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) balloon_alert(user, "adding glass panel...") - if(do_after(user, 20, target = src) && state == CABLED_CORE && G.use(2)) + if(do_after(user, 2 SECONDS, target = src) && state == CABLED_CORE && G.use(2)) balloon_alert(user, "added glass panel") state = GLASS_CORE update_appearance() @@ -295,8 +308,17 @@ if(tool.tool_behaviour == TOOL_CROWBAR && core_mmi) tool.play_tool_sound(src) balloon_alert(user, "removed [AI_CORE_BRAIN(core_mmi)]") - core_mmi.forceMove(loc) - return + if(remote_ai) + var/mob/living/silicon/ai/remoted_ai = remote_ai + remoted_ai.break_core_link() + if(!IS_MALF_AI(remoted_ai)) + //don't pull back shunted malf AIs + remoted_ai.death(gibbed = TRUE, drop_mmi = FALSE) + ///the drop_mmi param determines whether the MMI is dropped at their current location + ///which in this case would be somewhere else, so we drop their MMI at the core instead + remoted_ai.make_mmi_drop_and_transfer(core_mmi, src) + core_mmi.forceMove(loc) //if they're malf, just drops a blank MMI, or if it's an incomplete shell + return //it drops the mmi that was put in before it was finished if(GLASS_CORE) if(tool.tool_behaviour == TOOL_CROWBAR) @@ -380,7 +402,7 @@ icon_state = "ai-empty" return ..() -/obj/structure/ai_core/deconstruct(disassembled = TRUE) +/obj/structure/ai_core/atom_deconstruct(disassembled = TRUE) if(state >= GLASS_CORE) new /obj/item/stack/sheet/rglass(loc, 2) if(state >= CABLED_CORE) @@ -389,7 +411,6 @@ circuit.forceMove(loc) circuit = null new /obj/item/stack/sheet/plasteel(loc, 4) - qdel(src) /// Quick proc to call to see if the brainmob inside of us has suicided. Returns TRUE if we have, FALSE in any other scenario. /obj/structure/ai_core/proc/suicide_check() diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index 886d0b9bcba63..6d8e8ca701e3a 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -41,10 +41,8 @@ icon = 'icons/obj/fluff/general.dmi' icon_state = "gelmound" -/obj/structure/alien/gelpod/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/effect/mob_spawn/corpse/human/damaged(get_turf(src)) - qdel(src) +/obj/structure/alien/gelpod/atom_deconstruct(disassembled = TRUE) + new /obj/effect/mob_spawn/corpse/human/damaged(get_turf(src)) /* * Resin @@ -416,7 +414,7 @@ status = BURSTING proximity_monitor.set_range(0) flick("egg_opening", src) - addtimer(CALLBACK(src, PROC_REF(finish_bursting), kill), 15) + addtimer(CALLBACK(src, PROC_REF(finish_bursting), kill), 1.5 SECONDS) /obj/structure/alien/egg/proc/finish_bursting(kill = TRUE) status = BURST @@ -446,9 +444,8 @@ /obj/structure/alien/egg/atom_break(damage_flag) . = ..() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(status != BURST) - Burst(kill=TRUE) + if(status != BURST) + Burst(kill=TRUE) /obj/structure/alien/egg/HasProximity(atom/movable/AM) if(status == GROWN) diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm index 0a157dc98a1f3..77759c9e309b0 100644 --- a/code/game/objects/structures/beds_chairs/alien_nest.dm +++ b/code/game/objects/structures/beds_chairs/alien_nest.dm @@ -12,41 +12,51 @@ smoothing_groups = SMOOTH_GROUP_ALIEN_NEST canSmoothWith = SMOOTH_GROUP_ALIEN_NEST build_stack_type = null - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION elevation = 0 var/static/mutable_appearance/nest_overlay = mutable_appearance('icons/mob/nonhuman-player/alien.dmi', "nestoverlay", LYING_MOB_LAYER) -/obj/structure/bed/nest/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user) - if(has_buckled_mobs()) - for(var/buck in buckled_mobs) //breaking a nest releases all the buckled mobs, because the nest isn't holding them down anymore - var/mob/living/M = buck - - if(user.get_organ_by_type(/obj/item/organ/internal/alien/plasmavessel)) - unbuckle_mob(M) - add_fingerprint(user) - return - - if(M != user) - M.visible_message(span_notice("[user.name] pulls [M.name] free from the sticky nest!"),\ - span_notice("[user.name] pulls you free from the gelatinous resin."),\ - span_hear("You hear squelching...")) - else - M.visible_message(span_warning("[M.name] struggles to break free from the gelatinous resin!"),\ - span_notice("You struggle to break free from the gelatinous resin... (Stay still for about a minute and a half.)"),\ - span_hear("You hear squelching...")) - if(!do_after(M, 100 SECONDS, target = src)) - if(M?.buckled) - to_chat(M, span_warning("You fail to unbuckle yourself!")) - return - if(!M.buckled) - return - M.visible_message(span_warning("[M.name] breaks free from the gelatinous resin!"),\ - span_notice("You break free from the gelatinous resin!"),\ - span_hear("You hear squelching...")) - - - unbuckle_mob(M) - add_fingerprint(user) +/obj/structure/bed/nest/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + if(held_item?.tool_behaviour == TOOL_WRENCH) + return NONE + + return ..() + +/obj/structure/bed/nest/wrench_act_secondary(mob/living/user, obj/item/weapon) + return ITEM_INTERACT_BLOCKING + + +/obj/structure/bed/nest/user_unbuckle_mob(mob/living/captive, mob/living/hero) + if(!length(buckled_mobs)) + return + + if(hero.get_organ_by_type(/obj/item/organ/internal/alien/plasmavessel)) + unbuckle_mob(captive) + add_fingerprint(hero) + return + + if(captive != hero) + captive.visible_message(span_notice("[hero.name] pulls [captive.name] free from the sticky nest!"), + span_notice("[hero.name] pulls you free from the gelatinous resin."), + span_hear("You hear squelching...")) + unbuckle_mob(captive) + add_fingerprint(hero) + return + + captive.visible_message(span_warning("[captive.name] struggles to break free from the gelatinous resin!"), + span_notice("You struggle to break free from the gelatinous resin... (Stay still for about a minute and a half.)"), + span_hear("You hear squelching...")) + + if(!do_after(captive, 100 SECONDS, target = src, hidden = TRUE)) + if(captive.buckled) + to_chat(captive, span_warning("You fail to unbuckle yourself!")) + return + + captive.visible_message(span_warning("[captive.name] breaks free from the gelatinous resin!"), + span_notice("You break free from the gelatinous resin!"), + span_hear("You hear squelching...")) + + unbuckle_mob(captive) + add_fingerprint(hero) /obj/structure/bed/nest/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.incapacitated() || M.buckled ) diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm index e2038cb623b5f..e037043cc91a5 100644 --- a/code/game/objects/structures/beds_chairs/bed.dm +++ b/code/game/objects/structures/beds_chairs/bed.dm @@ -34,12 +34,11 @@ /obj/structure/bed/examine(mob/user) . = ..() - if(!(obj_flags & NO_DECONSTRUCTION)) - . += span_notice("It's held together by a couple of bolts.") + . += span_notice("It's held together by a couple of bolts.") /obj/structure/bed/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) if(held_item) - if(held_item.tool_behaviour != TOOL_WRENCH || obj_flags & NO_DECONSTRUCTION) + if(held_item.tool_behaviour != TOOL_WRENCH) return context[SCREENTIP_CONTEXT_RMB] = "Dismantle" @@ -49,19 +48,14 @@ context[SCREENTIP_CONTEXT_LMB] = "Unbuckle" return CONTEXTUAL_SCREENTIP_SET -/obj/structure/bed/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(build_stack_type) - new build_stack_type(loc, build_stack_amount) - ..() +/obj/structure/bed/atom_deconstruct(disassembled = TRUE) + if(build_stack_type) + new build_stack_type(loc, build_stack_amount) /obj/structure/bed/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) /obj/structure/bed/wrench_act_secondary(mob/living/user, obj/item/weapon) - if(obj_flags & NO_DECONSTRUCTION) - return TRUE - ..() weapon.play_tool_sound(src) deconstruct(disassembled = TRUE) @@ -116,17 +110,14 @@ if(!isnull(foldable_type)) . += span_notice("You can fold it up with a Right-click.") -/obj/structure/bed/medical/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return - +/obj/structure/bed/medical/click_alt(mob/user) if(has_buckled_mobs() && (user in buckled_mobs)) - return + return CLICK_ACTION_BLOCKING anchored = !anchored balloon_alert(user, "brakes [anchored ? "applied" : "released"]") update_appearance() + return CLICK_ACTION_SUCCESS /obj/structure/bed/medical/post_buckle_mob(mob/living/buckled) . = ..() @@ -227,13 +218,12 @@ /obj/item/emergency_bed/attack_self(mob/user) deploy_bed(user, user.loc) -/obj/item/emergency_bed/afterattack(obj/target, mob/user, proximity) - . = ..() - if(!proximity) - return +/obj/item/emergency_bed/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(isopenturf(interacting_with)) + deploy_bed(user, interacting_with) + return ITEM_INTERACT_SUCCESS + return NONE - if(isopenturf(target)) - deploy_bed(user, target) /obj/item/emergency_bed/proc/deploy_bed(mob/user, atom/location) var/obj/structure/bed/medical/emergency/deployed = new /obj/structure/bed/medical/emergency(location) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 0c4555bf390a4..4e86db314279b 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -36,16 +36,12 @@ SSjob.latejoin_trackers -= src //These may be here due to the arrivals shuttle return ..() -/obj/structure/chair/deconstruct(disassembled) - // If we have materials, and don't have the NOCONSTRUCT flag - if(!(obj_flags & NO_DECONSTRUCTION)) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - ..() +/obj/structure/chair/atom_deconstruct(disassembled) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) + else + for(var/datum/material/mat as anything in custom_materials) + new mat.sheet_type(loc, FLOOR(custom_materials[mat] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/chair/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) @@ -56,15 +52,11 @@ qdel(src) /obj/structure/chair/attackby(obj/item/W, mob/user, params) - if(obj_flags & NO_DECONSTRUCTION) - return . = ..() if(istype(W, /obj/item/assembly/shock_kit) && !HAS_TRAIT(src, TRAIT_ELECTRIFIED_BUCKLE)) electrify_self(W, user) return . = ..() -/obj/structure/chair/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation ///allows each chair to request the electrified_buckle component with overlays that dont look ridiculous /obj/structure/chair/proc/electrify_self(obj/item/assembly/shock_kit/input_shock_kit, mob/user, list/overlays_from_child_procs) @@ -85,8 +77,6 @@ /obj/structure/chair/wrench_act_secondary(mob/living/user, obj/item/weapon) - if(obj_flags & NO_DECONSTRUCTION) - return TRUE ..() weapon.play_tool_sound(src) deconstruct(disassembled = TRUE) @@ -274,7 +264,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool, 0) /obj/structure/chair/MouseDrop(over_object, src_location, over_location) . = ..() if(over_object == usr && Adjacent(usr)) - if(!item_chair || has_buckled_mobs() || src.obj_flags & NO_DECONSTRUCTION) + if(!item_chair || has_buckled_mobs()) return if(!usr.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) return @@ -450,6 +440,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) buildstacktype = /obj/item/stack/sheet/bronze buildstackamount = 1 item_chair = null + interaction_flags_click = NEED_DEXTERITY + /// Total rotations made var/turns = 0 /obj/structure/chair/bronze/Initialize(mapload) @@ -467,10 +459,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) if(turns >= 8) STOP_PROCESSING(SSfastprocess, src) -/obj/structure/chair/bronze/AltClick(mob/user) +/obj/structure/chair/bronze/click_alt(mob/user) turns = 0 - if(!user.can_perform_action(src, NEED_DEXTERITY)) - return if(!(datum_flags & DF_ISPROCESSING)) user.visible_message(span_notice("[user] spins [src] around, and the last vestiges of Ratvarian technology keeps it spinning FOREVER."), \ span_notice("Automated spinny chairs. The pinnacle of ancient Ratvarian technology.")) @@ -479,6 +469,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) user.visible_message(span_notice("[user] stops [src]'s uncontrollable spinning."), \ span_notice("You grab [src] and stop its wild spinning.")) STOP_PROCESSING(SSfastprocess, src) + return CLICK_ACTION_SUCCESS /obj/structure/chair/mime name = "invisible chair" @@ -487,9 +478,12 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) icon_state = null buildstacktype = null item_chair = null - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + obj_flags = parent_type::obj_flags | NO_DEBRIS_AFTER_DECONSTRUCTION alpha = 0 +/obj/structure/chair/mime/wrench_act_secondary(mob/living/user, obj/item/weapon) + return NONE + /obj/structure/chair/mime/post_buckle_mob(mob/living/M) M.pixel_y += 5 diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 50fcae8dec138..32ed0d14d873b 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -20,6 +20,7 @@ LINEN BINS w_class = WEIGHT_CLASS_TINY resistance_flags = FLAMMABLE dying_key = DYE_REGISTRY_BEDSHEET + interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING dog_fashion = /datum/dog_fashion/head/ghost /// Custom nouns to act as the subject of dreams @@ -133,11 +134,9 @@ LINEN BINS else return ..() -/obj/item/bedsheet/AltClick(mob/living/user) - // double check the canUseTopic args to make sure it's correct - if(!istype(user) || !user.can_perform_action(src, NEED_DEXTERITY)) - return +/obj/item/bedsheet/click_alt(mob/living/user) dir = REVERSE_DIR(dir) + return CLICK_ACTION_SUCCESS /obj/item/bedsheet/blue icon_state = "sheetblue" @@ -224,7 +223,7 @@ LINEN BINS /obj/item/bedsheet/medical name = "medical blanket" - desc = "It's a sterilized* blanket commonly used in the Medbay. *Sterilization is voided if a virologist is present onboard the station." + desc = "It's a 'sterilized' blanket commonly used in the Medbay." icon_state = "sheetmedical" inhand_icon_state = "sheetmedical" dream_messages = list("healing", "life", "surgery", "a doctor") @@ -609,8 +608,6 @@ LINEN BINS ..() /obj/structure/bedsheetbin/screwdriver_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return FALSE if(amount) to_chat(user, span_warning("The [src] must be empty first!")) return ITEM_INTERACT_SUCCESS diff --git a/code/game/objects/structures/bonfire.dm b/code/game/objects/structures/bonfire.dm index 987b9bcc37b56..a26a2f9278437 100644 --- a/code/game/objects/structures/bonfire.dm +++ b/code/game/objects/structures/bonfire.dm @@ -85,7 +85,7 @@ if(burning) to_chat(user, span_warning("You need to extinguish [src] before removing the logs!")) return - if(!has_buckled_mobs() && do_after(user, 50, target = src)) + if(!has_buckled_mobs() && do_after(user, 5 SECONDS, target = src)) for(var/obj/item/grown/log/bonfire_log in contents) bonfire_log.forceMove(drop_location()) bonfire_log.pixel_x += rand(1,4) @@ -191,7 +191,6 @@ // Late init so that we can wait for air to exist in lazyloaded templates /obj/structure/bonfire/prelit/LateInitialize() - . = ..() start_burning() #undef BONFIRE_FIRE_STACK_STRENGTH diff --git a/code/game/objects/structures/broken_flooring.dm b/code/game/objects/structures/broken_flooring.dm index 3d1fa986505dd..9b2e47290802f 100644 --- a/code/game/objects/structures/broken_flooring.dm +++ b/code/game/objects/structures/broken_flooring.dm @@ -16,7 +16,6 @@ return INITIALIZE_HINT_LATELOAD /obj/structure/broken_flooring/LateInitialize() - . = ..() var/turf/turf = get_turf(src) if(!isplatingturf(turf) && !always_floorplane) // Render as trash if not on plating plane = GAME_PLANE diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index dc273bdc938e8..acbd7bfa39539 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -163,7 +163,6 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) update_appearance() /obj/structure/closet/LateInitialize() - . = ..() if(!opened && is_maploaded) take_contents() @@ -581,25 +580,26 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) else return open(user) -/obj/structure/closet/deconstruct(disassembled = TRUE) - if (!(obj_flags & NO_DECONSTRUCTION)) - if(ispath(material_drop) && material_drop_amount) - new material_drop(loc, material_drop_amount) - if (secure) - var/obj/item/electronics/airlock/electronics = new(drop_location()) - if(length(req_one_access)) - electronics.one_access = TRUE - electronics.accesses = req_one_access - else - electronics.accesses = req_access - if(card_reader_installed) - new /obj/item/stock_parts/card_reader(drop_location()) +/obj/structure/closet/handle_deconstruct(disassembled) dump_contents() - qdel(src) + if(obj_flags & NO_DEBRIS_AFTER_DECONSTRUCTION) + return + + if(ispath(material_drop) && material_drop_amount) + new material_drop(loc, material_drop_amount) + if (secure) + var/obj/item/electronics/airlock/electronics = new(drop_location()) + if(length(req_one_access)) + electronics.one_access = TRUE + electronics.accesses = req_one_access + else + electronics.accesses = req_access + if(card_reader_installed) + new /obj/item/stock_parts/card_reader(drop_location()) /obj/structure/closet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) bust_open() /obj/structure/closet/CheckParts(list/parts_list) diff --git a/code/game/objects/structures/crates_lockers/closets/bodybag.dm b/code/game/objects/structures/crates_lockers/closets/bodybag.dm index bfed8bea979bd..38482fcfd9ba9 100644 --- a/code/game/objects/structures/crates_lockers/closets/bodybag.dm +++ b/code/game/objects/structures/crates_lockers/closets/bodybag.dm @@ -171,7 +171,7 @@ if(A_is_item.w_class < max_weight_of_contents) continue max_weight_of_contents = A_is_item.w_class - folding_bodybag.w_class = max_weight_of_contents + folding_bodybag.update_weight_class(max_weight_of_contents) the_folder.put_in_hands(folding_bodybag) /// Environmental bags. They protect against bad weather. diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index d90212ca113ad..3dc59fb9ce21a 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -23,7 +23,7 @@ . = ..() // Traitor steal objective - new /obj/item/areaeditor/blueprints(src) + new /obj/item/blueprints(src) new /obj/item/pipe_dispenser(src) /obj/structure/closet/secure_closet/engineering_electrical diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm index 1ac7e65884e40..1e19671a45546 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -36,10 +36,8 @@ flags_1 &= ~PREVENT_CONTENTS_EXPLOSION_1 return FALSE -/obj/structure/closet/secure_closet/freezer/deconstruct(disassembled) - if (!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/assembly/igniter/condenser(drop_location()) - . = ..() +/obj/structure/closet/secure_closet/freezer/atom_deconstruct(disassembled) + new /obj/item/assembly/igniter/condenser(drop_location()) /obj/structure/closet/secure_closet/freezer/empty name = "freezer" diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 0653918e0264f..c44cd0972aad1 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -46,20 +46,20 @@ var/static/list/crate_paint_jobs if(isnull(crate_paint_jobs)) crate_paint_jobs = list( - "Internals" = list("icon_state" = "o2crate"), - "Medical" = list("icon_state" = "medical"), - "Medical Plus" = list("icon_state" = "medicalcrate"), - "Radiation" = list("icon_state" = "radiation"), - "Hydrophonics" = list("icon_state" = "hydrocrate"), - "Science" = list("icon_state" = "scicrate"), - "Robotics" = list("icon_state" = "robo"), - "Solar" = list("icon_state" = "engi_e_crate"), - "Engineering" = list("icon_state" = "engi_crate"), - "Atmospherics" = list("icon_state" = "atmos"), - "Cargo" = list("icon_state" = "cargo"), - "Mining" = list("icon_state" = "mining"), - "Command" = list("icon_state" = "centcom") - ) + "Internals" = list("icon_state" = "o2crate"), + "Medical" = list("icon_state" = "medical"), + "Medical Plus" = list("icon_state" = "medicalcrate"), + "Radiation" = list("icon_state" = "radiation"), + "Hydrophonics" = list("icon_state" = "hydrocrate"), + "Science" = list("icon_state" = "scicrate"), + "Robotics" = list("icon_state" = "robo"), + "Solar" = list("icon_state" = "engi_e_crate"), + "Engineering" = list("icon_state" = "engi_crate"), + "Atmospherics" = list("icon_state" = "atmos"), + "Cargo" = list("icon_state" = "cargo"), + "Mining" = list("icon_state" = "mining"), + "Command" = list("icon_state" = "centcom"), + ) if(paint_jobs) paint_jobs = crate_paint_jobs diff --git a/code/game/objects/structures/crates_lockers/crates/bins.dm b/code/game/objects/structures/crates_lockers/crates/bins.dm index 6b865b845861f..a686d53f392c6 100644 --- a/code/game/objects/structures/crates_lockers/crates/bins.dm +++ b/code/game/objects/structures/crates_lockers/crates/bins.dm @@ -47,7 +47,7 @@ /obj/structure/closet/crate/bin/proc/do_animate() playsound(loc, open_sound, 15, TRUE, -3) flick(base_icon_state + "_animate", src) - addtimer(CALLBACK(src, PROC_REF(do_close)), 11) + addtimer(CALLBACK(src, PROC_REF(do_close)), 1.1 SECONDS) /obj/structure/closet/crate/bin/proc/do_close() playsound(loc, close_sound, 15, TRUE, -3) diff --git a/code/game/objects/structures/deployable_turret.dm b/code/game/objects/structures/deployable_turret.dm index ac4b35678c9b1..7b03348288abb 100644 --- a/code/game/objects/structures/deployable_turret.dm +++ b/code/game/objects/structures/deployable_turret.dm @@ -51,19 +51,21 @@ /// Undeploying, for when you want to move your big dakka around /obj/machinery/deployable_turret/wrench_act(mob/living/user, obj/item/wrench/used_wrench) - . = ..() if(!can_be_undeployed) - return + return ITEM_INTERACT_SKIP_TO_ATTACK if(!ishuman(user)) - return + return ITEM_INTERACT_SKIP_TO_ATTACK used_wrench.play_tool_sound(user) user.balloon_alert(user, "undeploying...") if(!do_after(user, undeploy_time)) - return - var/obj/undeployed_object = new spawned_on_undeploy(src) + return ITEM_INTERACT_BLOCKING + var/obj/undeployed_object = new spawned_on_undeploy() //Keeps the health the same even if you redeploy the gun undeployed_object.modify_max_integrity(max_integrity) + if(!user.put_in_hands(undeployed_object)) + undeployed_object.forceMove(loc) qdel(src) + return ITEM_INTERACT_SUCCESS //BUCKLE HOOKS diff --git a/code/game/objects/structures/destructible_structures.dm b/code/game/objects/structures/destructible_structures.dm index f33c99b681a64..beffa5d4fd741 100644 --- a/code/game/objects/structures/destructible_structures.dm +++ b/code/game/objects/structures/destructible_structures.dm @@ -4,16 +4,13 @@ var/break_sound = 'sound/magic/clockwork/invoke_general.ogg' //The sound played when a structure breaks var/list/debris = null //Parts left behind when a structure breaks, takes the form of list(path = amount_to_spawn) -/obj/structure/destructible/deconstruct(disassembled = TRUE) +/obj/structure/destructible/atom_deconstruct(disassembled = TRUE) if(!disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(islist(debris)) - for(var/I in debris) - for(var/i in 1 to debris[I]) - new I (get_turf(src)) - if(break_message) - visible_message(break_message) - if(break_sound) - playsound(src, break_sound, 50, TRUE) - qdel(src) - return 1 + if(islist(debris)) + for(var/I in debris) + for(var/i in 1 to debris[I]) + new I (get_turf(src)) + if(break_message) + visible_message(break_message) + if(break_sound) + playsound(src, break_sound, 50, TRUE) diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index d7deb5b42cf79..012e8e8a544e9 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -81,17 +81,15 @@ if(BURN) playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/displaycase/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - dump() - if(!disassembled) - new /obj/item/shard(drop_location()) - trigger_alarm() - qdel(src) +/obj/structure/displaycase/atom_deconstruct(disassembled = TRUE) + dump() + if(!disassembled) + new /obj/item/shard(drop_location()) + trigger_alarm() /obj/structure/displaycase/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) set_density(FALSE) broken = TRUE new /obj/item/shard(drop_location()) @@ -168,7 +166,7 @@ to_chat(user, span_warning("You need two glass sheets to fix the case!")) return to_chat(user, span_notice("You start fixing [src]...")) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) glass_sheet.use(2) broken = FALSE atom_integrity = max_integrity @@ -453,8 +451,8 @@ ui.open() /obj/item/key/displaycase - name = "display case key" - desc = "The key to the curator's display cases." + name = "curator key" + desc = "The key to the curator's display cases and arcade cabinets." /obj/item/showpiece_dummy name = "holographic replica" @@ -630,7 +628,7 @@ . = ..() if(atom_integrity <= (integrity_failure * max_integrity)) to_chat(user, span_notice("You start recalibrating [src]'s hover field...")) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) broken = FALSE atom_integrity = max_integrity update_appearance() @@ -673,7 +671,7 @@ /obj/structure/displaycase/forsale/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) broken = TRUE playsound(src, SFX_SHATTER, 70, TRUE) update_appearance() diff --git a/code/game/objects/structures/divine.dm b/code/game/objects/structures/divine.dm index ef9f650e42a56..6114a20158c68 100644 --- a/code/game/objects/structures/divine.dm +++ b/code/game/objects/structures/divine.dm @@ -7,19 +7,17 @@ density = FALSE can_buckle = 1 -/obj/structure/sacrificealtar/AltClick(mob/living/user) - ..() - if(!istype(user) || !user.can_perform_action(src)) - return +/obj/structure/sacrificealtar/click_alt(mob/living/user) if(!has_buckled_mobs()) - return + return CLICK_ACTION_BLOCKING var/mob/living/L = locate() in buckled_mobs if(!L) - return + return CLICK_ACTION_BLOCKING to_chat(user, span_notice("Invoking the sacred ritual, you sacrifice [L].")) L.investigate_log("has been sacrificially gibbed on an altar.", INVESTIGATE_DEATHS) L.gib(DROP_ALL_REMAINS) message_admins("[ADMIN_LOOKUPFLW(user)] has sacrificed [key_name_admin(L)] on the sacrificial altar at [AREACOORD(src)].") + return CLICK_ACTION_SUCCESS /obj/structure/healingfountain name = "healing fountain" diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index f110cd8b43eab..f75a8b9ce726c 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -184,7 +184,7 @@ W.play_tool_sound(src, 100) user.visible_message(span_notice("[user] installs the electronics into the airlock assembly."), \ span_notice("You start to install electronics into the airlock assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if( state != AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS ) return if(!user.transferItemToLoc(W, src)) @@ -224,7 +224,7 @@ playsound(src, 'sound/items/crowbar.ogg', 100, TRUE) user.visible_message(span_notice("[user] adds [G.name] to the airlock assembly."), \ span_notice("You start to install [G.name] into the airlock assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(G.get_amount() < 1 || glass) return if(G.type == /obj/item/stack/sheet/rglass) @@ -247,7 +247,7 @@ playsound(src, 'sound/items/crowbar.ogg', 100, TRUE) user.visible_message(span_notice("[user] adds [G.name] to the airlock assembly."), \ span_notice("You start to install [G.name] into the airlock assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(G.get_amount() < 2 || mineral) return to_chat(user, span_notice("You install [M] plating into the airlock assembly.")) @@ -363,25 +363,22 @@ target.update_name() qdel(source) -/obj/structure/door_assembly/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - if(!disassembled) - material_amt = rand(2,4) - new material_type(T, material_amt) - if(glass) - if(disassembled) - if(heat_proof_finished) - new /obj/item/stack/sheet/rglass(T) - else - new /obj/item/stack/sheet/glass(T) +/obj/structure/door_assembly/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + if(!disassembled) + material_amt = rand(2,4) + new material_type(target_turf, material_amt) + if(glass) + if(disassembled) + if(heat_proof_finished) + new /obj/item/stack/sheet/rglass(target_turf) else - new /obj/item/shard(T) - if(mineral) - var/obj/item/stack/sheet/mineral/mineral_path = text2path("/obj/item/stack/sheet/mineral/[mineral]") - new mineral_path(T, 2) - qdel(src) - + new /obj/item/stack/sheet/glass(target_turf) + else + new /obj/item/shard(target_turf) + if(mineral) + var/obj/item/stack/sheet/mineral/mineral_path = text2path("/obj/item/stack/sheet/mineral/[mineral]") + new mineral_path(target_turf, 2) /obj/structure/door_assembly/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) diff --git a/code/game/objects/structures/door_assembly_types.dm b/code/game/objects/structures/door_assembly_types.dm index 589cad42bcabc..dd06f7e42a9a4 100644 --- a/code/game/objects/structures/door_assembly_types.dm +++ b/code/game/objects/structures/door_assembly_types.dm @@ -271,24 +271,21 @@ name = "large public airlock assembly" base_name = "large public airlock" -/obj/structure/door_assembly/door_assembly_material/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - for(var/material in custom_materials) - var/datum/material/material_datum = material - var/material_count = FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1) - if(!disassembled) - material_count = rand(FLOOR(material_count/2, 1), material_count) - new material_datum.sheet_type(T, material_count) - if(glass) - if(disassembled) - if(heat_proof_finished) - new /obj/item/stack/sheet/rglass(T) - else - new /obj/item/stack/sheet/glass(T) +/obj/structure/door_assembly/door_assembly_material/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + for(var/datum/material/material_datum as anything in custom_materials) + var/material_count = FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1) + if(!disassembled) + material_count = rand(FLOOR(material_count/2, 1), material_count) + new material_datum.sheet_type(target_turf, material_count) + if(glass) + if(disassembled) + if(heat_proof_finished) + new /obj/item/stack/sheet/rglass(target_turf) else - new /obj/item/shard(T) - qdel(src) + new /obj/item/stack/sheet/glass(target_turf) + else + new /obj/item/shard(target_turf) /obj/structure/door_assembly/door_assembly_material/finish_door() var/obj/machinery/door/airlock/door = ..() diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 0d9b3664cb29a..cf3864b140059 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -16,10 +16,8 @@ else return ..() -/obj/structure/dresser/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/mineral/wood(drop_location(), 10) - qdel(src) +/obj/structure/dresser/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/mineral/wood(drop_location(), 10) /obj/structure/dresser/attack_hand(mob/user, list/modifiers) . = ..() @@ -42,7 +40,7 @@ return switch(choice) if("Underwear") - var/new_undies = tgui_input_list(user, "Select your underwear", "Changing", GLOB.underwear_list) + var/new_undies = tgui_input_list(user, "Select your underwear", "Changing", SSaccessories.underwear_list) if(new_undies) dressing_human.underwear = new_undies if("Underwear Color") @@ -50,11 +48,11 @@ if(new_underwear_color) dressing_human.underwear_color = sanitize_hexcolor(new_underwear_color) if("Undershirt") - var/new_undershirt = tgui_input_list(user, "Select your undershirt", "Changing", GLOB.undershirt_list) + var/new_undershirt = tgui_input_list(user, "Select your undershirt", "Changing", SSaccessories.undershirt_list) if(new_undershirt) dressing_human.undershirt = new_undershirt if("Socks") - var/new_socks = tgui_input_list(user, "Select your socks", "Changing", GLOB.socks_list) + var/new_socks = tgui_input_list(user, "Select your socks", "Changing", SSaccessories.socks_list) if(new_socks) dressing_human.socks = new_socks diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index fb925cdb7dae8..e78b71f14e963 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -160,7 +160,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) /obj/structure/extinguisher_cabinet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) broken = 1 opened = 1 if(stored_extinguisher) @@ -169,16 +169,14 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) update_appearance(UPDATE_ICON) -/obj/structure/extinguisher_cabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new /obj/item/wallframe/extinguisher_cabinet(loc) - else - new /obj/item/stack/sheet/iron (loc, 2) - if(stored_extinguisher) - stored_extinguisher.forceMove(loc) - stored_extinguisher = null - qdel(src) +/obj/structure/extinguisher_cabinet/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new /obj/item/wallframe/extinguisher_cabinet(loc) + else + new /obj/item/stack/sheet/iron (loc, 2) + if(stored_extinguisher) + stored_extinguisher.forceMove(loc) + stored_extinguisher = null /obj/item/wallframe/extinguisher_cabinet name = "extinguisher cabinet frame" diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index eaf830b7db78e..cace64a710169 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -49,7 +49,7 @@ opening = FALSE return update_appearance() - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/falsewall, toggle_open)), 5) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/falsewall, toggle_open)), 0.5 SECONDS) /obj/structure/falsewall/proc/toggle_open() if(!QDELETED(src)) @@ -91,9 +91,9 @@ qdel(src) return T -/obj/structure/falsewall/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/structure/falsewall/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(!opening || !tool.tool_behaviour) - return ..() + return NONE to_chat(user, span_warning("You must wait until the door has stopped moving!")) return ITEM_INTERACT_BLOCKING @@ -133,14 +133,12 @@ playsound(src, 'sound/items/welder.ogg', 100, TRUE) deconstruct(disassembled) -/obj/structure/falsewall/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - if(mineral_amount) - for(var/i in 1 to mineral_amount) - new mineral(loc) - qdel(src) +/obj/structure/falsewall/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + if(mineral_amount) + for(var/i in 1 to mineral_amount) + new mineral(loc) /obj/structure/falsewall/get_dumping_location() return null @@ -387,14 +385,12 @@ canSmoothWith = SMOOTH_GROUP_MATERIAL_WALLS material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS -/obj/structure/falsewall/material/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - for(var/material in custom_materials) - var/datum/material/material_datum = material - new material_datum.sheet_type(loc, FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1)) - qdel(src) +/obj/structure/falsewall/material/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + for(var/material in custom_materials) + var/datum/material/material_datum = material + new material_datum.sheet_type(loc, FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/falsewall/material/mat_update_desc(mat) desc = "A huge chunk of [mat] used to separate rooms." diff --git a/code/game/objects/structures/fans.dm b/code/game/objects/structures/fans.dm index 924da72ee3098..4f0a5fc450bfe 100644 --- a/code/game/objects/structures/fans.dm +++ b/code/game/objects/structures/fans.dm @@ -10,21 +10,15 @@ var/buildstackamount = 5 can_atmos_pass = ATMOS_PASS_NO -/obj/structure/fans/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - qdel(src) +/obj/structure/fans/atom_deconstruct(disassembled = TRUE) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) /obj/structure/fans/wrench_act(mob/living/user, obj/item/I) - ..() - if(obj_flags & NO_DECONSTRUCTION) - return TRUE - user.visible_message(span_warning("[user] disassembles [src]."), span_notice("You start to disassemble [src]..."), span_hear("You hear clanking and banging noises.")) if(I.use_tool(src, user, 20, volume=50)) - deconstruct() + deconstruct(TRUE) return TRUE /obj/structure/fans/tiny diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm index ab7d410f0966e..ab69b7bc7a41e 100644 --- a/code/game/objects/structures/fireaxe.dm +++ b/code/game/objects/structures/fireaxe.dm @@ -108,19 +108,17 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet, 32) /obj/structure/fireaxecabinet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) update_appearance() broken = TRUE playsound(src, 'sound/effects/glassbr3.ogg', 100, TRUE) new /obj/item/shard(loc) new /obj/item/shard(loc) -/obj/structure/fireaxecabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item && loc) - held_item.forceMove(loc) - new /obj/item/wallframe/fireaxecabinet(loc) - qdel(src) +/obj/structure/fireaxecabinet/atom_deconstruct(disassembled = TRUE) + if(held_item && loc) + held_item.forceMove(loc) + new /obj/item/wallframe/fireaxecabinet(loc) /obj/structure/fireaxecabinet/blob_act(obj/structure/blob/B) if(held_item) @@ -230,12 +228,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet/empty, 32) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet/mechremoval, 32) -/obj/structure/fireaxecabinet/mechremoval/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item && loc) - held_item.forceMove(loc) - new /obj/item/wallframe/fireaxecabinet/mechremoval(loc) - qdel(src) +/obj/structure/fireaxecabinet/mechremoval/atom_deconstruct(disassembled = TRUE) + if(held_item && loc) + held_item.forceMove(loc) + new /obj/item/wallframe/fireaxecabinet/mechremoval(loc) /obj/structure/fireaxecabinet/mechremoval/empty populate_contents = FALSE diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index e7060a145e99a..2cfd490203c06 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -263,13 +263,11 @@ var/matrix/M = matrix(transform) transform = M.Turn(-previous_rotation) -/obj/structure/flora/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(harvested) - return ..() +/obj/structure/flora/atom_deconstruct(disassembled = TRUE) + if(harvested) + return ..() - harvest(product_amount_multiplier = 0.6) - . = ..() + harvest(product_amount_multiplier = 0.6) /********* * Trees * @@ -451,7 +449,6 @@ icon_state = "pinepresents" desc = "A wondrous decorated Christmas tree. It has presents!" resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF //protected by the christmas spirit - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION var/gift_type = /obj/item/gift/anything var/unlimited = FALSE var/static/list/took_presents //shared between all xmas trees diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 3bb24147f5c49..0f20f87e0b547 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -81,7 +81,7 @@ balloon_alert(user, "need [amount] rods!") return balloon_alert(user, "concealing entrance...") - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(rod.get_amount() < amount) return rod.use(amount) @@ -94,7 +94,7 @@ balloon_alert(user, "need [amount] rods!") return balloon_alert(user, "adding plating...") - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(rod.get_amount() < amount) return rod.use(amount) @@ -176,7 +176,7 @@ balloon_alert(user, "need [amount] sheets!") return balloon_alert(user, "concealing entrance...") - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(sheets.get_amount() < amount) return sheets.use(amount) @@ -243,7 +243,7 @@ balloon_alert(user, "need [amount] sheets!") return balloon_alert(user, "concealing entrance...") - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(sheets.get_amount() < amount) return sheets.use(amount) @@ -265,7 +265,7 @@ balloon_alert(user, "need [amount] sheets!") return balloon_alert(user, "adding plating...") - if (do_after(user, 40, target = src)) + if (do_after(user, 4 SECONDS, target = src)) if(sheets.get_amount() < amount) return sheets.use(amount) @@ -384,11 +384,9 @@ return TRUE return FALSE -/obj/structure/girder/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/remains = pick(/obj/item/stack/rods, /obj/item/stack/sheet/iron) - new remains(loc) - qdel(src) +/obj/structure/girder/atom_deconstruct(disassembled = TRUE) + var/remains = pick(/obj/item/stack/rods, /obj/item/stack/sheet/iron) + new remains(loc) /obj/structure/girder/narsie_act() new /obj/structure/girder/cult(loc) @@ -447,7 +445,7 @@ balloon_alert(user, "need [amount] sheet!") return balloon_alert(user, "adding plating...") - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) if(R.get_amount() < amount) return R.use(amount) @@ -461,10 +459,8 @@ /obj/structure/girder/cult/narsie_act() return -/obj/structure/girder/cult/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/runed_metal(drop_location(), 1) - qdel(src) +/obj/structure/girder/cult/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/runed_metal(drop_location(), 1) /obj/structure/girder/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) switch(the_rcd.mode) @@ -519,7 +515,7 @@ balloon_alert(user, "need [amount] sheets!") return balloon_alert(user, "adding plating...") - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) if(B.get_amount() < amount) return B.use(amount) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index da02394251810..37b894e277307 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -10,8 +10,7 @@ density = TRUE anchored = TRUE pass_flags_self = PASSGRILLE | PASSWINDOW - obj_flags = CONDUCTS_ELECTRICITY - obj_flags = CAN_BE_HIT | IGNORE_DENSITY + obj_flags = CONDUCTS_ELECTRICITY | CAN_BE_HIT | IGNORE_DENSITY pressure_resistance = 5*ONE_ATMOSPHERE armor_type = /datum/armor/structure_grille max_integrity = 50 @@ -52,8 +51,6 @@ /obj/structure/grille/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(anchored) . += span_notice("It's secured in place with screws. The rods look like they could be cut through.") @@ -200,10 +197,8 @@ add_fingerprint(user) if(shock(user, 100)) return - if(obj_flags & NO_DECONSTRUCTION) - return FALSE tool.play_tool_sound(src, 100) - deconstruct() + deconstruct(TRUE) return ITEM_INTERACT_SUCCESS /obj/structure/grille/screwdriver_act(mob/living/user, obj/item/tool) @@ -212,8 +207,6 @@ add_fingerprint(user) if(shock(user, 90)) return FALSE - if(obj_flags & NO_DECONSTRUCTION) - return FALSE if(!tool.use_tool(src, user, 0, volume=100)) return FALSE set_anchored(!anchored) @@ -296,18 +289,13 @@ playsound(src, 'sound/items/welder.ogg', 80, TRUE) -/obj/structure/grille/deconstruct(disassembled = TRUE) - if(!loc) //if already qdel'd somehow, we do nothing - return - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/R = new rods_type(drop_location(), rods_amount) - transfer_fingerprints_to(R) - qdel(src) - ..() +/obj/structure/grille/atom_deconstruct(disassembled = TRUE) + var/obj/rods = new rods_type(drop_location(), rods_amount) + transfer_fingerprints_to(rods) /obj/structure/grille/atom_break() . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) icon_state = "brokengrille" set_density(FALSE) atom_integrity = 20 diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm index bc56b3838ca11..a51e82498e2bc 100644 --- a/code/game/objects/structures/guillotine.dm +++ b/code/game/objects/structures/guillotine.dm @@ -192,7 +192,7 @@ if (blade_status == GUILLOTINE_BLADE_RAISED) if (blade_sharpness < GUILLOTINE_BLADE_MAX_SHARP) blade_status = GUILLOTINE_BLADE_SHARPENING - if(do_after(user, 7, target = src)) + if(do_after(user, 0.7 SECONDS, target = src)) blade_status = GUILLOTINE_BLADE_RAISED user.visible_message(span_notice("[user] sharpens the large blade of the guillotine."), span_notice("You sharpen the large blade of the guillotine.")) diff --git a/code/game/objects/structures/gym/punching_bag.dm b/code/game/objects/structures/gym/punching_bag.dm index f441887f2c191..ef0db16e953e3 100644 --- a/code/game/objects/structures/gym/punching_bag.dm +++ b/code/game/objects/structures/gym/punching_bag.dm @@ -57,9 +57,12 @@ stamina_exhaustion = 2 if (is_heavy_gravity) stamina_exhaustion *= 1.5 + + if(HAS_TRAIT(user, TRAIT_STRENGTH)) //The strong get reductions to stamina damage taken while exercising + stamina_exhaustion *= 0.5 user.adjustStaminaLoss(stamina_exhaustion) - user.mind?.adjust_experience(/datum/skill/fitness, is_heavy_gravity ? 0.2 : 0.1) + user.mind?.adjust_experience(/datum/skill/athletics, is_heavy_gravity ? 0.2 : 0.1) user.apply_status_effect(/datum/status_effect/exercised) /obj/structure/punching_bag/wrench_act_secondary(mob/living/user, obj/item/tool) diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm index d3614ee6815bc..3c531f0488929 100644 --- a/code/game/objects/structures/gym/weight_machine.dm +++ b/code/game/objects/structures/gym/weight_machine.dm @@ -109,7 +109,7 @@ if(do_after(user, 8 SECONDS, src) && user.has_gravity()) // with enough dedication, even clowns can overcome their handicaps - var/clumsy_chance = 30 - (user.mind.get_skill_level(/datum/skill/fitness) * 5) + var/clumsy_chance = 30 - (user.mind.get_skill_level(/datum/skill/athletics) * 5) if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(clumsy_chance)) playsound(src, 'sound/effects/bang.ogg', 50, TRUE) to_chat(user, span_warning("Your hand slips, causing the [name] to smash you!")) @@ -135,7 +135,7 @@ if(iscarbon(user)) var/gravity_modifier = user.has_gravity() > STANDARD_GRAVITY ? 2 : 1 // remember the real xp gain is from sleeping after working out - user.mind.adjust_experience(/datum/skill/fitness, WORKOUT_XP * gravity_modifier) + user.mind.adjust_experience(/datum/skill/athletics, WORKOUT_XP * gravity_modifier) user.apply_status_effect(/datum/status_effect/exercised, EXERCISE_STATUS_DURATION) end_workout() @@ -168,9 +168,13 @@ return TRUE // No weight? I could do this all day var/gravity_modifier = affected_gravity > STANDARD_GRAVITY ? 0.75 : 1 // the amount of workouts you can do before you hit stamcrit - var/workout_reps = total_workout_reps[user.mind.get_skill_level(/datum/skill/fitness)] * gravity_modifier + var/workout_reps = total_workout_reps[user.mind.get_skill_level(/datum/skill/athletics)] * gravity_modifier // total stamina drain of 1 workout calculated based on the workout length var/stamina_exhaustion = FLOOR(user.maxHealth / workout_reps / WORKOUT_LENGTH, 0.1) + + if(HAS_TRAIT(user, TRAIT_STRENGTH)) //The strong get reductions to stamina damage taken while exercising + stamina_exhaustion *= 0.5 + user.adjustStaminaLoss(stamina_exhaustion * seconds_per_tick) return TRUE diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm index b48cafc85d99f..fca325744554d 100644 --- a/code/game/objects/structures/headpike.dm +++ b/code/game/objects/structures/headpike.dm @@ -17,6 +17,10 @@ icon_state = "headpike-bamboo" speartype = /obj/item/spear/bamboospear +/obj/structure/headpike/military //for military spears + icon_state = "headpike-military" + speartype = /obj/item/spear/military + /obj/structure/headpike/Initialize(mapload) . = ..() if(mapload) @@ -32,7 +36,7 @@ victim = locate() in parts_list if(!victim) //likely a mapspawned one victim = new(src) - victim.real_name = random_unique_name(prob(50)) + victim.real_name = generate_random_name() spear = locate(speartype) in parts_list if(!spear) spear = new speartype(src) @@ -64,7 +68,7 @@ if(!QDELETED(src)) deconstruct(TRUE) -/obj/structure/headpike/deconstruct(disassembled) +/obj/structure/headpike/atom_deconstruct(disassembled) var/obj/item/bodypart/head/our_head = victim var/obj/item/spear/our_spear = spear victim = null @@ -73,7 +77,6 @@ if(!disassembled) return ..() our_spear?.forceMove(drop_location()) - return ..() /obj/structure/headpike/attack_hand(mob/user, list/modifiers) . = ..() diff --git a/code/game/objects/structures/hivebot.dm b/code/game/objects/structures/hivebot.dm index ba371f8d65836..838113cab8c38 100644 --- a/code/game/objects/structures/hivebot.dm +++ b/code/game/objects/structures/hivebot.dm @@ -15,7 +15,7 @@ smoke.start() visible_message(span_boldannounce("[src] warps in!")) playsound(src.loc, 'sound/effects/empulse.ogg', 25, TRUE) - addtimer(CALLBACK(src, PROC_REF(warpbots)), rand(10, 600)) + addtimer(CALLBACK(src, PROC_REF(warpbots)), rand(1 SECONDS, 1 MINUTES)) /obj/structure/hivebot_beacon/proc/warpbots() icon_state = "def_radar" diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm index a1a3adf325145..1d7fc470afff8 100644 --- a/code/game/objects/structures/holosign.dm +++ b/code/game/objects/structures/holosign.dm @@ -215,7 +215,7 @@ var/mob/living/M = user M.electrocute_act(15,"Energy Barrier") shockcd = TRUE - addtimer(CALLBACK(src, PROC_REF(cooldown)), 5) + addtimer(CALLBACK(src, PROC_REF(cooldown)), 0.5 SECONDS) /obj/structure/holosign/barrier/cyborg/hacked/Bumped(atom/movable/AM) if(shockcd) @@ -227,4 +227,4 @@ var/mob/living/M = AM M.electrocute_act(15,"Energy Barrier") shockcd = TRUE - addtimer(CALLBACK(src, PROC_REF(cooldown)), 5) + addtimer(CALLBACK(src, PROC_REF(cooldown)), 0.5 SECONDS) diff --git a/code/game/objects/structures/icemoon/cave_entrance.dm b/code/game/objects/structures/icemoon/cave_entrance.dm index 20f14844c12b5..4401b87d23eca 100644 --- a/code/game/objects/structures/icemoon/cave_entrance.dm +++ b/code/game/objects/structures/icemoon/cave_entrance.dm @@ -40,10 +40,9 @@ GLOBAL_LIST_INIT(ore_probability, list( var/turf/closed/mineral/clearable = potential clearable.ScrapeAway(flags = CHANGETURF_IGNORE_AIR) -/obj/structure/spawner/ice_moon/deconstruct(disassembled) +/obj/structure/spawner/ice_moon/atom_deconstruct(disassembled) destroy_effect() drop_loot() - return ..() /** * Effects and messages created when the spawner is destroyed diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 7a7307b0431f5..0cc73b9adef9c 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -143,7 +143,7 @@ span_notice("You struggle to break free from [src], exacerbating your wounds! (Stay still for two minutes.)"),\ span_hear("You hear a wet squishing noise..")) buckled_mob.adjustBruteLoss(30) - if(!do_after(buckled_mob, 2 MINUTES, target = src)) + if(!do_after(buckled_mob, 2 MINUTES, target = src, hidden = TRUE)) if(buckled_mob?.buckled) to_chat(buckled_mob, span_warning("You fail to free yourself!")) return @@ -159,13 +159,12 @@ buckled_mob.pixel_y = buckled_mob.base_pixel_y + PIXEL_Y_OFFSET_LYING REMOVE_TRAIT(buckled_mob, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) -/obj/structure/kitchenspike/deconstruct(disassembled = TRUE) +/obj/structure/kitchenspike/atom_deconstruct(disassembled = TRUE) if(disassembled) var/obj/structure/meatspike_frame = new /obj/structure/kitchenspike_frame(src.loc) transfer_fingerprints_to(meatspike_frame) else new /obj/item/stack/sheet/iron(src.loc, 4) new /obj/item/stack/rods(loc, MEATSPIKE_IRONROD_REQUIREMENT) - qdel(src) #undef MEATSPIKE_IRONROD_REQUIREMENT diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 72f28ed82517a..6d65705586a6a 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -57,10 +57,8 @@ var/turf/T = get_turf(src) return T.attackby(C, user) //hand this off to the turf instead (for building plating, catwalks, etc) -/obj/structure/lattice/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new build_material(get_turf(src), number_of_mats) - qdel(src) +/obj/structure/lattice/atom_deconstruct(disassembled = TRUE) + new build_material(get_turf(src), number_of_mats) /obj/structure/lattice/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_TURF) @@ -113,11 +111,10 @@ C.deconstruct() ..() -/obj/structure/lattice/catwalk/deconstruct() +/obj/structure/lattice/catwalk/atom_deconstruct(disassembled = TRUE) var/turf/T = loc for(var/obj/structure/cable/C in T) C.deconstruct() - ..() /obj/structure/lattice/catwalk/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index ed6602cb5137a..7ef40423e0d44 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -167,14 +167,12 @@ playsound(src, 'sound/machines/click.ogg', 10, TRUE) -/obj/item/plunger/AltClick(mob/user) - if(!istype(user) || !user.can_perform_action(src)) - return - +/obj/item/plunger/click_alt(mob/user) var/new_layer = tgui_input_list(user, "Select a layer", "Layer", GLOB.plumbing_layers) - if(isnull(new_layer)) - return + if(isnull(new_layer) || !user.can_perform_action(src)) + return CLICK_ACTION_BLOCKING target_layer = GLOB.plumbing_layers[new_layer] + return CLICK_ACTION_SUCCESS ///A faster reinforced plunger /obj/item/plunger/reinforced diff --git a/code/game/objects/structures/lavaland/gulag_vent.dm b/code/game/objects/structures/lavaland/gulag_vent.dm new file mode 100644 index 0000000000000..b564908cdc6c1 --- /dev/null +++ b/code/game/objects/structures/lavaland/gulag_vent.dm @@ -0,0 +1,43 @@ +/** + * A boulder-spawning structure superficially similar to an ore vent which doesnt share any of its behaviour + * Prisoners can haul boulders up out of it in case the actual mining area is totally spent + */ +/obj/structure/gulag_vent + name = "work pit" + desc = "A timeworn shaft, almost totally mined out. With a bit of effort you might be able to haul something up." + icon = 'icons/obj/mining_zones/terrain.dmi' + icon_state = "ore_vent_active" + move_resist = MOVE_FORCE_EXTREMELY_STRONG + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF //This thing will take a beating. + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_REQUIRES_DEXTERITY + anchored = TRUE + density = TRUE + /// What kind of rock we got in there? + var/spawned_boulder = /obj/item/boulder/gulag + /// Prevents multiple people from hauling at a time + var/occupied = FALSE + +/obj/structure/gulag_vent/ice + icon_state = "ore_vent_ice_active" + +/obj/structure/gulag_vent/interact(mob/user) + . = ..() + if (!isliving(user)) + return + if (occupied) + balloon_alert(user, "occupied!") + return + var/mob/living/living_user = user + occupied = TRUE + living_user.balloon_alert_to_viewers("hauling...") + var/succeeded = do_after(living_user, 8 SECONDS, src) + occupied = FALSE + if (!succeeded) + return + var/stamina_damage_to_inflict = HAS_TRAIT(user, TRAIT_STRENGTH) ? 60 : 120 //Decreases the amount of stamina damage inflicted by half if you're STRONG + living_user.mind?.adjust_experience(/datum/skill/athletics, 10) + living_user.apply_status_effect(/datum/status_effect/exercised) + new spawned_boulder(get_turf(living_user)) + living_user.visible_message(span_notice("[living_user] hauls a boulder out of [src].")) + living_user.apply_damage(stamina_damage_to_inflict, STAMINA) + playsound(src, 'sound/weapons/genhit.ogg', vol = 50, vary = TRUE) diff --git a/code/game/objects/structures/lavaland/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm index 6d6b2e6af37af..58308b9b9cf2b 100644 --- a/code/game/objects/structures/lavaland/necropolis_tendril.dm +++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm @@ -42,9 +42,8 @@ GLOBAL_LIST_INIT(tendrils, list()) AddComponent(/datum/component/gps, "Eerie Signal") GLOB.tendrils += src -/obj/structure/spawner/lavaland/deconstruct(disassembled) +/obj/structure/spawner/lavaland/atom_deconstruct(disassembled) new /obj/effect/collapse(loc) - return ..() /obj/structure/spawner/lavaland/examine(mob/user) var/list/examine_messages = ..() @@ -92,7 +91,7 @@ GLOBAL_LIST_INIT(tendrils, list()) visible_message(span_boldannounce("The tendril writhes in fury as the earth around it begins to crack and break apart! Get back!")) balloon_alert_to_viewers("interact to grab loot before collapse!", vision_distance = 7) playsound(loc,'sound/effects/tendril_destroyed.ogg', 200, FALSE, 50, TRUE, TRUE) - addtimer(CALLBACK(src, PROC_REF(collapse)), 50) + addtimer(CALLBACK(src, PROC_REF(collapse)), 5 SECONDS) /obj/effect/collapse/examine(mob/user) var/list/examine_messages = ..() diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm index 70ab15427b759..c8961a5769ccf 100644 --- a/code/game/objects/structures/lavaland/ore_vent.dm +++ b/code/game/objects/structures/lavaland/ore_vent.dm @@ -261,6 +261,8 @@ * Also gives xp and mining points to all nearby miners in equal measure. */ /obj/structure/ore_vent/proc/handle_wave_conclusion() + SIGNAL_HANDLER + SEND_SIGNAL(src, COMSIG_VENT_WAVE_CONCLUDED) COOLDOWN_RESET(src, wave_cooldown) particles = null @@ -270,11 +272,13 @@ balloon_alert_to_viewers("vent tapped!") icon_state = icon_state_tapped update_appearance(UPDATE_ICON_STATE) + qdel(GetComponent(/datum/component/gps)) else visible_message(span_danger("\the [src] creaks and groans as the mining attempt fails, and the vent closes back up.")) icon_state = initial(icon_state) update_appearance(UPDATE_ICON_STATE) - return FALSE //Bad end, try again. + node = null + return //Bad end, try again. for(var/mob/living/miner in range(7, src)) //Give the miners who are near the vent points and xp. var/obj/item/card/id/user_id_card = miner.get_idcard(TRUE) @@ -283,9 +287,11 @@ if(!user_id_card) continue var/point_reward_val = (MINER_POINT_MULTIPLIER * boulder_size) - MINER_POINT_MULTIPLIER // We remove the base value of discovering the vent - user_id_card.registered_account.mining_points += point_reward_val - user_id_card.registered_account.bank_card_talk("You have been awarded [point_reward_val] mining points for your efforts.") + if(user_id_card.registered_account) + user_id_card.registered_account.mining_points += point_reward_val + user_id_card.registered_account.bank_card_talk("You have been awarded [point_reward_val] mining points for your efforts.") node.pre_escape() //Visually show the drone is done and flies away. + node = null add_overlay(mutable_appearance('icons/obj/mining_zones/terrain.dmi', "well", ABOVE_MOB_LAYER)) /** @@ -308,6 +314,7 @@ discovered = TRUE generate_description(user) balloon_alert_to_viewers("vent scanned!") + AddComponent(/datum/component/gps, name) return if(DOING_INTERACTION_WITH_TARGET(user, src)) @@ -321,11 +328,13 @@ discovered = TRUE balloon_alert(user, "vent scanned!") generate_description(user) + AddComponent(/datum/component/gps, name) var/obj/item/card/id/user_id_card = user.get_idcard(TRUE) if(isnull(user_id_card)) return - user_id_card.registered_account.mining_points += (MINER_POINT_MULTIPLIER) - user_id_card.registered_account.bank_card_talk("You've been awarded [MINER_POINT_MULTIPLIER] mining points for discovery of an ore vent.") + if(user_id_card.registered_account) + user_id_card.registered_account.mining_points += (MINER_POINT_MULTIPLIER) + user_id_card.registered_account.bank_card_talk("You've been awarded [MINER_POINT_MULTIPLIER] mining points for discovery of an ore vent.") return if(scan_only) return diff --git a/code/game/objects/structures/maintenance.dm b/code/game/objects/structures/maintenance.dm index f9ed6d93c1e9f..ecd6f54d2557a 100644 --- a/code/game/objects/structures/maintenance.dm +++ b/code/game/objects/structures/maintenance.dm @@ -303,11 +303,9 @@ at the cost of risking a vicious bite.**/ deconstruct() return TRUE -/obj/structure/steam_vent/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 1) - new /obj/item/stock_parts/water_recycler(loc, 1) - qdel(src) +/obj/structure/steam_vent/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 1) + new /obj/item/stock_parts/water_recycler(loc, 1) /** * Creates "steam" smoke, and determines when the vent needs to block line of sight via reset_opacity. diff --git a/code/game/objects/structures/mannequin.dm b/code/game/objects/structures/mannequin.dm index bdb5344d7fe10..a47802273d5a0 100644 --- a/code/game/objects/structures/mannequin.dm +++ b/code/game/objects/structures/mannequin.dm @@ -95,19 +95,19 @@ var/mutable_appearance/pedestal = mutable_appearance(icon, "pedestal_[material]") pedestal.pixel_y = -3 . += pedestal - var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[underwear_name] + var/datum/sprite_accessory/underwear/underwear = SSaccessories.underwear_list[underwear_name] if(underwear) if(body_type == FEMALE && underwear.gender == MALE) . += wear_female_version(underwear.icon_state, underwear.icon, BODY_LAYER, FEMALE_UNIFORM_FULL) else . += mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) - var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[undershirt_name] + var/datum/sprite_accessory/undershirt/undershirt = SSaccessories.undershirt_list[undershirt_name] if(undershirt) if(body_type == FEMALE) . += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) else . += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) - var/datum/sprite_accessory/socks/socks = GLOB.socks_list[socks_name] + var/datum/sprite_accessory/socks/socks = SSaccessories.socks_list[socks_name] if(socks) . += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) for(var/slot_flag in worn_items) @@ -168,15 +168,15 @@ return switch(choice) if("Underwear") - var/new_undies = tgui_input_list(user, "Select the mannequin's underwear", "Changing", GLOB.underwear_list) + var/new_undies = tgui_input_list(user, "Select the mannequin's underwear", "Changing", SSaccessories.underwear_list) if(new_undies) underwear_name = new_undies if("Undershirt") - var/new_undershirt = tgui_input_list(user, "Select the mannequin's undershirt", "Changing", GLOB.undershirt_list) + var/new_undershirt = tgui_input_list(user, "Select the mannequin's undershirt", "Changing", SSaccessories.undershirt_list) if(new_undershirt) undershirt_name = new_undershirt if("Socks") - var/new_socks = tgui_input_list(user, "Select the mannequin's socks", "Changing", GLOB.socks_list) + var/new_socks = tgui_input_list(user, "Select the mannequin's socks", "Changing", SSaccessories.socks_list) if(new_socks) socks_name = new_socks update_appearance() diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 03e37346c5714..d794f24dd0894 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -204,14 +204,12 @@ /////////////////////// END TOOL OVERRIDES /////////////////////// -/obj/structure/mineral_door/deconstruct(disassembled = TRUE) +/obj/structure/mineral_door/atom_deconstruct(disassembled = TRUE) var/turf/T = get_turf(src) if(disassembled) new sheetType(T, sheetAmount) else new sheetType(T, max(sheetAmount - 2, 1)) - qdel(src) - /obj/structure/mineral_door/iron name = "iron door" diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index f796bae34cf4d..7ea2330281413 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -118,7 +118,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) beard_dresser.set_facial_hairstyle("Shaved", update = TRUE) return TRUE - var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) + var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", SSaccessories.facial_hairstyles_list) if(isnull(new_style)) return TRUE @@ -131,7 +131,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) beard_dresser.set_facial_hairstyle(new_style, update = TRUE) /obj/structure/mirror/proc/change_hair(mob/living/carbon/human/hairdresser) - var/new_style = tgui_input_list(hairdresser, "Select a hairstyle", "Grooming", GLOB.hairstyles_list) + var/new_style = tgui_input_list(hairdresser, "Select a hairstyle", "Grooming", SSaccessories.hairstyles_list) if(isnull(new_style)) return TRUE if(HAS_TRAIT(hairdresser, TRAIT_BALD)) @@ -260,7 +260,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) /obj/structure/mirror/atom_break(damage_flag, mapload) . = ..() - if(broken || (obj_flags & NO_DECONSTRUCTION)) + if(broken) return icon_state = "mirror_broke" if(!mapload) @@ -269,13 +269,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) desc = "Oh no, seven years of bad luck!" broken = TRUE -/obj/structure/mirror/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - new /obj/item/shard(loc) - else - new /obj/item/wallframe/mirror(loc) - qdel(src) +/obj/structure/mirror/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + new /obj/item/shard(loc) + else + new /obj/item/wallframe/mirror(loc) /obj/structure/mirror/welder_act(mob/living/user, obj/item/I) ..() @@ -333,7 +331,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) selectable_races = sort_list(selectable_races) /obj/structure/mirror/magic/change_beard(mob/living/carbon/human/beard_dresser) // magical mirrors do nothing but give you the damn beard - var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) + var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", SSaccessories.facial_hairstyles_list) if(isnull(new_style)) return TRUE beard_dresser.set_facial_hairstyle(new_style, update = TRUE) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 05af991303f92..d52a4df28cbc2 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -45,6 +45,8 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an var/locked = FALSE ///Cooldown between breakout msesages. COOLDOWN_DECLARE(breakout_message_cooldown) + /// Cooldown between being able to slide the tray in or out. + COOLDOWN_DECLARE(open_close_cd) /obj/structure/bodycontainer/Initialize(mapload) . = ..() @@ -104,10 +106,8 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an return return attack_hand(user) -/obj/structure/bodycontainer/deconstruct(disassembled = TRUE) - if (!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 5) - qdel(src) +/obj/structure/bodycontainer/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 5) /obj/structure/bodycontainer/container_resist_act(mob/living/user) if(!locked) @@ -133,30 +133,90 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2) /obj/structure/bodycontainer/proc/open() - playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + if(!COOLDOWN_FINISHED(src, open_close_cd)) + return FALSE + + COOLDOWN_START(src, open_close_cd, 0.25 SECONDS) + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) playsound(src, 'sound/effects/roll.ogg', 5, TRUE) - var/turf/T = get_step(src, dir) - if (connected) - connected.setDir(dir) - for(var/atom/movable/AM in src) - AM.forceMove(T) + var/turf/dump_turf = get_step(src, dir) + connected?.setDir(dir) + for(var/atom/movable/moving in src) + moving.forceMove(dump_turf) + animate_slide_out(moving) update_appearance() + return TRUE /obj/structure/bodycontainer/proc/close() + if(!COOLDOWN_FINISHED(src, open_close_cd)) + return FALSE + + COOLDOWN_START(src, open_close_cd, 0.5 SECONDS) playsound(src, 'sound/effects/roll.ogg', 5, TRUE) playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) - for(var/atom/movable/AM in connected.loc) - if(!AM.anchored || AM == connected) - if(isliving(AM)) - var/mob/living/living_mob = AM - if(living_mob.incorporeal_move) - continue - else if(istype(AM, /obj/effect/dummy/phased_mob)) - continue - else if(isdead(AM)) + var/turf/close_loc = connected.loc + for(var/atom/movable/entering in close_loc) + if(entering.anchored && entering != connected) + continue + if(isliving(entering)) + var/mob/living/living_mob = entering + if(living_mob.incorporeal_move) continue - AM.forceMove(src) + else if(istype(entering, /obj/effect/dummy/phased_mob) || isdead(entering)) + continue + animate_slide_in(entering, close_loc) + entering.forceMove(src) update_appearance() + return TRUE + +#define SLIDE_LENGTH (0.3 SECONDS) + +/// Slides the passed object out of the morgue tray. +/obj/structure/bodycontainer/proc/animate_slide_out(atom/movable/animated) + var/old_layer = animated.layer + animated.layer = layer - (animated == connected ? 0.03 : 0.01) + animated.pixel_x = animated.base_pixel_x + (x * 32) - (animated.x * 32) + animated.pixel_y = animated.base_pixel_y + (y * 32) - (animated.y * 32) + animate( + animated, + pixel_x = animated.base_pixel_x, + pixel_y = animated.base_pixel_y, + time = SLIDE_LENGTH, + easing = CUBIC_EASING|EASE_OUT, + flags = ANIMATION_PARALLEL, + ) + addtimer(VARSET_CALLBACK(animated, layer, old_layer), SLIDE_LENGTH) + +/// Slides the passed object into the morgue tray from the passed turf. +/obj/structure/bodycontainer/proc/animate_slide_in(atom/movable/animated, turf/from_loc) + // It's easier to just make a visual for entering than to animate the object itself + var/obj/effect/temp_visual/morgue_content/visual = new(from_loc, animated) + visual.layer = layer - (animated == connected ? 0.03 : 0.01) + animate( + visual, + pixel_x = visual.base_pixel_x + (x * 32) - (visual.x * 32), + pixel_y = visual.base_pixel_y + (y * 32) - (visual.y * 32), + time = SLIDE_LENGTH, + easing = CUBIC_EASING|EASE_IN, + flags = ANIMATION_PARALLEL, + ) + +/// Used to mimic the appearance of an object sliding into a morgue tray. +/obj/effect/temp_visual/morgue_content + duration = SLIDE_LENGTH + +/obj/effect/temp_visual/morgue_content/Initialize(mapload, atom/movable/sliding_in) + . = ..() + if(isnull(sliding_in)) + return + + appearance = sliding_in.appearance + dir = sliding_in.dir + alpha = sliding_in.alpha + base_pixel_x = sliding_in.base_pixel_x + base_pixel_y = sliding_in.base_pixel_y + +#undef SLIDE_LENGTH #define MORGUE_EMPTY 1 #define MORGUE_NO_MOBS 2 @@ -172,6 +232,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an icon_state = "morgue1" base_icon_state = "morgue" dir = EAST + interaction_flags_click = ALLOW_SILICON_REACH|ALLOW_RESTING connected = /obj/structure/tray/m_tray @@ -192,13 +253,11 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an /// Minimum temperature of the internal air mixture var/minimum_temperature = T0C - 60 - /obj/structure/bodycontainer/morgue/Initialize(mapload) ..() return INITIALIZE_HINT_LATELOAD /obj/structure/bodycontainer/morgue/LateInitialize() - . = ..() var/datum/gas_mixture/external_air = loc.return_air() if(external_air) internal_air = external_air.copy() @@ -302,12 +361,10 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an . = ..() . += span_notice("The speaker is [beeper ? "enabled" : "disabled"]. Alt-click to toggle it.") -/obj/structure/bodycontainer/morgue/AltClick(mob/user) - ..() - if(!user.can_perform_action(src, (ALLOW_SILICON_REACH|ALLOW_RESTING))) - return +/obj/structure/bodycontainer/morgue/click_alt(mob/user) beeper = !beeper to_chat(user, span_notice("You turn the speaker function [beeper ? "on" : "off"].")) + return CLICK_ACTION_SUCCESS /obj/structure/bodycontainer/morgue/emag_act(mob/user, obj/item/card/emag/emag_card) if(obj_flags & EMAGGED) @@ -473,9 +530,8 @@ GLOBAL_LIST_EMPTY(crematoriums) connected = null return ..() -/obj/structure/tray/deconstruct(disassembled = TRUE) +/obj/structure/tray/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/iron (loc, 2) - qdel(src) /obj/structure/tray/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) @@ -532,6 +588,7 @@ GLOBAL_LIST_EMPTY(crematoriums) name = "crematorium tray" desc = "Apply body before burning." icon_state = "cremat" + layer = /obj/structure/bodycontainer/crematorium::layer - 0.03 /* * Morgue tray @@ -542,6 +599,7 @@ GLOBAL_LIST_EMPTY(crematoriums) icon = 'icons/obj/structures.dmi' icon_state = "morguet" pass_flags_self = PASSTABLE | LETPASSTHROW + layer = /obj/structure/bodycontainer/morgue::layer - 0.03 /obj/structure/tray/m_tray/CanAllowThrough(atom/movable/mover, border_dir) . = ..() diff --git a/code/game/objects/structures/mystery_box.dm b/code/game/objects/structures/mystery_box.dm index 1843ef99761fd..ab8a25f04c675 100644 --- a/code/game/objects/structures/mystery_box.dm +++ b/code/game/objects/structures/mystery_box.dm @@ -67,6 +67,32 @@ GLOBAL_LIST_INIT(mystery_box_extended, list( /obj/item/circular_saw, )) +GLOBAL_LIST_INIT(mystery_magic, list( + /obj/item/gun/magic/wand/arcane_barrage, + /obj/item/gun/magic/wand/arcane_barrage/blood, + /obj/item/gun/magic/wand/fireball, + /obj/item/gun/magic/wand/resurrection, + /obj/item/gun/magic/wand/death, + /obj/item/gun/magic/wand/polymorph, + /obj/item/gun/magic/wand/teleport, + /obj/item/gun/magic/wand/door, + /obj/item/gun/magic/wand/nothing, + /obj/item/storage/belt/wands/full, + /obj/item/gun/magic/staff/healing, + /obj/item/gun/magic/staff/change, + /obj/item/gun/magic/staff/animate, + /obj/item/gun/magic/staff/chaos, + /obj/item/gun/magic/staff/door, + /obj/item/gun/magic/staff/honk, + /obj/item/gun/magic/staff/spellblade, + /obj/item/gun/magic/staff/locker, + /obj/item/gun/magic/staff/flying, + /obj/item/gun/magic/staff/babel, + /obj/item/singularityhammer, + /obj/item/mod/control/pre_equipped/enchanted, + /obj/item/runic_vendor_scepter, +)) + /obj/structure/mystery_box name = "mystery box" @@ -207,6 +233,12 @@ GLOBAL_LIST_INIT(mystery_box_extended, list( /obj/structure/mystery_box/tdome/generate_valid_types() valid_types = GLOB.mystery_box_guns + GLOB.mystery_box_extended +/obj/structure/mystery_box/wands + desc = "A wooden crate that seems equally magical and mysterious, capable of granting the user all kinds of different magical items." + +/obj/structure/mystery_box/wands/generate_valid_types() + valid_types = GLOB.mystery_magic + /// This represents the item that comes out of the box and is constantly changing before the box finishes deciding. Can probably be just an /atom or /movable. /obj/mystery_box_item diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm index c737f21e6d9e6..841da89972599 100644 --- a/code/game/objects/structures/noticeboard.dm +++ b/code/game/objects/structures/noticeboard.dm @@ -110,15 +110,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/noticeboard, 32) notices-- update_appearance(UPDATE_ICON) -/obj/structure/noticeboard/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - new /obj/item/stack/sheet/mineral/wood(loc) - else - new /obj/item/wallframe/noticeboard(loc) +/obj/structure/noticeboard/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + new /obj/item/stack/sheet/mineral/wood(loc) + else + new /obj/item/wallframe/noticeboard(loc) for(var/obj/item/content in contents) remove_item(content) - qdel(src) /obj/item/wallframe/noticeboard name = "notice board" diff --git a/code/game/objects/structures/petrified_statue.dm b/code/game/objects/structures/petrified_statue.dm index a752faba40c33..5383436d4dbff 100644 --- a/code/game/objects/structures/petrified_statue.dm +++ b/code/game/objects/structures/petrified_statue.dm @@ -73,7 +73,7 @@ petrified_mob.forceMove(loc) return ..() -/obj/structure/statue/petrified/deconstruct(disassembled = TRUE) +/obj/structure/statue/petrified/atom_deconstruct(disassembled = TRUE) var/destruction_message = "[src] shatters!" if(!disassembled) if(petrified_mob) @@ -89,7 +89,6 @@ destruction_message = "[src] shatters, a solid brain tumbling out!" petrified_mob.dust() visible_message(span_danger(destruction_message)) - qdel(src) /obj/structure/statue/petrified/animate_atom_living(mob/living/owner) if(isnull(petrified_mob)) diff --git a/code/game/objects/structures/pinatas.dm b/code/game/objects/structures/pinatas.dm index 116de95c1676a..63502f12ad5e2 100644 --- a/code/game/objects/structures/pinatas.dm +++ b/code/game/objects/structures/pinatas.dm @@ -41,9 +41,8 @@ if(BURN) playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/pinata/deconstruct(disassembled) +/obj/structure/pinata/atom_deconstruct(disassembled) new debris(get_turf(src)) - return ..() ///An item that when used inhand spawns an immovable pinata /obj/item/pinata @@ -72,7 +71,7 @@ base_icon_state = "pinata_syndie_placed" destruction_loot = 2 debris = /obj/effect/decal/cleanable/wrapping/pinata/syndie - candy_options = list( + candy_options = list( /obj/item/food/bubblegum, /obj/item/food/candy, /obj/item/food/chocolatebar, diff --git a/code/game/objects/structures/plaques/_plaques.dm b/code/game/objects/structures/plaques/_plaques.dm index 8b8047ba4641a..4a1684434dcca 100644 --- a/code/game/objects/structures/plaques/_plaques.dm +++ b/code/game/objects/structures/plaques/_plaques.dm @@ -169,7 +169,7 @@ return user.visible_message(span_notice("[user] begins engraving [src]."), \ span_notice("You begin engraving [src].")) - if(!do_after(user, 40, target = src)) //This spits out a visible message that somebody is engraving a plaque, then has a delay. + if(!do_after(user, 4 SECONDS, target = src)) //This spits out a visible message that somebody is engraving a plaque, then has a delay. return name = "\improper [namechoice]" //We want improper here so examine doesn't get weird if somebody capitalizes the plaque title. desc = "The plaque reads: '[descriptionchoice]'" diff --git a/code/game/objects/structures/plaques/static_plaques.dm b/code/game/objects/structures/plaques/static_plaques.dm index 06538ea2ef1f1..642a7ac125e84 100644 --- a/code/game/objects/structures/plaques/static_plaques.dm +++ b/code/game/objects/structures/plaques/static_plaques.dm @@ -35,8 +35,7 @@ . = ..() return INITIALIZE_HINT_LATELOAD -/obj/structure/plaque/static_plaque/tram/LateInitialize(mapload) - . = ..() +/obj/structure/plaque/static_plaque/tram/LateInitialize() link_tram() set_tram_serial() diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index 6dd3eb800a316..a2a1e1c04bc20 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -124,10 +124,8 @@ return FALSE //If you're not laying down, or a small creature, or a ventcrawler, then no pass. -/obj/structure/plasticflaps/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/plastic/five(loc) - qdel(src) +/obj/structure/plasticflaps/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/plastic/five(loc) /obj/structure/plasticflaps/Initialize(mapload) . = ..() diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index 3604bd06c63c8..2651684e39b80 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -88,8 +88,6 @@ to_chat(user, span_warning("[src] is already in good condition!")) return -/obj/structure/railing/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/structure/railing/wirecutter_act(mob/living/user, obj/item/I) . = ..() @@ -98,19 +96,14 @@ deconstruct() return TRUE -/obj/structure/railing/deconstruct(disassembled) - if((obj_flags & NO_DECONSTRUCTION)) - return ..() +/obj/structure/railing/atom_deconstruct(disassembled) var/rods_to_make = istype(src,/obj/structure/railing/corner) ? 1 : 2 var/obj/rod = new item_deconstruct(drop_location(), rods_to_make) transfer_fingerprints_to(rod) - return ..() ///Implements behaviour that makes it possible to unanchor the railing. /obj/structure/railing/wrench_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return to_chat(user, span_notice("You begin to [anchored ? "unfasten the railing from":"fasten the railing to"] the floor...")) if(I.use_tool(src, user, volume = 75, extra_checks = CALLBACK(src, PROC_REF(check_anchored), anchored))) set_anchored(!anchored) diff --git a/code/game/objects/structures/reflector.dm b/code/game/objects/structures/reflector.dm index 0d6799b05835c..0700f19818a39 100644 --- a/code/game/objects/structures/reflector.dm +++ b/code/game/objects/structures/reflector.dm @@ -79,10 +79,10 @@ P.decayedRange = max(P.decayedRange--, 0) return BULLET_ACT_FORCE_PIERCE -/obj/structure/reflector/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/structure/reflector/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(admin && tool.tool_behaviour) return ITEM_INTERACT_BLOCKING - return ..() + return NONE /obj/structure/reflector/screwdriver_act(mob/living/user, obj/item/tool) can_rotate = !can_rotate diff --git a/code/game/objects/structures/secure_safe.dm b/code/game/objects/structures/secure_safe.dm index bc73eea6ec056..76c3ab4575f6c 100644 --- a/code/game/objects/structures/secure_safe.dm +++ b/code/game/objects/structures/secure_safe.dm @@ -45,12 +45,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/secure_safe, 32) if(mapload) PopulateContents() -/obj/structure/secure_safe/deconstruct(disassembled) +/obj/structure/secure_safe/atom_deconstruct(disassembled) if(!density) //if we're a wall item, we'll drop a wall frame. var/obj/item/wallframe/secure_safe/new_safe = new(get_turf(src)) for(var/obj/item in contents) item.forceMove(new_safe) - return ..() /obj/structure/secure_safe/proc/PopulateContents() new /obj/item/paper(src) diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index c71bd3c7e0cdd..350adcb11f1ab 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -184,9 +184,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) /obj/machinery/shower/wrench_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return - I.play_tool_sound(src) deconstruct() return TRUE @@ -369,8 +366,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) deconstruct() return TRUE -/obj/structure/showerframe/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/effect/mist name = "mist" diff --git a/code/game/objects/structures/stairs.dm b/code/game/objects/structures/stairs.dm index 169f76a4b5708..a26354211dc27 100644 --- a/code/game/objects/structures/stairs.dm +++ b/code/game/objects/structures/stairs.dm @@ -209,9 +209,8 @@ deconstruct(TRUE) return TRUE -/obj/structure/stairs_frame/deconstruct(disassembled = TRUE) +/obj/structure/stairs_frame/atom_deconstruct(disassembled = TRUE) new frame_stack(get_turf(src), frame_stack_amount) - qdel(src) /obj/structure/stairs_frame/attackby(obj/item/attacked_by, mob/user, params) if(!isstack(attacked_by)) diff --git a/code/game/objects/structures/syndicate_uplink_beacon.dm b/code/game/objects/structures/syndicate_uplink_beacon.dm index f4d4ea6fe6421..2106fade55a5c 100644 --- a/code/game/objects/structures/syndicate_uplink_beacon.dm +++ b/code/game/objects/structures/syndicate_uplink_beacon.dm @@ -43,7 +43,7 @@ return var/datum/looping_sound/typing/typing_sounds = new(src, start_immediately = TRUE) balloon_alert(user, "synchronizing...") - if(!do_after(user = user, delay = 3 SECONDS, target = src, interaction_key = REF(src))) + if(!do_after(user = user, delay = 3 SECONDS, target = src, interaction_key = REF(src), hidden = TRUE)) typing_sounds.stop() return typing_sounds.stop() @@ -52,7 +52,7 @@ /obj/structure/syndicate_uplink_beacon/screwdriver_act_secondary(mob/living/user, obj/item/tool) tool.play_tool_sound(src) balloon_alert(user, "deconstructing...") - if (!do_after(user, 5 SECONDS, target = src)) + if (!do_after(user, 5 SECONDS, target = src, hidden = TRUE)) return FALSE var/turf/beacon_tile = get_turf(src) new /obj/item/stack/sheet/iron/five(beacon_tile) diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm index ba654d10b912c..cb45eb18e75eb 100644 --- a/code/game/objects/structures/table_frames.dm +++ b/code/game/objects/structures/table_frames.dm @@ -75,9 +75,8 @@ T.set_custom_materials(custom_materials) qdel(src) -/obj/structure/table_frame/deconstruct(disassembled = TRUE) +/obj/structure/table_frame/atom_deconstruct(disassembled = TRUE) new framestack(get_turf(src), framestackamount) - qdel(src) /obj/structure/table_frame/narsie_act() new /obj/structure/table_frame/wood(src.loc) @@ -110,7 +109,7 @@ to_chat(user, span_warning("You need one [material.name] sheet to do this!")) return to_chat(user, span_notice("You start adding [material] to [src]...")) - if(do_after(user, 20, target = src) && material.use(1)) + if(do_after(user, 2 SECONDS, target = src) && material.use(1)) make_new_table(toConstruct, null, carpet_type) else return ..() diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 997d23c413962..a44364a3b4c09 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -73,7 +73,7 @@ context[SCREENTIP_CONTEXT_RMB] = "Deal card faceup" . = CONTEXTUAL_SCREENTIP_SET - if(!(obj_flags & NO_DECONSTRUCTION) && deconstruction_ready) + if(deconstruction_ready) if(held_item.tool_behaviour == TOOL_SCREWDRIVER) context[SCREENTIP_CONTEXT_RMB] = "Disassemble" . = CONTEXTUAL_SCREENTIP_SET @@ -207,7 +207,7 @@ pushed_mob.add_mood_event("table", /datum/mood_event/table_limbsmash, banged_limb) /obj/structure/table/screwdriver_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION || !deconstruction_ready) + if(!deconstruction_ready) return FALSE to_chat(user, span_notice("You start disassembling [src]...")) if(tool.use_tool(src, user, 2 SECONDS, volume=50)) @@ -215,12 +215,13 @@ return ITEM_INTERACT_SUCCESS /obj/structure/table/wrench_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION || !deconstruction_ready) + if(!deconstruction_ready) return FALSE to_chat(user, span_notice("You start deconstructing [src]...")) if(tool.use_tool(src, user, 4 SECONDS, volume=50)) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) - deconstruct(TRUE, 1) + frame = null + deconstruct(TRUE) return ITEM_INTERACT_SUCCESS /obj/structure/table/attackby(obj/item/I, mob/living/user, params) @@ -297,20 +298,18 @@ /obj/structure/table/proc/AfterPutItemOnTable(obj/item/thing, mob/living/user) return -/obj/structure/table/deconstruct(disassembled = TRUE, wrench_disassembly = 0) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - if(buildstack) - new buildstack(T, buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(T, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - if(!wrench_disassembly) - new frame(T) - else - new framestack(T, framestackamount) - qdel(src) +/obj/structure/table/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + if(buildstack) + new buildstack(target_turf, buildstackamount) + else + for(var/datum/material/mat in custom_materials) + new mat.sheet_type(target_turf, FLOOR(custom_materials[mat] / SHEET_MATERIAL_AMOUNT, 1)) + + if(frame) + new frame(target_turf) + else + new framestack(get_turf(src), framestackamount) /obj/structure/table/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) @@ -437,13 +436,12 @@ /obj/structure/table/glass/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER - if(obj_flags & NO_DECONSTRUCTION) - return + if(!isliving(AM)) return // Don't break if they're just flying past if(AM.throwing) - addtimer(CALLBACK(src, PROC_REF(throw_check), AM), 5) + addtimer(CALLBACK(src, PROC_REF(throw_check), AM), 0.5 SECONDS) else check_break(AM) @@ -469,19 +467,16 @@ victim.Paralyze(100) qdel(src) -/obj/structure/table/glass/deconstruct(disassembled = TRUE, wrench_disassembly = 0) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - ..() - return - else - var/turf/T = get_turf(src) - playsound(T, SFX_SHATTER, 50, TRUE) - - new frame(loc) - new glass_shard_type(loc) +/obj/structure/table/glass/atom_deconstruct(disassembled = TRUE) + if(disassembled) + ..() + return + else + var/turf/T = get_turf(src) + playsound(T, SFX_SHATTER, 50, TRUE) - qdel(src) + new frame(loc) + new glass_shard_type(loc) /obj/structure/table/glass/narsie_act() color = NARSIE_WINDOW_COLOUR @@ -841,10 +836,9 @@ if(isnull(held_item)) return NONE - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item.tool_behaviour == TOOL_WRENCH) - context[SCREENTIP_CONTEXT_RMB] = "Deconstruct" - return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_RMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET return NONE @@ -860,18 +854,16 @@ return TRUE /obj/structure/rack/wrench_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return NONE tool.play_tool_sound(src) deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/structure/rack/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - . = ..() - if(. || (tool.item_flags & ABSTRACT) || user.combat_mode) - return . +/obj/structure/rack/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if((tool.item_flags & ABSTRACT) || user.combat_mode) + return NONE if(user.transferItemToLoc(tool, drop_location(), silent = FALSE)) return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING /obj/structure/rack/attack_paw(mob/living/user, list/modifiers) attack_hand(user, modifiers) @@ -901,12 +893,10 @@ * Rack destruction */ -/obj/structure/rack/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - set_density(FALSE) - var/obj/item/rack_parts/newparts = new(loc) - transfer_fingerprints_to(newparts) - qdel(src) +/obj/structure/rack/atom_deconstruct(disassembled = TRUE) + set_density(FALSE) + var/obj/item/rack_parts/newparts = new(loc) + transfer_fingerprints_to(newparts) /* @@ -935,31 +925,26 @@ context[SCREENTIP_CONTEXT_LMB] = "Construct Rack" return CONTEXTUAL_SCREENTIP_SET - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item.tool_behaviour == TOOL_WRENCH) - context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" - return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET return NONE /obj/item/rack_parts/wrench_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return NONE tool.play_tool_sound(src) deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/item/rack_parts/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(drop_location()) - return ..() +/obj/item/rack_parts/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(drop_location()) /obj/item/rack_parts/attack_self(mob/user) if(building) return building = TRUE to_chat(user, span_notice("You start constructing a rack...")) - if(do_after(user, 50, target = user, progress=TRUE)) + if(do_after(user, 5 SECONDS, target = user, progress=TRUE)) if(!user.temporarilyRemoveItemFromInventory(src)) return var/obj/structure/rack/R = new /obj/structure/rack(get_turf(src)) diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index ec00eb110a7af..2c0b3bdc95bbd 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -103,13 +103,11 @@ return TRUE -/obj/structure/tank_dispenser/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/X in src) - var/obj/item/I = X - I.forceMove(loc) - new /obj/item/stack/sheet/iron (loc, 2) - qdel(src) +/obj/structure/tank_dispenser/atom_deconstruct(disassembled = TRUE) + for(var/X in src) + var/obj/item/I = X + I.forceMove(loc) + new /obj/item/stack/sheet/iron (loc, 2) /obj/structure/tank_dispenser/proc/dispense(tank_type, mob/receiver) var/existing_tank = locate(tank_type) in src diff --git a/code/game/objects/structures/tank_holder.dm b/code/game/objects/structures/tank_holder.dm index 5b7c9d2ed5534..34284b1f1dd0d 100644 --- a/code/game/objects/structures/tank_holder.dm +++ b/code/game/objects/structures/tank_holder.dm @@ -63,12 +63,11 @@ deconstruct(TRUE) return TRUE -/obj/structure/tank_holder/deconstruct(disassembled = TRUE) +/obj/structure/tank_holder/atom_deconstruct(disassembled = TRUE) var/atom/Tsec = drop_location() new /obj/item/stack/rods(Tsec, 2) if(tank) tank.forceMove(Tsec) - qdel(src) /obj/structure/tank_holder/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) diff --git a/code/game/objects/structures/training_machine.dm b/code/game/objects/structures/training_machine.dm index fd0d8bb0c8f0c..c2f4d3a18ae1b 100644 --- a/code/game/objects/structures/training_machine.dm +++ b/code/game/objects/structures/training_machine.dm @@ -20,6 +20,7 @@ can_buckle = TRUE buckle_lying = 0 max_integrity = 200 + interaction_flags_click = NEED_DEXTERITY|FORBID_TELEKINESIS_REACH|ALLOW_RESTING ///Is the machine moving? Setting this to FALSE will automatically call stop_moving() var/moving = FALSE ///The distance the machine is allowed to roam from its starting point @@ -174,21 +175,19 @@ attached_item.throw_at(destination, 4, 1) on_attached_delete() -/obj/structure/training_machine/AltClick(mob/user) - . = ..() - if(!user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH|ALLOW_RESTING)) - return +/obj/structure/training_machine/click_alt(mob/user) if(has_buckled_mobs()) user_unbuckle_mob(buckled_mobs[1], user) - return + return CLICK_ACTION_SUCCESS if (!attached_item) - return + return NONE if (obj_flags & EMAGGED) to_chat(user, span_warning("The toolbox is somehow stuck on! It won't budge!")) - return + return CLICK_ACTION_BLOCKING to_chat(user, span_notice("You remove \the [attached_item] from the training device.")) remove_attached_item(user) playsound(src, SFX_RUSTLE, 50, TRUE) + return CLICK_ACTION_SUCCESS /** * Toggle the machine's movement @@ -396,12 +395,10 @@ if (!.) check_hit(hit_atom) -/obj/item/training_toolbox/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return +/obj/item/training_toolbox/click_alt(mob/user) to_chat(user, span_notice("You push the 'Lap' button on the toolbox's display.")) lap_hits = initial(lap_hits) + return CLICK_ACTION_SUCCESS /obj/item/training_toolbox/examine(mob/user) . = ..() diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm index b04d9803569d1..3eeb81cb8aca5 100644 --- a/code/game/objects/structures/transit_tubes/station.dm +++ b/code/game/objects/structures/transit_tubes/station.dm @@ -73,7 +73,7 @@ return for(var/obj/structure/transit_tube_pod/pod in loc) pod.visible_message(span_warning("[user] starts putting [GM] into the [pod]!")) - if(do_after(user, 15, target = src)) + if(do_after(user, 1.5 SECONDS, target = src)) if(open_status == STATION_TUBE_OPEN && GM && user.grab_state >= GRAB_AGGRESSIVE && user.pulling == GM && !GM.buckled && !GM.has_buckled_mobs()) GM.Paralyze(100) src.Bumped(GM) @@ -87,7 +87,7 @@ else if(open_status == STATION_TUBE_OPEN) if(pod.contents.len && user.loc != pod) user.visible_message(span_notice("[user] starts emptying [pod]'s contents onto the floor."), span_notice("You start emptying [pod]'s contents onto the floor...")) - if(do_after(user, 10, target = src)) //So it doesn't default to close_animation() on fail + if(do_after(user, 1 SECONDS, target = src)) //So it doesn't default to close_animation() on fail if(pod && pod.loc == loc) for(var/atom/movable/AM in pod) AM.forceMove(get_turf(user)) @@ -153,7 +153,7 @@ /obj/structure/transit_tube/station/pod_stopped(obj/structure/transit_tube_pod/pod, from_dir) pod_moving = TRUE - addtimer(CALLBACK(src, PROC_REF(start_stopped), pod), 5) + addtimer(CALLBACK(src, PROC_REF(start_stopped), pod), 0.5 SECONDS) /obj/structure/transit_tube/station/proc/start_stopped(obj/structure/transit_tube_pod/pod) if(QDELETED(pod)) diff --git a/code/game/objects/structures/transit_tubes/transit_tube_construction.dm b/code/game/objects/structures/transit_tubes/transit_tube_construction.dm index 44952801ec7d3..e6b0f30225cba 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_construction.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_construction.dm @@ -51,8 +51,6 @@ qdel(src) return TRUE -/obj/structure/c_transit_tube/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation // transit tube station /obj/structure/c_transit_tube/station diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index 67d3d4c9510fa..f88aadc04631f 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -35,22 +35,16 @@ user.visible_message(span_notice("[user] empties \the [src]."), span_notice("You empty \the [src].")) empty_pod() else - deconstruct(TRUE, user) + deconstruct(TRUE) else return ..() -/obj/structure/transit_tube_pod/deconstruct(disassembled = TRUE, mob/user) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/location = get_turf(src) - if(user) - location = user.loc - add_fingerprint(user) - user.visible_message(span_notice("[user] removes [src]."), span_notice("You remove [src].")) - var/obj/structure/c_transit_tube_pod/R = new/obj/structure/c_transit_tube_pod(location) - transfer_fingerprints_to(R) - R.setDir(dir) - empty_pod(location) - qdel(src) +/obj/structure/transit_tube_pod/atom_deconstruct(disassembled = TRUE) + var/atom/location = get_turf(src) + var/obj/structure/c_transit_tube_pod/tube_pod = new/obj/structure/c_transit_tube_pod(location) + transfer_fingerprints_to(tube_pod) + tube_pod.setDir(dir) + empty_pod(location) /obj/structure/transit_tube_pod/ex_act(severity, target) . = ..() @@ -100,7 +94,7 @@ moving = TRUE current_tube = tube - var/datum/move_loop/engine = SSmove_manager.force_move_dir(src, dir, 0, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/engine = GLOB.move_manager.force_move_dir(src, dir, 0, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) RegisterSignal(engine, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(before_pipe_transfer)) RegisterSignal(engine, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(after_pipe_transfer)) RegisterSignal(engine, COMSIG_QDELETING, PROC_REF(engine_finish)) diff --git a/code/game/objects/structures/traps.dm b/code/game/objects/structures/traps.dm index 1b6f1da06b6ea..d4bab223d4570 100644 --- a/code/game/objects/structures/traps.dm +++ b/code/game/objects/structures/traps.dm @@ -200,6 +200,8 @@ icon_state = "trap-frost" /obj/structure/trap/chill/trap_effect(mob/living/victim) + if(HAS_TRAIT(victim, TRAIT_RESISTCOLD)) + return to_chat(victim, span_bolddanger("You're frozen solid!")) victim.Paralyze(2 SECONDS) victim.adjust_bodytemperature(-300) diff --git a/code/game/objects/structures/votingbox.dm b/code/game/objects/structures/votingbox.dm index 00eeeb55ae298..42ccd62509304 100644 --- a/code/game/objects/structures/votingbox.dm +++ b/code/game/objects/structures/votingbox.dm @@ -149,9 +149,8 @@ for(var/atom/movable/AM in contents) AM.forceMove(droppoint) -/obj/structure/votebox/deconstruct(disassembled) +/obj/structure/votebox/atom_deconstruct(disassembled) dump_contents() - . = ..() /obj/structure/votebox/proc/raffle(mob/user) var/list/options = list() diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index eac58d119a8b9..51d85d4583d9c 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -83,17 +83,15 @@ icon_state = "toilet[open][cistern]" return ..() -/obj/structure/toilet/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/obj/toilet_item in contents) - toilet_item.forceMove(drop_location()) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - ..() +/obj/structure/toilet/atom_deconstruct(dissambled = TRUE) + for(var/obj/toilet_item in contents) + toilet_item.forceMove(drop_location()) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) + else + for(var/i in custom_materials) + var/datum/material/M = i + new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/toilet/attackby(obj/item/I, mob/living/user, params) add_fingerprint(user) @@ -105,7 +103,7 @@ cistern = !cistern update_appearance() return COMPONENT_CANCEL_ATTACK_CHAIN - else if(I.tool_behaviour == TOOL_WRENCH && !(obj_flags & NO_DECONSTRUCTION)) + else if(I.tool_behaviour == TOOL_WRENCH) I.play_tool_sound(src) deconstruct() return TRUE @@ -227,10 +225,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32) exposed = !exposed return TRUE -/obj/structure/urinal/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/wallframe/urinal(loc) - qdel(src) +/obj/structure/urinal/atom_deconstruct(disassembled = TRUE) + new /obj/item/wallframe/urinal(loc) /obj/item/wallframe/urinal name = "urinal frame" @@ -256,7 +252,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32) /obj/item/food/urinalcake/attack_self(mob/living/user) user.visible_message(span_notice("[user] squishes [src]!"), span_notice("You squish [src]."), "You hear a squish.") icon_state = "urinalcake_squish" - addtimer(VARSET_CALLBACK(src, icon_state, "urinalcake"), 8) + addtimer(VARSET_CALLBACK(src, icon_state, "urinalcake"), 0.8 SECONDS) /obj/item/bikehorn/rubberducky/plasticducky name = "plastic ducky" @@ -349,7 +345,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) if(busy) to_chat(user, span_warning("Someone's already washing here!")) return - var/selected_area = parse_zone(user.zone_selected) + var/selected_area = user.parse_zone_with_bodypart(user.zone_selected) var/washing_face = 0 if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES)) washing_face = 1 @@ -357,7 +353,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) span_notice("You start washing your [washing_face ? "face" : "hands"]...")) busy = TRUE - if(!do_after(user, 40, target = src)) + if(!do_after(user, 4 SECONDS, target = src)) busy = FALSE return @@ -419,7 +415,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) return - if(O.tool_behaviour == TOOL_WRENCH && !(obj_flags & NO_DECONSTRUCTION)) + if(O.tool_behaviour == TOOL_WRENCH) O.play_tool_sound(src) deconstruct() return @@ -483,7 +479,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) if(!user.combat_mode) to_chat(user, span_notice("You start washing [O]...")) busy = TRUE - if(!do_after(user, 40, target = src)) + if(!do_after(user, 4 SECONDS, target = src)) busy = FALSE return 1 busy = FALSE @@ -495,12 +491,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) else return ..() -/obj/structure/sink/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - drop_materials() - if(has_water_reclaimer) - new /obj/item/stock_parts/water_recycler(drop_location()) - ..() +/obj/structure/sink/atom_deconstruct(dissambled = TRUE) + drop_materials() + if(has_water_reclaimer) + new /obj/item/stock_parts/water_recycler(drop_location()) /obj/structure/sink/process(seconds_per_tick) // Water reclamation complete? @@ -571,10 +565,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) deconstruct() return TRUE -/obj/structure/sinkframe/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - drop_materials() - return ..() +/obj/structure/sinkframe/atom_deconstruct(dissambled = TRUE) + drop_materials() /obj/structure/sinkframe/proc/drop_materials() for(var/datum/material/material as anything in custom_materials) @@ -609,7 +601,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) if(busy) to_chat(user, span_warning("Someone's already washing here!")) return - var/selected_area = parse_zone(user.zone_selected) + var/selected_area = user.parse_zone_with_bodypart(user.zone_selected) var/washing_face = FALSE if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES)) washing_face = TRUE @@ -725,9 +717,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) . = ..() icon_state = "puddle" -/obj/structure/water_source/puddle/deconstruct(disassembled = TRUE) - qdel(src) - //End legacy sink @@ -804,11 +793,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) playsound(loc, 'sound/effects/curtain.ogg', 50, TRUE) toggle() -/obj/structure/curtain/deconstruct(disassembled = TRUE) +/obj/structure/curtain/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/cloth (loc, 2) new /obj/item/stack/sheet/plastic (loc, 2) new /obj/item/stack/rods (loc, 1) - qdel(src) /obj/structure/curtain/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) switch(damage_type) @@ -840,10 +828,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) alpha = 255 opaque_closed = TRUE -/obj/structure/curtain/cloth/deconstruct(disassembled = TRUE) +/obj/structure/curtain/cloth/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/cloth (loc, 4) new /obj/item/stack/rods (loc, 1) - qdel(src) /obj/structure/curtain/cloth/fancy icon_type = "cur_fancy" diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 46eb13ee2b7c1..3437e2a5ae078 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -178,7 +178,7 @@ else if(istype(W, /obj/item/stack/cable_coil) && anchored) user.visible_message(span_notice("[user] wires the windoor assembly."), span_notice("You start to wire the windoor assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(!src || !anchored || src.state != "01") return var/obj/item/stack/cable_coil/CC = W @@ -220,7 +220,7 @@ user.visible_message(span_notice("[user] installs the electronics into the airlock assembly."), span_notice("You start to install electronics into the airlock assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(!src || electronics) W.forceMove(drop_location()) return @@ -327,8 +327,6 @@ qdel(src) -/obj/structure/windoor_assembly/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation //Flips the windoor assembly, determines whather the door opens to the left or the right /obj/structure/windoor_assembly/verb/flip() diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 730735b8b3a22..5ddac3f5a5245 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -78,8 +78,6 @@ /obj/structure/window/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return switch(state) if(WINDOW_SCREWED_TO_FRAME) @@ -190,11 +188,11 @@ return return ..() -/obj/structure/window/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/structure/window/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(!can_be_reached(user)) return ITEM_INTERACT_SKIP_TO_ATTACK // Guess you get to hit it add_fingerprint(user) - return ..() + return NONE /obj/structure/window/welder_act(mob/living/user, obj/item/tool) if(atom_integrity >= max_integrity) @@ -210,8 +208,6 @@ return ITEM_INTERACT_SUCCESS /obj/structure/window/screwdriver_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return switch(state) if(WINDOW_SCREWED_TO_FRAME) @@ -240,7 +236,7 @@ /obj/structure/window/wrench_act(mob/living/user, obj/item/tool) if(anchored) return FALSE - if((obj_flags & NO_DECONSTRUCTION) || (reinf && state >= RWINDOW_FRAME_BOLTED)) + if(reinf && state >= RWINDOW_FRAME_BOLTED) return FALSE to_chat(user, span_notice("You begin to disassemble [src]...")) @@ -255,7 +251,7 @@ return ITEM_INTERACT_SUCCESS /obj/structure/window/crowbar_act(mob/living/user, obj/item/tool) - if(!anchored || (obj_flags & NO_DECONSTRUCTION)) + if(!anchored) return FALSE switch(state) @@ -281,8 +277,6 @@ add_fingerprint(user) return ..() -/obj/structure/window/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/structure/window/set_anchored(anchorvalue) ..() @@ -330,18 +324,13 @@ playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/window/deconstruct(disassembled = TRUE) - if(QDELETED(src)) - return +/obj/structure/window/atom_deconstruct(disassembled = TRUE) if(!disassembled) playsound(src, break_sound, 70, TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/obj/item/shard/debris in spawn_debris(drop_location())) - transfer_fingerprints_to(debris) // transfer fingerprints to shards only - qdel(src) + for(var/obj/item/shard/debris in spawn_debris(drop_location())) + transfer_fingerprints_to(debris) // transfer fingerprints to shards only update_nearby_icons() - ///Spawns shard and debris decal based on the glass_material_datum, spawns rods if window is reinforned and number of shards/rods is determined by the window being fulltile or not. /obj/structure/window/proc/spawn_debris(location) var/datum/material/glass_material_ref = GET_MATERIAL_REF(glass_material_datum) @@ -480,9 +469,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) return FALSE /obj/structure/window/reinforced/attackby_secondary(obj/item/tool, mob/user, params) - if(obj_flags & NO_DECONSTRUCTION) - return ..() - switch(state) if(RWINDOW_SECURE) if(tool.tool_behaviour == TOOL_WELDER) @@ -546,7 +532,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) /obj/structure/window/reinforced/crowbar_act(mob/living/user, obj/item/tool) if(!anchored) return FALSE - if((obj_flags & NO_DECONSTRUCTION) || (state != WINDOW_OUT_OF_FRAME)) + if(state != WINDOW_OUT_OF_FRAME) return FALSE to_chat(user, span_notice("You begin to lever the window back into the frame...")) if(tool.use_tool(src, user, 10 SECONDS, volume = 75, extra_checks = CALLBACK(src, PROC_REF(check_state_and_anchored), state, anchored))) @@ -561,8 +547,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) /obj/structure/window/reinforced/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return + switch(state) if(RWINDOW_SECURE) . += span_notice("It's been screwed in with one way screws, you'd need to heat them to have any chance of backing them out.") @@ -715,7 +700,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw /obj/structure/window/reinforced/fulltile name = "full tile reinforced window" - desc = "A full tile reinforced window" + desc = "A full tile window that is reinforced with metal rods." icon = 'icons/obj/smooth_structures/reinforced_window.dmi' icon_state = "reinforced_window-0" base_icon_state = "reinforced_window" @@ -803,12 +788,20 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw /obj/structure/window/reinforced/shuttle/indestructible name = "hardened shuttle window" - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION flags_1 = PREVENT_CLICK_UNDER_1 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF -/obj/structure/window/reinforced/shuttle/indestructible/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - return FALSE +/obj/structure/window/reinforced/shuttle/indestructible/welder_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/window/reinforced/shuttle/indestructible/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/window/reinforced/shuttle/indestructible/wrench_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/window/reinforced/shuttle/indestructible/crowbar_act(mob/living/user, obj/item/tool) + return NONE /obj/structure/window/reinforced/plasma/plastitanium name = "plastitanium window" @@ -915,7 +908,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw return ..() if(istype(W, /obj/item/paper) && atom_integrity < max_integrity) user.visible_message(span_notice("[user] starts to patch the holes in \the [src].")) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) atom_integrity = min(atom_integrity+4,max_integrity) qdel(W) user.visible_message(span_notice("[user] patches some of the holes in \the [src].")) diff --git a/code/game/sound.dm b/code/game/sound.dm index 17275f5f3a63e..6b32eb46e85c9 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -26,17 +26,18 @@ /** * playsound is a proc used to play a 3D sound in a specific range. This uses SOUND_RANGE + extra_range to determine that. * - * source - Origin of sound. - * soundin - Either a file, or a string that can be used to get an SFX. - * vol - The volume of the sound, excluding falloff and pressure affection. - * vary - bool that determines if the sound changes pitch every time it plays. - * extrarange - modifier for sound range. This gets added on top of SOUND_RANGE. - * falloff_exponent - Rate of falloff for the audio. Higher means quicker drop to low volume. Should generally be over 1 to indicate a quick dive to 0 rather than a slow dive. - * frequency - playback speed of audio. - * channel - The channel the sound is played at. - * pressure_affected - Whether or not difference in pressure affects the sound (E.g. if you can hear in space). - * ignore_walls - Whether or not the sound can pass through walls. - * falloff_distance - Distance at which falloff begins. Sound is at peak volume (in regards to falloff) aslong as it is in this range. + * Arguments: + * * source - Origin of sound. + * * soundin - Either a file, or a string that can be used to get an SFX. + * * vol - The volume of the sound, excluding falloff and pressure affection. + * * vary - bool that determines if the sound changes pitch every time it plays. + * * extrarange - modifier for sound range. This gets added on top of SOUND_RANGE. + * * falloff_exponent - Rate of falloff for the audio. Higher means quicker drop to low volume. Should generally be over 1 to indicate a quick dive to 0 rather than a slow dive. + * * frequency - playback speed of audio. + * * channel - The channel the sound is played at. + * * pressure_affected - Whether or not difference in pressure affects the sound (E.g. if you can hear in space). + * * ignore_walls - Whether or not the sound can pass through walls. + * * falloff_distance - Distance at which falloff begins. Sound is at peak volume (in regards to falloff) aslong as it is in this range. */ /proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff_exponent = SOUND_FALLOFF_EXPONENT, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE, falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, use_reverb = TRUE) if(isarea(source)) @@ -82,6 +83,25 @@ listening_mob.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, 1, use_reverb) . += listening_mob +/** + * Plays a sound with a specific point of origin for src mob + * Affected by pressure, distance, terrain and environment (see arguments) + * + * Arguments: + * * turf_source - The turf our sound originates from, if this is not a turf, the sound is played with no spatial audio + * * soundin - Either a file, or a string that can be used to get an SFX. + * * vol - The volume of the sound, excluding falloff and pressure affection. + * * vary - bool that determines if the sound changes pitch every time it plays. + * * frequency - playback speed of audio. + * * falloff_exponent - Rate of falloff for the audio. Higher means quicker drop to low volume. Should generally be over 1 to indicate a quick dive to 0 rather than a slow dive. + * * channel - Optional: The channel the sound is played at. + * * pressure_affected - bool Whether or not difference in pressure affects the sound (E.g. if you can hear in space). + * * sound_to_use - Optional: Will default to soundin when absent + * * max_distance - number, determines the maximum distance of our sound + * * falloff_distance - Distance at which falloff begins. Sound is at peak volume (in regards to falloff) aslong as it is in this range. + * * distance_multiplier - Default 1, multiplies the maximum distance of our sound + * * use_reverb - bool default TRUE, determines if our sound has reverb + */ /mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff_exponent = SOUND_FALLOFF_EXPONENT, channel = 0, pressure_affected = TRUE, sound/sound_to_use, max_distance, falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = 1, use_reverb = TRUE) if(!client || !can_hear()) return @@ -181,253 +201,255 @@ /proc/get_rand_frequency() return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs. +///Used to convert a SFX define into a .ogg so we can add some variance to sounds. If soundin is already a .ogg, we simply return it /proc/get_sfx(soundin) - if(istext(soundin)) - switch(soundin) - if(SFX_SHATTER) - soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') - if(SFX_EXPLOSION) - soundin = pick('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg') - if(SFX_EXPLOSION_CREAKING) - soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg') - if(SFX_HULL_CREAKING) - soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') - if(SFX_SPARKS) - soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg') - if(SFX_RUSTLE) - soundin = pick('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg') - if(SFX_BODYFALL) - soundin = pick('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg') - if(SFX_PUNCH) - soundin = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') - if(SFX_CLOWN_STEP) - soundin = pick('sound/effects/footstep/clownstep1.ogg','sound/effects/footstep/clownstep2.ogg') - if(SFX_SUIT_STEP) - soundin = pick('sound/effects/suitstep1.ogg','sound/effects/suitstep2.ogg') - if(SFX_SWING_HIT) - soundin = pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg') - if(SFX_HISS) - soundin = pick('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg') - if(SFX_PAGE_TURN) - soundin = pick('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg') - if(SFX_RICOCHET) - soundin = pick( 'sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg','sound/weapons/effects/ric3.ogg','sound/weapons/effects/ric4.ogg','sound/weapons/effects/ric5.ogg') - if(SFX_TERMINAL_TYPE) - soundin = pick(list( - 'sound/machines/terminal_button01.ogg', - 'sound/machines/terminal_button02.ogg', - 'sound/machines/terminal_button03.ogg', - 'sound/machines/terminal_button04.ogg', - 'sound/machines/terminal_button05.ogg', - 'sound/machines/terminal_button06.ogg', - 'sound/machines/terminal_button07.ogg', - 'sound/machines/terminal_button08.ogg', - )) - if(SFX_DESECRATION) - soundin = pick('sound/misc/desecration-01.ogg', 'sound/misc/desecration-02.ogg', 'sound/misc/desecration-03.ogg') - if(SFX_IM_HERE) - soundin = pick('sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg') - if(SFX_CAN_OPEN) - soundin = pick('sound/effects/can_open1.ogg', 'sound/effects/can_open2.ogg', 'sound/effects/can_open3.ogg') - if(SFX_BULLET_MISS) - soundin = pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg') - if(SFX_REVOLVER_SPIN) - soundin = pick('sound/weapons/gun/revolver/spin1.ogg', 'sound/weapons/gun/revolver/spin2.ogg', 'sound/weapons/gun/revolver/spin3.ogg') - if(SFX_LAW) - soundin = pick(list( - 'sound/voice/beepsky/creep.ogg', - 'sound/voice/beepsky/god.ogg', - 'sound/voice/beepsky/iamthelaw.ogg', - 'sound/voice/beepsky/insult.ogg', - 'sound/voice/beepsky/radio.ogg', - 'sound/voice/beepsky/secureday.ogg', - )) - if(SFX_HONKBOT_E) - soundin = pick(list( - 'sound/effects/pray.ogg', - 'sound/effects/reee.ogg', - 'sound/items/AirHorn.ogg', - 'sound/items/AirHorn2.ogg', - 'sound/items/bikehorn.ogg', - 'sound/items/WEEOO1.ogg', - 'sound/machines/buzz-sigh.ogg', - 'sound/machines/ping.ogg', - 'sound/magic/Fireball.ogg', - 'sound/misc/sadtrombone.ogg', - 'sound/voice/beepsky/creep.ogg', - 'sound/voice/beepsky/iamthelaw.ogg', - 'sound/voice/hiss1.ogg', - 'sound/weapons/bladeslice.ogg', - 'sound/weapons/flashbang.ogg', - )) - if(SFX_GOOSE) - soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg') - if(SFX_WARPSPEED) - soundin = 'sound/runtime/hyperspace/hyperspace_begin.ogg' - if(SFX_SM_CALM) - soundin = pick(list( - 'sound/machines/sm/accent/normal/1.ogg', - 'sound/machines/sm/accent/normal/2.ogg', - 'sound/machines/sm/accent/normal/3.ogg', - 'sound/machines/sm/accent/normal/4.ogg', - 'sound/machines/sm/accent/normal/5.ogg', - 'sound/machines/sm/accent/normal/6.ogg', - 'sound/machines/sm/accent/normal/7.ogg', - 'sound/machines/sm/accent/normal/8.ogg', - 'sound/machines/sm/accent/normal/9.ogg', - 'sound/machines/sm/accent/normal/10.ogg', - 'sound/machines/sm/accent/normal/11.ogg', - 'sound/machines/sm/accent/normal/12.ogg', - 'sound/machines/sm/accent/normal/13.ogg', - 'sound/machines/sm/accent/normal/14.ogg', - 'sound/machines/sm/accent/normal/15.ogg', - 'sound/machines/sm/accent/normal/16.ogg', - 'sound/machines/sm/accent/normal/17.ogg', - 'sound/machines/sm/accent/normal/18.ogg', - 'sound/machines/sm/accent/normal/19.ogg', - 'sound/machines/sm/accent/normal/20.ogg', - 'sound/machines/sm/accent/normal/21.ogg', - 'sound/machines/sm/accent/normal/22.ogg', - 'sound/machines/sm/accent/normal/23.ogg', - 'sound/machines/sm/accent/normal/24.ogg', - 'sound/machines/sm/accent/normal/25.ogg', - 'sound/machines/sm/accent/normal/26.ogg', - 'sound/machines/sm/accent/normal/27.ogg', - 'sound/machines/sm/accent/normal/28.ogg', - 'sound/machines/sm/accent/normal/29.ogg', - 'sound/machines/sm/accent/normal/30.ogg', - 'sound/machines/sm/accent/normal/31.ogg', - 'sound/machines/sm/accent/normal/32.ogg', - 'sound/machines/sm/accent/normal/33.ogg', - )) - if(SFX_SM_DELAM) - soundin = pick(list( - 'sound/machines/sm/accent/delam/1.ogg', - 'sound/machines/sm/accent/delam/2.ogg', - 'sound/machines/sm/accent/delam/3.ogg', - 'sound/machines/sm/accent/delam/4.ogg', - 'sound/machines/sm/accent/delam/5.ogg', - 'sound/machines/sm/accent/delam/6.ogg', - 'sound/machines/sm/accent/delam/7.ogg', - 'sound/machines/sm/accent/delam/8.ogg', - 'sound/machines/sm/accent/delam/9.ogg', - 'sound/machines/sm/accent/delam/10.ogg', - 'sound/machines/sm/accent/delam/11.ogg', - 'sound/machines/sm/accent/delam/12.ogg', - 'sound/machines/sm/accent/delam/13.ogg', - 'sound/machines/sm/accent/delam/14.ogg', - 'sound/machines/sm/accent/delam/15.ogg', - 'sound/machines/sm/accent/delam/16.ogg', - 'sound/machines/sm/accent/delam/17.ogg', - 'sound/machines/sm/accent/delam/18.ogg', - 'sound/machines/sm/accent/delam/19.ogg', - 'sound/machines/sm/accent/delam/20.ogg', - 'sound/machines/sm/accent/delam/21.ogg', - 'sound/machines/sm/accent/delam/22.ogg', - 'sound/machines/sm/accent/delam/23.ogg', - 'sound/machines/sm/accent/delam/24.ogg', - 'sound/machines/sm/accent/delam/25.ogg', - 'sound/machines/sm/accent/delam/26.ogg', - 'sound/machines/sm/accent/delam/27.ogg', - 'sound/machines/sm/accent/delam/28.ogg', - 'sound/machines/sm/accent/delam/29.ogg', - 'sound/machines/sm/accent/delam/30.ogg', - 'sound/machines/sm/accent/delam/31.ogg', - 'sound/machines/sm/accent/delam/32.ogg', - 'sound/machines/sm/accent/delam/33.ogg', - )) - if(SFX_HYPERTORUS_CALM) - soundin = pick(list( - 'sound/machines/sm/accent/normal/1.ogg', - 'sound/machines/sm/accent/normal/2.ogg', - 'sound/machines/sm/accent/normal/3.ogg', - 'sound/machines/sm/accent/normal/4.ogg', - 'sound/machines/sm/accent/normal/5.ogg', - 'sound/machines/sm/accent/normal/6.ogg', - 'sound/machines/sm/accent/normal/7.ogg', - 'sound/machines/sm/accent/normal/8.ogg', - 'sound/machines/sm/accent/normal/9.ogg', - 'sound/machines/sm/accent/normal/10.ogg', - 'sound/machines/sm/accent/normal/11.ogg', - 'sound/machines/sm/accent/normal/12.ogg', - 'sound/machines/sm/accent/normal/13.ogg', - 'sound/machines/sm/accent/normal/14.ogg', - 'sound/machines/sm/accent/normal/15.ogg', - 'sound/machines/sm/accent/normal/16.ogg', - 'sound/machines/sm/accent/normal/17.ogg', - 'sound/machines/sm/accent/normal/18.ogg', - 'sound/machines/sm/accent/normal/19.ogg', - 'sound/machines/sm/accent/normal/20.ogg', - 'sound/machines/sm/accent/normal/21.ogg', - 'sound/machines/sm/accent/normal/22.ogg', - 'sound/machines/sm/accent/normal/23.ogg', - 'sound/machines/sm/accent/normal/24.ogg', - 'sound/machines/sm/accent/normal/25.ogg', - 'sound/machines/sm/accent/normal/26.ogg', - 'sound/machines/sm/accent/normal/27.ogg', - 'sound/machines/sm/accent/normal/28.ogg', - 'sound/machines/sm/accent/normal/29.ogg', - 'sound/machines/sm/accent/normal/30.ogg', - 'sound/machines/sm/accent/normal/31.ogg', - 'sound/machines/sm/accent/normal/32.ogg', - 'sound/machines/sm/accent/normal/33.ogg', - )) - if(SFX_HYPERTORUS_MELTING) - soundin = pick(list( - 'sound/machines/sm/accent/delam/1.ogg', - 'sound/machines/sm/accent/delam/2.ogg', - 'sound/machines/sm/accent/delam/3.ogg', - 'sound/machines/sm/accent/delam/4.ogg', - 'sound/machines/sm/accent/delam/5.ogg', - 'sound/machines/sm/accent/delam/6.ogg', - 'sound/machines/sm/accent/delam/7.ogg', - 'sound/machines/sm/accent/delam/8.ogg', - 'sound/machines/sm/accent/delam/9.ogg', - 'sound/machines/sm/accent/delam/10.ogg', - 'sound/machines/sm/accent/delam/11.ogg', - 'sound/machines/sm/accent/delam/12.ogg', - 'sound/machines/sm/accent/delam/13.ogg', - 'sound/machines/sm/accent/delam/14.ogg', - 'sound/machines/sm/accent/delam/15.ogg', - 'sound/machines/sm/accent/delam/16.ogg', - 'sound/machines/sm/accent/delam/17.ogg', - 'sound/machines/sm/accent/delam/18.ogg', - 'sound/machines/sm/accent/delam/19.ogg', - 'sound/machines/sm/accent/delam/20.ogg', - 'sound/machines/sm/accent/delam/21.ogg', - 'sound/machines/sm/accent/delam/22.ogg', - 'sound/machines/sm/accent/delam/23.ogg', - 'sound/machines/sm/accent/delam/24.ogg', - 'sound/machines/sm/accent/delam/25.ogg', - 'sound/machines/sm/accent/delam/26.ogg', - 'sound/machines/sm/accent/delam/27.ogg', - 'sound/machines/sm/accent/delam/28.ogg', - 'sound/machines/sm/accent/delam/29.ogg', - 'sound/machines/sm/accent/delam/30.ogg', - 'sound/machines/sm/accent/delam/31.ogg', - 'sound/machines/sm/accent/delam/32.ogg', - 'sound/machines/sm/accent/delam/33.ogg', - )) - if(SFX_CRUNCHY_BUSH_WHACK) - soundin = pick('sound/effects/crunchybushwhack1.ogg', 'sound/effects/crunchybushwhack2.ogg', 'sound/effects/crunchybushwhack3.ogg') - if(SFX_TREE_CHOP) - soundin = pick('sound/effects/treechop1.ogg', 'sound/effects/treechop2.ogg', 'sound/effects/treechop3.ogg') - if(SFX_ROCK_TAP) - soundin = pick('sound/effects/rocktap1.ogg', 'sound/effects/rocktap2.ogg', 'sound/effects/rocktap3.ogg') - if(SFX_SEAR) - soundin = 'sound/weapons/sear.ogg' - if(SFX_REEL) - soundin = pick( - 'sound/items/reel1.ogg', - 'sound/items/reel2.ogg', - 'sound/items/reel3.ogg', - 'sound/items/reel4.ogg', - 'sound/items/reel5.ogg', - ) - if(SFX_RATTLE) - soundin = pick( - 'sound/items/rattle1.ogg', - 'sound/items/rattle2.ogg', - 'sound/items/rattle3.ogg', - ) + if(!istext(soundin)) + return soundin + switch(soundin) + if(SFX_SHATTER) + soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') + if(SFX_EXPLOSION) + soundin = pick('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg') + if(SFX_EXPLOSION_CREAKING) + soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg') + if(SFX_HULL_CREAKING) + soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') + if(SFX_SPARKS) + soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg') + if(SFX_RUSTLE) + soundin = pick('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg') + if(SFX_BODYFALL) + soundin = pick('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg') + if(SFX_PUNCH) + soundin = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') + if(SFX_CLOWN_STEP) + soundin = pick('sound/effects/footstep/clownstep1.ogg','sound/effects/footstep/clownstep2.ogg') + if(SFX_SUIT_STEP) + soundin = pick('sound/effects/suitstep1.ogg','sound/effects/suitstep2.ogg') + if(SFX_SWING_HIT) + soundin = pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg') + if(SFX_HISS) + soundin = pick('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg') + if(SFX_PAGE_TURN) + soundin = pick('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg') + if(SFX_RICOCHET) + soundin = pick( 'sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg','sound/weapons/effects/ric3.ogg','sound/weapons/effects/ric4.ogg','sound/weapons/effects/ric5.ogg') + if(SFX_TERMINAL_TYPE) + soundin = pick(list( + 'sound/machines/terminal_button01.ogg', + 'sound/machines/terminal_button02.ogg', + 'sound/machines/terminal_button03.ogg', + 'sound/machines/terminal_button04.ogg', + 'sound/machines/terminal_button05.ogg', + 'sound/machines/terminal_button06.ogg', + 'sound/machines/terminal_button07.ogg', + 'sound/machines/terminal_button08.ogg', + )) + if(SFX_DESECRATION) + soundin = pick('sound/misc/desecration-01.ogg', 'sound/misc/desecration-02.ogg', 'sound/misc/desecration-03.ogg') + if(SFX_IM_HERE) + soundin = pick('sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg') + if(SFX_CAN_OPEN) + soundin = pick('sound/effects/can_open1.ogg', 'sound/effects/can_open2.ogg', 'sound/effects/can_open3.ogg') + if(SFX_BULLET_MISS) + soundin = pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg') + if(SFX_REVOLVER_SPIN) + soundin = pick('sound/weapons/gun/revolver/spin1.ogg', 'sound/weapons/gun/revolver/spin2.ogg', 'sound/weapons/gun/revolver/spin3.ogg') + if(SFX_LAW) + soundin = pick(list( + 'sound/voice/beepsky/creep.ogg', + 'sound/voice/beepsky/god.ogg', + 'sound/voice/beepsky/iamthelaw.ogg', + 'sound/voice/beepsky/insult.ogg', + 'sound/voice/beepsky/radio.ogg', + 'sound/voice/beepsky/secureday.ogg', + )) + if(SFX_HONKBOT_E) + soundin = pick(list( + 'sound/effects/pray.ogg', + 'sound/effects/reee.ogg', + 'sound/items/AirHorn.ogg', + 'sound/items/AirHorn2.ogg', + 'sound/items/bikehorn.ogg', + 'sound/items/WEEOO1.ogg', + 'sound/machines/buzz-sigh.ogg', + 'sound/machines/ping.ogg', + 'sound/magic/Fireball.ogg', + 'sound/misc/sadtrombone.ogg', + 'sound/voice/beepsky/creep.ogg', + 'sound/voice/beepsky/iamthelaw.ogg', + 'sound/voice/hiss1.ogg', + 'sound/weapons/bladeslice.ogg', + 'sound/weapons/flashbang.ogg', + )) + if(SFX_GOOSE) + soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg') + if(SFX_WARPSPEED) + soundin = 'sound/runtime/hyperspace/hyperspace_begin.ogg' + if(SFX_SM_CALM) + soundin = pick(list( + 'sound/machines/sm/accent/normal/1.ogg', + 'sound/machines/sm/accent/normal/2.ogg', + 'sound/machines/sm/accent/normal/3.ogg', + 'sound/machines/sm/accent/normal/4.ogg', + 'sound/machines/sm/accent/normal/5.ogg', + 'sound/machines/sm/accent/normal/6.ogg', + 'sound/machines/sm/accent/normal/7.ogg', + 'sound/machines/sm/accent/normal/8.ogg', + 'sound/machines/sm/accent/normal/9.ogg', + 'sound/machines/sm/accent/normal/10.ogg', + 'sound/machines/sm/accent/normal/11.ogg', + 'sound/machines/sm/accent/normal/12.ogg', + 'sound/machines/sm/accent/normal/13.ogg', + 'sound/machines/sm/accent/normal/14.ogg', + 'sound/machines/sm/accent/normal/15.ogg', + 'sound/machines/sm/accent/normal/16.ogg', + 'sound/machines/sm/accent/normal/17.ogg', + 'sound/machines/sm/accent/normal/18.ogg', + 'sound/machines/sm/accent/normal/19.ogg', + 'sound/machines/sm/accent/normal/20.ogg', + 'sound/machines/sm/accent/normal/21.ogg', + 'sound/machines/sm/accent/normal/22.ogg', + 'sound/machines/sm/accent/normal/23.ogg', + 'sound/machines/sm/accent/normal/24.ogg', + 'sound/machines/sm/accent/normal/25.ogg', + 'sound/machines/sm/accent/normal/26.ogg', + 'sound/machines/sm/accent/normal/27.ogg', + 'sound/machines/sm/accent/normal/28.ogg', + 'sound/machines/sm/accent/normal/29.ogg', + 'sound/machines/sm/accent/normal/30.ogg', + 'sound/machines/sm/accent/normal/31.ogg', + 'sound/machines/sm/accent/normal/32.ogg', + 'sound/machines/sm/accent/normal/33.ogg', + )) + if(SFX_SM_DELAM) + soundin = pick(list( + 'sound/machines/sm/accent/delam/1.ogg', + 'sound/machines/sm/accent/delam/2.ogg', + 'sound/machines/sm/accent/delam/3.ogg', + 'sound/machines/sm/accent/delam/4.ogg', + 'sound/machines/sm/accent/delam/5.ogg', + 'sound/machines/sm/accent/delam/6.ogg', + 'sound/machines/sm/accent/delam/7.ogg', + 'sound/machines/sm/accent/delam/8.ogg', + 'sound/machines/sm/accent/delam/9.ogg', + 'sound/machines/sm/accent/delam/10.ogg', + 'sound/machines/sm/accent/delam/11.ogg', + 'sound/machines/sm/accent/delam/12.ogg', + 'sound/machines/sm/accent/delam/13.ogg', + 'sound/machines/sm/accent/delam/14.ogg', + 'sound/machines/sm/accent/delam/15.ogg', + 'sound/machines/sm/accent/delam/16.ogg', + 'sound/machines/sm/accent/delam/17.ogg', + 'sound/machines/sm/accent/delam/18.ogg', + 'sound/machines/sm/accent/delam/19.ogg', + 'sound/machines/sm/accent/delam/20.ogg', + 'sound/machines/sm/accent/delam/21.ogg', + 'sound/machines/sm/accent/delam/22.ogg', + 'sound/machines/sm/accent/delam/23.ogg', + 'sound/machines/sm/accent/delam/24.ogg', + 'sound/machines/sm/accent/delam/25.ogg', + 'sound/machines/sm/accent/delam/26.ogg', + 'sound/machines/sm/accent/delam/27.ogg', + 'sound/machines/sm/accent/delam/28.ogg', + 'sound/machines/sm/accent/delam/29.ogg', + 'sound/machines/sm/accent/delam/30.ogg', + 'sound/machines/sm/accent/delam/31.ogg', + 'sound/machines/sm/accent/delam/32.ogg', + 'sound/machines/sm/accent/delam/33.ogg', + )) + if(SFX_HYPERTORUS_CALM) + soundin = pick(list( + 'sound/machines/sm/accent/normal/1.ogg', + 'sound/machines/sm/accent/normal/2.ogg', + 'sound/machines/sm/accent/normal/3.ogg', + 'sound/machines/sm/accent/normal/4.ogg', + 'sound/machines/sm/accent/normal/5.ogg', + 'sound/machines/sm/accent/normal/6.ogg', + 'sound/machines/sm/accent/normal/7.ogg', + 'sound/machines/sm/accent/normal/8.ogg', + 'sound/machines/sm/accent/normal/9.ogg', + 'sound/machines/sm/accent/normal/10.ogg', + 'sound/machines/sm/accent/normal/11.ogg', + 'sound/machines/sm/accent/normal/12.ogg', + 'sound/machines/sm/accent/normal/13.ogg', + 'sound/machines/sm/accent/normal/14.ogg', + 'sound/machines/sm/accent/normal/15.ogg', + 'sound/machines/sm/accent/normal/16.ogg', + 'sound/machines/sm/accent/normal/17.ogg', + 'sound/machines/sm/accent/normal/18.ogg', + 'sound/machines/sm/accent/normal/19.ogg', + 'sound/machines/sm/accent/normal/20.ogg', + 'sound/machines/sm/accent/normal/21.ogg', + 'sound/machines/sm/accent/normal/22.ogg', + 'sound/machines/sm/accent/normal/23.ogg', + 'sound/machines/sm/accent/normal/24.ogg', + 'sound/machines/sm/accent/normal/25.ogg', + 'sound/machines/sm/accent/normal/26.ogg', + 'sound/machines/sm/accent/normal/27.ogg', + 'sound/machines/sm/accent/normal/28.ogg', + 'sound/machines/sm/accent/normal/29.ogg', + 'sound/machines/sm/accent/normal/30.ogg', + 'sound/machines/sm/accent/normal/31.ogg', + 'sound/machines/sm/accent/normal/32.ogg', + 'sound/machines/sm/accent/normal/33.ogg', + )) + if(SFX_HYPERTORUS_MELTING) + soundin = pick(list( + 'sound/machines/sm/accent/delam/1.ogg', + 'sound/machines/sm/accent/delam/2.ogg', + 'sound/machines/sm/accent/delam/3.ogg', + 'sound/machines/sm/accent/delam/4.ogg', + 'sound/machines/sm/accent/delam/5.ogg', + 'sound/machines/sm/accent/delam/6.ogg', + 'sound/machines/sm/accent/delam/7.ogg', + 'sound/machines/sm/accent/delam/8.ogg', + 'sound/machines/sm/accent/delam/9.ogg', + 'sound/machines/sm/accent/delam/10.ogg', + 'sound/machines/sm/accent/delam/11.ogg', + 'sound/machines/sm/accent/delam/12.ogg', + 'sound/machines/sm/accent/delam/13.ogg', + 'sound/machines/sm/accent/delam/14.ogg', + 'sound/machines/sm/accent/delam/15.ogg', + 'sound/machines/sm/accent/delam/16.ogg', + 'sound/machines/sm/accent/delam/17.ogg', + 'sound/machines/sm/accent/delam/18.ogg', + 'sound/machines/sm/accent/delam/19.ogg', + 'sound/machines/sm/accent/delam/20.ogg', + 'sound/machines/sm/accent/delam/21.ogg', + 'sound/machines/sm/accent/delam/22.ogg', + 'sound/machines/sm/accent/delam/23.ogg', + 'sound/machines/sm/accent/delam/24.ogg', + 'sound/machines/sm/accent/delam/25.ogg', + 'sound/machines/sm/accent/delam/26.ogg', + 'sound/machines/sm/accent/delam/27.ogg', + 'sound/machines/sm/accent/delam/28.ogg', + 'sound/machines/sm/accent/delam/29.ogg', + 'sound/machines/sm/accent/delam/30.ogg', + 'sound/machines/sm/accent/delam/31.ogg', + 'sound/machines/sm/accent/delam/32.ogg', + 'sound/machines/sm/accent/delam/33.ogg', + )) + if(SFX_CRUNCHY_BUSH_WHACK) + soundin = pick('sound/effects/crunchybushwhack1.ogg', 'sound/effects/crunchybushwhack2.ogg', 'sound/effects/crunchybushwhack3.ogg') + if(SFX_TREE_CHOP) + soundin = pick('sound/effects/treechop1.ogg', 'sound/effects/treechop2.ogg', 'sound/effects/treechop3.ogg') + if(SFX_ROCK_TAP) + soundin = pick('sound/effects/rocktap1.ogg', 'sound/effects/rocktap2.ogg', 'sound/effects/rocktap3.ogg') + if(SFX_SEAR) + soundin = 'sound/weapons/sear.ogg' + if(SFX_REEL) + soundin = pick( + 'sound/items/reel1.ogg', + 'sound/items/reel2.ogg', + 'sound/items/reel3.ogg', + 'sound/items/reel4.ogg', + 'sound/items/reel5.ogg', + ) + if(SFX_RATTLE) + soundin = pick( + 'sound/items/rattle1.ogg', + 'sound/items/rattle2.ogg', + 'sound/items/rattle3.ogg', + ) return soundin diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index e7e2974d2f18f..32c531e34dc74 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -91,6 +91,8 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( var/list/old_baseturfs = baseturfs var/old_type = type + var/datum/weakref/old_ref = weak_reference + weak_reference = null var/list/post_change_callbacks = list() SEND_SIGNAL(src, COMSIG_TURF_CHANGE, path, new_baseturfs, flags, post_change_callbacks) @@ -137,6 +139,8 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( lattice_underneath = old_lattice_underneath + new_turf.weak_reference = old_ref + if(SSlighting.initialized) // Space tiles should never have lighting objects if(!space_lit) diff --git a/code/game/turfs/closed/indestructible.dm b/code/game/turfs/closed/indestructible.dm index 9f764715bf378..4b5e51b8f3b72 100644 --- a/code/game/turfs/closed/indestructible.dm +++ b/code/game/turfs/closed/indestructible.dm @@ -3,9 +3,7 @@ desc = "Effectively impervious to conventional methods of destruction." icon = 'icons/turf/walls.dmi' explosive_resistance = 50 - -/turf/closed/indestructible/rust_heretic_act() - return + rust_resistance = RUST_RESISTANCE_ABSOLUTE /turf/closed/indestructible/TerraformTurf(path, new_baseturf, flags, defer_change = FALSE, ignore_air = FALSE) return diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index 74f14c56cbb32..73bbae135a885 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -243,7 +243,7 @@ /turf/closed/mineral/attack_hulk(mob/living/carbon/human/H) ..() - if(do_after(H, 50, target = src)) + if(do_after(H, 5 SECONDS, target = src)) playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE) H.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") gets_drilled(H) @@ -650,6 +650,7 @@ initial_gas_mix = OPENTURF_LOW_PRESSURE turf_type = /turf/open/misc/ashplanet/rocky defer_change = TRUE + rust_resistance = RUST_RESISTANCE_ORGANIC /turf/closed/mineral/snowmountain name = "snowy mountainside" diff --git a/code/game/turfs/closed/wall/material_walls.dm b/code/game/turfs/closed/wall/material_walls.dm index e625000722208..5f16a68584f3e 100644 --- a/code/game/turfs/closed/wall/material_walls.dm +++ b/code/game/turfs/closed/wall/material_walls.dm @@ -9,6 +9,7 @@ canSmoothWith = SMOOTH_GROUP_MATERIAL_WALLS rcd_memory = null material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/material/break_wall() for(var/i in custom_materials) diff --git a/code/game/turfs/closed/wall/mineral_walls.dm b/code/game/turfs/closed/wall/mineral_walls.dm index b42e194ffcfc8..347e9af8f0d24 100644 --- a/code/game/turfs/closed/wall/mineral_walls.dm +++ b/code/game/turfs/closed/wall/mineral_walls.dm @@ -6,6 +6,7 @@ canSmoothWith = null rcd_memory = null material_flags = MATERIAL_EFFECTS + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/gold name = "gold wall" @@ -19,6 +20,7 @@ smoothing_groups = SMOOTH_GROUP_GOLD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_GOLD_WALLS custom_materials = list(/datum/material/gold = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/silver name = "silver wall" @@ -47,6 +49,7 @@ smoothing_groups = SMOOTH_GROUP_DIAMOND_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_DIAMOND_WALLS custom_materials = list(/datum/material/diamond = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_REINFORCED /turf/closed/wall/mineral/diamond/hulk_recoil(obj/item/bodypart/arm, mob/living/carbon/human/hulkman, damage = 41) return ..() @@ -63,6 +66,7 @@ smoothing_groups = SMOOTH_GROUP_BANANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_BANANIUM_WALLS custom_materials = list(/datum/material/bananium = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/sandstone name = "sandstone wall" @@ -77,6 +81,7 @@ smoothing_groups = SMOOTH_GROUP_SANDSTONE_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_SANDSTONE_WALLS custom_materials = list(/datum/material/sandstone = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/uranium article = "a" @@ -91,6 +96,7 @@ smoothing_groups = SMOOTH_GROUP_URANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_URANIUM_WALLS custom_materials = list(/datum/material/uranium = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_REINFORCED /// Mutex to prevent infinite recursion when propagating radiation pulses var/active = null @@ -148,6 +154,7 @@ smoothing_groups = SMOOTH_GROUP_PLASMA_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_PLASMA_WALLS custom_materials = list(/datum/material/plasma = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/wood name = "wooden wall" @@ -163,6 +170,7 @@ smoothing_groups = SMOOTH_GROUP_WOOD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_WOOD_WALLS custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/wood/attackby(obj/item/W, mob/user) if(W.get_sharpness() && W.force) @@ -193,6 +201,7 @@ canSmoothWith = SMOOTH_GROUP_BAMBOO_WALLS sheet_type = /obj/item/stack/sheet/mineral/bamboo hardness = 80 //it's not a mineral... + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/iron name = "rough iron wall" @@ -207,6 +216,7 @@ smoothing_groups = SMOOTH_GROUP_IRON_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_IRON_WALLS custom_materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT * 2.5) + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/snow name = "packed snow wall" @@ -224,6 +234,7 @@ bullet_sizzle = TRUE bullet_bounce_sound = null custom_materials = list(/datum/material/snow = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_BASIC /turf/closed/wall/mineral/snow/hulk_recoil(obj/item/bodypart/arm, mob/living/carbon/human/hulkman, damage = 0) return ..() //No recoil damage, snow is weak @@ -242,6 +253,7 @@ smoothing_groups = SMOOTH_GROUP_ABDUCTOR_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_ABDUCTOR_WALLS custom_materials = list(/datum/material/alloy/alien = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_ORGANIC /////////////////////Titanium walls///////////////////// @@ -260,9 +272,13 @@ smoothing_groups = SMOOTH_GROUP_TITANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_TITANIUM_WALLS custom_materials = list(/datum/material/titanium = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_TITANIUM -/turf/closed/wall/mineral/titanium/rust_heretic_act() - return // titanium does not rust +/turf/closed/wall/mineral/titanium/rust_turf() + if(HAS_TRAIT(src, TRAIT_RUSTY)) + ChangeTurf(/turf/closed/wall/rust) + return + return ..() /turf/closed/wall/mineral/titanium/nodiagonal icon = 'icons/turf/walls/shuttle_wall.dmi' @@ -291,16 +307,25 @@ base_icon_state = "survival_pod_walls" smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_WINDOW_FULLTILE + SMOOTH_GROUP_TITANIUM_WALLS + rust_resistance = RUST_RESISTANCE_TITANIUM /turf/closed/wall/mineral/titanium/survival/nodiagonal icon = 'icons/turf/walls/survival_pod_walls.dmi' icon_state = "survival_pod_walls-0" base_icon_state = "survival_pod_walls" smoothing_flags = SMOOTH_BITMASK + rust_resistance = RUST_RESISTANCE_TITANIUM /turf/closed/wall/mineral/titanium/survival/pod smoothing_groups = SMOOTH_GROUP_SURVIVAL_TITANIUM_POD + SMOOTH_GROUP_TITANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_SURVIVAL_TITANIUM_POD + rust_resistance = RUST_RESISTANCE_TITANIUM + +/turf/closed/wall/mineral/titanium/rust_turf() + if(HAS_TRAIT(src, TRAIT_RUSTY)) + ChangeTurf(/turf/closed/wall/rust) + return + return ..() /////////////////////Plastitanium walls///////////////////// @@ -317,20 +342,33 @@ smoothing_groups = SMOOTH_GROUP_PLASTITANIUM_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_PLASTITANIUM_WALLS + SMOOTH_GROUP_SYNDICATE_WALLS custom_materials = list(/datum/material/alloy/plastitanium = SHEET_MATERIAL_AMOUNT*2) + rust_resistance = RUST_RESISTANCE_TITANIUM + +/turf/closed/wall/mineral/plastitanium/rust_turf() + if(HAS_TRAIT(src, TRAIT_RUSTY)) + ChangeTurf(/turf/closed/wall/rust) + return + return ..() -/turf/closed/wall/mineral/plastitanium/rust_heretic_act() - return // plastitanium does not rust /turf/closed/wall/mineral/plastitanium/nodiagonal icon = 'icons/turf/walls/plastitanium_wall.dmi' icon_state = "map-shuttle_nd" base_icon_state = "plastitanium_wall" smoothing_flags = SMOOTH_BITMASK + rust_resistance = RUST_RESISTANCE_TITANIUM /turf/closed/wall/mineral/plastitanium/overspace icon_state = "map-overspace" smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS fixed_underlay = list("space" = TRUE) + rust_resistance = RUST_RESISTANCE_TITANIUM + +/turf/closed/wall/mineral/plastitanium/rust_turf() + if(HAS_TRAIT(src, TRAIT_RUSTY)) + ChangeTurf(/turf/closed/wall/rust) + return + return ..() /turf/closed/wall/mineral/plastitanium/explosive/ex_act(severity) diff --git a/code/game/turfs/closed/wall/reinf_walls.dm b/code/game/turfs/closed/wall/reinf_walls.dm index 0e119f92df019..e94a31eeafef4 100644 --- a/code/game/turfs/closed/wall/reinf_walls.dm +++ b/code/game/turfs/closed/wall/reinf_walls.dm @@ -14,6 +14,7 @@ girder_type = /obj/structure/girder/reinforced explosive_resistance = 2 rad_insulation = RAD_HEAVY_INSULATION + rust_resistance = RUST_RESISTANCE_REINFORCED heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall. also indicates the temperature at wich the wall will melt (currently only able to melt with H/E pipes) ///Dismantled state, related to deconstruction. var/d_state = INTACT @@ -222,11 +223,9 @@ if(the_rcd.canRturf || rcd_data["[RCD_DESIGN_MODE]"] == RCD_WALLFRAME) return ..() -/turf/closed/wall/r_wall/rust_heretic_act() - if(prob(50)) - return +/turf/closed/wall/r_wall/rust_turf() if(HAS_TRAIT(src, TRAIT_RUSTY)) - ScrapeAway() + ChangeTurf(/turf/closed/wall/rust) return return ..() @@ -243,6 +242,7 @@ smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + SMOOTH_GROUP_SYNDICATE_WALLS canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_PLASTITANIUM_WALLS + SMOOTH_GROUP_SYNDICATE_WALLS + rust_resistance = RUST_RESISTANCE_TITANIUM /turf/closed/wall/r_wall/syndicate/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) return FALSE diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 6797f5a379f0f..b5829a4364cd7 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -7,6 +7,7 @@ icon_state = "wall-0" base_icon_state = "wall" explosive_resistance = 1 + rust_resistance = RUST_RESISTANCE_BASIC thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT heat_capacity = 62500 //a little over 5 cm thick , 62500 for 1 m by 2.5 m by 0.25 m iron wall. also indicates the temperature at wich the wall will melt (currently only able to melt with H/E pipes) @@ -367,12 +368,11 @@ add_overlay(dent_decals) -/turf/closed/wall/rust_heretic_act() +/turf/closed/wall/rust_turf() if(HAS_TRAIT(src, TRAIT_RUSTY)) ScrapeAway() return - if(prob(70)) - new /obj/effect/temp_visual/glowing_rune(src) + return ..() /turf/closed/wall/metal_foam_base diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index c64dd309d5264..b61fffd944e94 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -41,15 +41,33 @@ /turf/open/update_overlays() if(isnull(damaged_dmi)) return ..() + . = ..() + if(broken) - . += mutable_appearance(damaged_dmi, pick(broken_states())) + var/mutable_appearance/broken_appearance = mutable_appearance(damaged_dmi, pick(broken_states())) + + if(smoothing_flags && !(smoothing_flags & SMOOTH_BROKEN_TURF)) + var/matrix/translation = new + translation.Translate(-LARGE_TURF_SMOOTHING_X_OFFSET, -LARGE_TURF_SMOOTHING_Y_OFFSET) + broken_appearance.transform = translation + + . += broken_appearance + else if(burnt) var/list/burnt_states = burnt_states() + var/mutable_appearance/burnt_appearance if(burnt_states.len) - . += mutable_appearance(damaged_dmi, pick(burnt_states)) + burnt_appearance = mutable_appearance(damaged_dmi, pick(burnt_states)) else - . += mutable_appearance(damaged_dmi, pick(broken_states())) + burnt_appearance = mutable_appearance(damaged_dmi, pick(broken_states())) + + if(smoothing_flags && !(smoothing_flags & SMOOTH_BURNT_TURF)) + var/matrix/translation = new + translation.Translate(-LARGE_TURF_SMOOTHING_X_OFFSET, -LARGE_TURF_SMOOTHING_Y_OFFSET) + burnt_appearance.transform = translation + + . += burnt_appearance //direction is direction of travel of A /turf/open/zPassIn(direction) @@ -297,7 +315,7 @@ I.AddElement(/datum/element/frozen) for(var/mob/living/L in contents) - if(L.bodytemperature <= 50) + if(L.bodytemperature <= 50 && !HAS_TRAIT(L, TRAIT_RESISTCOLD)) L.apply_status_effect(/datum/status_effect/freon) MakeSlippery(TURF_WET_PERMAFROST, 50) return TRUE diff --git a/code/game/turfs/open/ashplanet.dm b/code/game/turfs/open/ashplanet.dm index c3aee1e4d0ecb..31369a2e5cec8 100644 --- a/code/game/turfs/open/ashplanet.dm +++ b/code/game/turfs/open/ashplanet.dm @@ -15,9 +15,9 @@ clawfootstep = FOOTSTEP_SAND heavyfootstep = FOOTSTEP_GENERIC_HEAVY tiled_dirt = FALSE + rust_resistance = RUST_RESISTANCE_ORGANIC var/smooth_icon = 'icons/turf/floors/ash.dmi' - /turf/open/misc/ashplanet/Initialize(mapload) . = ..() if(smoothing_flags & SMOOTH_BITMASK) @@ -64,6 +64,7 @@ barefootstep = FOOTSTEP_HARD_BAREFOOT clawfootstep = FOOTSTEP_HARD_CLAW heavyfootstep = FOOTSTEP_GENERIC_HEAVY + rust_resistance = RUST_RESISTANCE_ORGANIC /turf/open/misc/ashplanet/wateryrock/Initialize(mapload) icon_state = "[icon_state][rand(1, 9)]" diff --git a/code/game/turfs/open/asteroid.dm b/code/game/turfs/open/asteroid.dm index 3a3a837968a22..4b43757bb9c1a 100644 --- a/code/game/turfs/open/asteroid.dm +++ b/code/game/turfs/open/asteroid.dm @@ -14,7 +14,7 @@ barefootstep = FOOTSTEP_SAND clawfootstep = FOOTSTEP_SAND heavyfootstep = FOOTSTEP_GENERIC_HEAVY - + rust_resistance = RUST_RESISTANCE_ORGANIC /// Base turf type to be created by the tunnel var/turf_type = /turf/open/misc/asteroid /// Whether this turf has different icon states diff --git a/code/game/turfs/open/chasm.dm b/code/game/turfs/open/chasm.dm index 142d966172b80..504e876d536ce 100644 --- a/code/game/turfs/open/chasm.dm +++ b/code/game/turfs/open/chasm.dm @@ -11,6 +11,7 @@ canSmoothWith = SMOOTH_GROUP_TURF_CHASM density = TRUE //This will prevent hostile mobs from pathing into chasms, while the canpass override will still let it function like an open turf bullet_bounce_sound = null //abandon all hope ye who enter + rust_resistance = RUST_RESISTANCE_ABSOLUTE /turf/open/chasm/Initialize(mapload) . = ..() @@ -46,8 +47,7 @@ return TRUE return FALSE -/turf/open/chasm/rust_heretic_act() - return FALSE + /turf/open/chasm/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) underlay_appearance.icon = 'icons/turf/floors.dmi' diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm index 2dbd065849ec1..12d9deedbae84 100644 --- a/code/game/turfs/open/floor.dm +++ b/code/game/turfs/open/floor.dm @@ -363,6 +363,12 @@ return TRUE return FALSE +/turf/open/floor/rust_turf() + if(HAS_TRAIT(src, TRAIT_RUSTY)) + return + ChangeTurf(/turf/open/floor/plating) + return ..() + /turf/open/floor/material name = "floor" icon_state = "materialfloor" diff --git a/code/game/turfs/open/floor/catwalk_plating.dm b/code/game/turfs/open/floor/catwalk_plating.dm index afb4274cb57ba..57bd0b74107ee 100644 --- a/code/game/turfs/open/floor/catwalk_plating.dm +++ b/code/game/turfs/open/floor/catwalk_plating.dm @@ -16,6 +16,7 @@ footstep = FOOTSTEP_CATWALK overfloor_placed = TRUE underfloor_accessibility = UNDERFLOOR_VISIBLE + rust_resistance = RUST_RESISTANCE_BASIC var/covered = TRUE var/catwalk_type = "maint" var/static/list/catwalk_underlays = list() @@ -90,7 +91,7 @@ icon_state = "titanium_above" floor_tile = /obj/item/stack/tile/catwalk_tile/titanium catwalk_type = "titanium" - + rust_resistance = RUST_RESISTANCE_TITANIUM /turf/open/floor/catwalk_floor/iron_smooth //the original green type name = "smooth plated catwalk floor" diff --git a/code/game/turfs/open/floor/fancy_floor.dm b/code/game/turfs/open/floor/fancy_floor.dm index d498d47a6c806..e9331872907f4 100644 --- a/code/game/turfs/open/floor/fancy_floor.dm +++ b/code/game/turfs/open/floor/fancy_floor.dm @@ -13,11 +13,11 @@ icon_state = "wood" floor_tile = /obj/item/stack/tile/wood footstep = FOOTSTEP_WOOD - turf_flags = NO_RUST barefootstep = FOOTSTEP_WOOD_BAREFOOT clawfootstep = FOOTSTEP_WOOD_CLAW heavyfootstep = FOOTSTEP_GENERIC_HEAVY tiled_dirt = FALSE + rust_resistance = RUST_RESISTANCE_BASIC /turf/open/floor/wood/broken_states() return list("wood-broken", "wood-broken2", "wood-broken3", "wood-broken4", "wood-broken5", "wood-broken6", "wood-broken7") @@ -149,6 +149,7 @@ clawfootstep = FOOTSTEP_GRASS heavyfootstep = FOOTSTEP_GENERIC_HEAVY tiled_dirt = FALSE + rust_resistance = RUST_RESISTANCE_ORGANIC /turf/open/floor/grass/broken_states() return list("[initial(icon_state)]_damaged") @@ -197,7 +198,7 @@ initial_gas_mix = FROZEN_ATMOS bullet_bounce_sound = null tiled_dirt = FALSE - + rust_resistance = RUST_RESISTANCE_ORGANIC slowdown = 1.5 bullet_sizzle = TRUE footstep = FOOTSTEP_SAND @@ -205,6 +206,7 @@ clawfootstep = FOOTSTEP_SAND heavyfootstep = FOOTSTEP_GENERIC_HEAVY + /turf/open/floor/fake_snow/Initialize(mapload) . = ..() AddElement(/datum/element/diggable, /obj/item/stack/tile/mineral/snow, 1, worm_chance = 0) @@ -256,6 +258,7 @@ clawfootstep = FOOTSTEP_CARPET_BAREFOOT heavyfootstep = FOOTSTEP_GENERIC_HEAVY tiled_dirt = FALSE + rust_resistance = RUST_RESISTANCE_BASIC /turf/open/floor/carpet/examine(mob/user) . = ..() diff --git a/code/game/turfs/open/floor/glass.dm b/code/game/turfs/open/floor/glass.dm index b1579da55f088..cece195aaf85a 100644 --- a/code/game/turfs/open/floor/glass.dm +++ b/code/game/turfs/open/floor/glass.dm @@ -33,7 +33,6 @@ return INITIALIZE_HINT_LATELOAD /turf/open/floor/glass/LateInitialize() - . = ..() AddElement(/datum/element/turf_z_transparency) setup_glow() diff --git a/code/game/turfs/open/floor/iron_floor.dm b/code/game/turfs/open/floor/iron_floor.dm index d38aedfd4f9d3..c3869ccc962ce 100644 --- a/code/game/turfs/open/floor/iron_floor.dm +++ b/code/game/turfs/open/floor/iron_floor.dm @@ -1,6 +1,7 @@ /turf/open/floor/iron icon_state = "floor" floor_tile = /obj/item/stack/tile/iron/base + rust_resistance = RUST_RESISTANCE_BASIC /turf/open/floor/iron/broken_states() return list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5") @@ -13,12 +14,6 @@ . = ..() . += span_notice("There's a small crack on the edge of it.") - -/turf/open/floor/iron/rust_heretic_act() - if(prob(70)) - new /obj/effect/temp_visual/glowing_rune(src) - ChangeTurf(/turf/open/floor/plating/rust) - /turf/open/floor/iron/update_icon_state() if(broken || burnt) return ..() diff --git a/code/game/turfs/open/floor/mineral_floor.dm b/code/game/turfs/open/floor/mineral_floor.dm index 620bfe85e04af..e8be1331378ab 100644 --- a/code/game/turfs/open/floor/mineral_floor.dm +++ b/code/game/turfs/open/floor/mineral_floor.dm @@ -13,10 +13,12 @@ name = "mineral floor" icon_state = null material_flags = MATERIAL_EFFECTS + rust_resistance = RUST_RESISTANCE_BASIC var/list/icons tiled_dirt = FALSE + /turf/open/floor/mineral/Initialize(mapload) . = ..() icons = typelist("icons", icons) @@ -37,6 +39,7 @@ floor_tile = /obj/item/stack/tile/mineral/plasma icons = list("plasma","plasma_dam") custom_materials = list(/datum/material/plasma = SMALL_MATERIAL_AMOUNT*5) + rust_resistance = RUST_RESISTANCE_BASIC //Plasma floor that can't be removed, for disco inferno @@ -52,6 +55,7 @@ floor_tile = /obj/item/stack/tile/mineral/gold icons = list("gold","gold_dam") custom_materials = list(/datum/material/gold = SMALL_MATERIAL_AMOUNT*5) + rust_resistance = RUST_RESISTANCE_BASIC //SILVER @@ -69,12 +73,12 @@ icon_state = "titanium" floor_tile = /obj/item/stack/tile/mineral/titanium custom_materials = list(/datum/material/titanium = SMALL_MATERIAL_AMOUNT*5) + rust_resistance = RUST_RESISTANCE_TITANIUM /turf/open/floor/mineral/titanium/broken_states() return list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5") -/turf/open/floor/mineral/titanium/rust_heretic_act() - return // titanium does not rust + /turf/open/floor/mineral/titanium/airless initial_gas_mix = AIRLESS_ATMOS @@ -153,13 +157,11 @@ icon_state = "plastitanium" floor_tile = /obj/item/stack/tile/mineral/plastitanium custom_materials = list(/datum/material/alloy/plastitanium = SMALL_MATERIAL_AMOUNT*5) + rust_resistance = RUST_RESISTANCE_TITANIUM /turf/open/floor/mineral/plastitanium/broken_states() return list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5") -/turf/open/floor/mineral/plastitanium/rust_heretic_act() - return // plastitanium does not rust - /turf/open/floor/mineral/plastitanium/airless initial_gas_mix = AIRLESS_ATMOS @@ -182,6 +184,7 @@ floor_tile = /obj/item/stack/tile/mineral/bananium icons = list("bananium","bananium_dam") custom_materials = list(/datum/material/bananium = SMALL_MATERIAL_AMOUNT*5) + rust_resistance = RUST_RESISTANCE_BASIC material_flags = NONE //The slippery comp makes it unpractical for good clown decor. The custom mat one should still slip. var/sound_cooldown = 0 @@ -228,6 +231,7 @@ floor_tile = /obj/item/stack/tile/mineral/diamond icons = list("diamond","diamond_dam") custom_materials = list(/datum/material/diamond = SMALL_MATERIAL_AMOUNT*5) + rust_resistance = RUST_RESISTANCE_REINFORCED //URANIUM @@ -238,6 +242,7 @@ floor_tile = /obj/item/stack/tile/mineral/uranium icons = list("uranium","uranium_dam") custom_materials = list(/datum/material/uranium = SMALL_MATERIAL_AMOUNT*5) + rust_resistance = RUST_RESISTANCE_REINFORCED var/last_event = 0 var/active = null @@ -288,6 +293,7 @@ icons = list("alienpod1", "alienpod2", "alienpod3", "alienpod4", "alienpod5", "alienpod6", "alienpod7", "alienpod8", "alienpod9") baseturfs = /turf/open/floor/plating/abductor2 custom_materials = list(/datum/material/alloy/alien = SMALL_MATERIAL_AMOUNT*5) + rust_resistance = RUST_RESISTANCE_ORGANIC damaged_dmi = null /turf/open/floor/mineral/abductor/Initialize(mapload) diff --git a/code/game/turfs/open/floor/plating.dm b/code/game/turfs/open/floor/plating.dm index 1de28b201d84c..1ff0d9261fb6c 100644 --- a/code/game/turfs/open/floor/plating.dm +++ b/code/game/turfs/open/floor/plating.dm @@ -14,6 +14,7 @@ barefootstep = FOOTSTEP_HARD_BAREFOOT clawfootstep = FOOTSTEP_HARD_CLAW heavyfootstep = FOOTSTEP_GENERIC_HEAVY + rust_resistance = RUST_RESISTANCE_BASIC //Can this plating have reinforced floors placed ontop of it var/attachment_holes = TRUE @@ -62,7 +63,7 @@ return else to_chat(user, span_notice("You begin reinforcing the floor...")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) if (R.get_amount() >= 2 && !istype(src, /turf/open/floor/engine)) place_on_top(/turf/open/floor/engine, flags = CHANGETURF_INHERIT_AIR) playsound(src, 'sound/items/deconstruct.ogg', 80, TRUE) @@ -121,10 +122,7 @@ #undef PLATE_REINFORCE_COST -/turf/open/floor/plating/rust_heretic_act() - if(prob(70)) - new /obj/effect/temp_visual/glowing_rune(src) - return ..() + /turf/open/floor/plating/make_plating(force = FALSE) return @@ -177,9 +175,8 @@ ScrapeAway(flags = CHANGETURF_INHERIT_AIR) return TRUE -/turf/open/floor/plating/foam/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - SHOULD_CALL_PARENT(FALSE) - return NONE // Fuck you +/turf/open/floor/plating/foam/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + return user.combat_mode ? ITEM_INTERACT_SKIP_TO_ATTACK : ITEM_INTERACT_BLOCKING // Fuck you //reinforced plating deconstruction states #define PLATE_INTACT 0 @@ -198,6 +195,7 @@ allow_replacement = FALSE rcd_proof = TRUE upgradable = FALSE + rust_resistance = RUST_RESISTANCE_REINFORCED //Used to track which stage of deconstruction the plate is currently in, Intact > Bolts Loosened > Cut var/deconstruction_state = PLATE_INTACT diff --git a/code/game/turfs/open/floor/plating/misc_plating.dm b/code/game/turfs/open/floor/plating/misc_plating.dm index 9b79313111f13..704578438fdc3 100644 --- a/code/game/turfs/open/floor/plating/misc_plating.dm +++ b/code/game/turfs/open/floor/plating/misc_plating.dm @@ -19,6 +19,7 @@ icon_state = "alienpod1" base_icon_state = "alienpod1" tiled_dirt = FALSE + rust_resistance = RUST_RESISTANCE_ORGANIC // Not actually broken, just should never break...yeah. broken = TRUE damaged_dmi = null @@ -32,6 +33,7 @@ icon_state = "alienplating" base_icon_state = "alienplating" tiled_dirt = FALSE + rust_resistance = RUST_RESISTANCE_ORGANIC damaged_dmi = null /turf/open/floor/plating/abductor2/break_tile() @@ -57,6 +59,7 @@ barefootstep = FOOTSTEP_SAND clawfootstep = FOOTSTEP_SAND heavyfootstep = FOOTSTEP_GENERIC_HEAVY + rust_resistance = RUST_RESISTANCE_BASIC /turf/open/floor/plating/snowed/cavern initial_gas_mix = BURNING_COLD diff --git a/code/game/turfs/open/floor/reinforced_floor.dm b/code/game/turfs/open/floor/reinforced_floor.dm index 6a23f8e6be50e..0a44c78ceca5e 100644 --- a/code/game/turfs/open/floor/reinforced_floor.dm +++ b/code/game/turfs/open/floor/reinforced_floor.dm @@ -13,6 +13,7 @@ heavyfootstep = FOOTSTEP_GENERIC_HEAVY tiled_dirt = FALSE rcd_proof = TRUE + rust_resistance = RUST_RESISTANCE_REINFORCED /turf/open/floor/engine/examine(mob/user) diff --git a/code/game/turfs/open/grass.dm b/code/game/turfs/open/grass.dm index d4bfc051e3b2d..d1779ad7499ac 100644 --- a/code/game/turfs/open/grass.dm +++ b/code/game/turfs/open/grass.dm @@ -10,29 +10,53 @@ barefootstep = FOOTSTEP_GRASS clawfootstep = FOOTSTEP_GRASS heavyfootstep = FOOTSTEP_GENERIC_HEAVY - smoothing_flags = SMOOTH_BITMASK + smoothing_flags = SMOOTH_BITMASK | SMOOTH_BROKEN_TURF | SMOOTH_BURNT_TURF smoothing_groups = SMOOTH_GROUP_TURF_OPEN + SMOOTH_GROUP_FLOOR_GRASS canSmoothWith = SMOOTH_GROUP_FLOOR_GRASS + SMOOTH_GROUP_CLOSED_TURFS layer = HIGH_TURF_LAYER - damaged_dmi = 'icons/turf/damaged.dmi' + rust_resistance = RUST_RESISTANCE_ORGANIC + damaged_dmi = 'icons/turf/floors/grass_damaged.dmi' + /// The icon used for smoothing. var/smooth_icon = 'icons/turf/floors/grass.dmi' + /// The base icon_state for the broken state. + var/base_broken_icon_state = "grass_damaged" + /// The base icon_state for the burnt state. + var/base_burnt_icon_state = "grass_damaged" /turf/open/misc/grass/broken_states() - return list("grass_damaged") + if (!smoothing_junction || !(smoothing_flags & SMOOTH_BROKEN_TURF)) + return list("[base_broken_icon_state]-255") + + return list("[base_broken_icon_state]-[smoothing_junction]") /turf/open/misc/grass/burnt_states() - return list("grass_damaged") + if (!smoothing_junction || !(smoothing_flags & SMOOTH_BURNT_TURF)) + return list("[base_burnt_icon_state]-255") + + return list("[base_burnt_icon_state]-[smoothing_junction]") /turf/open/misc/grass/Initialize(mapload) . = ..() if(smoothing_flags) var/matrix/translation = new - translation.Translate(-9, -9) + translation.Translate(LARGE_TURF_SMOOTHING_X_OFFSET, LARGE_TURF_SMOOTHING_Y_OFFSET) transform = translation icon = smooth_icon if(is_station_level(z)) GLOB.station_turfs += src + +/turf/open/misc/grass/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + . = ..() + if (!.) + return + + if(!smoothing_flags) + return + + underlay_appearance.transform = transform + + /turf/open/misc/grass/lavaland initial_gas_mix = LAVALAND_DEFAULT_ATMOS diff --git a/code/game/turfs/open/hay.dm b/code/game/turfs/open/hay.dm new file mode 100644 index 0000000000000..b0bd581c2bb8f --- /dev/null +++ b/code/game/turfs/open/hay.dm @@ -0,0 +1,14 @@ +/turf/open/misc/hay + name = "hay" + desc = "For horses and cows like you." + icon = 'icons/turf/floors.dmi' + icon_state = "hay" + base_icon_state = "hay" + +/turf/open/misc/hay/lavaland + baseturfs = list(/turf/open/misc/basalt) + initial_gas_mix = LAVALAND_DEFAULT_ATMOS + +/turf/open/misc/hay/icemoon + baseturfs = list(/turf/open/misc/snow) + initial_gas_mix = ICEMOON_DEFAULT_ATMOS diff --git a/code/game/turfs/open/ice.dm b/code/game/turfs/open/ice.dm index 3f951684e86d3..481dcb6b84732 100644 --- a/code/game/turfs/open/ice.dm +++ b/code/game/turfs/open/ice.dm @@ -14,6 +14,7 @@ barefootstep = FOOTSTEP_HARD_BAREFOOT clawfootstep = FOOTSTEP_HARD_CLAW heavyfootstep = FOOTSTEP_GENERIC_HEAVY + rust_resistance = RUST_RESISTANCE_ORGANIC /turf/open/misc/ice/Initialize(mapload) . = ..() diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 8165b35a256b8..53450b85db0df 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -40,6 +40,9 @@ var/mask_state = "lava-lightmask" /// The type for the preset fishing spot of this type of turf. var/fish_source_type = /datum/fish_source/lavaland + /// The color we use for our immersion overlay + var/immerse_overlay_color = "#a15e1b" + rust_resistance = RUST_RESISTANCE_ABSOLUTE /turf/open/lava/Initialize(mapload) . = ..() @@ -48,7 +51,7 @@ refresh_light() if(!smoothing_flags) update_appearance() - + AddElement(/datum/element/immerse, icon, icon_state, "immerse", immerse_overlay_color) /turf/open/lava/Destroy() for(var/mob/living/leaving_mob in contents) @@ -167,9 +170,6 @@ return TRUE return FALSE -/turf/open/lava/rust_heretic_act() - return FALSE - /turf/open/lava/singularity_act() return @@ -337,6 +337,7 @@ smoothing_groups = SMOOTH_GROUP_TURF_OPEN + SMOOTH_GROUP_FLOOR_LAVA canSmoothWith = SMOOTH_GROUP_FLOOR_LAVA underfloor_accessibility = 2 //This avoids strangeness when routing pipes / wires along catwalks over lava + immerse_overlay_color = "#F98511" /turf/open/lava/smooth/lava_land_surface initial_gas_mix = LAVALAND_DEFAULT_ATMOS @@ -360,6 +361,7 @@ immunity_trait = TRAIT_SNOWSTORM_IMMUNE immunity_resistance_flags = FREEZE_PROOF lava_temperature = 100 + immerse_overlay_color = "#CD4C9F" /turf/open/lava/plasma/examine(mob/user) . = ..() diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index 24345611576e4..677bc776ea5a7 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -10,6 +10,7 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT pathing_pass_method = TURF_PATHING_PASS_PROC plane = TRANSPARENT_FLOOR_PLANE + rust_resistance = RUST_RESISTANCE_ABSOLUTE var/can_cover_up = TRUE var/can_build_on = TRUE @@ -32,7 +33,6 @@ return INITIALIZE_HINT_LATELOAD /turf/open/openspace/LateInitialize() - . = ..() AddElement(/datum/element/turf_z_transparency) /turf/open/openspace/ChangeTurf(path, list/new_baseturfs, flags) @@ -149,9 +149,6 @@ return TRUE return FALSE -/turf/open/openspace/rust_heretic_act() - return FALSE - /turf/open/openspace/CanAStarPass(to_dir, datum/can_pass_info/pass_info) var/atom/movable/our_movable = pass_info.caller_ref.resolve() if(our_movable && !our_movable.can_z_move(DOWN, src, null, ZMOVE_FALL_FLAGS)) //If we can't fall here (flying/lattice), it's fine to path through @@ -188,7 +185,9 @@ if(!T) return if(T.turf_flags & NO_RUINS && protect_ruin) - ChangeTurf(replacement_turf, null, CHANGETURF_IGNORE_AIR) + var/turf/newturf = ChangeTurf(replacement_turf, null, CHANGETURF_IGNORE_AIR) + if(!isopenspaceturf(newturf)) // only openspace turfs should be returning INITIALIZE_HINT_LATELOAD + return INITIALIZE_HINT_NORMAL return if(!ismineralturf(T) || !drill_below) return diff --git a/code/game/turfs/open/planet.dm b/code/game/turfs/open/planet.dm index db391025e84b1..893942fc49c52 100644 --- a/code/game/turfs/open/planet.dm +++ b/code/game/turfs/open/planet.dm @@ -13,6 +13,7 @@ clawfootstep = FOOTSTEP_SAND heavyfootstep = FOOTSTEP_GENERIC_HEAVY tiled_dirt = FALSE + rust_resistance = RUST_RESISTANCE_ORGANIC /turf/open/misc/dirt/station name = "dirt flooring" //FOR THE LOVE OF GOD USE THIS INSTEAD OF DIRT FOR STATION MAPS @@ -66,20 +67,14 @@ /turf/open/misc/grass/jungle name = "jungle grass" + desc = "Greener on the other side." initial_gas_mix = OPENTURF_DEFAULT_ATMOS planetary_atmos = TRUE baseturfs = /turf/open/misc/dirt - desc = "Greener on the other side." icon_state = "junglegrass" base_icon_state = "junglegrass" smooth_icon = 'icons/turf/floors/junglegrass.dmi' -/turf/open/misc/grass/broken_states() - return list("jungle_damaged") - -/turf/open/misc/grass/burnt_states() - return list("jungle_damaged") - /turf/open/misc/grass/jungle/lavaland initial_gas_mix = LAVALAND_DEFAULT_ATMOS diff --git a/code/game/turfs/open/sand.dm b/code/game/turfs/open/sand.dm index cfcd4dccfb1fc..c863e28231d35 100644 --- a/code/game/turfs/open/sand.dm +++ b/code/game/turfs/open/sand.dm @@ -8,6 +8,7 @@ barefootstep = FOOTSTEP_SAND clawfootstep = FOOTSTEP_SAND heavyfootstep = FOOTSTEP_GENERIC_HEAVY + rust_resistance = RUST_RESISTANCE_ORGANIC /turf/open/misc/beach/ex_act(severity, target) return FALSE @@ -62,6 +63,7 @@ clawfootstep = FOOTSTEP_SAND heavyfootstep = FOOTSTEP_GENERIC_HEAVY tiled_dirt = FALSE + rust_resistance = RUST_RESISTANCE_ORGANIC /turf/open/misc/sandy_dirt/break_tile() . = ..() diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index d404870e1c8cf..28f7cfde8aceb 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -48,6 +48,7 @@ GLOBAL_LIST_EMPTY(starlight) name = "\proper space" overfloor_placed = FALSE underfloor_accessibility = UNDERFLOOR_INTERACTABLE + rust_resistance = RUST_RESISTANCE_ABSOLUTE temperature = TCMB thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT @@ -242,8 +243,6 @@ GLOBAL_LIST_EMPTY(starlight) return FALSE -/turf/open/space/rust_heretic_act() - return FALSE /turf/open/space/attempt_lattice_replacement() var/dest_x = destination_x @@ -273,7 +272,6 @@ GLOBAL_LIST_EMPTY(starlight) return INITIALIZE_HINT_LATELOAD /turf/open/space/openspace/LateInitialize() - . = ..() AddElement(/datum/element/turf_z_transparency) /turf/open/space/openspace/Destroy() diff --git a/code/game/turfs/open/water.dm b/code/game/turfs/open/water.dm index 3e2cb248f63cb..5dcfa85961d20 100644 --- a/code/game/turfs/open/water.dm +++ b/code/game/turfs/open/water.dm @@ -20,9 +20,15 @@ */ var/immerse_overlay_color = "#5AAA88" + /// Fishing element for this specific water tile + var/datum/fish_source/fishing_datum = /datum/fish_source/portal + /turf/open/water/Initialize(mapload) . = ..() AddElement(/datum/element/immerse, icon, icon_state, "immerse", immerse_overlay_color) + AddElement(/datum/element/watery_tile) + if(!isnull(fishing_datum)) + AddElement(/datum/element/lazy_fishing_spot, fishing_datum) /turf/open/water/jungle @@ -35,7 +41,4 @@ base_icon_state = "water" baseturfs = /turf/open/water/beach immerse_overlay_color = "#7799AA" - -/turf/open/water/beach/Initialize(mapload) - . = ..() - AddElement(/datum/element/lazy_fishing_spot, /datum/fish_source/ocean/beach) + fishing_datum = /datum/fish_source/ocean/beach diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 94084875984c4..e313f1652435a 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -88,6 +88,9 @@ GLOBAL_LIST_EMPTY(station_turfs) ///whether or not this turf forces movables on it to have no gravity (unless they themselves have forced gravity) var/force_no_gravity = FALSE + ///This turf's resistance to getting rusted + var/rust_resistance = RUST_RESISTANCE_ORGANIC + /// How pathing algorithm will check if this turf is passable by itself (not including content checks). By default it's just density check. /// WARNING: Currently to use a density shortcircuiting this does not support dense turfs with special allow through function var/pathing_pass_method = TURF_PATHING_PASS_DENSITY @@ -610,13 +613,19 @@ GLOBAL_LIST_EMPTY(station_turfs) /turf/proc/acid_melt() return -/turf/rust_heretic_act() - if(turf_flags & NO_RUST) +/// Check if the heretic is strong enough to rust this turf, and if so, rusts the turf with an added visual effect. +/turf/rust_heretic_act(rust_strength = 1) + if((turf_flags & NO_RUST) || (rust_strength < rust_resistance)) return + rust_turf() + +/// Override this to change behaviour when being rusted by a heretic +/turf/proc/rust_turf() if(HAS_TRAIT(src, TRAIT_RUSTY)) return - AddElement(/datum/element/rust) + AddElement(/datum/element/rust/heretic) + new /obj/effect/glowing_rune(src) /turf/handle_fall(mob/faller) if(has_gravity(src)) diff --git a/code/game/world.dm b/code/game/world.dm index cda503bd3b5b7..9e57dbba343c5 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -448,7 +448,7 @@ GLOBAL_VAR(restart_counter) /world/proc/incrementMaxZ() maxz++ SSmobs.MaxZChanged() - SSidlenpcpool.MaxZChanged() + SSai_controllers.on_max_z_changed() /world/proc/change_fps(new_value = 20) if(new_value <= 0) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 99aa63325ad0e..10b9a58b87007 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -48,14 +48,9 @@ ////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS -/datum/admins/proc/spawn_atom(object as text) - set category = "Debug" - set desc = "(atom path) Spawn an atom" - set name = "Spawn" - - if(!check_rights(R_SPAWN) || !object) +ADMIN_VERB(spawn_atom, R_SPAWN, "Spawn", "Spawn an atom.", ADMIN_CATEGORY_DEBUG, object as text) + if(!object) return - var/list/preparsed = splittext(object,":") var/path = preparsed[1] var/amount = 1 @@ -65,7 +60,7 @@ var/chosen = pick_closest_path(path) if(!chosen) return - var/turf/T = get_turf(usr) + var/turf/T = get_turf(user.mob) if(ispath(chosen, /turf)) T.ChangeTurf(chosen) @@ -74,21 +69,14 @@ var/atom/A = new chosen(T) A.flags_1 |= ADMIN_SPAWNED_1 - log_admin("[key_name(usr)] spawned [amount] x [chosen] at [AREACOORD(usr)]") + log_admin("[key_name(user)] spawned [amount] x [chosen] at [AREACOORD(user.mob)]") BLACKBOX_LOG_ADMIN_VERB("Spawn Atom") -/datum/admins/proc/podspawn_atom(object as text) - set category = "Debug" - set desc = "(atom path) Spawn an atom via supply drop" - set name = "Podspawn" - - if(!check_rights(R_SPAWN)) - return - +ADMIN_VERB(spawn_atom_pod, R_SPAWN, "PodSpawn", "Spawn an atom via supply drop.", ADMIN_CATEGORY_DEBUG, object as text) var/chosen = pick_closest_path(object) if(!chosen) return - var/turf/target_turf = get_turf(usr) + var/turf/target_turf = get_turf(user.mob) if(ispath(chosen, /turf)) target_turf.ChangeTurf(chosen) @@ -101,25 +89,18 @@ var/atom/A = new chosen(pod) A.flags_1 |= ADMIN_SPAWNED_1 - log_admin("[key_name(usr)] pod-spawned [chosen] at [AREACOORD(usr)]") + log_admin("[key_name(user)] pod-spawned [chosen] at [AREACOORD(user.mob)]") BLACKBOX_LOG_ADMIN_VERB("Podspawn Atom") -/datum/admins/proc/spawn_cargo(object as text) - set category = "Debug" - set desc = "(atom path) Spawn a cargo crate" - set name = "Spawn Cargo" - - if(!check_rights(R_SPAWN)) - return - +ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CATEGORY_DEBUG, object as text) var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/datum/supply_pack))) if(!chosen) return var/datum/supply_pack/S = new chosen S.admin_spawned = TRUE - S.generate(get_turf(usr)) + S.generate(get_turf(user.mob)) - log_admin("[key_name(usr)] spawned cargo pack [chosen] at [AREACOORD(usr)]") + log_admin("[key_name(user)] spawned cargo pack [chosen] at [AREACOORD(user.mob)]") BLACKBOX_LOG_ADMIN_VERB("Spawn Cargo") /datum/admins/proc/dynamic_mode_options(mob/user) @@ -246,10 +227,8 @@ log_admin(logged_message) message_admins(logged_message) -/datum/admins/proc/create_or_modify_area() - set category = "Debug" - set name = "Create or modify area" - create_area(usr) +ADMIN_VERB(create_or_modify_area, R_DEBUG, "Create Or Modify Area", "Create of modify an area. wow.", ADMIN_CATEGORY_DEBUG) + create_area(user.mob) //Kicks all the clients currently in the lobby. The second parameter (kick_only_afk) determins if an is_afk() check is ran, or if all clients are kicked //defaults to kicking everyone (afk + non afk clients in the lobby) diff --git a/code/modules/admin/admin_fax_panel.dm b/code/modules/admin/admin_fax_panel.dm index fe1f03d7d7ec2..8874b6f38eb5a 100644 --- a/code/modules/admin/admin_fax_panel.dm +++ b/code/modules/admin/admin_fax_panel.dm @@ -1,15 +1,6 @@ -/** - * If client have R_ADMIN flag, opens an admin fax panel. - */ -/client/proc/fax_panel() - set category = "Admin.Events" - set name = "Fax Panel" - - if(!check_rights(R_ADMIN)) - return - - var/datum/fax_panel_interface/ui = new(usr) - ui.ui_interact(usr) +ADMIN_VERB(fax_panel, R_ADMIN, "Fax Panel", "View and respond to faxes sent to CC.", ADMIN_CATEGORY_EVENTS) + var/datum/fax_panel_interface/ui = new /datum/fax_panel_interface(user.mob) + ui.ui_interact(user.mob) /// Admin Fax Panel. Tool for sending fax messages faster. /datum/fax_panel_interface @@ -97,15 +88,15 @@ switch(action) if("follow") - if(!isobserver(usr)) - usr.client?.admin_ghost() + if(!isobserver(ui.user)) + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/admin_ghost) - usr.client?.admin_follow(action_fax) + ui.user.client?.admin_follow(action_fax) if("preview") // see saved variant if(!fax_paper) return - fax_paper.ui_interact(usr) + fax_paper.ui_interact(ui.user) if("save") // save paper if(params["paperName"]) @@ -129,7 +120,7 @@ if(stamp) fax_paper.add_stamp(stamp_class, params["stampX"], params["stampY"], params["stampAngle"], stamp) - fax_paper.update_static_data(usr) // OK, it's work, and update UI. + fax_paper.update_static_data(ui.user) // OK, it's work, and update UI. if("send") //copy @@ -137,9 +128,9 @@ our_fax.name = fax_paper.name //send action_fax.receive(our_fax, sending_fax_name) - message_admins("[key_name_admin(usr)] has sent a custom fax message to [action_fax.name][ADMIN_FLW(action_fax)][ADMIN_SHOW_PAPER(fax_paper)].") - log_admin("[key_name(usr)] has sent a custom fax message to [action_fax.name]") + message_admins("[key_name_admin(ui.user)] has sent a custom fax message to [action_fax.name][ADMIN_FLW(action_fax)][ADMIN_SHOW_PAPER(fax_paper)].") + log_admin("[key_name(ui.user)] has sent a custom fax message to [action_fax.name]") if("createPaper") - var/obj/item/paper/our_paper = fax_paper.copy(/obj/item/paper, usr.loc) + var/obj/item/paper/our_paper = fax_paper.copy(/obj/item/paper, ui.user.loc) our_paper.name = fax_paper.name diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index 94ea182891f56..edc3525bf2f07 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -10,13 +10,8 @@ WRITE_FILE(F, "[time_stamp(format = "YYYY-MM-DD hh:mm:ss")] [REF(src)] ([x],[y],[z]) || [source] [message]
") -/client/proc/investigate_show() - set name = "Investigate" - set category = "Admin.Game" - if(!holder) - return - - var/list/investigates = list( +ADMIN_VERB(investigate_show, R_NONE, "Investigate", "Browse various detailed logs.", ADMIN_CATEGORY_GAME) + var/static/list/investigates = list( INVESTIGATE_ACCESSCHANGES, INVESTIGATE_ATMOS, INVESTIGATE_BOTANY, @@ -48,7 +43,7 @@ var/list/combined = sort_list(logs_present) + sort_list(logs_missing) - var/selected = tgui_input_list(src, "Investigate what?", "Investigation", combined) + var/selected = tgui_input_list(user, "Investigate what?", "Investigation", combined) if(isnull(selected)) return if(!(selected in combined) || selected == "---") @@ -62,6 +57,6 @@ var/F = file("[GLOB.log_directory]/[selected].html") if(!fexists(F)) - to_chat(src, span_danger("No [selected] logfile was found."), confidential = TRUE) + to_chat(user, span_danger("No [selected] logfile was found."), confidential = TRUE) return - src << browse(F,"window=investigate[selected];size=800x300") + user << browse(F,"window=investigate[selected];size=800x300") diff --git a/code/modules/admin/admin_pda_message.dm b/code/modules/admin/admin_pda_message.dm index 44ca86f893ec7..c1c4fef0b57c4 100644 --- a/code/modules/admin/admin_pda_message.dm +++ b/code/modules/admin/admin_pda_message.dm @@ -1,12 +1,6 @@ -///Allows an admin to send messages on PDA -/client/proc/message_pda() - set name = "PDA Message" - set category = "Admin.Events" - if(!holder || !check_rights(R_ADMIN)) - return - - holder.message_pda() +ADMIN_VERB(message_pda, R_ADMIN, "PDA Message", "Send a message to a user's PDA.", ADMIN_CATEGORY_EVENTS) + user.holder.message_pda() ///Opens up the PDA Message Panel /datum/admins/proc/message_pda() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 7864b3d732900..0f7d7a3f39b30 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -1,468 +1,103 @@ -//admin verb groups - They can overlap if you so wish. Only one of each verb will exist in the verbs list regardless -//the procs are cause you can't put the comments in the GLOB var define -GLOBAL_LIST_INIT(admin_verbs_default, world.AVerbsDefault()) -GLOBAL_PROTECT(admin_verbs_default) -/world/proc/AVerbsDefault() - return list( - /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ - /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ - /client/proc/cmd_admin_say, /*admin-only ooc chat*/ - /client/proc/deadmin, /*destroys our own admin datum so we can play as a regular player*/ - /client/proc/debugstatpanel, - /client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/ - /client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/ - /client/proc/fix_air, /*resets air in designated radius to its default atmos composition*/ - /client/proc/hide_verbs, /*hides all our adminverbs*/ - /client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/ - /client/proc/mark_datum_mapview, - /client/proc/reestablish_db_connection, /*reattempt a connection to the database*/ - /client/proc/reload_admins, - /client/proc/requests, - /client/proc/secrets, - /client/proc/stop_sounds, - /client/proc/tag_datum_mapview, - ) -GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin()) -GLOBAL_PROTECT(admin_verbs_admin) -/world/proc/AVerbsAdmin() - return list( -// Admin datums - /datum/admins/proc/access_news_network, /*allows access of newscasters*/ - /datum/admins/proc/announce, /*priority announce something to all clients.*/ - /datum/admins/proc/display_tags, - /datum/admins/proc/fishing_calculator, - /datum/admins/proc/known_alts_panel, - /datum/admins/proc/show_lag_switch_panel, - /datum/admins/proc/open_borgopanel, - /datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */ - /datum/admins/proc/paintings_manager, - /datum/admins/proc/set_admin_notice, /*announcement all clients see when joining the server.*/ - /datum/admins/proc/show_player_panel, /*shows an interface for individual players, with various links (links require additional flags*/ - /datum/admins/proc/toggleenter, /*toggles whether people can join the current game*/ - /datum/admins/proc/toggleguests, /*toggles whether guests can join the current game*/ - /datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/ - /datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/ - /datum/admins/proc/trophy_manager, - /datum/admins/proc/view_all_circuits, - /datum/verbs/menu/Admin/verb/playerpanel, /* It isn't /datum/admin but it fits no less */ - /datum/admins/proc/change_shuttle_events, //allows us to change the shuttle events - /datum/admins/proc/reset_tram, //tram related admin actions -// Client procs - /client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/ - /client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcom*/ - /client/proc/admin_disable_shuttle, /*allows us to disable the emergency shuttle admin-wise so that it cannot be called*/ - /client/proc/admin_enable_shuttle, /*undoes the above*/ - /client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/ - /client/proc/admin_hostile_environment, /*Allows admins to prevent the emergency shuttle from leaving, also lets admins clear hostile environments if theres one stuck*/ - /client/proc/centcom_podlauncher,/*Open a window to launch a Supplypod and configure it or it's contents*/ - /client/proc/check_ai_laws, /*shows AI and borg laws*/ - /client/proc/check_antagonists, /*shows all antags*/ - /client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/ - /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */ - /client/proc/cmd_admin_create_centcom_report, - /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ - /client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/ - /client/proc/cmd_admin_headset_message, /*send a message to somebody through their headset as CentCom*/ - /client/proc/cmd_admin_local_narrate, /*sends text to all mobs within view of atom*/ - /client/proc/cmd_admin_subtle_message, /*send a message to somebody as a 'voice in their head'*/ - /client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/ - /client/proc/cmd_change_command_name, - /client/proc/create_mob_worm, - /client/proc/fax_panel, /*send a paper to fax*/ - /client/proc/force_load_lazy_template, - /client/proc/game_panel, /*game panel, allows to change game-mode etc*/ - /client/proc/Getmob, /*teleports a mob to our location*/ - /client/proc/Getkey, /*teleports a mob with a certain ckey to our location*/ - /client/proc/getserverlogs, /*for accessing server logs*/ - /client/proc/getcurrentlogs, /*for accessing server logs for the current round*/ - /client/proc/ghost_pool_protection, /*opens a menu for toggling ghost roles*/ - /client/proc/invisimin, /*allows our mob to go invisible/visible*/ - /client/proc/jumptoarea, - /client/proc/jumptokey, /*allows us to jump to the location of a mob with a certain ckey*/ - /client/proc/jumptomob, /*allows us to jump to a specific mob*/ - /client/proc/jumptoturf, /*allows us to jump to a specific turf*/ - /client/proc/jumptocoord, /*we ghost and jump to a coordinate*/ - /client/proc/list_bombers, - /client/proc/list_dna, - /client/proc/list_fingerprints, - /client/proc/list_law_changes, - /client/proc/list_signalers, - /client/proc/manage_sect, /*manage chaplain religious sect*/ - /client/proc/message_pda, /*send a message to somebody on PDA*/ - /client/proc/respawn_character, - /client/proc/show_manifest, - /client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/ - /client/proc/toggle_combo_hud, /* toggle display of the combination pizza antag and taco sci/med/eng hud */ - /client/proc/toggle_view_range, /*changes how far we can see*/ - /client/proc/cmd_admin_law_panel, - /client/proc/log_viewer_new, - /client/proc/player_ticket_history, - ) -GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/ban_panel, /client/proc/stickybanpanel, /client/proc/library_control)) -GLOBAL_PROTECT(admin_verbs_ban) -GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_direct_mob_sound, /client/proc/play_sound, /client/proc/set_round_end_sound)) -GLOBAL_PROTECT(admin_verbs_sounds) -GLOBAL_LIST_INIT(admin_verbs_fun, list( -// Admin datums - /datum/admins/proc/station_traits_panel, -// Client procs - /client/proc/admin_away, - /client/proc/add_marked_mob_ability, - /client/proc/admin_change_sec_level, - /client/proc/cinematic, - /client/proc/cmd_admin_add_freeform_ai_law, - /client/proc/cmd_admin_gib_self, - /client/proc/cmd_select_equipment, - /client/proc/command_report_footnote, - /client/proc/delay_command_report, - /client/proc/drop_bomb, - /client/proc/drop_dynex_bomb, - /client/proc/forceEvent, - /client/proc/mass_zombie_cure, - /client/proc/mass_zombie_infection, - /client/proc/object_say, - /client/proc/polymorph_all, - /client/proc/remove_marked_mob_ability, - /client/proc/reset_ooc, - /client/proc/run_weather, - /client/proc/set_dynex_scale, - /client/proc/set_ooc, - /client/proc/show_tip, - /client/proc/smite, - /client/proc/summon_ert, - /client/proc/toggle_nuke, - /client/proc/toggle_random_events, - )) -GLOBAL_PROTECT(admin_verbs_fun) -GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character, /datum/admins/proc/beaker_panel)) -GLOBAL_PROTECT(admin_verbs_spawn) -GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer()) -GLOBAL_PROTECT(admin_verbs_server) -/world/proc/AVerbsServer() - return list( -// Admin datums - /datum/admins/proc/delay, - /datum/admins/proc/delay_round_end, - /datum/admins/proc/end_round, - /datum/admins/proc/restart, - /datum/admins/proc/startnow, - /datum/admins/proc/toggleaban, - /datum/admins/proc/toggleAI, -// Client procs - /client/proc/adminchangemap, - /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ - /client/proc/cmd_debug_del_all, - /client/proc/cmd_debug_force_del_all, - /client/proc/cmd_debug_hard_del_all, - /client/proc/everyone_random, - /client/proc/forcerandomrotate, - /client/proc/generate_job_config, - /client/proc/panicbunker, - /client/proc/toggle_cdn, - /client/proc/toggle_hub, - /client/proc/toggle_interviews, - /client/proc/toggle_random_events, - ) -GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug()) -GLOBAL_PROTECT(admin_verbs_debug) -/world/proc/AVerbsDebug() - return list( - #ifdef TESTING /* Keep these at the top to not make the list look fugly */ - /client/proc/check_missing_sprites, - #endif - /proc/machine_upgrade, - /datum/admins/proc/create_or_modify_area, - /client/proc/adventure_manager, - /client/proc/atmos_control, - /client/proc/callproc, - /client/proc/callproc_datum, - /client/proc/check_bomb_impacts, - /client/proc/check_timer_sources, - /client/proc/clear_dynamic_transit, - /client/proc/cmd_admin_debug_traitor_objectives, - /client/proc/cmd_admin_delete, - /client/proc/cmd_admin_list_open_jobs, - /client/proc/cmd_admin_toggle_fov, - /client/proc/cmd_debug_del_all, - /client/proc/cmd_debug_force_del_all, - /client/proc/cmd_debug_hard_del_all, - /client/proc/cmd_debug_make_powernets, - /client/proc/cmd_debug_mob_lists, - /client/proc/cmd_display_del_log, - /client/proc/cmd_display_init_log, - /client/proc/cmd_display_overlay_log, - /client/proc/Debug2, - /client/proc/debug_controller, - /client/proc/debug_hallucination_weighted_list_per_type, - /client/proc/debug_huds, - /client/proc/debugNatureMapGenerator, - /client/proc/debug_plane_masters, - /client/proc/debug_spell_requirements, - /client/proc/display_sendmaps, - /client/proc/enable_mapping_verbs, - /client/proc/generate_wikichem_list, - /client/proc/get_dynex_power, /*debug verbs for dynex explosions.*/ - /client/proc/get_dynex_range, /*debug verbs for dynex explosions.*/ - /client/proc/jump_to_ruin, - /client/proc/load_circuit, - /client/proc/map_export, - /client/proc/map_template_load, - /client/proc/map_template_upload, - /client/proc/modify_goals, - /client/proc/open_colorblind_test, - /client/proc/open_lua_editor, - /client/proc/outfit_manager, - /client/proc/populate_world, - /client/proc/pump_random_event, - /client/proc/print_cards, - /client/proc/reestablish_tts_connection, - /client/proc/reload_cards, - /client/proc/reload_configuration, - /client/proc/restart_controller, - /client/proc/run_empty_query, - /client/proc/SDQL2_query, - /client/proc/set_dynex_scale, - /client/proc/spawn_debug_full_crew, - /client/proc/test_cardpack_distribution, - /client/proc/test_movable_UI, - /client/proc/test_snap_UI, - /client/proc/toggle_cdn, - /client/proc/toggle_medal_disable, - /client/proc/unload_ctf, - /client/proc/validate_cards, - /client/proc/validate_puzzgrids, - /client/proc/GeneratePipeSpritesheet, - /client/proc/view_runtimes, - /client/proc/stop_weather, - ) -GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release)) -GLOBAL_PROTECT(admin_verbs_possess) -GLOBAL_LIST_INIT(admin_verbs_permissions, list(/client/proc/edit_admin_permissions)) -GLOBAL_PROTECT(admin_verbs_permissions) -GLOBAL_LIST_INIT(admin_verbs_poll, list(/client/proc/poll_panel)) -GLOBAL_PROTECT(admin_verbs_poll) - /client/proc/add_admin_verbs() - if(holder) - control_freak = CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS - - var/rights = holder.rank_flags() - add_verb(src, GLOB.admin_verbs_default) - if(rights & R_BUILD) - add_verb(src, /client/proc/togglebuildmodeself) - if(rights & R_ADMIN) - add_verb(src, GLOB.admin_verbs_admin) - if(rights & R_BAN) - add_verb(src, GLOB.admin_verbs_ban) - if(rights & R_FUN) - add_verb(src, GLOB.admin_verbs_fun) - if(rights & R_SERVER) - add_verb(src, GLOB.admin_verbs_server) - if(rights & R_DEBUG) - add_verb(src, GLOB.admin_verbs_debug) - if(rights & R_POSSESS) - add_verb(src, GLOB.admin_verbs_possess) - if(rights & R_PERMISSIONS) - add_verb(src, GLOB.admin_verbs_permissions) - if(rights & R_STEALTH) - add_verb(src, /client/proc/stealth) - if(rights & R_POLL) - add_verb(src, GLOB.admin_verbs_poll) - if(rights & R_SOUND) - add_verb(src, GLOB.admin_verbs_sounds) - if(CONFIG_GET(string/invoke_youtubedl)) - add_verb(src, /client/proc/play_web_sound) - if(rights & R_SPAWN) - add_verb(src, GLOB.admin_verbs_spawn) -#ifdef MAP_TEST - remove_verb(src, /client/proc/enable_mapping_verbs) - add_verb(src, list(/client/proc/disable_mapping_verbs, GLOB.admin_verbs_debug_mapping)) -#endif + control_freak = CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS + SSadmin_verbs.assosciate_admin(src) /client/proc/remove_admin_verbs() - remove_verb(src, list( - GLOB.admin_verbs_default, - /client/proc/togglebuildmodeself, - GLOB.admin_verbs_admin, - GLOB.admin_verbs_ban, - GLOB.admin_verbs_fun, - GLOB.admin_verbs_server, - GLOB.admin_verbs_debug, - GLOB.admin_verbs_possess, - GLOB.admin_verbs_permissions, - /client/proc/stealth, - GLOB.admin_verbs_poll, - GLOB.admin_verbs_sounds, - /client/proc/play_web_sound, - GLOB.admin_verbs_spawn, - /*Debug verbs added by "show debug verbs"*/ - GLOB.admin_verbs_debug_mapping, - /client/proc/disable_mapping_verbs, - /client/proc/readmin - )) - -/client/proc/hide_verbs() - set name = "Adminverbs - Hide All" - set category = "Admin" - - remove_admin_verbs() - add_verb(src, /client/proc/show_verbs) - - to_chat(src, span_interface("Almost all of your adminverbs have been hidden."), confidential = TRUE) - BLACKBOX_LOG_ADMIN_VERB("Hide All Adminverbs") - return - -/client/proc/show_verbs() - set name = "Adminverbs - Show" - set category = "Admin" - - remove_verb(src, /client/proc/show_verbs) - add_admin_verbs() - - to_chat(src, span_interface("All of your adminverbs are now visible."), confidential = TRUE) - BLACKBOX_LOG_ADMIN_VERB("Show Adminverbs") - + control_freak = initial(control_freak) + SSadmin_verbs.deassosciate_admin(src) +ADMIN_VERB(hide_verbs, R_NONE, "Adminverbs - Hide All", "Hide most of your admin verbs.", ADMIN_CATEGORY_MAIN) + user.remove_admin_verbs() + add_verb(user, /client/proc/show_verbs) + to_chat(user, span_interface("Almost all of your adminverbs have been hidden."), confidential = TRUE) + BLACKBOX_LOG_ADMIN_VERB("Hide All Adminverbs") -/client/proc/admin_ghost() - set category = "Admin.Game" - set name = "Aghost" - if(!holder) - return +ADMIN_VERB(admin_ghost, R_ADMIN, "AGhost", "Become a ghost without DNR.", ADMIN_CATEGORY_GAME) . = TRUE - if(isobserver(mob)) + if(isobserver(user.mob)) //re-enter - var/mob/dead/observer/ghost = mob + var/mob/dead/observer/ghost = user.mob if(!ghost.mind || !ghost.mind.current) //won't do anything if there is no body return FALSE if(!ghost.can_reenter_corpse) - log_admin("[key_name(usr)] re-entered corpse") - message_admins("[key_name_admin(usr)] re-entered corpse") + log_admin("[key_name(user)] re-entered corpse") + message_admins("[key_name_admin(user)] re-entered corpse") ghost.can_reenter_corpse = 1 //force re-entering even when otherwise not possible ghost.reenter_corpse() BLACKBOX_LOG_ADMIN_VERB("Admin Reenter") - else if(isnewplayer(mob)) - to_chat(src, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.", confidential = TRUE) + else if(isnewplayer(user.mob)) + to_chat(user, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.", confidential = TRUE) return FALSE else //ghostize - log_admin("[key_name(usr)] admin ghosted.") - message_admins("[key_name_admin(usr)] admin ghosted.") - var/mob/body = mob + log_admin("[key_name(user)] admin ghosted.") + message_admins("[key_name_admin(user)] admin ghosted.") + var/mob/body = user.mob body.ghostize(TRUE) - init_verbs() + user.init_verbs() if(body && !body.key) - body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus + body.key = "@[user.key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus BLACKBOX_LOG_ADMIN_VERB("Admin Ghost") -/client/proc/invisimin() - set name = "Invisimin" - set category = "Admin.Game" - set desc = "Toggles ghost-like invisibility (Don't abuse this)" - - if(isnull(holder) || isnull(mob)) +ADMIN_VERB(invisimin, R_ADMIN, "Invisimin", "Toggles ghost-like invisibility.", ADMIN_CATEGORY_GAME) + if(HAS_TRAIT(user.mob, TRAIT_INVISIMIN)) + REMOVE_TRAIT(user.mob, TRAIT_INVISIMIN, ADMIN_TRAIT) + user.mob.add_to_all_human_data_huds() + user.mob.RemoveInvisibility(INVISIBILITY_SOURCE_INVISIMIN) + to_chat(user, span_adminnotice(span_bold("Invisimin off. Invisibility reset.")), confidential = TRUE) return - if(HAS_TRAIT(mob, TRAIT_INVISIMIN)) - REMOVE_TRAIT(mob, TRAIT_INVISIMIN, ADMIN_TRAIT) - mob.add_to_all_human_data_huds() - mob.RemoveInvisibility(INVISIBILITY_SOURCE_INVISIMIN) - to_chat(mob, span_adminnotice(span_bold("Invisimin off. Invisibility reset.")), confidential = TRUE) - return + ADD_TRAIT(user.mob, TRAIT_INVISIMIN, ADMIN_TRAIT) + user.mob.remove_from_all_data_huds() + user.mob.SetInvisibility(INVISIBILITY_OBSERVER, INVISIBILITY_SOURCE_INVISIMIN, INVISIBILITY_PRIORITY_ADMIN) + to_chat(user, span_adminnotice(span_bold("Invisimin on. You are now as invisible as a ghost.")), confidential = TRUE) - ADD_TRAIT(mob, TRAIT_INVISIMIN, ADMIN_TRAIT) - mob.remove_from_all_data_huds() - mob.SetInvisibility(INVISIBILITY_OBSERVER, INVISIBILITY_SOURCE_INVISIMIN, INVISIBILITY_PRIORITY_ADMIN) - to_chat(mob, span_adminnotice(span_bold("Invisimin on. You are now as invisible as a ghost.")), confidential = TRUE) - -/client/proc/check_antagonists() - set name = "Check Antagonists" - set category = "Admin.Game" - if(holder) - holder.check_antagonists() - log_admin("[key_name(usr)] checked antagonists.") //for tsar~ - if(!isobserver(usr) && SSticker.HasRoundStarted()) - message_admins("[key_name_admin(usr)] checked antagonists.") +ADMIN_VERB(check_antagonists, R_ADMIN, "Check Antagonists", "See all antagonists for the round.", ADMIN_CATEGORY_GAME) + user.holder.check_antagonists() + log_admin("[key_name(user)] checked antagonists.") + if(!isobserver(user.mob) && SSticker.HasRoundStarted()) + message_admins("[key_name_admin(user)] checked antagonists.") BLACKBOX_LOG_ADMIN_VERB("Check Antagonists") -/client/proc/list_bombers() - set name = "List Bombers" - set category = "Admin.Game" - if(!holder) - return - holder.list_bombers() +ADMIN_VERB(list_bombers, R_ADMIN, "List Bombers", "Look at all bombs and their likely culprit.", ADMIN_CATEGORY_GAME) + user.holder.list_bombers() BLACKBOX_LOG_ADMIN_VERB("List Bombers") -/client/proc/list_signalers() - set name = "List Signalers" - set category = "Admin.Game" - if(!holder) - return - holder.list_signalers() +ADMIN_VERB(list_signalers, R_ADMIN, "List Signalers", "View all signalers.", ADMIN_CATEGORY_GAME) + user.holder.list_signalers() BLACKBOX_LOG_ADMIN_VERB("List Signalers") -/client/proc/list_law_changes() - set name = "List Law Changes" - set category = "Debug" - if(!holder) - return - holder.list_law_changes() +ADMIN_VERB(list_law_changes, R_ADMIN, "List Law Changes", "View all AI law changes.", ADMIN_CATEGORY_DEBUG) + user.holder.list_law_changes() BLACKBOX_LOG_ADMIN_VERB("List Law Changes") -/client/proc/show_manifest() - set name = "Show Manifest" - set category = "Debug" - if(!holder) - return - holder.show_manifest() +ADMIN_VERB(show_manifest, R_ADMIN, "Show Manifest", "View the shift's Manifest.", ADMIN_CATEGORY_DEBUG) + user.holder.show_manifest() BLACKBOX_LOG_ADMIN_VERB("Show Manifest") -/client/proc/list_dna() - set name = "List DNA" - set category = "Debug" - if(!holder) - return - holder.list_dna() +ADMIN_VERB(list_dna, R_ADMIN, "List DNA", "View DNA.", ADMIN_CATEGORY_DEBUG) + user.holder.list_dna() BLACKBOX_LOG_ADMIN_VERB("List DNA") -/client/proc/list_fingerprints() - set name = "List Fingerprints" - set category = "Debug" - if(!holder) - return - holder.list_fingerprints() +ADMIN_VERB(list_fingerprints, R_ADMIN, "List Fingerprints", "View fingerprints.", ADMIN_CATEGORY_DEBUG) + user.holder.list_fingerprints() BLACKBOX_LOG_ADMIN_VERB("List Fingerprints") -/client/proc/ban_panel() - set name = "Banning Panel" - set category = "Admin" - if(!check_rights(R_BAN)) - return - holder.ban_panel() +ADMIN_VERB(ban_panel, R_BAN, "Banning Panel", "Ban players here.", ADMIN_CATEGORY_MAIN) + user.holder.ban_panel() BLACKBOX_LOG_ADMIN_VERB("Banning Panel") -/client/proc/unban_panel() - set name = "Unbanning Panel" - set category = "Admin" - if(!check_rights(R_BAN)) - return - holder.unban_panel() +ADMIN_VERB(unban_panel, R_BAN, "Unbanning Panel", "Unban players here.", ADMIN_CATEGORY_MAIN) + user.holder.unban_panel() BLACKBOX_LOG_ADMIN_VERB("Unbanning Panel") -/client/proc/game_panel() - set name = "Game Panel" - set category = "Admin.Game" - if(holder) - holder.Game() +ADMIN_VERB(game_panel, R_ADMIN, "Game Panel", "Look at the state of the game.", ADMIN_CATEGORY_GAME) + user.holder.Game() BLACKBOX_LOG_ADMIN_VERB("Game Panel") -/client/proc/poll_panel() - set name = "Server Poll Management" - set category = "Admin" - if(!check_rights(R_POLL)) - return - holder.poll_list_panel() +ADMIN_VERB(poll_panel, R_POLL, "Server Poll Management", "View and manage polls.", ADMIN_CATEGORY_MAIN) + user.holder.poll_list_panel() BLACKBOX_LOG_ADMIN_VERB("Server Poll Management") /// Returns this client's stealthed ckey @@ -498,16 +133,11 @@ GLOBAL_PROTECT(admin_verbs_poll) /client/proc/createStealthKey() GLOB.stealthminID["[ckey]"] = generateStealthCkey() -/client/proc/stealth() - set category = "Admin" - set name = "Stealth Mode" - if(!holder) - return - - if(holder.fakekey) - disable_stealth_mode() +ADMIN_VERB(stealth, R_STEALTH, "Stealth Mode", "Toggle stealth.", ADMIN_CATEGORY_MAIN) + if(user.holder.fakekey) + user.disable_stealth_mode() else - enable_stealth_mode() + user.enable_stealth_mode() BLACKBOX_LOG_ADMIN_VERB("Stealth Mode") @@ -552,117 +182,86 @@ GLOBAL_PROTECT(admin_verbs_poll) #undef STEALTH_MODE_TRAIT -/client/proc/drop_bomb() - set category = "Admin.Fun" - set name = "Drop Bomb" - set desc = "Cause an explosion of varying strength at your location." - +ADMIN_VERB(drop_bomb, R_FUN, "Drop Bomb", "Cause an explosion of varying strength at your location", ADMIN_CATEGORY_FUN) var/list/choices = list("Small Bomb (1, 2, 3, 3)", "Medium Bomb (2, 3, 4, 4)", "Big Bomb (3, 5, 7, 5)", "Maxcap", "Custom Bomb") - var/choice = tgui_input_list(src, "What size explosion would you like to produce? NOTE: You can do all this rapidly and in an IC manner (using cruise missiles!) with the Config/Launch Supplypod verb. WARNING: These ignore the maxcap", "Drop Bomb", choices) + var/choice = tgui_input_list(user, "What size explosion would you like to produce? NOTE: You can do all this rapidly and in an IC manner (using cruise missiles!) with the Config/Launch Supplypod verb. WARNING: These ignore the maxcap", "Drop Bomb", choices) if(isnull(choice)) return - var/turf/epicenter = mob.loc + var/turf/epicenter = user.mob.loc switch(choice) if("Small Bomb (1, 2, 3, 3)") - explosion(epicenter, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flash_range = 3, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) + explosion(epicenter, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flash_range = 3, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) if("Medium Bomb (2, 3, 4, 4)") - explosion(epicenter, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4, flash_range = 4, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) + explosion(epicenter, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4, flash_range = 4, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) if("Big Bomb (3, 5, 7, 5)") - explosion(epicenter, devastation_range = 3, heavy_impact_range = 5, light_impact_range = 7, flash_range = 5, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) + explosion(epicenter, devastation_range = 3, heavy_impact_range = 5, light_impact_range = 7, flash_range = 5, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) if("Maxcap") - explosion(epicenter, devastation_range = GLOB.MAX_EX_DEVESTATION_RANGE, heavy_impact_range = GLOB.MAX_EX_HEAVY_RANGE, light_impact_range = GLOB.MAX_EX_LIGHT_RANGE, flash_range = GLOB.MAX_EX_FLASH_RANGE, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) + explosion(epicenter, devastation_range = GLOB.MAX_EX_DEVESTATION_RANGE, heavy_impact_range = GLOB.MAX_EX_HEAVY_RANGE, light_impact_range = GLOB.MAX_EX_LIGHT_RANGE, flash_range = GLOB.MAX_EX_FLASH_RANGE, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) if("Custom Bomb") - var/range_devastation = input("Devastation range (in tiles):") as null|num + var/range_devastation = input(user, "Devastation range (in tiles):") as null|num if(range_devastation == null) return - var/range_heavy = input("Heavy impact range (in tiles):") as null|num + var/range_heavy = input(user, "Heavy impact range (in tiles):") as null|num if(range_heavy == null) return - var/range_light = input("Light impact range (in tiles):") as null|num + var/range_light = input(user, "Light impact range (in tiles):") as null|num if(range_light == null) return - var/range_flash = input("Flash range (in tiles):") as null|num + var/range_flash = input(user, "Flash range (in tiles):") as null|num if(range_flash == null) return if(range_devastation > GLOB.MAX_EX_DEVESTATION_RANGE || range_heavy > GLOB.MAX_EX_HEAVY_RANGE || range_light > GLOB.MAX_EX_LIGHT_RANGE || range_flash > GLOB.MAX_EX_FLASH_RANGE) - if(tgui_alert(usr, "Bomb is bigger than the maxcap. Continue?",,list("Yes","No")) != "Yes") + if(tgui_alert(user, "Bomb is bigger than the maxcap. Continue?",,list("Yes","No")) != "Yes") return - epicenter = mob.loc //We need to reupdate as they may have moved again - explosion(epicenter, devastation_range = range_devastation, heavy_impact_range = range_heavy, light_impact_range = range_light, flash_range = range_flash, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) - message_admins("[ADMIN_LOOKUPFLW(usr)] creating an admin explosion at [epicenter.loc].") - log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc].") + epicenter = get_turf(user.mob) //We need to reupdate as they may have moved again + explosion(epicenter, devastation_range = range_devastation, heavy_impact_range = range_heavy, light_impact_range = range_light, flash_range = range_flash, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) + message_admins("[ADMIN_LOOKUPFLW(user.mob)] creating an admin explosion at [epicenter.loc].") + log_admin("[key_name(user)] created an admin explosion at [epicenter.loc].") BLACKBOX_LOG_ADMIN_VERB("Drop Bomb") -/client/proc/drop_dynex_bomb() - set category = "Admin.Fun" - set name = "Drop DynEx Bomb" - set desc = "Cause an explosion of varying strength at your location." - - var/ex_power = input("Explosive Power:") as null|num - var/turf/epicenter = mob.loc - if(ex_power && epicenter) - dyn_explosion(epicenter, ex_power) - message_admins("[ADMIN_LOOKUPFLW(usr)] creating an admin explosion at [epicenter.loc].") - log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc].") - BLACKBOX_LOG_ADMIN_VERB("Drop Dynamic Bomb") - -/client/proc/get_dynex_range() - set category = "Debug" - set name = "Get DynEx Range" - set desc = "Get the estimated range of a bomb, using explosive power." - - var/ex_power = input("Explosive Power:") as null|num +ADMIN_VERB(drop_bomb_dynex, R_FUN, "Drop DynEx Bomb", "Cause an explosion of varying strength at your location.", ADMIN_CATEGORY_FUN) + var/ex_power = input(user, "Explosive Power:") as null|num + var/turf/epicenter = get_turf(user.mob) + if(!ex_power || !epicenter) + return + dyn_explosion(epicenter, ex_power) + message_admins("[ADMIN_LOOKUPFLW(user.mob)] creating an admin explosion at [epicenter.loc].") + log_admin("[key_name(user)] created an admin explosion at [epicenter.loc].") + BLACKBOX_LOG_ADMIN_VERB("Drop Dynamic Bomb") + +ADMIN_VERB(get_dynex_range, R_FUN, "Get DynEx Range", "Get the estimated range of a bomb using explosive power.", ADMIN_CATEGORY_DEBUG) + var/ex_power = input(user, "Explosive Power:") as null|num if (isnull(ex_power)) return var/range = round((2 * ex_power)**GLOB.DYN_EX_SCALE) - to_chat(usr, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])", confidential = TRUE) - -/client/proc/get_dynex_power() - set category = "Debug" - set name = "Get DynEx Power" - set desc = "Get the estimated required power of a bomb, to reach a specific range." + to_chat(user, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])", confidential = TRUE) - var/ex_range = input("Light Explosion Range:") as null|num +ADMIN_VERB(get_dynex_power, R_FUN, "Get DynEx Power", "Get the estimated required power of a bomb to reach the given range.", ADMIN_CATEGORY_DEBUG) + var/ex_range = input(user, "Light Explosion Range:") as null|num if (isnull(ex_range)) return var/power = (0.5 * ex_range)**(1/GLOB.DYN_EX_SCALE) - to_chat(usr, "Estimated Explosive Power: [power]", confidential = TRUE) - -/client/proc/set_dynex_scale() - set category = "Debug" - set name = "Set DynEx Scale" - set desc = "Set the scale multiplier of dynex explosions. The default is 0.5." + to_chat(user, "Estimated Explosive Power: [power]", confidential = TRUE) - var/ex_scale = input("New DynEx Scale:") as null|num +ADMIN_VERB(set_dynex_scale, R_FUN, "Set DynEx Scale", "Set the scale multiplier on dynex explosions. Default 0.5.", ADMIN_CATEGORY_DEBUG) + var/ex_scale = input(user, "New DynEx Scale:") as null|num if(!ex_scale) return GLOB.DYN_EX_SCALE = ex_scale - log_admin("[key_name(usr)] has modified Dynamic Explosion Scale: [ex_scale]") - message_admins("[key_name_admin(usr)] has modified Dynamic Explosion Scale: [ex_scale]") + log_admin("[key_name(user)] has modified Dynamic Explosion Scale: [ex_scale]") + message_admins("[key_name_admin(user)] has modified Dynamic Explosion Scale: [ex_scale]") -/client/proc/atmos_control() - set name = "Atmos Control Panel" - set category = "Debug" - if(!check_rights(R_DEBUG)) - return - SSair.ui_interact(mob) +ADMIN_VERB(atmos_control, R_DEBUG|R_SERVER, "Atmos Control Panel", "Open the atmospherics control panel.", ADMIN_CATEGORY_DEBUG) + SSair.ui_interact(user.mob) -/client/proc/reload_cards() - set name = "Reload Cards" - set category = "Debug" - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB(reload_cards, R_DEBUG, "Reload Cards", "Reload all TCG cards.", ADMIN_CATEGORY_DEBUG) if(!SStrading_card_game.loaded) message_admins("The card subsystem is not currently loaded") return SStrading_card_game.reloadAllCardFiles() -/client/proc/validate_cards() - set name = "Validate Cards" - set category = "Debug" - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB(validate_cards, R_DEBUG, "Validate Cards", "Validate the card settings.", ADMIN_CATEGORY_DEBUG) if(!SStrading_card_game.loaded) message_admins("The card subsystem is not currently loaded") return @@ -673,66 +272,55 @@ GLOBAL_PROTECT(admin_verbs_poll) else message_admins("No errors found in card rarities or overrides.") -/client/proc/test_cardpack_distribution() - set name = "Test Cardpack Distribution" - set category = "Debug" - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB(test_cardpack_distribution, R_DEBUG, "Test Cardpack Distribution", "Test the distribution of a card pack.", ADMIN_CATEGORY_DEBUG) if(!SStrading_card_game.loaded) message_admins("The card subsystem is not currently loaded") return - var/pack = tgui_input_list(usr, "Which pack should we test?", "You fucked it didn't you", sort_list(SStrading_card_game.card_packs)) + var/pack = tgui_input_list(user, "Which pack should we test?", "You fucked it didn't you", sort_list(SStrading_card_game.card_packs)) if(!pack) return - var/batch_count = tgui_input_number(usr, "How many times should we open it?", "Don't worry, I understand") - var/batch_size = tgui_input_number(usr, "How many cards per batch?", "I hope you remember to check the validation") - var/guar = tgui_input_number(usr, "Should we use the pack's guaranteed rarity? If so, how many?", "We've all been there. Man you should have seen the old system") - + var/batch_count = tgui_input_number(user, "How many times should we open it?", "Don't worry, I understand") + var/batch_size = tgui_input_number(user, "How many cards per batch?", "I hope you remember to check the validation") + var/guar = tgui_input_number(user, "Should we use the pack's guaranteed rarity? If so, how many?", "We've all been there. Man you should have seen the old system") SStrading_card_game.check_card_distribution(pack, batch_size, batch_count, guar) -/client/proc/print_cards() - set name = "Print Cards" - set category = "Debug" +ADMIN_VERB(print_cards, R_DEBUG, "Print Cards", "Print all cards to chat.", ADMIN_CATEGORY_DEBUG) SStrading_card_game.printAllCards() -/client/proc/give_mob_action(mob/ability_recipient in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Give Mob Action" - set desc = "Gives a mob ability to a mob." - +ADMIN_VERB(give_mob_action, R_FUN, "Give Mob Action", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/ability_recipient) var/static/list/all_mob_actions = sort_list(subtypesof(/datum/action/cooldown/mob_cooldown), GLOBAL_PROC_REF(cmp_typepaths_asc)) var/static/list/actions_by_name = list() if (!length(actions_by_name)) for (var/datum/action/cooldown/mob_cooldown as anything in all_mob_actions) actions_by_name["[initial(mob_cooldown.name)] ([mob_cooldown])"] = mob_cooldown - var/ability = tgui_input_list(usr, "Choose an ability", "Ability", actions_by_name) + var/ability = tgui_input_list(user, "Choose an ability", "Ability", actions_by_name) if(isnull(ability)) return var/ability_type = actions_by_name[ability] var/datum/action/cooldown/mob_cooldown/add_ability - var/make_sequence = tgui_alert(usr, "Would you like this action to be a sequence of multiple abilities?", "Sequence Ability", list("Yes", "No")) + var/make_sequence = tgui_alert(user, "Would you like this action to be a sequence of multiple abilities?", "Sequence Ability", list("Yes", "No")) if(make_sequence == "Yes") add_ability = new /datum/action/cooldown/mob_cooldown(ability_recipient) add_ability.sequence_actions = list() while(!isnull(ability_type)) - var/ability_delay = tgui_input_number(usr, "Enter the delay in seconds before the next ability in the sequence is used", "Ability Delay", 2) + var/ability_delay = tgui_input_number(user, "Enter the delay in seconds before the next ability in the sequence is used", "Ability Delay", 2) if(isnull(ability_delay) || ability_delay < 0) ability_delay = 0 add_ability.sequence_actions[ability_type] = ability_delay * 1 SECONDS - ability = tgui_input_list(usr, "Choose a new sequence ability", "Sequence Ability", actions_by_name) + ability = tgui_input_list(user, "Choose a new sequence ability", "Sequence Ability", actions_by_name) ability_type = actions_by_name[ability] - var/ability_cooldown = tgui_input_number(usr, "Enter the sequence abilities cooldown in seconds", "Ability Cooldown", 2) + var/ability_cooldown = tgui_input_number(user, "Enter the sequence abilities cooldown in seconds", "Ability Cooldown", 2) if(isnull(ability_cooldown) || ability_cooldown < 0) ability_cooldown = 2 add_ability.cooldown_time = ability_cooldown * 1 SECONDS - var/ability_melee_cooldown = tgui_input_number(usr, "Enter the abilities melee cooldown in seconds", "Melee Cooldown", 2) + var/ability_melee_cooldown = tgui_input_number(user, "Enter the abilities melee cooldown in seconds", "Melee Cooldown", 2) if(isnull(ability_melee_cooldown) || ability_melee_cooldown < 0) ability_melee_cooldown = 2 add_ability.melee_cooldown_time = ability_melee_cooldown * 1 SECONDS - add_ability.name = tgui_input_text(usr, "Choose ability name", "Ability name", "Generic Ability") + add_ability.name = tgui_input_text(user, "Choose ability name", "Ability name", "Generic Ability") add_ability.create_sequence_actions() else add_ability = new ability_type(ability_recipient) @@ -741,15 +329,11 @@ GLOBAL_PROTECT(admin_verbs_poll) return add_ability.Grant(ability_recipient) - message_admins("[key_name_admin(usr)] added mob ability [ability_type] to mob [ability_recipient].") - log_admin("[key_name(usr)] added mob ability [ability_type] to mob [ability_recipient].") + message_admins("[key_name_admin(user)] added mob ability [ability_type] to mob [ability_recipient].") + log_admin("[key_name(user)] added mob ability [ability_type] to mob [ability_recipient].") BLACKBOX_LOG_ADMIN_VERB("Add Mob Ability") -/client/proc/remove_mob_action(mob/removal_target in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Remove Mob Action" - set desc = "Remove a special ability from the selected mob." - +ADMIN_VERB(remove_mob_action, R_FUN, "Remove Mob Action", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/removal_target) var/list/target_abilities = list() for(var/datum/action/cooldown/mob_cooldown/ability in removal_target.actions) target_abilities[ability.name] = ability @@ -757,7 +341,7 @@ GLOBAL_PROTECT(admin_verbs_poll) if(!length(target_abilities)) return - var/chosen_ability = tgui_input_list(usr, "Choose the spell to remove from [removal_target]", "Depower", sort_list(target_abilities)) + var/chosen_ability = tgui_input_list(user, "Choose the spell to remove from [removal_target]", "Depower", sort_list(target_abilities)) if(isnull(chosen_ability)) return var/datum/action/cooldown/mob_cooldown/to_remove = target_abilities[chosen_ability] @@ -765,20 +349,16 @@ GLOBAL_PROTECT(admin_verbs_poll) return qdel(to_remove) - log_admin("[key_name(usr)] removed the ability [chosen_ability] from [key_name(removal_target)].") - message_admins("[key_name_admin(usr)] removed the ability [chosen_ability] from [key_name_admin(removal_target)].") + log_admin("[key_name(user)] removed the ability [chosen_ability] from [key_name(removal_target)].") + message_admins("[key_name_admin(user)] removed the ability [chosen_ability] from [key_name_admin(removal_target)].") BLACKBOX_LOG_ADMIN_VERB("Remove Mob Ability") -/client/proc/give_spell(mob/spell_recipient in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Give Spell" - set desc = "Gives a spell to a mob." - - var/which = tgui_alert(usr, "Chose by name or by type path?", "Chose option", list("Name", "Typepath")) +ADMIN_VERB(give_spell, R_FUN, "Give Spell", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/spell_recipient) + var/which = tgui_alert(user, "Chose by name or by type path?", "Chose option", list("Name", "Typepath")) if(!which) return if(QDELETED(spell_recipient)) - to_chat(usr, span_warning("The intended spell recipient no longer exists.")) + to_chat(user, span_warning("The intended spell recipient no longer exists.")) return var/list/spell_list = list() @@ -792,22 +372,22 @@ GLOBAL_PROTECT(admin_verbs_poll) else spell_list += to_add - var/chosen_spell = tgui_input_list(usr, "Choose the spell to give to [spell_recipient]", "ABRAKADABRA", sort_list(spell_list)) + var/chosen_spell = tgui_input_list(user, "Choose the spell to give to [spell_recipient]", "ABRAKADABRA", sort_list(spell_list)) if(isnull(chosen_spell)) return var/datum/action/cooldown/spell/spell_path = which == "Typepath" ? chosen_spell : spell_list[chosen_spell] if(!ispath(spell_path)) return - var/robeless = (tgui_alert(usr, "Would you like to force this spell to be robeless?", "Robeless Casting?", list("Force Robeless", "Use Spell Setting")) == "Force Robeless") + var/robeless = (tgui_alert(user, "Would you like to force this spell to be robeless?", "Robeless Casting?", list("Force Robeless", "Use Spell Setting")) == "Force Robeless") if(QDELETED(spell_recipient)) - to_chat(usr, span_warning("The intended spell recipient no longer exists.")) + to_chat(user, span_warning("The intended spell recipient no longer exists.")) return BLACKBOX_LOG_ADMIN_VERB("Give Spell") - log_admin("[key_name(usr)] gave [key_name(spell_recipient)] the spell [chosen_spell][robeless ? " (Forced robeless)" : ""].") - message_admins("[key_name_admin(usr)] gave [key_name_admin(spell_recipient)] the spell [chosen_spell][robeless ? " (Forced robeless)" : ""].") + log_admin("[key_name(user)] gave [key_name(spell_recipient)] the spell [chosen_spell][robeless ? " (Forced robeless)" : ""].") + message_admins("[key_name_admin(user)] gave [key_name_admin(spell_recipient)] the spell [chosen_spell][robeless ? " (Forced robeless)" : ""].") var/datum/action/cooldown/spell/new_spell = new spell_path(spell_recipient.mind || spell_recipient) @@ -817,14 +397,10 @@ GLOBAL_PROTECT(admin_verbs_poll) new_spell.Grant(spell_recipient) if(!spell_recipient.mind) - to_chat(usr, span_userdanger("Spells given to mindless mobs will belong to the mob and not their mind, \ + to_chat(user, span_userdanger("Spells given to mindless mobs will belong to the mob and not their mind, \ and as such will not be transferred if their mind changes body (Such as from Mindswap).")) -/client/proc/remove_spell(mob/removal_target in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Remove Spell" - set desc = "Remove a spell from the selected mob." - +ADMIN_VERB(remove_spell, R_FUN, "Remove Spell", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/removal_target) var/list/target_spell_list = list() for(var/datum/action/cooldown/spell/spell in removal_target.actions) target_spell_list[spell.name] = spell @@ -832,7 +408,7 @@ GLOBAL_PROTECT(admin_verbs_poll) if(!length(target_spell_list)) return - var/chosen_spell = tgui_input_list(usr, "Choose the spell to remove from [removal_target]", "ABRAKADABRA", sort_list(target_spell_list)) + var/chosen_spell = tgui_input_list(user, "Choose the spell to remove from [removal_target]", "ABRAKADABRA", sort_list(target_spell_list)) if(isnull(chosen_spell)) return var/datum/action/cooldown/spell/to_remove = target_spell_list[chosen_spell] @@ -840,58 +416,39 @@ GLOBAL_PROTECT(admin_verbs_poll) return qdel(to_remove) - log_admin("[key_name(usr)] removed the spell [chosen_spell] from [key_name(removal_target)].") - message_admins("[key_name_admin(usr)] removed the spell [chosen_spell] from [key_name_admin(removal_target)].") + log_admin("[key_name(user)] removed the spell [chosen_spell] from [key_name(removal_target)].") + message_admins("[key_name_admin(user)] removed the spell [chosen_spell] from [key_name_admin(removal_target)].") BLACKBOX_LOG_ADMIN_VERB("Remove Spell") -/client/proc/give_disease(mob/living/T in GLOB.mob_living_list) - set category = "Admin.Fun" - set name = "Give Disease" - set desc = "Gives a Disease to a mob." - if(!istype(T)) - to_chat(src, span_notice("You can only give a disease to a mob of type /mob/living."), confidential = TRUE) - return - var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in sort_list(SSdisease.diseases, GLOBAL_PROC_REF(cmp_typepaths_asc)) +ADMIN_VERB(give_disease, R_FUN, "Give Disease", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/living/victim) + var/datum/disease/D = input(user, "Choose the disease to give to that guy", "ACHOO") as null|anything in sort_list(SSdisease.diseases, GLOBAL_PROC_REF(cmp_typepaths_asc)) if(!D) return - T.ForceContractDisease(new D, FALSE, TRUE) + victim.ForceContractDisease(new D, FALSE, TRUE) BLACKBOX_LOG_ADMIN_VERB("Give Disease") - log_admin("[key_name(usr)] gave [key_name(T)] the disease [D].") - message_admins(span_adminnotice("[key_name_admin(usr)] gave [key_name_admin(T)] the disease [D].")) - -/client/proc/object_say(obj/O in world) - set category = "Admin.Events" - set name = "OSay" - set desc = "Makes an object say something." - var/message = tgui_input_text(usr, "What do you want the message to be?", "Make Sound", encode = FALSE) + log_admin("[key_name(user)] gave [key_name(victim)] the disease [D].") + message_admins(span_adminnotice("[key_name_admin(user)] gave [key_name_admin(victim)] the disease [D].")) + +ADMIN_VERB_AND_CONTEXT_MENU(object_say, R_FUN, "OSay", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, obj/speaker in world) + var/message = tgui_input_text(user, "What do you want the message to be?", "Make Sound", encode = FALSE) if(!message) return - O.say(message, sanitize = FALSE) - log_admin("[key_name(usr)] made [O] at [AREACOORD(O)] say \"[message]\"") - message_admins(span_adminnotice("[key_name_admin(usr)] made [O] at [AREACOORD(O)]. say \"[message]\"")) + speaker.say(message, sanitize = FALSE) + log_admin("[key_name(user)] made [speaker] at [AREACOORD(speaker)] say \"[message]\"") + message_admins(span_adminnotice("[key_name_admin(user)] made [speaker] at [AREACOORD(speaker)]. say \"[message]\"")) BLACKBOX_LOG_ADMIN_VERB("Object Say") -/client/proc/togglebuildmodeself() - set name = "Toggle Build Mode Self" - set category = "Admin.Events" - if (!(holder.rank_flags() & R_BUILD)) - return - if(src.mob) - togglebuildmode(src.mob) - BLACKBOX_LOG_ADMIN_VERB("Toggle Build Mode") -/client/proc/check_ai_laws() - set name = "Check AI Laws" - set category = "Admin.Game" - if(holder) - src.holder.output_ai_laws() +ADMIN_VERB(build_mode_self, R_BUILD, "Toggle Build Mode Self", "Toggle build mode for yourself.", ADMIN_CATEGORY_EVENTS) + togglebuildmode(user.mob) // why is this a global proc??? + BLACKBOX_LOG_ADMIN_VERB("Toggle Build Mode") -/client/proc/manage_sect() - set name = "Manage Religious Sect" - set category = "Admin.Game" +ADMIN_VERB(check_ai_laws, R_ADMIN, "Check AI Laws", "View the current AI laws.", ADMIN_CATEGORY_GAME) + user.holder.output_ai_laws() +ADMIN_VERB(manage_sect, R_ADMIN, "Manage Religious Sect", "Manages the chaplain's religion.", ADMIN_CATEGORY_GAME) if (!isnull(GLOB.religious_sect)) var/you_sure = tgui_alert( - usr, + user, "The Chaplain has already chosen [GLOB.religious_sect.name], override their selection?", "Replace God?", list("Yes", "Cancel"), @@ -904,7 +461,7 @@ GLOBAL_PROTECT(admin_verbs_poll) choices["nothing"] = null for(var/datum/religion_sect/sect as anything in subtypesof(/datum/religion_sect)) choices[initial(sect.name)] = sect - var/choice = tgui_input_list(usr, "Set new Chaplain sect", "God Picker", choices) + var/choice = tgui_input_list(user, "Set new Chaplain sect", "God Picker", choices) if(isnull(choice)) return if(choice == "nothing") @@ -912,122 +469,51 @@ GLOBAL_PROTECT(admin_verbs_poll) return set_new_religious_sect(choices[choice], reset_existing = TRUE) -/client/proc/deadmin() - set name = "Deadmin" - set category = "Admin" - set desc = "Shed your admin powers." - - if(!holder) - return - - holder.deactivate() - - to_chat(src, span_interface("You are now a normal player.")) - log_admin("[src] deadminned themselves.") - message_admins("[src] deadminned themselves.") +ADMIN_VERB(deadmin, R_NONE, "DeAdmin", "Shed your admin powers.", ADMIN_CATEGORY_MAIN) + user.holder.deactivate() + to_chat(user, span_interface("You are now a normal player.")) + log_admin("[key_name(user)] deadminned themselves.") + message_admins("[key_name_admin(user)] deadminned themselves.") BLACKBOX_LOG_ADMIN_VERB("Deadmin") -/client/proc/readmin() - set name = "Readmin" - set category = "Admin" - set desc = "Regain your admin powers." - - var/datum/admins/A = GLOB.deadmins[ckey] - - if(!A) - A = GLOB.admin_datums[ckey] - if (!A) - var/msg = " is trying to readmin but they have no deadmin entry" - message_admins("[key_name_admin(src)][msg]") - log_admin_private("[key_name(src)][msg]") - return - - A.associate(src) - - if (!holder) - return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force - - to_chat(src, span_interface("You are now an admin."), confidential = TRUE) - message_admins("[src] re-adminned themselves.") - log_admin("[src] re-adminned themselves.") - BLACKBOX_LOG_ADMIN_VERB("Readmin") - -/client/proc/populate_world(amount = 50) - set name = "Populate World" - set category = "Debug" - set desc = "(\"Amount of mobs to create\") Populate the world with test mobs." - +ADMIN_VERB(populate_world, R_DEBUG, "Populate World", "Populate the world with test mobs.", ADMIN_CATEGORY_DEBUG, amount = 50 as num) for (var/i in 1 to amount) var/turf/tile = get_safe_random_station_turf() var/mob/living/carbon/human/hooman = new(tile) hooman.equipOutfit(pick(subtypesof(/datum/outfit))) testing("Spawned test mob at [get_area_name(tile, TRUE)] ([tile.x],[tile.y],[tile.z])") -/client/proc/toggle_AI_interact() - set name = "Toggle Admin AI Interact" - set category = "Admin.Game" - set desc = "Allows you to interact with most machines as an AI would as a ghost" - - AI_Interact = !AI_Interact - if(mob && isAdminGhostAI(mob)) - mob.has_unlimited_silicon_privilege = AI_Interact - - log_admin("[key_name(usr)] has [AI_Interact ? "activated" : "deactivated"] Admin AI Interact") - message_admins("[key_name_admin(usr)] has [AI_Interact ? "activated" : "deactivated"] their AI interaction") - -/client/proc/debugstatpanel() - set name = "Debug Stat Panel" - set category = "Debug" - - src.stat_panel.send_message("create_debug") - -/client/proc/admin_2fa_verify() - set name = "Verify Admin" - set category = "Admin" - - var/datum/admins/admin = GLOB.admin_datums[ckey] - admin?.associate(src) - -/client/proc/display_sendmaps() - set name = "Send Maps Profile" - set category = "Debug" +ADMIN_VERB(toggle_ai_interact, R_ADMIN, "Toggle Admin AI Interact", "Allows you to interact with most machines as an AI would as a ghost.", ADMIN_CATEGORY_GAME) + user.AI_Interact = !user.AI_Interact + if(user.mob && isAdminGhostAI(user.mob)) + user.mob.has_unlimited_silicon_privilege = user.AI_Interact - src << link("?debug=profile&type=sendmaps&window=test") + log_admin("[key_name(user)] has [user.AI_Interact ? "activated" : "deactivated"] Admin AI Interact") + message_admins("[key_name_admin(user)] has [user.AI_Interact ? "activated" : "deactivated"] their AI interaction") -/** - * Debug verb that spawns human crewmembers - * of each job type, gives them a mind and assigns the role, - * and injects them into the manifest, as if they were a "player". - * - * This spawns humans with minds and jobs, but does NOT make them 'players'. - * They're all clientles mobs with minds / jobs. - */ -/client/proc/spawn_debug_full_crew() - set name = "Spawn Debug Full Crew" - set desc = "Creates a full crew for the station, filling the datacore and assigning them all minds / jobs. Don't do this on live" - set category = "Debug" +ADMIN_VERB(debug_statpanel, R_DEBUG, "Debug Stat Panel", "Toggles local debug of the stat panel", ADMIN_CATEGORY_DEBUG) + user.stat_panel.send_message("create_debug") - if(!check_rights(R_DEBUG)) - return - - var/mob/admin = usr +ADMIN_VERB(display_sendmaps, R_DEBUG, "Send Maps Profile", "View the profile.", ADMIN_CATEGORY_DEBUG) + user << link("?debug=profile&type=sendmaps&window=test") +ADMIN_VERB(spawn_debug_full_crew, R_DEBUG, "Spawn Debug Full Crew", "Creates a full crew for the station, flling datacore and assigning minds and jobs.", ADMIN_CATEGORY_DEBUG) if(SSticker.current_state != GAME_STATE_PLAYING) - to_chat(admin, "You should only be using this after a round has setup and started.") + to_chat(user, "You should only be using this after a round has setup and started.") return // Two input checks here to make sure people are certain when they're using this. - if(tgui_alert(admin, "This command will create a bunch of dummy crewmembers with minds, job, and datacore entries, which will take a while and fill the manifest.", "Spawn Crew", list("Yes", "Cancel")) != "Yes") + if(tgui_alert(user, "This command will create a bunch of dummy crewmembers with minds, job, and datacore entries, which will take a while and fill the manifest.", "Spawn Crew", list("Yes", "Cancel")) != "Yes") return - if(tgui_alert(admin, "I sure hope you aren't doing this on live. Are you sure?", "Spawn Crew (Be certain)", list("Yes", "Cancel")) != "Yes") + if(tgui_alert(user, "I sure hope you aren't doing this on live. Are you sure?", "Spawn Crew (Be certain)", list("Yes", "Cancel")) != "Yes") return // Find the observer spawn, so we have a place to dump the dummies. var/obj/effect/landmark/observer_start/observer_point = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list var/turf/destination = get_turf(observer_point) if(!destination) - to_chat(admin, "Failed to find the observer spawn to send the dummies.") + to_chat(user, "Failed to find the observer spawn to send the dummies.") return // Okay, now go through all nameable occupations. @@ -1049,7 +535,7 @@ GLOBAL_PROTECT(admin_verbs_poll) // Assign the rank to the new player dummy. if(!SSjob.AssignRole(new_guy, job, do_eligibility_checks = FALSE)) qdel(new_guy) - to_chat(admin, "[rank] wasn't able to be spawned.") + to_chat(user, "[rank] wasn't able to be spawned.") continue // It's got a job, spawn in a human and shove it in the human. @@ -1070,13 +556,9 @@ GLOBAL_PROTECT(admin_verbs_poll) number_made++ CHECK_TICK - to_chat(admin, "[number_made] crewmembers have been created.") - -/// Debug verb for seeing at a glance what all spells have as set requirements -/client/proc/debug_spell_requirements() - set name = "Show Spell Requirements" - set category = "Debug" + to_chat(user, "[number_made] crewmembers have been created.") +ADMIN_VERB(debug_spell_requirements, R_DEBUG, "Debug Spell Requirements", "View all spells and their requirements.", ADMIN_CATEGORY_DEBUG) var/header = "Name Requirements" var/all_requirements = list() for(var/datum/action/cooldown/spell/spell as anything in typesof(/datum/action/cooldown/spell)) @@ -1104,69 +586,54 @@ GLOBAL_PROTECT(admin_verbs_poll) var/page_style = "" var/page_contents = "[page_style][header][jointext(all_requirements, "")]
" - var/datum/browser/popup = new(mob, "spellreqs", "Spell Requirements", 600, 400) + var/datum/browser/popup = new(user.mob, "spellreqs", "Spell Requirements", 600, 400) popup.set_content(page_contents) popup.open() -/client/proc/force_load_lazy_template() - set name = "Load/Jump Lazy Template" - set category = "Admin.Events" - if(!check_rights(R_ADMIN)) - return - +ADMIN_VERB(load_lazy_template, R_ADMIN, "Load/Jump Lazy Template", "Loads a lazy template and/or jumps to it.", ADMIN_CATEGORY_EVENTS) var/list/choices = LAZY_TEMPLATE_KEY_LIST_ALL() - var/choice = tgui_input_list(usr, "Key?", "Lazy Loader", choices) + var/choice = tgui_input_list(user, "Key?", "Lazy Loader", choices) + var/teleport_to_template = tgui_input_list(user, "Jump to template after loading?", "Where to?", list("Yes", "No")) if(!choice) return choice = choices[choice] if(!choice) - to_chat(usr, span_warning("No template with that key found, report this!")) + to_chat(user, span_warning("No template with that key found, report this!")) return var/already_loaded = LAZYACCESS(SSmapping.loaded_lazy_templates, choice) var/force_load = FALSE - if(already_loaded && (tgui_alert(usr, "Template already loaded.", "", list("Jump", "Load Again")) == "Load Again")) + if(already_loaded && (tgui_alert(user, "Template already loaded.", "", list("Jump", "Load Again")) == "Load Again")) force_load = TRUE var/datum/turf_reservation/reservation = SSmapping.lazy_load_template(choice, force = force_load) if(!reservation) - to_chat(usr, span_boldwarning("Failed to load template!")) + to_chat(user, span_boldwarning("Failed to load template!")) return - if(!isobserver(usr)) - admin_ghost() - usr.forceMove(reservation.bottom_left_turfs[1]) + if(teleport_to_template == "Yes") + if(!isobserver(user.mob)) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) + user.mob.forceMove(reservation.bottom_left_turfs[1]) + to_chat(user, span_boldnicegreen("Template loaded, you have been moved to the bottom left of the reservation.")) - message_admins("[key_name_admin(usr)] has loaded lazy template '[choice]'") - to_chat(usr, span_boldnicegreen("Template loaded, you have been moved to the bottom left of the reservation.")) + message_admins("[key_name_admin(user)] has loaded lazy template '[choice]'") -/client/proc/library_control() - set name = "Library Management" - set category = "Admin" - if(!check_rights(R_BAN)) - return - - if(!holder.library_manager) - holder.library_manager = new() - holder.library_manager.ui_interact(usr) +ADMIN_VERB(library_control, R_BAN, "Library Management", "List and manage the Library.", ADMIN_CATEGORY_MAIN) + if(!user.holder.library_manager) + user.holder.library_manager = new + user.holder.library_manager.ui_interact(user.mob) BLACKBOX_LOG_ADMIN_VERB("Library Management") -/client/proc/create_mob_worm() - set category = "Admin.Fun" - set name = "Create Mob Worm" - set desc = "Attached a linked list of mobs to a marked mob" - if (!check_rights(R_FUN)) - return - if(isnull(holder)) - return - if(!isliving(holder.marked_datum)) - to_chat(usr, span_warning("Error: Please mark a mob to attach mobs to.")) +ADMIN_VERB(create_mob_worm, R_FUN, "Create Mob Worm", "Attach a linked list of mobs to your marked mob.", ADMIN_CATEGORY_FUN) + if(!isliving(user.holder.marked_datum)) + to_chat(user, span_warning("Error: Please mark a mob to attach mobs to.")) return - var/mob/living/head = holder.marked_datum + var/mob/living/head = user.holder.marked_datum var/attempted_target_path = tgui_input_text( - usr, + user, "Enter typepath of a mob you'd like to make your chain from.", "Typepath", "[/mob/living/basic/pet/dog/corgi/ian]", @@ -1181,7 +648,7 @@ GLOBAL_PROTECT(admin_verbs_poll) if(isnull(desired_mob) || !ispath(desired_mob) || QDELETED(head)) return //The user pressed "Cancel" - var/amount = tgui_input_number(usr, "How long should our tail be?", "Worm Configurator", default = 3, min_value = 1) + var/amount = tgui_input_number(user, "How long should our tail be?", "Worm Configurator", default = 3, min_value = 1) if (isnull(amount) || amount < 1 || QDELETED(head)) return head.AddComponent(/datum/component/mob_chain) diff --git a/code/modules/admin/adminmenu.dm b/code/modules/admin/adminmenu.dm deleted file mode 100644 index 9a93856aa4e2d..0000000000000 --- a/code/modules/admin/adminmenu.dm +++ /dev/null @@ -1,11 +0,0 @@ -/datum/verbs/menu/Admin/Generate_list(client/C) - if (C.holder) - . = ..() - -/datum/verbs/menu/Admin/verb/playerpanel() - set name = "Player Panel" - set desc = "Player Panel" - set category = "Admin.Game" - if(usr.client.holder) - usr.client.holder.player_panel_new() - BLACKBOX_LOG_ADMIN_VERB("Player Panel New") diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm index 1680304679edf..823a4a9e64bf0 100644 --- a/code/modules/admin/callproc/callproc.dm +++ b/code/modules/admin/callproc/callproc.dm @@ -92,11 +92,8 @@ GLOBAL_PROTECT(AdminProcCallHandler) usr = lastusr handler.remove_caller(user) -/client/proc/callproc() - set category = "Debug" - set name = "Advanced ProcCall" - set waitfor = FALSE - callproc_blocking() +ADMIN_VERB(advanced_proc_call, R_DEBUG, "Advanced ProcCall", "Call a proc on any datum in the server.", ADMIN_CATEGORY_DEBUG) + user.callproc_blocking() /client/proc/callproc_blocking(list/get_retval) if(!check_rights(R_DEBUG)) @@ -230,37 +227,30 @@ GLOBAL_PROTECT(LastAdminCalledProc) return (GLOB.AdminProcCaller && GLOB.AdminProcCaller == usr?.client?.ckey) || (GLOB.AdminProcCallHandler && usr == GLOB.AdminProcCallHandler) #endif -/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf) - set category = "Debug" - set name = "Atom ProcCall" - set waitfor = FALSE - - if(!check_rights(R_DEBUG)) - return - - var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null +ADMIN_VERB_ONLY_CONTEXT_MENU(call_proc_datum, R_DEBUG, "Atom ProcCall", datum/thing as null|area|mob|obj|turf) + var/procname = input(user, "Proc name, eg: fake_blood","Proc:", null) as text|null if(!procname) return - if(!hascall(A,procname)) - to_chat(usr, "Error: callproc_datum(): type [A.type] has no proc named [procname].", confidential = TRUE) + if(!hascall(thing, procname)) + to_chat(user, "Error: callproc_datum(): type [thing.type] has no proc named [procname].", confidential = TRUE) return - var/list/lst = get_callproc_args() + var/list/lst = user.get_callproc_args() if(!lst) return - if(!A || !is_valid_src(A)) - to_chat(usr, span_warning("Error: callproc_datum(): owner of proc no longer exists."), confidential = TRUE) + if(!thing || !is_valid_src(thing)) + to_chat(user, span_warning("Error: callproc_datum(): owner of proc no longer exists."), confidential = TRUE) return - log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") - var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]." + log_admin("[key_name(user)] called [thing]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") + var/msg = "[key_name(user)] called [thing]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]." message_admins(msg) - admin_ticket_log(A, msg) + admin_ticket_log(thing, msg) BLACKBOX_LOG_ADMIN_VERB("Atom ProcCall") - var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc - . = get_callproc_returnval(returnval,procname) + var/returnval = WrapAdminProcCall(thing, procname, lst) // Pass the lst as an argument list to the proc + . = user.get_callproc_returnval(returnval,procname) if(.) - to_chat(usr, ., confidential = TRUE) + to_chat(user, ., confidential = TRUE) /client/proc/get_callproc_args() var/argnum = input("Number of arguments","Number:",0) as num|null diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index fcf9693731e05..509787ffd3a56 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -16,7 +16,7 @@ /proc/randomize_human(mob/living/carbon/human/human, randomize_mutations = FALSE) human.gender = human.dna.species.sexes ? pick(MALE, FEMALE, PLURAL, NEUTER) : PLURAL human.physique = human.gender - human.real_name = human.dna?.species.random_name(human.gender) || random_unique_name(human.gender) + human.real_name = human.generate_random_mob_name() human.name = human.get_visible_name() human.set_hairstyle(random_hairstyle(human.gender), update = FALSE) human.set_facial_hairstyle(random_facial_hairstyle(human.gender), update = FALSE) @@ -24,7 +24,7 @@ human.set_facial_haircolor(human.hair_color, update = FALSE) human.eye_color_left = random_eye_color() human.eye_color_right = human.eye_color_left - human.skin_tone = random_skin_tone() + human.skin_tone = pick(GLOB.skin_tones) human.dna.species.randomize_active_underwear_only(human) // Needs to be called towards the end to update all the UIs just set above human.dna.initialize_dna(newblood_type = random_blood_type(), create_mutation_blocks = randomize_mutations, randomize_features = TRUE) diff --git a/code/modules/admin/force_event.dm b/code/modules/admin/force_event.dm index 20066547de9c6..519adbd8a9e5c 100644 --- a/code/modules/admin/force_event.dm +++ b/code/modules/admin/force_event.dm @@ -1,12 +1,6 @@ -///Allows an admin to force an event -/client/proc/forceEvent() - set name = "Trigger Event" - set category = "Admin.Events" - if(!holder || !check_rights(R_FUN)) - return - - holder.forceEvent() +ADMIN_VERB(force_event, R_FUN, "Trigger Event", "Forces an event to occur.", ADMIN_CATEGORY_EVENTS) + user.holder.forceEvent() ///Opens up the Force Event Panel /datum/admins/proc/forceEvent() diff --git a/code/modules/admin/greyscale_modify_menu.dm b/code/modules/admin/greyscale_modify_menu.dm index ea0774cc99d12..f96ecb7c590b6 100644 --- a/code/modules/admin/greyscale_modify_menu.dm +++ b/code/modules/admin/greyscale_modify_menu.dm @@ -154,13 +154,13 @@ if("recolor") var/index = text2num(params["color_index"]) - var/new_color = lowertext(params["new_color"]) + var/new_color = LOWER_TEXT(params["new_color"]) if(split_colors[index] != new_color && (findtext(new_color, GLOB.is_color) || (unlocked && findtext(new_color, GLOB.is_alpha_color)))) split_colors[index] = new_color queue_refresh() if("recolor_from_string") - var/full_color_string = lowertext(params["color_string"]) + var/full_color_string = LOWER_TEXT(params["color_string"]) if(full_color_string != split_colors.Join() && ReadColorsFromString(full_color_string)) queue_refresh() diff --git a/code/modules/admin/ipintel.dm b/code/modules/admin/ipintel.dm deleted file mode 100644 index 7ca4ccbc320a7..0000000000000 --- a/code/modules/admin/ipintel.dm +++ /dev/null @@ -1,136 +0,0 @@ -/datum/ipintel - var/ip - var/intel = 0 - var/cache = FALSE - var/cacheminutesago = 0 - var/cachedate = "" - var/cacherealtime = 0 - -/datum/ipintel/New() - cachedate = SQLtime() - cacherealtime = world.realtime - -/datum/ipintel/proc/is_valid() - . = FALSE - if (intel < 0) - return - if (intel <= CONFIG_GET(number/ipintel_rating_bad)) - if (world.realtime < cacherealtime + (CONFIG_GET(number/ipintel_save_good) * 60 * 60 * 10)) - return TRUE - else - if (world.realtime < cacherealtime + (CONFIG_GET(number/ipintel_save_bad) * 60 * 60 * 10)) - return TRUE - -/proc/get_ip_intel(ip, bypasscache = FALSE, updatecache = TRUE) - var/datum/ipintel/res = new() - res.ip = ip - . = res - if (!ip || !CONFIG_GET(string/ipintel_email) || !SSipintel.enabled) - return - if (!bypasscache) - var/datum/ipintel/cachedintel = SSipintel.cache[ip] - if (cachedintel?.is_valid()) - cachedintel.cache = TRUE - return cachedintel - - if(SSdbcore.Connect()) - var/rating_bad = CONFIG_GET(number/ipintel_rating_bad) - var/datum/db_query/query_get_ip_intel = SSdbcore.NewQuery({" - SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW()) - FROM [format_table_name("ipintel")] - WHERE - ip = INET_ATON(':ip') - AND (( - intel < :rating_bad - AND - date + INTERVAL :save_good HOUR > NOW() - ) OR ( - intel >= :rating_bad - AND - date + INTERVAL :save_bad HOUR > NOW() - )) - "}, list("ip" = ip, "rating_bad" = rating_bad, "save_good" = CONFIG_GET(number/ipintel_save_good), "save_bad" = CONFIG_GET(number/ipintel_save_bad))) - if(!query_get_ip_intel.Execute()) - qdel(query_get_ip_intel) - return - if (query_get_ip_intel.NextRow()) - res.cache = TRUE - res.cachedate = query_get_ip_intel.item[1] - res.intel = text2num(query_get_ip_intel.item[2]) - res.cacheminutesago = text2num(query_get_ip_intel.item[3]) - res.cacherealtime = world.realtime - (text2num(query_get_ip_intel.item[3])*10*60) - SSipintel.cache[ip] = res - qdel(query_get_ip_intel) - return - qdel(query_get_ip_intel) - res.intel = ip_intel_query(ip) - if (updatecache && res.intel >= 0) - SSipintel.cache[ip] = res - if(SSdbcore.Connect()) - var/datum/db_query/query_add_ip_intel = SSdbcore.NewQuery( - "INSERT INTO [format_table_name("ipintel")] (ip, intel) VALUES (INET_ATON(:ip), :intel) ON DUPLICATE KEY UPDATE intel = VALUES(intel), date = NOW()", - list("ip" = ip, "intel" = res.intel) - ) - query_add_ip_intel.Execute() - qdel(query_add_ip_intel) - - -/proc/ip_intel_query(ip, retryed=0) - . = -1 //default - if (!ip) - return - if (SSipintel.throttle > world.timeofday) - return - if (!SSipintel.enabled) - return - - var/list/http[] = world.Export("http://[CONFIG_GET(string/ipintel_domain)]/check.php?ip=[ip]&contact=[CONFIG_GET(string/ipintel_email)]&format=json&flags=f") - - if (http) - var/status = text2num(http["STATUS"]) - - if (status == 200) - var/response = json_decode(file2text(http["CONTENT"])) - if (response) - if (response["status"] == "success") - var/intelnum = text2num(response["result"]) - if (isnum(intelnum)) - return text2num(response["result"]) - else - ipintel_handle_error("Bad intel from server: [response["result"]].", ip, retryed) - if (!retryed) - sleep(2.5 SECONDS) - return .(ip, 1) - else - ipintel_handle_error("Bad response from server: [response["status"]].", ip, retryed) - if (!retryed) - sleep(2.5 SECONDS) - return .(ip, 1) - - else if (status == 429) - ipintel_handle_error("Error #429: We have exceeded the rate limit.", ip, 1) - return - else - ipintel_handle_error("Unknown status code: [status].", ip, retryed) - if (!retryed) - sleep(2.5 SECONDS) - return .(ip, 1) - else - ipintel_handle_error("Unable to connect to API.", ip, retryed) - if (!retryed) - sleep(2.5 SECONDS) - return .(ip, 1) - - -/proc/ipintel_handle_error(error, ip, retryed) - if (retryed) - SSipintel.errors++ - error += " Could not check [ip]. Disabling IPINTEL for [SSipintel.errors] minute[( SSipintel.errors == 1 ? "" : "s" )]" - SSipintel.throttle = world.timeofday + (10 * 120 * SSipintel.errors) - else - error += " Attempting retry on [ip]." - log_ipintel(error) - -/proc/log_ipintel(text) - log_game("IPINTEL: [text]") - debug_admins("IPINTEL: [text]") diff --git a/code/modules/admin/known_alts.dm b/code/modules/admin/known_alts.dm index d6486f77bd730..4105c7f4edc93 100644 --- a/code/modules/admin/known_alts.dm +++ b/code/modules/admin/known_alts.dm @@ -187,8 +187,5 @@ GLOBAL_DATUM_INIT(known_alts, /datum/known_alts, new) client << browse(html, "window=known_alts;size=700x400") -/datum/admins/proc/known_alts_panel() - set name = "Known Alts Panel" - set category = "Admin" - - GLOB.known_alts.show_panel(usr.client) +ADMIN_VERB(known_alts_panel, R_ADMIN, "Known Alts Panel", "View a panel of known alts.", ADMIN_CATEGORY_MAIN) + GLOB.known_alts.show_panel(user) diff --git a/code/modules/admin/outfit_manager.dm b/code/modules/admin/outfit_manager.dm index fcb41b3f2f1a5..f3ef7d2685c22 100644 --- a/code/modules/admin/outfit_manager.dm +++ b/code/modules/admin/outfit_manager.dm @@ -1,18 +1,8 @@ -/client/proc/outfit_manager() - set category = "Debug" - set name = "Outfit Manager" - - if(!check_rights(R_DEBUG)) - return - var/datum/outfit_manager/ui = new(usr) - ui.ui_interact(usr) - +ADMIN_VERB(outfit_manager, R_DEBUG|R_ADMIN, "Outfit Manager", "View and edit outfits.", ADMIN_CATEGORY_DEBUG) + var/static/datum/outfit_manager/ui = new + ui.ui_interact(user.mob) /datum/outfit_manager - var/client/owner - -/datum/outfit_manager/New(user) - owner = CLIENT_FROM_VAR(user) /datum/outfit_manager/ui_state(mob/user) return GLOB.admin_state @@ -53,24 +43,24 @@ switch(action) if("new") - owner.open_outfit_editor(new /datum/outfit) + ui.user.client.open_outfit_editor(new /datum/outfit) if("load") - owner.holder.load_outfit(owner.mob) + ui.user.client.holder.load_outfit(ui.user) if("copy") - var/datum/outfit/outfit = tgui_input_list(owner, "Pick an outfit to copy from", "Outfit Manager", subtypesof(/datum/outfit)) + var/datum/outfit/outfit = tgui_input_list(ui.user, "Pick an outfit to copy from", "Outfit Manager", subtypesof(/datum/outfit)) if(isnull(outfit)) return if(!ispath(outfit)) return - owner.open_outfit_editor(new outfit) + ui.user.client.open_outfit_editor(new outfit) var/datum/outfit/target_outfit = locate(params["outfit"]) if(!istype(target_outfit)) return switch(action) //wow we're switching through action again this is horrible optimization smh if("edit") - owner.open_outfit_editor(target_outfit) + ui.user.client.open_outfit_editor(target_outfit) if("save") - owner.holder.save_outfit(owner.mob, target_outfit) + ui.user.client.holder.save_outfit(ui.user, target_outfit) if("delete") - owner.holder.delete_outfit(owner.mob, target_outfit) + ui.user.client.holder.delete_outfit(ui.user, target_outfit) diff --git a/code/modules/admin/painting_manager.dm b/code/modules/admin/painting_manager.dm index bd7d28fb73fba..7a8bd7127a4d3 100644 --- a/code/modules/admin/painting_manager.dm +++ b/code/modules/admin/painting_manager.dm @@ -1,11 +1,6 @@ -/datum/admins/proc/paintings_manager() - set name = "Paintings Manager" - set category = "Admin" - - if(!check_rights(R_ADMIN)) - return - var/datum/paintings_manager/ui = new(usr) - ui.ui_interact(usr) +ADMIN_VERB(painting_manager, R_ADMIN, "Paintings Manager", "View and redact paintings.", ADMIN_CATEGORY_MAIN) + var/static/datum/paintings_manager/ui = new + ui.ui_interact(user.mob) /// Painting Admin Management Panel /datum/paintings_manager diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm index cf816fef8a7a1..e508a10473927 100644 --- a/code/modules/admin/permissionedit.dm +++ b/code/modules/admin/permissionedit.dm @@ -1,10 +1,6 @@ -/client/proc/edit_admin_permissions() - set category = "Admin" - set name = "Permissions Panel" - set desc = "Edit admin permissions" - if(!check_rights(R_PERMISSIONS)) - return - usr.client.holder.edit_admin_permissions() + +ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit admin permissions.", ADMIN_CATEGORY_MAIN) + user.holder.edit_admin_permissions() /datum/admins/proc/edit_admin_permissions(action, target, operation, page) if(!check_rights(R_PERMISSIONS)) @@ -253,8 +249,8 @@ qdel(query_add_admin) var/datum/db_query/query_add_admin_log = SSdbcore.NewQuery({" INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) - VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add admin', :target, CONCAT('New admin added: ', :target)) - "}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = .)) + VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'add admin', :target, CONCAT('New admin added: ', :target)) + "}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = .)) if(!query_add_admin_log.warn_execute()) qdel(query_add_admin_log) return FALSE @@ -279,8 +275,8 @@ qdel(query_add_rank) var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({" INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) - VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove admin', :admin_ckey, CONCAT('Admin removed: ', :admin_ckey)) - "}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_ckey" = admin_ckey)) + VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'remove admin', :admin_ckey, CONCAT('Admin removed: ', :admin_ckey)) + "}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_ckey" = admin_ckey)) if(!query_add_rank_log.warn_execute()) qdel(query_add_rank_log) return @@ -427,8 +423,8 @@ qdel(query_add_rank) var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({" INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) - VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add rank', :new_rank, CONCAT('New rank added: ', :new_rank)) - "}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "new_rank" = custom_rank.name)) + VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'add rank', :new_rank, CONCAT('New rank added: ', :new_rank)) + "}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "new_rank" = custom_rank.name)) if(!query_add_rank_log.warn_execute()) qdel(query_add_rank_log) return @@ -444,8 +440,8 @@ qdel(query_change_rank) var/datum/db_query/query_change_rank_log = SSdbcore.NewQuery({" INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) - VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change admin rank', :target, CONCAT('Rank of ', :target, ' changed from ', :old_rank, ' to ', :new_rank)) - "}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = admin_ckey, "old_rank" = old_rank, "new_rank" = joined_rank)) + VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'change admin rank', :target, CONCAT('Rank of ', :target, ' changed from ', :old_rank, ' to ', :new_rank)) + "}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = admin_ckey, "old_rank" = old_rank, "new_rank" = joined_rank)) if(!query_change_rank_log.warn_execute()) qdel(query_change_rank_log) return @@ -543,8 +539,8 @@ qdel(query_add_rank) var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({" INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) - VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove rank', :admin_rank, CONCAT('Rank removed: ', :admin_rank)) - "}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_rank" = admin_rank)) + VALUES (NOW(), :round_id, :adminckey, INET_ATON(:adminip), 'remove rank', :admin_rank, CONCAT('Rank removed: ', :admin_rank)) + "}, list("round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_rank" = admin_rank)) if(!query_add_rank_log.warn_execute()) qdel(query_add_rank_log) return diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index c8c3b660920ea..31c34957544e4 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -231,10 +231,10 @@ if(isliving(M)) if(iscarbon(M)) //Carbon stuff - if(ismonkey(M)) - M_job = "Monkey" - else if(ishuman(M)) + if(ishuman(M) && M.job) M_job = M.job + else if(ismonkey(M)) + M_job = "Monkey" else if(isalien(M)) //aliens if(islarva(M)) M_job = "Alien larva" diff --git a/code/modules/admin/sound_emitter.dm b/code/modules/admin/sound_emitter.dm index 4786e0ad7c124..d697537c6df5f 100644 --- a/code/modules/admin/sound_emitter.dm +++ b/code/modules/admin/sound_emitter.dm @@ -51,10 +51,13 @@ return edit_emitter(user) -/obj/effect/sound_emitter/AltClick(mob/user) - if(check_rights_for(user.client, R_SOUND)) - activate(user) - to_chat(user, span_notice("Sound emitter activated."), confidential = TRUE) +/obj/effect/sound_emitter/click_alt(mob/user) + if(!check_rights_for(user.client, R_SOUND)) + return CLICK_ACTION_BLOCKING + + activate(user) + to_chat(user, span_notice("Sound emitter activated."), confidential = TRUE) + return CLICK_ACTION_SUCCESS /obj/effect/sound_emitter/proc/edit_emitter(mob/user) var/dat = "" diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index f32eefe046fe7..c39706795acd0 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -393,6 +393,7 @@ ROLE_REV_HEAD, ROLE_SENTIENT_DISEASE, ROLE_SPIDER, + ROLE_SPY, ROLE_SYNDICATE, ROLE_TRAITOR, ROLE_WIZARD, @@ -577,7 +578,7 @@ duration = text2num(duration) if (!(interval in list("SECOND", "MINUTE", "HOUR", "DAY", "WEEK", "MONTH", "YEAR"))) interval = "MINUTE" - var/time_message = "[duration] [lowertext(interval)]" //no DisplayTimeText because our duration is of variable interval type + var/time_message = "[duration] [LOWER_TEXT(interval)]" //no DisplayTimeText because our duration is of variable interval type if(duration > 1) //pluralize the interval if necessary time_message += "s" var/is_server_ban = (roles_to_ban[1] == "Server") @@ -799,7 +800,7 @@ return var/kn = key_name(usr) var/kna = key_name_admin(usr) - var/change_message = "[usr.client.key] unbanned [target] from [role] on [SQLtime()] during round #[GLOB.round_id]
" + var/change_message = "[usr.client.key] unbanned [target] from [role] on [ISOtime()] during round #[GLOB.round_id]
" var/datum/db_query/query_unban = SSdbcore.NewQuery({" UPDATE [format_table_name("ban")] SET unbanned_datetime = NOW(), @@ -844,7 +845,7 @@ var/kn = key_name(usr) var/kna = key_name_admin(usr) - var/change_message = "[usr.client.key] re-activated ban of [target] from [role] on [SQLtime()] during round #[GLOB.round_id]
" + var/change_message = "[usr.client.key] re-activated ban of [target] from [role] on [ISOtime()] during round #[GLOB.round_id]
" var/datum/db_query/query_reban = SSdbcore.NewQuery({" UPDATE [format_table_name("ban")] SET unbanned_datetime = NULL, diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm index 27ef12322243f..68b96e41ae30f 100644 --- a/code/modules/admin/sql_message_system.dm +++ b/code/modules/admin/sql_message_system.dm @@ -52,7 +52,7 @@ return if(isnull(expiry)) if(tgui_alert(usr, "Set an expiry time? Expired messages are hidden like deleted ones.", "Expiry time?", list("Yes", "No", "Cancel")) == "Yes") - var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons.", "Set expiry time", SQLtime()) as null|text + var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons.", "Set expiry time", ISOtime()) as null|text if(!expire_time) return var/datum/db_query/query_validate_expire_time = SSdbcore.NewQuery( @@ -183,7 +183,7 @@ if(!new_text) qdel(query_find_edit_message) return - var/edit_text = "Edited by [editor_key] on [SQLtime()] from
[old_text]
to
[new_text]
" + var/edit_text = "Edited by [editor_key] on [ISOtime()] from
[old_text]
to
[new_text]
" var/datum/db_query/query_edit_message = SSdbcore.NewQuery({" UPDATE [format_table_name("messages")] SET text = :text, lasteditor = :lasteditor, edits = CONCAT(IFNULL(edits,''),:edit_text) @@ -253,7 +253,7 @@ return new_expiry = query_validate_expire_time_edit.item[1] qdel(query_validate_expire_time_edit) - var/edit_text = "Expiration time edited by [editor_key] on [SQLtime()] from [(old_expiry ? old_expiry : "no expiration date")] to [new_expiry]
" + var/edit_text = "Expiration time edited by [editor_key] on [ISOtime()] from [(old_expiry ? old_expiry : "no expiration date")] to [new_expiry]
" var/datum/db_query/query_edit_message_expiry = SSdbcore.NewQuery({" UPDATE [format_table_name("messages")] SET expire_timestamp = :expire_time, lasteditor = :lasteditor, edits = CONCAT(IFNULL(edits,''),:edit_text) @@ -307,7 +307,7 @@ qdel(query_find_edit_note_severity) return new_severity = new_severity - var/edit_text = "Note severity edited by [editor_key] on [SQLtime()] from [old_severity] to [new_severity]
" + var/edit_text = "Note severity edited by [editor_key] on [ISOtime()] from [old_severity] to [new_severity]
" var/datum/db_query/query_edit_note_severity = SSdbcore.NewQuery({" UPDATE [format_table_name("messages")] SET severity = :severity, lasteditor = :lasteditor, edits = CONCAT(IFNULL(edits,''),:edit_text) @@ -351,7 +351,7 @@ var/target_key = query_find_message_secret.item[2] var/admin_key = query_find_message_secret.item[3] var/secret = text2num(query_find_message_secret.item[4]) - var/edit_text = "Made [secret ? "not secret" : "secret"] by [editor_key] on [SQLtime()]
" + var/edit_text = "Made [secret ? "not secret" : "secret"] by [editor_key] on [ISOtime()]
" var/datum/db_query/query_message_secret = SSdbcore.NewQuery({" UPDATE [format_table_name("messages")] SET secret = NOT secret, lasteditor = :lasteditor, edits = CONCAT(IFNULL(edits,''),:edit_text) @@ -752,18 +752,4 @@ notesfile.cd = "/" notesfile.dir.Remove(ckey) -/*alternatively this proc can be run once to pass through every note and attempt to convert it before deleting the file, if done then AUTOCONVERT_NOTES should be turned off -this proc can take several minutes to execute fully if converting and cause DD to hang if converting a lot of notes; it's not advised to do so while a server is live -/proc/mass_convert_notes() - to_chat(world, "Beginning mass note conversion", confidential = TRUE) - var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) - log_game("Error: Cannot access [NOTESFILE]") - return - notesfile.cd = "/" - for(var/ckey in notesfile.dir) - convert_notes_sql(ckey) - to_chat(world, "Deleting NOTESFILE", confidential = TRUE) - fdel(NOTESFILE) - to_chat(world, "Finished mass note conversion, remember to turn off AUTOCONVERT_NOTES", confidential = TRUE)*/ #undef NOTESFILE diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm index 537e0b92acbdd..fede9724ab181 100644 --- a/code/modules/admin/stickyban.dm +++ b/code/modules/admin/stickyban.dm @@ -481,10 +481,5 @@ . = list2params(.) - -/client/proc/stickybanpanel() - set name = "Sticky Ban Panel" - set category = "Admin" - if (!holder) - return - holder.stickyban_show() +ADMIN_VERB(panel_sticky_ban, R_BAN, "Sticky Ban Panel", "List and manage sticky bans.", ADMIN_CATEGORY_MAIN) + user.holder.stickyban_show() diff --git a/code/modules/admin/tag.dm b/code/modules/admin/tag.dm index 64c6c16fc406d..e52112eba1495 100644 --- a/code/modules/admin/tag.dm +++ b/code/modules/admin/tag.dm @@ -49,21 +49,14 @@ [X.getToxLoss()] \ [X.getOxyLoss()]" -/// Display all of the tagged datums -/datum/admins/proc/display_tags() - set category = "Admin.Game" - set name = "View Tags" - - if (!istype(src, /datum/admins)) - src = usr.client.holder - if (!istype(src, /datum/admins)) - to_chat(usr, "Error: you are not an admin!", confidential = TRUE) - return - +ADMIN_VERB(display_tags, R_ADMIN, "View Tags", "Display all of the tagged datums.", ADMIN_CATEGORY_GAME) var/index = 0 var/list/dat = list("
Tag Menu

") - dat += "
Refresh
" + var/list/tagged_datums = user.holder.tagged_datums + var/list/marked_datum = user.holder.marked_datum + + dat += "
Refresh
" if(LAZYLEN(tagged_datums)) for(var/datum/iter_datum as anything in tagged_datums) index++ @@ -71,7 +64,7 @@ if(isnull(iter_datum)) dat += "\t[index]: Null reference - Check runtime logs!" - stack_trace("Null datum found in tagged datum menu! User: [usr]") + stack_trace("Null datum found in tagged datum menu! User: [user]") continue else if(iscarbon(iter_datum)) var/mob/living/carbon/resolved_carbon = iter_datum @@ -99,7 +92,7 @@ dat += "No datums tagged :(" dat = dat.Join("
") - usr << browse(dat, "window=tag;size=800x480") + user << browse(dat, "window=tag;size=800x480") #undef TAG_DEL #undef TAG_MARK diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 5506bfa2b0d79..2ba75020d48d1 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -136,8 +136,7 @@ to_chat(usr, "[shuttle_console] was [shuttle_console.admin_controlled ? "locked" : "unlocked"].", confidential = TRUE) else if(href_list["delay_round_end"]) - // Permissions are checked in delay_round_end - delay_round_end() + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/delay_round_end) else if(href_list["undelay_round_end"]) if(!check_rights(R_SERVER)) @@ -725,21 +724,10 @@ our_mob.AIize(our_mob.client, move) else if(href_list["makerobot"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/our_mob = locate(href_list["makerobot"]) - if(!istype(our_mob)) - return - if(iscyborg(our_mob)) - to_chat(usr, "That's already a cyborg.", confidential = TRUE) - return - - usr.client.cmd_admin_robotize(our_mob) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_admin_robotize, locate(href_list["makerobot"])) else if(href_list["adminplayeropts"]) - var/mob/M = locate(href_list["adminplayeropts"]) - show_player_panel(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_player_panel, locate(href_list["adminplayeropts"])) else if(href_list["ppbyckey"]) var/target_ckey = href_list["ppbyckey"] @@ -754,7 +742,7 @@ return to_chat(usr, span_notice("Jumping to [target_ckey]'s new mob: [target_mob]!")) - show_player_panel(target_mob) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_player_panel, target_mob) else if(href_list["adminplayerobservefollow"]) if(!isobserver(usr) && !check_rights(R_ADMIN)) @@ -771,20 +759,13 @@ AM.forceMove(get_turf(usr)) else if(href_list["adminplayerobservecoodjump"]) - if(!isobserver(usr) && !check_rights(R_ADMIN)) - return - if(isnewplayer(usr)) - return - - var/x = text2num(href_list["X"]) - var/y = text2num(href_list["Y"]) - var/z = text2num(href_list["Z"]) - - var/client/C = usr.client - if(!isobserver(usr)) - C.admin_ghost() - sleep(0.2 SECONDS) - C.jumptocoord(x,y,z) + return SSadmin_verbs.dynamic_invoke_verb( + usr, + /datum/admin_verb/jump_to_coord, + text2num(href_list["X"]), + text2num(href_list["Y"]), + text2num(href_list["Z"]), + ) else if(href_list["adminchecklaws"]) if(!check_rights(R_ADMIN)) @@ -984,15 +965,7 @@ give_admin_popup(target, owner, message) else if(href_list["adminsmite"]) - if(!check_rights(R_ADMIN|R_FUN)) - return - - var/mob/living/carbon/human/H = locate(href_list["adminsmite"]) in GLOB.mob_list - if(!H || !istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human", confidential = TRUE) - return - - usr.client.smite(H) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/admin_smite, locate(href_list["adminsmite"])) else if(href_list["CentComReply"]) if(!check_rights(R_ADMIN)) @@ -1021,42 +994,21 @@ var/obj/item/station_charter/charter = locate(href_list["reject_custom_name"]) if(istype(charter)) charter.reject_proposed(usr) - else if(href_list["jumpto"]) - if(!isobserver(usr) && !check_rights(R_ADMIN)) - return - var/mob/M = locate(href_list["jumpto"]) - usr.client.jumptomob(M) + else if(href_list["jumpto"]) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/jump_to_mob, locate(href_list["jumpto"])) else if(href_list["getmob"]) - if(!check_rights(R_ADMIN)) - return - - if(tgui_alert(usr, "Confirm?", "Message", list("Yes", "No")) != "Yes") - return - var/mob/M = locate(href_list["getmob"]) - usr.client.Getmob(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/get_mob, locate(href_list["getmob"])) else if(href_list["sendmob"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["sendmob"]) - usr.client.sendmob(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/send_mob, locate(href_list["sendmob"])) else if(href_list["narrateto"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["narrateto"]) - usr.client.cmd_admin_direct_narrate(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_admin_direct_narrate, locate(href_list["narrateto"])) else if(href_list["subtlemessage"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["subtlemessage"]) - usr.client.cmd_admin_subtle_message(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_admin_subtle_message, locate(href_list["subtlemessage"])) else if(href_list["playsoundto"]) if(!check_rights(R_SOUND)) @@ -1065,7 +1017,7 @@ var/mob/M = locate(href_list["playsoundto"]) var/S = input("", "Select a sound file",) as null|sound if(S) - usr.client.play_direct_mob_sound(S, M) + SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/play_direct_mob_sound, S, M) else if(href_list["individuallog"]) if(!check_rights(R_ADMIN)) @@ -1104,7 +1056,8 @@ else D.traitor_panel() else - show_traitor_panel(M) + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_traitor_panel, M) + return else if(href_list["skill"]) if(!check_rights(R_ADMIN)) @@ -1124,17 +1077,11 @@ else to_chat(usr, "This can only be used on instances of type /mob and /mind", confidential = TRUE) return - show_skill_panel(target_mind) + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_skill_panel, target_mind) + return else if(href_list["borgpanel"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["borgpanel"]) - if(!iscyborg(M)) - to_chat(usr, "This can only be used on cyborgs", confidential = TRUE) - else - open_borgopanel(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/borg_panel, locate(href_list["borgpanel"])) else if(href_list["initmind"]) if(!check_rights(R_ADMIN)) @@ -1306,9 +1253,7 @@ return else if(href_list["check_antagonist"]) - if(!check_rights(R_ADMIN)) - return - usr.client.check_antagonists() + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/check_antagonists) else if(href_list["kick_all_from_lobby"]) if(!check_rights(R_ADMIN)) @@ -1378,7 +1323,7 @@ log_admin("[key_name(usr)] turned a Lag Switch measure at index ([switch_index]) [LAZYACCESS(SSlag_switch.measures, switch_index) ? "ON" : "OFF"]") message_admins("[key_name_admin(usr)] turned a Lag Switch measure [LAZYACCESS(SSlag_switch.measures, switch_index) ? "ON" : "OFF"]") - src.show_lag_switch_panel() + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/lag_switch_panel) else if(href_list["change_lag_switch_option"]) if(!check_rights(R_ADMIN)) @@ -1407,7 +1352,7 @@ log_admin("[key_name(usr)] set the Lag Switch slowmode cooldown to [new_num] seconds.") message_admins("[key_name_admin(usr)] set the Lag Switch slowmode cooldown to [new_num] seconds.") - src.show_lag_switch_panel() + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/lag_switch_panel) else if(href_list["viewruntime"]) var/datum/error_viewer/error_viewer = locate(href_list["viewruntime"]) @@ -1523,13 +1468,7 @@ toggle_id_ctf(usr, CTF_GHOST_CTF_GAME_ID) else if(href_list["rebootworld"]) - if(!check_rights(R_ADMIN)) - return - var/confirm = tgui_alert(usr,"Are you sure you want to reboot the server?", "Confirm Reboot", list("Yes", "No")) - if(confirm == "No") - return - if(confirm == "Yes") - restart() + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/restart) else if(href_list["check_teams"]) if(!check_rights(R_ADMIN)) @@ -1748,9 +1687,7 @@ return remove_tagged_datum(datum_to_remove) else if(href_list["show_tags"]) - if(!check_rights(R_ADMIN)) - return - return display_tags() + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/display_tags) else if(href_list["mark_datum"]) if(!check_rights(R_ADMIN)) @@ -1797,7 +1734,4 @@ web_sound(usr, link_url, credit) else if(href_list["debug_z_levels"]) - if(!check_rights(R_DEBUG)) - return - - owner.debug_z_levels() + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/debug_z_levels) diff --git a/code/modules/admin/trophy_manager.dm b/code/modules/admin/trophy_manager.dm index 6a45afb8e4593..5ad703b099427 100644 --- a/code/modules/admin/trophy_manager.dm +++ b/code/modules/admin/trophy_manager.dm @@ -1,11 +1,6 @@ -/datum/admins/proc/trophy_manager() - set name = "Trophy Manager" - set category = "Admin" - - if(!check_rights(R_ADMIN)) - return - var/datum/trophy_manager/ui = new(usr) - ui.ui_interact(usr) +ADMIN_VERB(trophy_manager, R_ADMIN, "Trophy Manager", "View all trophies.", ADMIN_CATEGORY_MAIN) + var/static/datum/trophy_manager/ui = new + ui.ui_interact(user.mob) /// Trophy Admin Management Panel /datum/trophy_manager diff --git a/code/modules/admin/verb_datums/_admin_verb_datum.dm b/code/modules/admin/verb_datums/_admin_verb_datum.dm new file mode 100644 index 0000000000000..6255d962c40c2 --- /dev/null +++ b/code/modules/admin/verb_datums/_admin_verb_datum.dm @@ -0,0 +1,27 @@ +GENERAL_PROTECT_DATUM(/datum/admin_verb) + +/** + * This is the admin verb datum. It is used to store the verb's information and handle the verb's functionality. + * All of this is setup for you, and you should not be defining this manually. + * That means you reader. + */ +/datum/admin_verb + var/name //! The name of the verb. + var/description //! The description of the verb. + var/category //! The category of the verb. + var/permissions //! The permissions required to use the verb. + var/visibility_flag //! The flag that determines if the verb is visible. + VAR_PROTECTED/verb_path //! The path to the verb proc. + +/datum/admin_verb/Destroy(force) + if(!force) + return QDEL_HINT_LETMELIVE + return ..() + +/// Assigns the verb to the admin. +/datum/admin_verb/proc/assign_to_client(client/admin) + add_verb(admin, verb_path) + +/// Unassigns the verb from the admin. +/datum/admin_verb/proc/unassign_from_client(client/admin) + remove_verb(admin, verb_path) diff --git a/code/modules/admin/verb_datums/_admin_verb_holder.dm b/code/modules/admin/verb_datums/_admin_verb_holder.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 17047dbcd6819..36db4fa8bc4b0 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -195,20 +195,15 @@ state = SDQL2_STATE_ERROR;\ CRASH("SDQL2 fatal error");}; -/client/proc/SDQL2_query(query_text as message) - set category = "Debug" - if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe. - message_admins(span_danger("ERROR: Non-admin [key_name(usr)] attempted to execute a SDQL query!")) - usr.log_message("non-admin attempted to execute a SDQL query!", LOG_ADMIN) - return FALSE - var/prompt = tgui_alert(usr, "Run SDQL2 Query?", "SDQL2", list("Yes", "Cancel")) +ADMIN_VERB(sdql2_query, R_DEBUG, "SDQL2 Query", "Run a SDQL2 query.", ADMIN_CATEGORY_DEBUG, query_text as message) + var/prompt = tgui_alert(user, "Run SDQL2 Query?", "SDQL2", list("Yes", "Cancel")) if (prompt != "Yes") return - var/list/results = world.SDQL2_query(query_text, key_name_admin(usr), "[key_name(usr)]") + var/list/results = world.SDQL2_query(query_text, key_name_admin(user), "[key_name(user)]") if(length(results) == 3) for(var/I in 1 to 3) - to_chat(usr, span_admin(results[I]), confidential = TRUE) - SSblackbox.record_feedback("nested tally", "SDQL query", 1, list(ckey, query_text)) + to_chat(user, span_admin(results[I]), confidential = TRUE) + SSblackbox.record_feedback("nested tally", "SDQL query", 1, list(user.ckey, query_text)) /world/proc/SDQL2_query(query_text, log_entry1, log_entry2, silent = FALSE) var/query_log = "executed SDQL query(s): \"[query_text]\"." @@ -1027,7 +1022,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/sdql2_vv_all, new(null return null else if(expression [start] == "{" && long) - if(lowertext(copytext(expression[start + 1], 1, 3)) != "0x") //3 == length("0x") + 1 + if(LOWER_TEXT(copytext(expression[start + 1], 1, 3)) != "0x") //3 == length("0x") + 1 to_chat(usr, span_danger("Invalid pointer syntax: [expression[start + 1]]"), confidential = TRUE) return null var/datum/located = locate("\[[expression[start + 1]]]") diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm index 58a18e1a9363d..eb2623398414a 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm @@ -109,7 +109,7 @@ return null /datum/sdql_parser/proc/tokenl(i) - return lowertext(token(i)) + return LOWER_TEXT(token(i)) /datum/sdql_parser/proc/query_options(i, list/node) var/list/options = list() @@ -624,7 +624,7 @@ node += "null" i++ - else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3))))//3 == length("0x") + 1 + else if(LOWER_TEXT(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3))))//3 == length("0x") + 1 node += hex2num(copytext(token(i), 3)) i++ diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm index 06c19ce5c91db..bc74347475ae9 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm @@ -81,8 +81,8 @@ /proc/_log(X, Y) return log(X, Y) -/proc/_lowertext(T) - return lowertext(T) +/proc/_LOWER_TEXT(T) + return LOWER_TEXT(T) /proc/_matrix(a, b, c, d, e, f) return matrix(a, b, c, d, e, f) diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm index 88c183ab507ea..88ee5148f7a3c 100644 --- a/code/modules/admin/verbs/admin.dm +++ b/code/modules/admin/verbs/admin.dm @@ -1,15 +1,5 @@ -// Admin Tab - Admin Verbs - -/client/proc/show_tip() - set category = "Admin" - set name = "Show Tip" - set desc = "Sends a tip (that you specify) to all players. After all \ - you're the experienced player here." - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please specify your tip that you want to send to the players.", "Tip", "") as message|null +ADMIN_VERB(show_tip, R_ADMIN, "Show Tip", "Sends a tip to all players.", ADMIN_CATEGORY_MAIN) + var/input = input(user, "Please specify your tip that you want to send to the players.", "Tip", "") as message|null if(!input) return @@ -22,44 +12,34 @@ else SSticker.selected_tip = input - message_admins("[key_name_admin(usr)] sent a tip of the round.") - log_admin("[key_name(usr)] sent \"[input]\" as the Tip of the Round.") + message_admins("[key_name_admin(user)] sent a tip of the round.") + log_admin("[key_name(user)] sent \"[input]\" as the Tip of the Round.") BLACKBOX_LOG_ADMIN_VERB("Show Tip") -/datum/admins/proc/announce() - set category = "Admin" - set name = "Announce" - set desc="Announce your desires to the world" - if(!check_rights(0)) +ADMIN_VERB(announce, R_ADMIN, "Announce", "Announce your desires to the world.", ADMIN_CATEGORY_MAIN) + var/message = input(user, "Global message to send:", "Admin Announce") as message|null + if(!message) return - var/message = input("Global message to send:", "Admin Announce", null, null) as message|null - if(message) - if(!check_rights(R_SERVER,0)) - message = adminscrub(message,500) - send_ooc_announcement(message, "From [usr.client.holder.fakekey ? "Administrator" : usr.key]") - log_admin("Announce: [key_name(usr)] : [message]") + if(!user.holder.check_for_rights(R_SERVER)) + message = adminscrub(message,500) + send_ooc_announcement(message, "From [user.holder.fakekey ? "Administrator" : user.key]") + log_admin("Announce: [key_name(user)] : [message]") BLACKBOX_LOG_ADMIN_VERB("Announce") -/datum/admins/proc/unprison(mob/M in GLOB.mob_list) - set category = "Admin" - set name = "Unprison" - if (is_centcom_level(M.z)) - SSjob.SendToLateJoin(M) - message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]") - log_admin("[key_name(usr)] has unprisoned [key_name(M)]") - else - tgui_alert(usr,"[M.name] is not prisoned.") - BLACKBOX_LOG_ADMIN_VERB("Unprison") - -/client/proc/cmd_admin_check_player_exp() //Allows admins to determine who the newer players are. - set category = "Admin" - set name = "Player Playtime" - if(!check_rights(R_ADMIN)) +ADMIN_VERB(unprison, R_ADMIN, "UnPrison", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/prisoner in GLOB.mob_list) + if(!is_centcom_level(prisoner.z)) + tgui_alert(user, "[prisoner.name] is not prisoned.") return + SSjob.SendToLateJoin(prisoner) + message_admins("[key_name_admin(user)] has unprisoned [key_name_admin(prisoner)]") + log_admin("[key_name(user)] has unprisoned [key_name(prisoner)]") + BLACKBOX_LOG_ADMIN_VERB("Unprison") + +ADMIN_VERB(cmd_admin_check_player_exp, R_ADMIN, "Player Playtime", "View player playtime.", ADMIN_CATEGORY_MAIN) if(!CONFIG_GET(flag/use_exp_tracking)) - to_chat(usr, span_warning("Tracking is disabled in the server configuration file."), confidential = TRUE) + to_chat(user, span_warning("Tracking is disabled in the server configuration file."), confidential = TRUE) return var/list/msg = list() @@ -67,7 +47,7 @@ for(var/client/client in sort_list(GLOB.clients, GLOBAL_PROC_REF(cmp_playtime_asc))) msg += "
  • [ADMIN_PP(client.mob)] [key_name_admin(client)]: " + client.get_exp_living() + "
  • " msg += "" - src << browse(msg.Join(), "window=Player_playtime_check") + user << browse(msg.Join(), "window=Player_playtime_check") /client/proc/trigger_centcom_recall() if(!check_rights(R_ADMIN)) @@ -164,23 +144,18 @@ /////////////////////////////////////////////////////////////////////////////////////////////// -/client/proc/cmd_admin_drop_everything(mob/M in GLOB.mob_list) - set category = null - set name = "Drop Everything" - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Make [M] drop everything?", "Message", list("Yes", "No")) +ADMIN_VERB(drop_everything, R_ADMIN, "Drop Everything", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/dropee in GLOB.mob_list) + var/confirm = tgui_alert(user, "Make [dropee] drop everything?", "Message", list("Yes", "No")) if(confirm != "Yes") return - M.drop_everything(del_on_drop = FALSE, force = TRUE, del_if_nodrop = TRUE) - M.regenerate_icons() + dropee.drop_everything(del_on_drop = FALSE, force = TRUE, del_if_nodrop = TRUE) + dropee.regenerate_icons() - log_admin("[key_name(usr)] made [key_name(M)] drop everything!") - var/msg = "[key_name_admin(usr)] made [ADMIN_LOOKUPFLW(M)] drop everything!" + log_admin("[key_name(user)] made [key_name(dropee)] drop everything!") + var/msg = "[key_name_admin(user)] made [ADMIN_LOOKUPFLW(dropee)] drop everything!" message_admins(msg) - admin_ticket_log(M, msg) + admin_ticket_log(dropee, msg) BLACKBOX_LOG_ADMIN_VERB("Drop Everything") /proc/cmd_admin_mute(whom, mute_type, automute = 0) diff --git a/code/modules/admin/verbs/admin_newscaster.dm b/code/modules/admin/verbs/admin_newscaster.dm index 2f6870394c277..0439cfa8811ac 100644 --- a/code/modules/admin/verbs/admin_newscaster.dm +++ b/code/modules/admin/verbs/admin_newscaster.dm @@ -1,17 +1,6 @@ -/datum/admins/proc/access_news_network() //MARKER - set category = "Admin.Events" - set name = "Access Newscaster Network" - set desc = "Allows you to view, add and edit news feeds." - - if (!istype(src, /datum/admins)) - src = usr.client.holder - if (!istype(src, /datum/admins)) - to_chat(usr, "Error: you are not an admin!", confidential = TRUE) - return - +ADMIN_VERB(access_news_network, R_ADMIN, "Access Newscaster Network", "Allows you to view, add, and edit news feeds.", ADMIN_CATEGORY_EVENTS) var/datum/newspanel/new_newspanel = new - - new_newspanel.ui_interact(usr) + new_newspanel.ui_interact(user.mob) /datum/newspanel ///What newscaster channel is currently being viewed by the player? diff --git a/code/modules/admin/verbs/adminevents.dm b/code/modules/admin/verbs/adminevents.dm index f69e891625a6d..035edeb3d93e4 100644 --- a/code/modules/admin/verbs/adminevents.dm +++ b/code/modules/admin/verbs/adminevents.dm @@ -1,37 +1,24 @@ // Admin Tab - Event Verbs -/client/proc/cmd_admin_subtle_message(mob/M in GLOB.mob_list) - set category = "Admin.Events" - set name = "Subtle Message" +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_subtle_message, R_ADMIN, "Subtle Message", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/target in world) + message_admins("[key_name_admin(user)] has started answering [ADMIN_LOOKUPFLW(target)]'s prayer.") + var/msg = input(user, "Message:", "Subtle PM to [target.key]") as text|null - if(!ismob(M)) - return - if(!check_rights(R_ADMIN)) + if(!msg) + message_admins("[key_name_admin(user)] decided not to answer [ADMIN_LOOKUPFLW(target)]'s prayer") return - message_admins("[key_name_admin(src)] has started answering [ADMIN_LOOKUPFLW(M)]'s prayer.") - var/msg = input("Message:", "Subtle PM to [M.key]") as text|null + target.balloon_alert(target, "you hear a voice") + to_chat(target, "You hear a voice in your head... [msg]", confidential = TRUE) - if(!msg) - message_admins("[key_name_admin(src)] decided not to answer [ADMIN_LOOKUPFLW(M)]'s prayer") - return - if(usr) - if (usr.client) - if(usr.client.holder) - M.balloon_alert(M, "you hear a voice") - to_chat(M, "You hear a voice in your head... [msg]", confidential = TRUE) - - log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]") - msg = span_adminnotice(" SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]") + log_admin("SubtlePM: [key_name(user)] -> [key_name(target)] : [msg]") + msg = span_adminnotice(" SubtleMessage: [key_name_admin(user)] -> [key_name_admin(target)] : [msg]") message_admins(msg) - admin_ticket_log(M, msg) + admin_ticket_log(target, msg) BLACKBOX_LOG_ADMIN_VERB("Subtle Message") -/client/proc/cmd_admin_headset_message(mob/M in GLOB.mob_list) - set category = "Admin.Events" - set name = "Headset Message" - - admin_headset_message(M) +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_headset_message, R_ADMIN, "Headset Message", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/target in world) + user.admin_headset_message(target) /client/proc/admin_headset_message(mob/target in GLOB.mob_list, sender = null) var/mob/living/carbon/human/human_recipient @@ -73,102 +60,64 @@ BLACKBOX_LOG_ADMIN_VERB("Headset Message") -/client/proc/cmd_admin_world_narrate() - set category = "Admin.Events" - set name = "Global Narrate" - - if(!check_rights(R_ADMIN)) - return - - var/msg = input("Message:", "Enter the text you wish to appear to everyone:") as text|null - +ADMIN_VERB(cmd_admin_world_narrate, R_ADMIN, "Global Narrate", "Send a direct narration to all connected players.", ADMIN_CATEGORY_EVENTS) + var/msg = input(user, "Message:", "Enter the text you wish to appear to everyone:") as text|null if (!msg) return to_chat(world, "[msg]", confidential = TRUE) - log_admin("GlobalNarrate: [key_name(usr)] : [msg]") - message_admins(span_adminnotice("[key_name_admin(usr)] Sent a global narrate")) + log_admin("GlobalNarrate: [key_name(user)] : [msg]") + message_admins(span_adminnotice("[key_name_admin(user)] Sent a global narrate")) BLACKBOX_LOG_ADMIN_VERB("Global Narrate") -/client/proc/cmd_admin_local_narrate(atom/A) - set category = "Admin.Events" - set name = "Local Narrate" - - if(!check_rights(R_ADMIN)) - return - if(!A) - return - var/range = input("Range:", "Narrate to mobs within how many tiles:", 7) as num|null +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_local_narrate, R_ADMIN, "Local Narrate", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/locale in world) + var/range = input(user, "Range:", "Narrate to mobs within how many tiles:", 7) as num|null if(!range) return - var/msg = input("Message:", "Enter the text you wish to appear to everyone within view:") as text|null + var/msg = input(user, "Message:", "Enter the text you wish to appear to everyone within view:") as text|null if (!msg) return - for(var/mob/M in view(range,A)) + for(var/mob/M in view(range, locale)) to_chat(M, msg, confidential = TRUE) - log_admin("LocalNarrate: [key_name(usr)] at [AREACOORD(A)]: [msg]") - message_admins(span_adminnotice(" LocalNarrate: [key_name_admin(usr)] at [ADMIN_VERBOSEJMP(A)]: [msg]
    ")) + log_admin("LocalNarrate: [key_name(user)] at [AREACOORD(locale)]: [msg]") + message_admins(span_adminnotice(" LocalNarrate: [key_name_admin(user)] at [ADMIN_VERBOSEJMP(locale)]: [msg]
    ")) BLACKBOX_LOG_ADMIN_VERB("Local Narrate") -/client/proc/cmd_admin_direct_narrate(mob/M) - set category = "Admin.Events" - set name = "Direct Narrate" - - if(!check_rights(R_ADMIN)) - return - - if(!M) - M = input("Direct narrate to whom?", "Active Players") as null|anything in GLOB.player_list - - if(!M) - return - - var/msg = input("Message:", "Enter the text you wish to appear to your target:") as text|null +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_direct_narrate, R_ADMIN, "Direct Narrate", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/target) + var/msg = input(user, "Message:", "Enter the text you wish to appear to your target:") as text|null if( !msg ) return - to_chat(M, msg, confidential = TRUE) - log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]") - msg = span_adminnotice(" DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]
    ") + to_chat(target, msg, confidential = TRUE) + log_admin("DirectNarrate: [key_name(user)] to ([key_name(target)]): [msg]") + msg = span_adminnotice(" DirectNarrate: [key_name_admin(user)] to ([key_name_admin(target)]): [msg]
    ") message_admins(msg) - admin_ticket_log(M, msg) + admin_ticket_log(target, msg) BLACKBOX_LOG_ADMIN_VERB("Direct Narrate") -/client/proc/cmd_admin_add_freeform_ai_law() - set category = "Admin.Events" - set name = "Add Custom AI law" - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null +ADMIN_VERB(cmd_admin_add_freeform_ai_law, R_ADMIN, "Add Custom AI Law", "Add a custom law to the Silicons.", ADMIN_CATEGORY_EVENTS) + var/input = input(user, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null if(!input) return - log_admin("Admin [key_name(usr)] has added a new AI law - [input]") - message_admins("Admin [key_name_admin(usr)] has added a new AI law - [input]") + log_admin("Admin [key_name(user)] has added a new AI law - [input]") + message_admins("Admin [key_name_admin(user)] has added a new AI law - [input]") - var/show_log = tgui_alert(usr, "Show ion message?", "Message", list("Yes", "No")) + var/show_log = tgui_alert(user, "Show ion message?", "Message", list("Yes", "No")) var/announce_ion_laws = (show_log == "Yes" ? 100 : 0) - var/datum/round_event/ion_storm/add_law_only/ion = new() + var/datum/round_event/ion_storm/add_law_only/ion = new ion.announce_chance = announce_ion_laws ion.ionMessage = input BLACKBOX_LOG_ADMIN_VERB("Add Custom AI Law") -/client/proc/admin_call_shuttle() - set category = "Admin.Events" - set name = "Call Shuttle" - +ADMIN_VERB(call_shuttle, R_ADMIN, "Call Shuttle", "Force a shuttle call with additional modifiers.", ADMIN_CATEGORY_EVENTS) if(EMERGENCY_AT_LEAST_DOCKED) return - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "You sure?", "Confirm", list("Yes", "Yes (No Recall)", "No")) + var/confirm = tgui_alert(user, "You sure?", "Confirm", list("Yes", "Yes (No Recall)", "No")) switch(confirm) if(null, "No") return @@ -178,46 +127,30 @@ SSshuttle.emergency.request() BLACKBOX_LOG_ADMIN_VERB("Call Shuttle") - log_admin("[key_name(usr)] admin-called the emergency shuttle.") - message_admins(span_adminnotice("[key_name_admin(usr)] admin-called the emergency shuttle[confirm == "Yes (No Recall)" ? " (non-recallable)" : ""].")) - return - -/client/proc/admin_cancel_shuttle() - set category = "Admin.Events" - set name = "Cancel Shuttle" - if(!check_rights(0)) - return - if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") - return - - if(SSshuttle.admin_emergency_no_recall) - SSshuttle.admin_emergency_no_recall = FALSE + log_admin("[key_name(user)] admin-called the emergency shuttle.") + message_admins(span_adminnotice("[key_name_admin(user)] admin-called the emergency shuttle[confirm == "Yes (No Recall)" ? " (non-recallable)" : ""].")) +ADMIN_VERB(cancel_shuttle, R_ADMIN, "Cancel Shuttle", "Recall the shuttle, regardless of circumstances.", ADMIN_CATEGORY_EVENTS) if(EMERGENCY_AT_LEAST_DOCKED) return + if(tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) != "Yes") + return + SSshuttle.admin_emergency_no_recall = FALSE SSshuttle.emergency.cancel() BLACKBOX_LOG_ADMIN_VERB("Cancel Shuttle") - log_admin("[key_name(usr)] admin-recalled the emergency shuttle.") - message_admins(span_adminnotice("[key_name_admin(usr)] admin-recalled the emergency shuttle.")) - - return - -/client/proc/admin_disable_shuttle() - set category = "Admin.Events" - set name = "Disable Shuttle" - - if(!check_rights(R_ADMIN)) - return + log_admin("[key_name(user)] admin-recalled the emergency shuttle.") + message_admins(span_adminnotice("[key_name_admin(user)] admin-recalled the emergency shuttle.")) +ADMIN_VERB(disable_shuttle, R_ADMIN, "Disable Shuttle", "Those fuckers aren't getting out.", ADMIN_CATEGORY_EVENTS) if(SSshuttle.emergency.mode == SHUTTLE_DISABLED) - to_chat(usr, span_warning("Error, shuttle is already disabled.")) + to_chat(user, span_warning("Error, shuttle is already disabled.")) return - if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") + if(tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) != "Yes") return - message_admins(span_adminnotice("[key_name_admin(usr)] disabled the shuttle.")) + message_admins(span_adminnotice("[key_name_admin(user)] disabled the shuttle.")) SSshuttle.last_mode = SSshuttle.emergency.mode SSshuttle.last_call_time = SSshuttle.emergency.timeLeft(1) @@ -232,21 +165,15 @@ color_override = "grey", ) -/client/proc/admin_enable_shuttle() - set category = "Admin.Events" - set name = "Enable Shuttle" - - if(!check_rights(R_ADMIN)) - return - +ADMIN_VERB(enable_shuttle, R_ADMIN, "Enable Shuttle", "Those fuckers ARE getting out.", ADMIN_CATEGORY_EVENTS) if(SSshuttle.emergency.mode != SHUTTLE_DISABLED) - to_chat(usr, span_warning("Error, shuttle not disabled.")) + to_chat(user, span_warning("Error, shuttle not disabled.")) return - if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") + if(tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) != "Yes") return - message_admins(span_adminnotice("[key_name_admin(usr)] enabled the emergency shuttle.")) + message_admins(span_adminnotice("[key_name_admin(user)] enabled the emergency shuttle.")) SSshuttle.admin_emergency_no_recall = FALSE SSshuttle.emergency_no_recall = FALSE if(SSshuttle.last_mode == SHUTTLE_DISABLED) //If everything goes to shit, fix it. @@ -264,159 +191,90 @@ color_override = "green", ) -/client/proc/admin_hostile_environment() - set category = "Admin.Events" - set name = "Hostile Environment" - - if(!check_rights(R_ADMIN)) - return - - switch(tgui_alert(usr, "Select an Option", "Hostile Environment Manager", list("Enable", "Disable", "Clear All"))) +ADMIN_VERB(hostile_environment, R_ADMIN, "Hostile Environment", "Disable the shuttle, naturally.", ADMIN_CATEGORY_EVENTS) + switch(tgui_alert(user, "Select an Option", "Hostile Environment Manager", list("Enable", "Disable", "Clear All"))) if("Enable") if (SSshuttle.hostile_environments["Admin"] == TRUE) - to_chat(usr, span_warning("Error, admin hostile environment already enabled.")) + to_chat(user, span_warning("Error, admin hostile environment already enabled.")) else - message_admins(span_adminnotice("[key_name_admin(usr)] Enabled an admin hostile environment")) + message_admins(span_adminnotice("[key_name_admin(user)] Enabled an admin hostile environment")) SSshuttle.registerHostileEnvironment("Admin") if("Disable") if (!SSshuttle.hostile_environments["Admin"]) - to_chat(usr, span_warning("Error, no admin hostile environment found.")) + to_chat(user, span_warning("Error, no admin hostile environment found.")) else - message_admins(span_adminnotice("[key_name_admin(usr)] Disabled the admin hostile environment")) + message_admins(span_adminnotice("[key_name_admin(user)] Disabled the admin hostile environment")) SSshuttle.clearHostileEnvironment("Admin") if("Clear All") - message_admins(span_adminnotice("[key_name_admin(usr)] Disabled all current hostile environment sources")) + message_admins(span_adminnotice("[key_name_admin(user)] Disabled all current hostile environment sources")) SSshuttle.hostile_environments.Cut() SSshuttle.checkHostileEnvironment() -/client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb)) - set category = "Admin.Events" - set name = "Toggle Nuke" - set popup_menu = FALSE - if(!check_rights(R_DEBUG)) - return - - if(!N.timing) - var/newtime = input(usr, "Set activation timer.", "Activate Nuke", "[N.timer_set]") as num|null +ADMIN_VERB(toggle_nuke, R_DEBUG|R_ADMIN, "Toggle Nuke", "Arm or disarm a nuke.", ADMIN_CATEGORY_EVENTS, obj/machinery/nuclearbomb/nuke in world) + if(!nuke.timing) + var/newtime = input(user, "Set activation timer.", "Activate Nuke", "[nuke.timer_set]") as num|null if(!newtime) return - N.timer_set = newtime - N.toggle_nuke_safety() - N.toggle_nuke_armed() - - log_admin("[key_name(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [AREACOORD(N)].") - message_admins("[ADMIN_LOOKUPFLW(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(N)].") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[N.timing]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! + nuke.timer_set = newtime + nuke.toggle_nuke_safety() + nuke.toggle_nuke_armed() -/client/proc/admin_change_sec_level() - set category = "Admin.Events" - set name = "Set Security Level" - set desc = "Changes the security level. Announcement only, i.e. setting to Delta won't activate nuke" - - if(!check_rights(R_ADMIN)) - return + log_admin("[key_name(user)] [nuke.timing ? "activated" : "deactivated"] a nuke at [AREACOORD(nuke)].") + message_admins("[ADMIN_LOOKUPFLW(user)] [nuke.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(nuke)].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[nuke.timing]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! - var/level = tgui_input_list(usr, "Select Security Level:", "Set Security Level", SSsecurity_level.available_levels) +ADMIN_VERB(change_sec_level, R_ADMIN, "Set Security Level", "Changes the security level. Announcement effects only.", ADMIN_CATEGORY_EVENTS) + var/level = tgui_input_list(user, "Select Security Level:", "Set Security Level", SSsecurity_level.available_levels) if(!level) return SSsecurity_level.set_level(level) - log_admin("[key_name(usr)] changed the security level to [level]") - message_admins("[key_name_admin(usr)] changed the security level to [level]") + log_admin("[key_name(user)] changed the security level to [level]") + message_admins("[key_name_admin(user)] changed the security level to [level]") BLACKBOX_LOG_ADMIN_VERB("Set Security Level [capitalize(level)]") -/client/proc/run_weather() - set category = "Admin.Events" - set name = "Run Weather" - set desc = "Triggers a weather on the z-level you choose." - - if(!holder) - return - - var/weather_type = input("Choose a weather", "Weather") as null|anything in sort_list(subtypesof(/datum/weather), GLOBAL_PROC_REF(cmp_typepaths_asc)) +ADMIN_VERB(run_weather, R_FUN, "Run Weather", "Triggers specific weather on the z-level you choose.", ADMIN_CATEGORY_EVENTS) + var/weather_type = input(user, "Choose a weather", "Weather") as null|anything in sort_list(subtypesof(/datum/weather), GLOBAL_PROC_REF(cmp_typepaths_asc)) if(!weather_type) return - var/turf/T = get_turf(mob) - var/z_level = input("Z-Level to target?", "Z-Level", T?.z) as num|null + var/turf/T = get_turf(user.mob) + var/z_level = input(user, "Z-Level to target?", "Z-Level", T?.z) as num|null if(!isnum(z_level)) return SSweather.run_weather(weather_type, z_level) - message_admins("[key_name_admin(usr)] started weather of type [weather_type] on the z-level [z_level].") - log_admin("[key_name(usr)] started weather of type [weather_type] on the z-level [z_level].") + message_admins("[key_name_admin(user)] started weather of type [weather_type] on the z-level [z_level].") + log_admin("[key_name(user)] started weather of type [weather_type] on the z-level [z_level].") BLACKBOX_LOG_ADMIN_VERB("Run Weather") -/client/proc/add_marked_mob_ability() - set category = "Admin.Events" - set name = "Add Mob Ability (Marked Mob)" - set desc = "Adds an ability to a marked mob." - - if(!holder) - return - - if(!isliving(holder.marked_datum)) - to_chat(usr, span_warning("Error: Please mark a mob to add actions to it.")) - return - give_mob_action(holder.marked_datum) - -/client/proc/remove_marked_mob_ability() - set category = "Admin.Events" - set name = "Remove Mob Ability (Marked Mob)" - set desc = "Removes an ability from marked mob." - - if(!holder) - return - - if(!isliving(holder.marked_datum)) - to_chat(usr, span_warning("Error: Please mark a mob to remove actions from it.")) - return - remove_mob_action(holder.marked_datum) - -/client/proc/command_report_footnote() - set category = "Admin.Events" - set name = "Command Report Footnote" - set desc = "Adds a footnote to the roundstart command report." - - if(!check_rights(R_ADMIN)) - return - +ADMIN_VERB(command_report_footnote, R_ADMIN, "Command Report Footnote", "Adds a footnote to the roundstart command report.", ADMIN_CATEGORY_EVENTS) var/datum/command_footnote/command_report_footnote = new /datum/command_footnote() - SScommunications.block_command_report++ //Add a blocking condition to the counter until the inputs are done. - - command_report_footnote.message = tgui_input_text(usr, "This message will be attached to the bottom of the roundstart threat report. Be sure to delay the roundstart report if you need extra time.", "P.S.") + GLOB.communications_controller.block_command_report += 1 //Add a blocking condition to the counter until the inputs are done. + command_report_footnote.message = tgui_input_text(user, "This message will be attached to the bottom of the roundstart threat report. Be sure to delay the roundstart report if you need extra time.", "P.S.") if(!command_report_footnote.message) + GLOB.communications_controller.block_command_report -= 1 + qdel(command_report_footnote) return - command_report_footnote.signature = tgui_input_text(usr, "Whose signature will appear on this footnote?", "Also sign here, here, aaand here.") + command_report_footnote.signature = tgui_input_text(user, "Whose signature will appear on this footnote?", "Also sign here, here, aaand here.") if(!command_report_footnote.signature) command_report_footnote.signature = "Classified" - SScommunications.command_report_footnotes += command_report_footnote - SScommunications.block_command_report-- + GLOB.communications_controller.command_report_footnotes += command_report_footnote + GLOB.communications_controller.block_command_report-- - message_admins("[usr] has added a footnote to the command report: [command_report_footnote.message], signed [command_report_footnote.signature]") + message_admins("[user] has added a footnote to the command report: [command_report_footnote.message], signed [command_report_footnote.signature]") /datum/command_footnote var/message var/signature -/client/proc/delay_command_report() - set category = "Admin.Events" - set name = "Delay Command Report" - set desc = "Prevents the roundstart command report from being sent until toggled." - - if(!check_rights(R_ADMIN)) - return - - if(SScommunications.block_command_report) //If it's anything other than 0, decrease. If 0, increase. - SScommunications.block_command_report-- - message_admins("[usr] has enabled the roundstart command report.") - else - SScommunications.block_command_report++ - message_admins("[usr] has delayed the roundstart command report.") +ADMIN_VERB(delay_command_report, R_FUN, "Delay Command Report", "Prevents the roundstart command report from being sent; or forces it to send it delayed.", ADMIN_CATEGORY_EVENTS) + GLOB.communications_controller.block_command_report = !GLOB.communications_controller.block_command_report + message_admins("[key_name_admin(user)] has [(GLOB.communications_controller.block_command_report ? "delayed" : "sent")] the roundstart command report.") diff --git a/code/modules/admin/verbs/adminfun.dm b/code/modules/admin/verbs/adminfun.dm index fcba8d40928ca..8bc7a611b35d4 100644 --- a/code/modules/admin/verbs/adminfun.dm +++ b/code/modules/admin/verbs/adminfun.dm @@ -1,74 +1,54 @@ -// Admin Tab - Fun Verbs - -/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world) - set category = "Admin.Fun" - set name = "Explosion" - - if(!check_rights(R_ADMIN)) - return - - var/devastation = input("Range of total devastation. -1 to none", "Input") as num|null +ADMIN_VERB(admin_explosion, R_ADMIN|R_FUN, "Explosion", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/orignator as obj|mob|turf) + var/devastation = input(user, "Range of total devastation. -1 to none", "Input") as num|null if(devastation == null) return - var/heavy = input("Range of heavy impact. -1 to none", "Input") as num|null + var/heavy = input(user, "Range of heavy impact. -1 to none", "Input") as num|null if(heavy == null) return - var/light = input("Range of light impact. -1 to none", "Input") as num|null + var/light = input(user, "Range of light impact. -1 to none", "Input") as num|null if(light == null) return - var/flash = input("Range of flash. -1 to none", "Input") as num|null + var/flash = input(user, "Range of flash. -1 to none", "Input") as num|null if(flash == null) return - var/flames = input("Range of flames. -1 to none", "Input") as num|null + var/flames = input(user, "Range of flames. -1 to none", "Input") as num|null if(flames == null) return if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1) || (flames != -1)) if ((devastation > 20) || (heavy > 20) || (light > 20) || (flames > 20)) - if (tgui_alert(usr, "Are you sure you want to do this? It will laaag.", "Confirmation", list("Yes", "No")) == "No") + if (tgui_alert(user, "Are you sure you want to do this? It will laaag.", "Confirmation", list("Yes", "No")) == "No") return - explosion(O, devastation, heavy, light, flames, flash, explosion_cause = mob) - log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]") - message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]") + explosion(orignator, devastation, heavy, light, flames, flash, explosion_cause = user.mob) + log_admin("[key_name(user)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(orignator)]") + message_admins("[key_name_admin(user)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(orignator)]") BLACKBOX_LOG_ADMIN_VERB("Explosion") -/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world) - set category = "Admin.Fun" - set name = "EM Pulse" - - if(!check_rights(R_ADMIN)) - return - - var/heavy = input("Range of heavy pulse.", "Input") as num|null +ADMIN_VERB(admin_emp, R_ADMIN|R_FUN, "EM Pulse", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/orignator as obj|mob|turf) + var/heavy = input(user, "Range of heavy pulse.", "Input") as num|null if(heavy == null) return - var/light = input("Range of light pulse.", "Input") as num|null + var/light = input(user, "Range of light pulse.", "Input") as num|null if(light == null) return if (heavy || light) - empulse(O, heavy, light) - log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at [AREACOORD(O)]") - message_admins("[key_name_admin(usr)] created an EM Pulse ([heavy],[light]) at [AREACOORD(O)]") + empulse(orignator, heavy, light) + log_admin("[key_name(user)] created an EM Pulse ([heavy],[light]) at [AREACOORD(orignator)]") + message_admins("[key_name_admin(user)] created an EM Pulse ([heavy],[light]) at [AREACOORD(orignator)]") BLACKBOX_LOG_ADMIN_VERB("EM Pulse") -/client/proc/cmd_admin_gib(mob/victim in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Gib" - - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Drop a brain?", "Confirm", list("Yes", "No","Cancel")) || "Cancel" +ADMIN_VERB(gib_them, R_ADMIN, "Gib", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/victim in GLOB.mob_list) + var/confirm = tgui_alert(user, "Drop a brain?", "Confirm", list("Yes", "No","Cancel")) || "Cancel" if(confirm == "Cancel") return //Due to the delay here its easy for something to have happened to the mob if(isnull(victim)) return - log_admin("[key_name(usr)] has gibbed [key_name(victim)]") - message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(victim)]") + log_admin("[key_name(user)] has gibbed [key_name(victim)]") + message_admins("[key_name_admin(user)] has gibbed [key_name_admin(victim)]") if(isobserver(victim)) new /obj/effect/gibspawner/generic(get_turf(victim)) @@ -84,62 +64,47 @@ BLACKBOX_LOG_ADMIN_VERB("Gib") -/client/proc/cmd_admin_gib_self() - set name = "Gibself" - set category = "Admin.Fun" - - var/confirm = tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) +ADMIN_VERB(gib_self, R_ADMIN, "Gibself", "Give yourself the same treatment you give others.", ADMIN_CATEGORY_FUN) + var/confirm = tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) if(confirm != "Yes") return - log_admin("[key_name(usr)] used gibself.") - message_admins(span_adminnotice("[key_name_admin(usr)] used gibself.")) + log_admin("[key_name(user)] used gibself.") + message_admins(span_adminnotice("[key_name_admin(user)] used gibself.")) BLACKBOX_LOG_ADMIN_VERB("Gib Self") - var/mob/living/ourself = mob + var/mob/living/ourself = user.mob if (istype(ourself)) ourself.gib() -/client/proc/everyone_random() - set category = "Admin.Fun" - set name = "Make Everyone Random" - set desc = "Make everyone have a random appearance. You can only use this before rounds!" - +ADMIN_VERB(everyone_random, R_SERVER, "Make Everyone Random", "Make everyone have a random appearance.", ADMIN_CATEGORY_FUN) if(SSticker.HasRoundStarted()) - to_chat(usr, "Nope you can't do this, the game's already started. This only works before rounds!", confidential = TRUE) + to_chat(user, "Nope you can't do this, the game's already started. This only works before rounds!", confidential = TRUE) return var/frn = CONFIG_GET(flag/force_random_names) if(frn) CONFIG_SET(flag/force_random_names, FALSE) - message_admins("Admin [key_name_admin(usr)] has disabled \"Everyone is Special\" mode.") - to_chat(usr, "Disabled.", confidential = TRUE) + message_admins("Admin [key_name_admin(user)] has disabled \"Everyone is Special\" mode.") + to_chat(user, "Disabled.", confidential = TRUE) return - var/notifyplayers = tgui_alert(usr, "Do you want to notify the players?", "Options", list("Yes", "No", "Cancel")) || "Cancel" + var/notifyplayers = tgui_alert(user, "Do you want to notify the players?", "Options", list("Yes", "No", "Cancel")) || "Cancel" if(notifyplayers == "Cancel") return - log_admin("Admin [key_name(src)] has forced the players to have random appearances.") - message_admins("Admin [key_name_admin(usr)] has forced the players to have random appearances.") + log_admin("Admin [key_name(user)] has forced the players to have random appearances.") + message_admins("Admin [key_name_admin(user)] has forced the players to have random appearances.") if(notifyplayers == "Yes") - to_chat(world, span_adminnotice("Admin [usr.key] has forced the players to have completely random identities!"), confidential = TRUE) + to_chat(world, span_adminnotice("Admin [user.key] has forced the players to have completely random identities!"), confidential = TRUE) - to_chat(usr, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.", confidential = TRUE) + to_chat(user, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.", confidential = TRUE) CONFIG_SET(flag/force_random_names, TRUE) BLACKBOX_LOG_ADMIN_VERB("Make Everyone Random") -/client/proc/mass_zombie_infection() - set category = "Admin.Fun" - set name = "Mass Zombie Infection" - set desc = "Infects all humans with a latent organ that will zombify \ - them on death." - - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Please confirm you want to add latent zombie organs in all humans?", "Confirm Zombies", list("Yes", "No")) +ADMIN_VERB(mass_zombie_infection, R_ADMIN, "Mass Zombie Infection", "Infects all humans with a latent organ that will zombify them on death.", ADMIN_CATEGORY_FUN) + var/confirm = tgui_alert(user, "Please confirm you want to add latent zombie organs in all humans?", "Confirm Zombies", list("Yes", "No")) if(confirm != "Yes") return @@ -147,45 +112,32 @@ var/mob/living/carbon/human/H = i new /obj/item/organ/internal/zombie_infection/nodamage(H) - message_admins("[key_name_admin(usr)] added a latent zombie infection to all humans.") - log_admin("[key_name(usr)] added a latent zombie infection to all humans.") + message_admins("[key_name_admin(user)] added a latent zombie infection to all humans.") + log_admin("[key_name(user)] added a latent zombie infection to all humans.") BLACKBOX_LOG_ADMIN_VERB("Mass Zombie Infection") -/client/proc/mass_zombie_cure() - set category = "Admin.Fun" - set name = "Mass Zombie Cure" - set desc = "Removes the zombie infection from all humans, returning them to normal." - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Please confirm you want to cure all zombies?", "Confirm Zombie Cure", list("Yes", "No")) +ADMIN_VERB(mass_zombie_cure, R_ADMIN, "Mass Zombie Cure", "Removes the zombie infection from all humans, returning them to normal.", ADMIN_CATEGORY_FUN) + var/confirm = tgui_alert(user, "Please confirm you want to cure all zombies?", "Confirm Zombie Cure", list("Yes", "No")) if(confirm != "Yes") return for(var/obj/item/organ/internal/zombie_infection/nodamage/I in GLOB.zombie_infection_list) qdel(I) - message_admins("[key_name_admin(usr)] cured all zombies.") - log_admin("[key_name(usr)] cured all zombies.") + message_admins("[key_name_admin(user)] cured all zombies.") + log_admin("[key_name(user)] cured all zombies.") BLACKBOX_LOG_ADMIN_VERB("Mass Zombie Cure") -/client/proc/polymorph_all() - set category = "Admin.Fun" - set name = "Polymorph All" - set desc = "Applies the effects of the bolt of change to every single mob." - - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Please confirm you want polymorph all mobs?", "Confirm Polymorph", list("Yes", "No")) +ADMIN_VERB(polymorph_all, R_ADMIN, "Polymorph All", "Applies the effects of the bolt of change to every single mob.", ADMIN_CATEGORY_FUN) + var/confirm = tgui_alert(user, "Please confirm you want polymorph all mobs?", "Confirm Polymorph", list("Yes", "No")) if(confirm != "Yes") return var/list/mobs = shuffle(GLOB.alive_mob_list.Copy()) // might change while iterating - var/who_did_it = key_name_admin(usr) + var/who_did_it = key_name_admin(user) - message_admins("[key_name_admin(usr)] started polymorphed all living mobs.") - log_admin("[key_name(usr)] polymorphed all living mobs.") + message_admins("[key_name_admin(user)] started polymorphed all living mobs.") + log_admin("[key_name(user)] polymorphed all living mobs.") BLACKBOX_LOG_ADMIN_VERB("Polymorph All") for(var/mob/living/M in mobs) @@ -201,23 +153,18 @@ message_admins("Mass polymorph started by [who_did_it] is complete.") -/client/proc/smite(mob/living/target as mob) - set category = "Admin.Fun" - set name = "Smite" - if(!check_rights(R_ADMIN) || !check_rights(R_FUN)) - return - - var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in GLOB.smites +ADMIN_VERB_AND_CONTEXT_MENU(admin_smite, R_ADMIN|R_FUN, "Smite", "Smite a player with divine power.", ADMIN_CATEGORY_FUN, mob/living/target in world) + var/punishment = input(user, "Choose a punishment", "DIVINE SMITING") as null|anything in GLOB.smites if(QDELETED(target) || !punishment) return var/smite_path = GLOB.smites[punishment] var/datum/smite/smite = new smite_path - var/configuration_success = smite.configure(usr) + var/configuration_success = smite.configure(user) if (configuration_success == FALSE) return - smite.effect(src, target) + smite.effect(user, target) /// "Turns" people into objects. Really, we just add them to the contents of the item. /proc/objectify(atom/movable/target, path) diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index f133d486fdbde..0e1e6809daae0 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -1,159 +1,153 @@ -// Admin Tab - Game Verbs +ADMIN_VERB(cmd_player_panel, R_ADMIN, "Player Panel", "See all players and their Player Panel.", ADMIN_CATEGORY_GAME) + user.holder.player_panel_new() -/datum/admins/proc/show_player_panel(mob/M in GLOB.mob_list) - set category = "Admin.Game" - set name = "Show Player Panel" - set desc="Edit player (respawn, ban, heal, etc)" - - if(!check_rights()) - return +ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mob/player in world) + log_admin("[key_name(user)] checked the individual player panel for [key_name(player)][isobserver(user.mob)?"":" while in game"].") - log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].") - - if(!M) - to_chat(usr, span_warning("You seem to be selecting a mob that doesn't exist anymore."), confidential = TRUE) + if(!player) + to_chat(user, span_warning("You seem to be selecting a mob that doesn't exist anymore."), confidential = TRUE) return - var/body = "Options for [M.key]" - body += "Options panel for [M]" - if(M.client) - body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank_names() : "Player"]\]" + var/body = "Options for [player.key]" + body += "Options panel for [player]" + if(player.client) + body += " played by [player.client] " + body += "\[[player.client.holder ? player.client.holder.rank_names() : "Player"]\]" if(CONFIG_GET(flag/use_exp_tracking)) - body += "\[" + M.client.get_exp_living(FALSE) + "\]" + body += "\[" + player.client.get_exp_living(FALSE) + "\]" - if(isnewplayer(M)) + if(isnewplayer(player)) body += " Hasn't Entered Game " else - body += " \[Heal\] " + body += " \[Heal\] " - if(M.ckey) - body += "
    \[Find Updated Panel\]" + if(player.ckey) + body += "
    \[Find Updated Panel\]" - if(M.client) - body += "
    \[First Seen: [M.client.player_join_date]\]\[Byond account registered on: [M.client.account_join_date]\]" + if(player.client) + body += "
    \[First Seen: [player.client.player_join_date]\]\[Byond account registered on: [player.client.account_join_date]\]" body += "

    CentCom Galactic Ban DB: " if(CONFIG_GET(string/centcom_ban_db)) - body += "Search" + body += "Search" else body += "Disabled" body += "

    Show related accounts by: " - body += "\[ CID | " - body += "IP \]" + body += "\[ CID | " + body += "IP \]" var/full_version = "Unknown" - if(M.client.byond_version) - full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]" + if(player.client.byond_version) + full_version = "[player.client.byond_version].[player.client.byond_build ? player.client.byond_build : "xxx"]" body += "
    \[Byond version: [full_version]\]
    " body += "

    \[ " - body += "VV - " - if(M.mind) - body += "TP - " - body += "SKILLS - " + body += "VV - " + if(player.mind) + body += "TP - " + body += "SKILLS - " else - body += "Init Mind - " - if (iscyborg(M)) - body += "BP - " - body += "PM - " - body += "SM - " - if (ishuman(M) && M.mind) - body += "HM - " - body += "FLW - " + body += "Init Mind - " + if (iscyborg(player)) + body += "BP - " + body += "PM - " + body += "SM - " + if (ishuman(player) && player.mind) + body += "HM - " + body += "FLW - " //Default to client logs if available var/source = LOGSRC_MOB - if(M.ckey) + if(player.ckey) source = LOGSRC_CKEY - body += "LOGS\]
    " + body += "LOGS\]
    " - body += "Mob type = [M.type]

    " + body += "Mob type = [player.type]

    " - if(M.client) + if(player.client) body += "Old names: " - var/datum/player_details/deets = GLOB.player_details[M.ckey] + var/datum/player_details/deets = GLOB.player_details[player.ckey] if(deets) body += deets.get_played_names() else body += "None?!" body += "

    " - body += "Kick | " - if(M.client) - body += "Ban | " + body += "Kick | " + if(player.client) + body += "Ban | " else - body += "Ban | " + body += "Ban | " - body += "Notes | Messages | Watchlist | " - if(M.client) - body += "| Prison | " - body += "\ Send back to Lobby | " - var/muted = M.client.prefs.muted + body += "Notes | Messages | Watchlist | " + if(player.client) + body += "| Prison | " + body += "\ Send back to Lobby | " + var/muted = player.client.prefs.muted body += "
    Mute: " - body += "\[IC | " - body += "OOC | " - body += "PRAY | " - body += "ADMINHELP | " - body += "WEBREQ | " - body += "DEADCHAT\]" - body += "(toggle all)" + body += "\[IC | " + body += "OOC | " + body += "PRAY | " + body += "ADMINHELP | " + body += "WEBREQ | " + body += "DEADCHAT\]" + body += "(toggle all)" body += "

    " - body += "Jump to | " - body += "Get | " - body += "Send To" + body += "Jump to | " + body += "Get | " + body += "Send To" body += "

    " - body += "Traitor panel | " - body += "Narrate to | " - body += "Subtle message | " - body += "Play sound to | " - body += "Language Menu" - - if(M.client) - if(!isnewplayer(M)) + body += "Traitor panel | " + body += "Narrate to | " + body += "Subtle message | " + body += "Play sound to | " + body += "Language Menu" + + if(player.client) + if(!isnewplayer(player)) body += "

    " body += "Transformation:
    " - if(isobserver(M)) + if(isobserver(player)) body += "Ghost | " else - body += "Make Ghost | " + body += "Make Ghost | " - if(ishuman(M) && !ismonkey(M)) + if(ishuman(player) && !ismonkey(player)) body += "Human | " else - body += "Make Human | " + body += "Make Human | " - if(ismonkey(M)) + if(ismonkey(player)) body += "Monkey | " else - body += "Make Monkey | " + body += "Make Monkey | " - if(iscyborg(M)) + if(iscyborg(player)) body += "Cyborg | " else - body += "Make Cyborg | " + body += "Make Cyborg | " - if(isAI(M)) + if(isAI(player)) body += "AI" else - body += "Make AI" + body += "Make AI" body += "

    " body += "Other actions:" body += "
    " - if(!isnewplayer(M)) - body += "Forcesay | " - body += "Apply Client Quirks | " - body += "Thunderdome 1 | " - body += "Thunderdome 2 | " - body += "Thunderdome Admin | " - body += "Thunderdome Observer | " - body += "Commend Behavior | " + if(!isnewplayer(player)) + body += "Forcesay | " + body += "Apply Client Quirks | " + body += "Thunderdome 1 | " + body += "Thunderdome 2 | " + body += "Thunderdome Admin | " + body += "Thunderdome Observer | " + body += "Commend Behavior | " body += "
    " body += "" - usr << browse(body, "window=adminplayeropts-[REF(M)];size=550x515") + user << browse(body, "window=adminplayeropts-[REF(player)];size=550x515") BLACKBOX_LOG_ADMIN_VERB("Player Panel") /client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list) @@ -176,14 +170,8 @@ If a guy was gibbed and you want to revive him, this is a good way to do so. Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one. Traitors and the like can also be revived with the previous role mostly intact. /N */ -/client/proc/respawn_character() - set category = "Admin.Game" - set name = "Respawn Character" - set desc = "Respawn a person that has been gibbed/dusted/killed. They must be a ghost for this to work and preferably should not have a body to go back into." - if(!check_rights(R_ADMIN)) - return - - var/input = ckey(input(src, "Please specify which key will be respawned.", "Key", "")) +ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player that has been round removed in some manner. They must be a ghost.", ADMIN_CATEGORY_GAME) + var/input = ckey(input(user, "Please specify which key will be respawned.", "Key", "")) if(!input) return @@ -194,19 +182,19 @@ Traitors and the like can also be revived with the previous role mostly intact. break if(!G_found)//If a ghost was not found. - to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.", confidential = TRUE) + to_chat(user, "There is no active key like that in the game or the person is not currently a ghost.", confidential = TRUE) return if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something //check if they were a monkey if(findtext(G_found.real_name,"monkey")) - if(tgui_alert(usr,"This character appears to have been a monkey. Would you like to respawn them as such?",,list("Yes","No")) == "Yes") + if(tgui_alert(user,"This character appears to have been a monkey. Would you like to respawn them as such?",,list("Yes","No")) == "Yes") var/mob/living/carbon/human/species/monkey/new_monkey = new SSjob.SendToLateJoin(new_monkey) G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use new_monkey.key = G_found.key to_chat(new_monkey, "You have been fully respawned. Enjoy the game.", confidential = TRUE) - var/msg = span_adminnotice("[key_name_admin(usr)] has respawned [new_monkey.key] as a filthy monkey.") + var/msg = span_adminnotice("[key_name_admin(user)] has respawned [new_monkey.key] as a filthy monkey.") message_admins(msg) admin_ticket_log(new_monkey, msg) return //all done. The ghost is auto-deleted @@ -222,7 +210,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(record_found)//If they have a record we can determine a few things. new_character.real_name = record_found.name - new_character.gender = lowertext(record_found.gender) + new_character.gender = LOWER_TEXT(record_found.gender) new_character.age = record_found.age var/datum/dna/found_dna = record_found.locked_dna new_character.hardset_dna(found_dna.unique_identity, found_dna.mutation_index, null, record_found.name, record_found.blood_type, new record_found.species_type, found_dna.features) @@ -248,7 +236,7 @@ Traitors and the like can also be revived with the previous role mostly intact. */ //Two variables to properly announce later on. - var/admin = key_name_admin(src) + var/admin = key_name_admin(user) var/player_key = G_found.key //Now for special roles and equipment. @@ -303,13 +291,8 @@ Traitors and the like can also be revived with the previous role mostly intact. BLACKBOX_LOG_ADMIN_VERB("Respawn Character") return new_character -/client/proc/cmd_admin_list_open_jobs() - set category = "Admin.Game" - set name = "Manage Job Slots" - - if(!check_rights(R_ADMIN)) - return - holder.manage_free_slots() +ADMIN_VERB(manage_job_slots, R_ADMIN, "Manage Job Slots", "Manage the number of available job slots.", ADMIN_CATEGORY_GAME) + user.holder.manage_free_slots() BLACKBOX_LOG_ADMIN_VERB("Manage Job Slots") /datum/admins/proc/manage_free_slots() @@ -352,38 +335,25 @@ Traitors and the like can also be revived with the previous role mostly intact. browser.set_content(dat.Join()) browser.open() -/client/proc/toggle_view_range() - set category = "Admin.Game" - set name = "Change View Range" - set desc = "switches between 1x and custom views" - - if(view_size.getView() == view_size.default) - view_size.setTo(input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,37) - 7) +ADMIN_VERB(toggle_view_range, R_ADMIN, "Change View Range", "Switch between 1x and custom views.", ADMIN_CATEGORY_GAME) + if(user.view_size.getView() == user.view_size.default) + user.view_size.setTo(input(user, "Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,37) - 7) else - view_size.resetToDefault(getScreenSize(prefs.read_preference(/datum/preference/toggle/widescreen))) - - log_admin("[key_name(usr)] changed their view range to [view].") - //message_admins("\blue [key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI + user.view_size.resetToDefault(getScreenSize(user.prefs.read_preference(/datum/preference/toggle/widescreen))) - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Change View Range", "[view]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! + log_admin("[key_name(user)] changed their view range to [user.view].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Change View Range", "[user.view]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/client/proc/toggle_combo_hud() - set category = "Admin.Game" - set name = "Toggle Combo HUD" - set desc = "Toggles the Admin Combo HUD (antag, sci, med, eng)" - - if(!check_rights(R_ADMIN)) - return - - if (combo_hud_enabled) - disable_combo_hud() +ADMIN_VERB(combo_hud, R_ADMIN, "Toggle Combo HUD", "Toggles the Admin Combo HUD.", ADMIN_CATEGORY_GAME) + if(user.combo_hud_enabled) + user.disable_combo_hud() else - enable_combo_hud() + user.enable_combo_hud() - to_chat(usr, "You toggled your admin combo HUD [combo_hud_enabled ? "ON" : "OFF"].", confidential = TRUE) - message_admins("[key_name_admin(usr)] toggled their admin combo HUD [combo_hud_enabled ? "ON" : "OFF"].") - log_admin("[key_name(usr)] toggled their admin combo HUD [combo_hud_enabled ? "ON" : "OFF"].") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Combo HUD", "[combo_hud_enabled ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! + to_chat(user, "You toggled your admin combo HUD [user.combo_hud_enabled ? "ON" : "OFF"].", confidential = TRUE) + message_admins("[key_name_admin(user)] toggled their admin combo HUD [user.combo_hud_enabled ? "ON" : "OFF"].") + log_admin("[key_name(user)] toggled their admin combo HUD [user.combo_hud_enabled ? "ON" : "OFF"].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Combo HUD", "[user.combo_hud_enabled ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! /client/proc/enable_combo_hud() if (combo_hud_enabled) @@ -417,47 +387,31 @@ Traitors and the like can also be revived with the previous role mostly intact. mob.lighting_cutoff = mob.default_lighting_cutoff() mob.update_sight() -/datum/admins/proc/show_traitor_panel(mob/target_mob in GLOB.mob_list) - set category = "Admin.Game" - set desc = "Edit mobs's memory and role" - set name = "Show Traitor Panel" +ADMIN_VERB(show_traitor_panel, R_ADMIN, "Show Traitor Panel", "Edit mobs's memory and role", ADMIN_CATEGORY_GAME, mob/target_mob) var/datum/mind/target_mind = target_mob.mind if(!target_mind) - to_chat(usr, "This mob has no mind!", confidential = TRUE) + to_chat(user, "This mob has no mind!", confidential = TRUE) return if(!istype(target_mob) && !istype(target_mind)) - to_chat(usr, "This can only be used on instances of type /mob and /mind", confidential = TRUE) + to_chat(user, "This can only be used on instances of type /mob and /mind", confidential = TRUE) return target_mind.traitor_panel() BLACKBOX_LOG_ADMIN_VERB("Traitor Panel") -/datum/admins/proc/show_skill_panel(target) - set category = "Admin.Game" - set desc = "Edit mobs's experience and skill levels" - set name = "Show Skill Panel" +ADMIN_VERB(show_skill_panel, R_ADMIN, "Show Skill Panel", "Edit mobs's experience and skill levels", ADMIN_CATEGORY_GAME, mob/target_mob) var/datum/mind/target_mind - if(ismob(target)) - var/mob/target_mob = target - target_mind = target_mob.mind - else if (istype(target, /datum/mind)) - target_mind = target + if(istype(target_mob, /datum/mind)) + target_mind = target_mob else - to_chat(usr, "This can only be used on instances of type /mob and /mind", confidential = TRUE) - return - var/datum/skill_panel/SP = new(usr, target_mind) - SP.ui_interact(usr) + target_mind = target_mob.mind -/datum/admins/proc/show_lag_switch_panel() - set category = "Admin.Game" - set name = "Show Lag Switches" - set desc="Display the controls for drastic lag mitigation measures." + var/datum/skill_panel/SP = new(user, target_mind) + SP.ui_interact(user.mob) +ADMIN_VERB(lag_switch_panel, R_ADMIN, "Show Lag Switches", "Display the controls for drastic lag mitigation.", ADMIN_CATEGORY_GAME) if(!SSlag_switch.initialized) - to_chat(usr, span_notice("The Lag Switch subsystem has not yet been initialized.")) + to_chat(user, span_notice("The Lag Switch subsystem has not yet been initialized.")) return - if(!check_rights()) - return - var/list/dat = list("Lag Switches

    Lag (Reduction) Switches

    ") dat += "Automatic Trigger: [SSlag_switch.auto_switch ? "On" : "Off"]
    " dat += "Population Threshold: [SSlag_switch.trigger_pop]
    " @@ -475,4 +429,4 @@ Traitors and the like can also be revived with the previous role mostly intact. dat += "Disable parallax: [SSlag_switch.measures[DISABLE_PARALLAX] ? "On" : "Off"] - trait applies to character
    " dat += "Disable footsteps: [SSlag_switch.measures[DISABLE_FOOTSTEPS] ? "On" : "Off"] - trait applies to character
    " dat += "" - usr << browse(dat.Join(), "window=lag_switch_panel;size=420x480") + user << browse(dat.Join(), "window=lag_switch_panel;size=420x480") diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 6c6dc4335c7ac..a389980f533fd 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -500,7 +500,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) state = AHELP_RESOLVED GLOB.ahelp_tickets.ListInsert(src) - addtimer(CALLBACK(initiator, TYPE_PROC_REF(/client, giveadminhelpverb)), 50) + addtimer(CALLBACK(initiator, TYPE_PROC_REF(/client, giveadminhelpverb)), 5 SECONDS) AddInteraction("Resolved by [key_name].", player_message = "Ticket resolved!") to_chat(initiator, span_adminhelp("Your ticket has been resolved by an admin. The Adminhelp verb will be returned to you shortly."), confidential = TRUE) @@ -1047,10 +1047,10 @@ GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new) if(!M.mind) continue - for(var/string in splittext(lowertext(M.real_name), " ")) + for(var/string in splittext(LOWER_TEXT(M.real_name), " ")) if(!(string in ignored_words)) nameWords += string - for(var/string in splittext(lowertext(M.name), " ")) + for(var/string in splittext(LOWER_TEXT(M.name), " ")) if(!(string in ignored_words)) nameWords += string diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index dfcc5f60dd0c4..0248ccd99754e 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -1,114 +1,66 @@ -/client/proc/jumptoarea(area/A in get_sorted_areas()) - set name = "Jump to Area" - set desc = "Area to jump to" - set category = "Admin.Game" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - - if(!A) - return - - var/list/turfs = list() - for (var/list/zlevel_turfs as anything in A.get_zlevel_turf_lists()) - for (var/turf/area_turf as anything in zlevel_turfs) - if(!area_turf.density) - turfs.Add(area_turf) - - if(length(turfs)) - var/turf/T = pick(turfs) - usr.forceMove(T) - log_admin("[key_name(usr)] jumped to [AREACOORD(T)]") - message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]") - BLACKBOX_LOG_ADMIN_VERB("Jump To Area") - else - to_chat(src, "Nowhere to jump to!", confidential = TRUE) - return - - -/client/proc/jumptoturf(turf/T in world) - set name = "Jump to Turf" - set category = "Admin.Game" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - - log_admin("[key_name(usr)] jumped to [AREACOORD(T)]") - message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]") - usr.forceMove(T) +ADMIN_VERB(jump_to_area, R_ADMIN, "Jump To Area", "Jumps to the specified area.", ADMIN_CATEGORY_GAME, area/target in get_sorted_areas()) + var/turf/drop_location + top_level: + for(var/list/zlevel_turfs as anything in target.get_zlevel_turf_lists()) + for(var/turf/area_turf as anything in zlevel_turfs) + if(area_turf.density) + continue + drop_location = area_turf + break top_level + + if(isnull(drop_location)) + to_chat(user, span_warning("No valid drop location found in the area!")) + return + + user.mob.abstract_move(drop_location) + log_admin("[key_name(user)] jumped to [AREACOORD(drop_location)]") + message_admins("[key_name_admin(user)] jumped to [AREACOORD(drop_location)]") + BLACKBOX_LOG_ADMIN_VERB("Jump To Area") + +ADMIN_VERB_AND_CONTEXT_MENU(jump_to_turf, R_ADMIN, "Jump To Turf", "Jump to any turf in the game. This will lag your client.", ADMIN_CATEGORY_GAME, turf/locale in world) + log_admin("[key_name(user)] jumped to [AREACOORD(locale)]") + message_admins("[key_name_admin(user)] jumped to [AREACOORD(locale)]") + user.mob.abstract_move(locale) BLACKBOX_LOG_ADMIN_VERB("Jump To Turf") - return -/client/proc/jumptomob(mob/M in GLOB.mob_list) - set category = "Admin.Game" - set name = "Jump to Mob" +ADMIN_VERB_AND_CONTEXT_MENU(jump_to_mob, R_ADMIN, "Jump To Mob", "Jump to any mob in the game.", ADMIN_CATEGORY_GAME, mob/target in world) + user.mob.abstract_move(target.loc) + log_admin("[key_name(user)] jumped to [key_name(target)]") + message_admins("[key_name_admin(user)] jumped to [ADMIN_LOOKUPFLW(target)] at [AREACOORD(target)]") + BLACKBOX_LOG_ADMIN_VERB("Jump To Mob") - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) +ADMIN_VERB(jump_to_coord, R_ADMIN, "Jump To Coordinate", "Jump to a specific coordinate in the game world.", ADMIN_CATEGORY_GAME, cx as num, cy as num, cz as num) + var/turf/where_we_droppin = locate(cx, cy, cz) + if(isnull(where_we_droppin)) + to_chat(user, span_warning("Invalid coordinates.")) return - log_admin("[key_name(usr)] jumped to [key_name(M)]") - message_admins("[key_name_admin(usr)] jumped to [ADMIN_LOOKUPFLW(M)] at [AREACOORD(M)]") - if(src.mob) - var/mob/A = src.mob - var/turf/T = get_turf(M) - if(T && isturf(T)) - BLACKBOX_LOG_ADMIN_VERB("Jump To Mob") - A.forceMove(M.loc) - else - to_chat(A, "This mob is not located in the game world.", confidential = TRUE) - -/client/proc/jumptocoord(tx as num, ty as num, tz as num) - set category = "Admin.Game" - set name = "Jump to Coordinate" - - if (!holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return + user.mob.abstract_move(where_we_droppin) + message_admins("[key_name_admin(user)] jumped to coordinates [cx], [cy], [cz]") + BLACKBOX_LOG_ADMIN_VERB("Jump To Coordiate") - if(src.mob) - var/mob/A = src.mob - var/turf/T = locate(tx,ty,tz) - A.forceMove(T) - BLACKBOX_LOG_ADMIN_VERB("Jump To Coordiate") - message_admins("[key_name_admin(usr)] jumped to coordinates [tx], [ty], [tz]") - -/client/proc/jumptokey() - set category = "Admin.Game" - set name = "Jump to Key" - - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB(jump_to_key, R_ADMIN, "Jump To Key", "Jump to a specific player.", ADMIN_CATEGORY_GAME) + if(!isobserver(user.mob)) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) var/list/keys = list() for(var/mob/M in GLOB.player_list) keys += M.client - var/client/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sort_key(keys) + var/client/selection = input(user, "Please, select a player!", "Admin Jumping") as null|anything in sort_key(keys) if(!selection) - to_chat(src, "No keys found.", confidential = TRUE) + to_chat(user, "No keys found.", confidential = TRUE) return var/mob/M = selection.mob - log_admin("[key_name(usr)] jumped to [key_name(M)]") - message_admins("[key_name_admin(usr)] jumped to [ADMIN_LOOKUPFLW(M)]") - - usr.forceMove(M.loc) - + log_admin("[key_name(user)] jumped to [key_name(M)]") + message_admins("[key_name_admin(user)] jumped to [ADMIN_LOOKUPFLW(M)]") + user.mob.abstract_move(M.loc) BLACKBOX_LOG_ADMIN_VERB("Jump To Key") -/client/proc/Getmob(mob/M in GLOB.mob_list - GLOB.dummy_mob_list) - set category = "Admin.Game" - set name = "Get Mob" - set desc = "Mob to teleport" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - - var/atom/loc = get_turf(usr) - M.admin_teleport(loc) +ADMIN_VERB_AND_CONTEXT_MENU(get_mob, R_ADMIN, "Get Mob", "Teleport a mob to your location.", ADMIN_CATEGORY_GAME, mob/target in world) + var/atom/loc = get_turf(user.mob) + target.admin_teleport(loc) BLACKBOX_LOG_ADMIN_VERB("Get Mob") - /// Proc to hook user-enacted teleporting behavior and keep logging of the event. /atom/movable/proc/admin_teleport(atom/new_location) if(isnull(new_location)) @@ -126,56 +78,41 @@ admin_ticket_log(src, msg) return ..() - -/client/proc/Getkey() - set category = "Admin.Game" - set name = "Get Key" - set desc = "Key to teleport" - - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - +ADMIN_VERB(get_key, R_ADMIN, "Get Key", "Teleport the player with the provided key to you.", ADMIN_CATEGORY_GAME) var/list/keys = list() for(var/mob/M in GLOB.player_list) keys += M.client - var/client/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sort_key(keys) + var/client/selection = input(user, "Please, select a player!", "Admin Jumping") as null|anything in sort_key(keys) if(!selection) return var/mob/M = selection.mob if(!M) return - log_admin("[key_name(usr)] teleported [key_name(M)]") - var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)]" + log_admin("[key_name(user)] teleported [key_name(M)]") + var/msg = "[key_name_admin(user)] teleported [ADMIN_LOOKUPFLW(M)]" message_admins(msg) admin_ticket_log(M, msg) if(M) - M.forceMove(get_turf(usr)) - usr.forceMove(M.loc) + M.forceMove(get_turf(user)) BLACKBOX_LOG_ADMIN_VERB("Get Key") -/client/proc/sendmob(mob/jumper in sort_mobs()) - set category = "Admin.Game" - set name = "Send Mob" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB_AND_CONTEXT_MENU(send_mob, R_ADMIN, "Send Mob", "Teleport the specified mob to an area of your choosing.", ADMIN_CATEGORY_GAME, mob/jumper) var/list/sorted_areas = get_sorted_areas() if(!length(sorted_areas)) - to_chat(src, "No areas found.", confidential = TRUE) + to_chat(user, "No areas found.", confidential = TRUE) return - var/area/target_area = tgui_input_list(src, "Pick an area", "Send Mob", sorted_areas) + var/area/target_area = tgui_input_list(user, "Pick an area", "Send Mob", sorted_areas) if(isnull(target_area)) return if(!istype(target_area)) return var/list/turfs = get_area_turfs(target_area) if(length(turfs) && jumper.forceMove(pick(turfs))) - log_admin("[key_name(usr)] teleported [key_name(jumper)] to [AREACOORD(jumper)]") - var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(jumper)] to [AREACOORD(jumper)]" + log_admin("[key_name(user)] teleported [key_name(jumper)] to [AREACOORD(jumper)]") + var/msg = "[key_name_admin(user)] teleported [ADMIN_LOOKUPFLW(jumper)] to [AREACOORD(jumper)]" message_admins(msg) admin_ticket_log(jumper, msg) else - to_chat(src, "Failed to move mob to a valid location.", confidential = TRUE) + to_chat(user, "Failed to move mob to a valid location.", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Send Mob") diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index dd8bbb5cda4fd..0e8053c7ab06e 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -13,36 +13,19 @@ // We also make SURE to fail loud, IE: if something stops the message from reaching the recipient, the sender HAS to know // If you "refactor" this to make it "cleaner" I will send you to hell -/// Allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm -/client/proc/cmd_admin_pm_context(mob/M in GLOB.mob_list) - set category = null - set name = "Admin PM Mob" - if(!holder) - to_chat(src, - type = MESSAGE_TYPE_ADMINPM, - html = span_danger("Error: Admin-PM-Context: Only administrators may use this command."), - confidential = TRUE) - return - if(!ismob(M)) - to_chat(src, +ADMIN_VERB_ONLY_CONTEXT_MENU(cmd_admin_pm_context, R_NONE, "Admin PM Mob", mob/target in world) + if(!ismob(target)) + to_chat( + src, type = MESSAGE_TYPE_ADMINPM, html = span_danger("Error: Admin-PM-Context: Target mob is not a mob, somehow."), - confidential = TRUE) + confidential = TRUE, + ) return - cmd_admin_pm(M.client, null) + user.cmd_admin_pm(target.client, null) BLACKBOX_LOG_ADMIN_VERB("Admin PM Mob") -/// Shows a list of clients we could send PMs to, then forwards our choice to cmd_admin_pm -/client/proc/cmd_admin_pm_panel() - set category = "Admin" - set name = "Admin PM" - if(!holder) - to_chat(src, - type = MESSAGE_TYPE_ADMINPM, - html = span_danger("Error: Admin-PM-Panel: Only administrators may use this command."), - confidential = TRUE) - return - +ADMIN_VERB(cmd_admin_pm_panel, R_NONE, "Admin PM", "Show a list of clients to PM", ADMIN_CATEGORY_MAIN) var/list/targets = list() for(var/client/client in GLOB.clients) var/nametag = "" @@ -62,7 +45,7 @@ var/target = input(src,"To whom shall we send a message?", "Admin PM", null) as null|anything in sort_list(targets) if (isnull(target)) return - cmd_admin_pm(targets[target], null) + user.cmd_admin_pm(targets[target], null) BLACKBOX_LOG_ADMIN_VERB("Admin PM") /// Replys to some existing ahelp, reply to whom, which can be a client or ckey @@ -629,7 +612,7 @@ // The ticket's id var/ticket_id = ticket?.id - var/compliant_msg = trim(lowertext(message)) + var/compliant_msg = trim(LOWER_TEXT(message)) var/tgs_tagged = "[sender](TGS/External)" var/list/splits = splittext(compliant_msg, " ") var/split_size = length(splits) diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 0ea8a7ceb76fe..595993466d2b6 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -1,18 +1,12 @@ -/client/proc/cmd_admin_say(msg as text) - set category = "Admin" - set name = "Asay" //Gave this shit a shorter name so you only have to time out "asay" rather than "admin say" to use it --NeoFite - set hidden = TRUE - if(!check_rights(0)) +ADMIN_VERB(cmd_admin_say, R_NONE, "ASay", "Send a message to other admins", ADMIN_CATEGORY_MAIN, message as text) + message = emoji_parse(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)) + if(!message) return - msg = emoji_parse(copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)) - if(!msg) - return - - if(findtext(msg, "@") || findtext(msg, "#")) - var/list/link_results = check_asay_links(msg) + if(findtext(message, "@") || findtext(message, "#")) + var/list/link_results = check_asay_links(message) if(length(link_results)) - msg = link_results[ASAY_LINK_NEW_MESSAGE_INDEX] + message = link_results[ASAY_LINK_NEW_MESSAGE_INDEX] link_results[ASAY_LINK_NEW_MESSAGE_INDEX] = null var/list/pinged_admin_clients = link_results[ASAY_LINK_PINGED_ADMINS_INDEX] for(var/iter_ckey in pinged_admin_clients) @@ -22,18 +16,18 @@ window_flash(iter_admin_client) SEND_SOUND(iter_admin_client.mob, sound('sound/misc/asay_ping.ogg')) - mob.log_talk(msg, LOG_ASAY) - msg = keywords_lookup(msg) - var/asay_color = prefs.read_preference(/datum/preference/color/asay_color) + user.mob.log_talk(message, LOG_ASAY) + message = keywords_lookup(message) + var/asay_color = user.prefs.read_preference(/datum/preference/color/asay_color) var/custom_asay_color = (CONFIG_GET(flag/allow_admin_asaycolor) && asay_color) ? "" : "" - msg = "[span_adminsay("[span_prefix("ADMIN:")] [key_name(usr, 1)] [ADMIN_FLW(mob)]: [custom_asay_color][msg]")][custom_asay_color ? "":null]" + message = "[span_adminsay("[span_prefix("ADMIN:")] [key_name_admin(user)] [ADMIN_FLW(user.mob)]: [custom_asay_color][message]")][custom_asay_color ? "":null]" to_chat(GLOB.admins, type = MESSAGE_TYPE_ADMINCHAT, - html = msg, + html = message, confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Asay") /client/proc/get_admin_say() var/msg = input(src, null, "asay \"text\"") as text|null - cmd_admin_say(msg) + SSadmin_verbs.dynamic_invoke_verb(src, /datum/admin_verb/cmd_admin_say, msg) diff --git a/code/modules/admin/verbs/anonymousnames.dm b/code/modules/admin/verbs/anonymousnames.dm index 9a71d68637a88..10edb49d99336 100644 --- a/code/modules/admin/verbs/anonymousnames.dm +++ b/code/modules/admin/verbs/anonymousnames.dm @@ -131,8 +131,7 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme) /datum/anonymous_theme/proc/anonymous_name(mob/target) var/datum/client_interface/client = GET_CLIENT(target) var/species_type = client.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type - return species.random_name(target.gender,1) + return generate_random_name_species_based(target.gender, TRUE, species_type) /** * anonymous_ai_name: generates a random name, based off of whatever the round's anonymousnames is set to (but for sillycones). diff --git a/code/modules/admin/verbs/atmosdebug.dm b/code/modules/admin/verbs/atmosdebug.dm index 2e73a9955f747..9f744ff014749 100644 --- a/code/modules/admin/verbs/atmosdebug.dm +++ b/code/modules/admin/verbs/atmosdebug.dm @@ -1,35 +1,27 @@ -/client/proc/atmosscan() - set category = "Mapping" - set name = "Check Plumbing" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB_VISIBILITY(atmos_debug, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(atmos_debug, R_DEBUG, "Check Plumbing", "Verifies the integrity of the plumbing network.", ADMIN_CATEGORY_MAPPING) BLACKBOX_LOG_ADMIN_VERB("Check Plumbing") //all plumbing - yes, some things might get stated twice, doesn't matter. for(var/obj/machinery/atmospherics/components/pipe as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/atmospherics/components)) if(pipe.z && (!pipe.nodes || !pipe.nodes.len || (null in pipe.nodes))) - to_chat(usr, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential = TRUE) + to_chat(user, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential = TRUE) //Pipes for(var/obj/machinery/atmospherics/pipe/pipe as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/atmospherics/pipe)) if(istype(pipe, /obj/machinery/atmospherics/pipe/smart) || istype(pipe, /obj/machinery/atmospherics/pipe/layer_manifold)) continue if(pipe.z && (!pipe.nodes || !pipe.nodes.len || (null in pipe.nodes))) - to_chat(usr, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential = TRUE) + to_chat(user, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential = TRUE) //Nodes for(var/obj/machinery/atmospherics/node1 as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/atmospherics)) for(var/obj/machinery/atmospherics/node2 in node1.nodes) if(!(node1 in node2.nodes)) - to_chat(usr, "One-way connection in [node1.name] located at [ADMIN_VERBOSEJMP(node1)]", confidential = TRUE) + to_chat(user, "One-way connection in [node1.name] located at [ADMIN_VERBOSEJMP(node1)]", confidential = TRUE) -/client/proc/powerdebug() - set category = "Mapping" - set name = "Check Power" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB_VISIBILITY(power_debug, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(power_debug, R_DEBUG, "Check Power", "Verifies the integrity of the power network.", ADMIN_CATEGORY_MAPPING) BLACKBOX_LOG_ADMIN_VERB("Check Power") var/list/results = list() @@ -56,4 +48,4 @@ var/obj/structure/cable/C = locate(/obj/structure/cable) in T.contents if(!C) results += "Unwired terminal at [ADMIN_VERBOSEJMP(term)]" - to_chat(usr, "[results.Join("\n")]", confidential = TRUE) + to_chat(user, "[results.Join("\n")]", confidential = TRUE) diff --git a/code/modules/admin/verbs/beakerpanel.dm b/code/modules/admin/verbs/beakerpanel.dm index 5ba32ae7b6ce0..7088fba92f128 100644 --- a/code/modules/admin/verbs/beakerpanel.dm +++ b/code/modules/admin/verbs/beakerpanel.dm @@ -60,14 +60,11 @@ reagents.add_reagent(reagenttype, amount) return container -/datum/admins/proc/beaker_panel() - set category = "Admin.Events" - set name = "Spawn reagent container" - if(!check_rights()) - return +ADMIN_VERB(beaker_panel, R_SPAWN, "Spawn Reagent Container", "Spawn a reagent container.", ADMIN_CATEGORY_EVENTS) var/datum/asset/asset_datum = get_asset_datum(/datum/asset/simple/namespaced/common) - asset_datum.send(usr) + asset_datum.send(user) //Could somebody tell me why this isn't using the browser datum, given that it copypastes all of browser datum's html + // fuck if I know, but im not touching it var/dat = {" @@ -320,4 +317,4 @@ "} - usr << browse(dat, "window=beakerpanel;size=1100x720") + user << browse(dat, "window=beakerpanel;size=1100x720") diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm index b8fd3698a563e..6a8e1efdb5656 100644 --- a/code/modules/admin/verbs/borgpanel.dm +++ b/code/modules/admin/verbs/borgpanel.dm @@ -1,21 +1,6 @@ -/datum/admins/proc/open_borgopanel(borgo in GLOB.silicon_mobs) - set category = "Admin.Game" - set name = "Show Borg Panel" - set desc = "Show borg panel" - - if(!check_rights(R_ADMIN)) - return - - if (!iscyborg(borgo)) - borgo = input("Select a borg", "Select a borg", null, null) as null|anything in sort_names(GLOB.silicon_mobs) - if (!iscyborg(borgo)) - to_chat(usr, span_warning("Borg is required for borgpanel"), confidential = TRUE) - - var/datum/borgpanel/borgpanel = new(usr, borgo) - - borgpanel.ui_interact(usr) - - +ADMIN_VERB(borg_panel, R_ADMIN, "Show Borg Panel", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/living/silicon/robot/borgo) + var/datum/borgpanel/borgpanel = new(user.mob, borgo) + borgpanel.ui_interact(user.mob) /datum/borgpanel var/mob/living/silicon/robot/borg diff --git a/code/modules/admin/verbs/change_shuttle_events.dm b/code/modules/admin/verbs/change_shuttle_events.dm index 4ec8a7cd7b83a..90f7e03672e73 100644 --- a/code/modules/admin/verbs/change_shuttle_events.dm +++ b/code/modules/admin/verbs/change_shuttle_events.dm @@ -1,20 +1,9 @@ -///Manipulate the events that are gonna run/are running on the escape shuttle -/datum/admins/proc/change_shuttle_events() - set category = "Admin.Events" - set name = "Change Shuttle Events" - set desc = "Allows you to change the events on a shuttle." - - if (!istype(src, /datum/admins)) - src = usr.client.holder - if (!istype(src, /datum/admins)) - to_chat(usr, "Error: you are not an admin!", confidential = TRUE) - return - +ADMIN_VERB(change_shuttle_events, R_ADMIN|R_FUN, "Change Shuttle Events", "Change the events on a shuttle.", ADMIN_CATEGORY_EVENTS) //At least for now, just letting admins modify the emergency shuttle is fine var/obj/docking_port/mobile/port = SSshuttle.emergency if(!port) - to_chat(usr, span_admin("Uh oh, couldn't find the escape shuttle!")) + to_chat(user, span_admin("Uh oh, couldn't find the escape shuttle!")) var/list/options = list("Clear"="Clear") @@ -27,16 +16,16 @@ options[((event in active) ? "(Remove)" : "(Add)") + initial(event.name)] = event //Throw up an ugly menu with the shuttle events and the options to add or remove them, or clear them all - var/result = input(usr, "Choose an event to add/remove", "Shuttle Events") as null|anything in sort_list(options) + var/result = input(user, "Choose an event to add/remove", "Shuttle Events") as null|anything in sort_list(options) if(result == "Clear") port.event_list.Cut() - message_admins("[key_name_admin(usr)] has cleared the shuttle events on: [port]") + message_admins("[key_name_admin(user)] has cleared the shuttle events on: [port]") else if(options[result]) var/typepath = options[result] if(typepath in active) port.event_list.Remove(active[options[result]]) - message_admins("[key_name_admin(usr)] has removed '[active[result]]' from [port].") + message_admins("[key_name_admin(user)] has removed '[active[result]]' from [port].") else port.event_list.Add(new typepath (port)) - message_admins("[key_name_admin(usr)] has added '[typepath]' to [port].") + message_admins("[key_name_admin(user)] has added '[typepath]' to [port].") diff --git a/code/modules/admin/verbs/cinematic.dm b/code/modules/admin/verbs/cinematic.dm index b001099d28340..f9e96c89cd076 100644 --- a/code/modules/admin/verbs/cinematic.dm +++ b/code/modules/admin/verbs/cinematic.dm @@ -1,14 +1,10 @@ -/client/proc/cinematic() - set name = "Cinematic" - set category = "Admin.Fun" - set desc = "Shows a cinematic." // Intended for testing but I thought it might be nice for events on the rare occasion Feel free to comment it out if it's not wanted. - set hidden = TRUE - - if(!SSticker) - return - - var/datum/cinematic/choice = tgui_input_list(usr, "Chose a cinematic to play to everyone in the server.", "Choose Cinematic", sort_list(subtypesof(/datum/cinematic), GLOBAL_PROC_REF(cmp_typepaths_asc))) +ADMIN_VERB(cinematic, R_FUN, "Cinematic", "Show a cinematic to all players.", ADMIN_CATEGORY_FUN) + var/datum/cinematic/choice = tgui_input_list( + user, + "Chose a cinematic to play to everyone in the server.", + "Choose Cinematic", + sort_list(subtypesof(/datum/cinematic), GLOBAL_PROC_REF(cmp_typepaths_asc)), + ) if(!choice || !ispath(choice, /datum/cinematic)) return - play_cinematic(choice, world) diff --git a/code/modules/admin/verbs/commandreport.dm b/code/modules/admin/verbs/commandreport.dm index 86e7ec1328b47..047ef04a0b7ce 100644 --- a/code/modules/admin/verbs/commandreport.dm +++ b/code/modules/admin/verbs/commandreport.dm @@ -7,32 +7,19 @@ #define WIZARD_PRESET "The Wizard Federation" #define CUSTOM_PRESET "Custom Command Name" -/// Verb to change the global command name. -/client/proc/cmd_change_command_name() - set category = "Admin.Events" - set name = "Change Command Name" - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please input a new name for Central Command.", "What?", "") as text|null +ADMIN_VERB(change_command_name, R_ADMIN, "Change Command Name", "Change the name of Central Command.", ADMIN_CATEGORY_EVENTS) + var/input = input(user, "Please input a new name for Central Command.", "What?", "") as text|null if(!input) return change_command_name(input) - message_admins("[key_name_admin(src)] has changed Central Command's name to [input]") - log_admin("[key_name(src)] has changed the Central Command name to: [input]") + message_admins("[key_name_admin(user)] has changed Central Command's name to [input]") + log_admin("[key_name(user)] has changed the Central Command name to: [input]") /// Verb to open the create command report window and send command reports. -/client/proc/cmd_admin_create_centcom_report() - set category = "Admin.Events" - set name = "Create Command Report" - - if(!check_rights(R_ADMIN)) - return - +ADMIN_VERB(create_command_report, R_ADMIN, "Create Command Report", "Create a command report to be sent to the station.", ADMIN_CATEGORY_EVENTS) BLACKBOX_LOG_ADMIN_VERB("Create Command Report") - var/datum/command_report_menu/tgui = new(usr) - tgui.ui_interact(usr) + var/datum/command_report_menu/tgui = new /datum/command_report_menu(user.mob) + tgui.ui_interact(user.mob) /// Datum for holding the TGUI window for command reports. /datum/command_report_menu diff --git a/code/modules/admin/verbs/config_helpers.dm b/code/modules/admin/verbs/config_helpers.dm index 013c7b63f8a48..c043274d4277f 100644 --- a/code/modules/admin/verbs/config_helpers.dm +++ b/code/modules/admin/verbs/config_helpers.dm @@ -1,19 +1,14 @@ -/// Verbs created to help server operators with generating certain config files. +#define GENERATE_JOB_CONFIG_VERB_DESC "Generate a job configuration (jobconfig.toml) file for the server. If TOML file already exists, will re-generate it based off the already existing config values. Will migrate from the old jobs.txt format if necessary." -/client/proc/generate_job_config() - set name = "Generate Job Configuration" - set category = "Server" - set desc = "Generate a job configuration (jobconfig.toml) file for the server. If TOML file already exists, will re-generate it based off the already existing config values. Will migrate from the old jobs.txt format if necessary." - - if(!check_rights(R_SERVER)) - return - - if(tgui_alert(usr, "This verb is not at all useful if you are not a server operator with access to the configuration folder. Do you wish to proceed?", "Generate jobconfig.toml for download", list("Yes", "No")) != "Yes") +ADMIN_VERB(generate_job_config, R_SERVER, "Generate Job Configuration", GENERATE_JOB_CONFIG_VERB_DESC, ADMIN_CATEGORY_SERVER) + if(tgui_alert(user, "This verb is not at all useful if you are not a server operator with access to the configuration folder. Do you wish to proceed?", "Generate jobconfig.toml for download", list("Yes", "No")) != "Yes") return - if(SSjob.generate_config(usr)) - to_chat(usr, span_notice("Job configuration file generated. Download prompt should appear now.")) + if(SSjob.generate_config(user)) + to_chat(user, span_notice("Job configuration file generated. Download prompt should appear now.")) else - to_chat(usr, span_warning("Job configuration file could not be generated. Check the server logs / runtimes / above warning messages for more information.")) + to_chat(user, span_warning("Job configuration file could not be generated. Check the server logs / runtimes / above warning messages for more information.")) BLACKBOX_LOG_ADMIN_VERB("Generate Job Configuration") + +#undef GENERATE_JOB_CONFIG_VERB_DESC diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index 032a4d4fa482b..c330618d8b4cd 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -1,39 +1,30 @@ -/client/proc/dsay(msg as text) - set category = "Admin.Game" - set name = "Dsay" - set hidden = TRUE - if(!holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - if(!mob) - return - if(prefs.muted & MUTE_DEADCHAT) - to_chat(src, span_danger("You cannot send DSAY messages (muted)."), confidential = TRUE) + +ADMIN_VERB(dsay, R_NONE, "DSay", "Speak to the dead.", ADMIN_CATEGORY_GAME, message as text) + if(user.prefs.muted & MUTE_DEADCHAT) + to_chat(user, span_danger("You cannot send DSAY messages (muted)."), confidential = TRUE) return - if (handle_spam_prevention(msg,MUTE_DEADCHAT)) + if (user.handle_spam_prevention(message,MUTE_DEADCHAT)) return - msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN) - mob.log_talk(msg, LOG_DSAY) + message = copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN) + user.mob.log_talk(message, LOG_DSAY) - if (!msg) + if (!message) return - var/rank_name = holder.rank_names() - var/admin_name = key - if(holder.fakekey) + var/rank_name = user.holder.rank_names() + var/admin_name = user.key + if(user.holder.fakekey) rank_name = pick(strings("admin_nicknames.json", "ranks", "config")) admin_name = pick(strings("admin_nicknames.json", "names", "config")) var/name_and_rank = "[span_tooltip(rank_name, "STAFF")] ([admin_name])" - deadchat_broadcast("[span_prefix("DEAD:")] [name_and_rank] says, \"[emoji_parse(msg)]\"") + deadchat_broadcast("[span_prefix("DEAD:")] [name_and_rank] says, \"[emoji_parse(message)]\"") BLACKBOX_LOG_ADMIN_VERB("Dsay") /client/proc/get_dead_say() var/msg = input(src, null, "dsay \"text\"") as text|null - if (isnull(msg)) return - - dsay(msg) + SSadmin_verbs.dynamic_invoke_verb(src, /datum/admin_verb/dsay, msg) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 35b1baa063d57..20cdf3514598f 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1,40 +1,27 @@ -/client/proc/Debug2() - set category = "Debug" - set name = "Debug-Game" - if(!check_rights(R_DEBUG)) - return - - if(GLOB.Debug2) - GLOB.Debug2 = 0 - message_admins("[key_name(src)] toggled debugging off.") - log_admin("[key_name(src)] toggled debugging off.") - else - GLOB.Debug2 = 1 - message_admins("[key_name(src)] toggled debugging on.") - log_admin("[key_name(src)] toggled debugging on.") - +ADMIN_VERB(toggle_game_debug, R_DEBUG, "Debug-Game", "Toggles game debugging.", ADMIN_CATEGORY_DEBUG) + GLOB.Debug2 = !GLOB.Debug2 + var/message = "toggled debugging [(GLOB.Debug2 ? "ON" : "OFF")]" + message_admins("[key_name_admin(user)] [message].") + log_admin("[key_name(user)] [message].") BLACKBOX_LOG_ADMIN_VERB("Toggle Debug Two") -/client/proc/Cell() - set category = "Debug" - set name = "Air Status in Location" - if(!mob) - return - var/turf/T = get_turf(mob) - if(!isturf(T)) +ADMIN_VERB_VISIBILITY(air_status, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(air_status, R_DEBUG, "Air Status In Location", "Gets the air status for your current turf.", ADMIN_CATEGORY_DEBUG) + var/turf/user_turf = get_turf(user.mob) + if(!isturf(user_turf)) return - atmos_scan(user=usr, target=T, silent=TRUE) + atmos_scan(user.mob, user_turf, silent = TRUE) BLACKBOX_LOG_ADMIN_VERB("Air Status In Location") -/client/proc/cmd_admin_robotize(mob/M in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Make Cyborg" - +ADMIN_VERB(cmd_admin_robotize, R_FUN, "Make Cyborg", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/target) if(!SSticker.HasRoundStarted()) - tgui_alert(usr,"Wait until the game starts") + tgui_alert(user, "Wait until the game starts") + return + if(issilicon(target)) + tgui_alert(user, "They are already a cyborg.") return - log_admin("[key_name(src)] has robotized [M.key].") - INVOKE_ASYNC(M, TYPE_PROC_REF(/mob, Robotize)) + log_admin("[key_name(user)] has robotized [target.key].") + INVOKE_ASYNC(target, TYPE_PROC_REF(/mob, Robotize)) /client/proc/poll_type_to_del(search_string) var/list/types = get_fancy_list_of_atom_types() @@ -50,13 +37,8 @@ return return types[key] -//TODO: merge the vievars version into this or something maybe mayhaps -/client/proc/cmd_debug_del_all(object as text) - set category = "Debug" - set name = "Del-All" - - var/type_to_del = poll_type_to_del(object) - +ADMIN_VERB(cmd_del_all, R_DEBUG|R_SPAWN, "Del-All", "Delete all datums with the specified type.", ADMIN_CATEGORY_DEBUG, object as text) + var/type_to_del = user.poll_type_to_del(object) if(!type_to_del) return @@ -66,16 +48,12 @@ counter++ qdel(O) CHECK_TICK - log_admin("[key_name(src)] has deleted all ([counter]) instances of [type_to_del].") - message_admins("[key_name_admin(src)] has deleted all ([counter]) instances of [type_to_del].") + log_admin("[key_name(user)] has deleted all ([counter]) instances of [type_to_del].") + message_admins("[key_name_admin(user)] has deleted all ([counter]) instances of [type_to_del].") BLACKBOX_LOG_ADMIN_VERB("Delete All") -/client/proc/cmd_debug_force_del_all(object as text) - set category = "Debug" - set name = "Force-Del-All" - - var/type_to_del = poll_type_to_del(object) - +ADMIN_VERB(cmd_del_all_force, R_DEBUG|R_SPAWN, "Force-Del-All", "Forcibly delete all datums with the specified type.", ADMIN_CATEGORY_DEBUG, object as text) + var/type_to_del = user.poll_type_to_del(object) if(!type_to_del) return @@ -85,29 +63,25 @@ counter++ qdel(O, force = TRUE) CHECK_TICK - log_admin("[key_name(src)] has force-deleted all ([counter]) instances of [type_to_del].") - message_admins("[key_name_admin(src)] has force-deleted all ([counter]) instances of [type_to_del].") + log_admin("[key_name(user)] has force-deleted all ([counter]) instances of [type_to_del].") + message_admins("[key_name_admin(user)] has force-deleted all ([counter]) instances of [type_to_del].") BLACKBOX_LOG_ADMIN_VERB("Force-Delete All") -/client/proc/cmd_debug_hard_del_all(object as text) - set category = "Debug" - set name = "Hard-Del-All" - - var/type_to_del = poll_type_to_del(object) - +ADMIN_VERB(cmd_del_all_hard, R_DEBUG|R_SPAWN, "Hard-Del-All", "Hard delete all datums with the specified type.", ADMIN_CATEGORY_DEBUG, object as text) + var/type_to_del = user.poll_type_to_del(object) if(!type_to_del) return - var/choice = alert("ARE YOU SURE that you want to hard delete this type? It will cause MASSIVE lag.", "Hoooo lad what happen?", "Yes", "No") + var/choice = alert(user, "ARE YOU SURE that you want to hard delete this type? It will cause MASSIVE lag.", "Hoooo lad what happen?", "Yes", "No") if(choice != "Yes") return - choice = alert("Do you want to pre qdelete the atom? This will speed things up significantly, but may break depending on your level of fuckup.", "How do you even get it that bad", "Yes", "No") + choice = alert(user, "Do you want to pre qdelete the atom? This will speed things up significantly, but may break depending on your level of fuckup.", "How do you even get it that bad", "Yes", "No") var/should_pre_qdel = TRUE if(choice == "No") should_pre_qdel = FALSE - choice = alert("Ok one last thing, do you want to yield to the game? or do it all at once. These are hard deletes remember.", "Jesus christ man", "Yield", "Ignore the server") + choice = alert(user, "Ok one last thing, do you want to yield to the game? or do it all at once. These are hard deletes remember.", "Jesus christ man", "Yield", "Ignore the server") var/should_check_tick = TRUE if(choice == "Ignore the server") should_check_tick = FALSE @@ -129,24 +103,20 @@ qdel(O) del(O) CHECK_TICK - log_admin("[key_name(src)] has hard deleted all ([counter]) instances of [type_to_del].") - message_admins("[key_name_admin(src)] has hard deleted all ([counter]) instances of [type_to_del].") + log_admin("[key_name(user)] has hard deleted all ([counter]) instances of [type_to_del].") + message_admins("[key_name_admin(user)] has hard deleted all ([counter]) instances of [type_to_del].") BLACKBOX_LOG_ADMIN_VERB("Hard Delete All") -/client/proc/cmd_debug_make_powernets() - set category = "Debug" - set name = "Make Powernets" +ADMIN_VERB(cmd_debug_make_powernets, R_DEBUG|R_SERVER, "Make Powernets", "Regenerates all powernets for all cables.", ADMIN_CATEGORY_DEBUG) SSmachines.makepowernets() - log_admin("[key_name(src)] has remade the powernet. makepowernets() called.") - message_admins("[key_name_admin(src)] has remade the powernets. makepowernets() called.") + log_admin("[key_name(user)] has remade the powernet. makepowernets() called.") + message_admins("[key_name_admin(user)] has remade the powernets. makepowernets() called.") BLACKBOX_LOG_ADMIN_VERB("Make Powernets") -/client/proc/cmd_admin_grantfullaccess(mob/M in GLOB.mob_list) - set category = "Debug" - set name = "Grant Full Access" - +ADMIN_VERB_VISIBILITY(cmd_admin_grantfullaccess, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_grantfullaccess, R_DEBUG, "Grant Full Access", "Grant full access to a mob.", ADMIN_CATEGORY_DEBUG, mob/M in world) if(!SSticker.HasRoundStarted()) - tgui_alert(usr,"Wait until the game starts") + tgui_alert(user, "Wait until the game starts") return if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -180,51 +150,44 @@ H.equip_to_slot(id, ITEM_SLOT_ID) else - tgui_alert(usr,"Invalid mob") + tgui_alert(user,"Invalid mob") BLACKBOX_LOG_ADMIN_VERB("Grant Full Access") - log_admin("[key_name(src)] has granted [M.key] full access.") - message_admins(span_adminnotice("[key_name_admin(usr)] has granted [M.key] full access.")) - -/client/proc/cmd_assume_direct_control(mob/M in GLOB.mob_list) - set category = "Admin.Game" - set name = "Assume direct control" - set desc = "Direct intervention" + log_admin("[key_name(user)] has granted [M.key] full access.") + message_admins(span_adminnotice("[key_name_admin(user)] has granted [M.key] full access.")) +ADMIN_VERB(cmd_assume_direct_control, R_ADMIN, "Assume Direct Control", "Assume direct control of a mob.", ADMIN_CATEGORY_DEBUG, mob/M) if(M.ckey) - if(tgui_alert(usr,"This mob is being controlled by [M.key]. Are you sure you wish to assume control of it? [M.key] will be made a ghost.",,list("Yes","No")) != "Yes") + if(tgui_alert(user,"This mob is being controlled by [M.key]. Are you sure you wish to assume control of it? [M.key] will be made a ghost.",,list("Yes","No")) != "Yes") return if(!M || QDELETED(M)) - to_chat(usr, span_warning("The target mob no longer exists.")) + to_chat(user, span_warning("The target mob no longer exists.")) return - message_admins(span_adminnotice("[key_name_admin(usr)] assumed direct control of [M].")) - log_admin("[key_name(usr)] assumed direct control of [M].") - var/mob/adminmob = mob + message_admins(span_adminnotice("[key_name_admin(user)] assumed direct control of [M].")) + log_admin("[key_name(user)] assumed direct control of [M].") + var/mob/adminmob = user.mob if(M.ckey) M.ghostize(FALSE) - M.key = key - init_verbs() + M.key = user.key + user.init_verbs() if(isobserver(adminmob)) qdel(adminmob) BLACKBOX_LOG_ADMIN_VERB("Assume Direct Control") -/client/proc/cmd_give_direct_control(mob/M in GLOB.mob_list) - set category = "Admin.Game" - set name = "Give direct control" - +ADMIN_VERB(cmd_give_direct_control, R_ADMIN, "Give Direct Control", "Give direct control of a mob to another player.", ADMIN_CATEGORY_GAME, mob/M) if(!M) return if(M.ckey) - if(tgui_alert(usr,"This mob is being controlled by [M.key]. Are you sure you wish to give someone else control of it? [M.key] will be made a ghost.",,list("Yes","No")) != "Yes") + if(tgui_alert(user,"This mob is being controlled by [M.key]. Are you sure you wish to give someone else control of it? [M.key] will be made a ghost.",,list("Yes","No")) != "Yes") return - var/client/newkey = input(src, "Pick the player to put in control.", "New player") as null|anything in sort_list(GLOB.clients) + var/client/newkey = input(user, "Pick the player to put in control.", "New player") as null|anything in sort_list(GLOB.clients) if(isnull(newkey)) return var/mob/oldmob = newkey.mob var/delmob = FALSE - if((isobserver(oldmob) || tgui_alert(usr,"Do you want to delete [newkey]'s old mob?","Delete?",list("Yes","No")) != "No")) + if((isobserver(oldmob) || tgui_alert(user,"Do you want to delete [newkey]'s old mob?","Delete?",list("Yes","No")) != "No")) delmob = TRUE if(!M || QDELETED(M)) - to_chat(usr, span_warning("The target mob no longer exists, aborting.")) + to_chat(user, span_warning("The target mob no longer exists, aborting.")) return if(M.ckey) M.ghostize(FALSE) @@ -232,14 +195,12 @@ M.client?.init_verbs() if(delmob) qdel(oldmob) - message_admins(span_adminnotice("[key_name_admin(usr)] gave away direct control of [M] to [newkey].")) - log_admin("[key_name(usr)] gave away direct control of [M] to [newkey].") + message_admins(span_adminnotice("[key_name_admin(user)] gave away direct control of [M] to [newkey].")) + log_admin("[key_name(user)] gave away direct control of [M] to [newkey].") BLACKBOX_LOG_ADMIN_VERB("Give Direct Control") -/client/proc/cmd_admin_areatest(on_station, filter_maint) - set category = "Mapping" - set name = "Test Areas" - +ADMIN_VERB_VISIBILITY(cmd_admin_areatest, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_areatest, R_DEBUG, "Test Areas", "Tests the areas for various machinery.", ADMIN_CATEGORY_MAPPING, on_station as num, filter_maint as num) var/list/dat = list() var/list/areas_all = list() var/list/areas_with_APC = list() @@ -270,7 +231,7 @@ )) if(SSticker.current_state == GAME_STATE_STARTUP) - to_chat(usr, "Game still loading, please hold!", confidential = TRUE) + to_chat(user, "Game still loading, please hold!", confidential = TRUE) return var/log_message @@ -283,8 +244,8 @@ dat += "Maintenance Areas Filtered Out" log_message += ", with no maintenance areas" - message_admins(span_adminnotice("[key_name_admin(usr)] used the Test Areas debug command checking [log_message].")) - log_admin("[key_name(usr)] used the Test Areas debug command checking [log_message].") + message_admins(span_adminnotice("[key_name_admin(user)] used the Test Areas debug command checking [log_message].")) + log_admin("[key_name(user)] used the Test Areas debug command checking [log_message].") for(var/area/A as anything in GLOB.areas) if(on_station) @@ -425,28 +386,23 @@ if(!(areas_with_APC.len || areas_with_multiple_APCs.len || areas_with_air_alarm.len || areas_with_RC.len || areas_with_light.len || areas_with_LS.len || areas_with_intercom.len || areas_with_camera.len)) dat += "No problem areas!" - var/datum/browser/popup = new(usr, "testareas", "Test Areas", 500, 750) + var/datum/browser/popup = new(user.mob, "testareas", "Test Areas", 500, 750) popup.set_content(dat.Join()) popup.open() +ADMIN_VERB_VISIBILITY(cmd_admin_areatest_station, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_areatest_station, R_DEBUG, "Test Areas (STATION ONLY)", "Tests the areas for various machinery on station z-levels.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/cmd_admin_areatest, /* on_station = */ TRUE) -/client/proc/cmd_admin_areatest_station() - set category = "Mapping" - set name = "Test Areas (STATION ONLY)" - cmd_admin_areatest(TRUE) +ADMIN_VERB_VISIBILITY(cmd_admin_areatest_station_no_maintenance, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_areatest_station_no_maintenance, R_DEBUG, "Test Areas (STATION - NO MAINT)", "Tests the areas for various machinery on station z-levels, excluding maintenance areas.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/cmd_admin_areatest, /* on_station = */ TRUE, /* filter_maint = */ TRUE) -/client/proc/cmd_admin_areatest_station_no_maintenance() - set category = "Mapping" - set name = "Test Areas (STATION - NO MAINT)" - cmd_admin_areatest(on_station = TRUE, filter_maint = TRUE) - -/client/proc/cmd_admin_areatest_all() - set category = "Mapping" - set name = "Test Areas (ALL)" - cmd_admin_areatest(FALSE) +ADMIN_VERB_VISIBILITY(cmd_admin_areatest_all, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_areatest_all, R_DEBUG, "Test Areas (ALL)", "Tests the areas for various machinery on all z-levels.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/cmd_admin_areatest) /client/proc/robust_dress_shop() - var/list/baseoutfits = list("Naked","Custom","As Job...", "As Plasmaman...") var/list/outfits = list() var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job) - typesof(/datum/outfit/plasmaman) @@ -497,52 +453,29 @@ return dresscode -/client/proc/cmd_admin_rejuvenate(mob/living/M in GLOB.mob_list) - set category = "Debug" - set name = "Rejuvenate" - - if(!check_rights(R_ADMIN)) - return - - if(!mob) - return +ADMIN_VERB_ONLY_CONTEXT_MENU(cmd_admin_rejuvenate, R_ADMIN, "Rejuvenate", mob/living/M in world) if(!istype(M)) - tgui_alert(usr,"Cannot revive a ghost") + tgui_alert(user,"Cannot revive a ghost") return M.revive(ADMIN_HEAL_ALL) - log_admin("[key_name(usr)] healed / revived [key_name(M)]") - var/msg = span_danger("Admin [key_name_admin(usr)] healed / revived [ADMIN_LOOKUPFLW(M)]!") + log_admin("[key_name(user)] healed / revived [key_name(M)]") + var/msg = span_danger("Admin [key_name_admin(user)] healed / revived [ADMIN_LOOKUPFLW(M)]!") message_admins(msg) admin_ticket_log(M, msg) BLACKBOX_LOG_ADMIN_VERB("Rejuvenate") -/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in world) - set category = "Debug" - set name = "Delete" - - if(!check_rights(R_SPAWN|R_DEBUG)) - return - - admin_delete(A) +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_delete, R_DEBUG|R_SPAWN, "Delete", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/target as obj|mob|turf in world) + user.admin_delete(target) -/client/proc/cmd_admin_check_contents(mob/living/M in GLOB.mob_list) - set category = "Debug" - set name = "Check Contents" - - var/list/L = M.get_contents() - for(var/t in L) - to_chat(usr, "[t] [ADMIN_VV(t)] [ADMIN_TAG(t)]", confidential = TRUE) +ADMIN_VERB_AND_CONTEXT_MENU(cmd_check_contents, R_ADMIN, "Check Contents", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/living/mob) + var/list/mob_contents = mob.get_contents() + for(var/content in mob_contents) + to_chat(user, "[content] [ADMIN_VV(content)] [ADMIN_TAG(content)]", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Check Contents") -/client/proc/modify_goals() - set category = "Debug" - set name = "Modify goals" - - if(!check_rights(R_ADMIN)) - return - - holder.modify_goals() +ADMIN_VERB(modify_goals, R_ADMIN, "Modify Goals", "Modify the station goals for the shift.", ADMIN_CATEGORY_DEBUG) + user.holder.modify_goals() /datum/admins/proc/modify_goals() var/dat = "" @@ -551,34 +484,27 @@ dat += "
    Add New Goal" usr << browse(dat, "window=goals;size=400x400") -/client/proc/cmd_debug_mob_lists() - set category = "Debug" - set name = "Debug Mob Lists" - set desc = "For when you just gotta know" - var/chosen_list = tgui_input_list(usr, "Which list?", "Select List", list("Players","Admins","Mobs","Living Mobs","Dead Mobs","Clients","Joined Clients")) +ADMIN_VERB(debug_mob_lists, R_DEBUG, "Debug Mob Lists", "For when you just gotta know.", ADMIN_CATEGORY_DEBUG) + var/chosen_list = tgui_input_list(user, "Which list?", "Select List", list("Players","Admins","Mobs","Living Mobs","Dead Mobs","Clients","Joined Clients")) if(isnull(chosen_list)) return switch(chosen_list) if("Players") - to_chat(usr, jointext(GLOB.player_list,","), confidential = TRUE) + to_chat(user, jointext(GLOB.player_list,","), confidential = TRUE) if("Admins") - to_chat(usr, jointext(GLOB.admins,","), confidential = TRUE) + to_chat(user, jointext(GLOB.admins,","), confidential = TRUE) if("Mobs") - to_chat(usr, jointext(GLOB.mob_list,","), confidential = TRUE) + to_chat(user, jointext(GLOB.mob_list,","), confidential = TRUE) if("Living Mobs") - to_chat(usr, jointext(GLOB.alive_mob_list,","), confidential = TRUE) + to_chat(user, jointext(GLOB.alive_mob_list,","), confidential = TRUE) if("Dead Mobs") - to_chat(usr, jointext(GLOB.dead_mob_list,","), confidential = TRUE) + to_chat(user, jointext(GLOB.dead_mob_list,","), confidential = TRUE) if("Clients") - to_chat(usr, jointext(GLOB.clients,","), confidential = TRUE) + to_chat(user, jointext(GLOB.clients,","), confidential = TRUE) if("Joined Clients") - to_chat(usr, jointext(GLOB.joined_player_list,","), confidential = TRUE) - -/client/proc/cmd_display_del_log() - set category = "Debug" - set name = "Display del() Log" - set desc = "Display del's log of everything that's passed through it." + to_chat(user, jointext(GLOB.joined_player_list,","), confidential = TRUE) +ADMIN_VERB(del_log, R_DEBUG, "Display del() Log", "Display del's log of everything that's passed through it.", ADMIN_CATEGORY_DEBUG) var/list/dellog = list("List of things that have gone through qdel this round

      ") sortTim(SSgarbage.items, cmp=/proc/cmp_qdel_item_time, associative = TRUE) for(var/path in SSgarbage.items) @@ -609,37 +535,19 @@ dellog += "
    " - usr << browse(dellog.Join(), "window=dellog") - -/client/proc/cmd_display_overlay_log() - set category = "Debug" - set name = "Display overlay Log" - set desc = "Display SSoverlays log of everything that's passed through it." - - render_stats(SSoverlays.stats, src) - -/client/proc/cmd_display_init_log() - set category = "Debug" - set name = "Display Initialize() Log" - set desc = "Displays a list of things that didn't handle Initialize() properly" + user << browse(dellog.Join(), "window=dellog") - usr << browse(replacetext(SSatoms.InitLog(), "\n", "
    "), "window=initlog") +ADMIN_VERB(display_overlay_log, R_DEBUG, "Display Overlay Log", "Display SSoverlays log of everything that's passed through it.", ADMIN_CATEGORY_DEBUG) + render_stats(SSoverlays.stats, user) -/client/proc/open_colorblind_test() - set category = "Debug" - set name = "Colorblind Testing" - set desc = "Change your view to a budget version of colorblindness to test for usability" +ADMIN_VERB(init_log, R_DEBUG, "Display Initialize() Log", "Displays a list of things that didn't handle Initialize() properly.", ADMIN_CATEGORY_DEBUG) + user << browse(replacetext(SSatoms.InitLog(), "\n", "
    "), "window=initlog") - if(!holder) - return - holder.color_test.ui_interact(mob) - -/client/proc/debug_plane_masters() - set category = "Debug" - set name = "Edit/Debug Planes" - set desc = "Edit and visualize plane masters and their connections (relays)" +ADMIN_VERB(debug_color_test, R_DEBUG, "Colorblind Testing", "Change your view to a budget version of colorblindness to test for usability.", ADMIN_CATEGORY_DEBUG) + user.holder.color_test.ui_interact(user.mob) - edit_plane_masters() +ADMIN_VERB(debug_plane_masters, R_DEBUG, "Edit/Debug Planes", "Edit and visualize plane masters and their connections (relays).", ADMIN_CATEGORY_DEBUG) + user.edit_plane_masters() /client/proc/edit_plane_masters(mob/debug_on) if(!holder) @@ -651,21 +559,10 @@ holder.plane_debug.set_mirroring(FALSE) holder.plane_debug.ui_interact(mob) -/client/proc/debug_huds(i as num) - set category = "Debug" - set name = "Debug HUDs" - set desc = "Debug the data or antag HUDs" +ADMIN_VERB(debug_huds, R_DEBUG, "Debug HUDs", "Debug the data or antag HUDs.", ADMIN_CATEGORY_DEBUG, i as num) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/debug_variables, GLOB.huds[i]) - if(!holder) - return - debug_variables(GLOB.huds[i]) - -/client/proc/jump_to_ruin() - set category = "Debug" - set name = "Jump to Ruin" - set desc = "Displays a list of all placed ruins to teleport to." - if(!holder) - return +ADMIN_VERB(jump_to_ruin, R_DEBUG, "Jump to Ruin", "Displays a list of all placed ruins to teleport to.", ADMIN_CATEGORY_DEBUG) var/list/names = list() for(var/obj/effect/landmark/ruin/ruin_landmark as anything in GLOB.ruin_landmarks) var/datum/map_template/ruin/template = ruin_landmark.ruin_template @@ -680,23 +577,17 @@ names[name] = ruin_landmark - var/ruinname = tgui_input_list(usr, "Select ruin", "Jump to Ruin", sort_list(names)) - + var/ruinname = tgui_input_list(user, "Select ruin", "Jump to Ruin", sort_list(names)) var/obj/effect/landmark/ruin/landmark = names[ruinname] - - if(istype(landmark)) - var/datum/map_template/ruin/template = landmark.ruin_template - usr.forceMove(get_turf(landmark)) - to_chat(usr, span_name("[template.name]"), confidential = TRUE) - to_chat(usr, "[template.description]", confidential = TRUE) - -/client/proc/place_ruin() - set category = "Debug" - set name = "Spawn Ruin" - set desc = "Attempt to randomly place a specific ruin." - if (!holder) + if(!istype(landmark)) return + var/datum/map_template/ruin/template = landmark.ruin_template + user.mob.forceMove(get_turf(landmark)) + to_chat(user, span_name("[template.name]"), confidential = TRUE) + to_chat(user, "[template.description]", confidential = TRUE) +ADMIN_VERB_VISIBILITY(place_ruin, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(place_ruin, R_DEBUG, "Spawn Ruin", "Attempt to randomly place a specific ruin.", ADMIN_CATEGORY_MAPPING) var/list/exists = list() for(var/landmark in GLOB.ruin_landmarks) var/obj/effect/landmark/ruin/L = landmark @@ -714,15 +605,15 @@ themed_names[name] = list(ruin, theme, list(ruin.default_area)) names += sort_list(themed_names) - var/ruinname = tgui_input_list(usr, "Select ruin", "Spawn Ruin", sort_list(names)) + var/ruinname = tgui_input_list(user, "Select ruin", "Spawn Ruin", sort_list(names)) var/data = names[ruinname] if (!data) return var/datum/map_template/ruin/template = data[1] if (exists[template]) - var/response = tgui_alert(usr,"There is already a [template] in existence.", "Spawn Ruin", list("Jump", "Place Another", "Cancel")) + var/response = tgui_alert(user,"There is already a [template] in existence.", "Spawn Ruin", list("Jump", "Place Another", "Cancel")) if (response == "Jump") - usr.forceMove(get_turf(exists[template])) + user.mob.forceMove(get_turf(exists[template])) return else if (response == "Cancel") return @@ -731,25 +622,17 @@ seedRuins(SSmapping.levels_by_trait(data[2]), max(1, template.cost), data[3], list(ruinname = template)) if (GLOB.ruin_landmarks.len > len) var/obj/effect/landmark/ruin/landmark = GLOB.ruin_landmarks[GLOB.ruin_landmarks.len] - log_admin("[key_name(src)] randomly spawned ruin [ruinname] at [COORD(landmark)].") - usr.forceMove(get_turf(landmark)) - to_chat(src, span_name("[template.name]"), confidential = TRUE) - to_chat(src, "[template.description]", confidential = TRUE) + log_admin("[key_name(user)] randomly spawned ruin [ruinname] at [COORD(landmark)].") + user.mob.forceMove(get_turf(landmark)) + to_chat(user, span_name("[template.name]"), confidential = TRUE) + to_chat(user, "[template.description]", confidential = TRUE) else - to_chat(src, span_warning("Failed to place [template.name]."), confidential = TRUE) - -/client/proc/unload_ctf() - set category = "Debug" - set name = "Unload CTF" - set desc = "Despawns the majority of CTF" + to_chat(user, span_warning("Failed to place [template.name]."), confidential = TRUE) - toggle_id_ctf(usr, CTF_GHOST_CTF_GAME_ID, unload=TRUE) - -/client/proc/run_empty_query(val as num) - set category = "Debug" - set name = "Run empty query" - set desc = "Amount of queries to run" +ADMIN_VERB(unload_ctf, R_DEBUG, "Unload CTF", "Despawns the majority of CTF.", ADMIN_CATEGORY_DEBUG) + toggle_id_ctf(user, CTF_GHOST_CTF_GAME_ID, unload=TRUE) +ADMIN_VERB(run_empty_query, R_DEBUG, "Run Empty Query", "Runs a specified number of empty queries.", ADMIN_CATEGORY_DEBUG, val as num) var/list/queries = list() for(var/i in 1 to val) var/datum/db_query/query = SSdbcore.NewQuery("NULL") @@ -761,45 +644,31 @@ qdel(query) queries.Cut() - message_admins("[key_name_admin(src)] ran [val] empty queries.") + message_admins("[key_name_admin(user)] ran [val] empty queries.") -/client/proc/clear_dynamic_transit() - set category = "Debug" - set name = "Clear Dynamic Turf Reservations" - set desc = "Deallocates all reserved space, restoring it to round start conditions." - if(!holder) - return - var/answer = tgui_alert(usr,"WARNING: THIS WILL WIPE ALL RESERVED SPACE TO A CLEAN SLATE! ANY MOVING SHUTTLES, ELEVATORS, OR IN-PROGRESS PHOTOGRAPHY WILL BE DELETED!", "Really wipe dynamic turfs?", list("YES", "NO")) +ADMIN_VERB(clear_turf_reservations, R_DEBUG, "Clear Dynamic Turf Reservations", "Deallocates all reserved space, restoring it to round start conditions.", ADMIN_CATEGORY_DEBUG) + var/answer = tgui_alert( + user, + "WARNING: THIS WILL WIPE ALL RESERVED SPACE TO A CLEAN SLATE! ANY MOVING SHUTTLES, ELEVATORS, OR IN-PROGRESS PHOTOGRAPHY WILL BE DELETED!", + "Really wipe dynamic turfs?", + list("YES", "NO"), + ) if(answer != "YES") return - message_admins(span_adminnotice("[key_name_admin(src)] cleared dynamic transit space.")) - BLACKBOX_LOG_ADMIN_VERB("Clear Dynamic Transit") - log_admin("[key_name(src)] cleared dynamic transit space.") + message_admins(span_adminnotice("[key_name_admin(user)] cleared dynamic transit space.")) + BLACKBOX_LOG_ADMIN_VERB("Clear Dynamic Turf Reservations") + log_admin("[key_name(user)] cleared dynamic turf reservations.") SSmapping.wipe_reservations() //this goes after it's logged, incase something horrible happens. -/client/proc/toggle_medal_disable() - set category = "Debug" - set name = "Toggle Medal Disable" - set desc = "Toggles the safety lock on trying to contact the medal hub." - - if(!check_rights(R_DEBUG)) - return - +ADMIN_VERB(toggle_medal_disable, R_DEBUG, "Toggle Medal Disable", "Toggles the safety lock on trying to contact the medal hub.", ADMIN_CATEGORY_DEBUG) SSachievements.achievements_enabled = !SSachievements.achievements_enabled - message_admins(span_adminnotice("[key_name_admin(src)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.")) + message_admins(span_adminnotice("[key_name_admin(user)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.")) BLACKBOX_LOG_ADMIN_VERB("Toggle Medal Disable") - log_admin("[key_name(src)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.") - -/client/proc/view_runtimes() - set category = "Debug" - set name = "View Runtimes" - set desc = "Open the runtime Viewer" - - if(!holder) - return + log_admin("[key_name(user)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.") - GLOB.error_cache.show_to(src) +ADMIN_VERB(view_runtimes, R_DEBUG, "View Runtimes", "Opens the runtime viewer.", ADMIN_CATEGORY_DEBUG) + GLOB.error_cache.show_to(user) // The runtime viewer has the potential to crash the server if there's a LOT of runtimes // this has happened before, multiple times, so we'll just leave an alert on it @@ -808,80 +677,54 @@ if(GLOB.total_runtimes >= 100000) warning = "There are a TON of runtimes, clicking any button (especially \"linear\") WILL LIKELY crash the server" // Not using TGUI alert, because it's view runtimes, stuff is probably broken - alert(usr, "[warning]. Proceed with caution. If you really need to see the runtimes, download the runtime log and view it in a text editor.", "HEED THIS WARNING CAREFULLY MORTAL") - -/client/proc/pump_random_event() - set category = "Debug" - set name = "Pump Random Event" - set desc = "Schedules the event subsystem to fire a new random event immediately. Some events may fire without notification." - if(!holder) - return + alert(user, "[warning]. Proceed with caution. If you really need to see the runtimes, download the runtime log and view it in a text editor.", "HEED THIS WARNING CAREFULLY MORTAL") +ADMIN_VERB(pump_random_event, R_DEBUG, "Pump Random Event", "Schedules the event subsystem to fire a new random event immediately. Some events may fire without notification.", ADMIN_CATEGORY_DEBUG) SSevents.scheduled = world.time - message_admins(span_adminnotice("[key_name_admin(src)] pumped a random event.")) + message_admins(span_adminnotice("[key_name_admin(user)] pumped a random event.")) BLACKBOX_LOG_ADMIN_VERB("Pump Random Event") - log_admin("[key_name(src)] pumped a random event.") - -/client/proc/start_line_profiling() - set category = "Profile" - set name = "Start Line Profiling" - set desc = "Starts tracking line by line profiling for code lines that support it" + log_admin("[key_name(user)] pumped a random event.") +ADMIN_VERB_VISIBILITY(start_line_profiling, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(start_line_profiling, R_DEBUG, "Start Line Profiling", "Starts tracking line by line profiling for code lines that support it.", ADMIN_CATEGORY_PROFILE) LINE_PROFILE_START - message_admins(span_adminnotice("[key_name_admin(src)] started line by line profiling.")) + message_admins(span_adminnotice("[key_name_admin(user)] started line by line profiling.")) BLACKBOX_LOG_ADMIN_VERB("Start Line Profiling") - log_admin("[key_name(src)] started line by line profiling.") - -/client/proc/stop_line_profiling() - set category = "Profile" - set name = "Stops Line Profiling" - set desc = "Stops tracking line by line profiling for code lines that support it" + log_admin("[key_name(user)] started line by line profiling.") +ADMIN_VERB_VISIBILITY(stop_line_profiling, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(stop_line_profiling, R_DEBUG, "Stop Line Profiling", "Stops tracking line by line profiling for code lines that support it.", ADMIN_CATEGORY_PROFILE) LINE_PROFILE_STOP - message_admins(span_adminnotice("[key_name_admin(src)] stopped line by line profiling.")) + message_admins(span_adminnotice("[key_name_admin(user)] stopped line by line profiling.")) BLACKBOX_LOG_ADMIN_VERB("Stop Line Profiling") - log_admin("[key_name(src)] stopped line by line profiling.") - -/client/proc/show_line_profiling() - set category = "Profile" - set name = "Show Line Profiling" - set desc = "Shows tracked profiling info from code lines that support it" + log_admin("[key_name(user)] stopped line by line profiling.") +ADMIN_VERB_VISIBILITY(show_line_profiling, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(show_line_profiling, R_DEBUG, "Show Line Profiling", "Shows tracked profiling info from code lines that support it.", ADMIN_CATEGORY_PROFILE) var/sortlist = list( "Avg time" = GLOBAL_PROC_REF(cmp_profile_avg_time_dsc), "Total Time" = GLOBAL_PROC_REF(cmp_profile_time_dsc), "Call Count" = GLOBAL_PROC_REF(cmp_profile_count_dsc) ) - var/sort = input(src, "Sort type?", "Sort Type", "Avg time") as null|anything in sortlist + var/sort = input(user, "Sort type?", "Sort Type", "Avg time") as null|anything in sortlist if (!sort) return sort = sortlist[sort] - profile_show(src, sort) + profile_show(user, sort) -/client/proc/reload_configuration() - set category = "Debug" - set name = "Reload Configuration" - set desc = "Force config reload to world default" - if(!check_rights(R_DEBUG)) - return - if(tgui_alert(usr, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modifications?", "Really reset?", list("No", "Yes")) == "Yes") - config.admin_reload() - -/// A debug verb to check the sources of currently running timers -/client/proc/check_timer_sources() - set category = "Debug" - set name = "Check Timer Sources" - set desc = "Checks the sources of the running timers" - if (!check_rights(R_DEBUG)) +ADMIN_VERB(reload_configuration, R_DEBUG, "Reload Configuration", "Reloads the configuration from the default path on the disk, wiping any in-round modifications.", ADMIN_CATEGORY_DEBUG) + if(!tgui_alert(user, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modifications?", "Really reset?", list("No", "Yes")) == "Yes") return + config.admin_reload() +ADMIN_VERB(check_timer_sources, R_DEBUG, "Check Timer Sources", "Checks the sources of running timers.", ADMIN_CATEGORY_DEBUG) var/bucket_list_output = generate_timer_source_output(SStimer.bucket_list) var/second_queue = generate_timer_source_output(SStimer.second_queue) - usr << browse({" + user << browse({"

    bucket_list

    [bucket_list_output] @@ -889,24 +732,16 @@ [second_queue] "}, "window=check_timer_sources;size=700x700") -/// A debug verb to try and re-establish a connection with the TTS server and to refetch TTS voices. -/// Since voices are cached beforehand, this is unlikely to update preferences. -/client/proc/reestablish_tts_connection() - set category = "Debug" - set name = "Re-establish Connection To TTS" - set desc = "Re-establishes connection to the TTS server if possible" - if (!check_rights(R_DEBUG)) - return - - message_admins("[key_name_admin(usr)] attempted to re-establish connection to the TTS HTTP server.") - log_admin("[key_name(usr)] attempted to re-establish connection to the TTS HTTP server.") +ADMIN_VERB(reestablish_tts_connection, R_DEBUG, "Re-establish Connection To TTS", "Re-establishes connection to the TTS server if possible", ADMIN_CATEGORY_DEBUG) + message_admins("[key_name_admin(user)] attempted to re-establish connection to the TTS HTTP server.") + log_admin("[key_name(user)] attempted to re-establish connection to the TTS HTTP server.") var/success = SStts.establish_connection_to_tts() if(!success) - message_admins("[key_name_admin(usr)] failed to re-established the connection to the TTS HTTP server.") - log_admin("[key_name(usr)] failed to re-established the connection to the TTS HTTP server.") + message_admins("[key_name_admin(user)] failed to re-established the connection to the TTS HTTP server.") + log_admin("[key_name(user)] failed to re-established the connection to the TTS HTTP server.") return - message_admins("[key_name_admin(usr)] successfully re-established the connection to the TTS HTTP server.") - log_admin("[key_name(usr)] successfully re-established the connection to the TTS HTTP server.") + message_admins("[key_name_admin(user)] successfully re-established the connection to the TTS HTTP server.") + log_admin("[key_name(user)] successfully re-established the connection to the TTS HTTP server.") /proc/generate_timer_source_output(list/datum/timedevent/events) var/list/per_source = list() @@ -930,7 +765,7 @@ var/list/sorted = list() for (var/source in per_source) sorted += list(list("source" = source, "count" = per_source[source])) - sorted = sortTim(sorted, GLOBAL_PROC_REF(cmp_timer_data)) + sortTim(sorted, GLOBAL_PROC_REF(cmp_timer_data)) // Now that everything is sorted, compile them into an HTML output var/output = "" @@ -950,10 +785,14 @@ return b["count"] - a["count"] #ifdef TESTING -/client/proc/check_missing_sprites() - set category = "Debug" - set name = "Debug Worn Item Sprites" - set desc = "We're cancelling the Spritemageddon. (This will create a LOT of runtimes! Don't use on a live server!)" +ADMIN_VERB_CUSTOM_EXIST_CHECK(check_missing_sprites) + return TRUE +#else +ADMIN_VERB_CUSTOM_EXIST_CHECK(check_missing_sprites) + return FALSE +#endif + +ADMIN_VERB(check_missing_sprites, R_DEBUG, "Debug Worn Item Sprites", "We're cancelling the Spritemageddon. (This will create a LOT of runtimes! Don't use on a live server!)", ADMIN_CATEGORY_DEBUG) var/actual_file_name for(var/test_obj in subtypesof(/obj/item)) var/obj/item/sprite = new test_obj @@ -962,55 +801,54 @@ //Is there an explicit worn_icon to pick against the worn_icon_state? Easy street expected behavior. if(sprite.worn_icon) if(!(sprite.icon_state in icon_states(sprite.worn_icon))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Slot Flags are [sprite.slot_flags]."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Slot Flags are [sprite.slot_flags]."), confidential = TRUE) else if(sprite.worn_icon_state) if(sprite.slot_flags & ITEM_SLOT_MASK) actual_file_name = 'icons/mob/clothing/mask.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_NECK) actual_file_name = 'icons/mob/clothing/neck.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BACK) actual_file_name = 'icons/mob/clothing/back.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_HEAD) actual_file_name = 'icons/mob/clothing/head/default.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BELT) actual_file_name = 'icons/mob/clothing/belt.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_SUITSTORE) actual_file_name = 'icons/mob/clothing/belt_mirror.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) else if(sprite.icon_state) if(sprite.slot_flags & ITEM_SLOT_MASK) actual_file_name = 'icons/mob/clothing/mask.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_NECK) actual_file_name = 'icons/mob/clothing/neck.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BACK) actual_file_name = 'icons/mob/clothing/back.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_HEAD) actual_file_name = 'icons/mob/clothing/head/default.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BELT) actual_file_name = 'icons/mob/clothing/belt.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_SUITSTORE) actual_file_name = 'icons/mob/clothing/belt_mirror.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) -#endif + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm index a6a9a204b8521..4575614bb948f 100644 --- a/code/modules/admin/verbs/diagnostics.dm +++ b/code/modules/admin/verbs/diagnostics.dm @@ -1,15 +1,10 @@ -/client/proc/air_status(turf/target) - set category = "Debug" - set name = "Display Air Status" - - if(!isturf(target)) - return - atmos_scan(user=usr, target=target, silent=TRUE) +ADMIN_VERB_VISIBILITY(debug_air_status, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(debug_air_status, R_DEBUG, "Debug Air Status" , ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, turf/target in world) + atmos_scan(user.mob, target, silent = TRUE) BLACKBOX_LOG_ADMIN_VERB("Show Air Status") -/client/proc/fix_next_move() - set category = "Debug" - set name = "Unfreeze Everyone" +ADMIN_VERB_VISIBILITY(fix_next_move, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(fix_next_move, R_DEBUG, "Fix Next Move", "Unfreezes all frozen mobs.", ADMIN_CATEGORY_DEBUG) var/largest_move_time = 0 var/largest_click_time = 0 var/mob/largest_move_mob = null @@ -34,12 +29,9 @@ message_admins("[ADMIN_LOOKUPFLW(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [DisplayTimeText(largest_click_time)]!") message_admins("world.time = [world.time]") BLACKBOX_LOG_ADMIN_VERB("Unfreeze Everyone") - return - -/client/proc/radio_report() - set category = "Debug" - set name = "Radio report" +ADMIN_VERB_VISIBILITY(radio_report, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(radio_report, R_DEBUG, "Radio Report", "Shows a report of all radio devices and their filters.", ADMIN_CATEGORY_DEBUG) var/output = "Radio Report
    " for (var/fq in SSradio.frequencies) output += "Freq: [fq]
    " @@ -64,29 +56,21 @@ else output += "    [device]
    " - usr << browse(output,"window=radioreport") + user << browse(output,"window=radioreport") BLACKBOX_LOG_ADMIN_VERB("Show Radio Report") -/client/proc/reload_admins() - set name = "Reload Admins" - set category = "Admin" - - if(!src.holder) - return - - var/confirm = tgui_alert(usr, "Are you sure you want to reload all admins?", "Confirm", list("Yes", "No")) +ADMIN_VERB(reload_admins, R_NONE, "Reload Admins", "Reloads all admins from the database.", ADMIN_CATEGORY_MAIN) + var/confirm = tgui_alert(user, "Are you sure you want to reload all admins?", "Confirm", list("Yes", "No")) if(confirm != "Yes") return load_admins() BLACKBOX_LOG_ADMIN_VERB("Reload All Admins") - message_admins("[key_name_admin(usr)] manually reloaded admins") + message_admins("[key_name_admin(user)] manually reloaded admins") -/client/proc/toggle_cdn() - set name = "Toggle CDN" - set category = "Server" +ADMIN_VERB(toggle_cdn, R_SERVER|R_DEBUG, "Toggle CDN", "Toggles the CDN for the server.", ADMIN_CATEGORY_SERVER) var/static/admin_disabled_cdn_transport = null - if (alert(usr, "Are you sure you want to toggle the CDN asset transport?", "Confirm", "Yes", "No") != "Yes") + if (alert(user, "Are you sure you want to toggle the CDN asset transport?", "Confirm", "Yes", "No") != "Yes") return var/current_transport = CONFIG_GET(string/asset_transport) if (!current_transport || current_transport == "simple") @@ -94,17 +78,17 @@ CONFIG_SET(string/asset_transport, admin_disabled_cdn_transport) admin_disabled_cdn_transport = null SSassets.OnConfigLoad() - message_admins("[key_name_admin(usr)] re-enabled the CDN asset transport") - log_admin("[key_name(usr)] re-enabled the CDN asset transport") + message_admins("[key_name_admin(user)] re-enabled the CDN asset transport") + log_admin("[key_name(user)] re-enabled the CDN asset transport") else - to_chat(usr, span_adminnotice("The CDN is not enabled!")) - if (tgui_alert(usr, "The CDN asset transport is not enabled! If you having issues with assets you can also try disabling filename mutations.", "The CDN asset transport is not enabled!", list("Try disabling filename mutations", "Nevermind")) == "Try disabling filename mutations") + to_chat(user, span_adminnotice("The CDN is not enabled!")) + if (tgui_alert(user, "The CDN asset transport is not enabled! If you having issues with assets you can also try disabling filename mutations.", "The CDN asset transport is not enabled!", list("Try disabling filename mutations", "Nevermind")) == "Try disabling filename mutations") SSassets.transport.dont_mutate_filenames = !SSassets.transport.dont_mutate_filenames - message_admins("[key_name_admin(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms") - log_admin("[key_name(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms") + message_admins("[key_name_admin(user)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms") + log_admin("[key_name(user)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms") else admin_disabled_cdn_transport = current_transport CONFIG_SET(string/asset_transport, "simple") SSassets.OnConfigLoad() - message_admins("[key_name_admin(usr)] disabled the CDN asset transport") - log_admin("[key_name(usr)] disabled the CDN asset transport") + message_admins("[key_name_admin(user)] disabled the CDN asset transport") + log_admin("[key_name(user)] disabled the CDN asset transport") diff --git a/code/modules/admin/verbs/ert.dm b/code/modules/admin/verbs/ert.dm index 6fc238931a65e..c86d08151ee62 100644 --- a/code/modules/admin/verbs/ert.dm +++ b/code/modules/admin/verbs/ert.dm @@ -261,18 +261,14 @@ return -/client/proc/summon_ert() - set category = "Admin.Fun" - set name = "Summon ERT" - set desc = "Summons an emergency response team" - - message_admins("[key_name(usr)] is creating a CentCom response team...") - if(holder?.makeEmergencyresponseteam()) - message_admins("[key_name(usr)] created a CentCom response team.") - log_admin("[key_name(usr)] created a CentCom response team.") +ADMIN_VERB(summon_ert, R_FUN, "Summon ERT", "Summons an emergency response team.", ADMIN_CATEGORY_FUN) + message_admins("[key_name_admin(user)] is creating a CentCom response team...") + if(user.holder?.makeEmergencyresponseteam()) + message_admins("[key_name_admin(user)] created a CentCom response team.") + log_admin("[key_name(user)] created a CentCom response team.") else - message_admins("[key_name_admin(usr)] tried to create a CentCom response team. Unfortunately, there were not enough candidates available.") - log_admin("[key_name(usr)] failed to create a CentCom response team.") + message_admins("[key_name_admin(user)] tried to create a CentCom response team. Unfortunately, there were not enough candidates available.") + log_admin("[key_name(user)] failed to create a CentCom response team.") #undef ERT_EXPERIENCED_LEADER_CHOOSE_TOP #undef DUMMY_HUMAN_SLOT_ADMIN diff --git a/code/modules/admin/verbs/fix_air.dm b/code/modules/admin/verbs/fix_air.dm index 15c1cccbfab79..00fbb3f1bec83 100644 --- a/code/modules/admin/verbs/fix_air.dm +++ b/code/modules/admin/verbs/fix_air.dm @@ -1,20 +1,12 @@ // Proc taken from yogstation, credit to nichlas0010 for the original -/client/proc/fix_air(turf/open/T in world) - set name = "Fix Air" - set category = "Admin.Game" - set desc = "Fixes air in specified radius." +ADMIN_VERB_AND_CONTEXT_MENU(fix_air, R_ADMIN, "Fix Air", "Fixes air in a specified radius.", ADMIN_CATEGORY_GAME, turf/open/locale in world, range = 2 as num) + message_admins("[key_name_admin(user)] fixed air with range [range] in area [locale.loc.name]") + user.mob.log_message("fixed air with range [range] in area [locale.loc.name]", LOG_ADMIN) - if(!holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - if(check_rights(R_ADMIN,1)) - var/range=input("Enter range:","Num",2) as num - message_admins("[key_name_admin(usr)] fixed air with range [range] in area [T.loc.name]") - usr.log_message("fixed air with range [range] in area [T.loc.name]", LOG_ADMIN) - for(var/turf/open/F in range(range,T)) - if(F.blocks_air) - //skip walls - continue - var/datum/gas_mixture/GM = SSair.parse_gas_string(F.initial_gas_mix, /datum/gas_mixture/turf) - F.copy_air(GM) - F.update_visuals() + for(var/turf/open/valid_range_turf in range(range,locale)) + if(valid_range_turf.blocks_air) + //skip walls + continue + var/datum/gas_mixture/GM = SSair.parse_gas_string(valid_range_turf.initial_gas_mix, /datum/gas_mixture/turf) + valid_range_turf.copy_air(GM) + valid_range_turf.update_visuals() diff --git a/code/modules/admin/verbs/fov.dm b/code/modules/admin/verbs/fov.dm index f74ba6f80584d..afcd379e4a0b5 100644 --- a/code/modules/admin/verbs/fov.dm +++ b/code/modules/admin/verbs/fov.dm @@ -1,14 +1,8 @@ -/client/proc/cmd_admin_toggle_fov() - set name = "Enable/Disable Field of View" - set category = "Debug" - - if(!check_rights(R_ADMIN) || !check_rights(R_DEBUG)) - return - +ADMIN_VERB(toggle_fov, R_ADMIN|R_DEBUG, "Enable/Disable Field Of View", "Toggle FOV globally.", ADMIN_CATEGORY_DEBUG) var/on_off = CONFIG_GET(flag/native_fov) - message_admins("[key_name_admin(usr)] has [on_off ? "disabled" : "enabled"] the Native Field of View configuration..") - log_admin("[key_name(usr)] has [on_off ? "disabled" : "enabled"] the Native Field of View configuration.") + message_admins("[key_name_admin(user)] has [on_off ? "disabled" : "enabled"] the Native Field of View configuration..") + log_admin("[key_name(user)] has [on_off ? "disabled" : "enabled"] the Native Field of View configuration.") CONFIG_SET(flag/native_fov, !on_off) SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggled Field of View", "[on_off ? "Enabled" : "Disabled"]")) diff --git a/code/modules/admin/verbs/fps.dm b/code/modules/admin/verbs/fps.dm index 578a0c095144c..7af7968cde402 100644 --- a/code/modules/admin/verbs/fps.dm +++ b/code/modules/admin/verbs/fps.dm @@ -1,23 +1,16 @@ -//replaces the old Ticklag verb, fps is easier to understand -/client/proc/set_server_fps() - set category = "Debug" - set name = "Set Server FPS" - set desc = "Sets game speed in frames-per-second. Can potentially break the game" - - if(!check_rights(R_DEBUG)) - return - +ADMIN_VERB_VISIBILITY(set_server_fps, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(set_server_fps, R_DEBUG, "Set Server FPS", "Sets game speed in frames-per-second. Can potentially break the game", ADMIN_CATEGORY_DEBUG) var/cfg_fps = CONFIG_GET(number/fps) - var/new_fps = round(input("Sets game frames-per-second. Can potentially break the game (default: [cfg_fps])","FPS", world.fps) as num|null) + var/new_fps = round(input(user, "Sets game frames-per-second. Can potentially break the game (default: [cfg_fps])","FPS", world.fps) as num|null) if(new_fps <= 0) - to_chat(src, span_danger("Error: set_server_fps(): Invalid world.fps value. No changes made."), confidential = TRUE) + to_chat(user, span_danger("Error: set_server_fps(): Invalid world.fps value. No changes made."), confidential = TRUE) return if(new_fps > cfg_fps * 1.5) - if(tgui_alert(usr, "You are setting fps to a high value:\n\t[new_fps] frames-per-second\n\tconfig.fps = [cfg_fps]","Warning!",list("Confirm","ABORT-ABORT-ABORT")) != "Confirm") + if(tgui_alert(user, "You are setting fps to a high value:\n\t[new_fps] frames-per-second\n\tconfig.fps = [cfg_fps]","Warning!",list("Confirm","ABORT-ABORT-ABORT")) != "Confirm") return - var/msg = "[key_name(src)] has modified world.fps to [new_fps]" + var/msg = "[key_name(user)] has modified world.fps to [new_fps]" log_admin(msg, 0) message_admins(msg, 0) SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Set Server FPS", "[new_fps]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index 77b43f9b49f48..bceac01cbe0d6 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -1,17 +1,8 @@ -//This proc allows download of past server logs saved within the data/logs/ folder. -/client/proc/getserverlogs() - set name = "Get Server Logs" - set desc = "View/retrieve logfiles." - set category = "Admin" +ADMIN_VERB(get_server_logs, R_ADMIN, "Get Server Logs", "View or retrieve logfiles.", ADMIN_CATEGORY_MAIN) + user.browseserverlogs() - browseserverlogs() - -/client/proc/getcurrentlogs() - set name = "Get Current Logs" - set desc = "View/retrieve logfiles for the current round." - set category = "Admin" - - browseserverlogs(current=TRUE) +ADMIN_VERB(get_current_logs, R_ADMIN, "Get Current Logs", "View or retrieve logfiles for the current round.", ADMIN_CATEGORY_MAIN) + user.browseserverlogs(current=TRUE) /client/proc/browseserverlogs(current=FALSE) var/path = browse_files(current ? BROWSE_ROOT_CURRENT_LOGS : BROWSE_ROOT_ALL_LOGS) @@ -32,4 +23,3 @@ else return to_chat(src, "Attempting to send [path], this may take a fair few minutes if the file is very large.", confidential = TRUE) - return diff --git a/code/modules/admin/verbs/ghost_pool_protection.dm b/code/modules/admin/verbs/ghost_pool_protection.dm index 843f6868e7072..439f4a37b897d 100644 --- a/code/modules/admin/verbs/ghost_pool_protection.dm +++ b/code/modules/admin/verbs/ghost_pool_protection.dm @@ -1,11 +1,8 @@ //very similar to centcom_podlauncher in terms of how this is coded, so i kept a lot of comments from it -/client/proc/ghost_pool_protection() //Creates a verb for admins to open up the ui - set name = "Ghost Pool Protection" - set desc = "Choose which ways people can get into the round, or just clear it out completely for admin events." - set category = "Admin.Events" - var/datum/ghost_pool_menu/tgui = new(usr)//create the datum - tgui.ui_interact(usr)//datum has a tgui component, here we open the window +ADMIN_VERB(ghost_pool_protection, R_ADMIN, "Ghost Pool Protection", "Choose which ways people can get into the round, or just clear it out completely for admin events.", ADMIN_CATEGORY_EVENTS) + var/datum/ghost_pool_menu/tgui = new(user) + tgui.ui_interact(user.mob) /datum/ghost_pool_menu var/client/holder //client of whoever is using this datum diff --git a/code/modules/admin/verbs/highlander_datum.dm b/code/modules/admin/verbs/highlander_datum.dm index ad8f75bca82b1..de7e4918fc00b 100644 --- a/code/modules/admin/verbs/highlander_datum.dm +++ b/code/modules/admin/verbs/highlander_datum.dm @@ -36,7 +36,7 @@ GLOBAL_DATUM(highlander_controller, /datum/highlander_controller) robot.gib() continue robot.make_scottish() - addtimer(CALLBACK(SSshuttle.emergency, TYPE_PROC_REF(/obj/docking_port/mobile/emergency, request), null, 1), 50) + addtimer(CALLBACK(SSshuttle.emergency, TYPE_PROC_REF(/obj/docking_port/mobile/emergency, request), null, 1), 5 SECONDS) /datum/highlander_controller/Destroy(force) . = ..() diff --git a/code/modules/admin/verbs/lawpanel.dm b/code/modules/admin/verbs/lawpanel.dm index 9b52c8d7339fe..f1daaf175761f 100644 --- a/code/modules/admin/verbs/lawpanel.dm +++ b/code/modules/admin/verbs/lawpanel.dm @@ -1,15 +1,9 @@ -/client/proc/cmd_admin_law_panel() - set category = "Admin.Events" - set name = "Law Panel" - - if(!check_rights(R_ADMIN)) - return - if(!isobserver(usr) && SSticker.HasRoundStarted()) - message_admins("[key_name_admin(usr)] checked AI laws via the Law Panel.") - +ADMIN_VERB(law_panel, R_ADMIN, "Law Panel", "View the AI laws.", ADMIN_CATEGORY_EVENTS) + if(!isobserver(user) && SSticker.HasRoundStarted()) + message_admins("[key_name_admin(user)] checked AI laws via the Law Panel.") + var/datum/law_panel/tgui = new + tgui.ui_interact(user.mob) BLACKBOX_LOG_ADMIN_VERB("Law Panel") - var/datum/law_panel/tgui = new() - tgui.ui_interact(usr) /datum/law_panel @@ -211,7 +205,7 @@ switch(action) if("lawchange_logs") - usr.client?.list_law_changes() + ui.user?.client?.holder?.list_law_changes() return FALSE if("force_state_laws") diff --git a/code/modules/admin/verbs/light_debug.dm b/code/modules/admin/verbs/light_debug.dm index ae5b24ff38032..eac81f6ed294b 100644 --- a/code/modules/admin/verbs/light_debug.dm +++ b/code/modules/admin/verbs/light_debug.dm @@ -10,7 +10,7 @@ sum[source.source_atom.type] += 1 total += 1 - sum = sortTim(sum, /proc/cmp_numeric_asc, TRUE) + sortTim(sum, associative = TRUE) var/text = "" for(var/type in sum) text += "[type] = [sum[type]]\n" diff --git a/code/modules/admin/verbs/lua/lua_editor.dm b/code/modules/admin/verbs/lua/lua_editor.dm index 9e1b851824b33..d4a4bc2ee50b7 100644 --- a/code/modules/admin/verbs/lua/lua_editor.dm +++ b/code/modules/admin/verbs/lua/lua_editor.dm @@ -233,10 +233,6 @@ . = ..() qdel(src) -/client/proc/open_lua_editor() - set name = "Open Lua Editor" - set category = "Debug" - if(!check_rights_for(src, R_DEBUG)) - return - var/datum/lua_editor/editor = new() - editor.ui_interact(usr) +ADMIN_VERB(lua_editor, R_DEBUG, "Open Lua Editor", "Its codin' time.", ADMIN_CATEGORY_DEBUG) + var/datum/lua_editor/editor = new + editor.ui_interact(user.mob) diff --git a/code/modules/admin/verbs/lua/lua_state.dm b/code/modules/admin/verbs/lua/lua_state.dm index ee7d6953e12ac..27994d966a7cb 100644 --- a/code/modules/admin/verbs/lua/lua_state.dm +++ b/code/modules/admin/verbs/lua/lua_state.dm @@ -109,14 +109,7 @@ GLOBAL_PROTECT(lua_usr) if(islist(function)) var/list/new_function_path = list() for(var/path_element in function) - if(isweakref(path_element)) - var/datum/weakref/weak_ref = path_element - var/resolved = weak_ref.hard_resolve() - if(!resolved) - return list("status" = "errored", "param" = "Weakref in function path ([weak_ref] [text_ref(weak_ref)]) resolved to null.", "name" = jointext(function, ".")) - new_function_path += resolved - else - new_function_path += path_element + new_function_path += path_element function = new_function_path var/msg = "[key_name(usr)] called the lua function \"[function]\" with arguments: [english_list(call_args)]" log_lua(msg) diff --git a/code/modules/admin/verbs/machine_upgrade.dm b/code/modules/admin/verbs/machine_upgrade.dm index 2f681574d5d45..258de6bcf4dfd 100644 --- a/code/modules/admin/verbs/machine_upgrade.dm +++ b/code/modules/admin/verbs/machine_upgrade.dm @@ -1,13 +1,7 @@ -/proc/machine_upgrade(obj/machinery/M in world) - set name = "Tweak Component Ratings" - set category = "Debug" - if (!istype(M)) - return - - var/new_rating = input("Enter new rating:","Num") as num|null - if(new_rating && M.component_parts) - for(var/obj/item/stock_parts/P in M.component_parts) +ADMIN_VERB(machine_upgrade, R_DEBUG, "Tweak Component Ratings", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, obj/machinery/machine in world) + var/new_rating = input(user, "Enter new rating:","Num") as num|null + if(new_rating && machine.component_parts) + for(var/obj/item/stock_parts/P in machine.component_parts) P.rating = new_rating - M.RefreshParts() - + machine.RefreshParts() SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Machine Upgrade", "[new_rating]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/manipulate_organs.dm b/code/modules/admin/verbs/manipulate_organs.dm index 6ead4d3b137fb..bfb5050dafa21 100644 --- a/code/modules/admin/verbs/manipulate_organs.dm +++ b/code/modules/admin/verbs/manipulate_organs.dm @@ -1,7 +1,6 @@ -/client/proc/manipulate_organs(mob/living/carbon/carbon_victim in world) - set name = "Manipulate Organs" - set category = "Debug" - var/operation = tgui_input_list(usr, "Select organ operation", "Organ Manipulation", list("add organ", "add implant", "drop organ/implant", "remove organ/implant")) +ADMIN_VERB_VISIBILITY(manipulate_organs, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(manipulate_organs, R_DEBUG, "Manipulate Organs", "Manipulate the organs of a living carbon.", ADMIN_CATEGORY_DEBUG, mob/living/carbon/carbon_victim in world) + var/operation = tgui_input_list(user, "Select organ operation", "Organ Manipulation", list("add organ", "add implant", "drop organ/implant", "remove organ/implant")) if (isnull(operation)) return @@ -12,7 +11,7 @@ var/dat = replacetext("[path]", "/obj/item/organ/", ":") organs[dat] = path - var/obj/item/organ/organ_to_grant = tgui_input_list(usr, "Select organ type", "Organ Manipulation", organs) + var/obj/item/organ/organ_to_grant = tgui_input_list(user, "Select organ type", "Organ Manipulation", organs) if(isnull(organ_to_grant)) return if(isnull(organs[organ_to_grant])) @@ -20,18 +19,18 @@ organ_to_grant = organs[organ_to_grant] organ_to_grant = new organ_to_grant if(!organ_to_grant.Insert(carbon_victim)) - to_chat(usr, span_notice("[carbon_victim] is unable to carry this organ!")) + to_chat(user, span_notice("[carbon_victim] is unable to carry this organ!")) qdel(organ_to_grant) return - log_admin("[key_name(usr)] has added organ [organ_to_grant.type] to [key_name(carbon_victim)]") - message_admins("[key_name_admin(usr)] has added organ [organ_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]") + log_admin("[key_name(user)] has added organ [organ_to_grant.type] to [key_name(carbon_victim)]") + message_admins("[key_name_admin(user)] has added organ [organ_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]") if("add implant") for(var/path in subtypesof(/obj/item/implant)) var/dat = replacetext("[path]", "/obj/item/implant/", ":") organs[dat] = path - var/obj/item/implant/implant_to_grant = tgui_input_list(usr, "Select implant type", "Organ Manipulation", organs) + var/obj/item/implant/implant_to_grant = tgui_input_list(user, "Select implant type", "Organ Manipulation", organs) if(isnull(implant_to_grant)) return if(isnull(organs[implant_to_grant])) @@ -39,11 +38,11 @@ implant_to_grant = organs[implant_to_grant] implant_to_grant = new implant_to_grant if(!implant_to_grant.implant(carbon_victim)) - to_chat(usr, span_notice("[carbon_victim] is unable to hold this implant!")) + to_chat(user, span_notice("[carbon_victim] is unable to hold this implant!")) qdel(implant_to_grant) return - log_admin("[key_name(usr)] has added implant [implant_to_grant.type] to [key_name(carbon_victim)]") - message_admins("[key_name_admin(usr)] has added implant [implant_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]") + log_admin("[key_name(user)] has added implant [implant_to_grant.type] to [key_name(carbon_victim)]") + message_admins("[key_name_admin(user)] has added implant [implant_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]") if("drop organ/implant", "remove organ/implant") for(var/obj/item/organ/user_organs as anything in carbon_victim.organs) @@ -52,15 +51,15 @@ for(var/obj/item/implant/user_implants as anything in carbon_victim.implants) organs["[user_implants.name] ([user_implants.type])"] = user_implants - var/obj/item/organ_to_modify = tgui_input_list(usr, "Select organ/implant", "Organ Manipulation", organs) + var/obj/item/organ_to_modify = tgui_input_list(user, "Select organ/implant", "Organ Manipulation", organs) if(isnull(organ_to_modify)) return if(isnull(organs[organ_to_modify])) return organ_to_modify = organs[organ_to_modify] - log_admin("[key_name(usr)] has removed [organ_to_modify.type] from [key_name(carbon_victim)]") - message_admins("[key_name_admin(usr)] has removed [organ_to_modify.type] from [ADMIN_LOOKUPFLW(carbon_victim)]") + log_admin("[key_name(user)] has removed [organ_to_modify.type] from [key_name(carbon_victim)]") + message_admins("[key_name_admin(user)] has removed [organ_to_modify.type] from [ADMIN_LOOKUPFLW(carbon_victim)]") var/obj/item/organ/organ_holder var/obj/item/implant/implant_holder @@ -70,7 +69,7 @@ organ_holder.Remove(carbon_victim) else implant_holder = organ_to_modify - implant_holder.removed(carbon_victim) + implant_holder.removed(carbon_victim, special = TRUE) organ_to_modify.forceMove(get_turf(carbon_victim)) diff --git a/code/modules/admin/verbs/map_export.dm b/code/modules/admin/verbs/map_export.dm index 8233ce4389d4b..056a2ea1f8a18 100644 --- a/code/modules/admin/verbs/map_export.dm +++ b/code/modules/admin/verbs/map_export.dm @@ -1,23 +1,22 @@ -/client/proc/map_export() - set category = "Debug" - set name = "Map Export" - set desc = "Select a part of the map by coordinates and download it." - - var/z_level = tgui_input_number(usr, "Export Which Z-Level?", "Map Exporter", usr.z || 2) - var/start_x = tgui_input_number(usr, "Start X?", "Map Exporter", usr.x || 1, world.maxx, 1) - var/start_y = tgui_input_number(usr, "Start Y?", "Map Exporter", usr.y || 1, world.maxy, 1) - var/end_x = tgui_input_number(usr, "End X?", "Map Exporter", usr.x || 1, world.maxx, 1) - var/end_y = tgui_input_number(usr, "End Y?", "Map Exporter", usr.y || 1, world.maxy, 1) +ADMIN_VERB(map_export, R_DEBUG, "Map Export", "Select a part of the map by coordinates and download it.", ADMIN_CATEGORY_DEBUG) + var/user_x = user.mob.x + var/user_y = user.mob.y + var/user_z = user.mob.z + var/z_level = tgui_input_number(user, "Export Which Z-Level?", "Map Exporter", user_z || 2) + var/start_x = tgui_input_number(user, "Start X?", "Map Exporter", user_x || 1, world.maxx, 1) + var/start_y = tgui_input_number(user, "Start Y?", "Map Exporter", user_y || 1, world.maxy, 1) + var/end_x = tgui_input_number(user, "End X?", "Map Exporter", user_x || 1, world.maxx, 1) + var/end_y = tgui_input_number(user, "End Y?", "Map Exporter", user_y || 1, world.maxy, 1) var/date = time2text(world.timeofday, "YYYY-MM-DD_hh-mm-ss") - var/file_name = sanitize_filename(tgui_input_text(usr, "Filename?", "Map Exporter", "exported_map_[date]")) - var/confirm = tgui_alert(usr, "Are you sure you want to do this? This will cause extreme lag!", "Map Exporter", list("Yes", "No")) + var/file_name = sanitize_filename(tgui_input_text(user, "Filename?", "Map Exporter", "exported_map_[date]")) + var/confirm = tgui_alert(user, "Are you sure you want to do this? This will cause extreme lag!", "Map Exporter", list("Yes", "No")) - if(confirm != "Yes" || !check_rights(R_DEBUG)) + if(confirm != "Yes") return var/map_text = write_map(start_x, start_y, z_level, end_x, end_y, z_level) - log_admin("Build Mode: [key_name(usr)] is exporting the map area from ([start_x], [start_y], [z_level]) through ([end_x], [end_y], [z_level])") - send_exported_map(usr, file_name, map_text) + log_admin("Build Mode: [key_name(user)] is exporting the map area from ([start_x], [start_y], [z_level]) through ([end_x], [end_y], [z_level])") + send_exported_map(user, file_name, map_text) /** * A procedure for saving DMM text to a file and then sending it to the user. diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm index 827bbfb16e862..a27aca0f0147b 100644 --- a/code/modules/admin/verbs/map_template_loadverb.dm +++ b/code/modules/admin/verbs/map_template_loadverb.dm @@ -1,20 +1,17 @@ -/client/proc/map_template_load() - set category = "Debug" - set name = "Map template - Place" - +ADMIN_VERB(map_template_load, R_DEBUG, "Map Template - Place", "Place a map template at your current location.", ADMIN_CATEGORY_DEBUG) var/datum/map_template/template - var/map = tgui_input_list(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template", sort_list(SSmapping.map_templates)) + var/map = tgui_input_list(user, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template", sort_list(SSmapping.map_templates)) if(!map) return template = SSmapping.map_templates[map] - var/turf/T = get_turf(mob) + var/turf/T = get_turf(user.mob) if(!T) return var/list/preview = list() var/center - var/centeralert = tgui_alert(usr,"Center Template.","Template Centering",list("Yes","No")) + var/centeralert = tgui_alert(user,"Center Template.","Template Centering",list("Yes","No")) switch(centeralert) if("Yes") center = TRUE @@ -26,8 +23,8 @@ var/image/item = image('icons/turf/overlays.dmi', place_on,"greenOverlay") SET_PLANE(item, ABOVE_LIGHTING_PLANE, place_on) preview += item - images += preview - if(tgui_alert(usr,"Confirm location.","Template Confirm",list("Yes","No")) == "Yes") + user.images += preview + if(tgui_alert(user,"Confirm location.","Template Confirm",list("Yes","No")) == "Yes") if(template.load(T, centered = center)) var/affected = template.get_affected_turfs(T, centered = center) for(var/AT in affected) @@ -36,23 +33,20 @@ template.post_load(P) break - message_admins(span_adminnotice("[key_name_admin(src)] has placed a map template ([template.name]) at [ADMIN_COORDJMP(T)]")) + message_admins(span_adminnotice("[key_name_admin(user)] has placed a map template ([template.name]) at [ADMIN_COORDJMP(T)]")) else - to_chat(src, "Failed to place map", confidential = TRUE) - images -= preview - -/client/proc/map_template_upload() - set category = "Debug" - set name = "Map Template - Upload" + to_chat(user, "Failed to place map", confidential = TRUE) + user.images -= preview - var/map = input(src, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file +ADMIN_VERB(map_template_upload, R_DEBUG, "Map Template - Upload", "Upload a map template to the server.", ADMIN_CATEGORY_DEBUG) + var/map = input(user, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file if(!map) return if(copytext("[map]", -4) != ".dmm")//4 == length(".dmm") - to_chat(src, span_warning("Filename must end in '.dmm': [map]"), confidential = TRUE) + to_chat(user, span_warning("Filename must end in '.dmm': [map]"), confidential = TRUE) return var/datum/map_template/M - switch(tgui_alert(usr, "What kind of map is this?", "Map type", list("Normal", "Shuttle", "Cancel"))) + switch(tgui_alert(user, "What kind of map is this?", "Map type", list("Normal", "Shuttle", "Cancel"))) if("Normal") M = new /datum/map_template(map, "[map]", TRUE) if("Shuttle") @@ -60,23 +54,23 @@ else return if(!M.cached_map) - to_chat(src, span_warning("Map template '[map]' failed to parse properly."), confidential = TRUE) + to_chat(user, span_warning("Map template '[map]' failed to parse properly."), confidential = TRUE) return var/datum/map_report/report = M.cached_map.check_for_errors() var/report_link if(report) - report.show_to(src) + report.show_to(user) report_link = " - validation report" - to_chat(src, span_warning("Map template '[map]' failed validation."), confidential = TRUE) + to_chat(user, span_warning("Map template '[map]' failed validation."), confidential = TRUE) if(report.loadable) - var/response = tgui_alert(usr, "The map failed validation, would you like to load it anyways?", "Map Errors", list("Cancel", "Upload Anyways")) + var/response = tgui_alert(user, "The map failed validation, would you like to load it anyways?", "Map Errors", list("Cancel", "Upload Anyways")) if(response != "Upload Anyways") return else - tgui_alert(usr, "The map failed validation and cannot be loaded.", "Map Errors", list("Oh Darn")) + tgui_alert(user, "The map failed validation and cannot be loaded.", "Map Errors", list("Oh Darn")) return SSmapping.map_templates[M.name] = M - message_admins(span_adminnotice("[key_name_admin(src)] has uploaded a map template '[map]' ([M.width]x[M.height])[report_link].")) - to_chat(src, span_notice("Map template '[map]' ready to place ([M.width]x[M.height])"), confidential = TRUE) + message_admins(span_adminnotice("[key_name_admin(user)] has uploaded a map template '[map]' ([M.width]x[M.height])[report_link].")) + to_chat(user, span_notice("Map template '[map]' ready to place ([M.width]x[M.height])"), confidential = TRUE) diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index aaf4cd13529fb..91481bb9a3e6b 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -1,69 +1,5 @@ -//- Are all the floors with or without air, as they should be? (regular or airless) -//- Does the area have an APC? -//- Does the area have an Air Alarm? -//- Does the area have a Request Console? -//- Does the area have lights? -//- Does the area have a light switch? -//- Does the area have enough intercoms? -//- Does the area have enough security cameras? (Use the 'Camera Range Display' verb under Debug) -//- Is the area connected to the scrubbers air loop? -//- Is the area connected to the vent air loop? (vent pumps) -//- Is everything wired properly? -//- Does the area have a fire alarm and firedoors? -//- Do all pod doors work properly? -//- Are accesses set properly on doors, pod buttons, etc. -//- Are all items placed properly? (not below vents, scrubbers, tables) -//- Does the disposal system work properly from all the disposal units in this room and all the units, the pipes of which pass through this room? -//- Check for any misplaced or stacked piece of pipe (air and disposal) -//- Check for any misplaced or stacked piece of wire -//- Identify how hard it is to break into the area and where the weak points are -//- Check if the area has too much empty space. If so, make it smaller and replace the rest with maintenance tunnels. - -GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list( - /client/proc/camera_view, //-errorage - /client/proc/sec_camera_report, //-errorage - /client/proc/intercom_view, //-errorage - /client/proc/air_status, //Air things - /client/proc/Cell, //More air things - /client/proc/atmosscan, //check plumbing - /client/proc/powerdebug, //check power - /client/proc/count_objects_on_z_level, - /client/proc/count_objects_all, - /client/proc/cmd_assume_direct_control, //-errorage - /client/proc/cmd_give_direct_control, - /client/proc/set_server_fps, //allows you to set the ticklag. - /client/proc/cmd_admin_grantfullaccess, - /client/proc/cmd_admin_areatest_all, - /client/proc/cmd_admin_areatest_station, - /client/proc/cmd_admin_areatest_station_no_maintenance, - #ifdef TESTING - /client/proc/see_dirty_varedits, - #endif - /client/proc/cmd_admin_rejuvenate, - /datum/admins/proc/show_traitor_panel, - /client/proc/disable_communication, - /client/proc/show_map_reports, - /client/proc/cmd_show_at_list, - /client/proc/cmd_show_at_markers, - /client/proc/manipulate_organs, - /client/proc/start_line_profiling, - /client/proc/stop_line_profiling, - /client/proc/show_line_profiling, - /client/proc/create_mapping_job_icons, - /client/proc/debug_z_levels, - /client/proc/place_ruin, - /client/proc/station_food_debug, - /client/proc/station_stack_debug, - /client/proc/check_for_obstructed_atmospherics, - /client/proc/modify_lights, - /client/proc/visualize_lights, -)) -GLOBAL_PROTECT(admin_verbs_debug_mapping) - -/client/proc/camera_view() - set category = "Mapping" - set name = "Camera Range Display" - +ADMIN_VERB_VISIBILITY(camera_view, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(camera_view, R_DEBUG, "Camera Range Display", "Shows the range of cameras on the station.", ADMIN_CATEGORY_MAPPING) var/on = FALSE for(var/turf/T in world) if(T.maptext) @@ -82,28 +18,20 @@ GLOBAL_PROTECT(admin_verbs_debug_mapping) #ifdef TESTING GLOBAL_LIST_EMPTY(dirty_vars) -/client/proc/see_dirty_varedits() - set category = "Mapping" - set name = "Dirty Varedits" - +ADMIN_VERB_VISIBILITY(see_dirty_varedits, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(see_dirty_varedits, R_DEBUG, "Dirty Varedits", "Shows all dirty varedits.", ADMIN_CATEGORY_MAPPING) var/list/dat = list() dat += "

    Abandon all hope ye who enter here



    " for(var/thing in GLOB.dirty_vars) dat += "[thing]
    " CHECK_TICK - var/datum/browser/popup = new(usr, "dirty_vars", "Dirty Varedits", 900, 750) + var/datum/browser/popup = new(user, "dirty_vars", "Dirty Varedits", 900, 750) popup.set_content(dat.Join()) popup.open() #endif -/client/proc/sec_camera_report() - set category = "Mapping" - set name = "Camera Report" - - if(!Master) - tgui_alert(usr,"Master_controller not found.","Sec Camera Report") - return FALSE - +ADMIN_VERB_VISIBILITY(sec_camera_report, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(sec_camera_report, R_DEBUG, "Camera Report", "Get a printout of all camera issues.", ADMIN_CATEGORY_MAPPING) var/list/obj/machinery/camera/CL = list() for(var/obj/machinery/camera/C as anything in GLOB.cameranet.cameras) @@ -133,15 +61,13 @@ GLOBAL_LIST_EMPTY(dirty_vars) output += "
  • Camera not connected to wall at [ADMIN_VERBOSEJMP(C1)] Network: [json_encode(C1.network)]
  • " output += "" - usr << browse(output,"window=airreport;size=1000x500") + user << browse(output,"window=airreport;size=1000x500") BLACKBOX_LOG_ADMIN_VERB("Show Camera Report") -/client/proc/intercom_view() - set category = "Mapping" - set name = "Intercom Range Display" - +ADMIN_VERB_VISIBILITY(intercom_view, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(intercom_view, R_DEBUG, "Intercom Range Display", "Shows the range of intercoms on the station.", ADMIN_CATEGORY_MAPPING) var/static/intercom_range_display_status = FALSE - intercom_range_display_status = !intercom_range_display_status //blame cyberboss if this breaks something //blamed + intercom_range_display_status = !intercom_range_display_status for(var/obj/effect/abstract/marker/intercom/marker in GLOB.all_abstract_markers) qdel(marker) @@ -153,23 +79,17 @@ GLOBAL_LIST_EMPTY(dirty_vars) new /obj/effect/abstract/marker/intercom(turf) BLACKBOX_LOG_ADMIN_VERB("Show Intercom Range") -/client/proc/show_map_reports() - set category = "Mapping" - set name = "Show map report list" - set desc = "Displays a list of map reports" - +ADMIN_VERB_VISIBILITY(show_map_reports, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(show_map_reports, R_DEBUG, "Show Map Reports", "Displays a list of map reports.", ADMIN_CATEGORY_MAPPING) var/dat = {"List of all map reports:
    "} for(var/datum/map_report/report as anything in GLOB.map_reports) dat += "[report.tag] ([report.original_path]) - View
    " - usr << browse(dat, "window=map_reports") - -/client/proc/cmd_show_at_list() - set category = "Mapping" - set name = "Show roundstart AT list" - set desc = "Displays a list of active turfs coordinates at roundstart" + user << browse(dat, "window=map_reports") +ADMIN_VERB_VISIBILITY(cmd_show_at_list, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_show_at_list, R_DEBUG, "Show roundstart AT list", "Displays a list of active turfs coordinates at roundstart.", ADMIN_CATEGORY_MAPPING) var/dat = {"Coordinate list of Active Turfs at Roundstart
    Real-time Active Turfs list you can see in Air Subsystem at active_turfs var
    "} @@ -178,50 +98,39 @@ GLOBAL_LIST_EMPTY(dirty_vars) dat += "[ADMIN_VERBOSEJMP(T)]\n" dat += "
    " - usr << browse(dat, "window=at_list") + user << browse(dat, "window=at_list") BLACKBOX_LOG_ADMIN_VERB("Show Roundstart Active Turfs") -/client/proc/cmd_show_at_markers() - set category = "Mapping" - set name = "Show roundstart AT markers" - set desc = "Places a marker on all active-at-roundstart turfs" - +ADMIN_VERB_VISIBILITY(cmd_show_at_markers, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_show_at_markers, R_DEBUG, "Show roundstart AT markers", "Places a marker on all active-at-roundstart turfs.", ADMIN_CATEGORY_MAPPING) var/count = 0 for(var/obj/effect/abstract/marker/at/AT in GLOB.all_abstract_markers) qdel(AT) count++ if(count) - to_chat(usr, "[count] AT markers removed.", confidential = TRUE) + to_chat(user, "[count] AT markers removed.", confidential = TRUE) else for(var/t in GLOB.active_turfs_startlist) new /obj/effect/abstract/marker/at(t) count++ - to_chat(usr, "[count] AT markers placed.", confidential = TRUE) + to_chat(user, "[count] AT markers placed.", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Show Roundstart Active Turf Markers") -/client/proc/enable_mapping_verbs() - set category = "Debug" - set name = "Mapping verbs - Enable" - if(!check_rights(R_DEBUG)) - return - remove_verb(src, /client/proc/enable_mapping_verbs) - add_verb(src, list(/client/proc/disable_mapping_verbs, GLOB.admin_verbs_debug_mapping)) +ADMIN_VERB(enable_mapping_verbs, R_DEBUG, "Enable Mapping Verbs", "Enable all mapping verbs.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.update_visibility_flag(user, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG, TRUE) BLACKBOX_LOG_ADMIN_VERB("Enable Debug Verbs") -/client/proc/disable_mapping_verbs() - set category = "Debug" - set name = "Mapping verbs - Disable" - remove_verb(src, list(/client/proc/disable_mapping_verbs, GLOB.admin_verbs_debug_mapping)) - add_verb(src, /client/proc/enable_mapping_verbs) +ADMIN_VERB_VISIBILITY(disable_mapping_verbs, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(disable_mapping_verbs, R_DEBUG, "Disable Mapping Verbs", "Disable all mapping verbs.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.update_visibility_flag(user, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG, FALSE) BLACKBOX_LOG_ADMIN_VERB("Disable Debug Verbs") -/client/proc/count_objects_on_z_level() - set category = "Mapping" - set name = "Count Objects On Level" - var/level = input("Which z-level?","Level?") as text|null +ADMIN_VERB_VISIBILITY(count_objects_on_z_level, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(count_objects_on_z_level, R_DEBUG, "Count Objects On Z-Level", "Counts the number of objects of a certain type on a specific z-level.", ADMIN_CATEGORY_MAPPING) + var/level = input(user, "Which z-level?","Level?") as text|null if(!level) return var/num_level = text2num(level) @@ -230,7 +139,7 @@ GLOBAL_LIST_EMPTY(dirty_vars) if(!isnum(num_level)) return - var/type_text = input("Which type path?","Path?") as text|null + var/type_text = input(user, "Which type path?","Path?") as text|null if(!type_text) return var/type_path = text2path(type_text) @@ -257,11 +166,9 @@ GLOBAL_LIST_EMPTY(dirty_vars) to_chat(world, "There are [count] objects of type [type_path] on z-level [num_level]", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Count Objects Zlevel") -/client/proc/count_objects_all() - set category = "Mapping" - set name = "Count Objects All" - - var/type_text = input("Which type path?","") as text|null +ADMIN_VERB_VISIBILITY(count_objects_all, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(count_objects_all, R_DEBUG, "Count Objects All", "Counts the number of objects of a certain type in the game world.", ADMIN_CATEGORY_MAPPING) + var/type_text = input(user, "Which type path?","") as text|null if(!type_text) return var/type_path = text2path(type_text) @@ -277,23 +184,17 @@ GLOBAL_LIST_EMPTY(dirty_vars) to_chat(world, "There are [count] objects of type [type_path] in the game world", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Count Objects All") - -//This proc is intended to detect lag problems relating to communication procs GLOBAL_VAR_INIT(say_disabled, FALSE) -/client/proc/disable_communication() - set category = "Mapping" - set name = "Disable all communication verbs" - +ADMIN_VERB_VISIBILITY(disable_communication, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(disable_communication, R_DEBUG, "Disable all communication verbs", "Disables all communication verbs.", ADMIN_CATEGORY_MAPPING) GLOB.say_disabled = !GLOB.say_disabled if(GLOB.say_disabled) - message_admins("[key] used 'Disable all communication verbs', killing all communication methods.") + message_admins("[key_name_admin(user)] used 'Disable all communication verbs', killing all communication methods.") else - message_admins("[key] used 'Disable all communication verbs', restoring all communication methods.") + message_admins("[key_name_admin(user)] used 'Disable all communication verbs', restoring all communication methods.") -//This generates the icon states for job starting location landmarks. -/client/proc/create_mapping_job_icons() - set name = "Generate job landmarks icons" - set category = "Mapping" +ADMIN_VERB_VISIBILITY(create_mapping_job_icons, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(create_mapping_job_icons, R_DEBUG, "Generate job landmarks icons", "Generates job starting location landmarks.", ADMIN_CATEGORY_MAPPING) var/icon/final = icon() var/mob/living/carbon/human/dummy/D = new(locate(1,1,1)) //spawn on 1,1,1 so we don't have runtimes when items are deleted D.setDir(SOUTH) @@ -317,11 +218,9 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) final.Insert(icon('icons/hud/screen_gen.dmi', "x[x_number == 1 ? "" : x_number]"), "x[x_number == 1 ? "" : x_number]") fcopy(final, "icons/mob/landmarks.dmi") -/client/proc/debug_z_levels() - set name = "Debug Z-Levels" - set category = "Mapping" - - to_chat(src, examine_block(gather_z_level_information(append_grid = TRUE)), confidential = TRUE) +ADMIN_VERB_VISIBILITY(debug_z_levels, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(debug_z_levels, R_DEBUG, "Debug Z-Levels", "Displays a list of all z-levels and their linkages.", ADMIN_CATEGORY_MAPPING) + to_chat(user, examine_block(gather_z_level_information(append_grid = TRUE)), confidential = TRUE) /// Returns all necessary z-level information. Argument `append_grid` allows the user to see a table showing all of the z-level linkages, which is only visible and useful in-game. /proc/gather_z_level_information(append_grid = FALSE) @@ -383,9 +282,8 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) return messages.Join("\n") -/client/proc/station_food_debug() - set name = "Count Station Food" - set category = "Mapping" +ADMIN_VERB_VISIBILITY(station_food_debug, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(station_food_debug, R_DEBUG, "Count Station Food", "Counts the number of food items on the station.", ADMIN_CATEGORY_MAPPING) var/list/foodcount = list() for(var/obj/item/food/fuck_me in world) var/turf/location = get_turf(fuck_me) @@ -402,13 +300,12 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) var/page_style = "" var/page_contents = "[page_style]
    [table_header][jointext(table_contents, "")]
    " - var/datum/browser/popup = new(mob, "fooddebug", "Station Food Count", 600, 400) + var/datum/browser/popup = new(user.mob, "fooddebug", "Station Food Count", 600, 400) popup.set_content(page_contents) popup.open() -/client/proc/station_stack_debug() - set name = "Count Station Stacks" - set category = "Mapping" +ADMIN_VERB_VISIBILITY(station_stack_debug, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(station_stack_debug, R_DEBUG, "Count Station Stacks", "Count the stacks of materials on station.", ADMIN_CATEGORY_MAPPING) var/list/stackcount = list() for(var/obj/item/stack/fuck_me in world) var/turf/location = get_turf(fuck_me) @@ -425,18 +322,13 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) var/page_style = "" var/page_contents = "[page_style][table_header][jointext(table_contents, "")]
    " - var/datum/browser/popup = new(mob, "stackdebug", "Station Stack Count", 600, 400) + var/datum/browser/popup = new(user.mob, "stackdebug", "Station Stack Count", 600, 400) popup.set_content(page_contents) popup.open() -/// Check all tiles with a vent or scrubber on it and ensure that nothing is covering it up. -/client/proc/check_for_obstructed_atmospherics() - set name = "Check For Obstructed Atmospherics" - set category = "Mapping" - if(!holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - message_admins(span_adminnotice("[key_name_admin(usr)] is checking for obstructed atmospherics through the debug command.")) +ADMIN_VERB_VISIBILITY(check_for_obstructed_atmospherics, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(check_for_obstructed_atmospherics, R_DEBUG, "Check For Obstructed Atmospherics", "Checks for obstructions on atmospherics machines.", ADMIN_CATEGORY_MAPPING) + message_admins(span_adminnotice("[key_name_admin(user)] is checking for obstructed atmospherics through the debug command.")) BLACKBOX_LOG_ADMIN_VERB("Check For Obstructed Atmospherics") var/list/results = list() @@ -485,17 +377,14 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) results += "There is an obstruction on top of an atmospherics machine at: [ADMIN_VERBOSEJMP(iterated_turf)].
    " if(results.len == 1) // only the header is in the list, we're good - to_chat(src, "No obstructions detected.", confidential = TRUE) + to_chat(user, "No obstructions detected.", confidential = TRUE) else - var/datum/browser/popup = new(usr, "atmospherics_obstructions", "Atmospherics Obstructions", 900, 750) + var/datum/browser/popup = new(user.mob, "atmospherics_obstructions", "Atmospherics Obstructions", 900, 750) popup.set_content(results.Join()) popup.open() -/client/proc/modify_lights() - set name = "Toggle Light Debug" - set category = "Mapping" - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB_VISIBILITY(modify_lights, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(modify_lights, R_DEBUG, "Toggle Light Debug", "Toggles light debug mode.", ADMIN_CATEGORY_MAPPING) if(GLOB.light_debug_enabled) undebug_sources() return @@ -507,10 +396,6 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) CHECK_TICK debug_sources() -/client/proc/visualize_lights() - set name = "Visualize Lighting Corners" - set category = "Mapping" - if(!check_rights(R_DEBUG)) - return - +ADMIN_VERB_VISIBILITY(visualize_lights, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(visualize_lights, R_DEBUG, "Visualize Lighting Corners", "Visualizes the corners of all lights on the station.", ADMIN_CATEGORY_MAPPING) display_corners() diff --git a/code/modules/admin/verbs/maprotation.dm b/code/modules/admin/verbs/maprotation.dm index c41677db37ccb..09d6d93bee632 100644 --- a/code/modules/admin/verbs/maprotation.dm +++ b/code/modules/admin/verbs/maprotation.dm @@ -1,16 +1,13 @@ -/client/proc/forcerandomrotate() - set category = "Server" - set name = "Trigger Random Map Rotation" - var/rotate = tgui_alert(usr,"Force a random map rotation to trigger?", "Rotate map?", list("Yes", "Cancel")) + +ADMIN_VERB(force_random_rotate, R_SERVER, "Trigger 'Random' Map Rotation", "Force a map vote.", ADMIN_CATEGORY_SERVER) + var/rotate = tgui_alert(user,"Force a random map rotation to trigger?", "Rotate map?", list("Yes", "Cancel")) if (rotate != "Yes") return - message_admins("[key_name_admin(usr)] is forcing a random map rotation.") - log_admin("[key_name(usr)] is forcing a random map rotation.") + message_admins("[key_name_admin(user)] is forcing a random map rotation.") + log_admin("[key_name(user)] is forcing a random map rotation.") SSmapping.maprotate() -/client/proc/adminchangemap() - set category = "Server" - set name = "Change Map" +ADMIN_VERB(admin_change_map, R_SERVER, "Change Map", "Set the next map.", ADMIN_CATEGORY_SERVER) var/list/maprotatechoices = list() for (var/map in config.maplist) var/datum/map_config/virtual_map = config.maplist[map] @@ -32,21 +29,21 @@ mapname += "\]" maprotatechoices[mapname] = virtual_map - var/chosenmap = tgui_input_list(usr, "Choose a map to change to", "Change Map", sort_list(maprotatechoices)|"Custom") + var/chosenmap = tgui_input_list(user, "Choose a map to change to", "Change Map", sort_list(maprotatechoices)|"Custom") if (isnull(chosenmap)) return if(chosenmap == "Custom") - message_admins("[key_name_admin(usr)] is changing the map to a custom map") - log_admin("[key_name(usr)] is changing the map to a custom map") + message_admins("[key_name_admin(user)] is changing the map to a custom map") + log_admin("[key_name(user)] is changing the map to a custom map") var/datum/map_config/virtual_map = new - var/map_file = input("Pick file:", "Map File") as null|file + var/map_file = input(user, "Pick file:", "Map File") as null|file if(isnull(map_file)) return if(copytext("[map_file]", -4) != ".dmm")//4 == length(".dmm") - to_chat(src, span_warning("Filename must end in '.dmm': [map_file]")) + to_chat(user, span_warning("Filename must end in '.dmm': [map_file]")) return if(fexists("_maps/custom/[map_file]")) @@ -56,20 +53,20 @@ // This is to make sure the map works so the server does not start without a map. var/datum/parsed_map/M = new (map_file) if(!M) - to_chat(src, span_warning("Map '[map_file]' failed to parse properly.")) + to_chat(user, span_warning("Map '[map_file]' failed to parse properly.")) return if(!M.bounds) - to_chat(src, span_warning("Map '[map_file]' has non-existant bounds.")) + to_chat(user, span_warning("Map '[map_file]' has non-existant bounds.")) qdel(M) return qdel(M) var/config_file = null var/list/json_value = list() - var/config = tgui_alert(usr,"Would you like to upload an additional config for this map?", "Map Config", list("Yes", "No")) + var/config = tgui_alert(user,"Would you like to upload an additional config for this map?", "Map Config", list("Yes", "No")) if(config == "Yes") - config_file = input("Pick file:", "Config JSON File") as null|file + config_file = input(user, "Pick file:", "Config JSON File") as null|file if(isnull(config_file)) return if(copytext("[config_file]", -5) != ".json") @@ -94,18 +91,18 @@ ) else virtual_map = load_map_config() - virtual_map.map_name = input("Choose the name for the map", "Map Name") as null|text + virtual_map.map_name = input(user, "Choose the name for the map", "Map Name") as null|text if(isnull(virtual_map.map_name)) virtual_map.map_name = "Custom" - var/shuttles = tgui_alert(usr,"Do you want to modify the shuttles?", "Map Shuttles", list("Yes", "No")) + var/shuttles = tgui_alert(user,"Do you want to modify the shuttles?", "Map Shuttles", list("Yes", "No")) if(shuttles == "Yes") for(var/s in virtual_map.shuttles) - var/shuttle = input(s, "Map Shuttles") as null|text + var/shuttle = input(user, s, "Map Shuttles") as null|text if(!shuttle) continue if(!SSmapping.shuttle_templates[shuttle]) - to_chat(usr, span_warning("No such shuttle as '[shuttle]' exists, using default.")) + to_chat(user, span_warning("No such shuttle as '[shuttle]' exists, using default.")) continue virtual_map.shuttles[s] = shuttle @@ -123,13 +120,13 @@ text2file(json_encode(json_value), PATH_TO_NEXT_MAP_JSON) if(SSmapping.changemap(virtual_map)) - message_admins("[key_name_admin(usr)] has changed the map to [virtual_map.map_name]") + message_admins("[key_name_admin(user)] has changed the map to [virtual_map.map_name]") SSmapping.map_force_chosen = TRUE fdel("data/custom_map_json/[config_file]") else var/datum/map_config/virtual_map = maprotatechoices[chosenmap] - message_admins("[key_name_admin(usr)] is changing the map to [virtual_map.map_name]") - log_admin("[key_name(usr)] is changing the map to [virtual_map.map_name]") + message_admins("[key_name_admin(user)] is changing the map to [virtual_map.map_name]") + log_admin("[key_name(user)] is changing the map to [virtual_map.map_name]") if (SSmapping.changemap(virtual_map)) - message_admins("[key_name_admin(usr)] has changed the map to [virtual_map.map_name]") + message_admins("[key_name_admin(user)] has changed the map to [virtual_map.map_name]") SSmapping.map_force_chosen = TRUE diff --git a/code/modules/admin/verbs/panicbunker.dm b/code/modules/admin/verbs/panicbunker.dm index c8c478586699d..57aba1ee8d96b 100644 --- a/code/modules/admin/verbs/panicbunker.dm +++ b/code/modules/admin/verbs/panicbunker.dm @@ -1,8 +1,6 @@ -/client/proc/panicbunker() - set category = "Server" - set name = "Toggle Panic Bunker" +ADMIN_VERB(panic_bunker, R_SERVER, "Toggle Panic Bunker", "Toggles the panic bunker for the server.", ADMIN_CATEGORY_SERVER) if (!CONFIG_GET(flag/sql_enabled)) - to_chat(usr, span_adminnotice("The Database is not enabled!"), confidential = TRUE) + to_chat(user, span_adminnotice("The Database is not enabled!"), confidential = TRUE) return var/new_pb = !CONFIG_GET(flag/panic_bunker) @@ -10,28 +8,26 @@ var/time_rec = 0 var/message = "" if(new_pb) - time_rec = input(src, "How many living minutes should they need to play? 0 to disable.", "Shit's fucked isn't it", CONFIG_GET(number/panic_bunker_living)) as num - message = input(src, "What should they see when they log in?", "MMM", CONFIG_GET(string/panic_bunker_message)) as text + time_rec = input(user, "How many living minutes should they need to play? 0 to disable.", "Shit's fucked isn't it", CONFIG_GET(number/panic_bunker_living)) as num + message = input(user, "What should they see when they log in?", "MMM", CONFIG_GET(string/panic_bunker_message)) as text message = replacetext(message, "%minutes%", time_rec) CONFIG_SET(number/panic_bunker_living, time_rec) CONFIG_SET(string/panic_bunker_message, message) - var/interview_sys = tgui_alert(usr, "Should the interview system be enabled? (Allows players to connect under the hour limit and force them to be manually approved to play)", "Enable interviews?", list("Enable", "Disable")) + var/interview_sys = tgui_alert(user, "Should the interview system be enabled? (Allows players to connect under the hour limit and force them to be manually approved to play)", "Enable interviews?", list("Enable", "Disable")) interview = interview_sys == "Enable" CONFIG_SET(flag/panic_bunker_interview, interview) CONFIG_SET(flag/panic_bunker, new_pb) - log_admin("[key_name(usr)] has toggled the Panic Bunker, it is now [new_pb ? "on and set to [time_rec] with a message of [message]. The interview system is [interview ? "enabled" : "disabled"]" : "off"].") - message_admins("[key_name_admin(usr)] has toggled the Panic Bunker, it is now [new_pb ? "enabled with a living minutes requirement of [time_rec]. The interview system is [interview ? "enabled" : "disabled"]" : "disabled"].") + log_admin("[key_name(user)] has toggled the Panic Bunker, it is now [new_pb ? "on and set to [time_rec] with a message of [message]. The interview system is [interview ? "enabled" : "disabled"]" : "off"].") + message_admins("[key_name_admin(user)] has toggled the Panic Bunker, it is now [new_pb ? "enabled with a living minutes requirement of [time_rec]. The interview system is [interview ? "enabled" : "disabled"]" : "disabled"].") if (new_pb && !SSdbcore.Connect()) message_admins("The Database is not connected! Panic bunker will not work until the connection is reestablished.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Panic Bunker", "[new_pb ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/client/proc/toggle_interviews() - set category = "Server" - set name = "Toggle PB Interviews" +ADMIN_VERB(toggle_interviews, R_SERVER, "Toggle PB Interviews", "Toggle whether new players will be interviewed or blocked from connecting.", ADMIN_CATEGORY_SERVER) if (!CONFIG_GET(flag/panic_bunker)) - to_chat(usr, span_adminnotice("NOTE: The panic bunker is not enabled, so this change will not effect anything until it is enabled."), confidential = TRUE) + to_chat(user, span_adminnotice("NOTE: The panic bunker is not enabled, so this change will not effect anything until it is enabled."), confidential = TRUE) var/new_interview = !CONFIG_GET(flag/panic_bunker_interview) CONFIG_SET(flag/panic_bunker_interview, new_interview) - log_admin("[key_name(usr)] has toggled the Panic Bunker's interview system, it is now [new_interview ? "enabled" : "disabled"].") - message_admins("[key_name(usr)] has toggled the Panic Bunker's interview system, it is now [new_interview ? "enabled" : "disabled"].") + log_admin("[key_name(user)] has toggled the Panic Bunker's interview system, it is now [new_interview ? "enabled" : "disabled"].") + message_admins("[key_name(user)] has toggled the Panic Bunker's interview system, it is now [new_interview ? "enabled" : "disabled"].") diff --git a/code/modules/admin/verbs/player_ticket_history.dm b/code/modules/admin/verbs/player_ticket_history.dm index ac87707e98d38..829d4dfc2b57e 100644 --- a/code/modules/admin/verbs/player_ticket_history.dm +++ b/code/modules/admin/verbs/player_ticket_history.dm @@ -19,13 +19,8 @@ GENERAL_PROTECT_DATUM(/datum/ticket_log_entry) GLOBAL_DATUM_INIT(player_ticket_history, /datum/ticket_history_holder, new) GLOBAL_PROTECT(player_ticket_history) -/client/proc/player_ticket_history() - set name = "Player Ticket History" - set desc = "Allows you to view the ticket history of a player." - set category = "Admin" - if(!check_rights(R_ADMIN)) - return - GLOB.player_ticket_history.ui_interact(mob) +ADMIN_VERB(player_ticket_history, R_ADMIN, "Player Ticket History", "Allows you to view the ticket history of a player.", ADMIN_CATEGORY_MAIN) + GLOB.player_ticket_history.ui_interact(user.mob) /datum/ticket_history_holder /// Assosciative list of ticket histories. ckey -> list/datum/ticket_history @@ -34,7 +29,7 @@ GLOBAL_PROTECT(player_ticket_history) var/list/user_selections = list() /datum/ticket_history_holder/proc/cache_history_for_ckey(ckey, entries = 5) - ckey = lowertext(ckey) + ckey = LOWER_TEXT(ckey) if(!isnum(entries) || entries <= 0) return diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index 1b63c83529b8a..c4e4257e84fc7 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -3,20 +3,15 @@ #define SHELLEO_STDOUT 2 #define SHELLEO_STDERR 3 -/client/proc/play_sound(S as sound) - set category = "Admin.Fun" - set name = "Play Global Sound" - if(!check_rights(R_SOUND)) - return - +ADMIN_VERB(play_sound, R_SOUND, "Play Global Sound", "Play a sound to all connected players.", ADMIN_CATEGORY_FUN, sound as sound) var/freq = 1 - var/vol = input(usr, "What volume would you like the sound to play at?",, 100) as null|num + var/vol = tgui_input_number(user, "What volume would you like the sound to play at?", max_value = 100) if(!vol) return vol = clamp(vol, 1, 100) - var/sound/admin_sound = new() - admin_sound.file = S + var/sound/admin_sound = new + admin_sound.file = sound admin_sound.priority = 250 admin_sound.channel = CHANNEL_ADMIN admin_sound.frequency = freq @@ -25,15 +20,15 @@ admin_sound.status = SOUND_STREAM admin_sound.volume = vol - var/res = tgui_alert(usr, "Show the title of this song to the players?",, list("Yes","No", "Cancel")) + var/res = tgui_alert(user, "Show the title of this song to the players?",, list("Yes","No", "Cancel")) switch(res) if("Yes") - to_chat(world, span_boldannounce("An admin played: [S]"), confidential = TRUE) + to_chat(world, span_boldannounce("An admin played: [sound]"), confidential = TRUE) if("Cancel") return - log_admin("[key_name(src)] played sound [S]") - message_admins("[key_name_admin(src)] played sound [S]") + log_admin("[key_name(user)] played sound [sound]") + message_admins("[key_name_admin(user)] played sound [sound]") for(var/mob/M in GLOB.player_list) if(M.client.prefs.read_preference(/datum/preference/toggle/sound_midi)) @@ -43,31 +38,20 @@ BLACKBOX_LOG_ADMIN_VERB("Play Global Sound") - -/client/proc/play_local_sound(S as sound) - set category = "Admin.Fun" - set name = "Play Local Sound" - if(!check_rights(R_SOUND)) - return - - log_admin("[key_name(src)] played a local sound [S]") - message_admins("[key_name_admin(src)] played a local sound [S]") - playsound(get_turf(src.mob), S, 50, FALSE, FALSE) +ADMIN_VERB(play_local_sound, R_SOUND, "Play Local Sound", "Plays a sound only you can hear.", ADMIN_CATEGORY_FUN, sound as sound) + log_admin("[key_name(user)] played a local sound [sound]") + message_admins("[key_name_admin(user)] played a local sound [sound]") + playsound(get_turf(user.mob), sound, 50, FALSE, FALSE) BLACKBOX_LOG_ADMIN_VERB("Play Local Sound") -/client/proc/play_direct_mob_sound(S as sound, mob/M) - set category = "Admin.Fun" - set name = "Play Direct Mob Sound" - if(!check_rights(R_SOUND)) - return - - if(!M) - M = input(usr, "Choose a mob to play the sound to. Only they will hear it.", "Play Mob Sound") as null|anything in sort_names(GLOB.player_list) - if(!M || QDELETED(M)) +ADMIN_VERB(play_direct_mob_sound, R_SOUND, "Play Direct Mob Sound", "Play a sound directly to a mob.", ADMIN_CATEGORY_FUN, sound as sound, mob/target in world) + if(!target) + target = input(user, "Choose a mob to play the sound to. Only they will hear it.", "Play Mob Sound") as null|anything in sort_names(GLOB.player_list) + if(QDELETED(target)) return - log_admin("[key_name(src)] played a direct mob sound [S] to [M].") - message_admins("[key_name_admin(src)] played a direct mob sound [S] to [ADMIN_LOOKUPFLW(M)].") - SEND_SOUND(M, S) + log_admin("[key_name(user)] played a direct mob sound [sound] to [key_name_admin(target)].") + message_admins("[key_name_admin(user)] played a direct mob sound [sound] to [ADMIN_LOOKUPFLW(target)].") + SEND_SOUND(target, sound) BLACKBOX_LOG_ADMIN_VERB("Play Direct Mob Sound") ///Takes an input from either proc/play_web_sound or the request manager and runs it through youtube-dl and prompts the user before playing it to the server. @@ -169,59 +153,41 @@ BLACKBOX_LOG_ADMIN_VERB("Play Internet Sound") +ADMIN_VERB_CUSTOM_EXIST_CHECK(play_web_sound) + return !!CONFIG_GET(string/invoke_youtubedl) -/client/proc/play_web_sound() - set category = "Admin.Fun" - set name = "Play Internet Sound" - if(!check_rights(R_SOUND)) - return - - var/ytdl = CONFIG_GET(string/invoke_youtubedl) - if(!ytdl) - to_chat(src, span_boldwarning("Youtube-dl was not configured, action unavailable"), confidential = TRUE) //Check config.txt for the INVOKE_YOUTUBEDL value - return - +ADMIN_VERB(play_web_sound, R_SOUND, "Play Internet Sound", "Play a given internet sound to all players.", ADMIN_CATEGORY_FUN) if(S_TIMER_COOLDOWN_TIMELEFT(SStimer, COOLDOWN_INTERNET_SOUND)) - if(tgui_alert(usr, "Someone else is already playing an Internet sound! It has [DisplayTimeText(S_TIMER_COOLDOWN_TIMELEFT(SStimer, COOLDOWN_INTERNET_SOUND), 1)] remaining. \ + if(tgui_alert(user, "Someone else is already playing an Internet sound! It has [DisplayTimeText(S_TIMER_COOLDOWN_TIMELEFT(SStimer, COOLDOWN_INTERNET_SOUND), 1)] remaining. \ Would you like to override?", "Musicalis Interruptus", list("No","Yes")) != "Yes") return - var/web_sound_input = tgui_input_text(usr, "Enter content URL (supported sites only, leave blank to stop playing)", "Play Internet Sound", null) + var/web_sound_input = tgui_input_text(user, "Enter content URL (supported sites only, leave blank to stop playing)", "Play Internet Sound", null) if(length(web_sound_input)) web_sound_input = trim(web_sound_input) if(findtext(web_sound_input, ":") && !findtext(web_sound_input, GLOB.is_http_protocol)) - to_chat(src, span_boldwarning("Non-http(s) URIs are not allowed."), confidential = TRUE) - to_chat(src, span_warning("For youtube-dl shortcuts like ytsearch: please use the appropriate full URL from the website."), confidential = TRUE) + to_chat(user, span_boldwarning("Non-http(s) URIs are not allowed."), confidential = TRUE) + to_chat(user, span_warning("For youtube-dl shortcuts like ytsearch: please use the appropriate full URL from the website."), confidential = TRUE) return - web_sound(usr, web_sound_input) + web_sound(user.mob, web_sound_input) else - web_sound(usr, null) + web_sound(user.mob, null) -/client/proc/set_round_end_sound(S as sound) - set category = "Admin.Fun" - set name = "Set Round End Sound" - if(!check_rights(R_SOUND)) - return - - SSticker.SetRoundEndSound(S) +ADMIN_VERB(set_round_end_sound, R_SOUND, "Set Round End Sound", "Set the sound that plays on round end.", ADMIN_CATEGORY_FUN, sound as sound) + SSticker.SetRoundEndSound(sound) - log_admin("[key_name(src)] set the round end sound to [S]") - message_admins("[key_name_admin(src)] set the round end sound to [S]") + log_admin("[key_name(user)] set the round end sound to [sound]") + message_admins("[key_name_admin(user)] set the round end sound to [sound]") BLACKBOX_LOG_ADMIN_VERB("Set Round End Sound") -/client/proc/stop_sounds() - set category = "Debug" - set name = "Stop All Playing Sounds" - if(!src.holder) - return - - log_admin("[key_name(src)] stopped all currently playing sounds.") - message_admins("[key_name_admin(src)] stopped all currently playing sounds.") - for(var/mob/M in GLOB.player_list) - SEND_SOUND(M, sound(null)) - var/client/C = M.client - C?.tgui_panel?.stop_music() +ADMIN_VERB(stop_sounds, R_NONE, "Stop All Playing Sounds", "Stops all playing sounds for EVERYONE.", ADMIN_CATEGORY_DEBUG) + log_admin("[key_name(user)] stopped all currently playing sounds.") + message_admins("[key_name_admin(user)] stopped all currently playing sounds.") + for(var/mob/player as anything in GLOB.player_list) + SEND_SOUND(player, sound(null)) + var/client/player_client = player.client + player_client?.tgui_panel?.stop_music() S_TIMER_COOLDOWN_RESET(SStimer, COOLDOWN_INTERNET_SOUND) BLACKBOX_LOG_ADMIN_VERB("Stop All Playing Sounds") diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm index 63304104ab536..2949447b2ef02 100644 --- a/code/modules/admin/verbs/possess.dm +++ b/code/modules/admin/verbs/possess.dm @@ -1,32 +1,20 @@ -/proc/possess(obj/target in world) - set name = "Possess Obj" - set category = "Object" - var/result = usr.AddComponent(/datum/component/object_possession, target) +ADMIN_VERB_AND_CONTEXT_MENU(possess, R_POSSESS, "Possess Obj", "Possess an object.", ADMIN_CATEGORY_OBJECT, obj/target in world) + var/result = user.mob.AddComponent(/datum/component/object_possession, target) if(isnull(result)) // trigger a safety movement just in case we yonk - usr.forceMove(get_turf(usr)) + user.mob.forceMove(get_turf(user.mob)) return var/turf/target_turf = get_turf(target) - var/message = "[key_name(usr)] has possessed [target] ([target.type]) at [AREACOORD(target_turf)]" + var/message = "[key_name(user)] has possessed [target] ([target.type]) at [AREACOORD(target_turf)]" message_admins(message) log_admin(message) BLACKBOX_LOG_ADMIN_VERB("Possess Object") -/proc/release() - set name = "Release Obj" - set category = "Object" - - qdel(usr.GetComponent(/datum/component/object_possession)) +ADMIN_VERB(release, R_POSSESS, "Release Object", "Stop possessing an object.", ADMIN_CATEGORY_OBJECT) + var/possess_component = user.mob.GetComponent(/datum/component/object_possession) + if(!isnull(possess_component)) + qdel(possess_component) BLACKBOX_LOG_ADMIN_VERB("Release Object") - -/proc/give_possession_verbs(mob/dude in GLOB.mob_list) - set desc = "Give this guy possess/release verbs" - set category = "Debug" - set name = "Give Possessing Verbs" - - add_verb(dude, GLOBAL_PROC_REF(possess)) - add_verb(dude, GLOBAL_PROC_REF(release)) - BLACKBOX_LOG_ADMIN_VERB("Give Possessing Verbs") diff --git a/code/modules/admin/verbs/reestablish_db_connection.dm b/code/modules/admin/verbs/reestablish_db_connection.dm index a299eb43b0f68..5c3701c97b0cc 100644 --- a/code/modules/admin/verbs/reestablish_db_connection.dm +++ b/code/modules/admin/verbs/reestablish_db_connection.dm @@ -1,26 +1,24 @@ -/client/proc/reestablish_db_connection() - set category = "Server" - set name = "Reestablish DB Connection" +ADMIN_VERB(reestablish_db_connection, R_NONE, "Reestablish DB Connection", "Attempts to (re)establish the DB Connection", ADMIN_CATEGORY_SERVER) if (!CONFIG_GET(flag/sql_enabled)) - to_chat(usr, span_adminnotice("The Database is not enabled!"), confidential = TRUE) + to_chat(user, span_adminnotice("The Database is not enabled!"), confidential = TRUE) return if (SSdbcore.IsConnected()) - if (!check_rights(R_DEBUG,0)) - tgui_alert(usr,"The database is already connected! (Only those with +debug can force a reconnection)", "The database is already connected!") + if (!user.holder.check_for_rights(R_DEBUG)) + tgui_alert(user,"The database is already connected! (Only those with +debug can force a reconnection)", "The database is already connected!") return - var/reconnect = tgui_alert(usr,"The database is already connected! If you *KNOW* that this is incorrect, you can force a reconnection", "The database is already connected!", list("Force Reconnect", "Cancel")) + var/reconnect = tgui_alert(user,"The database is already connected! If you *KNOW* that this is incorrect, you can force a reconnection", "The database is already connected!", list("Force Reconnect", "Cancel")) if (reconnect != "Force Reconnect") return SSdbcore.Disconnect() - log_admin("[key_name(usr)] has forced the database to disconnect") - message_admins("[key_name_admin(usr)] has forced the database to disconnect!") + log_admin("[key_name(user)] has forced the database to disconnect") + message_admins("[key_name_admin(user)] has forced the database to disconnect!") BLACKBOX_LOG_ADMIN_VERB("Force Reestablished Database Connection") - log_admin("[key_name(usr)] is attempting to re-establish the DB Connection") - message_admins("[key_name_admin(usr)] is attempting to re-establish the DB Connection") + log_admin("[key_name(user)] is attempting to re-establish the DB Connection") + message_admins("[key_name_admin(user)] is attempting to re-establish the DB Connection") BLACKBOX_LOG_ADMIN_VERB("Reestablished Database Connection") SSdbcore.failed_connections = 0 diff --git a/code/modules/admin/verbs/requests.dm b/code/modules/admin/verbs/requests.dm index 2cd32648b67bf..53d3e092f8124 100644 --- a/code/modules/admin/verbs/requests.dm +++ b/code/modules/admin/verbs/requests.dm @@ -1,7 +1,4 @@ -/// Verb for opening the requests manager panel -/client/proc/requests() - set name = "Requests Manager" - set desc = "Open the request manager panel to view all requests during this round" - set category = "Admin.Game" - BLACKBOX_LOG_ADMIN_VERB("Request Manager") + +ADMIN_VERB(requests, R_NONE, "Requests Manager", "Open the request manager panel to view all requests during this round", ADMIN_CATEGORY_GAME) GLOB.requests.ui_interact(usr) + BLACKBOX_LOG_ADMIN_VERB("Request Manager") diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm index e70138ad8ac25..379b9475dc50b 100644 --- a/code/modules/admin/verbs/secrets.dm +++ b/code/modules/admin/verbs/secrets.dm @@ -1,12 +1,9 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller) -/client/proc/secrets() //Creates a verb for admins to open up the ui - set name = "Secrets" - set desc = "Abuse harder than you ever have before with this handy dandy semi-misc stuff menu" - set category = "Admin.Game" +ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before with this handy dandy semi-misc stuff menu.", ADMIN_CATEGORY_GAME) + var/datum/secrets_menu/tgui = new(user) + tgui.ui_interact(user.mob) BLACKBOX_LOG_ADMIN_VERB("Secrets Panel") - var/datum/secrets_menu/tgui = new(usr)//create the datum - tgui.ui_interact(usr)//datum has a tgui component, here we open the window /datum/secrets_menu var/client/holder //client of whoever is using this datum @@ -102,25 +99,25 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller) D.cure(0) if("list_bombers") - holder.list_bombers() + holder.holder.list_bombers() if("list_signalers") - holder.list_signalers() + holder.holder.list_signalers() if("list_lawchanges") - holder.list_law_changes() + holder.holder.list_law_changes() if("showailaws") - holder.check_ai_laws() + holder.holder.list_law_changes() if("manifest") - holder.show_manifest() + holder.holder.show_manifest() if("dna") - holder.list_dna() + holder.holder.list_dna() if("fingerprints") - holder.list_fingerprints() + holder.holder.list_fingerprints() if("ctfbutton") toggle_id_ctf(holder, CTF_GHOST_CTF_GAME_ID) @@ -225,7 +222,7 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller) if("allspecies") if(!is_funmin) return - var/result = input(holder, "Please choose a new species","Species") as null|anything in GLOB.species_list + var/result = input(holder, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc)) if(result) SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Species Change", "[result]")) log_admin("[key_name(holder)] turned all humans into [result]") @@ -620,7 +617,7 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller) E.announce_chance = 0 E.processing = TRUE if(holder) - log_admin("[key_name(holder)] used secret [action]") + log_admin("[key_name(holder)] used secret: [action].") #undef THUNDERDOME_TEMPLATE_FILE #undef HIGHLANDER_DELAY_TEXT @@ -727,4 +724,3 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller) var/datum/antagonist/malf_ai/antag_datum = new antag_datum.give_objectives = keep_generic_objecives assign_admin_objective_and_antag(player, antag_datum) - diff --git a/code/modules/admin/verbs/selectequipment.dm b/code/modules/admin/verbs/selectequipment.dm index 59513db012976..b94fd5cb2e455 100644 --- a/code/modules/admin/verbs/selectequipment.dm +++ b/code/modules/admin/verbs/selectequipment.dm @@ -1,10 +1,6 @@ -/client/proc/cmd_select_equipment(mob/target in GLOB.mob_list) - set category = "Admin.Events" - set name = "Select equipment" - - - var/datum/select_equipment/ui = new(usr, target) - ui.ui_interact(usr) +ADMIN_VERB_ONLY_CONTEXT_MENU(select_equipment, R_FUN, "Select Equipment", mob/target in world) + var/datum/select_equipment/ui = new(user, target) + ui.ui_interact(user.mob) /* * This is the datum housing the select equipment UI. @@ -152,7 +148,7 @@ return custom_outfit -/datum/select_equipment/ui_act(action, params) +/datum/select_equipment/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) if(..()) return . = TRUE @@ -181,7 +177,7 @@ user.admin_apply_outfit(target_mob, new_outfit) if("customoutfit") - user.outfit_manager() + return SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/outfit_manager) if("togglefavorite") var/datum/outfit/outfit_path = resolve_outfit(params["path"]) diff --git a/code/modules/admin/verbs/server.dm b/code/modules/admin/verbs/server.dm index d049372e6a9a3..eb5684252f8c9 100644 --- a/code/modules/admin/verbs/server.dm +++ b/code/modules/admin/verbs/server.dm @@ -1,191 +1,147 @@ // Server Tab - Server Verbs -/client/proc/toggle_random_events() - set category = "Server" - set name = "Toggle random events on/off" - set desc = "Toggles random events such as meteors, black holes, blob (but not space dust) on/off" +ADMIN_VERB(toggle_random_events, R_SERVER, "Toggle Random Events", "Toggles random events on or off.", ADMIN_CATEGORY_SERVER) var/new_are = !CONFIG_GET(flag/allow_random_events) CONFIG_SET(flag/allow_random_events, new_are) - message_admins("[key_name_admin(usr)] has [new_are ? "enabled" : "disabled"] random events.") + message_admins("[key_name_admin(user)] has [new_are ? "enabled" : "disabled"] random events.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Random Events", "[new_are ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/client/proc/toggle_hub() - set category = "Server" - set name = "Toggle Hub" - +ADMIN_VERB(toggle_hub, R_SERVER, "Toggle Hub", "Toggles the server's visilibility on the BYOND Hub.", ADMIN_CATEGORY_SERVER) world.update_hub_visibility(!GLOB.hub_visibility) - log_admin("[key_name(usr)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") - message_admins("[key_name_admin(usr)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") + log_admin("[key_name(user)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") + message_admins("[key_name_admin(user)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") if (GLOB.hub_visibility && !world.reachable) message_admins("WARNING: The server will not show up on the hub because byond is detecting that a filewall is blocking incoming connections.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggled Hub Visibility", "[GLOB.hub_visibility ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/restart() - set category = "Server" - set name = "Reboot World" - set desc = "Restarts the world immediately" - if (!usr.client.holder) - return - - var/localhost_addresses = list("127.0.0.1", "::1") +ADMIN_VERB(restart, R_SERVER, "Reboot World", "Restarts the world immediately.", ADMIN_CATEGORY_SERVER) var/list/options = list("Regular Restart", "Regular Restart (with delay)", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)") if(world.TgsAvailable()) options += "Server Restart (Kill and restart DD)"; if(SSticker.admin_delay_notice) - if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") != "Yes") + if(alert(user, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") != "Yes") return FALSE - var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options - if(result) - BLACKBOX_LOG_ADMIN_VERB("Reboot World") - var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]." - switch(result) - if("Regular Restart") - if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) - if(alert(usr, "Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart") - return FALSE - SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10) - if("Regular Restart (with delay)") - var/delay = input("What delay should the restart have (in seconds)?", "Restart Delay", 5) as num|null - if(!delay) - return FALSE - if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) - if(alert(usr,"Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart") - return FALSE - SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", delay * 10) - if("Hard Restart (No Delay, No Feeback Reason)") - to_chat(world, "World reboot - [init_by]") - world.Reboot() - if("Hardest Restart (No actions, just reboot)") - to_chat(world, "Hard world reboot - [init_by]") - world.Reboot(fast_track = TRUE) - if("Server Restart (Kill and restart DD)") - to_chat(world, "Server restart - [init_by]") - world.TgsEndProcess() - -/datum/admins/proc/end_round() - set category = "Server" - set name = "End Round" - set desc = "Attempts to produce a round end report and then restart the server organically." - - if (!usr.client.holder) + var/result = input(user, "Select reboot method", "World Reboot", options[1]) as null|anything in options + if(isnull(result)) return - var/confirm = tgui_alert(usr, "End the round and restart the game world?", "End Round", list("Yes", "Cancel")) - if(confirm == "Cancel") + + BLACKBOX_LOG_ADMIN_VERB("Reboot World") + var/init_by = "Initiated by [user.holder.fakekey ? "Admin" : user.key]." + switch(result) + if("Regular Restart") + if(!user.is_localhost()) + if(alert(user, "Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart") + return FALSE + SSticker.Reboot(init_by, "admin reboot - by [user.key] [user.holder.fakekey ? "(stealth)" : ""]", 10) + if("Regular Restart (with delay)") + var/delay = input("What delay should the restart have (in seconds)?", "Restart Delay", 5) as num|null + if(!delay) + return FALSE + if(!user.is_localhost()) + if(alert(user,"Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart") + return FALSE + SSticker.Reboot(init_by, "admin reboot - by [user.key] [user.holder.fakekey ? "(stealth)" : ""]", delay * 10) + if("Hard Restart (No Delay, No Feeback Reason)") + to_chat(world, "World reboot - [init_by]") + world.Reboot() + if("Hardest Restart (No actions, just reboot)") + to_chat(world, "Hard world reboot - [init_by]") + world.Reboot(fast_track = TRUE) + if("Server Restart (Kill and restart DD)") + to_chat(world, "Server restart - [init_by]") + world.TgsEndProcess() + +ADMIN_VERB(end_round, R_SERVER, "End Round", "Forcibly ends the round and allows the server to restart normally.", ADMIN_CATEGORY_SERVER) + var/confirm = tgui_alert(user, "End the round and restart the game world?", "End Round", list("Yes", "Cancel")) + if(confirm != "Yes") return - if(confirm == "Yes") - SSticker.force_ending = FORCE_END_ROUND - BLACKBOX_LOG_ADMIN_VERB("End Round") - -/datum/admins/proc/toggleooc() - set category = "Server" - set desc = "Toggle dis bitch" - set name = "Toggle OOC" + SSticker.force_ending = FORCE_END_ROUND + BLACKBOX_LOG_ADMIN_VERB("End Round") + +ADMIN_VERB(toggle_ooc, R_ADMIN, "Toggle OOC", "Toggle the OOC channel on or off.", ADMIN_CATEGORY_SERVER) toggle_ooc() - log_admin("[key_name(usr)] toggled OOC.") - message_admins("[key_name_admin(usr)] toggled OOC.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! - -/datum/admins/proc/toggleoocdead() - set category = "Server" - set desc = "Toggle dis bitch" - set name = "Toggle Dead OOC" + log_admin("[key_name(user)] toggled OOC.") + message_admins("[key_name_admin(user)] toggled OOC.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) + +ADMIN_VERB(toggle_ooc_dead, R_ADMIN, "Toggle Dead OOC", "Toggle the OOC channel for dead players on or off.", ADMIN_CATEGORY_SERVER) toggle_dooc() + log_admin("[key_name(user)] toggled OOC.") + message_admins("[key_name_admin(user)] toggled Dead OOC.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dead OOC", "[GLOB.dooc_allowed ? "Enabled" : "Disabled"]")) + +ADMIN_VERB(start_now, R_SERVER, "Start Now", "Start the round RIGHT NOW.", ADMIN_CATEGORY_SERVER) + var/static/list/waiting_states = list(GAME_STATE_PREGAME, GAME_STATE_STARTUP) + if(!(SSticker.current_state in waiting_states)) + to_chat(user, span_warning(span_red("The game has already started!"))) + return - log_admin("[key_name(usr)] toggled OOC.") - message_admins("[key_name_admin(usr)] toggled Dead OOC.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dead OOC", "[GLOB.dooc_allowed ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! - -/datum/admins/proc/startnow() - set category = "Server" - set desc = "Start the round RIGHT NOW" - set name = "Start Now" - if(SSticker.current_state == GAME_STATE_PREGAME || SSticker.current_state == GAME_STATE_STARTUP) - if(!SSticker.start_immediately) - var/localhost_addresses = list("127.0.0.1", "::1") - if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) - if(tgui_alert(usr, "Are you sure you want to start the round?","Start Now",list("Start Now","Cancel")) != "Start Now") - return FALSE - SSticker.start_immediately = TRUE - log_admin("[usr.key] has started the game.") - var/msg = "" - if(SSticker.current_state == GAME_STATE_STARTUP) - msg = " (The server is still setting up, but the round will be \ - started as soon as possible.)" - message_admins("[usr.key] has started the game.[msg]") - BLACKBOX_LOG_ADMIN_VERB("Start Now") - return TRUE + if(SSticker.start_immediately) SSticker.start_immediately = FALSE - SSticker.SetTimeLeft(1800) - to_chat(world, "The game will start in 180 seconds.") + SSticker.SetTimeLeft(3 MINUTES) + to_chat(world, span_big(span_notice("The game will start in 3 minutes."))) SEND_SOUND(world, sound('sound/ai/default/attention.ogg')) - message_admins("[usr.key] has cancelled immediate game start. Game will start in 180 seconds.") - log_admin("[usr.key] has cancelled immediate game start.") - else - to_chat(usr, "Error: Start Now: Game has already started.") - return FALSE + message_admins(span_adminnotice("[key_name_admin(user)] has cancelled immediate game start. Game will start in 3 minutes.")) + log_admin("[key_name(user)] has cancelled immediate game start.") + return -/datum/admins/proc/delay_round_end() - set category = "Server" - set desc = "Prevent the server from restarting" - set name = "Delay Round End" + if(!user.is_localhost()) + var/response = tgui_alert(user, "Are you sure you want to start the round?", "Start Now", list("Start Now", "Cancel")) + if(response != "Start Now") + return + SSticker.start_immediately = TRUE - if(!check_rights(R_SERVER)) - return + log_admin("[key_name(user)] has started the game.") + message_admins("[key_name_admin(user)] has started the game.") + if(SSticker.current_state == GAME_STATE_STARTUP) + message_admins("The server is still setting up, but the round will be started as soon as possible.") + BLACKBOX_LOG_ADMIN_VERB("Start Now") +ADMIN_VERB(delay_round_end, R_SERVER, "Delay Round End", "Prevent the server from restarting.", ADMIN_CATEGORY_SERVER) if(SSticker.delay_end) - tgui_alert(usr, "The round end is already delayed. The reason for the current delay is: \"[SSticker.admin_delay_notice]\"", "Alert", list("Ok")) + tgui_alert(user, "The round end is already delayed. The reason for the current delay is: \"[SSticker.admin_delay_notice]\"", "Alert", list("Ok")) return - var/delay_reason = input(usr, "Enter a reason for delaying the round end", "Round Delay Reason") as null|text + var/delay_reason = input(user, "Enter a reason for delaying the round end", "Round Delay Reason") as null|text if(isnull(delay_reason)) return if(SSticker.delay_end) - tgui_alert(usr, "The round end is already delayed. The reason for the current delay is: \"[SSticker.admin_delay_notice]\"", "Alert", list("Ok")) + tgui_alert(user, "The round end is already delayed. The reason for the current delay is: \"[SSticker.admin_delay_notice]\"", "Alert", list("Ok")) return SSticker.delay_end = TRUE SSticker.admin_delay_notice = delay_reason - log_admin("[key_name(usr)] delayed the round end for reason: [SSticker.admin_delay_notice]") - message_admins("[key_name_admin(usr)] delayed the round end for reason: [SSticker.admin_delay_notice]") + log_admin("[key_name(user)] delayed the round end for reason: [SSticker.admin_delay_notice]") + message_admins("[key_name_admin(user)] delayed the round end for reason: [SSticker.admin_delay_notice]") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Delay Round End", "Reason: [delay_reason]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/toggleenter() - set category = "Server" - set desc = "People can't enter" - set name = "Toggle Entering" +ADMIN_VERB(toggle_enter, R_SERVER, "Toggle Entering", "Toggle the ability to enter the game.", ADMIN_CATEGORY_SERVER) if(!SSlag_switch.initialized) return SSlag_switch.set_measure(DISABLE_NON_OBSJOBS, !SSlag_switch.measures[DISABLE_NON_OBSJOBS]) - log_admin("[key_name(usr)] toggled new player game entering. Lag Switch at index ([DISABLE_NON_OBSJOBS])") - message_admins("[key_name_admin(usr)] toggled new player game entering [SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "OFF" : "ON"].") + log_admin("[key_name(user)] toggled new player game entering. Lag Switch at index ([DISABLE_NON_OBSJOBS])") + message_admins("[key_name_admin(user)] toggled new player game entering [SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "OFF" : "ON"].") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Entering", "[!SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/toggleAI() - set category = "Server" - set desc = "People can't be AI" - set name = "Toggle AI" +ADMIN_VERB(toggle_ai, R_SERVER, "Toggle AI", "Toggle the ability to choose AI jobs.", ADMIN_CATEGORY_SERVER) var/alai = CONFIG_GET(flag/allow_ai) CONFIG_SET(flag/allow_ai, !alai) if (alai) - to_chat(world, "The AI job is no longer chooseable.", confidential = TRUE) + to_chat(world, span_bold("The AI job is no longer chooseable."), confidential = TRUE) else to_chat(world, "The AI job is chooseable now.", confidential = TRUE) - log_admin("[key_name(usr)] toggled AI allowed.") + log_admin("[key_name(user)] toggled AI allowed.") world.update_status() SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/toggleaban() - set category = "Server" - set desc = "Respawn basically" - set name = "Toggle Respawn" - +ADMIN_VERB(toggle_respawn, R_SERVER, "Toggle Respawn", "Toggle the ability to respawn.", ADMIN_CATEGORY_SERVER) var/respawn_state = CONFIG_GET(flag/allow_respawn) var/new_state = -1 var/new_state_text = "" @@ -203,80 +159,71 @@ if(RESPAWN_FLAG_NEW_CHARACTER) // respawn currently enabled for different slot characters only new_state = RESPAWN_FLAG_DISABLED new_state_text = "Disabled" - to_chat(world, span_bold("You may no longer respawn :("), confidential = TRUE) + to_chat(world, span_bold("You may no longer respawn."), confidential = TRUE) else WARNING("Invalid respawn state in config: [respawn_state]") if(new_state == -1) - to_chat(usr, span_warning("The config for respawn is set incorrectly, please complain to your nearest server host (or fix it yourself). \ + to_chat(user, span_warning("The config for respawn is set incorrectly, please complain to your nearest server host (or fix it yourself). \ In the meanwhile respawn has been set to \"Off\".")) new_state = RESPAWN_FLAG_DISABLED new_state_text = "Disabled" CONFIG_SET(flag/allow_respawn, new_state) - message_admins(span_adminnotice("[key_name_admin(usr)] toggled respawn to \"[new_state_text]\".")) - log_admin("[key_name(usr)] toggled respawn to \"[new_state_text]\".") + message_admins(span_adminnotice("[key_name_admin(user)] toggled respawn to \"[new_state_text]\".")) + log_admin("[key_name(user)] toggled respawn to \"[new_state_text]\".") world.update_status() SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Respawn", "[new_state_text]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/delay() - set category = "Server" - set desc = "Delay the game start" - set name = "Delay Pre-Game" - - var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null +ADMIN_VERB(delay, R_SERVER, "Delay Pre-Game", "Delay the game start.", ADMIN_CATEGORY_SERVER) + var/newtime = input(user, "Set a new time in seconds. Set -1 for indefinite delay.", "Set Delay", round(SSticker.GetTimeLeft()/10)) as num|null if(!newtime) return if(SSticker.current_state > GAME_STATE_PREGAME) - return tgui_alert(usr, "Too late... The game has already started!") + return tgui_alert(user, "Too late... The game has already started!") newtime = newtime*10 SSticker.SetTimeLeft(newtime) SSticker.start_immediately = FALSE if(newtime < 0) to_chat(world, "The game start has been delayed.", confidential = TRUE) - log_admin("[key_name(usr)] delayed the round start.") + log_admin("[key_name(user)] delayed the round start.") else - to_chat(world, "The game will start in [DisplayTimeText(newtime)].", confidential = TRUE) + to_chat(world, span_infoplain(span_bold("The game will start in [DisplayTimeText(newtime)].")), confidential = TRUE) SEND_SOUND(world, sound('sound/ai/default/attention.ogg')) - log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].") + log_admin("[key_name(user)] set the pre-game delay to [DisplayTimeText(newtime)].") BLACKBOX_LOG_ADMIN_VERB("Delay Game Start") -/datum/admins/proc/set_admin_notice() - set category = "Server" - set name = "Set Admin Notice" - set desc ="Set an announcement that appears to everyone who joins the server. Only lasts this round" - if(!check_rights(0)) - return - - var/new_admin_notice = input(src,"Set a public notice for this round. Everyone who joins the server will see it.\n(Leaving it blank will delete the current notice):","Set Notice",GLOB.admin_notice) as message|null +ADMIN_VERB(set_admin_notice, R_SERVER, "Set Admin Notice", "Set an announcement that appears to everyone who joins the server. Only lasts this round.", ADMIN_CATEGORY_SERVER) + var/new_admin_notice = input( + user, + "Set a public notice for this round. Everyone who joins the server will see it.\n(Leaving it blank will delete the current notice):", + "Set Notice", + GLOB.admin_notice, + ) as message|null if(new_admin_notice == null) return if(new_admin_notice == GLOB.admin_notice) return if(new_admin_notice == "") - message_admins("[key_name(usr)] removed the admin notice.") - log_admin("[key_name(usr)] removed the admin notice:\n[GLOB.admin_notice]") + message_admins("[key_name(user)] removed the admin notice.") + log_admin("[key_name(user)] removed the admin notice:\n[GLOB.admin_notice]") else - message_admins("[key_name(usr)] set the admin notice.") - log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]") + message_admins("[key_name(user)] set the admin notice.") + log_admin("[key_name(user)] set the admin notice:\n[new_admin_notice]") to_chat(world, span_adminnotice("Admin Notice:\n \t [new_admin_notice]"), confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Set Admin Notice") GLOB.admin_notice = new_admin_notice - return -/datum/admins/proc/toggleguests() - set category = "Server" - set desc = "Guests can't enter" - set name = "Toggle guests" +ADMIN_VERB(toggle_guests, R_SERVER, "Toggle Guests", "Toggle the ability for guests to enter the game.", ADMIN_CATEGORY_SERVER) var/new_guest_ban = !CONFIG_GET(flag/guest_ban) CONFIG_SET(flag/guest_ban, new_guest_ban) if (new_guest_ban) - to_chat(world, "Guests may no longer enter the game.", confidential = TRUE) + to_chat(world, span_bold("Guests may no longer enter the game."), confidential = TRUE) else to_chat(world, "Guests may now enter the game.", confidential = TRUE) - log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") - message_admins(span_adminnotice("[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.")) + log_admin("[key_name(user)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") + message_admins(span_adminnotice("[key_name_admin(user)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.")) SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Guests", "[!new_guest_ban ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/shuttlepanel.dm b/code/modules/admin/verbs/shuttlepanel.dm index d3cccafa68356..ae0ad4dcde3c5 100644 --- a/code/modules/admin/verbs/shuttlepanel.dm +++ b/code/modules/admin/verbs/shuttlepanel.dm @@ -1,13 +1,5 @@ -/datum/admins/proc/open_shuttlepanel() - set category = "Admin.Events" - set name = "Shuttle Manipulator" - set desc = "Opens the shuttle manipulator UI." - - if(!check_rights(R_ADMIN)) - return - - SSshuttle.ui_interact(usr) - +ADMIN_VERB(shuttle_panel, R_ADMIN, "Shuttle Manipulator", "Opens the shuttle manipulator UI.", ADMIN_CATEGORY_EVENTS) + SSshuttle.ui_interact(user.mob) /obj/docking_port/mobile/proc/admin_fly_shuttle(mob/user) var/list/options = list() diff --git a/code/modules/admin/verbs/spawnobjasmob.dm b/code/modules/admin/verbs/spawnobjasmob.dm index 924c9885713ad..e673202f0bae1 100644 --- a/code/modules/admin/verbs/spawnobjasmob.dm +++ b/code/modules/admin/verbs/spawnobjasmob.dm @@ -1,11 +1,4 @@ -/datum/admins/proc/spawn_objasmob(object as text) - set category = "Debug" - set desc = "(obj path) Spawn object-mob" - set name = "Spawn object-mob" - - if(!check_rights(R_SPAWN)) - return - +ADMIN_VERB(spawn_obj_as_mob, R_SPAWN, "Spawn Object-Mob", "Spawn an object as if it were a mob.", ADMIN_CATEGORY_DEBUG, object as text) var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/obj))) if (!chosen) @@ -15,21 +8,63 @@ var/obj/chosen_obj = text2path(chosen) - var/list/settings = list( - "mainsettings" = list( - "name" = list("desc" = "Name", "type" = "string", "value" = "Bob"), - "maxhealth" = list("desc" = "Max. health", "type" = "number", "value" = 100), - "access" = list("desc" = "Access ID", "type" = "datum", "path" = "/obj/item/card/id", "value" = "Default"), - "objtype" = list("desc" = "Base obj type", "type" = "datum", "path" = "/obj", "value" = "[chosen]"), - "googlyeyes" = list("desc" = "Googly eyes", "type" = "boolean", "value" = "No"), - "disableai" = list("desc" = "Disable AI", "type" = "boolean", "value" = "Yes"), - "idledamage" = list("desc" = "Damaged while idle", "type" = "boolean", "value" = "No"), - "dropitem" = list("desc" = "Drop obj on death", "type" = "boolean", "value" = "Yes"), - "mobtype" = list("desc" = "Base mob type", "type" = "datum", "path" = "/mob/living/simple_animal/hostile/mimic/copy", "value" = "/mob/living/simple_animal/hostile/mimic/copy"), - "ckey" = list("desc" = "ckey", "type" = "ckey", "value" = "none"), + var/list/settings = list("mainsettings" = list( + "name" = list( + "desc" = "Name", + "type" = "string", + "value" = "Bob", + ), + "maxhealth" = list( + "desc" = "Max. health", + "type" = "number", + "value" = 100, + ), + "access" = list( + "desc" = "Access ID", + "type" = "datum", + "path" = "/obj/item/card/id", + "value" = "Default", + ), + "objtype" = list( + "desc" = "Base obj type", + "type" = "datum", + "path" = "/obj", + "value" = "[chosen]", + ), + "googlyeyes" = list( + "desc" = "Googly eyes", + "type" = "boolean", + "value" = "No", + ), + "disableai" = list( + "desc" = "Disable AI", + "type" = "boolean", + "value" = "Yes", + ), + "idledamage" = list( + "desc" = "Damaged while idle", + "type" = "boolean", + "value" = "No", + ), + "dropitem" = list( + "desc" = "Drop obj on death", + "type" = "boolean", + "value" = "Yes", + ), + "mobtype" = list( + "desc" = "Base mob type", + "type" = "datum", + "path" = "/mob/living/simple_animal/hostile/mimic/copy", + "value" = "/mob/living/simple_animal/hostile/mimic/copy", + ), + "ckey" = list( + "desc" = "ckey", + "type" = "ckey", + "value" = "none", + ), )) - var/list/prefreturn = presentpreflikepicker(usr,"Customize mob", "Customize mob", Button1="Ok", width = 450, StealFocus = 1,Timeout = 0, settings=settings) + var/list/prefreturn = presentpreflikepicker(user.mob,"Customize mob", "Customize mob", Button1="Ok", width = 450, StealFocus = 1,Timeout = 0, settings=settings) if (prefreturn["button"] == 1) settings = prefreturn["settings"] var/mainsettings = settings["mainsettings"] @@ -37,9 +72,9 @@ basemob = text2path(mainsettings["mobtype"]["value"]) if (!ispath(basemob, /mob/living/simple_animal/hostile/mimic/copy) || !ispath(chosen_obj, /obj)) - to_chat(usr, "Mob or object path invalid", confidential = TRUE) + to_chat(user.mob, "Mob or object path invalid", confidential = TRUE) - basemob = new basemob(get_turf(usr), new chosen_obj(get_turf(usr)), usr, mainsettings["dropitem"]["value"] == "Yes" ? FALSE : TRUE, (mainsettings["googlyeyes"]["value"] == "Yes" ? FALSE : TRUE)) + basemob = new basemob(get_turf(user.mob), new chosen_obj(get_turf(user.mob)), user.mob, mainsettings["dropitem"]["value"] == "Yes" ? FALSE : TRUE, (mainsettings["googlyeyes"]["value"] == "Yes" ? FALSE : TRUE)) if (mainsettings["disableai"]["value"] == "Yes") basemob.toggle_ai(AI_OFF) @@ -65,5 +100,5 @@ basemob.ckey = mainsettings["ckey"]["value"] - log_admin("[key_name(usr)] spawned a sentient object-mob [basemob] from [chosen_obj] at [AREACOORD(usr)]") + log_admin("[key_name(user.mob)] spawned a sentient object-mob [basemob] from [chosen_obj] at [AREACOORD(user.mob)]") BLACKBOX_LOG_ADMIN_VERB("Spawn object-mob") diff --git a/code/modules/admin/verbs/special_verbs.dm b/code/modules/admin/verbs/special_verbs.dm new file mode 100644 index 0000000000000..309c14d4455f6 --- /dev/null +++ b/code/modules/admin/verbs/special_verbs.dm @@ -0,0 +1,43 @@ +// Admin Verbs in this file are special and cannot use the AVD system for some reason or another. + +/client/proc/show_verbs() + set name = "Adminverbs - Show" + set category = ADMIN_CATEGORY_MAIN + + remove_verb(src, /client/proc/show_verbs) + add_admin_verbs() + + to_chat(src, span_interface("All of your adminverbs are now visible."), confidential = TRUE) + BLACKBOX_LOG_ADMIN_VERB("Show Adminverbs") + +/client/proc/readmin() + set name = "Readmin" + set category = "Admin" + set desc = "Regain your admin powers." + + var/datum/admins/A = GLOB.deadmins[ckey] + + if(!A) + A = GLOB.admin_datums[ckey] + if (!A) + var/msg = " is trying to readmin but they have no deadmin entry" + message_admins("[key_name_admin(src)][msg]") + log_admin_private("[key_name(src)][msg]") + return + + A.associate(src) + + if (!holder) + return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force + + to_chat(src, span_interface("You are now an admin."), confidential = TRUE) + message_admins("[src] re-adminned themselves.") + log_admin("[src] re-adminned themselves.") + BLACKBOX_LOG_ADMIN_VERB("Readmin") + +/client/proc/admin_2fa_verify() + set name = "Verify Admin" + set category = "Admin" + + var/datum/admins/admin = GLOB.admin_datums[ckey] + admin?.associate(src) diff --git a/code/modules/admin/view_variables/debug_variable_appearance.dm b/code/modules/admin/view_variables/debug_variable_appearance.dm new file mode 100644 index 0000000000000..9e92eba4605c3 --- /dev/null +++ b/code/modules/admin/view_variables/debug_variable_appearance.dm @@ -0,0 +1,101 @@ +/// Shows a header name on top when you investigate an appearance/image +/image/vv_get_header() + . = list() + var/icon_name = "[icon || "null"]
    " + . += replacetext(icon_name, "icons/obj", "") // shortens the name. We know the path already. + if(icon) + . += icon_state ? "\"[icon_state]\"" : "(icon_state = null)" + +/// Makes nice short vv names for images +/image/debug_variable_value(name, level, datum/owner, sanitize, display_flags) + var/display_name = "[type]" + if("[src]" != "[type]") // If we have a name var, let's use it. + display_name = "[src] [type]" + + var/display_value + var/list/icon_file_name = splittext("[icon]", "/") + if(length(icon_file_name)) + display_value = icon_file_name[length(icon_file_name)] + else + display_value = "null" + + if(icon_state) + display_value = "[display_value]:[icon_state]" + + var/display_ref = get_vv_link_ref() + return "[display_name] ([display_value]) [display_ref]" + +/// Returns the ref string to use when displaying this image in the vv menu of something else +/image/proc/get_vv_link_ref() + return REF(src) + +// It is endlessly annoying to display /appearance directly for stupid byond reasons, so we copy everything we care about into a holder datum +// That we can override procs on and store other vars on and such. +/mutable_appearance/appearance_mirror + // So people can see where it came from + var/appearance_ref + // vis flags can't be displayed by mutable appearances cause it don't make sense as overlays, but appearances do carry them + // can't use the name either for byond reasons + var/_vis_flags + +// all alone at the end of the universe +GLOBAL_DATUM_INIT(pluto, /atom/movable, new /atom/movable(null)) + +// arg is actually an appearance, typed as mutable_appearance as closest mirror +/mutable_appearance/appearance_mirror/New(mutable_appearance/appearance_father) + . = ..() // /mutable_appearance/New() copies over all the appearance vars MAs care about by default + // We copy over our appearance onto an atom. This is done so we can read vars carried by but not accessible on appearances + GLOB.pluto.appearance = appearance_father + _vis_flags = GLOB.pluto.vis_flags + appearance_ref = REF(appearance_father) + +// This means if the appearance loses refs before a click it's gone, but that's consistent to other datums so it's fine +// Need to ref the APPEARANCE because we just free on our own, which sorta fucks this operation up you know? +/mutable_appearance/appearance_mirror/get_vv_link_ref() + return appearance_ref + +/mutable_appearance/appearance_mirror/can_vv_get(var_name) + var/static/datum/beloved = new() + if(beloved.vars.Find(var_name)) // If datums have it, get out + return FALSE + // If it is one of the two args on /image, yeet (I am sorry) + if(var_name == NAMEOF(src, realized_overlays)) + return FALSE + if(var_name == NAMEOF(src, realized_underlays)) + return FALSE + // Filtering out the stuff I know we don't care about + if(var_name == NAMEOF(src, x)) + return FALSE + if(var_name == NAMEOF(src, y)) + return FALSE + if(var_name == NAMEOF(src, z)) + return FALSE + // Could make an argument for these but I think they will just confuse people, so yeeet +#ifndef SPACEMAN_DMM // Spaceman doesn't believe in contents on appearances, sorry lads + if(var_name == NAMEOF(src, contents)) + return FALSE +#endif + if(var_name == NAMEOF(src, loc)) + return FALSE + if(var_name == NAMEOF(src, vis_contents)) + return FALSE + return ..() + +/mutable_appearance/appearance_mirror/vv_get_var(var_name) + // No editing for you + var/value = vars[var_name] + return "
  • (READ ONLY) [var_name] = [_debug_variable_value(var_name, value, 0, src, sanitize = TRUE, display_flags = NONE)]
  • " + +/mutable_appearance/appearance_mirror/vv_get_dropdown() + SHOULD_CALL_PARENT(FALSE) + + . = list() + VV_DROPDOWN_OPTION("", "---") + VV_DROPDOWN_OPTION(VV_HK_CALLPROC, "Call Proc") + VV_DROPDOWN_OPTION(VV_HK_MARK, "Mark Object") + VV_DROPDOWN_OPTION(VV_HK_TAG, "Tag Datum") + VV_DROPDOWN_OPTION(VV_HK_DELETE, "Delete") + VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player") + +/proc/get_vv_appearance(mutable_appearance/appearance) // actually appearance yadeeyada + return new /mutable_appearance/appearance_mirror(appearance) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 8aea000a1a631..a4035acd01421 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -30,6 +30,9 @@ // This is split into a seperate proc mostly to make errors that happen not break things too much /proc/_debug_variable_value(name, value, level, datum/owner, sanitize, display_flags) + if(isappearance(value)) + value = get_vv_appearance(value) + . = "DISPLAY_ERROR: ([value] [REF(value)])" // Make sure this line can never runtime if(isnull(value)) @@ -49,10 +52,6 @@ return "/icon ([value])" #endif - if(isappearance(value)) - var/image/actually_an_appearance = value - return "/appearance ([actually_an_appearance.icon])" - if(isfilter(value)) var/datum/filter_value = value return "/filter ([filter_value.type] [REF(filter_value)])" diff --git a/code/modules/admin/view_variables/mark_datum.dm b/code/modules/admin/view_variables/mark_datum.dm index 44c3b2b83b21a..1d9dd3a1a37ce 100644 --- a/code/modules/admin/view_variables/mark_datum.dm +++ b/code/modules/admin/view_variables/mark_datum.dm @@ -8,10 +8,8 @@ holder.RegisterSignal(holder.marked_datum, COMSIG_QDELETING, TYPE_PROC_REF(/datum/admins, handle_marked_del)) vv_update_display(D, "marked", VV_MSG_MARKED) -/client/proc/mark_datum_mapview(datum/D as mob|obj|turf|area in view(view)) - set category = "Debug" - set name = "Mark Object" - mark_datum(D) +ADMIN_VERB_ONLY_CONTEXT_MENU(mark_datum, R_NONE, "Mark Object", datum/target as mob|obj|turf|area in view()) + user.mark_datum(target) /datum/admins/proc/handle_marked_del(datum/source) SIGNAL_HANDLER diff --git a/code/modules/admin/view_variables/tag_datum.dm b/code/modules/admin/view_variables/tag_datum.dm index 3b611e3cdf934..b4ca42860c341 100644 --- a/code/modules/admin/view_variables/tag_datum.dm +++ b/code/modules/admin/view_variables/tag_datum.dm @@ -12,7 +12,5 @@ else holder.add_tagged_datum(target_datum) -/client/proc/tag_datum_mapview(datum/target_datum as mob|obj|turf|area in view(view)) - set category = "Debug" - set name = "Tag Datum" - tag_datum(target_datum) +ADMIN_VERB_ONLY_CONTEXT_MENU(tag_datum, R_NONE, "Tag Datum", datum/target_datum as mob|obj|turf|area in view()) + user.tag_datum(target_datum) diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index 96500de507001..4f36365312701 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -98,9 +98,7 @@ if(!check_rights(NONE)) return var/mass_remove = href_list[VV_HK_MASS_REMOVECOMPONENT] - var/list/components = list() - for(var/datum/component/component in target.GetComponents(/datum/component)) - components += component.type + var/list/components = target._datum_components.Copy() var/list/names = list() names += "---Components---" if(length(components)) @@ -142,6 +140,7 @@ return var/datum/greyscale_modify_menu/menu = new(target, usr, SSgreyscale.configurations, unlocked = TRUE) menu.ui_interact(usr) + if(href_list[VV_HK_CALLPROC]) - usr.client.callproc_datum(target) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/call_proc_datum, target) diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index 9f0d86e04f656..37bf0911c608f 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -1,3 +1,10 @@ +#define ICON_STATE_CHECKED 1 /// this dmi is checked. We don't check this one anymore. +#define ICON_STATE_NULL 2 /// this dmi has null-named icon_state, allowing it to show a sprite on vv editor. + +ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the variables of a datum.", ADMIN_CATEGORY_DEBUG, datum/thing in world) + user.debug_variables(thing) +// This is kept as a seperate proc because admins are able to show VV to non-admins + /client/proc/debug_variables(datum/thing in world) set category = "Debug" set name = "View Variables" @@ -14,6 +21,8 @@ var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv) asset_cache_datum.send(usr) + if(isappearance(thing)) + thing = get_vv_appearance(thing) // this is /mutable_appearance/our_bs_subtype var/islist = islist(thing) || (!isdatum(thing) && hascall(thing, "Cut")) // Some special lists dont count as lists, but can be detected by if they have list procs if(!islist && !isdatum(thing)) return @@ -23,7 +32,7 @@ var/icon/sprite var/hash - var/type = islist? /list : thing.type + var/type = islist ? /list : thing.type var/no_icon = FALSE if(isatom(thing)) @@ -32,8 +41,25 @@ no_icon = TRUE else if(isimage(thing)) + // icon_state=null shows first image even if dmi has no icon_state for null name. + // This list remembers which dmi has null icon_state, to determine if icon_state=null should display a sprite + // (NOTE: icon_state="" is correct, but saying null is obvious) + var/static/list/dmi_nullstate_checklist = list() var/image/image_object = thing - sprite = icon(image_object.icon, image_object.icon_state) + var/icon_filename_text = "[image_object.icon]" // "icon(null)" type can exist. textifying filters it. + if(icon_filename_text) + if(image_object.icon_state) + sprite = icon(image_object.icon, image_object.icon_state) + + else // it means: icon_state="" + if(!dmi_nullstate_checklist[icon_filename_text]) + dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_CHECKED + if("" in icon_states(image_object.icon)) + // this dmi has nullstate. We'll allow "icon_state=null" to show image. + dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_NULL + + if(dmi_nullstate_checklist[icon_filename_text] == ICON_STATE_NULL) + sprite = icon(image_object.icon, image_object.icon_state) var/sprite_text if(sprite) @@ -281,3 +307,6 @@ datumrefresh=[refid];[HrefToken()]'>Refresh /client/proc/vv_update_display(datum/thing, span, content) src << output("[span]:[content]", "variables[REF(thing)].browser:replace_span") + +#undef ICON_STATE_CHECKED +#undef ICON_STATE_NULL diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 89ed48585ed36..cf5d5a83e8dfe 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -296,9 +296,12 @@ GLOBAL_LIST_EMPTY(antagonists) var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = job_rank, role = job_rank, poll_time = 5 SECONDS, checked_target = owner.current, alert_pic = owner.current, role_name_text = name) if(chosen_one) to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!") - message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(owner)]) to replace a jobbanned player.") + message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(owner)]) to replace antagonist banned player.") + log_game("[key_name(chosen_one)] has taken control of ([key_name(owner)]) to replace antagonist banned player.") owner.current.ghostize(FALSE) owner.current.key = chosen_one.key + else + log_game("Couldn't find antagonist ban replacement for ([key_name(owner)]).") /** * Called by the remove_antag_datum() and remove_all_antag_datums() mind procs for the antag datum to handle its own removal and deletion. diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 2719c576a5eca..18dce0501ff65 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -103,11 +103,13 @@ /// The applied outfit var/datum/outfit/syndicate/outfit = /datum/outfit/syndicate/reinforcement /// The antag datum applied - var/datum/antagonist/nukeop/reinforcement/antag_datum = /datum/antagonist/nukeop/reinforcement + var/antag_datum = /datum/antagonist/nukeop/reinforcement /// Style used by the droppod var/pod_style = STYLE_SYNDICATE /// Do we use a random subtype of the outfit? var/use_subtypes = TRUE + /// Where do we land our pod? + var/turf/spawn_location /obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user) if(used) @@ -143,7 +145,6 @@ /obj/item/antag_spawner/nuke_ops/spawn_antag(client/our_client, turf/T, kind, datum/mind/user) var/mob/living/carbon/human/nukie = new() - var/obj/structure/closet/supplypod/pod = setup_pod() our_client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE) nukie.ckey = our_client.key var/datum/mind/op_mind = nukie.mind @@ -152,15 +153,33 @@ else nukie.forceMove(locate(1,1,1)) - antag_datum = new() - - antag_datum.nukeop_outfit = use_subtypes ? pick(subtypesof(outfit)) : outfit + var/new_datum = new antag_datum() var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop, TRUE) - op_mind.add_antag_datum(antag_datum, creator_op ? creator_op.get_team() : null) + op_mind.add_antag_datum(new_datum, creator_op ? creator_op.get_team() : null) op_mind.special_role = special_role_name + + if(outfit) + var/datum/antagonist/nukeop/nukie_datum = op_mind.has_antag_datum(antag_datum) + nukie_datum.nukeop_outfit = use_subtypes ? pick(subtypesof(outfit)) : outfit + + var/obj/structure/closet/supplypod/pod = setup_pod() nukie.forceMove(pod) - new /obj/effect/pod_landingzone(get_turf(src), pod) + new /obj/effect/pod_landingzone(spawn_location ? spawn_location : get_turf(src), pod) + +/obj/item/antag_spawner/nuke_ops/overwatch + name = "overwatch support beacon" + desc = "Assigns an Overwatch Intelligence Agent to your operation. Stationed at their own remote outpost, they can view station cameras, alarms, and even move the Infiltrator shuttle! \ + Also, all members of your operation will recieve body cameras that they can view your progress from." + special_role_name = ROLE_OPERATIVE_OVERWATCH + outfit = /datum/outfit/syndicate/support + use_subtypes = FALSE + antag_datum = /datum/antagonist/nukeop/support + +/obj/item/antag_spawner/nuke_ops/overwatch/Initialize(mapload) + . = ..() + if(length(GLOB.nukeop_overwatch_start)) //Otherwise, it will default to the datum's spawn point anyways + spawn_location = pick(GLOB.nukeop_overwatch_start) //////CLOWN OP /obj/item/antag_spawner/nuke_ops/clown @@ -265,7 +284,6 @@ new /obj/effect/dummy/phased_mob(T, spawned) spawned.key = C.key - spawned.generate_antagonist_status() /obj/item/antag_spawner/slaughter_demon/laughter name = "vial of tickles" diff --git a/code/modules/antagonists/abductor/abductor_structures.dm b/code/modules/antagonists/abductor/abductor_structures.dm index 7da1d72d06b5a..da0ad5de9ea5b 100644 --- a/code/modules/antagonists/abductor/abductor_structures.dm +++ b/code/modules/antagonists/abductor/abductor_structures.dm @@ -31,7 +31,7 @@ to_chat(user, span_warning("You need one alien alloy sheet to do this!")) return to_chat(user, span_notice("You start adding [stacked_sheets] to [src]...")) - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) stacked_sheets.use(1) new /obj/structure/table/abductor(src.loc) qdel(src) @@ -42,7 +42,7 @@ to_chat(user, span_warning("You need one sheet of silver to do this!")) return to_chat(user, span_notice("You start adding [stacked_sheets] to [src]...")) - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) stacked_sheets.use(1) new /obj/structure/table/optable/abductor(src.loc) qdel(src) diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm index 14d8d73788655..2fb5d52604531 100644 --- a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm +++ b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm @@ -48,7 +48,7 @@ icon_state = "gizmo_scan" to_chat(user, span_notice("You switch the device to [mode == GIZMO_SCAN? "SCAN": "MARK"] MODE")) -/obj/item/abductor/gizmo/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/abductor/gizmo/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!ScientistCheck(user)) return ITEM_INTERACT_SKIP_TO_ATTACK // So you slap them with it if(!console) @@ -93,7 +93,7 @@ to_chat(user, span_warning("You need to be next to the specimen to prepare it for transport!")) return to_chat(user, span_notice("You begin preparing [target] for transport...")) - if(do_after(user, 100, target = target)) + if(do_after(user, 10 SECONDS, target = target)) marked_target_weakref = WEAKREF(target) to_chat(user, span_notice("You finish preparing [target] for transport.")) @@ -110,7 +110,7 @@ icon_state = "silencer" inhand_icon_state = "gizmo" -/obj/item/abductor/silencer/interact_with_atom(atom/interacting_with, mob/living/user) +/obj/item/abductor/silencer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!AbductorCheck(user)) return ITEM_INTERACT_SKIP_TO_ATTACK // So you slap them with it @@ -285,8 +285,8 @@
    Congratulations! You are now trained for invasive xenobiology research!"} -/obj/item/paper/guides/antag/abductor/AltClick() - return //otherwise it would fold into a paperplane. +/obj/item/paper/guides/antag/abductor/click_alt() + return CLICK_ACTION_BLOCKING //otherwise it would fold into a paperplane. /obj/item/melee/baton/abductor name = "advanced baton" @@ -523,7 +523,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} user.visible_message(span_notice("[user] places down [src] and activates it."), span_notice("You place down [src] and activate it.")) user.dropItemToGround(src) playsound(src, 'sound/machines/terminal_alert.ogg', 50) - addtimer(CALLBACK(src, PROC_REF(try_spawn_machine)), 30) + addtimer(CALLBACK(src, PROC_REF(try_spawn_machine)), 3 SECONDS) /obj/item/abductor_machine_beacon/proc/try_spawn_machine() var/viable = FALSE diff --git a/code/modules/antagonists/abductor/equipment/glands/electric.dm b/code/modules/antagonists/abductor/equipment/glands/electric.dm index a5ec2cfde2153..72b2c1e14ad1c 100644 --- a/code/modules/antagonists/abductor/equipment/glands/electric.dm +++ b/code/modules/antagonists/abductor/equipment/glands/electric.dm @@ -19,7 +19,7 @@ owner.visible_message(span_danger("[owner]'s skin starts emitting electric arcs!"),\ span_warning("You feel electric energy building up inside you!")) playsound(get_turf(owner), SFX_SPARKS, 100, TRUE, -1, SHORT_RANGE_SOUND_EXTRARANGE) - addtimer(CALLBACK(src, PROC_REF(zap)), rand(30, 100)) + addtimer(CALLBACK(src, PROC_REF(zap)), rand(3 SECONDS, 10 SECONDS)) /obj/item/organ/internal/heart/gland/electric/proc/zap() tesla_zap(source = owner, zap_range = 4, power = 8e3, cutoff = 1e3, zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN) diff --git a/code/modules/antagonists/abductor/equipment/glands/heal.dm b/code/modules/antagonists/abductor/equipment/glands/heal.dm index 683cb33fc9adb..7f4462377654c 100644 --- a/code/modules/antagonists/abductor/equipment/glands/heal.dm +++ b/code/modules/antagonists/abductor/equipment/glands/heal.dm @@ -159,7 +159,7 @@ else to_chat(owner, span_warning("You feel a weird rumble behind your eye sockets...")) - addtimer(CALLBACK(src, PROC_REF(finish_replace_eyes)), rand(100, 200)) + addtimer(CALLBACK(src, PROC_REF(finish_replace_eyes)), rand(10 SECONDS, 20 SECONDS)) /obj/item/organ/internal/heart/gland/heal/proc/finish_replace_eyes() var/eye_type = /obj/item/organ/internal/eyes @@ -177,7 +177,7 @@ else to_chat(owner, span_warning("You feel a weird tingle in your [parse_zone(body_zone)]... even if you don't have one.")) - addtimer(CALLBACK(src, PROC_REF(finish_replace_limb), body_zone), rand(150, 300)) + addtimer(CALLBACK(src, PROC_REF(finish_replace_limb), body_zone), rand(15 SECONDS, 30 SECONDS)) /obj/item/organ/internal/heart/gland/heal/proc/finish_replace_limb(body_zone) owner.visible_message(span_warning("With a loud snap, [owner]'s [parse_zone(body_zone)] rapidly grows back from [owner.p_their()] body!"), @@ -207,7 +207,7 @@ if(owner.reagents.has_reagent(R.type)) keep_going = TRUE if(keep_going) - addtimer(CALLBACK(src, PROC_REF(keep_replacing_blood)), 30) + addtimer(CALLBACK(src, PROC_REF(keep_replacing_blood)), 3 SECONDS) /obj/item/organ/internal/heart/gland/heal/proc/replace_chest(obj/item/bodypart/chest/chest) if(!IS_ORGANIC_LIMB(chest)) diff --git a/code/modules/antagonists/abductor/equipment/glands/plasma.dm b/code/modules/antagonists/abductor/equipment/glands/plasma.dm index 0d709579cc8c5..76cd806bb42b8 100644 --- a/code/modules/antagonists/abductor/equipment/glands/plasma.dm +++ b/code/modules/antagonists/abductor/equipment/glands/plasma.dm @@ -9,8 +9,8 @@ /obj/item/organ/internal/heart/gland/plasma/activate() to_chat(owner, span_warning("You feel bloated.")) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), owner, span_userdanger("A massive stomachache overcomes you.")), 150) - addtimer(CALLBACK(src, PROC_REF(vomit_plasma)), 200) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), owner, span_userdanger("A massive stomachache overcomes you.")), 15 SECONDS) + addtimer(CALLBACK(src, PROC_REF(vomit_plasma)), 20 SECONDS) /obj/item/organ/internal/heart/gland/plasma/proc/vomit_plasma() if(!owner) diff --git a/code/modules/antagonists/abductor/equipment/glands/quantum.dm b/code/modules/antagonists/abductor/equipment/glands/quantum.dm index d32304a5987e8..a2a4a9149e741 100644 --- a/code/modules/antagonists/abductor/equipment/glands/quantum.dm +++ b/code/modules/antagonists/abductor/equipment/glands/quantum.dm @@ -15,7 +15,7 @@ if(!iscarbon(M)) continue entangled_mob = M - addtimer(CALLBACK(src, PROC_REF(quantum_swap)), rand(600, 2400)) + addtimer(CALLBACK(src, PROC_REF(quantum_swap)), rand(1 MINUTES, 4 MINUTES)) return /obj/item/organ/internal/heart/gland/quantum/proc/quantum_swap() diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm index 5bd5ce8c2ecfc..ee729de7068b8 100644 --- a/code/modules/antagonists/abductor/machinery/console.dm +++ b/code/modules/antagonists/abductor/machinery/console.dm @@ -198,11 +198,8 @@ pad.teleport_target = location to_chat(user, span_notice("Location marked as test subject release point.")) -/obj/machinery/abductor/console/Initialize(mapload) - ..() - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/abductor/console/LateInitialize() +/obj/machinery/abductor/console/post_machine_initialize() + . = ..() if(!team_number) return diff --git a/code/modules/antagonists/abductor/machinery/pad.dm b/code/modules/antagonists/abductor/machinery/pad.dm index 6f2dc48a67213..1610d9a6cff33 100644 --- a/code/modules/antagonists/abductor/machinery/pad.dm +++ b/code/modules/antagonists/abductor/machinery/pad.dm @@ -38,7 +38,7 @@ /obj/machinery/abductor/pad/proc/MobToLoc(place,mob/living/target) new /obj/effect/temp_visual/teleport_abductor(place) - addtimer(CALLBACK(src, PROC_REF(doMobToLoc), place, target), 80) + addtimer(CALLBACK(src, PROC_REF(doMobToLoc), place, target), 8 SECONDS) /obj/machinery/abductor/pad/proc/doPadToLoc(place) flick("alien-pad", src) @@ -48,7 +48,7 @@ /obj/machinery/abductor/pad/proc/PadToLoc(place) new /obj/effect/temp_visual/teleport_abductor(place) - addtimer(CALLBACK(src, PROC_REF(doPadToLoc), place), 80) + addtimer(CALLBACK(src, PROC_REF(doPadToLoc), place), 8 SECONDS) /obj/effect/temp_visual/teleport_abductor name = "Huh" diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 401daa97ac5b2..929a3b5c4ffd4 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -153,7 +153,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) SSsecurity_level.set_level(SEC_LEVEL_DELTA) max_blob_points = INFINITY blob_points = INFINITY - addtimer(CALLBACK(src, PROC_REF(victory)), 450) + addtimer(CALLBACK(src, PROC_REF(victory)), 45 SECONDS) else if(!free_strain_rerolls && (last_reroll_time + BLOB_POWER_REROLL_FREE_TIME 0) - var/mob/living/carbon/carbon_owner = owner.current - if (istype(carbon_owner)) - carbon_owner.equip_conspicuous_item(new /obj/item/assembly/flash) - carbon_owner.AddComponentFrom(REF(src), /datum/component/can_flash_from_behind) - RegisterSignal(carbon_owner, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON, PROC_REF(on_mob_successful_flashed_carbon)) + grant_conversion_skills() + carbon_owner.equip_conspicuous_item(new /obj/item/assembly/flash) - if (!is_first_brother) - to_chat(carbon_owner, span_boldwarning("The Syndicate have higher expectations from you than others. They have granted you an extra flash to convert one other person.")) + var/is_first_brother = team.members.len == 1 + if (!is_first_brother) + to_chat(carbon_owner, span_boldwarning("The Syndicate have higher expectations from you than others. They have granted you an extra flash to convert one other person.")) return ..() /datum/antagonist/brother/on_removal() owner.special_role = null - owner.RemoveComponentSource(REF(src), /datum/component/can_flash_from_behind) - UnregisterSignal(owner, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON) - + remove_conversion_skills() return ..() +/// Give us the ability to add another brother +/datum/antagonist/brother/proc/grant_conversion_skills() + var/mob/living/carbon/carbon_owner = owner.current + if (!istype(carbon_owner)) + return + carbon_owner.AddComponentFrom(REF(src), /datum/component/can_flash_from_behind) + RegisterSignal(carbon_owner, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON, PROC_REF(on_mob_successful_flashed_carbon)) + +/// Take away the ability to add more brothers +/datum/antagonist/brother/proc/remove_conversion_skills() + if (isnull(owner.current)) + return + var/mob/living/carbon/carbon_owner = owner.current + carbon_owner.RemoveComponentSource(REF(src), /datum/component/can_flash_from_behind) + UnregisterSignal(carbon_owner, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON) + /datum/antagonist/brother/proc/on_mob_successful_flashed_carbon(mob/living/source, mob/living/carbon/flashed, obj/item/assembly/flash/flash) SIGNAL_HANDLER @@ -95,11 +110,19 @@ ) flashed.balloon_alert(source, "converted") - UnregisterSignal(source, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON) - source.RemoveComponentSource(REF(src), /datum/component/can_flash_from_behind) - /datum/antagonist/brother/antag_panel_data() - return "Conspirators : [get_brother_names()]" + return "Conspirators : [get_brother_names()] | Remaining: [team.brothers_left]" + +/datum/antagonist/brother/get_admin_commands() + . = ..() + .["Adjust Remaining Conversions"] = CALLBACK(src, PROC_REF(update_recruitments_remaining)) + +/// Add or remove the potential to put more bros in here +/datum/antagonist/brother/proc/update_recruitments_remaining(mob/admin) + var/new_count = tgui_input_number(admin, "How many more people should be able to be recruited?", "Adjust Conversions Remaining", default = 1, min_value = 0) + if (isnull(new_count)) + return + team.set_brothers_left(new_count) /datum/antagonist/brother/get_preview_icon() var/mob/living/carbon/human/dummy/consistent/brother1 = new @@ -131,6 +154,9 @@ /datum/antagonist/brother/proc/get_brother_names() var/list/brothers = team.members - owner + if (!length(brothers)) + return "none" + var/brother_text = "" for(var/i = 1 to brothers.len) var/datum/mind/M = brothers[i] @@ -167,13 +193,15 @@ member_name = "blood brother" var/brothers_left = 2 -/datum/team/brother_team/New() +/datum/team/brother_team/New(starting_members) . = ..() if (prob(10)) brothers_left += 1 /datum/team/brother_team/add_member(datum/mind/new_member) . = ..() + if (!length(objectives)) + forge_brother_objectives() if (!new_member.has_antag_datum(/datum/antagonist/brother)) add_brother(new_member.current) @@ -193,11 +221,17 @@ if (isnull(new_brother) || isnull(new_brother.mind) || !GET_CLIENT(new_brother) || new_brother.mind.has_antag_datum(/datum/antagonist/brother)) return FALSE + set_brothers_left(brothers_left - 1) for (var/datum/mind/brother_mind as anything in members) if (brother_mind == new_brother.mind) continue + to_chat(brother_mind, span_notice("[span_bold("[new_brother.real_name]")] has been converted to aid you as your brother!")) + if (brothers_left == 0) + to_chat(brother_mind, span_notice("You cannot recruit any more brothers.")) + new_brother.mind.add_antag_datum(/datum/antagonist/brother, src) + return TRUE /datum/team/brother_team/proc/update_name() @@ -217,7 +251,7 @@ add_objective(new /datum/objective/convert_brother) var/is_hijacker = prob(10) - for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker)) + for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (brothers_left > 2) - is_hijacker)) forge_single_objective() if(is_hijacker) if(!locate(/datum/objective/hijack) in objectives) @@ -236,6 +270,22 @@ else add_objective(new /datum/objective/steal, needs_target = TRUE) +/// Control how many more people we can recruit +/datum/team/brother_team/proc/set_brothers_left(remaining_brothers) + if (brothers_left == remaining_brothers) + return + + if (brothers_left == 0 && remaining_brothers > 0) + for (var/datum/mind/brother_mind as anything in members) + var/datum/antagonist/brother/brother_datum = brother_mind.has_antag_datum(/datum/antagonist/brother) + brother_datum?.grant_conversion_skills() + + else if (brothers_left > 0 && remaining_brothers <= 0) + for (var/datum/mind/brother_mind as anything in members) + var/datum/antagonist/brother/brother_datum = brother_mind.has_antag_datum(/datum/antagonist/brother) + brother_datum?.remove_conversion_skills() + brothers_left = remaining_brothers + /datum/objective/convert_brother name = "convert brother" explanation_text = "Convert a brainwashable person using your flash on them directly. Any handheld flash will work if you lose or break your starting flash." diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index eb3714203a8d0..9cde062d6481b 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -526,6 +526,7 @@ new_profile.age = target.age new_profile.physique = target.physique + new_profile.athletics_level = target.mind?.get_skill_level(/datum/skill/athletics) || SKILL_LEVEL_NONE // Grab the target's quirks. for(var/datum/quirk/target_quirk as anything in target.quirks) @@ -766,6 +767,7 @@ user.socks = chosen_profile.socks user.age = chosen_profile.age user.physique = chosen_profile.physique + user.mind?.set_level(/datum/skill/athletics, chosen_profile.athletics_level, silent = TRUE) user.grad_style = LAZYLISTDUPLICATE(chosen_profile.grad_style) user.grad_color = LAZYLISTDUPLICATE(chosen_profile.grad_color) user.voice = chosen_profile.voice @@ -913,6 +915,8 @@ var/age /// The body type of the profile source. var/physique + /// The athleticism of the profile source. + var/athletics_level /// The quirks of the profile source. var/list/quirks = list() /// The hair and facial hair gradient styles of the profile source. @@ -958,6 +962,7 @@ new_profile.id_icon = id_icon new_profile.age = age new_profile.physique = physique + new_profile.athletics_level = athletics_level new_profile.quirks = quirks.Copy() new_profile.grad_style = LAZYLISTDUPLICATE(grad_style) new_profile.grad_color = LAZYLISTDUPLICATE(grad_color) diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index 5bd0f390cb8bb..7e13612153b49 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -145,7 +145,7 @@ target.take_overall_damage(40) SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[absorbing_iteration]")) - if(!do_after(owner, 15 SECONDS, target)) + if(!do_after(owner, 15 SECONDS, target, hidden = TRUE)) owner.balloon_alert(owner, "interrupted!") is_absorbing = FALSE return FALSE diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm index ef3070356d5d2..2b1753c27273a 100644 --- a/code/modules/antagonists/changeling/powers/biodegrade.dm +++ b/code/modules/antagonists/changeling/powers/biodegrade.dm @@ -15,7 +15,7 @@ user.visible_message(span_warning("[user] vomits a glob of acid on [user.p_their()] [O]!"), \ span_warning("We vomit acidic ooze onto our restraints!")) - addtimer(CALLBACK(src, PROC_REF(dissolve_handcuffs), user, O), 30) + addtimer(CALLBACK(src, PROC_REF(dissolve_handcuffs), user, O), 3 SECONDS) log_combat(user, user.handcuffed, "melted handcuffs", addition = "(biodegrade)") ..() return TRUE @@ -27,7 +27,7 @@ user.visible_message(span_warning("[user] vomits a glob of acid on [user.p_their()] [O]!"), \ span_warning("We vomit acidic ooze onto our restraints!")) - addtimer(CALLBACK(src, PROC_REF(dissolve_legcuffs), user, O), 30) + addtimer(CALLBACK(src, PROC_REF(dissolve_legcuffs), user, O), 3 SECONDS) log_combat(user, user.legcuffed, "melted legcuffs", addition = "(biodegrade)") ..() return TRUE @@ -38,7 +38,7 @@ return FALSE user.visible_message(span_warning("[user] vomits a glob of acid across the front of [user.p_their()] [S]!"), \ span_warning("We vomit acidic ooze onto our [user.wear_suit.name]!")) - addtimer(CALLBACK(src, PROC_REF(dissolve_straightjacket), user, S), 30) + addtimer(CALLBACK(src, PROC_REF(dissolve_straightjacket), user, S), 3 SECONDS) log_combat(user, user.wear_suit, "melted [user.wear_suit]", addition = "(biodegrade)") ..() return TRUE @@ -49,7 +49,7 @@ return FALSE C.visible_message(span_warning("[C]'s hinges suddenly begin to melt and run!")) to_chat(user, span_warning("We vomit acidic goop onto the interior of [C]!")) - addtimer(CALLBACK(src, PROC_REF(open_closet), user, C), 70) + addtimer(CALLBACK(src, PROC_REF(open_closet), user, C), 7 SECONDS) log_combat(user, user.loc, "melted locker", addition = "(biodegrade)") ..() return TRUE diff --git a/code/modules/antagonists/changeling/powers/pheromone_receptors.dm b/code/modules/antagonists/changeling/powers/pheromone_receptors.dm index 18fda4bf4ff02..0e468159a3c7a 100644 --- a/code/modules/antagonists/changeling/powers/pheromone_receptors.dm +++ b/code/modules/antagonists/changeling/powers/pheromone_receptors.dm @@ -23,6 +23,9 @@ /datum/action/changeling/pheromone_receptors/sting_action(mob/living/carbon/user) ..() var/datum/antagonist/changeling/changeling = IS_CHANGELING(user) + if(HAS_TRAIT(user, TRAIT_ANOSMIA)) //Anosmia quirk holders can't smell anything + to_chat(user, span_warning("We can't smell!")) + return if(!receptors_active) to_chat(user, span_warning("We search for the scent of any nearby changelings.")) changeling.chem_recharge_slowdown += 0.25 diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index d6767f5c1b1cb..ea172fee0134b 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -174,7 +174,7 @@ target.visible_message(span_warning("A grotesque blade forms around [target.name]\'s arm!"), span_userdanger("Your arm twists and mutates, transforming into a horrific monstrosity!"), span_hear("You hear organic matter ripping and tearing!")) playsound(target, 'sound/effects/blobattack.ogg', 30, TRUE) - addtimer(CALLBACK(src, PROC_REF(remove_fake), target, blade), 600) + addtimer(CALLBACK(src, PROC_REF(remove_fake), target, blade), 1 MINUTES) return TRUE /datum/action/changeling/sting/false_armblade/proc/remove_fake(mob/target, obj/item/melee/arm_blade/false/blade) diff --git a/code/modules/antagonists/changeling/powers/transform.dm b/code/modules/antagonists/changeling/powers/transform.dm index 530eca763223b..1e1ef9e65d8e2 100644 --- a/code/modules/antagonists/changeling/powers/transform.dm +++ b/code/modules/antagonists/changeling/powers/transform.dm @@ -19,6 +19,9 @@ return . = ..() +/obj/item/clothing/glasses/changeling/attack_paw(mob/user, list/modifiers) + attack_hand(user, modifiers) + /obj/item/clothing/under/changeling name = "flesh" item_flags = DROPDEL @@ -31,6 +34,9 @@ return . = ..() +/obj/item/clothing/under/changeling/attack_paw(mob/user, list/modifiers) + attack_hand(user, modifiers) + /obj/item/clothing/suit/changeling name = "flesh" allowed = list(/obj/item/changeling) @@ -44,6 +50,9 @@ return . = ..() +/obj/item/clothing/suit/changeling/attack_paw(mob/user, list/modifiers) + attack_hand(user, modifiers) + /obj/item/clothing/head/changeling name = "flesh" icon_state = null @@ -57,6 +66,9 @@ return . = ..() +/obj/item/clothing/head/changeling/attack_paw(mob/user, list/modifiers) + attack_hand(user, modifiers) + /obj/item/clothing/shoes/changeling name = "flesh" item_flags = DROPDEL @@ -69,6 +81,9 @@ return . = ..() +/obj/item/clothing/shoes/changeling/attack_paw(mob/user, list/modifiers) + attack_hand(user, modifiers) + /obj/item/clothing/gloves/changeling name = "flesh" item_flags = DROPDEL @@ -81,6 +96,9 @@ return . = ..() +/obj/item/clothing/gloves/changeling/attack_paw(mob/user, list/modifiers) + attack_hand(user, modifiers) + /obj/item/clothing/mask/changeling name = "flesh" item_flags = DROPDEL @@ -93,6 +111,9 @@ return . = ..() +/obj/item/clothing/mask/changeling/attack_paw(mob/user, list/modifiers) + attack_hand(user, modifiers) + /obj/item/changeling name = "flesh" slot_flags = ALL @@ -106,6 +127,9 @@ return . = ..() +/obj/item/changeling/attack_paw(mob/user, list/modifiers) + attack_hand(user, modifiers) + /obj/item/changeling/id slot_flags = ITEM_SLOT_ID /// Cached flat icon of the ID diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index e70e3fc31b3a1..5a25d68c507a0 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -1,3 +1,10 @@ +/// how many units of blood one charge of blood rites is worth +#define USES_TO_BLOOD 2 +/// blood rites charges gained from sapping blood from a victim +#define BLOOD_DRAIN_GAIN 50 +/// penalty for self healing, 1 point of damage * this # = charges required +#define SELF_HEAL_PENALTY 1.65 + /datum/action/innate/cult/blood_magic //Blood magic handles the creation of blood spells (formerly talismans) name = "Prepare Blood Magic" button_icon_state = "carve" @@ -103,6 +110,8 @@ var/health_cost = 0 /// Have we already been positioned into our starting location? var/positioned = FALSE + /// If false, the spell will not delete after running out of charges + var/deletes_on_empty = TRUE /datum/action/innate/cult/blood_spell/Grant(mob/living/owner, datum/action/innate/cult/blood_magic/BM) if(health_cost) @@ -121,26 +130,25 @@ ..() /datum/action/innate/cult/blood_spell/IsAvailable(feedback = FALSE) - if(!IS_CULTIST(owner) || owner.incapacitated() || !charges) + if(!IS_CULTIST(owner) || owner.incapacitated() || (!charges && deletes_on_empty)) return FALSE return ..() /datum/action/innate/cult/blood_spell/Activate() - if(magic_path) //If this spell flows from the hand - if(!hand_magic) - hand_magic = new magic_path(owner, src) - if(!owner.put_in_hands(hand_magic)) - qdel(hand_magic) - hand_magic = null - to_chat(owner, span_warning("You have no empty hand for invoking blood magic!")) - return - to_chat(owner, span_notice("Your wounds glow as you invoke the [name].")) - return - if(hand_magic) - qdel(hand_magic) - hand_magic = null - to_chat(owner, span_warning("You snuff out the spell, saving it for later.")) - + if(!magic_path) // only concerned with spells that flow from the hand + return + if(hand_magic) + qdel(hand_magic) + hand_magic = null + to_chat(owner, span_warning("You snuff out the spell, saving it for later.")) + return + hand_magic = new magic_path(owner, src) + if(!owner.put_in_hands(hand_magic)) + qdel(hand_magic) + hand_magic = null + to_chat(owner, span_warning("You have no empty hand for invoking blood magic!")) + return + to_chat(owner, span_notice("Your wounds glow as you invoke the [name].")) //Cult Blood Spells /datum/action/innate/cult/blood_spell/stun @@ -170,6 +178,7 @@ span_cult_italic("You speak the cursed words, emitting an EMP blast from your hand.")) empulse(owner, 2, 5) charges-- + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) qdel(src) @@ -214,6 +223,7 @@ span_cult_italic("A [summoned_blade] materializes at your feet.")) SEND_SOUND(owner, sound('sound/effects/magic.ogg', FALSE, 0, 25)) charges-- + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) qdel(src) @@ -255,6 +265,7 @@ desc = base_desc desc += "
    Has [charges] use\s remaining." build_all_button_icons() + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) to_chat(caller, span_cult("You have exhausted the spell's power!")) qdel(src) @@ -308,6 +319,7 @@ revealing = FALSE name = "Conceal Runes" button_icon_state = "gone" + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "Conceal Runes") if(charges <= 0) qdel(src) desc = base_desc @@ -321,6 +333,7 @@ button_icon_state = "manip" charges = 5 magic_path = "/obj/item/melee/blood_magic/manipulator" + deletes_on_empty = FALSE // The "magic hand" items /obj/item/melee/blood_magic @@ -350,7 +363,7 @@ /obj/item/melee/blood_magic/Destroy() if(!QDELETED(source)) - if(uses <= 0) + if(uses <= 0 && source.deletes_on_empty) source.hand_magic = null qdel(source) source = null @@ -371,6 +384,7 @@ qdel(src) return log_combat(user, M, "used a cult spell on", source.name, "") + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") M.lastattacker = user.real_name M.lastattackerckey = user.ckey @@ -501,7 +515,7 @@ playsound(loc, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2) C.visible_message(span_danger("[user] begins restraining [C] with dark magic!"), \ span_userdanger("[user] begins shaping dark magic shackles around your wrists!")) - if(do_after(user, 30, C)) + if(do_after(user, 3 SECONDS, C)) if(!C.handcuffed) C.set_handcuffed(new /obj/item/restraints/handcuffs/energy/cult/used(C)) C.update_handcuffed() @@ -580,7 +594,7 @@ playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, TRUE) var/prev_color = candidate.color candidate.color = "black" - if(do_after(user, 90, target = candidate)) + if(do_after(user, 9 SECONDS, target = candidate)) candidate.undeploy() candidate.emp_act(EMP_HEAVY) var/construct_class = show_radial_menu(user, src, GLOB.construct_radial_images, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE) @@ -609,7 +623,7 @@ channeling = TRUE playsound(T, 'sound/machines/airlockforced.ogg', 50, TRUE) do_sparks(5, TRUE, target) - if(do_after(user, 50, target = user)) + if(do_after(user, 5 SECONDS, target = user)) if(QDELETED(target)) channeling = FALSE return @@ -671,167 +685,236 @@ . = ..() . += "Bloody halberd, blood bolt barrage, and blood beam cost [BLOOD_HALBERD_COST], [BLOOD_BARRAGE_COST], and [BLOOD_BEAM_COST] charges respectively." +/** + * handles inhand use of blood rites on constructs, humans, or non-living blood sources + * + * see '/obj/item/melee/blood_magic/manipulator/proc/heal_construct' for construct/shade behavior + * see '/obj/item/melee/blood_magic/manipulator/proc/heal_cultist' for human cultist behavior + * see '/obj/item/melee/blood_magic/manipulator/proc/drain_victim' for human non-cultist behavior + * if any of the above procs return FALSE, '/obj/item/melee/blood_magic/afterattack' will not be called + * + * '/obj/item/melee/blood_magic/manipulator/proc/blood_draw' handles blood pools/trails and does not affect parent proc + */ /obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity) - if(proximity) - if(ishuman(target)) - var/mob/living/carbon/human/human_bloodbag = target - if(HAS_TRAIT(human_bloodbag, TRAIT_NOBLOOD)) - to_chat(user,span_warning("Blood rites do not work on people with no blood!")) - return - if(IS_CULTIST(human_bloodbag)) - if(human_bloodbag.stat == DEAD) - to_chat(user,span_warning("Only a revive rune can bring back the dead!")) - return - if(human_bloodbag.blood_volume < BLOOD_VOLUME_SAFE) - var/restore_blood = BLOOD_VOLUME_SAFE - human_bloodbag.blood_volume - if(uses*2 < restore_blood) - human_bloodbag.blood_volume += uses*2 - to_chat(user,span_danger("You use the last of your blood rites to restore what blood you could!")) - uses = 0 - return ..() - else - human_bloodbag.blood_volume = BLOOD_VOLUME_SAFE - uses -= round(restore_blood/2) - to_chat(user,span_warning("Your blood rites have restored [human_bloodbag == user ? "your" : "[human_bloodbag.p_their()]"] blood to safe levels!")) - var/overall_damage = human_bloodbag.getBruteLoss() + human_bloodbag.getFireLoss() + human_bloodbag.getToxLoss() + human_bloodbag.getOxyLoss() - if(overall_damage == 0) - to_chat(user,span_cult("That cultist doesn't require healing!")) - else - var/ratio = uses/overall_damage - if(human_bloodbag == user) - to_chat(user,span_cult("Your blood healing is far less efficient when used on yourself!")) - ratio *= 0.35 // Healing is half as effective if you can't perform a full heal - uses -= round(overall_damage) // Healing is 65% more "expensive" even if you can still perform the full heal - if(ratio>1) - ratio = 1 - uses -= round(overall_damage) - human_bloodbag.visible_message(span_warning("[human_bloodbag] is fully healed by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic!")) - else - human_bloodbag.visible_message(span_warning("[human_bloodbag] is partially healed by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic.")) - uses = 0 - ratio *= -1 - var/need_mob_update = FALSE - need_mob_update += human_bloodbag.adjustOxyLoss((overall_damage*ratio) * (human_bloodbag.getOxyLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustToxLoss((overall_damage*ratio) * (human_bloodbag.getToxLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustFireLoss((overall_damage*ratio) * (human_bloodbag.getFireLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustBruteLoss((overall_damage*ratio) * (human_bloodbag.getBruteLoss() / overall_damage), updating_health = FALSE) - if(need_mob_update) - human_bloodbag.updatehealth() - playsound(get_turf(human_bloodbag), 'sound/magic/staff_healing.ogg', 25) - new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) - user.Beam(human_bloodbag, icon_state="sendbeam", time = 15) - else - if(human_bloodbag.stat == DEAD) - to_chat(user,span_warning("[human_bloodbag.p_Their()] blood has stopped flowing, you'll have to find another way to extract it.")) - return - if(human_bloodbag.has_status_effect(/datum/status_effect/speech/slurring/cult)) - to_chat(user,span_danger("[human_bloodbag.p_Their()] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!")) - return - if(human_bloodbag.blood_volume > BLOOD_VOLUME_SAFE) - human_bloodbag.blood_volume -= 100 - uses += 50 - user.Beam(human_bloodbag, icon_state="drainbeam", time = 1 SECONDS) - playsound(get_turf(human_bloodbag), 'sound/magic/enter_blood.ogg', 50) - human_bloodbag.visible_message(span_danger("[user] drains some of [human_bloodbag]'s blood!")) - to_chat(user,span_cult_italic("Your blood rite gains 50 charges from draining [human_bloodbag]'s blood.")) - new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) - else - to_chat(user,span_warning("[human_bloodbag.p_Theyre()] missing too much blood - you cannot drain [human_bloodbag.p_them()] further!")) - return - if(isconstruct(target)) - var/mob/living/basic/construct/construct_thing = target - var/missing_health = construct_thing.maxHealth - construct_thing.health - if(missing_health) - if(uses > missing_health) - construct_thing.adjust_health(-missing_health) - construct_thing.visible_message(span_warning("[construct_thing] is fully healed by [user]'s blood magic!")) - uses -= missing_health - else - construct_thing.adjust_health(-uses) - construct_thing.visible_message(span_warning("[construct_thing] is partially healed by [user]'s blood magic!")) - uses = 0 - playsound(get_turf(construct_thing), 'sound/magic/staff_healing.ogg', 25) - user.Beam(construct_thing, icon_state="sendbeam", time = 1 SECONDS) - if(istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder) || isturf(target)) - blood_draw(target, user) - ..() + if(!proximity) + return + + if((isconstruct(target) || isshade(target)) && !heal_construct(target, user)) + return + if(istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder) || isturf(target)) + blood_draw(target, user) + if(ishuman(target)) + var/mob/living/carbon/human/human_bloodbag = target + if(HAS_TRAIT(human_bloodbag, TRAIT_NOBLOOD)) + human_bloodbag.balloon_alert(user, "no blood!") + return + if(human_bloodbag.stat == DEAD) + human_bloodbag.balloon_alert(user, "dead!") + return + + if(IS_CULTIST(human_bloodbag) && !heal_cultist(human_bloodbag, user)) + return + if(!IS_CULTIST(human_bloodbag) && !drain_victim(human_bloodbag, user)) + return + ..() + +/** + * handles blood rites usage on constructs + * + * will only return TRUE if some amount healing is done + */ +/obj/item/melee/blood_magic/manipulator/proc/heal_construct(atom/target, mob/living/carbon/human/user) + var/mob/living/basic/construct_thing = target + if(!IS_CULTIST(construct_thing)) + return FALSE + var/missing_health = construct_thing.maxHealth - construct_thing.health + if(!missing_health) + to_chat(user,span_cult("That cultist doesn't require healing!")) + return FALSE + if(uses <= 0) + construct_thing.balloon_alert(user, "out of blood!") + return FALSE + if(uses > missing_health) + construct_thing.adjust_health(-missing_health) + construct_thing.visible_message(span_warning("[construct_thing] is fully healed by [user]'s blood magic!")) + uses -= missing_health + else + construct_thing.adjust_health(-uses) + construct_thing.visible_message(span_warning("[construct_thing] is partially healed by [user]'s blood magic!")) + uses = 0 + playsound(get_turf(construct_thing), 'sound/magic/staff_healing.ogg', 25) + user.Beam(construct_thing, icon_state="sendbeam", time = 1 SECONDS) + return TRUE + +/** + * handles blood rites usage on human cultists + * + * first restores blood, then heals damage. healing damage is more expensive, especially if performed on oneself + * returns TRUE if some amount of blood is restored and/or damage is healed + */ +/obj/item/melee/blood_magic/manipulator/proc/heal_cultist(mob/living/carbon/human/human_bloodbag, mob/living/carbon/human/user) + if(uses <= 0) + human_bloodbag.balloon_alert(user, "out of blood!") + return FALSE + + /// used to ensure the proc returns TRUE if we completely restore an undamaged persons blood + var/blood_donor = FALSE + if(human_bloodbag.blood_volume < BLOOD_VOLUME_SAFE) + var/blood_needed = BLOOD_VOLUME_SAFE - human_bloodbag.blood_volume + /// how much blood we are capable of restoring, based on spell charges + var/blood_bank = USES_TO_BLOOD * uses + if(blood_bank < blood_needed) + human_bloodbag.blood_volume += blood_bank + to_chat(user,span_danger("You use the last of your blood rites to restore what blood you could!")) + uses = 0 + return TRUE + blood_donor = TRUE + human_bloodbag.blood_volume = BLOOD_VOLUME_SAFE + uses -= round(blood_needed / USES_TO_BLOOD) + to_chat(user,span_warning("Your blood rites have restored [human_bloodbag == user ? "your" : "[human_bloodbag.p_their()]"] blood to safe levels!")) + + var/overall_damage = human_bloodbag.getBruteLoss() + human_bloodbag.getFireLoss() + human_bloodbag.getToxLoss() + human_bloodbag.getOxyLoss() + if(overall_damage == 0) + if(blood_donor) + return TRUE + to_chat(user,span_cult("That cultist doesn't require healing!")) + return FALSE + /// how much damage we can/will heal + var/damage_healed = -1 * min(uses, overall_damage) + /// how many spell charges will be consumed to heal said damage + var/healing_cost = damage_healed + if(human_bloodbag == user) + to_chat(user,span_cult("Your blood healing is far less efficient when used on yourself!")) + damage_healed = -1 * min(uses * (1 / SELF_HEAL_PENALTY), overall_damage) + healing_cost = damage_healed * SELF_HEAL_PENALTY + uses += round(healing_cost) + human_bloodbag.visible_message(span_warning("[human_bloodbag] is [uses == 0 ? "partially healed":"fully healed"] by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic!")) + + var/need_mob_update = FALSE + need_mob_update += human_bloodbag.adjustOxyLoss(damage_healed * (human_bloodbag.getOxyLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustToxLoss(damage_healed * (human_bloodbag.getToxLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustFireLoss(damage_healed * (human_bloodbag.getFireLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustBruteLoss(damage_healed * (human_bloodbag.getBruteLoss() / overall_damage), updating_health = FALSE) + if(need_mob_update) + human_bloodbag.updatehealth() + playsound(get_turf(human_bloodbag), 'sound/magic/staff_healing.ogg', 25) + new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) + if (user != human_bloodbag) //Dont create beam from the user to the user + user.Beam(human_bloodbag, icon_state="sendbeam", time = 15) + return TRUE + +/** + * handles blood rites use on a non-cultist human + * + * returns TRUE if blood is successfully drained from the victim + */ +/obj/item/melee/blood_magic/manipulator/proc/drain_victim(mob/living/carbon/human/human_bloodbag, mob/living/carbon/human/user) + if(human_bloodbag.has_status_effect(/datum/status_effect/speech/slurring/cult)) + to_chat(user,span_danger("[human_bloodbag.p_Their()] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!")) + return FALSE + if(human_bloodbag.blood_volume <= BLOOD_VOLUME_SAFE) + to_chat(user,span_warning("[human_bloodbag.p_Theyre()] missing too much blood - you cannot drain [human_bloodbag.p_them()] further!")) + return FALSE + human_bloodbag.blood_volume -= BLOOD_DRAIN_GAIN * USES_TO_BLOOD + uses += BLOOD_DRAIN_GAIN + user.Beam(human_bloodbag, icon_state="drainbeam", time = 1 SECONDS) + playsound(get_turf(human_bloodbag), 'sound/magic/enter_blood.ogg', 50) + human_bloodbag.visible_message(span_danger("[user] drains some of [human_bloodbag]'s blood!")) + to_chat(user,span_cult_italic("Your blood rite gains 50 charges from draining [human_bloodbag]'s blood.")) + new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) + return TRUE +/** + * handles blood rites use on turfs, blood pools, and blood trails + */ /obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user) var/blood_to_gain = 0 var/turf/our_turf = get_turf(target) - if(our_turf) - for(var/obj/effect/decal/cleanable/blood/blood_around_us in range(our_turf,2)) - if(blood_around_us.blood_state == BLOOD_STATE_HUMAN) - if(blood_around_us.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam - blood_to_gain += 30 - else - blood_to_gain += max((blood_around_us.bloodiness**2)/800,1) - new /obj/effect/temp_visual/cult/turf/floor(get_turf(blood_around_us)) - qdel(blood_around_us) - for(var/obj/effect/decal/cleanable/trail_holder/trail_around_us in range(our_turf, 2)) - if(trail_around_us.blood_state == BLOOD_STATE_HUMAN) - blood_to_gain += 5 //These don't get bloodiness, so we'll just increase this by a fixed value - new /obj/effect/temp_visual/cult/turf/floor(get_turf(trail_around_us)) - qdel(trail_around_us) - if(blood_to_gain) - user.Beam(our_turf,icon_state="drainbeam", time = 15) - new /obj/effect/temp_visual/cult/sparks(get_turf(user)) - playsound(our_turf, 'sound/magic/enter_blood.ogg', 50) - to_chat(user, span_cult_italic("Your blood rite has gained [round(blood_to_gain)] charge\s from blood sources around you!")) - uses += max(1, round(blood_to_gain)) - + if(!our_turf) + return + for(var/obj/effect/decal/cleanable/blood/blood_around_us in range(our_turf,2)) + if(blood_around_us.blood_state != BLOOD_STATE_HUMAN) + break + if(blood_around_us.bloodiness == 100) // Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam + blood_to_gain += 30 + else + blood_to_gain += max((blood_around_us.bloodiness**2)/800,1) + new /obj/effect/temp_visual/cult/turf/floor(get_turf(blood_around_us)) + qdel(blood_around_us) + for(var/obj/effect/decal/cleanable/trail_holder/trail_around_us in range(our_turf, 2)) + if(trail_around_us.blood_state != BLOOD_STATE_HUMAN) + break + blood_to_gain += 5 //These don't get bloodiness, so we'll just increase this by a fixed value + new /obj/effect/temp_visual/cult/turf/floor(get_turf(trail_around_us)) + qdel(trail_around_us) + + if(!blood_to_gain) + return + user.Beam(our_turf,icon_state="drainbeam", time = 15) + new /obj/effect/temp_visual/cult/sparks(get_turf(user)) + playsound(our_turf, 'sound/magic/enter_blood.ogg', 50) + to_chat(user, span_cult_italic("Your blood rite has gained [round(blood_to_gain)] charge\s from blood sources around you!")) + uses += max(1, round(blood_to_gain)) + +/** + * handles untargeted use of blood rites + * + * allows user to trade in spell uses for equipment or spells + */ /obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user) - if(IS_CULTIST(user)) - var/static/list/spells = list( - "Bloody Halberd (150)" = image(icon = 'icons/obj/weapons/spear.dmi', icon_state = "occultpoleaxe0"), - "Blood Bolt Barrage (300)" = image(icon = 'icons/obj/weapons/guns/ballistic.dmi', icon_state = "arcane_barrage"), - "Blood Beam (500)" = image(icon = 'icons/obj/weapons/hand.dmi', icon_state = "disintegrate") - ) - var/choice = show_radial_menu(user, src, spells, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE) - if(!check_menu(user)) - to_chat(user, span_cult_italic("You decide against conducting a greater blood rite.")) - return - switch(choice) - if("Bloody Halberd (150)") - if(uses < BLOOD_HALBERD_COST) - to_chat(user, span_cult_italic("You need [BLOOD_HALBERD_COST] charges to perform this rite.")) - else - uses -= BLOOD_HALBERD_COST - var/turf/current_position = get_turf(user) - qdel(src) - var/datum/action/innate/cult/halberd/halberd_act_granted = new(user) - var/obj/item/melee/cultblade/halberd/rite = new(current_position) - halberd_act_granted.Grant(user, rite) - rite.halberd_act = halberd_act_granted - if(user.put_in_hands(rite)) - to_chat(user, span_cult_italic("A [rite.name] appears in your hand!")) - else - user.visible_message(span_warning("A [rite.name] appears at [user]'s feet!"), \ - span_cult_italic("A [rite.name] materializes at your feet.")) - if("Blood Bolt Barrage (300)") - if(uses < BLOOD_BARRAGE_COST) - to_chat(user, span_cult_italic("You need [BLOOD_BARRAGE_COST] charges to perform this rite.")) - else - var/obj/rite = new /obj/item/gun/magic/wand/arcane_barrage/blood() - uses -= BLOOD_BARRAGE_COST - qdel(src) - if(user.put_in_hands(rite)) - to_chat(user, span_cult("Your hands glow with power!")) - else - to_chat(user, span_cult_italic("You need a free hand for this rite!")) - qdel(rite) - if("Blood Beam (500)") - if(uses < BLOOD_BEAM_COST) - to_chat(user, span_cult_italic("You need [BLOOD_BEAM_COST] charges to perform this rite.")) - else - var/obj/rite = new /obj/item/blood_beam() - uses -= BLOOD_BEAM_COST - qdel(src) - if(user.put_in_hands(rite)) - to_chat(user, span_cult_large("Your hands glow with POWER OVERWHELMING!!!")) - else - to_chat(user, span_cult_italic("You need a free hand for this rite!")) - qdel(rite) + var/static/list/spells = list( + "Bloody Halberd (150)" = image(icon = 'icons/obj/weapons/spear.dmi', icon_state = "occultpoleaxe0"), + "Blood Bolt Barrage (300)" = image(icon = 'icons/obj/weapons/guns/ballistic.dmi', icon_state = "arcane_barrage"), + "Blood Beam (500)" = image(icon = 'icons/obj/weapons/hand.dmi', icon_state = "disintegrate") + ) + var/choice = show_radial_menu(user, src, spells, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE) + if(!check_menu(user)) + to_chat(user, span_cult_italic("You decide against conducting a greater blood rite.")) + return + + switch(choice) + if("Bloody Halberd (150)") + if(uses < BLOOD_HALBERD_COST) + to_chat(user, span_cult_italic("You need [BLOOD_HALBERD_COST] charges to perform this rite.")) + return + uses -= BLOOD_HALBERD_COST + var/turf/current_position = get_turf(user) + qdel(src) + var/datum/action/innate/cult/halberd/halberd_act_granted = new(user) + var/obj/item/melee/cultblade/halberd/rite = new(current_position) + halberd_act_granted.Grant(user, rite) + rite.halberd_act = halberd_act_granted + if(user.put_in_hands(rite)) + to_chat(user, span_cult_italic("A [rite.name] appears in your hand!")) + else + user.visible_message(span_warning("A [rite.name] appears at [user]'s feet!"), \ + span_cult_italic("A [rite.name] materializes at your feet.")) + + if("Blood Bolt Barrage (300)") + if(uses < BLOOD_BARRAGE_COST) + to_chat(user, span_cult_italic("You need [BLOOD_BARRAGE_COST] charges to perform this rite.")) + return + var/obj/rite = new /obj/item/gun/magic/wand/arcane_barrage/blood() + uses -= BLOOD_BARRAGE_COST + qdel(src) + if(user.put_in_hands(rite)) + to_chat(user, span_cult("Your hands glow with power!")) + else + to_chat(user, span_cult_italic("You need a free hand for this rite!")) + qdel(rite) + + if("Blood Beam (500)") + if(uses < BLOOD_BEAM_COST) + to_chat(user, span_cult_italic("You need [BLOOD_BEAM_COST] charges to perform this rite.")) + return + var/obj/rite = new /obj/item/blood_beam() + uses -= BLOOD_BEAM_COST + qdel(src) + if(user.put_in_hands(rite)) + to_chat(user, span_cult_large("Your hands glow with POWER OVERWHELMING!!!")) + else + to_chat(user, span_cult_italic("You need a free hand for this rite!")) + qdel(rite) /obj/item/melee/blood_magic/manipulator/proc/check_menu(mob/living/user) if(!istype(user)) @@ -839,3 +922,7 @@ if(user.incapacitated() || !user.Adjacent(src)) return FALSE return TRUE + +#undef USES_TO_BLOOD +#undef BLOOD_DRAIN_GAIN +#undef SELF_HEAL_PENALTY diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm index ff64cc86a2bb1..586cb44172e29 100644 --- a/code/modules/antagonists/cult/cult_comms.dm +++ b/code/modules/antagonists/cult/cult_comms.dm @@ -229,20 +229,20 @@ if(!LAZYLEN(destinations)) to_chat(owner, span_warning("You need more space to summon your cult!")) return - if(do_after(owner, 30, target = owner)) + if(do_after(owner, 3 SECONDS, target = owner)) for(var/datum/mind/B in antag.cult_team.members) if(B.current && B.current.stat != DEAD) var/turf/mobloc = get_turf(B.current) switch(i) if(1) new /obj/effect/temp_visual/cult/sparks(mobloc, B.current.dir) - playsound(mobloc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(mobloc, 'sound/effects/portal_travel.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(2) new /obj/effect/temp_visual/dir_setting/cult/phase/out(mobloc, B.current.dir) - playsound(mobloc, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(mobloc, 'sound/effects/portal_travel.ogg', 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(3) new /obj/effect/temp_visual/dir_setting/cult/phase(mobloc, B.current.dir) - playsound(mobloc, SFX_SPARKS, 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(mobloc, 'sound/effects/portal_travel.ogg', 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(4) playsound(mobloc, 'sound/magic/exit_blood.ogg', 100, TRUE) if(B.current != owner) @@ -252,7 +252,7 @@ S.release_shades(owner) B.current.setDir(SOUTH) new /obj/effect/temp_visual/cult/blood(final) - addtimer(CALLBACK(B.current, TYPE_PROC_REF(/mob/, reckon), final), 10) + addtimer(CALLBACK(B.current, TYPE_PROC_REF(/mob/, reckon), final), 1 SECONDS) else return antag.cult_team.reckoning_complete = TRUE diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 5a8b1978aa9e8..a9537d26d3802 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -620,9 +620,9 @@ Striking a noncultist, however, will tear their flesh."} new /obj/effect/temp_visual/dir_setting/cult/phase/out(mobloc, user_cultist.dir) new /obj/effect/temp_visual/dir_setting/cult/phase(destination, user_cultist.dir) - playsound(mobloc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(mobloc, 'sound/effects/portal_travel.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) playsound(destination, 'sound/effects/phasein.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - playsound(destination, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(destination, 'sound/effects/portal_travel.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) /obj/item/flashlight/flare/culttorch name = "void torch" @@ -989,7 +989,7 @@ Striking a noncultist, however, will tear their flesh."} if(.) if(illusions > 0) illusions-- - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/shield/mirror, readd)), 450) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/shield/mirror, readd)), 45 SECONDS) if(prob(60)) var/mob/living/simple_animal/hostile/illusion/M = new(owner.loc) M.faction = list(FACTION_CULT) diff --git a/code/modules/antagonists/cult/rune_spawn_action.dm b/code/modules/antagonists/cult/rune_spawn_action.dm index af4350427b551..3d791dbce44dc 100644 --- a/code/modules/antagonists/cult/rune_spawn_action.dm +++ b/code/modules/antagonists/cult/rune_spawn_action.dm @@ -42,7 +42,7 @@ var/chosen_keyword if(initial(rune_type.req_keyword)) chosen_keyword = tgui_input_text(owner, "Enter a keyword for the new rune.", "Words of Power", max_length = MAX_NAME_LEN) - if(!chosen_keyword) + if(!chosen_keyword || !turf_check(T)) return //the outer ring is always the same across all runes var/obj/effect/temp_visual/cult/rune_spawn/R1 = new(T, scribe_time, rune_color) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 6fe9cf472989b..b75d74ee16002 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -104,6 +104,7 @@ Runes can either be invoked by one's self or with many different cultists. Each var/list/invokers = can_invoke(user) if(length(invokers) >= req_cultists) invoke(invokers) + SSblackbox.record_feedback("tally", "cult_rune_invoke", 1, "[name]") else to_chat(user, span_danger("You need [req_cultists - length(invokers)] more adjacent cultists to use this rune in such a manner.")) fail_invoke() @@ -187,7 +188,7 @@ structure_check() searches for nearby cultist structures required for the invoca var/oldcolor = color color = rgb(255, 0, 0) animate(src, color = oldcolor, time = 5) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 5) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.5 SECONDS) //Malformed Rune: This forms if a rune is not drawn correctly. Invoking it does nothing but hurt the user. /obj/effect/rune/malformed @@ -490,7 +491,7 @@ structure_check() searches for nearby cultist structures required for the invoca fail_invoke() return var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to? - if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated() || !actual_selected_rune) + if(!Adjacent(user) || QDELETED(src) || user.incapacitated() || !actual_selected_rune) fail_invoke() return @@ -544,7 +545,7 @@ structure_check() searches for nearby cultist structures required for the invoca /obj/effect/rune/teleport/proc/handle_portal(portal_type, turf/origin) var/turf/T = get_turf(src) close_portal() // To avoid stacking descriptions/animations - playsound(T, pick('sound/effects/sparks1.ogg', 'sound/effects/sparks2.ogg', 'sound/effects/sparks3.ogg', 'sound/effects/sparks4.ogg'), 100, TRUE, 14) + playsound(T, 'sound/effects/portal_travel.ogg', 100, TRUE, 14) inner_portal = new /obj/effect/temp_visual/cult/portal(T) if(portal_type == "space") set_light_color(color) diff --git a/code/modules/antagonists/disease/disease_datum.dm b/code/modules/antagonists/disease/disease_datum.dm index 9d5af7ab83e77..17364feec5597 100644 --- a/code/modules/antagonists/disease/disease_datum.dm +++ b/code/modules/antagonists/disease/disease_datum.dm @@ -54,7 +54,7 @@ result += objectives_text - var/special_role_text = lowertext(name) + var/special_role_text = LOWER_TEXT(name) if(win) result += span_greentext("The [special_role_text] was successful!") diff --git a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm index 54f2ef351a78e..31f312ae5407b 100644 --- a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm +++ b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm @@ -23,7 +23,7 @@ if(!fug_antag) to_chat(fugitive_hunter, span_warning("This is not a wanted fugitive!")) return - if(do_after(fugitive_hunter, 50, target = fugitive)) + if(do_after(fugitive_hunter, 5 SECONDS, target = fugitive)) add_prisoner(fugitive, fug_antag) /obj/machinery/fugitive_capture/proc/add_prisoner(mob/living/carbon/human/fugitive, datum/antagonist/fugitive/antag) diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index 01ca69fa734c6..ef6e2d0a4557b 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -46,6 +46,8 @@ var/high_value_sacrifices = 0 /// Lazy assoc list of [refs to humans] to [image previews of the human]. Humans that we have as sacrifice targets. var/list/mob/living/carbon/human/sac_targets + /// List of all sickly blades linked with heretic mind. + var/list/obj/item/melee/sickly_blade/blades_list /// List of all sacrifice target's names, used for end of round report var/list/all_sac_targets = list() /// Whether we're drawing a rune or not @@ -54,6 +56,8 @@ var/static/list/scribing_tools = typecacheof(list(/obj/item/pen, /obj/item/toy/crayon)) /// A blacklist of turfs we cannot scribe on. var/static/list/blacklisted_rune_turfs = typecacheof(list(/turf/open/space, /turf/open/openspace, /turf/open/lava, /turf/open/chasm)) + /// Controls what types of turf we can spread rust to, increases as we unlock more powerful rust abilites + var/rust_strength = 0 /// Static list of what each path converts to in the UI (colors are TGUI colors) var/static/list/path_to_ui_color = list( PATH_START = "grey", @@ -82,6 +86,9 @@ /datum/antagonist/heretic/Destroy() LAZYNULL(sac_targets) + for(var/obj/item/melee/sickly_blade/blade as anything in blades_list) + blade.owner = null + LAZYNULL(blades_list) return ..() /datum/antagonist/heretic/ui_data(mob/user) @@ -202,7 +209,7 @@ if(give_objectives) forge_primary_objectives() - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ecult_op.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)//subject to change + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/heretic/heretic_gain.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE) for(var/starting_knowledge in GLOB.heretic_start_knowledge) gain_knowledge(starting_knowledge) @@ -350,7 +357,7 @@ else drawing_effect = new(target_turf, rune_colour) - if(!do_after(user, drawing_time, target_turf, extra_checks = additional_checks)) + if(!do_after(user, drawing_time, target_turf, extra_checks = additional_checks, hidden = TRUE)) target_turf.balloon_alert(user, "interrupted!") new /obj/effect/temp_visual/drawing_heretic_rune/fail(target_turf, rune_colour) qdel(drawing_effect) @@ -661,6 +668,14 @@ /datum/antagonist/heretic/proc/get_knowledge(wanted) return researched_knowledge[wanted] +/// Makes our heretic more able to rust things. +/// if side_path_only is set to TRUE, this function does nothing for rust heretics. +/datum/antagonist/heretic/proc/increase_rust_strength(side_path_only=FALSE) + if(side_path_only && get_knowledge(/datum/heretic_knowledge/limited_amount/starting/base_rust)) + return + + rust_strength++ + /** * Get a list of all rituals this heretic can invoke on a rune. * Iterates over all of our knowledge and, if we can invoke it, adds it to our list. diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm index bb59076a6bb06..94546bfdd1981 100644 --- a/code/modules/antagonists/heretic/heretic_knowledge.dm +++ b/code/modules/antagonists/heretic/heretic_knowledge.dm @@ -225,6 +225,8 @@ var/limit = 1 /// A list of weakrefs to all items we've created. var/list/datum/weakref/created_items + /// if we have all the blades then we don’t want to tear our hands off + var/valid_blades = FALSE /datum/heretic_knowledge/limited_amount/Destroy(force) LAZYCLEARLIST(created_items) @@ -237,8 +239,14 @@ LAZYREMOVE(created_items, ref) if(LAZYLEN(created_items) >= limit) - loc.balloon_alert(user, "ritual failed, at limit!") - return FALSE + for(var/obj/item/melee/sickly_blade/is_blade_ritual as anything in result_atoms) + valid_blades = blades_limit_check(user) + break + if(valid_blades) + return TRUE + else + loc.balloon_alert(user, "ritual failed, at limit!") + return FALSE return TRUE @@ -246,8 +254,36 @@ for(var/result in result_atoms) var/atom/created_thing = new result(loc) LAZYADD(created_items, WEAKREF(created_thing)) + if(istype(created_thing, /obj/item/melee/sickly_blade)) + add_to_list_sickly_blade(user, created_thing) return TRUE +/datum/heretic_knowledge/limited_amount/proc/add_to_list_sickly_blade(mob/living/heretic, obj/item/melee/sickly_blade/created_blade) + var/obj/item/melee/sickly_blade/blade_check = created_blade + var/datum/antagonist/heretic/our_heretic = IS_HERETIC(heretic) + if(!isnull(our_heretic)) + blade_check.owner = our_heretic + LAZYADD(our_heretic.blades_list, blade_check) + +/datum/heretic_knowledge/limited_amount/proc/blades_limit_check(mob/living/heretic) + var/datum/antagonist/heretic/our_heretic = IS_HERETIC(heretic) + var/success_check = FALSE + for(var/obj/item/melee/sickly_blade/blades_in_list as anything in our_heretic.blades_list) + if(get_turf(heretic) == get_turf(blades_in_list)) + continue + success_check = TRUE + LAZYREMOVE(our_heretic.blades_list, blades_in_list) + var/mob/living/living_target = recursive_loc_check(src, /mob/living) + if(living_target) + living_target.apply_damage(15) + var/obj/item/bodypart/thief_hand = living_target.get_bodypart(BODY_ZONE_L_ARM) + if(!isnull(thief_hand)) + thief_hand.dismember(BRUTE) + to_chat(living_target, span_boldwarning("You feel severe pain in your hand as if otherworldly powers tore it from inside. [blades_in_list] collapse and disappeared.. maybe it never existed?")) + qdel(blades_in_list) + break + return success_check + /** * A knowledge subtype for limited_amount knowledge * used for base knowledge (the ones that make blades) @@ -730,6 +766,7 @@ source = user, header = "A Heretic is Ascending!", ) + heretic_datum.increase_rust_strength() return TRUE /datum/heretic_knowledge/ultimate/cleanup_atoms(list/selected_atoms) diff --git a/code/modules/antagonists/heretic/heretic_monsters.dm b/code/modules/antagonists/heretic/heretic_monsters.dm index 3f3dd32035722..1f95ed62ea92f 100644 --- a/code/modules/antagonists/heretic/heretic_monsters.dm +++ b/code/modules/antagonists/heretic/heretic_monsters.dm @@ -13,7 +13,7 @@ /datum/antagonist/heretic_monster/on_gain() . = ..() - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ecult_op.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)//subject to change + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/heretic/heretic_gain.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE) /datum/antagonist/heretic_monster/on_removal() if(!silent) diff --git a/code/modules/antagonists/heretic/influences.dm b/code/modules/antagonists/heretic/influences.dm index 5123f7ec4bf62..662af81249a5c 100644 --- a/code/modules/antagonists/heretic/influences.dm +++ b/code/modules/antagonists/heretic/influences.dm @@ -282,7 +282,7 @@ being_drained = TRUE balloon_alert(user, "draining influence...") - if(!do_after(user, 10 SECONDS, src)) + if(!do_after(user, 10 SECONDS, src, hidden = TRUE)) being_drained = FALSE balloon_alert(user, "interrupted!") return diff --git a/code/modules/antagonists/heretic/items/corrupted_organs.dm b/code/modules/antagonists/heretic/items/corrupted_organs.dm new file mode 100644 index 0000000000000..311e84c805599 --- /dev/null +++ b/code/modules/antagonists/heretic/items/corrupted_organs.dm @@ -0,0 +1,242 @@ +/// Renders you unable to see people who were heretics at the time that this organ is gained +/obj/item/organ/internal/eyes/corrupt + name = "corrupt orbs" + desc = "These eyes have seen something they shouldn't have." + /// The override images we are applying + var/list/hallucinations + +/obj/item/organ/internal/eyes/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their eyes have wide dilated pupils, and no iris. Something is moving in the darkness.", BODY_ZONE_PRECISE_EYES) + +/obj/item/organ/internal/eyes/corrupt/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags) + . = ..() + if (!organ_owner.client) + return + + var/list/human_mobs = GLOB.human_list.Copy() + human_mobs -= organ_owner + for (var/mob/living/carbon/human/check_human as anything in human_mobs) + if (!IS_HERETIC(check_human) && !prob(5)) // Throw in some false positives + continue + var/image/invisible_man = image('icons/blanks/32x32.dmi', check_human, "nothing") + invisible_man.override = TRUE + LAZYADD(hallucinations, invisible_man) + + if (LAZYLEN(hallucinations)) + organ_owner.client.images |= hallucinations + +/obj/item/organ/internal/eyes/corrupt/on_mob_remove(mob/living/carbon/organ_owner, special) + . = ..() + if (!LAZYLEN(hallucinations)) + return + organ_owner.client?.images -= hallucinations + QDEL_NULL(hallucinations) + + +/// Sometimes speak in incomprehensible tongues +/obj/item/organ/internal/tongue/corrupt + name = "corrupt tongue" + desc = "This one tells only lies." + +/obj/item/organ/internal/tongue/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + AddElement(/datum/element/noticable_organ, "The inside of %PRONOUN_Their mouth is full of stars.", BODY_ZONE_PRECISE_MOUTH) + +/obj/item/organ/internal/tongue/corrupt/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags) + . = ..() + RegisterSignal(organ_owner, COMSIG_MOB_SAY, PROC_REF(on_spoken)) + +/obj/item/organ/internal/tongue/corrupt/on_mob_remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_MOB_SAY) + +/// When the mob speaks, sometimes put it in a different language +/obj/item/organ/internal/tongue/corrupt/proc/on_spoken(mob/living/organ_owner, list/speech_args) + SIGNAL_HANDLER + if (organ_owner.has_reagent(/datum/reagent/water/holywater) || prob(60)) + return + speech_args[SPEECH_LANGUAGE] = /datum/language/shadowtongue + + +/// Randomly secretes alcohol or hallucinogens when you're drinking something +/obj/item/organ/internal/liver/corrupt + name = "corrupt liver" + desc = "After what you've seen you could really go for a drink." + /// How much extra ingredients to add? + var/amount_added = 5 + /// What extra ingredients can we add? + var/list/extra_ingredients = list( + /datum/reagent/consumable/ethanol/pina_olivada, + /datum/reagent/consumable/ethanol/rum, + /datum/reagent/consumable/ethanol/thirteenloko, + /datum/reagent/consumable/ethanol/vodka, + /datum/reagent/consumable/superlaughter, + /datum/reagent/drug/bath_salts, + /datum/reagent/drug/blastoff, + /datum/reagent/drug/happiness, + /datum/reagent/drug/mushroomhallucinogen, + ) + +/obj/item/organ/internal/liver/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + +/obj/item/organ/internal/liver/corrupt/on_mob_insert(mob/living/carbon/organ_owner, special) + . = ..() + RegisterSignal(organ_owner, COMSIG_ATOM_EXPOSE_REAGENTS, PROC_REF(on_drank)) + +/obj/item/organ/internal/liver/corrupt/on_mob_remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_ATOM_EXPOSE_REAGENTS) + +/// If we drank something, add a little extra +/obj/item/organ/internal/liver/corrupt/proc/on_drank(atom/source, list/reagents, datum/reagents/source_reagents, methods) + SIGNAL_HANDLER + if (!(methods & INGEST)) + return + var/datum/reagents/extra_reagents = new() + extra_reagents.add_reagent(pick(extra_ingredients), amount_added) + extra_reagents.trans_to(source, amount_added, transferred_by = src, methods = INJECT) + if (prob(20)) + to_chat(source, span_warning("As you take a sip, you feel something bubbling in your stomach...")) + + +/// Rapidly become hungry if you are not digesting blood +/obj/item/organ/internal/stomach/corrupt + name = "corrupt stomach" + desc = "This parasite demands an unwholesome diet in order to be satisfied." + /// Do we have an unholy thirst? + var/thirst_satiated = FALSE + /// Timer for when we get thirsty again + var/thirst_timer + /// How long until we prompt the player to drink blood again? + COOLDOWN_DECLARE(message_cooldown) + +/obj/item/organ/internal/stomach/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + AddElement(/datum/element/noticable_organ, "%PRONOUN_They %PRONOUN_have an unhealthy pallor.") + +/obj/item/organ/internal/stomach/corrupt/on_mob_insert(mob/living/carbon/organ_owner, special) + . = ..() + RegisterSignal(organ_owner, COMSIG_ATOM_EXPOSE_REAGENTS, PROC_REF(on_drank)) + +/obj/item/organ/internal/stomach/corrupt/on_mob_remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_ATOM_EXPOSE_REAGENTS) + +/// Check if we drank a little blood +/obj/item/organ/internal/stomach/corrupt/proc/on_drank(atom/source, list/reagents, datum/reagents/source_reagents, methods) + SIGNAL_HANDLER + if (!(methods & INGEST)) + return + + var/contains_blood = locate(/datum/reagent/blood) in reagents + if (!contains_blood) + return + + if (!thirst_satiated) + to_chat(source, span_cult_italic("The thirst is satisfied... for now.")) + thirst_satiated = TRUE + deltimer(thirst_timer) + thirst_timer = addtimer(VARSET_CALLBACK(src, thirst_satiated, FALSE), 3 MINUTES, TIMER_STOPPABLE | TIMER_DELETE_ME) + +/obj/item/organ/internal/stomach/corrupt/handle_hunger(mob/living/carbon/human/human, seconds_per_tick, times_fired) + if (thirst_satiated || human.has_reagent(/datum/reagent/water/holywater)) + return ..() + + human.adjust_nutrition(-1 * seconds_per_tick) + + if (!COOLDOWN_FINISHED(src, message_cooldown)) + return ..() + COOLDOWN_START(src, message_cooldown, 30 SECONDS) + + var/static/list/blood_messages = list( + "Blood...", + "Everyone suddenly looks so tasty.", + "The blood...", + "There's an emptiness in you that only blood can fill.", + "You could really go for some blood right now.", + "You feel the blood rushing through your veins.", + "You think about biting someone's throat.", + "Your stomach growls and you feel a metallic taste in your mouth.", + ) + to_chat(human, span_cult_italic(pick(blood_messages))) + + return ..() + + +/// Occasionally bombards you with spooky hands and lets everyone hear your pulse. +/obj/item/organ/internal/heart/corrupt + name = "corrupt heart" + desc = "What corruption is this spreading along with the blood?" + /// How long until the next heart? + COOLDOWN_DECLARE(hand_cooldown) + +/obj/item/organ/internal/heart/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + +/obj/item/organ/internal/heart/corrupt/on_life(seconds_per_tick, times_fired) + . = ..() + if (!COOLDOWN_FINISHED(src, hand_cooldown) || IS_IN_MANSUS(owner) || !owner.needs_heart() || !is_beating() || owner.has_reagent(/datum/reagent/water/holywater)) + return + fire_curse_hand(owner) + COOLDOWN_START(src, hand_cooldown, rand(6 SECONDS, 45 SECONDS)) // Wide variance to put you off guard + + +/// Sometimes cough out some kind of dangerous gas +/obj/item/organ/internal/lungs/corrupt + name = "corrupt lungs" + desc = "Some things SHOULD be drowned in tar." + /// How likely are we not to cough every time we take a breath? + var/cough_chance = 15 + /// How much gas to emit? + var/gas_amount = 30 + /// What can we cough up? + var/list/gas_types = list( + /datum/gas/bz = 30, + /datum/gas/miasma = 50, + /datum/gas/plasma = 20, + ) + +/obj/item/organ/internal/lungs/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + +/obj/item/organ/internal/lungs/corrupt/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/breather) + . = ..() + if (!. || IS_IN_MANSUS(owner) || breather.has_reagent(/datum/reagent/water/holywater) || !prob(cough_chance)) + return + breather.emote("cough"); + var/chosen_gas = pick_weight(gas_types) + var/datum/gas_mixture/mix_to_spawn = new() + mix_to_spawn.add_gas(pick(chosen_gas)) + mix_to_spawn.gases[chosen_gas][MOLES] = gas_amount + mix_to_spawn.temperature = breather.bodytemperature + log_atmos("[owner] coughed some gas into the air due to their corrupted lungs.", mix_to_spawn) + var/turf/open/our_turf = get_turf(breather) + our_turf.assume_air(mix_to_spawn) + + +/// It's full of worms +/obj/item/organ/internal/appendix/corrupt + name = "corrupt appendix" + desc = "What kind of dark, cosmic force is even going to bother to corrupt an appendix?" + /// How likely are we to spawn worms? + var/worm_chance = 2 + +/obj/item/organ/internal/appendix/corrupt/Initialize(mapload) + . = ..() + AddElement(/datum/element/corrupted_organ) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their abdomen is distended... and wiggling.", BODY_ZONE_PRECISE_GROIN) + +/obj/item/organ/internal/appendix/corrupt/on_life(seconds_per_tick, times_fired) + . = ..() + if (owner.stat != CONSCIOUS || owner.has_reagent(/datum/reagent/water/holywater) || IS_IN_MANSUS(owner) || !SPT_PROB(worm_chance, seconds_per_tick)) + return + owner.vomit(MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM, vomit_type = /obj/effect/decal/cleanable/vomit/nebula/worms, distance = 0) + owner.Knockdown(0.5 SECONDS) diff --git a/code/modules/antagonists/heretic/items/forbidden_book.dm b/code/modules/antagonists/heretic/items/forbidden_book.dm index ad6bc3888006a..06f091c77e762 100644 --- a/code/modules/antagonists/heretic/items/forbidden_book.dm +++ b/code/modules/antagonists/heretic/items/forbidden_book.dm @@ -39,11 +39,11 @@ if(book_open) close_animation() RemoveElement(/datum/element/heretic_focus) - w_class = WEIGHT_CLASS_SMALL + update_weight_class(WEIGHT_CLASS_SMALL) else open_animation() AddElement(/datum/element/heretic_focus) - w_class = WEIGHT_CLASS_NORMAL + update_weight_class(WEIGHT_CLASS_NORMAL) /obj/item/codex_cicatrix/afterattack(atom/target, mob/user, proximity_flag, click_parameters) . = ..() diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm index 81f9b4bc80a9f..5ad8aed9ef978 100644 --- a/code/modules/antagonists/heretic/items/heretic_blades.dm +++ b/code/modules/antagonists/heretic/items/heretic_blades.dm @@ -23,6 +23,14 @@ attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends") attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend") var/after_use_message = "" + //set owner to find where blade linked + var/datum/antagonist/heretic/owner + +/obj/item/melee/sickly_blade/Destroy() + if(!isnull(owner)) + LAZYREMOVE(owner.blades_list, src) + owner = null + return ..() /obj/item/melee/sickly_blade/attack(mob/living/M, mob/living/user) if(!IS_HERETIC_OR_MONSTER(user)) diff --git a/code/modules/antagonists/heretic/knowledge/ash_lore.dm b/code/modules/antagonists/heretic/knowledge/ash_lore.dm index fe10f7949eae5..9386611304292 100644 --- a/code/modules/antagonists/heretic/knowledge/ash_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/ash_lore.dm @@ -214,7 +214,7 @@ priority_announce( text = "[generate_heretic_text()] Fear the blaze, for the Ashlord, [user.real_name] has ascended! The flames shall consume all! [generate_heretic_text()]", title = "[generate_heretic_text()]", - sound = ANNOUNCER_SPANOMALIES, + sound = 'sound/ambience/antag/heretic/ascend_ash.ogg', color_override = "pink", ) diff --git a/code/modules/antagonists/heretic/knowledge/blade_lore.dm b/code/modules/antagonists/heretic/knowledge/blade_lore.dm index 93983c41e0d7d..6553353745517 100644 --- a/code/modules/antagonists/heretic/knowledge/blade_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/blade_lore.dm @@ -406,7 +406,7 @@ priority_announce( text = "[generate_heretic_text()] Master of blades, the Torn Champion's disciple, [user.real_name] has ascended! Their steel is that which will cut reality in a maelstom of silver! [generate_heretic_text()]", title = "[generate_heretic_text()]", - sound = ANNOUNCER_SPANOMALIES, + sound = 'sound/ambience/antag/heretic/ascend_blade.ogg', color_override = "pink", ) user.client?.give_award(/datum/award/achievement/misc/blade_ascension, user) diff --git a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm index 09efb5c2eb8f4..6e22ebc37900a 100644 --- a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm @@ -22,7 +22,6 @@ * Cosmic Expansion * > Sidepaths: * Eldritch Coin - * Rusted Ritual * * Creators's Gift */ @@ -118,6 +117,7 @@ /datum/heretic_knowledge/blade_upgrade/cosmic, /datum/heretic_knowledge/reroll_targets, /datum/heretic_knowledge/curse/corrosion, + /datum/heretic_knowledge/summon/rusty, /datum/heretic_knowledge/spell/space_phase, ) spell_to_add = /datum/action/cooldown/spell/pointed/projectile/star_blast @@ -229,7 +229,6 @@ next_knowledge = list( /datum/heretic_knowledge/ultimate/cosmic_final, /datum/heretic_knowledge/eldritch_coin, - /datum/heretic_knowledge/summon/rusty, ) spell_to_add = /datum/action/cooldown/spell/conjure/cosmic_expansion cost = 1 @@ -271,7 +270,7 @@ priority_announce( text = "[generate_heretic_text()] A Star Gazer has arrived into the station, [user.real_name] has ascended! This station is the domain of the Cosmos! [generate_heretic_text()]", title = "[generate_heretic_text()]", - sound = ANNOUNCER_SPANOMALIES, + sound = 'sound/ambience/antag/heretic/ascend_cosmic.ogg', color_override = "pink", ) var/mob/living/basic/heretic_summon/star_gazer/star_gazer_mob = new /mob/living/basic/heretic_summon/star_gazer(loc) diff --git a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm index 8898ba7f59c66..4a7b2fd205297 100644 --- a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm @@ -314,7 +314,7 @@ priority_announce( text = "[generate_heretic_text()] Ever coiling vortex. Reality unfolded. ARMS OUTREACHED, THE LORD OF THE NIGHT, [user.real_name] has ascended! Fear the ever twisting hand! [generate_heretic_text()]", title = "[generate_heretic_text()]", - sound = ANNOUNCER_SPANOMALIES, + sound = 'sound/ambience/antag/heretic/ascend_flesh.ogg', color_override = "pink", ) diff --git a/code/modules/antagonists/heretic/knowledge/lock_lore.dm b/code/modules/antagonists/heretic/knowledge/lock_lore.dm index 0727b86bb668e..2807167d819fb 100644 --- a/code/modules/antagonists/heretic/knowledge/lock_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/lock_lore.dm @@ -224,7 +224,7 @@ priority_announce( text = "Delta-class dimensional anomaly detec[generate_heretic_text()] Reality rended, torn. Gates open, doors open, [user.real_name] has ascended! Fear the tide! [generate_heretic_text()]", title = "[generate_heretic_text()]", - sound = ANNOUNCER_SPANOMALIES, + sound = 'sound/ambience/antag/heretic/ascend_knock.ogg', color_override = "pink", ) user.client?.give_award(/datum/award/achievement/misc/lock_ascension, user) diff --git a/code/modules/antagonists/heretic/knowledge/moon_lore.dm b/code/modules/antagonists/heretic/knowledge/moon_lore.dm index 723599ad262f5..b708bf6584e9c 100644 --- a/code/modules/antagonists/heretic/knowledge/moon_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/moon_lore.dm @@ -189,8 +189,13 @@ /datum/heretic_knowledge/ultimate/moon_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user) - priority_announce("[generate_heretic_text()] Laugh, for the ringleader [user.real_name] has ascended! \ - The truth shall finally devour the lie! [generate_heretic_text()]","[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) + priority_announce( + text = "[generate_heretic_text()] Laugh, for the ringleader [user.real_name] has ascended! \ + The truth shall finally devour the lie! [generate_heretic_text()]", + title = "[generate_heretic_text()]", + sound = 'sound/ambience/antag/heretic/ascend_moon.ogg', + color_override = "pink", + ) user.client?.give_award(/datum/award/achievement/misc/moon_ascension, user) ADD_TRAIT(user, TRAIT_MADNESS_IMMUNE, REF(src)) diff --git a/code/modules/antagonists/heretic/knowledge/rust_lore.dm b/code/modules/antagonists/heretic/knowledge/rust_lore.dm index 8d577b1992a2e..fe553c8b8c779 100644 --- a/code/modules/antagonists/heretic/knowledge/rust_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/rust_lore.dm @@ -46,7 +46,8 @@ /datum/heretic_knowledge/rust_fist name = "Grasp of Rust" desc = "Your Mansus Grasp will deal 500 damage to non-living matter and rust any surface it touches. \ - Already rusted surfaces are destroyed. Surfaces and structures can only be rusted by using Right-Click." + Already rusted surfaces are destroyed. Surfaces and structures can only be rusted by using Right-Click. \ + Allows you to rust basic iron walls and floors." gain_text = "On the ceiling of the Mansus, rust grows as moss does on a stone." next_knowledge = list(/datum/heretic_knowledge/rust_regen) cost = 1 @@ -55,6 +56,7 @@ /datum/heretic_knowledge/rust_fist/on_gain(mob/user, datum/antagonist/heretic/our_heretic) RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp)) RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY, PROC_REF(on_secondary_mansus_grasp)) + our_heretic.increase_rust_strength() /datum/heretic_knowledge/rust_fist/on_lose(mob/user, datum/antagonist/heretic/our_heretic) UnregisterSignal(user, list(COMSIG_HERETIC_MANSUS_GRASP_ATTACK, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY)) @@ -65,7 +67,7 @@ if(!issilicon(target) && !(target.mob_biotypes & MOB_ROBOTIC)) return - target.rust_heretic_act() + source.do_rust_heretic_act(target) /datum/heretic_knowledge/rust_fist/proc/on_secondary_mansus_grasp(mob/living/source, atom/target) SIGNAL_HANDLER @@ -76,7 +78,7 @@ var/obj/machinery/door/airlock/airlock = target airlock.loseMainPower() - target.rust_heretic_act() + source.do_rust_heretic_act(target) return COMPONENT_USE_HAND /datum/heretic_knowledge/rust_regen @@ -129,11 +131,11 @@ // Heals all damage + Stamina var/need_mob_update = FALSE - need_mob_update += source.adjustBruteLoss(-2, updating_health = FALSE) - need_mob_update += source.adjustFireLoss(-2, updating_health = FALSE) - need_mob_update += source.adjustToxLoss(-2, updating_health = FALSE, forced = TRUE) // Slimes are people too - need_mob_update += source.adjustOxyLoss(-0.5, updating_health = FALSE) - need_mob_update += source.adjustStaminaLoss(-2, updating_stamina = FALSE) + need_mob_update += source.adjustBruteLoss(-3, updating_health = FALSE) + need_mob_update += source.adjustFireLoss(-3, updating_health = FALSE) + need_mob_update += source.adjustToxLoss(-3, updating_health = FALSE, forced = TRUE) // Slimes are people too + need_mob_update += source.adjustOxyLoss(-1.5, updating_health = FALSE) + need_mob_update += source.adjustStaminaLoss(-10, updating_stamina = FALSE) if(need_mob_update) source.updatehealth() // Reduces duration of stuns/etc @@ -141,16 +143,23 @@ // Heals blood loss if(source.blood_volume < BLOOD_VOLUME_NORMAL) source.blood_volume += 2.5 * seconds_per_tick + // Slowly regulates your body temp + source.adjust_bodytemperature((source.get_body_temp_normal() - source.bodytemperature)/5) /datum/heretic_knowledge/mark/rust_mark name = "Mark of Rust" desc = "Your Mansus Grasp now applies the Mark of Rust. The mark is triggered from an attack with your Rusty Blade. \ - When triggered, the victim's organs and equipment will have a 75% chance to sustain damage and may be destroyed." + When triggered, your victim will suffer heavy disgust and confusion. \ + Allows you to rust reinforced walls and floors as well as plasteel." gain_text = "The Blacksmith looks away. To a place lost long ago. \"Rusted Hills help those in dire need... at a cost.\"" next_knowledge = list(/datum/heretic_knowledge/knowledge_ritual/rust) route = PATH_RUST mark_type = /datum/status_effect/eldritch/rust +/datum/heretic_knowledge/mark/rust_mark/on_gain(mob/user, datum/antagonist/heretic/our_heretic) + . = ..() + our_heretic.increase_rust_strength() + /datum/heretic_knowledge/knowledge_ritual/rust next_knowledge = list(/datum/heretic_knowledge/spell/rust_construction) route = PATH_RUST @@ -169,12 +178,13 @@ /datum/heretic_knowledge/spell/area_conversion name = "Aggressive Spread" desc = "Grants you Aggressive Spread, a spell that spreads rust to nearby surfaces. \ - Already rusted surfaces are destroyed." + Already rusted surfaces are destroyed \ Also improves the rusting abilities of non rust-heretics." gain_text = "All wise men know well not to visit the Rusted Hills... Yet the Blacksmith's tale was inspiring." next_knowledge = list( /datum/heretic_knowledge/blade_upgrade/rust, /datum/heretic_knowledge/reroll_targets, /datum/heretic_knowledge/curse/corrosion, + /datum/heretic_knowledge/summon/rusty, /datum/heretic_knowledge/crucible, /datum/heretic_knowledge/rifle, ) @@ -182,41 +192,54 @@ cost = 1 route = PATH_RUST +/datum/heretic_knowledge/spell/area_conversion/on_gain(mob/user, datum/antagonist/heretic/our_heretic) + . = ..() + our_heretic.increase_rust_strength(TRUE) + /datum/heretic_knowledge/blade_upgrade/rust name = "Toxic Blade" - desc = "Your Rusty Blade now poisons enemies on attack." + desc = "Your Rusty Blade now disgusts enemies on attack \ Allows you to rust Titanium and Plastitanium.." gain_text = "The Blacksmith hands you their blade. \"The Blade will guide you through the flesh, should you let it.\" \ The heavy rust weights it down. You stare deeply into it. The Rusted Hills call for you, now." next_knowledge = list(/datum/heretic_knowledge/spell/entropic_plume) route = PATH_RUST +/datum/heretic_knowledge/blade_upgrade/rust/on_gain(mob/user, datum/antagonist/heretic/our_heretic) + . = ..() + our_heretic.increase_rust_strength() + /datum/heretic_knowledge/blade_upgrade/rust/do_melee_effects(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade) - // No user == target check here, cause it's technically good for the heretic? - target.reagents?.add_reagent(/datum/reagent/eldritch, 5) + target.adjust_disgust(50) +/datum/heretic_knowledge/spell/area_conversion/on_gain(mob/user, datum/antagonist/heretic/our_heretic) + . = ..() /datum/heretic_knowledge/spell/entropic_plume name = "Entropic Plume" desc = "Grants you Entropic Plume, a spell that releases a vexing wave of Rust. \ Blinds, poisons, and inflicts Amok on any heathen it hits, causing them to strike \ - at friend or foe wildly. Also rusts and destroys and surfaces it hits." + at friend or foe wildly. Also rusts and destroys and surfaces it hits and improves the rusting abilities of non-rust heretics." gain_text = "The corrosion was unstoppable. The rust was unpleasable. \ The Blacksmith was gone, and you hold their blade. Champions of hope, the Rustbringer is nigh!" next_knowledge = list( /datum/heretic_knowledge/ultimate/rust_final, - /datum/heretic_knowledge/summon/rusty, /datum/heretic_knowledge/spell/rust_charge, ) spell_to_add = /datum/action/cooldown/spell/cone/staggered/entropic_plume cost = 1 route = PATH_RUST +/datum/heretic_knowledge/spell/entropic_plume/on_gain(mob/user) + . = ..() + var/datum/antagonist/heretic/our_heretic = IS_HERETIC(user) + our_heretic.increase_rust_strength(TRUE) + /datum/heretic_knowledge/ultimate/rust_final name = "Rustbringer's Oath" desc = "The ascension ritual of the Path of Rust. \ Bring 3 corpses to a transmutation rune on the bridge of the station to complete the ritual. \ When completed, the ritual site will endlessly spread rust onto any surface, stopping for nothing. \ Additionally, you will become extremely resilient on rust, healing at triple the rate \ - and becoming immune to many effects and dangers." + and becoming immune to many effects and dangers \ You will be able to rust almost anything upon ascending." gain_text = "Champion of rust. Corruptor of steel. Fear the dark, for the RUSTBRINGER has come! \ The Blacksmith forges ahead! Rusted Hills, CALL MY NAME! WITNESS MY ASCENSION!" route = PATH_RUST @@ -227,6 +250,8 @@ /// A static list of traits we give to the heretic when on rust. var/static/list/conditional_immunities = list( TRAIT_BOMBIMMUNE, + TRAIT_IGNOREDAMAGESLOWDOWN, + TRAIT_IGNORESLOWDOWN, TRAIT_NO_SLIP_ALL, TRAIT_NOBREATH, TRAIT_PIERCEIMMUNE, @@ -262,13 +287,49 @@ priority_announce( text = "[generate_heretic_text()] Fear the decay, for the Rustbringer, [user.real_name] has ascended! None shall escape the corrosion! [generate_heretic_text()]", title = "[generate_heretic_text()]", - sound = ANNOUNCER_SPANOMALIES, + sound = 'sound/ambience/antag/heretic/ascend_rust.ogg', color_override = "pink", ) - new /datum/rust_spread(loc) + trigger(loc) RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) RegisterSignal(user, COMSIG_LIVING_LIFE, PROC_REF(on_life)) user.client?.give_award(/datum/award/achievement/misc/rust_ascension, user) + var/datum/action/cooldown/spell/aoe/rust_conversion/rust_spread_spell = locate() in user.actions + rust_spread_spell?.cooldown_time /= 2 + +// I sure hope this doesn't have performance implications +/datum/heretic_knowledge/ultimate/rust_final/proc/trigger(turf/center) + var/greatest_dist = 0 + var/list/turfs_to_transform = list() + for (var/turf/transform_turf as anything in GLOB.station_turfs) + if (transform_turf.turf_flags & NO_RUST) + continue + var/dist = get_dist(center, transform_turf) + if (dist > greatest_dist) + greatest_dist = dist + if (!turfs_to_transform["[dist]"]) + turfs_to_transform["[dist]"] = list() + turfs_to_transform["[dist]"] += transform_turf + + for (var/iterator in 1 to greatest_dist) + if(!turfs_to_transform["[iterator]"]) + continue + addtimer(CALLBACK(src, PROC_REF(transform_area), turfs_to_transform["[iterator]"]), (5 SECONDS) * iterator) + +/datum/heretic_knowledge/ultimate/rust_final/proc/transform_area(list/turfs) + turfs = shuffle(turfs) + var/numturfs = length(turfs) + var/first_third = turfs.Copy(1, round(numturfs * 0.33)) + var/second_third = turfs.Copy(round(numturfs * 0.33), round(numturfs * 0.66)) + var/third_third = turfs.Copy(round(numturfs * 0.66), numturfs) + addtimer(CALLBACK(src, PROC_REF(delay_transform_turfs), first_third), 5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(delay_transform_turfs), second_third), 5 SECONDS * 0.33) + addtimer(CALLBACK(src, PROC_REF(delay_transform_turfs), third_third), 5 SECONDS * 0.66) + +/datum/heretic_knowledge/ultimate/rust_final/proc/delay_transform_turfs(list/turfs) + for(var/turf/turf as anything in turfs) + turf.rust_heretic_act(5) + CHECK_TICK /** * Signal proc for [COMSIG_MOVABLE_MOVED]. @@ -304,85 +365,12 @@ return var/need_mob_update = FALSE - need_mob_update += source.adjustBruteLoss(-4, updating_health = FALSE) - need_mob_update += source.adjustFireLoss(-4, updating_health = FALSE) - need_mob_update += source.adjustToxLoss(-4, updating_health = FALSE, forced = TRUE) - need_mob_update += source.adjustOxyLoss(-4, updating_health = FALSE) + need_mob_update += source.adjustBruteLoss(-5, updating_health = FALSE) + need_mob_update += source.adjustFireLoss(-5, updating_health = FALSE) + need_mob_update += source.adjustToxLoss(-5, updating_health = FALSE, forced = TRUE) + need_mob_update += source.adjustOxyLoss(-5, updating_health = FALSE) need_mob_update += source.adjustStaminaLoss(-20, updating_stamina = FALSE) + if(source.blood_volume < BLOOD_VOLUME_NORMAL) + source.blood_volume += 5 * seconds_per_tick if(need_mob_update) source.updatehealth() - -/** - * #Rust spread datum - * - * Simple datum that automatically spreads rust around it. - * - * Simple implementation of automatically growing entity. - */ -/datum/rust_spread - /// The rate of spread every tick. - var/spread_per_sec = 6 - /// The very center of the spread. - var/turf/centre - /// List of turfs at the edge of our rust (but not yet rusted). - var/list/edge_turfs = list() - /// List of all turfs we've afflicted. - var/list/rusted_turfs = list() - /// Static blacklist of turfs we can't spread to. - var/static/list/blacklisted_turfs = typecacheof(list( - /turf/open/indestructible, - /turf/closed/indestructible, - /turf/open/space, - /turf/open/lava, - /turf/open/chasm - )) - -/datum/rust_spread/New(loc) - centre = get_turf(loc) - centre.rust_heretic_act() - rusted_turfs += centre - START_PROCESSING(SSprocessing, src) - -/datum/rust_spread/Destroy(force) - centre = null - edge_turfs.Cut() - rusted_turfs.Cut() - STOP_PROCESSING(SSprocessing, src) - return ..() - -/datum/rust_spread/process(seconds_per_tick) - var/spread_amount = round(spread_per_sec * seconds_per_tick) - - if(length(edge_turfs) < spread_amount) - compile_turfs() - - for(var/i in 0 to spread_amount) - if(!length(edge_turfs)) - break - var/turf/afflicted_turf = pick_n_take(edge_turfs) - afflicted_turf.rust_heretic_act() - rusted_turfs |= afflicted_turf - -/** - * Compile turfs - * - * Recreates the edge_turfs list. - * Updates the rusted_turfs list, in case any turfs within were un-rusted. - */ -/datum/rust_spread/proc/compile_turfs() - edge_turfs.Cut() - - var/max_dist = 1 - for(var/turf/found_turf as anything in rusted_turfs) - if(!HAS_TRAIT(found_turf, TRAIT_RUSTY)) - rusted_turfs -= found_turf - max_dist = max(max_dist, get_dist(found_turf, centre) + 1) - - for(var/turf/nearby_turf as anything in spiral_range_turfs(max_dist, centre, FALSE)) - if(nearby_turf in rusted_turfs || is_type_in_typecache(nearby_turf, blacklisted_turfs)) - continue - - for(var/turf/line_turf as anything in get_line(nearby_turf, centre)) - if(get_dist(nearby_turf, line_turf) <= 1) - edge_turfs |= nearby_turf - CHECK_TICK diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm index 3749e37fe6af1..30757e88a4b29 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm @@ -107,3 +107,17 @@ return bloodiest_wound.adjust_blood_flow(-0.5 * seconds_between_ticks) + +/// Torment the target with a frightening hand +/proc/fire_curse_hand(mob/living/carbon/victim) + var/grab_dir = turn(victim.dir, pick(-90, 90, 180, 180)) // Not in front, favour behind + var/turf/spawn_turf = get_ranged_target_turf(victim, grab_dir, 8) + if (isnull(spawn_turf)) + return + new /obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, victim.dir) + playsound(spawn_turf, 'sound/effects/curse2.ogg', 80, TRUE, -1) + var/obj/projectile/curse_hand/hel/hand = new (spawn_turf) + hand.preparePixelProjectile(victim, spawn_turf) + if (QDELETED(hand)) // safety check if above fails - above has a stack trace if it does fail + return + hand.fire() diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_curse.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_curse.dm new file mode 100644 index 0000000000000..87086de6e0024 --- /dev/null +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_curse.dm @@ -0,0 +1,93 @@ +/// A curse given to people to disencourage them from retaliating against someone who sacrificed them +/datum/status_effect/heretic_curse + id = "heretic_curse" + alert_type = null + status_type = STATUS_EFFECT_MULTIPLE // In case several different people sacrifice you, unlucky + /// Who cursed us? + var/mob/living/the_curser + /// Don't experience bad things too often + COOLDOWN_DECLARE(consequence_cooldown) + +/datum/status_effect/heretic_curse/on_creation(mob/living/new_owner, mob/living/the_curser) + src.the_curser = the_curser + return ..() + +/datum/status_effect/heretic_curse/Destroy() + the_curser = null + return ..() + +/datum/status_effect/heretic_curse/on_apply() + if (isnull(the_curser) || !iscarbon(owner)) + return FALSE + + the_curser.AddElement(/datum/element/relay_attackers) + RegisterSignal(the_curser, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_curser_attacked)) + RegisterSignal(the_curser, COMSIG_QDELETING, PROC_REF(on_curser_destroyed)) + + owner.AddElement(/datum/element/relay_attackers) + RegisterSignal(owner, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_owner_attacked)) + + return TRUE + +/datum/status_effect/heretic_curse/on_remove() + UnregisterSignal(owner, COMSIG_ATOM_WAS_ATTACKED) + UnregisterSignal(the_curser, COMSIG_ATOM_WAS_ATTACKED) + the_curser = null + + +/// If the heretic that cursed us is destroyed this thing is useless now +/datum/status_effect/heretic_curse/proc/on_curser_destroyed() + SIGNAL_HANDLER + qdel(src) + +/// If we attack the guy who cursed us, that's no good +/datum/status_effect/heretic_curse/proc/on_curser_attacked(datum/source, mob/attacker) + SIGNAL_HANDLER + if (attacker != owner || !HAS_TRAIT(source, TRAIT_ALLOW_HERETIC_CASTING)) + return + log_combat(owner, the_curser, "attacked", addition = "and lost some organs because they had previously been sacrificed by them.") + experience_the_consequences() + +/// If we are attacked by the guy who cursed us, that's also no good +/datum/status_effect/heretic_curse/proc/on_owner_attacked(datum/source, mob/attacker) + SIGNAL_HANDLER + if (attacker != the_curser || !HAS_TRAIT(attacker, TRAIT_ALLOW_HERETIC_CASTING)) + return + log_combat(the_curser, owner, "attacked", addition = "and as they had previously sacrificed them, removed some of their organs.") + experience_the_consequences() + +/// Experience something you may not enjoy which may also significantly shorten your lifespan +/datum/status_effect/heretic_curse/proc/experience_the_consequences() + if (!COOLDOWN_FINISHED(src, consequence_cooldown) || owner.stat != CONSCIOUS) + return + + var/mob/living/carbon/carbon_owner = owner + var/obj/item/bodypart/chest/organ_storage = owner.get_bodypart(BODY_ZONE_CHEST) + if (isnull(organ_storage)) + carbon_owner.gib() // IDK how you don't have a chest but you're not getting away that easily + return + + var/list/removable_organs = list() + for(var/obj/item/organ/internal/bodypart_organ in organ_storage.contents) + if(bodypart_organ.organ_flags & ORGAN_UNREMOVABLE) + continue + removable_organs += bodypart_organ + + if (!length(removable_organs)) + return // This one is a little more possible but they're probably already in pretty bad shape by this point + + var/obj/item/organ/internal/removing_organ = pick(removable_organs) + + if (carbon_owner.vomit(vomit_flags = VOMIT_CATEGORY_BLOOD)) + carbon_owner.visible_message(span_boldwarning("[carbon_owner] vomits out [carbon_owner.p_their()] [removing_organ]")) + else + carbon_owner.visible_message(span_boldwarning("[carbon_owner]'s [removing_organ] rips itself out of `[carbon_owner.p_their()] chest!")) + + removing_organ.Remove(carbon_owner) + + var/turf/land_turf = get_step(carbon_owner, carbon_owner.dir) + if (land_turf.is_blocked_turf(exclude_mobs = TRUE)) + land_turf = carbon_owner.drop_location() + + removing_organ.forceMove(land_turf) + COOLDOWN_START(src, consequence_cooldown, 10 SECONDS) diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm index 797d754ea0b0b..1d2be465b3026 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm @@ -26,6 +26,16 @@ var/list/datum/mind/target_blacklist /// An assoc list of [ref] to [timers] - a list of all the timers of people in the shadow realm currently var/list/return_timers + /// Evil organs we can put in people + var/static/list/grantable_organs = list( + /obj/item/organ/internal/appendix/corrupt, + /obj/item/organ/internal/eyes/corrupt, + /obj/item/organ/internal/heart/corrupt, + /obj/item/organ/internal/liver/corrupt, + /obj/item/organ/internal/lungs/corrupt, + /obj/item/organ/internal/stomach/corrupt, + /obj/item/organ/internal/tongue/corrupt, + ) /datum/heretic_knowledge/hunt_and_sacrifice/Destroy(force) heretic_mind = null @@ -197,6 +207,8 @@ heretic_datum.total_sacrifices++ heretic_datum.knowledge_points += 2 + sacrifice.apply_status_effect(/datum/status_effect/heretic_curse, user) + if(!begin_sacrifice(sacrifice)) disembowel_target(sacrifice) @@ -278,6 +290,8 @@ disembowel_target(sac_target) return + curse_organs(sac_target) + // Send 'em to the destination. If the teleport fails, just disembowel them and stop the chain if(!destination || !do_teleport(sac_target, destination, asoundin = 'sound/magic/repulse.ogg', asoundout = 'sound/magic/blind.ogg', no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC, forced = TRUE)) disembowel_target(sac_target) @@ -299,6 +313,31 @@ RegisterSignal(sac_target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_target_escape)) // Cheese condition RegisterSignal(sac_target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) // Loss condition +/// Apply a sinister curse to some of the target's organs as an incentive to leave us alone +/datum/heretic_knowledge/hunt_and_sacrifice/proc/curse_organs(mob/living/carbon/human/sac_target) + var/usable_organs = grantable_organs.Copy() + if (isplasmaman(sac_target)) + usable_organs -= /obj/item/organ/internal/lungs/corrupt // Their lungs are already more cursed than anything I could give them + + var/total_implant = rand(2, 4) + var/gave_any = FALSE + + for (var/i in 1 to total_implant) + if (!length(usable_organs)) + break + var/organ_path = pick_n_take(usable_organs) + var/obj/item/organ/internal/to_give = new organ_path + if (!to_give.Insert(sac_target)) + qdel(to_give) + else + gave_any = TRUE + + if (!gave_any) + return + + new /obj/effect/gibspawner/human/bodypartless(get_turf(sac_target)) + sac_target.visible_message(span_boldwarning("Several organs force themselves out of [sac_target]!")) + /** * This proc is called from [proc/after_target_sleeps] when the [sac_target] should be waking up.) * @@ -375,8 +414,7 @@ if(IS_HERETIC(sac_target)) var/datum/antagonist/heretic/victim_heretic = sac_target.mind?.has_antag_datum(/datum/antagonist/heretic) victim_heretic.knowledge_points -= 3 - else - sac_target.gain_trauma(/datum/brain_trauma/mild/phobia/heresy, TRAUMA_RESILIENCE_MAGIC) + // Wherever we end up, we sure as hell won't be able to explain sac_target.adjust_timed_status_effect(40 SECONDS, /datum/status_effect/speech/slurring/heretic) sac_target.adjust_stutter(40 SECONDS) diff --git a/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm b/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm index 3d326b4a9af45..671e01603c5c7 100644 --- a/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm +++ b/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm @@ -20,22 +20,22 @@ /datum/heretic_knowledge/entropy_pulse name = "Pulse of Entropy" - desc = "Allows you to transmute 20 irons and 2 garbage items to fill the surrounding vicinity of the rune with rust." + desc = "Allows you to transmute 10 iron sheets and a garbage item to fill the surrounding vicinity of the rune with rust." gain_text = "Reality begins to whisper to me. To give it its entropic end." required_atoms = list( - /obj/item/stack/sheet/iron = 20, - /obj/item/trash = 2 + /obj/item/stack/sheet/iron = 10, + /obj/item/trash = 1, ) cost = 0 route = PATH_SIDE - var/rusting_range = 4 + var/rusting_range = 8 /datum/heretic_knowledge/entropy_pulse/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) for(var/turf/nearby_turf in view(rusting_range, loc)) if(get_dist(nearby_turf, loc) <= 1) //tiles on rune should always be rusted nearby_turf.rust_heretic_act() //we exclude closed turf to avoid exposing cultist bases - if(prob(20) || isclosedturf(nearby_turf)) + if(prob(10) || isclosedturf(nearby_turf)) continue nearby_turf.rust_heretic_act() return TRUE @@ -76,17 +76,17 @@ /datum/heretic_knowledge/summon/rusty name = "Rusted Ritual" - desc = "Allows you to transmute a pool of vomit, a book, and a head into a Rust Walker. \ + desc = "Allows you to transmute a pool of vomit, some cable coil, and 5 sheets of iron into a Rust Walker. \ Rust Walkers excel at spreading rust and are moderately strong in combat." gain_text = "I combined my knowledge of creation with my desire for corruption. The Marshal knew my name, and the Rusted Hills echoed out." next_knowledge = list( - /datum/heretic_knowledge/spell/entropic_plume, - /datum/heretic_knowledge/spell/cosmic_expansion, + /datum/heretic_knowledge/spell/area_conversion, + /datum/heretic_knowledge/spell/star_blast, ) required_atoms = list( /obj/effect/decal/cleanable/vomit = 1, - /obj/item/book = 1, - /obj/item/bodypart/head = 1, + /obj/item/stack/sheet/iron = 5, + /obj/item/stack/cable_coil = 15, ) mob_to_summon = /mob/living/basic/heretic_summon/rust_walker cost = 1 diff --git a/code/modules/antagonists/heretic/knowledge/starting_lore.dm b/code/modules/antagonists/heretic/knowledge/starting_lore.dm index f1b5f7f55ea19..1c9f39cb66006 100644 --- a/code/modules/antagonists/heretic/knowledge/starting_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/starting_lore.dm @@ -293,3 +293,4 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge()) body.do_jitter_animation() body.visible_message(span_danger("An awful ripping sound is heard as [ripped_thing]'s [exterior_text] is ripped straight out, wrapping around [le_book || "the book"], turning into an eldritch shade of blue!")) return ..() + diff --git a/code/modules/antagonists/heretic/knowledge/void_lore.dm b/code/modules/antagonists/heretic/knowledge/void_lore.dm index 85015c06e1f16..da1864f87dbc5 100644 --- a/code/modules/antagonists/heretic/knowledge/void_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/void_lore.dm @@ -202,7 +202,7 @@ priority_announce( text = "[generate_heretic_text()] The nobleman of void [user.real_name] has arrived, stepping along the Waltz that ends worlds! [generate_heretic_text()]", title = "[generate_heretic_text()]", - sound = ANNOUNCER_SPANOMALIES, + sound = 'sound/ambience/antag/heretic/ascend_void.ogg', color_override = "pink", ) user.client?.give_award(/datum/award/achievement/misc/void_ascension, user) diff --git a/code/modules/antagonists/heretic/magic/aggressive_spread.dm b/code/modules/antagonists/heretic/magic/aggressive_spread.dm index de1233382f646..fedc30193ed48 100644 --- a/code/modules/antagonists/heretic/magic/aggressive_spread.dm +++ b/code/modules/antagonists/heretic/magic/aggressive_spread.dm @@ -14,12 +14,12 @@ invocation_type = INVOCATION_WHISPER spell_requirements = NONE - aoe_radius = 3 + aoe_radius = 2 /datum/action/cooldown/spell/aoe/rust_conversion/get_things_to_cast_on(atom/center) return RANGE_TURFS(aoe_radius, center) -/datum/action/cooldown/spell/aoe/rust_conversion/cast_on_thing_in_aoe(turf/victim, atom/caster) +/datum/action/cooldown/spell/aoe/rust_conversion/cast_on_thing_in_aoe(turf/victim, mob/living/caster) // We have less chance of rusting stuff that's further var/distance_to_caster = get_dist(victim, caster) var/chance_of_not_rusting = (max(distance_to_caster, 1) - 1) * 100 / (aoe_radius + 1) @@ -27,7 +27,7 @@ if(prob(chance_of_not_rusting)) return - victim.rust_heretic_act() + caster.do_rust_heretic_act(victim) /datum/action/cooldown/spell/aoe/rust_conversion/small name = "Rust Conversion" diff --git a/code/modules/antagonists/heretic/magic/cosmic_runes.dm b/code/modules/antagonists/heretic/magic/cosmic_runes.dm index 4af3b94b44f34..207b60ae9393a 100644 --- a/code/modules/antagonists/heretic/magic/cosmic_runes.dm +++ b/code/modules/antagonists/heretic/magic/cosmic_runes.dm @@ -113,7 +113,7 @@ var/oldcolor = rgb(255, 255, 255) color = rgb(150, 50, 200) animate(src, color = oldcolor, time = 5) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 5) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.5 SECONDS) /// For linking a new rune /obj/effect/cosmic_rune/proc/link_rune(datum/weakref/new_rune) diff --git a/code/modules/antagonists/heretic/magic/flesh_surgery.dm b/code/modules/antagonists/heretic/magic/flesh_surgery.dm index 12b3fcfbcaf33..2ca256419efca 100644 --- a/code/modules/antagonists/heretic/magic/flesh_surgery.dm +++ b/code/modules/antagonists/heretic/magic/flesh_surgery.dm @@ -135,7 +135,7 @@ // Round u pto the nearest generic zone (body, chest, arm) var/zone_to_check = check_zone(caster.zone_selected) - var/parsed_zone = parse_zone(zone_to_check) + var/parsed_zone = victim.parse_zone_with_bodypart(zone_to_check) var/list/organs_we_can_remove = list() for(var/obj/item/organ/organ as anything in carbon_victim.organs) @@ -211,7 +211,7 @@ carbon_victim.emote("scream") // We need to wait for the spell to actually finish casting to put the organ in their hands, hence, 1 ms timer. - addtimer(CALLBACK(caster, TYPE_PROC_REF(/mob, put_in_hands), picked_organ), 1) + addtimer(CALLBACK(caster, TYPE_PROC_REF(/mob, put_in_hands), picked_organ), 0.1 SECONDS) return TRUE /// Extra checks ran while we're extracting an organ to make sure we can continue to do. diff --git a/code/modules/antagonists/heretic/magic/manse_link.dm b/code/modules/antagonists/heretic/magic/manse_link.dm index 565e7e683ebdf..06fd4dd9863f4 100644 --- a/code/modules/antagonists/heretic/magic/manse_link.dm +++ b/code/modules/antagonists/heretic/magic/manse_link.dm @@ -55,7 +55,7 @@ to_chat(owner, span_notice("You begin linking [linkee]'s mind to yours...")) to_chat(linkee, span_warning("You feel your mind being pulled somewhere... connected... intertwined with the very fabric of reality...")) - if(!do_after(owner, link_time, linkee)) + if(!do_after(owner, link_time, linkee, hidden = TRUE)) to_chat(owner, span_warning("You fail to link to [linkee]'s mind.")) to_chat(linkee, span_warning("The foreign presence leaves your mind.")) return FALSE diff --git a/code/modules/antagonists/heretic/magic/mirror_walk.dm b/code/modules/antagonists/heretic/magic/mirror_walk.dm index 0bc9b05902025..b9029e1ab072d 100644 --- a/code/modules/antagonists/heretic/magic/mirror_walk.dm +++ b/code/modules/antagonists/heretic/magic/mirror_walk.dm @@ -64,7 +64,7 @@ jaunter.Beam(nearby_reflection, icon_state = "light_beam", time = phase_out_time) nearby_reflection.visible_message(span_warning("[nearby_reflection] begins to shimmer and shake slightly!")) - if(!do_after(jaunter, phase_out_time, nearby_reflection, IGNORE_USER_LOC_CHANGE|IGNORE_INCAPACITATED)) + if(!do_after(jaunter, phase_out_time, nearby_reflection, IGNORE_USER_LOC_CHANGE|IGNORE_INCAPACITATED, hidden = TRUE)) return playsound(jaunter, 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1) @@ -96,7 +96,7 @@ nearby_reflection.Beam(phase_turf, icon_state = "light_beam", time = phase_in_time) nearby_reflection.visible_message(span_warning("[nearby_reflection] begins to shimmer and shake slightly!")) - if(!do_after(unjaunter, phase_in_time, nearby_reflection)) + if(!do_after(unjaunter, phase_in_time, nearby_reflection, hidden = TRUE)) return FALSE // We can move around while phasing in, but we'll always end up where we started it. diff --git a/code/modules/antagonists/heretic/magic/realignment.dm b/code/modules/antagonists/heretic/magic/realignment.dm index 081138b7181b9..d3ddc03fbbef3 100644 --- a/code/modules/antagonists/heretic/magic/realignment.dm +++ b/code/modules/antagonists/heretic/magic/realignment.dm @@ -53,6 +53,7 @@ duration = 8 SECONDS alert_type = /atom/movable/screen/alert/status_effect/realignment tick_interval = 0.2 SECONDS + show_duration = TRUE /datum/status_effect/realignment/get_examine_text() return span_notice("[owner.p_Theyre()] glowing a soft white.") diff --git a/code/modules/antagonists/heretic/magic/rust_wave.dm b/code/modules/antagonists/heretic/magic/rust_wave.dm index 5ca4b7da07e4b..65c5592b34e8b 100644 --- a/code/modules/antagonists/heretic/magic/rust_wave.dm +++ b/code/modules/antagonists/heretic/magic/rust_wave.dm @@ -24,15 +24,15 @@ . = ..() new /obj/effect/temp_visual/dir_setting/entropic(get_step(cast_on, cast_on.dir), cast_on.dir) -/datum/action/cooldown/spell/cone/staggered/entropic_plume/do_turf_cone_effect(turf/target_turf, atom/caster, level) - target_turf.rust_heretic_act() +/datum/action/cooldown/spell/cone/staggered/entropic_plume/do_turf_cone_effect(turf/target_turf, mob/living/caster, level) + caster.do_rust_heretic_act(target_turf) /datum/action/cooldown/spell/cone/staggered/entropic_plume/do_mob_cone_effect(mob/living/victim, atom/caster, level) if(victim.can_block_magic(antimagic_flags) || IS_HERETIC_OR_MONSTER(victim) || victim == caster) return victim.apply_status_effect(/datum/status_effect/amok) victim.apply_status_effect(/datum/status_effect/cloudstruck, level * 1 SECONDS) - victim.reagents?.add_reagent(/datum/reagent/eldritch, max(1, 6 - level)) + victim.adjust_disgust(100) /datum/action/cooldown/spell/cone/staggered/entropic_plume/calculate_cone_shape(current_level) // At the first level (that isn't level 1) we will be small diff --git a/code/modules/antagonists/heretic/magic/space_crawl.dm b/code/modules/antagonists/heretic/magic/space_crawl.dm index 69a15d812bb55..49677e3bb5086 100644 --- a/code/modules/antagonists/heretic/magic/space_crawl.dm +++ b/code/modules/antagonists/heretic/magic/space_crawl.dm @@ -69,6 +69,11 @@ RegisterSignal(holder, COMSIG_MOVABLE_MOVED, PROC_REF(update_status_on_signal)) if(iscarbon(jaunter)) jaunter.drop_all_held_items() + // Sanity check to ensure we didn't lose our focus as a result. + if(!HAS_TRAIT(jaunter, TRAIT_ALLOW_HERETIC_CASTING)) + REMOVE_TRAIT(jaunter, TRAIT_NO_TRANSFORM, REF(src)) + exit_jaunt(jaunter, our_turf) + return FALSE // Give them some space hands to prevent them from doing things var/obj/item/space_crawl/left_hand = new(jaunter) var/obj/item/space_crawl/right_hand = new(jaunter) @@ -77,6 +82,8 @@ jaunter.put_in_hands(left_hand) jaunter.put_in_hands(right_hand) + RegisterSignal(jaunter, SIGNAL_REMOVETRAIT(TRAIT_ALLOW_HERETIC_CASTING), PROC_REF(on_focus_lost)) + RegisterSignal(jaunter, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_change)) our_turf.visible_message(span_warning("[jaunter] sinks into [our_turf]!")) playsound(our_turf, 'sound/magic/cosmic_energy.ogg', 50, TRUE, -1) new /obj/effect/temp_visual/space_explosion(our_turf) @@ -88,8 +95,8 @@ /** * Attempts to Exit the passed space or misc turf. */ -/datum/action/cooldown/spell/jaunt/space_crawl/proc/try_exit_jaunt(turf/our_turf, mob/living/jaunter) - if(HAS_TRAIT_FROM(jaunter, TRAIT_NO_TRANSFORM, REF(src))) +/datum/action/cooldown/spell/jaunt/space_crawl/proc/try_exit_jaunt(turf/our_turf, mob/living/jaunter, force = FALSE) + if(!force && HAS_TRAIT_FROM(jaunter, TRAIT_NO_TRANSFORM, REF(src))) to_chat(jaunter, span_warning("You cannot exit yet!!")) return FALSE @@ -101,6 +108,7 @@ /datum/action/cooldown/spell/jaunt/space_crawl/on_jaunt_exited(obj/effect/dummy/phased_mob/jaunt, mob/living/unjaunter) UnregisterSignal(jaunt, COMSIG_MOVABLE_MOVED) + UnregisterSignal(unjaunter, list(SIGNAL_REMOVETRAIT(TRAIT_ALLOW_HERETIC_CASTING), COMSIG_MOB_STATCHANGE)) playsound(get_turf(unjaunter), 'sound/magic/cosmic_energy.ogg', 50, TRUE, -1) new /obj/effect/temp_visual/space_explosion(get_turf(unjaunter)) if(iscarbon(unjaunter)) @@ -109,6 +117,19 @@ qdel(space_hand) return ..() +/// Signal proc for [SIGNAL_REMOVETRAIT] via [TRAIT_ALLOW_HERETIC_CASTING], losing our focus midcast will throw us out. +/datum/action/cooldown/spell/jaunt/space_crawl/proc/on_focus_lost(mob/living/source) + SIGNAL_HANDLER + var/turf/our_turf = get_turf(source) + try_exit_jaunt(our_turf, source, TRUE) + +/// Signal proc for [COMSIG_MOB_STATCHANGE], to throw us out of the jaunt if we lose consciousness. +/datum/action/cooldown/spell/jaunt/space_crawl/proc/on_stat_change(mob/living/source, new_stat, old_stat) + SIGNAL_HANDLER + if(new_stat != CONSCIOUS) + var/turf/our_turf = get_turf(source) + try_exit_jaunt(our_turf, source, TRUE) + /// Spacecrawl "hands", prevent the user from holding items in spacecrawl /obj/item/space_crawl name = "space crawl" diff --git a/code/modules/antagonists/heretic/moon_lunatic.dm b/code/modules/antagonists/heretic/moon_lunatic.dm index 21177f1a62319..dbc07a6b5054b 100644 --- a/code/modules/antagonists/heretic/moon_lunatic.dm +++ b/code/modules/antagonists/heretic/moon_lunatic.dm @@ -26,10 +26,6 @@ to_chat(owner, span_boldnotice("Ruin the lie, save the truth through obeying [heretic_master] the ringleader!")) -/datum/antagonist/lunatic/greet() - owner.current.playsound_local(get_turf(owner.current), 'sound/effects/moon_parade.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE) - return ..() - /datum/antagonist/lunatic/apply_innate_effects(mob/living/mob_override) var/mob/living/our_mob = mob_override || owner.current handle_clown_mutation(our_mob, "Ancient knowledge from the moon has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") diff --git a/code/modules/antagonists/heretic/rust_effect.dm b/code/modules/antagonists/heretic/rust_effect.dm index e48faae429c25..ad86fa5a747f5 100644 --- a/code/modules/antagonists/heretic/rust_effect.dm +++ b/code/modules/antagonists/heretic/rust_effect.dm @@ -1,14 +1,15 @@ // Small visual effect imparted onto rusted things by rust heretics. -/obj/effect/temp_visual/glowing_rune +/obj/effect/glowing_rune icon = 'icons/effects/eldritch.dmi' icon_state = "small_rune_1" - duration = 1 MINUTES + anchored = TRUE layer = LOW_SIGIL_LAYER + mouse_opacity = MOUSE_OPACITY_TRANSPARENT plane = GAME_PLANE -/obj/effect/temp_visual/glowing_rune/Initialize(mapload) +/obj/effect/glowing_rune/Initialize(mapload) . = ..() pixel_y = rand(-6, 6) pixel_x = rand(-6, 6) - icon_state = "small_rune_[rand(12)]" + icon_state = "small_rune_[rand(1, 12)]" update_appearance() diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm index 607f485ff6421..d2058a5b4f19e 100644 --- a/code/modules/antagonists/heretic/status_effects/buffs.dm +++ b/code/modules/antagonists/heretic/status_effects/buffs.dm @@ -6,6 +6,7 @@ status_type = STATUS_EFFECT_REFRESH duration = 15 SECONDS alert_type = /atom/movable/screen/alert/status_effect/crucible_soul + show_duration = TRUE var/turf/location /datum/status_effect/crucible_soul/on_apply() @@ -30,6 +31,7 @@ id = "Blessing of Dusk and Dawn" status_type = STATUS_EFFECT_REFRESH duration = 60 SECONDS + show_duration = TRUE alert_type =/atom/movable/screen/alert/status_effect/duskndawn /datum/status_effect/duskndawn/on_apply() @@ -47,6 +49,7 @@ status_type = STATUS_EFFECT_REFRESH duration = 60 SECONDS tick_interval = 1 SECONDS + show_duration = TRUE alert_type = /atom/movable/screen/alert/status_effect/marshal /datum/status_effect/marshal/on_apply() @@ -192,7 +195,7 @@ qdel(to_remove) - addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_BEING_BLADE_SHIELDED, type), 1) + addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_BEING_BLADE_SHIELDED, type), 0.1 SECONDS) return SUCCESSFUL_BLOCK @@ -299,6 +302,7 @@ id = "Moon Grasp Hide Identity" status_type = STATUS_EFFECT_REFRESH duration = 15 SECONDS + show_duration = TRUE alert_type = /atom/movable/screen/alert/status_effect/moon_grasp_hide /datum/status_effect/moon_grasp_hide/on_apply() diff --git a/code/modules/antagonists/heretic/status_effects/mark_effects.dm b/code/modules/antagonists/heretic/status_effects/mark_effects.dm index 3dffa2dd4fe80..b234fb604c241 100644 --- a/code/modules/antagonists/heretic/status_effects/mark_effects.dm +++ b/code/modules/antagonists/heretic/status_effects/mark_effects.dm @@ -95,28 +95,8 @@ effect_icon_state = "emark3" /datum/status_effect/eldritch/rust/on_effect() - if(iscarbon(owner)) - var/mob/living/carbon/carbon_owner = owner - var/static/list/organs_to_damage = list( - ORGAN_SLOT_BRAIN, - ORGAN_SLOT_EARS, - ORGAN_SLOT_EYES, - ORGAN_SLOT_LIVER, - ORGAN_SLOT_LUNGS, - ORGAN_SLOT_STOMACH, - ORGAN_SLOT_HEART, - ) - - // Roughly 75% of their organs will take a bit of damage - for(var/organ_slot in organs_to_damage) - if(prob(75)) - carbon_owner.adjustOrganLoss(organ_slot, 20) - - // And roughly 75% of their items will take a smack, too - for(var/obj/item/thing in carbon_owner.get_all_gear()) - if(!QDELETED(thing) && prob(75)) - thing.take_damage(100) - + owner.adjust_disgust(100) + owner.adjust_confusion(10 SECONDS) return ..() // MARK OF VOID diff --git a/code/modules/antagonists/heretic/structures/mawed_crucible.dm b/code/modules/antagonists/heretic/structures/mawed_crucible.dm index 7c1208b1e44bf..8e5410f0f6751 100644 --- a/code/modules/antagonists/heretic/structures/mawed_crucible.dm +++ b/code/modules/antagonists/heretic/structures/mawed_crucible.dm @@ -21,8 +21,7 @@ . = ..() break_message = span_warning("[src] falls apart with a thud!") -/obj/structure/destructible/eldritch_crucible/deconstruct(disassembled = TRUE) - +/obj/structure/destructible/eldritch_crucible/atom_deconstruct(disassembled = TRUE) // Create a spillage if we were destroyed with leftover mass if(current_mass) break_message = span_warning("[src] falls apart with a thud, spilling shining extract everywhere!") diff --git a/code/modules/antagonists/malf_ai/malf_ai.dm b/code/modules/antagonists/malf_ai/malf_ai.dm index f9f422d6e6fc3..b76452e6076f3 100644 --- a/code/modules/antagonists/malf_ai/malf_ai.dm +++ b/code/modules/antagonists/malf_ai/malf_ai.dm @@ -159,6 +159,8 @@ to_chat(malf_ai, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") + if(malf_ai.malf_picker) + return malf_ai.add_malf_picker() @@ -246,7 +248,7 @@ result += objectives_text - var/special_role_text = lowertext(name) + var/special_role_text = LOWER_TEXT(name) if(malf_ai_won) result += span_greentext("The [special_role_text] was successful!") diff --git a/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm b/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm index 51058f82ac02e..0ac27c14c97bf 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm @@ -24,7 +24,7 @@ filtered_modules[AM.category][AM] = AM for(var/category in filtered_modules) - filtered_modules[category] = sortTim(filtered_modules[category], GLOBAL_PROC_REF(cmp_malfmodules_priority)) + sortTim(filtered_modules[category], GLOBAL_PROC_REF(cmp_malfmodules_priority)) return filtered_modules diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index ab88a6f02fc3d..a80ccec73bf37 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -47,6 +47,9 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( /obj/machinery/hypertorus/corner, /obj/machinery/atmospherics/components/binary/valve, /obj/machinery/portable_atmospherics/canister, + /obj/machinery/computer/shuttle, + /obj/machinery/computer/emergency_shuttle, + /obj/machinery/computer/gateway_control, ))) GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) @@ -166,7 +169,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/action/innate/ai/nuke_station name = "Doomsday Device" desc = "Activates the doomsday device. This is not reversible." - button_icon_state = "doomsday_device" + button_icon = 'icons/obj/machines/nuke_terminal.dmi' + button_icon_state = "nuclearbomb_timing" auto_use_uses = FALSE /datum/action/innate/ai/nuke_station/Activate() @@ -449,7 +453,12 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) to_chat(caller, span_warning("You can only animate machines!")) return FALSE var/obj/machinery/clicked_machine = clicked_on - if(!clicked_machine.can_be_overridden() || is_type_in_typecache(clicked_machine, GLOB.blacklisted_malf_machines)) + + if(istype(clicked_machine, /obj/machinery/porta_turret_cover)) //clicking on a closed turret will attempt to override the turret itself instead of the animated/abstract cover. + var/obj/machinery/porta_turret_cover/clicked_turret = clicked_machine + clicked_machine = clicked_turret.parent_turret + + if((clicked_machine.resistance_flags & INDESTRUCTIBLE) || is_type_in_typecache(clicked_machine, GLOB.blacklisted_malf_machines)) to_chat(caller, span_warning("That machine can't be overridden!")) return FALSE @@ -537,7 +546,12 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) to_chat(caller, span_warning("You can only overload machines!")) return FALSE var/obj/machinery/clicked_machine = clicked_on - if(is_type_in_typecache(clicked_machine, GLOB.blacklisted_malf_machines)) + + if(istype(clicked_machine, /obj/machinery/porta_turret_cover)) //clicking on a closed turret will attempt to override the turret itself instead of the animated/abstract cover. + var/obj/machinery/porta_turret_cover/clicked_turret = clicked_machine + clicked_machine = clicked_turret.parent_turret + + if((clicked_machine.resistance_flags & INDESTRUCTIBLE) || is_type_in_typecache(clicked_machine, GLOB.blacklisted_malf_machines)) to_chat(caller, span_warning("You cannot overload that device!")) return FALSE @@ -598,6 +612,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/action/innate/ai/honk name = "Percussive Intercomm Interference" desc = "Rock the station's intercom system with an obnoxious HONK!" + button_icon = 'icons/obj/machines/wallmounts.dmi' button_icon_state = "intercom" uses = 2 @@ -686,7 +701,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) I.loc = T client.images += I I.icon_state = "[success ? "green" : "red"]Overlay" //greenOverlay and redOverlay for success and failure respectively - addtimer(CALLBACK(src, PROC_REF(remove_transformer_image), client, I, T), 30) + addtimer(CALLBACK(src, PROC_REF(remove_transformer_image), client, I, T), 3 SECONDS) if(!success) to_chat(src, span_warning("[alert_msg]")) return success @@ -705,7 +720,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/action/innate/ai/break_air_alarms name = "Override Air Alarm Safeties" desc = "Enables extremely dangerous settings on all air alarms." - button_icon_state = "break_air_alarms" + button_icon = 'icons/obj/machines/wallmounts.dmi' + button_icon_state = "alarmx" uses = 1 /datum/action/innate/ai/break_air_alarms/Activate() @@ -761,7 +777,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/action/innate/ai/emergency_lights name = "Disable Emergency Lights" desc = "Disables all emergency lighting. Note that emergency lights can be restored through reboot at an APC." - button_icon_state = "emergency_lights" + button_icon = 'icons/obj/lighting.dmi' + button_icon_state = "floor_emergency" uses = 1 /datum/action/innate/ai/emergency_lights/Activate() @@ -941,6 +958,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) var/prev_verbs /// Saved span state, used to restore after a voice change var/prev_span + /// The list of available voices + var/static/list/voice_options = list("normal", SPAN_ROBOT, SPAN_YELL, SPAN_CLOWN) /obj/machinery/ai_voicechanger/Initialize(mapload) . = ..() @@ -968,11 +987,12 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /obj/machinery/ai_voicechanger/ui_data(mob/user) var/list/data = list() - data["voices"] = list("normal", SPAN_ROBOT, SPAN_YELL, SPAN_CLOWN) //manually adding this since i dont see other option + data["voices"] = voice_options data["loud"] = loudvoice data["on"] = changing_voice data["say_verb"] = say_verb data["name"] = say_name + data["selected"] = say_span || owner.speech_span return data /obj/machinery/ai_voicechanger/ui_act(action, params) @@ -1006,9 +1026,23 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) if(changing_voice) owner.radio.use_command = loudvoice if("look") - say_span = params["look"] + var/selection = params["look"] + if(isnull(selection)) + return FALSE + + var/found = FALSE + for(var/option in voice_options) + if(option == selection) + found = TRUE + break + if(!found) + stack_trace("User attempted to select an unavailable voice option") + return FALSE + + say_span = selection if(changing_voice) owner.speech_span = say_span + to_chat(usr, span_notice("Voice set to [selection].")) if("verb") say_verb = params["verb"] if(changing_voice) diff --git a/code/modules/antagonists/ninja/ninjaDrainAct.dm b/code/modules/antagonists/ninja/ninjaDrainAct.dm index 7f11d934cc6ff..0aaf5dbbfcf3b 100644 --- a/code/modules/antagonists/ninja/ninjaDrainAct.dm +++ b/code/modules/antagonists/ninja/ninjaDrainAct.dm @@ -1,3 +1,8 @@ +/// Minimum amount of energy we can drain in a single drain action +#define NINJA_MIN_DRAIN (0.2 * STANDARD_CELL_CHARGE) +/// Maximum amount of energy we can drain in a single drain action +#define NINJA_MAX_DRAIN (0.4 * STANDARD_CELL_CHARGE) + /** * Atom level proc for space ninja's glove interactions. * @@ -26,13 +31,13 @@ var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) while(cell.charge> 0 && !maxcapacity) - drain = rand(hacking_module.mindrain, hacking_module.maxdrain) + drain = rand(NINJA_MIN_DRAIN, NINJA_MAX_DRAIN) if(cell.charge < drain) drain = cell.charge if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE//Reached maximum battery capacity. - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) @@ -62,13 +67,13 @@ var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) while(charge > 0 && !maxcapacity) - drain = rand(hacking_module.mindrain, hacking_module.maxdrain) + drain = rand(NINJA_MIN_DRAIN, NINJA_MAX_DRAIN) if(charge < drain) drain = charge if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) charge -= drain @@ -88,7 +93,7 @@ /obj/item/stock_parts/cell/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) var/drain_total = 0 - if(charge && !do_after(ninja, 3 SECONDS, target = src)) + if(charge && !do_after(ninja, 3 SECONDS, target = src, hidden = TRUE)) drain_total = charge if(hacking_module.mod.get_charge() + charge > hacking_module.mod.get_max_charge()) drain_total = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() @@ -112,7 +117,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/rnd/server/master/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return overload_source_code_hdd() to_chat(ninja, span_notice("Sabotage complete. Storage device overloaded.")) @@ -131,7 +136,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/rnd/server/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return stored_research.modify_points_all(0) to_chat(ninja, span_notice("Sabotage complete. Research notes corrupted.")) @@ -154,7 +159,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/computer/records/security/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 20 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(can_hack), ninja))) + if(!do_after(ninja, 20 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(can_hack), ninja), hidden = TRUE)) return for(var/datum/record/crew/target in GLOB.manifest.general) target.wanted_status = WANTED_ARREST @@ -228,9 +233,9 @@ var/drain_total = 0 var/datum/powernet/wire_powernet = powernet while(!maxcapacity && src) - drain = (round((rand(hacking_module.mindrain, hacking_module.maxdrain))/2)) + drain = (round((rand(NINJA_MIN_DRAIN, NINJA_MAX_DRAIN))/2)) var/drained = 0 - if(wire_powernet && do_after(ninja, 1 SECONDS, target = src)) + if(wire_powernet && do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) drained = min(drain, delayed_surplus()) add_delayedload(drained) if(drained < drain)//if no power on net, drain apcs @@ -264,13 +269,13 @@ var/drain_total = 0 if(get_charge()) while(cell.charge > 0 && !maxcapacity) - drain = rand(hacking_module.mindrain, hacking_module.maxdrain) + drain = rand(NINJA_MIN_DRAIN, NINJA_MAX_DRAIN) if(cell.charge < drain) drain = cell.charge if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) @@ -290,7 +295,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /mob/living/silicon/robot/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 6 SECONDS, target = src)) + if(!do_after(ninja, 6 SECONDS, target = src, hidden = TRUE)) return spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) @@ -342,7 +347,7 @@ //BOTS// /mob/living/simple_animal/bot/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) to_chat(src, span_boldwarning("Your circutry suddenly begins heating up!")) - if(!do_after(ninja, 1.5 SECONDS, target = src)) + if(!do_after(ninja, 1.5 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN if(!hacking_module.mod.subtract_charge(DEFAULT_CHARGE_DRAIN * 7)) @@ -368,7 +373,7 @@ balloon_alert(ninja, "no energy!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 1.5 SECONDS, target = src)) + if(!do_after(ninja, 1.5 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN hacking_module.mod.add_charge(cell.charge) @@ -385,7 +390,7 @@ balloon_alert(ninja, "already hacked!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 2 SECONDS, target = src)) + if(!do_after(ninja, 2 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN if(!hacking_module.mod.subtract_charge(DEFAULT_CHARGE_DRAIN * 5)) @@ -403,7 +408,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN AI_notify_hack() - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN do_sparks(3, cardinal_only = FALSE, source = src) @@ -417,7 +422,7 @@ balloon_alert(ninja, "already hacked!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 2 SECONDS, target = src)) + if(!do_after(ninja, 2 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN do_sparks(3, cardinal_only = FALSE, source = src) @@ -438,7 +443,7 @@ AI_notify_hack() - if(!do_after(ninja, 20 SECONDS, target = src)) //Shorter due to how incredibly easy it is for someone to (even accidentally) interrupt. + if(!do_after(ninja, 20 SECONDS, target = src, hidden = TRUE)) //Shorter due to how incredibly easy it is for someone to (even accidentally) interrupt. return COMPONENT_CANCEL_ATTACK_CHAIN force_event(/datum/round_event_control/tram_malfunction, "ninja interference") @@ -466,3 +471,6 @@ //FIRELOCKS// /obj/machinery/door/firedoor/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) crack_open() + +#undef NINJA_MIN_DRAIN +#undef NINJA_MAX_DRAIN diff --git a/code/modules/antagonists/nukeop/datums/operative.dm b/code/modules/antagonists/nukeop/datums/operative.dm index 516108c572513..3b4c9fa4da7ce 100644 --- a/code/modules/antagonists/nukeop/datums/operative.dm +++ b/code/modules/antagonists/nukeop/datums/operative.dm @@ -46,7 +46,6 @@ var/datum/component/uplink/uplink = owner.find_syndicate_uplink() if (uplink) uplink.uplink_handler.add_telecrystals(extra_tc) - var/datum/component/uplink/uplink = owner.find_syndicate_uplink() if(uplink) var/datum/team/nuclear/nuke_team = get_team() diff --git a/code/modules/antagonists/nukeop/datums/operative_leader.dm b/code/modules/antagonists/nukeop/datums/operative_leader.dm index 76ca635158b16..0c583bfe794b0 100644 --- a/code/modules/antagonists/nukeop/datums/operative_leader.dm +++ b/code/modules/antagonists/nukeop/datums/operative_leader.dm @@ -35,7 +35,7 @@ var/obj/item/war_declaration = new challengeitem(leader.drop_location()) leader.put_in_hands(war_declaration) nuke_team.war_button_ref = WEAKREF(war_declaration) - addtimer(CALLBACK(src, PROC_REF(nuketeam_name_assign)), 1) + addtimer(CALLBACK(src, PROC_REF(nuketeam_name_assign)), 0.1 SECONDS) /datum/antagonist/nukeop/leader/proc/nuketeam_name_assign() if(!nuke_team) diff --git a/code/modules/antagonists/nukeop/datums/operative_support.dm b/code/modules/antagonists/nukeop/datums/operative_support.dm new file mode 100644 index 0000000000000..c9ea12b63c5d2 --- /dev/null +++ b/code/modules/antagonists/nukeop/datums/operative_support.dm @@ -0,0 +1,54 @@ +/datum/antagonist/nukeop/support + name = ROLE_OPERATIVE_OVERWATCH + show_to_ghosts = TRUE + send_to_spawnpoint = TRUE + nukeop_outfit = /datum/outfit/syndicate/support + +/datum/antagonist/nukeop/support/greet() + owner.current.playsound_local(get_turf(owner.current), 'sound/machines/printer.ogg', 100, 0, use_reverb = FALSE) + to_chat(owner, span_big("You are a [name]! You've been temporarily assigned to provide camera overwatch and manage communications for a nuclear operative team!")) + to_chat(owner, span_red("Use your tools to set up your equipment however you like, but do NOT attempt to leave your outpost.")) + owner.announce_objectives() + +/datum/antagonist/nukeop/support/on_gain() + ..() + for(var/datum/mind/teammate_mind in nuke_team.members) + var/mob/living/our_teammate = teammate_mind.current + our_teammate.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "operative bodycam", \ + c_tag = "[our_teammate.real_name]", \ + network = OPERATIVE_CAMERA_NET, \ + emp_proof = FALSE, \ + ) + our_teammate.playsound_local(get_turf(owner.current), 'sound/weapons/egloves.ogg', 100, 0) + to_chat(our_teammate, span_notice("A Syndicate Overwatch Intelligence Agent has been assigned to your team. Smile, you're on camera!")) + + RegisterSignal(nuke_team, COMSIG_NUKE_TEAM_ADDITION, PROC_REF(late_bodycam)) + + owner.current.grant_language(/datum/language/codespeak) + +/datum/antagonist/nukeop/support/get_spawnpoint() + return pick(GLOB.nukeop_overwatch_start) + +/datum/antagonist/nukeop/support/forge_objectives() + var/datum/objective/overwatch/objective = new + objective.owner = owner + objectives += objective + +/datum/antagonist/nukeop/support/proc/late_bodycam(datum/source, mob/living/new_teammate) + SIGNAL_HANDLER + new_teammate.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "operative bodycam", \ + c_tag = "[new_teammate.real_name]", \ + network = OPERATIVE_CAMERA_NET, \ + emp_proof = FALSE, \ + ) + to_chat(new_teammate, span_notice("You have been equipped with a bodycam, viewable by your Overwatch Intelligence Agent. Make sure to show them a good performance!")) + +/datum/objective/overwatch + explanation_text = "Provide intelligence support and overwatch to your operative team!" + +/datum/objective/overwatch/check_completion() + return GLOB.station_was_nuked diff --git a/code/modules/antagonists/nukeop/datums/operative_team.dm b/code/modules/antagonists/nukeop/datums/operative_team.dm index 9bec3b0fcf0e1..3345f3cf4d25f 100644 --- a/code/modules/antagonists/nukeop/datums/operative_team.dm +++ b/code/modules/antagonists/nukeop/datums/operative_team.dm @@ -313,5 +313,9 @@ return TRUE return FALSE +/datum/team/nuclear/add_member(datum/mind/new_member) + ..() + SEND_SIGNAL(src, COMSIG_NUKE_TEAM_ADDITION, new_member.current) + #undef SPAWN_AT_BASE #undef SPAWN_AT_INFILTRATOR diff --git a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm index e5a5d2cfb3567..9b536066843e2 100644 --- a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm +++ b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm @@ -1,5 +1,5 @@ -#define ACTIVATION_COST (300 KILO JOULES) -#define ACTIVATION_UP_KEEP (25 KILO WATTS) +#define ACTIVATION_COST (0.3 * STANDARD_CELL_CHARGE) +#define ACTIVATION_UP_KEEP (0.025 * STANDARD_CELL_RATE) /obj/item/borg_chameleon name = "cyborg chameleon projector" @@ -66,7 +66,7 @@ to_chat(user, span_notice("You activate \the [src].")) playsound(src, 'sound/effects/seedling_chargeup.ogg', 100, TRUE, -6) apply_wibbly_filters(user) - if (do_after(user, 50, target=user) && user.cell.use(ACTIVATION_COST)) + if (do_after(user, 5 SECONDS, target = user, hidden = TRUE) && user.cell.use(ACTIVATION_COST)) playsound(src, 'sound/effects/bamf.ogg', 100, TRUE, -6) to_chat(user, span_notice("You are now disguised as the Nanotrasen engineering borg \"[friendlyName]\".")) activate(user) diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm index 6082567129c34..8d2e746f0a220 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm @@ -124,7 +124,7 @@ GLOBAL_VAR(station_nuke_source) if(istype(weapon, /obj/item/nuke_core_container)) var/obj/item/nuke_core_container/core_box = weapon to_chat(user, span_notice("You start loading the plutonium core into [core_box]...")) - if(do_after(user, 5 SECONDS, target=src)) + if(do_after(user, 5 SECONDS, target = src, hidden = TRUE)) if(core_box.load(core, user)) to_chat(user, span_notice("You load the plutonium core into [core_box].")) deconstruction_state = NUKESTATE_CORE_REMOVED diff --git a/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm b/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm new file mode 100644 index 0000000000000..852c0d7d32fbd --- /dev/null +++ b/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm @@ -0,0 +1,46 @@ +///One of the special items that spawns in the overwatch agent's room. +/obj/item/paper/fluff/overwatch + name = "OVERWATCH NOTES #1" + color = COLOR_RED + desc = "A note from Syndicate leadership regarding your new job. You should read this!" + default_raw_text = @{" +Congratulations! You have been picked to be the Sole Survivor of an anti-Nanotrasen suicide mission! +We're kidding of course, these types of missions tend to have abnormally high survival rates. I guess that says a lot about who your team will be going up against. +
    +You've been assigned to provide intelligence support to the ground-pounders carrying out the operation. +Each operative has been equipped with a bodycam that can be accessed via your Overwatch Camera Console. +Additionally, you have been given the boards to access station alerts, cameras, and remotely control the infiltrator shuttle. +
    +Feel free to set up your workplace however you like. We've provided the tools and boards in your backroom. +
    +Happy hunting! + "} + +/obj/machinery/computer/security/overwatch + name = "overwatch camera console" + desc = "Allows you to view members of your operative team via their bodycam feeds. We call them 'bodycams', but they're actually a swarm of tiny, near-imperceptible camera drones that follow each target. \ + It is believed that adversaries either don't notice the drones, or avoid attacking them in hopes that they'll capture footage of their combat prowess against our operatives." + icon_screen = "commsyndie" + icon_keyboard = "syndie_key" + network = list(OPERATIVE_CAMERA_NET) + circuit = /obj/item/circuitboard/computer/overwatch + +/obj/item/circuitboard/computer/overwatch + name = "Overwatch Body Cameras" + build_path = /obj/machinery/computer/security/overwatch + greyscale_colors = CIRCUIT_COLOR_SECURITY + +/obj/item/circuitboard/computer/syndicate_shuttle_docker + name = "Shuttle Controller" + build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/syndicate + greyscale_colors = CIRCUIT_COLOR_SECURITY + +/obj/item/clothing/glasses/overwatch + name = "intelligence glasses" + desc = "A set of incredibly advanced sunglasses, providing you with an array of different sensor scans and visual readouts for pretty much anything you look at. \ + It's kind of overwhelming, actually. Wearing this for a few hours will probably give you a migrane." + icon_state = "sunhudmed" + flags_cover = GLASSESCOVERSEYES + flash_protect = FLASH_PROTECTION_WELDER + clothing_traits = list(TRAIT_REAGENT_SCANNER) + var/list/hudlist = list(DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED, DATA_HUD_SECURITY_ADVANCED) diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm index 80360f5636098..e8ae07ffdde83 100644 --- a/code/modules/antagonists/nukeop/outfits.dm +++ b/code/modules/antagonists/nukeop/outfits.dm @@ -114,6 +114,14 @@ r_hand = /obj/item/tank/internals/plasmaman/belt/full tc = 0 +/datum/outfit/syndicate/support/plasmaman + name = "Nuclear Operative Overwatch Agent (Plasmaman)" + back = /obj/item/storage/backpack/satchel + head = /obj/item/clothing/head/helmet/space/plasmaman/syndie + uniform = /obj/item/clothing/under/plasmaman/syndicate + glasses = /obj/item/clothing/glasses/overwatch + r_hand = /obj/item/tank/internals/plasmaman/belt/full + /datum/outfit/syndicate/reinforcement/gorlex name = "Syndicate Operative - Gorlex Reinforcement" suit = /obj/item/clothing/suit/armor/vest/alt @@ -191,3 +199,14 @@ var/obj/item/shield/energy/shield = locate() in H.held_items shield.icon_state = "[shield.base_icon_state]1" H.update_held_items() + +/datum/outfit/syndicate/support + name = "Nuclear Operative Overwatch Agent" + back = /obj/item/storage/backpack/satchel + uniform = /obj/item/clothing/under/syndicate/tacticool + glasses = /obj/item/clothing/glasses/overwatch + suit = /obj/item/clothing/suit/jacket/letterman_syndie + shoes = /obj/item/clothing/shoes/sandal + command_radio = TRUE + tc = 0 + uplink_type = null diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm index 15a028b24d740..0fa80f5524776 100644 --- a/code/modules/antagonists/pirate/pirate.dm +++ b/code/modules/antagonists/pirate/pirate.dm @@ -85,7 +85,7 @@ //Lists notable loot. if(!cargo_hold || !cargo_hold.total_report) return "Nothing" - cargo_hold.total_report.total_value = sortTim(cargo_hold.total_report.total_value, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE) + sortTim(cargo_hold.total_report.total_value, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE) var/count = 0 var/list/loot_texts = list() for(var/datum/export/E in cargo_hold.total_report.total_value) diff --git a/code/modules/antagonists/pirate/pirate_event.dm b/code/modules/antagonists/pirate/pirate_event.dm index e4a14182d0e7f..5ecefa3094d45 100644 --- a/code/modules/antagonists/pirate/pirate_event.dm +++ b/code/modules/antagonists/pirate/pirate_event.dm @@ -42,7 +42,7 @@ priority_announce("Incoming subspace communication. Secure channel opened at all communication consoles.", "Incoming Message", SSstation.announcer.get_rand_report_sound()) threat.answer_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(pirates_answered), threat, chosen_gang, payoff, world.time) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(spawn_pirates), threat, chosen_gang), RESPONSE_MAX_TIME) - SScommunications.send_message(threat, unique = TRUE) + GLOB.communications_controller.send_message(threat, unique = TRUE) /proc/pirates_answered(datum/comm_message/threat, datum/pirate_gang/chosen_gang, payoff, initial_send_time) if(world.time > initial_send_time + RESPONSE_MAX_TIME) diff --git a/code/modules/antagonists/pirate/pirate_gangs.dm b/code/modules/antagonists/pirate/pirate_gangs.dm index 5016683c5eab6..aef8222a99348 100644 --- a/code/modules/antagonists/pirate/pirate_gangs.dm +++ b/code/modules/antagonists/pirate/pirate_gangs.dm @@ -205,3 +205,25 @@ GLOBAL_LIST_INIT(heavy_pirate_gangs, init_pirate_gangs(is_heavy = TRUE)) response_too_late = "You were not ready then, and now that time has passed. We can only go forward, never back." response_not_enough = "You have insulted us, but there shall be no feud, only swift justice!" announcement_color = "purple" + +//medieval militia, from OUTER SPACE! +/datum/pirate_gang/medieval + name = "Medieval Warmongers" + + is_heavy_threat = TRUE + ship_template_id = "medieval" + ship_name_pool = "medieval_names" + + threat_title = "HOMAGE PAYMENT REQUEST" + threat_content = "SALUTATIONS, THIS IS %SHIPNAME AND WE ARE COLLECTING MONEY \ + FROM THE VASSALS IN OUR TERRITORY, YOU JUST SO HAPPEN TO BE IN IT TOO!! NORMALLY \ + WE SLAUGHTER WEAKLINGS LIKE YOU FOR TRESPASING ON OUR LAND, BUT WE ARE WILLING \ + TO WELCOME YOU INTO OUR SPACE IF YOU PAY %PAYOFF AS HOMAGE TO OUR LAW. BE WISE ON YOUR CHOICE!! \ + (send message. send message. why message not sent?)." + arrival_announcement = "I FIGURED OUT HOW TO FLY MY SHIP, WE WILL BE DOCKING NEXT TO YOU IN A MINUTE!!" + possible_answers = list("Please don't hurt me.","You are dumb, go larp somewhere else.") + + response_received = "THIS WILL SUFFICE, REMEMBER WHO OWNS YOU!!" + response_rejected = "FOOLISH DECISION, I'LL MAKE AN EXAMPLE OUT OF YOUR CARCASS!! (does anyone remember how to pilot our ship?)" + response_too_late = "YOU ARE ALREADY UNDER SIEGE YOU BUFFON, ARE YOU BRAINSICK OR IGNORANT?!!" + response_not_enough = "DO THINK OF ME AS A JESTER? YOU ARE DEAD MEAT!! (i forgot how to fly the ship, tarnation.)" diff --git a/code/modules/antagonists/pirate/pirate_outfits.dm b/code/modules/antagonists/pirate/pirate_outfits.dm index 4c73cac107f12..15a3d4fe2dcb2 100644 --- a/code/modules/antagonists/pirate/pirate_outfits.dm +++ b/code/modules/antagonists/pirate/pirate_outfits.dm @@ -148,3 +148,34 @@ glasses = null suit = /obj/item/clothing/suit/jacket/oversized head = /obj/item/clothing/head/costume/crown + +/datum/outfit/pirate/medieval + name = "Medieval Warmonger" + + id = null + glasses = null + uniform = /obj/item/clothing/under/costume/gamberson/military + suit = /obj/item/clothing/suit/armor/vest/military + suit_store = /obj/item/spear/military + back = /obj/item/storage/backpack/satchel/leather + gloves = /obj/item/clothing/gloves/color/brown + head = /obj/item/clothing/head/helmet/military + mask = /obj/item/clothing/mask/balaclava + shoes = /obj/item/clothing/shoes/workboots + belt = /obj/item/claymore/shortsword + l_pocket = /obj/item/flashlight/flare/torch + +/datum/outfit/pirate/medieval/warlord + name = "Medieval Warlord" + + neck = /obj/item/bedsheet/pirate + suit = /obj/item/clothing/suit/armor/riot/knight/warlord + suit_store = null + back = /obj/item/fireaxe/boardingaxe + gloves = /obj/item/clothing/gloves/combat + head = /obj/item/clothing/head/helmet/knight/warlord + mask = /obj/item/clothing/mask/breath + shoes = /obj/item/clothing/shoes/bronze + belt = /obj/item/gun/magic/hook + l_pocket = /obj/item/tank/internals/emergency_oxygen + r_pocket = /obj/item/flashlight/lantern diff --git a/code/modules/antagonists/pirate/pirate_roles.dm b/code/modules/antagonists/pirate/pirate_roles.dm index 64baa724db1ec..78a3d3fd12acf 100644 --- a/code/modules/antagonists/pirate/pirate_roles.dm +++ b/code/modules/antagonists/pirate/pirate_roles.dm @@ -191,3 +191,33 @@ /obj/effect/mob_spawn/ghost_role/human/pirate/lustrous/gunner rank = "Coruscant" + +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval + name = "\improper Improvised sleeper" + desc = "A body bag poked with holes, currently being used as a sleeping bag. Someone seems to be sleeping inside of it." + density = FALSE + you_are_text = "You were a nobody before, until you were given a sword and the opportunity to rise up in ranks. If you put some effort, you can make it big!" + flavour_text = "Raiding some cretins while engaging in bloodsport and violence? what a deal. Stay together and pillage everything!" + icon = 'icons/obj/medical/bodybag.dmi' + icon_state = "bodybag" + fluff_spawn = null + prompt_name = "a medieval warmonger" + outfit = /datum/outfit/pirate/medieval + rank = "Footsoldier" + +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval/special(mob/living/carbon/spawned_mob) + . = ..() + if(rank == "Footsoldier") + ADD_TRAIT(spawned_mob, TRAIT_NOGUNS, INNATE_TRAIT) + spawned_mob.AddComponent(/datum/component/unbreakable) + var/datum/action/cooldown/mob_cooldown/dash/dodge = new(spawned_mob) + dodge.Grant(spawned_mob) + +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval/warlord + rank = "Warlord" + outfit = /datum/outfit/pirate/medieval/warlord + +/obj/effect/mob_spawn/ghost_role/human/pirate/medieval/warlord/special(mob/living/carbon/spawned_mob) + . = ..() + spawned_mob.dna.add_mutation(/datum/mutation/human/hulk/superhuman) + spawned_mob.dna.add_mutation(/datum/mutation/human/gigantism) diff --git a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm index 2b323d51162a4..16cad321853d9 100644 --- a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm +++ b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm @@ -96,6 +96,9 @@ light_color = COLOR_SOFT_RED possible_destinations = "pirate_away;pirate_home;pirate_custom" +/obj/machinery/computer/shuttle/pirate/drop_pod + possible_destinations = "null" + /obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/pirate name = "pirate shuttle navigation computer" desc = "Used to designate a precise transit location for the pirate shuttle." @@ -232,7 +235,7 @@ pad_ref = WEAKREF(I.buffer) return TRUE -/obj/machinery/computer/piratepad_control/LateInitialize() +/obj/machinery/computer/piratepad_control/post_machine_initialize() . = ..() if(cargo_hold_id) for(var/obj/machinery/piratepad/P as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/piratepad)) @@ -425,7 +428,7 @@ /datum/export/pirate/ransom/sell_object(mob/living/carbon/human/sold_item, datum/export_report/report, dry_run = TRUE, apply_elastic = TRUE) . = ..() - if(. == EXPORT_NOT_SOLD) + if(. == EXPORT_NOT_SOLD || dry_run) return var/turf/picked_turf = pick(GLOB.holdingfacility) sold_item.forceMove(picked_turf) @@ -436,7 +439,7 @@ sold_item.flash_act() sold_item.adjust_confusion(10 SECONDS) sold_item.adjust_dizzy(10 SECONDS) - addtimer(src, CALLBACK(src, PROC_REF(send_back_to_station), sold_item), COME_BACK_FROM_CAPTURE_TIME) + addtimer(CALLBACK(src, PROC_REF(send_back_to_station), sold_item), COME_BACK_FROM_CAPTURE_TIME) to_chat(sold_item, span_hypnophrase("A million voices echo in your head... \"Yaarrr, thanks for the booty, landlubber. \ You will be ransomed back to your station, so it's only a matter of time before we ship you back...")) diff --git a/code/modules/antagonists/space_dragon/carp_rift.dm b/code/modules/antagonists/space_dragon/carp_rift.dm index e003bf76e4d9b..4b8a20acba8d1 100644 --- a/code/modules/antagonists/space_dragon/carp_rift.dm +++ b/code/modules/antagonists/space_dragon/carp_rift.dm @@ -160,7 +160,7 @@ newcarp.faction = dragon.owner.current.faction.Copy() if(SPT_PROB(1.5, seconds_per_tick)) var/rand_dir = pick(GLOB.cardinals) - SSmove_manager.move_to(src, get_step(src, rand_dir), 1) + GLOB.move_manager.move_to(src, get_step(src, rand_dir), 1) return // Increase time trackers and check for any updated states. diff --git a/code/modules/antagonists/space_ninja/space_ninja.dm b/code/modules/antagonists/space_ninja/space_ninja.dm index bf19635ed9b0d..7f88c687c12d1 100644 --- a/code/modules/antagonists/space_ninja/space_ninja.dm +++ b/code/modules/antagonists/space_ninja/space_ninja.dm @@ -2,7 +2,7 @@ name = "\improper Space Ninja" antagpanel_category = ANTAG_GROUP_NINJAS job_rank = ROLE_NINJA - antag_hud_name = "space_ninja" + antag_hud_name = "ninja" hijack_speed = 1 show_name_in_check_antagonists = TRUE show_to_ghosts = TRUE diff --git a/code/modules/antagonists/spy/spy.dm b/code/modules/antagonists/spy/spy.dm index e0ea7e4075404..8bcc113f08939 100644 --- a/code/modules/antagonists/spy/spy.dm +++ b/code/modules/antagonists/spy/spy.dm @@ -131,6 +131,33 @@ your_mission.explanation_text = pick_list_replacements(SPY_OBJECTIVE_FILE, "objective_body") objectives += your_mission + if((length(objectives) < 3) && prob(25)) + switch(rand(1, 4)) + if(1) + var/datum/objective/protect/save_the_person = new() + save_the_person.owner = owner + save_the_person.find_target() + save_the_person.no_failure = TRUE + objectives += save_the_person + if(2) + var/datum/objective/protect/nonhuman/save_the_entity = new() + save_the_entity.owner = owner + save_the_entity.find_target() + save_the_entity.no_failure = TRUE + objectives += save_the_entity + if(3) + var/datum/objective/jailbreak/save_the_jailbird = new() + save_the_jailbird.owner = owner + save_the_jailbird.find_target() + save_the_jailbird.no_failure = TRUE + objectives += save_the_jailbird + if(4) + var/datum/objective/jailbreak/detain/cage_the_jailbird = new() + cage_the_jailbird.owner = owner + cage_the_jailbird.find_target() + cage_the_jailbird.no_failure = TRUE + objectives += cage_the_jailbird + if(prob(10)) var/datum/objective/martyr/leave_no_trace = new() leave_no_trace.owner = owner @@ -141,6 +168,11 @@ steal_the_shuttle.owner = owner objectives += steal_the_shuttle + else if(prob(10)) //10% chance on 87.3% chance + var/datum/objective/exile/hit_the_bricks = new() + hit_the_bricks.owner = owner + objectives += hit_the_bricks + else var/datum/objective/escape/gtfo = new() gtfo.owner = owner diff --git a/code/modules/antagonists/spy/spy_uplink.dm b/code/modules/antagonists/spy/spy_uplink.dm index 2a9d9b9b14e9b..5de66271fe29c 100644 --- a/code/modules/antagonists/spy/spy_uplink.dm +++ b/code/modules/antagonists/spy/spy_uplink.dm @@ -56,7 +56,7 @@ /datum/component/spy_uplink/proc/on_attack_self(obj/item/source, mob/user) SIGNAL_HANDLER - if(is_our_spy(user)) + if(IS_SPY(user)) INVOKE_ASYNC(src, TYPE_PROC_REF(/datum, ui_interact), user) return NONE @@ -65,7 +65,7 @@ if(!ismovable(target)) return NONE - if(!is_our_spy(user)) + if(!IS_SPY(user)) return NONE if(!try_steal(target, user)) return NONE @@ -136,7 +136,7 @@ span_notice("You start scanning [stealing], preparing it for extraction."), ) - if(!do_after(spy, bounty.theft_time, stealing, interaction_key = REF(src))) + if(!do_after(spy, bounty.theft_time, stealing, interaction_key = REF(src), hidden = TRUE)) return FALSE if(bounty.claimed) to_chat(spy, span_warning("Your uplinks blinks red: The bounty for [stealing] has been claimed by another spy!")) diff --git a/code/modules/antagonists/survivalist/survivalist.dm b/code/modules/antagonists/survivalist/survivalist.dm index 2480b186600a6..b801076747faf 100644 --- a/code/modules/antagonists/survivalist/survivalist.dm +++ b/code/modules/antagonists/survivalist/survivalist.dm @@ -3,7 +3,10 @@ show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE suicide_cry = "FOR MYSELF!!" + /// What do we display when you gain the antag datum? var/greet_message = "" + /// Should we immediately print the objectives? + var/announce_objectives = TRUE /datum/antagonist/survivalist/forge_objectives() var/datum/objective/survive/survive = new @@ -18,7 +21,8 @@ /datum/antagonist/survivalist/greet() . = ..() to_chat(owner, "[greet_message]") - owner.announce_objectives() + if (announce_objectives) + owner.announce_objectives() /datum/antagonist/survivalist/guns greet_message = "Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, by any means necessary. Kill anyone who gets in your way." @@ -52,3 +56,52 @@ /datum/antagonist/survivalist/magic/on_removal() REMOVE_TRAIT(owner, TRAIT_MAGICALLY_GIFTED, REF(src)) return..() + +/// Applied by the battle royale objective +/datum/antagonist/survivalist/battle_royale + name = "Battle Royale Contestant" + greet_message = "There has to be some way you can make it out of this alive..." + announce_objectives = FALSE + +/datum/antagonist/survivalist/battle_royale/on_gain() + . = ..() + if (isnull(owner.current)) + return + RegisterSignals(owner.current, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(on_died)) + +/datum/antagonist/survivalist/battle_royale/greet() + to_chat(owner, span_warning("[span_bold("You hear a tinny voice in your ear: ")] \ + Welcome contestant to Rumble Royale, the galaxy's greatest show! \n\ + You may have already heard our announcement, but we're glad to tell you that you are on live TV! \n\ + Your objective in this contest is simple: Within ten minutes be the last contestant left alive, to win a fabulous prize! \n\ + Your fellow contestants will be hearing this too, so you should grab a GPS quick and get hunting! \n\ + Noncompliance and removal of this implant is not recommended, and remember to smile for the cameras!")) + + return ..() + +/datum/antagonist/survivalist/battle_royale/on_removal() + if (isnull(owner.current)) + return ..() + UnregisterSignal(owner.current, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING)) + if (owner.current.stat == DEAD) + return ..() + to_chat(owner, span_notice("Your body is flooded with relief. Against all the odds, you've made it out alive.")) + owner.current?.mob_mood.add_mood_event("battle_royale", /datum/mood_event/royale_survivor) + return ..() + +/// Add an objective to go to a specific place. +/datum/antagonist/survivalist/battle_royale/proc/set_target_area(target_area_name) + var/datum/objective/custom/travel = new + travel.owner = owner + travel.explanation_text = "Reach the [target_area_name] before time runs out." + objectives.Insert(1, travel) + owner.announce_objectives() + +/// Called if you fail to survive. +/datum/antagonist/survivalist/battle_royale/proc/on_died() + SIGNAL_HANDLER + owner.remove_antag_datum(type) + +/datum/mood_event/royale_survivor + description = "I made it out of Rumble Royale with my life." + mood_change = 4 diff --git a/code/modules/antagonists/traitor/balance_helper.dm b/code/modules/antagonists/traitor/balance_helper.dm index e78625ff1c1c5..b2a9661bfeb59 100644 --- a/code/modules/antagonists/traitor/balance_helper.dm +++ b/code/modules/antagonists/traitor/balance_helper.dm @@ -1,11 +1,5 @@ -/client/proc/cmd_admin_debug_traitor_objectives() - set name = "Debug Traitor Objectives" - set category = "Debug" - - if(!check_rights(R_DEBUG)) - return - - SStraitor.traitor_debug_panel?.ui_interact(usr) +ADMIN_VERB(debug_traitor_objectives, R_DEBUG, "Debug Traitor Objectives", "Verify functionality of traitor goals.", ADMIN_CATEGORY_DEBUG) + SStraitor.traitor_debug_panel?.ui_interact(user.mob) /datum/traitor_objective_debug var/list/all_objectives diff --git a/code/modules/antagonists/traitor/components/demoraliser.dm b/code/modules/antagonists/traitor/components/demoraliser.dm index 47cdae620f47e..ee44527728c0b 100644 --- a/code/modules/antagonists/traitor/components/demoraliser.dm +++ b/code/modules/antagonists/traitor/components/demoraliser.dm @@ -13,7 +13,7 @@ src.moods = moods RegisterSignal(host, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) -/datum/proximity_monitor/advanced/demoraliser/field_turf_crossed(atom/movable/crossed, turf/location) +/datum/proximity_monitor/advanced/demoraliser/field_turf_crossed(atom/movable/crossed, turf/old_location, turf/new_location) if (!isliving(crossed)) return if (!can_see(crossed, host, current_range)) diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 88776b6819af6..5ad5aeecf26c7 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -360,7 +360,7 @@ result += contractor_round_end() result += "
    The traitor had a total of [DISPLAY_PROGRESSION(uplink_handler.progression_points)] Reputation and [uplink_handler.telecrystals] Unused Telecrystals." - var/special_role_text = lowertext(name) + var/special_role_text = LOWER_TEXT(name) if(traitor_won) result += span_greentext("The [special_role_text] was successful!") diff --git a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm index 0d62ecece5f2a..9182f23a649db 100644 --- a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm +++ b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm @@ -41,10 +41,10 @@ target_jobs = list( // Medical /datum/job/doctor, - /datum/job/virologist, /datum/job/paramedic, /datum/job/psychologist, /datum/job/chemist, + /datum/job/coroner, // Service /datum/job/clown, /datum/job/botanist, @@ -76,6 +76,7 @@ telecrystal_reward = list(1, 2) target_jobs = list( // Cargo + /datum/job/bitrunner, /datum/job/shaft_miner, // Service /datum/job/chaplain, @@ -100,6 +101,7 @@ /datum/job/chief_medical_officer, /datum/job/research_director, /datum/job/quartermaster, + /datum/job/chief_engineer, ) /datum/traitor_objective/destroy_heirloom/captain diff --git a/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm b/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm new file mode 100644 index 0000000000000..9b8f519da959d --- /dev/null +++ b/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm @@ -0,0 +1,43 @@ +/datum/traitor_objective/ultimate/battle_royale + name = "Implant crewmembers with a subtle implant, then make them fight to the death on pay-per-view TV." + description = "Go to %AREA%, and receive the Royale Broadcast Kit. \ + Use the contained implant on station personnel to subtly implant them with a micro-explosive. \ + Once you have at least six contestants, use the contained remote to start a timer and begin broadcasting live. \ + If more than one contestant remains alive after ten minutes, all of the implants will detonate." + + ///Area type the objective owner must be in to receive the tools. + var/area/kit_spawn_area + ///Whether the kit was sent already. + var/equipped = FALSE + +/datum/traitor_objective/ultimate/battle_royale/generate_objective(datum/mind/generating_for, list/possible_duplicates) + var/list/possible_areas = GLOB.the_station_areas.Copy() + for(var/area/possible_area as anything in possible_areas) + if(ispath(possible_area, /area/station/hallway) || ispath(possible_area, /area/station/security)) + possible_areas -= possible_area + if(length(possible_areas) == 0) + return FALSE + kit_spawn_area = pick(possible_areas) + replace_in_name("%AREA%", initial(kit_spawn_area.name)) + return TRUE + +/datum/traitor_objective/ultimate/battle_royale/generate_ui_buttons(mob/user) + var/list/buttons = list() + if(!equipped) + buttons += add_ui_button("", "Pressing this will call down a pod with the Royale Broadcast kit.", "biohazard", "deliver_kit") + return buttons + +/datum/traitor_objective/ultimate/battle_royale/ui_perform_action(mob/living/user, action) + . = ..() + if(action != "deliver_kit" || equipped) + return + var/area/delivery_area = get_area(user) + if(delivery_area.type != kit_spawn_area) + to_chat(user, span_warning("You must be in [initial(kit_spawn_area.name)] to receive the Royale Broadcast kit.")) + return + equipped = TRUE + podspawn(list( + "target" = get_turf(user), + "style" = STYLE_SYNDICATE, + "spawn" = /obj/item/storage/box/syndie_kit/battle_royale, + )) diff --git a/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm b/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm index 6d8bd27f9c7d2..cb9f4ac73aaf8 100644 --- a/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm +++ b/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm @@ -1,11 +1,12 @@ /datum/traitor_objective_category/final_objective name = "Final Objective" objectives = list( - /datum/traitor_objective/ultimate/romerol = 1, /datum/traitor_objective/ultimate/battlecruiser = 1, - /datum/traitor_objective/ultimate/supermatter_cascade = 1, - /datum/traitor_objective/ultimate/infect_ai = 1, + /datum/traitor_objective/ultimate/battle_royale = 1, /datum/traitor_objective/ultimate/dark_matteor = 1, + /datum/traitor_objective/ultimate/infect_ai = 1, + /datum/traitor_objective/ultimate/romerol = 1, + /datum/traitor_objective/ultimate/supermatter_cascade = 1, ) weight = 100 diff --git a/code/modules/antagonists/traitor/objectives/infect.dm b/code/modules/antagonists/traitor/objectives/infect.dm index 5f761a273fce5..459e8f54a0d70 100644 --- a/code/modules/antagonists/traitor/objectives/infect.dm +++ b/code/modules/antagonists/traitor/objectives/infect.dm @@ -166,7 +166,7 @@ to_chat(affected_mob, span_warning("You feel someone try to inject you with something.")) balloon_alert(user, "injecting...") log_combat(user, affected_mob, "attempted to inject", src) - if(!do_after(user, 1.5 SECONDS)) + if(!do_after(user, 1.5 SECONDS, hidden = TRUE)) balloon_alert(user, "interrupted!") return var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness() diff --git a/code/modules/antagonists/traitor/objectives/kidnapping.dm b/code/modules/antagonists/traitor/objectives/kidnapping.dm index d6aec912fdbac..ea7fef9b4b607 100644 --- a/code/modules/antagonists/traitor/objectives/kidnapping.dm +++ b/code/modules/antagonists/traitor/objectives/kidnapping.dm @@ -48,7 +48,7 @@ /datum/job/chemist, /datum/job/doctor, /datum/job/psychologist, - /datum/job/virologist, + /datum/job/coroner, // Science /datum/job/geneticist, /datum/job/roboticist, @@ -80,6 +80,7 @@ target_jobs = list( // Cargo + /datum/job/bitrunner, /datum/job/shaft_miner, // Medical /datum/job/paramedic, diff --git a/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm b/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm index b3e211d28671f..1976fd38fc8ae 100644 --- a/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm +++ b/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm @@ -192,7 +192,7 @@ for(var/mob/living/silicon/ai/ai_player in GLOB.player_list) to_chat(ai_player, alertstr) - if(!do_after(user, 30 SECONDS, src, IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM | IGNORE_INCAPACITATED | IGNORE_SLOWDOWNS, extra_checks = CALLBACK(src, PROC_REF(scan_checks), user, user_area, objective))) + if(!do_after(user, 30 SECONDS, src, IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM | IGNORE_INCAPACITATED | IGNORE_SLOWDOWNS, extra_checks = CALLBACK(src, PROC_REF(scan_checks), user, user_area, objective), hidden = TRUE)) playsound(user, 'sound/machines/buzz-sigh.ogg', 30, TRUE) return diff --git a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm index 48a295989816e..5f3e2387a351f 100644 --- a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm +++ b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm @@ -49,7 +49,7 @@ GLOBAL_DATUM_INIT(objective_machine_handler, /datum/objective_target_machine_han for(var/obj/machinery/machine as anything in possible_machines) prepare_machine(machine) - replace_in_name("%JOB%", lowertext(chosen_job)) + replace_in_name("%JOB%", LOWER_TEXT(chosen_job)) replace_in_name("%MACHINE%", possible_machines[1].name) return TRUE @@ -66,7 +66,6 @@ GLOBAL_DATUM_INIT(objective_machine_handler, /datum/objective_target_machine_han telecrystal_reward = list(3, 4) progression_minimum = 15 MINUTES - progression_maximum = 30 MINUTES applicable_jobs = list( JOB_STATION_ENGINEER = /obj/machinery/telecomms/hub, @@ -165,7 +164,7 @@ GLOBAL_DATUM_INIT(objective_machine_handler, /datum/objective_target_machine_han if (. || !istype(target, target_machine_path)) return balloon_alert(user, "planting device...") - if(!do_after(user, delay = deploy_time, target = src, interaction_key = DOAFTER_SOURCE_PLANTING_DEVICE)) + if(!do_after(user, delay = deploy_time, target = src, interaction_key = DOAFTER_SOURCE_PLANTING_DEVICE, hidden = TRUE)) return TRUE target.AddComponent(\ /datum/component/interaction_booby_trap,\ diff --git a/code/modules/antagonists/traitor/objectives/steal.dm b/code/modules/antagonists/traitor/objectives/steal.dm index 61d4796d66fb1..22d8ed7d39c7b 100644 --- a/code/modules/antagonists/traitor/objectives/steal.dm +++ b/code/modules/antagonists/traitor/objectives/steal.dm @@ -285,7 +285,7 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) if(result & COMPONENT_FORCE_FAIL_PLACEMENT || !istype(target, target_object_type)) balloon_alert(user, "you can't attach this onto here!") return - if(!do_after(user, deploy_time, src)) + if(!do_after(user, deploy_time, src, hidden = TRUE)) return if(planted_on) return diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index 44d00f3c17047..40b15248413a7 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -362,7 +362,7 @@ qdel(src) return RegisterSignal(src, COMSIG_MOVABLE_CROSS_OVER, PROC_REF(check_teleport)) - SSmove_manager.move_towards(src, get_turf(whistle.whistler)) + GLOB.move_manager.move_towards(src, get_turf(whistle.whistler)) /// Check if anything the tornado crosses is the creator. /obj/effect/temp_visual/teleporting_tornado/proc/check_teleport(datum/source, atom/movable/crossed) diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index edb218a3c7631..b5ed82a7f2b50 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -394,6 +394,7 @@ soulstone_spirit.faction |= "[REF(user)]" //Add the master as a faction, allowing inter-mob cooperation if(IS_CULTIST(user)) soulstone_spirit.mind.add_antag_datum(/datum/antagonist/cult) + SSblackbox.record_feedback("tally", "cult_shade_created", 1) soulstone_spirit.cancel_camera() update_appearance() @@ -454,6 +455,7 @@ if(CONSTRUCT_JUGGERNAUT) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_jugger", 1) return switch(theme) if(THEME_WIZARD) @@ -465,6 +467,7 @@ if(CONSTRUCT_WRAITH) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_wraith", 1) return switch(theme) if(THEME_WIZARD) @@ -476,6 +479,7 @@ if(CONSTRUCT_ARTIFICER) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_arti", 1) return switch(theme) if(THEME_WIZARD) diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm index aece8d6741ba3..69c33e751ece7 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm @@ -1,44 +1,45 @@ +#define SPELLBOOK_CATEGORY_ASSISTANCE "Assistance" // Wizard spells that assist the caster in some way /datum/spellbook_entry/summonitem name = "Summon Item" desc = "Recalls a previously marked item to your hand from anywhere in the universe." spell_type = /datum/action/cooldown/spell/summonitem - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE cost = 1 /datum/spellbook_entry/charge name = "Charge" desc = "This spell can be used to recharge a variety of things in your hands, from magical artifacts to electrical components. A creative wizard can even use it to grant magical power to a fellow magic user." spell_type = /datum/action/cooldown/spell/charge - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE cost = 1 /datum/spellbook_entry/shapeshift name = "Wild Shapeshift" desc = "Take on the shape of another for a time to use their natural abilities. Once you've made your choice it cannot be changed." spell_type = /datum/action/cooldown/spell/shapeshift/wizard - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE cost = 1 /datum/spellbook_entry/tap name = "Soul Tap" desc = "Fuel your spells using your own soul!" spell_type = /datum/action/cooldown/spell/tap - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE cost = 1 /datum/spellbook_entry/item/staffanimation name = "Staff of Animation" desc = "An arcane staff capable of shooting bolts of eldritch energy which cause inanimate objects to come to life. This magic doesn't affect machines." item_path = /obj/item/gun/magic/staff/animate - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE /datum/spellbook_entry/item/soulstones name = "Soulstone Shard Kit" desc = "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. \ The spell Artificer allows you to create arcane machines for the captured souls to pilot." item_path = /obj/item/storage/belt/soulstone/full - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE /datum/spellbook_entry/item/soulstones/try_equip_item(mob/living/carbon/human/user, obj/item/to_equip) var/was_equipped = user.equip_to_slot_if_possible(to_equip, ITEM_SLOT_BELT, disable_warning = TRUE) @@ -56,13 +57,13 @@ name = "A Necromantic Stone" desc = "A Necromantic stone is able to resurrect three dead individuals as skeletal thralls for you to command." item_path = /obj/item/necromantic_stone - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE /datum/spellbook_entry/item/contract name = "Contract of Apprenticeship" desc = "A magical contract binding an apprentice wizard to your service, using it will summon them to your side." item_path = /obj/item/antag_spawner/contract - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE refundable = TRUE /datum/spellbook_entry/item/guardian @@ -70,7 +71,7 @@ desc = "A deck of guardian tarot cards, capable of binding a personal guardian to your body. There are multiple types of guardian available, but all of them will transfer some amount of damage to you. \ It would be wise to avoid buying these with anything capable of causing you to swap bodies with others." item_path = /obj/item/guardian_creator/wizard - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE /datum/spellbook_entry/item/bloodbottle name = "Bottle of Blood" @@ -80,7 +81,7 @@ in their killing, and you yourself may become a victim." item_path = /obj/item/antag_spawner/slaughter_demon limit = 3 - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE refundable = TRUE /datum/spellbook_entry/item/hugbottle @@ -95,7 +96,7 @@ item_path = /obj/item/antag_spawner/slaughter_demon/laughter cost = 1 //non-destructive; it's just a jape, sibling! limit = 3 - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE refundable = TRUE /datum/spellbook_entry/item/vendormancer @@ -105,4 +106,6 @@ throw around to squash oponents or be directly detonated. When out of \ charges a long channel will restore the charges." item_path = /obj/item/runic_vendor_scepter - category = "Assistance" + category = SPELLBOOK_CATEGORY_ASSISTANCE + +#undef SPELLBOOK_CATEGORY_ASSISTANCE diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/defensive.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/defensive.dm index 1ffac3cf3af4e..a66d99c21c88d 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/defensive.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/defensive.dm @@ -1,49 +1,50 @@ +#define SPELLBOOK_CATEGORY_DEFENSIVE "Defensive" // Defensive wizard spells /datum/spellbook_entry/magicm name = "Magic Missile" desc = "Fires several, slow moving, magic projectiles at nearby targets." spell_type = /datum/action/cooldown/spell/aoe/magic_missile - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/disabletech name = "Disable Tech" desc = "Disables all weapons, cameras and most other technology in range." spell_type = /datum/action/cooldown/spell/emp/disable_tech - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE cost = 1 /datum/spellbook_entry/repulse name = "Repulse" desc = "Throws everything around the user away." spell_type = /datum/action/cooldown/spell/aoe/repulse/wizard - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/lightning_packet name = "Thrown Lightning" desc = "Forged from eldrich energies, a packet of pure power, \ known as a spell packet will appear in your hand, that when thrown will stun the target." spell_type = /datum/action/cooldown/spell/conjure_item/spellpacket - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/timestop name = "Time Stop" desc = "Stops time for everyone except for you, allowing you to move freely \ while your enemies and even projectiles are frozen." spell_type = /datum/action/cooldown/spell/timestop - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/smoke name = "Smoke" desc = "Spawns a cloud of choking smoke at your location." spell_type = /datum/action/cooldown/spell/smoke - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE cost = 1 /datum/spellbook_entry/forcewall name = "Force Wall" desc = "Create a magical barrier that only you can pass through." spell_type = /datum/action/cooldown/spell/forcewall - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE cost = 1 /datum/spellbook_entry/lichdom @@ -53,28 +54,28 @@ no matter the circumstances. Be wary - with each revival, your body will become weaker, and \ it will become easier for others to find your item of power." spell_type = /datum/action/cooldown/spell/lichdom - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE no_coexistance_typecache = list(/datum/action/cooldown/spell/splattercasting) /datum/spellbook_entry/chuunibyou name = "Chuuni Invocations" desc = "Makes all your spells shout invocations, and the invocations become... stupid. You heal slightly after casting a spell." spell_type = /datum/action/cooldown/spell/chuuni_invocations - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/spacetime_dist name = "Spacetime Distortion" desc = "Entangle the strings of space-time in an area around you, \ randomizing the layout and making proper movement impossible. The strings vibrate..." spell_type = /datum/action/cooldown/spell/spacetime_dist - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE cost = 1 /datum/spellbook_entry/the_traps name = "The Traps!" desc = "Summon a number of traps around you. They will damage and enrage any enemies that step on them." spell_type = /datum/action/cooldown/spell/conjure/the_traps - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE cost = 1 /datum/spellbook_entry/bees @@ -82,7 +83,7 @@ desc = "This spell magically kicks a transdimensional beehive, \ instantly summoning a swarm of bees to your location. These bees are NOT friendly to anyone." spell_type = /datum/action/cooldown/spell/conjure/bee - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/duffelbag name = "Bestow Cursed Duffel Bag" @@ -91,7 +92,7 @@ if it is not fed regularly, and regardless of whether or not it's been fed, \ it will slow the person wearing it down significantly." spell_type = /datum/action/cooldown/spell/touch/duffelbag - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE cost = 1 /datum/spellbook_entry/item/staffhealing @@ -99,26 +100,26 @@ desc = "An altruistic staff that can heal the lame and raise the dead." item_path = /obj/item/gun/magic/staff/healing cost = 1 - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/item/lockerstaff name = "Staff of the Locker" desc = "A staff that shoots lockers. It eats anyone it hits on its way, leaving a welded locker with your victims behind." item_path = /obj/item/gun/magic/staff/locker - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/item/scryingorb name = "Scrying Orb" desc = "An incandescent orb of crackling energy. Using it will allow you to release your ghost while alive, allowing you to spy upon the station and talk to the deceased. In addition, buying it will permanently grant you X-ray vision." item_path = /obj/item/scrying - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/item/wands name = "Wand Assortment" desc = "A collection of wands that allow for a wide variety of utility. \ Wands have a limited number of charges, so be conservative with their use. Comes in a handy belt." item_path = /obj/item/storage/belt/wands/full - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/item/wands/try_equip_item(mob/living/carbon/human/user, obj/item/to_equip) var/was_equipped = user.equip_to_slot_if_possible(to_equip, ITEM_SLOT_BELT, disable_warning = TRUE) @@ -130,7 +131,7 @@ while providing more protection against attacks and the void of space. \ Also grants a battlemage shield." item_path = /obj/item/mod/control/pre_equipped/enchanted - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE /datum/spellbook_entry/item/armor/try_equip_item(mob/living/carbon/human/user, obj/item/to_equip) var/obj/item/mod/control/mod = to_equip @@ -151,5 +152,7 @@ name = "Battlemage Armour Charges" desc = "A powerful defensive rune, it will grant eight additional charges to a battlemage shield." item_path = /obj/item/wizard_armour_charge - category = "Defensive" + category = SPELLBOOK_CATEGORY_DEFENSIVE cost = 1 + +#undef SPELLBOOK_CATEGORY_DEFENSIVE diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/mobility.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/mobility.dm index 6a8f322a3a5f4..bc09b092f6cd9 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/mobility.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/mobility.dm @@ -1,47 +1,48 @@ +#define SPELLBOOK_CATEGORY_MOBILITY "Mobility" // Wizard spells that aid mobiilty(or stealth?) /datum/spellbook_entry/mindswap name = "Mindswap" desc = "Allows you to switch bodies with a target next to you. You will both fall asleep when this happens, and it will be quite obvious that you are the target's body if someone watches you do it." spell_type = /datum/action/cooldown/spell/pointed/mind_transfer - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY /datum/spellbook_entry/knock name = "Knock" desc = "Opens nearby doors and closets." spell_type = /datum/action/cooldown/spell/aoe/knock - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY cost = 1 /datum/spellbook_entry/blink name = "Blink" desc = "Randomly teleports you a short distance." spell_type = /datum/action/cooldown/spell/teleport/radius_turf/blink - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY /datum/spellbook_entry/teleport name = "Teleport" desc = "Teleports you to an area of your selection." spell_type = /datum/action/cooldown/spell/teleport/area_teleport/wizard - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY /datum/spellbook_entry/jaunt name = "Ethereal Jaunt" desc = "Turns your form ethereal, temporarily making you invisible and able to pass through walls." spell_type = /datum/action/cooldown/spell/jaunt/ethereal_jaunt - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY /datum/spellbook_entry/swap name = "Swap" desc = "Switch places with any living target within nine tiles. Right click to mark a secondary target. You will always swap to your primary target." spell_type = /datum/action/cooldown/spell/pointed/swap - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY cost = 1 /datum/spellbook_entry/item/warpwhistle name = "Warp Whistle" desc = "A strange whistle that will transport you to a distant safe place on the station. There is a window of vulnerability at the beginning of every use." item_path = /obj/item/warp_whistle - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY cost = 1 /datum/spellbook_entry/item/staffdoor @@ -49,11 +50,13 @@ desc = "A particular staff that can mold solid walls into ornate doors. Useful for getting around in the absence of other transportation. Does not work on glass." item_path = /obj/item/gun/magic/staff/door cost = 1 - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY /datum/spellbook_entry/item/teleport_rod name = /obj/item/teleport_rod::name desc = /obj/item/teleport_rod::desc item_path = /obj/item/teleport_rod cost = 2 // Puts it at 3 cost if you go for safety instant summons, but teleporting anywhere on screen is pretty good. - category = "Mobility" + category = SPELLBOOK_CATEGORY_MOBILITY + +#undef SPELLBOOK_CATEGORY_MOBILITY diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/offensive.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/offensive.dm index b23de0aa6b069..9eb35cbf7b42e 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/offensive.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/offensive.dm @@ -1,27 +1,28 @@ +#define SPELLBOOK_CATEGORY_OFFENSIVE "Offensive" // Offensive wizard spells /datum/spellbook_entry/fireball name = "Fireball" desc = "Fires an explosive fireball at a target. Considered a classic among all wizards." spell_type = /datum/action/cooldown/spell/pointed/projectile/fireball - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/spell_cards name = "Spell Cards" desc = "Blazing hot rapid-fire homing cards. Send your foes to the shadow realm with their mystical power!" spell_type = /datum/action/cooldown/spell/pointed/projectile/spell_cards - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/rod_form name = "Rod Form" desc = "Take on the form of an immovable rod, destroying all in your path. Purchasing this spell multiple times will also increase the rod's damage and travel range." spell_type = /datum/action/cooldown/spell/rod_form - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/disintegrate name = "Smite" desc = "Charges your hand with an unholy energy that can be used to cause a touched victim to violently explode." spell_type = /datum/action/cooldown/spell/touch/smite - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/summon_simians name = "Summon Simians" @@ -29,45 +30,45 @@ summons primal monkeys and lesser gorillas that will promptly flip out and attack everything in sight. Fun! \ Their lesser, easily manipulable minds will be convinced you are one of their allies, but only for a minute. Unless you also are a monkey." spell_type = /datum/action/cooldown/spell/conjure/simian - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/blind name = "Blind" desc = "Temporarily blinds a single target." spell_type = /datum/action/cooldown/spell/pointed/blind - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE cost = 1 /datum/spellbook_entry/mutate name = "Mutate" desc = "Causes you to turn into a hulk and gain laser vision for a short while." spell_type = /datum/action/cooldown/spell/apply_mutations/mutate - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/fleshtostone name = "Flesh to Stone" desc = "Charges your hand with the power to turn victims into inert statues for a long period of time." spell_type = /datum/action/cooldown/spell/touch/flesh_to_stone - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/teslablast name = "Tesla Blast" desc = "Charge up a tesla arc and release it at a random nearby target! You can move freely while it charges. The arc jumps between targets and can knock them down." spell_type = /datum/action/cooldown/spell/charged/beam/tesla - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/lightningbolt name = "Lightning Bolt" desc = "Fire a lightning bolt at your foes! It will jump between targets, but can't knock them down." spell_type = /datum/action/cooldown/spell/pointed/projectile/lightningbolt - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE cost = 1 /datum/spellbook_entry/infinite_guns name = "Lesser Summon Guns" desc = "Why reload when you have infinite guns? Summons an unending stream of bolt action rifles that deal little damage, but will knock targets down. Requires both hands free to use. Learning this spell makes you unable to learn Arcane Barrage." spell_type = /datum/action/cooldown/spell/conjure_item/infinite_guns/gun - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE cost = 3 no_coexistance_typecache = list(/datum/action/cooldown/spell/conjure_item/infinite_guns/arcane_barrage) @@ -75,7 +76,7 @@ name = "Arcane Barrage" desc = "Fire a torrent of arcane energy at your foes with this (powerful) spell. Deals much more damage than Lesser Summon Guns, but won't knock targets down. Requires both hands free to use. Learning this spell makes you unable to learn Lesser Summon Gun." spell_type = /datum/action/cooldown/spell/conjure_item/infinite_guns/arcane_barrage - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE cost = 3 no_coexistance_typecache = list(/datum/action/cooldown/spell/conjure_item/infinite_guns/gun) @@ -83,68 +84,77 @@ name = "Barnyard Curse" desc = "This spell dooms an unlucky soul to possess the speech and facial attributes of a barnyard animal." spell_type = /datum/action/cooldown/spell/pointed/barnyardcurse - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/splattercasting name = "Splattercasting" desc = "Dramatically lowers the cooldown on all spells, but each one will cost blood, as well as it naturally \ draining from you over time. You can replenish it from your victims, specifically their necks." spell_type = /datum/action/cooldown/spell/splattercasting - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE no_coexistance_typecache = list(/datum/action/cooldown/spell/lichdom) /datum/spellbook_entry/sanguine_strike name = "Exsanguinating Strike" desc = "Sanguine spell that enchants your next weapon strike to deal more damage, heal you for damage dealt, and refill blood." spell_type = /datum/action/cooldown/spell/sanguine_strike - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/scream_for_me name = "Scream For Me" desc = "Sadistic sanguine spell that inflicts numerous severe blood wounds all over the victim's body." spell_type = /datum/action/cooldown/spell/touch/scream_for_me cost = 1 - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/item/staffchaos name = "Staff of Chaos" desc = "A caprious tool that can fire all sorts of magic without any rhyme or reason. Using it on people you care about is not recommended." item_path = /obj/item/gun/magic/staff/chaos - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/item/staffchange name = "Staff of Change" desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself." item_path = /obj/item/gun/magic/staff/change - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/item/mjolnir name = "Mjolnir" desc = "A mighty hammer on loan from Thor, God of Thunder. It crackles with barely contained power." item_path = /obj/item/mjollnir - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/item/singularity_hammer name = "Singularity Hammer" desc = "A hammer that creates an intensely powerful field of gravity where it strikes, pulling everything nearby to the point of impact." item_path = /obj/item/singularityhammer - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/item/spellblade name = "Spellblade" desc = "A sword capable of firing blasts of energy which rip targets limb from limb." item_path = /obj/item/gun/magic/staff/spellblade - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE /datum/spellbook_entry/item/highfrequencyblade name = "High Frequency Blade" desc = "An incredibly swift enchanted blade resonating at a frequency high enough to be able to slice through anything." item_path = /obj/item/highfrequencyblade/wizard - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE cost = 3 /datum/spellbook_entry/item/frog_contract name = "Frog Contract" desc = "Sign a pact with the frogs to have your own destructive pet guardian!" item_path = /obj/item/frog_contract - category = "Offensive" + category = SPELLBOOK_CATEGORY_OFFENSIVE + +/datum/spellbook_entry/item/staffshrink + name = "Staff of Shrinking" + desc = "An artefact that can shrink anything for a reasonable duration. Small structures can be walked over, and small people are very vulnerable (often because their armour no longer fits)." + item_path = /obj/item/gun/magic/staff/shrink + category = SPELLBOOK_CATEGORY_OFFENSIVE + + +#undef SPELLBOOK_CATEGORY_OFFENSIVE diff --git a/code/modules/antagonists/wizard/equipment/teleport_rod.dm b/code/modules/antagonists/wizard/equipment/teleport_rod.dm index 79df35ca25a18..a1d9904ddb27d 100644 --- a/code/modules/antagonists/wizard/equipment/teleport_rod.dm +++ b/code/modules/antagonists/wizard/equipment/teleport_rod.dm @@ -144,6 +144,7 @@ duration = 6 SECONDS alert_type = /atom/movable/screen/alert/status_effect/teleport_flux remove_on_fullheal = TRUE // staff of healing ~synergy~ + show_duration = TRUE /// Amount of damage to deal when teleporting in flux var/tp_damage = 15 diff --git a/code/modules/antagonists/wizard/grand_ritual/finales/clown.dm b/code/modules/antagonists/wizard/grand_ritual/finales/clown.dm index bda79c908c040..d2f4a5a076358 100644 --- a/code/modules/antagonists/wizard/grand_ritual/finales/clown.dm +++ b/code/modules/antagonists/wizard/grand_ritual/finales/clown.dm @@ -24,8 +24,7 @@ var/datum/action/cooldown/spell/conjure_item/clown_pockets/new_spell = new(victim) new_spell.Grant(victim) continue - if (!ismonkey(victim)) // Monkeys cannot yet wear clothes - dress_as_magic_clown(victim) + dress_as_magic_clown(victim) if (prob(15)) create_vendetta(victim.mind, invoker.mind) diff --git a/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm b/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm index f75da5f855742..79364a80a198a 100644 --- a/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm +++ b/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm @@ -187,7 +187,7 @@ tear_reality() SEND_SIGNAL(src, COMSIG_GRAND_RUNE_COMPLETE, cheese_sacrificed) flick("[icon_state]_activate", src) - addtimer(CALLBACK(src, PROC_REF(remove_rune)), 6) + addtimer(CALLBACK(src, PROC_REF(remove_rune)), 0.6 SECONDS) SSblackbox.record_feedback("amount", "grand_runes_invoked", 1) /obj/effect/grand_rune/proc/remove_rune() diff --git a/code/modules/antagonists/wizard/slaughter_antag.dm b/code/modules/antagonists/wizard/slaughter_antag.dm index c9aea4478c393..484db3d14c864 100644 --- a/code/modules/antagonists/wizard/slaughter_antag.dm +++ b/code/modules/antagonists/wizard/slaughter_antag.dm @@ -1,5 +1,6 @@ /datum/antagonist/slaughter name = "\improper Slaughter Demon" + roundend_category = "demons" show_name_in_check_antagonists = TRUE ui_name = "AntagInfoDemon" job_rank = ROLE_ALIEN @@ -38,6 +39,30 @@ data["explain_attack"] = TRUE return data +/datum/antagonist/slaughter/roundend_report() + var/list/report = list() + + if(!owner) + CRASH("Antagonist datum without owner") + + report += printplayer(owner) + + if(objectives.len) + report += printobjectives(objectives) + + var/datum/action/cooldown/spell/jaunt/bloodcrawl/slaughter_demon/consume_ability = locate() in owner.current?.actions + if(consume_ability?.consume_count > 0) + report += span_greentext("The [name] consumed a total of [consume_ability.consume_count] bodies!") + else + report += span_redtext("The [name] did not consume anyone! Shame!!") + + if(owner.current?.stat != DEAD) + report += "The [name] survived!" + else + report += "The [name] was vanquished!" + + return report.Join("
    ") + /datum/antagonist/slaughter/laughter name = "Laughter demon" objective_verb = "Hug and Tickle" diff --git a/code/modules/antagonists/xeno/xeno.dm b/code/modules/antagonists/xeno/xeno.dm index c0e5383048ff7..59c83fd52ed11 100644 --- a/code/modules/antagonists/xeno/xeno.dm +++ b/code/modules/antagonists/xeno/xeno.dm @@ -87,7 +87,7 @@ explanation_text = "Escape from captivity." /datum/objective/escape_captivity/check_completion() - if(!istype(get_area(owner), SScommunications.captivity_area)) + if(!istype(get_area(owner), GLOB.communications_controller.captivity_area)) return TRUE /datum/objective/advance_hive @@ -111,7 +111,7 @@ parts += "The [name] were:
    " - if(check_captivity(progenitor)) + if(check_captivity(progenitor.current) == CAPTIVE_XENO_PASS) parts += span_greentext("The progenitor of this hive was [progenitor.key], as [progenitor], who successfully escaped captivity!") + "
    " else parts += span_redtext("The progenitor of this hive was [progenitor.key], as [progenitor], who failed to escape captivity") + "
    " @@ -146,7 +146,7 @@ if(!captive_alien || captive_alien.stat == DEAD) return CAPTIVE_XENO_DEAD - if(istype(get_area(captive_alien), SScommunications.captivity_area)) + if(istype(get_area(captive_alien), GLOB.communications_controller.captivity_area)) return CAPTIVE_XENO_FAIL return CAPTIVE_XENO_PASS @@ -155,7 +155,7 @@ /mob/living/carbon/alien/mind_initialize() ..() if(!mind.has_antag_datum(/datum/antagonist/xeno)) - if(SScommunications.xenomorph_egg_delivered && istype(get_area(src), SScommunications.captivity_area)) + if(GLOB.communications_controller.xenomorph_egg_delivered && istype(get_area(src), GLOB.communications_controller.captivity_area)) mind.add_antag_datum(/datum/antagonist/xeno/captive) else mind.add_antag_datum(/datum/antagonist/xeno) diff --git a/code/modules/art/paintings.dm b/code/modules/art/paintings.dm index dd370f480f455..f050528bd3bc7 100644 --- a/code/modules/art/paintings.dm +++ b/code/modules/art/paintings.dm @@ -350,7 +350,7 @@ var/result = rustg_dmi_create_png(png_filename, "[width]", "[height]", image_data) if(result) CRASH("Error generating painting png : [result]") - painting_metadata.md5 = md5(lowertext(image_data)) + painting_metadata.md5 = md5(LOWER_TEXT(image_data)) generated_icon = new(png_filename) icon_generated = TRUE update_appearance() @@ -569,10 +569,12 @@ current_canvas = null update_appearance() -/obj/structure/sign/painting/AltClick(mob/user) - . = ..() - if(current_canvas?.can_select_frame(user)) - INVOKE_ASYNC(current_canvas, TYPE_PROC_REF(/obj/item/canvas, select_new_frame), user) +/obj/structure/sign/painting/click_alt(mob/user) + if(!current_canvas?.can_select_frame(user)) + return CLICK_ACTION_BLOCKING + + INVOKE_ASYNC(current_canvas, TYPE_PROC_REF(/obj/item/canvas, select_new_frame), user) + return CLICK_ACTION_SUCCESS /obj/structure/sign/painting/proc/frame_canvas(mob/user, obj/item/canvas/new_canvas) if(!(new_canvas.type in accepted_canvas_types)) @@ -663,7 +665,7 @@ stack_trace("Invalid persistence_id - [persistence_id]") return var/data = current_canvas.get_data_string() - var/md5 = md5(lowertext(data)) + var/md5 = md5(LOWER_TEXT(data)) var/list/current = SSpersistent_paintings.paintings[persistence_id] if(!current) current = list() diff --git a/code/modules/art/statues.dm b/code/modules/art/statues.dm index caebda5076605..8ed46a5bf81af 100644 --- a/code/modules/art/statues.dm +++ b/code/modules/art/statues.dm @@ -30,35 +30,28 @@ /obj/structure/statue/wrench_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return FALSE default_unfasten_wrench(user, tool) return ITEM_INTERACT_SUCCESS /obj/structure/statue/attackby(obj/item/W, mob/living/user, params) add_fingerprint(user) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(W.tool_behaviour == TOOL_WELDER) - if(!W.tool_start_check(user, amount=1)) - return FALSE - user.balloon_alert(user, "slicing apart...") - if(W.use_tool(src, user, 40, volume=50)) - deconstruct(TRUE) - return + if(W.tool_behaviour == TOOL_WELDER) + if(!W.tool_start_check(user, amount=1)) + return FALSE + user.balloon_alert(user, "slicing apart...") + if(W.use_tool(src, user, 40, volume=50)) + deconstruct(TRUE) + return return ..() -/obj/structure/statue/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation - -/obj/structure/statue/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/amount_mod = disassembled ? 0 : -2 - for(var/mat in custom_materials) - var/datum/material/custom_material = GET_MATERIAL_REF(mat) - var/amount = max(0,round(custom_materials[mat]/SHEET_MATERIAL_AMOUNT) + amount_mod) - if(amount > 0) - new custom_material.sheet_type(drop_location(), amount) - qdel(src) + +/obj/structure/statue/atom_deconstruct(disassembled = TRUE) + var/amount_mod = disassembled ? 0 : -2 + for(var/mat in custom_materials) + var/datum/material/custom_material = GET_MATERIAL_REF(mat) + var/amount = max(0,round(custom_materials[mat]/SHEET_MATERIAL_AMOUNT) + amount_mod) + if(amount > 0) + new custom_material.sheet_type(drop_location(), amount) //////////////////////////////////////STATUES///////////////////////////////////////////////////////////// ////////////////////////uranium/////////////////////////////////// diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm index f5f33afa83c34..31584976cedf3 100644 --- a/code/modules/assembly/doorcontrol.dm +++ b/code/modules/assembly/doorcontrol.dm @@ -32,7 +32,7 @@ if(openclose == null || !sync_doors) openclose = M.density INVOKE_ASYNC(M, openclose ? TYPE_PROC_REF(/obj/machinery/door/poddoor, open) : TYPE_PROC_REF(/obj/machinery/door/poddoor, close)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 1 SECONDS) /obj/item/assembly/control/curtain name = "curtain controller" @@ -53,7 +53,7 @@ if(openclose == null || !sync_doors) openclose = M.density INVOKE_ASYNC(M, openclose ? TYPE_PROC_REF(/obj/structure/curtain/cloth/fancy/mechanical, open) : TYPE_PROC_REF(/obj/structure/curtain/cloth/fancy/mechanical, close)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 5) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 0.5 SECONDS) /obj/item/assembly/control/airlock @@ -101,7 +101,7 @@ for(var/D in open_or_close) INVOKE_ASYNC(D, doors_need_closing ? TYPE_PROC_REF(/obj/machinery/door/airlock, close) : TYPE_PROC_REF(/obj/machinery/door/airlock, open)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 1 SECONDS) /obj/item/assembly/control/massdriver @@ -130,7 +130,7 @@ if (M.id == src.id) INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/machinery/door/poddoor, close)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 1 SECONDS) /obj/item/assembly/control/igniter @@ -149,7 +149,7 @@ if(M.id == src.id) INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/machinery/igniter, toggle)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 30) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 3 SECONDS) /obj/item/assembly/control/flasher name = "flasher controller" @@ -163,7 +163,7 @@ if(M.id == src.id) INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/machinery/flasher, flash)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 5 SECONDS) /obj/item/assembly/control/crematorium @@ -178,4 +178,4 @@ if (C.id == id) C.cremate(usr) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 5 SECONDS) diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index 659bcec50cf97..b81eb26e7fae9 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -43,7 +43,7 @@ flashing = flash . = ..() if(flash) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_icon)), 5) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_icon)), 0.5 SECONDS) holder?.update_icon(updates) /obj/item/assembly/flash/update_overlays() diff --git a/code/modules/assembly/health.dm b/code/modules/assembly/health.dm index 23c329894e7b8..20316ebfd66d1 100644 --- a/code/modules/assembly/health.dm +++ b/code/modules/assembly/health.dm @@ -7,11 +7,10 @@ var/scanning = FALSE var/health_scan - var/alarm_health = HEALTH_THRESHOLD_CRIT + var/health_target = HEALTH_THRESHOLD_CRIT /obj/item/assembly/health/examine(mob/user) . = ..() - . += "Use it in hand to turn it off/on and Alt-click to swap between \"detect death\" mode and \"detect critical state\" mode." . += "[src.scanning ? "The sensor is on and you can see [health_scan] displayed on the screen" : "The sensor is off"]." /obj/item/assembly/health/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) @@ -37,17 +36,6 @@ update_appearance() return secured -/obj/item/assembly/health/AltClick(mob/living/user) - if(!can_interact(user)) - return - - if(alarm_health == HEALTH_THRESHOLD_CRIT) - alarm_health = HEALTH_THRESHOLD_DEAD - to_chat(user, span_notice("You toggle [src] to \"detect death\" mode.")) - else - alarm_health = HEALTH_THRESHOLD_CRIT - to_chat(user, span_notice("You toggle [src] to \"detect critical state\" mode.")) - /obj/item/assembly/health/process() //not ready yet if(!scanning || !secured) @@ -65,7 +53,7 @@ //only do the pulse if we are within alarm thresholds var/mob/living/target_mob = object health_scan = target_mob.health - if(health_scan > alarm_health) + if(health_scan > health_target) return //do the pulse & the scan @@ -84,14 +72,43 @@ STOP_PROCESSING(SSobj, src) return -/obj/item/assembly/health/attack_self(mob/user) - . = ..() - if (secured) - balloon_alert(user, "scanning [scanning ? "disabled" : "enabled"]") +/obj/item/assembly/health/proc/toggle_target() + if(health_target == HEALTH_THRESHOLD_CRIT) + health_target = HEALTH_THRESHOLD_DEAD else - balloon_alert(user, "secure it first!") - toggle_scan() + health_target = HEALTH_THRESHOLD_CRIT + return /obj/item/assembly/health/proc/get_status_tab_item(mob/living/carbon/source, list/items) SIGNAL_HANDLER items += "Health: [round((source.health / source.maxHealth) * 100)]%" + + +/obj/item/assembly/health/ui_status(mob/user, datum/ui_state/state) + return is_secured(user) ? ..() : UI_CLOSE + +/obj/item/assembly/health/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "HealthSensor", name) + ui.open() + +/obj/item/assembly/health/ui_data(mob/user) + var/list/data = list() + data["health"] = health_scan + data["scanning"] = scanning + data["target"] = health_target + return data + +/obj/item/assembly/health/ui_act(action, params) + . = ..() + if(.) + return . + + switch(action) + if("scanning") + toggle_scan() + return TRUE + if("target") + toggle_target() + return TRUE diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index 70f116b3e3e09..5f50618e77dfa 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -141,8 +141,6 @@ return ..() -/obj/item/assembly_holder/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/item/assembly_holder/screwdriver_act(mob/user, obj/item/tool) if(..()) diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index b5c847a78abb5..8dd4573fcfde1 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -35,8 +35,6 @@ buffer_turf = null return ..() -/obj/item/assembly/infra/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/item/assembly/infra/examine(mob/user) . = ..() diff --git a/code/modules/asset_cache/assets/arcade.dm b/code/modules/asset_cache/assets/arcade.dm index bcd23919f9797..338b891190cd4 100644 --- a/code/modules/asset_cache/assets/arcade.dm +++ b/code/modules/asset_cache/assets/arcade.dm @@ -1,5 +1,7 @@ /datum/asset/simple/arcade assets = list( + "shopkeeper.png" = 'icons/ui_icons/arcade/shopkeeper.png', + "fireplace.png" = 'icons/ui_icons/arcade/fireplace.png', "boss1.gif" = 'icons/ui_icons/arcade/boss1.gif', "boss2.gif" = 'icons/ui_icons/arcade/boss2.gif', "boss3.gif" = 'icons/ui_icons/arcade/boss3.gif', diff --git a/code/modules/asset_cache/assets/icon_ref_map.dm b/code/modules/asset_cache/assets/icon_ref_map.dm new file mode 100644 index 0000000000000..2f7f846309912 --- /dev/null +++ b/code/modules/asset_cache/assets/icon_ref_map.dm @@ -0,0 +1,28 @@ +/// Maps icon names to ref values +/datum/asset/json/icon_ref_map + name = "icon_ref_map" + early = TRUE + +/datum/asset/json/icon_ref_map/generate() + var/list/data = list() //"icons/obj/drinks.dmi" => "[0xc000020]" + + //var/start = "0xc000000" + var/value = 0 + + while(TRUE) + value += 1 + var/ref = "\[0xc[num2text(value,6,16)]\]" + var/mystery_meat = locate(ref) + + if(isicon(mystery_meat)) + if(!isfile(mystery_meat)) // Ignore the runtime icons for now + continue + var/path = get_icon_dmi_path(mystery_meat) //Try to get the icon path + if(path) + data[path] = ref + else if(mystery_meat) + continue; //Some other non-icon resource, ogg/json/whatever + else //Out of resources end this, could also try to end this earlier as soon as runtime generated icons appear but eh + break; + + return data diff --git a/code/modules/asset_cache/assets/tgui.dm b/code/modules/asset_cache/assets/tgui.dm index 9c79925602c77..4b31d93e037f5 100644 --- a/code/modules/asset_cache/assets/tgui.dm +++ b/code/modules/asset_cache/assets/tgui.dm @@ -1,3 +1,23 @@ +// If you use a file(...) object, instead of caching the asset it will be loaded from disk every time it's requested. +// This is useful for development, but not recommended for production. +// And if TGS is defined, we're being run in a production environment. + +#ifdef TGS +/datum/asset/simple/tgui + keep_local_name = FALSE + assets = list( + "tgui.bundle.js" = "tgui/public/tgui.bundle.js", + "tgui.bundle.css" = "tgui/public/tgui.bundle.css", + ) + +/datum/asset/simple/tgui_panel + keep_local_name = FALSE + assets = list( + "tgui-panel.bundle.js" = "tgui/public/tgui-panel.bundle.js", + "tgui-panel.bundle.css" = "tgui/public/tgui-panel.bundle.css", + ) + +#else /datum/asset/simple/tgui keep_local_name = TRUE assets = list( @@ -11,3 +31,5 @@ "tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"), "tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"), ) + +#endif diff --git a/code/modules/asset_cache/assets/uplink.dm b/code/modules/asset_cache/assets/uplink.dm index e283b86c04299..e85ee1b35b5c1 100644 --- a/code/modules/asset_cache/assets/uplink.dm +++ b/code/modules/asset_cache/assets/uplink.dm @@ -9,7 +9,7 @@ var/list/items = list() for(var/datum/uplink_category/category as anything in subtypesof(/datum/uplink_category)) categories += category - categories = sortTim(categories, GLOBAL_PROC_REF(cmp_uplink_category_desc)) + sortTim(categories, GLOBAL_PROC_REF(cmp_uplink_category_desc)) var/list/new_categories = list() for(var/datum/uplink_category/category as anything in categories) diff --git a/code/modules/asset_cache/transports/asset_transport.dm b/code/modules/asset_cache/transports/asset_transport.dm index 19e40fb48848e..3dbcc301843cc 100644 --- a/code/modules/asset_cache/transports/asset_transport.dm +++ b/code/modules/asset_cache/transports/asset_transport.dm @@ -82,11 +82,15 @@ /// asset_list - A list of asset filenames to be sent to the client. Can optionally be assoicated with the asset's asset_cache_item datum. /// Returns TRUE if any assets were sent. /datum/asset_transport/proc/send_assets(client/client, list/asset_list) +#if defined(UNIT_TESTS) + return +#endif + if (!istype(client)) if (ismob(client)) - var/mob/M = client - if (M.client) - client = M.client + var/mob/our_mob = client + if (our_mob.client) + client = our_mob.client else //no stacktrace because this will mainly happen because the client went away return else diff --git a/code/modules/atmospherics/Atmospherics.md b/code/modules/atmospherics/Atmospherics.md index 6d61a8cf16bcc..1203ed232e184 100644 --- a/code/modules/atmospherics/Atmospherics.md +++ b/code/modules/atmospherics/Atmospherics.md @@ -3,7 +3,7 @@ This file will be written in the first person in the interest of having a laid back style, as some of the concepts here would be ass to read as technical writing. Understand that this isn't the work of one person, but the combined efforts of several contributors. It is a living document, and one you should strive to keep up to date. -I have ~~stolen~~ adapted this document from the work of duncathan, an off and on maintainer who is responsible for the majority of the quality of the current atmos system. He pushed through several code cleanliness and sanity refactors to the system, and wrote the rundown of gas mixtures you'll find in this document. See the [original](https://gist.github.com/duncathan/77d918748d153b4f31a8f76f6085b91a) for his draft. +I have ~~stolen~~ adapted this document from the work of duncathan, an off and on maintainer who is responsible for the majority of the quality of the current atmos system. Hii pushed through several code cleanliness and sanity refactors to the system, and wrote the rundown of gas mixtures you'll find in this document. See the [original](https://gist.github.com/duncathan/77d918748d153b4f31a8f76f6085b91a) for his draft. Now, the purpose of this bit of documentation. diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm index 7b21309e4e56e..f7eaf5788c9ee 100644 --- a/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm +++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm @@ -116,7 +116,7 @@ return user.visible_message(span_notice("[user.name] wires the air alarm."), \ span_notice("You start wiring the air alarm...")) - if (do_after(user, 20, target = src)) + if (do_after(user, 2 SECONDS, target = src)) if (cable.get_amount() >= 5 && buildstage == AIR_ALARM_BUILD_NO_WIRES) cable.use(5) to_chat(user, span_notice("You wire the air alarm.")) @@ -140,7 +140,7 @@ if(istype(W, /obj/item/electroadaptive_pseudocircuit)) var/obj/item/electroadaptive_pseudocircuit/P = W - if(!P.adapt_circuit(user, circuit_cost = 25 KILO JOULES)) + if(!P.adapt_circuit(user, circuit_cost = 0.025 * STANDARD_CELL_CHARGE)) return user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \ span_notice("You adapt an air alarm circuit and slot it into the assembly.")) diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index d42618e9ee99d..fa8b833234586 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -81,7 +81,7 @@ fire = 100 acid = 70 -/obj/machinery/atmospherics/LateInitialize() +/obj/machinery/atmospherics/post_machine_initialize() . = ..() update_name() @@ -301,8 +301,8 @@ * * given_layer - the piping_layer we are checking */ /obj/machinery/atmospherics/proc/connection_check(obj/machinery/atmospherics/target, given_layer) - //check if the target & src connect in the same direction - if(!((initialize_directions & get_dir(src, target)) && (target.initialize_directions & get_dir(target, src)))) + //if target is not multiz then we have to check if the target & src connect in the same direction + if(!istype(target, /obj/machinery/atmospherics/pipe/multiz) && !((initialize_directions & get_dir(src, target)) && (target.initialize_directions & get_dir(target, src)))) return FALSE //both target & src can't be connected either way @@ -607,11 +607,6 @@ animate(our_client, pixel_x = 0, pixel_y = 0, time = 0.05 SECONDS) our_client.move_delay = world.time + 0.05 SECONDS -/obj/machinery/atmospherics/AltClick(mob/living/L) - if(vent_movement & VENTCRAWL_ALLOWED && istype(L)) - L.handle_ventcrawl(src) - return - return ..() /** * Getter of a list of pipenets diff --git a/code/modules/atmospherics/machinery/bluespace_vendor.dm b/code/modules/atmospherics/machinery/bluespace_vendor.dm index 847533540180d..91da04afaf2e7 100644 --- a/code/modules/atmospherics/machinery/bluespace_vendor.dm +++ b/code/modules/atmospherics/machinery/bluespace_vendor.dm @@ -71,7 +71,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/bluespace_vendor, 30) AddComponent(/datum/component/payment, tank_cost, SSeconomy.get_dep_account(ACCOUNT_ENG), PAYMENT_ANGRY) find_and_hang_on_wall( FALSE) -/obj/machinery/bluespace_vendor/LateInitialize() +/obj/machinery/bluespace_vendor/post_machine_initialize() . = ..() if(!map_spawned) return diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm index c06863ba09266..fe6f9423b433d 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm @@ -38,13 +38,15 @@ Passive gate is similar to the regular pump except: update_appearance() return ..() -/obj/machinery/atmospherics/components/binary/passive_gate/AltClick(mob/user) - if(can_interact(user)) - target_pressure = MAX_OUTPUT_PRESSURE - investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "pressure output set to [target_pressure] kPa") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/binary/passive_gate/click_alt(mob/user) + if(target_pressure == MAX_OUTPUT_PRESSURE) + return CLICK_ACTION_BLOCKING + + target_pressure = MAX_OUTPUT_PRESSURE + investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "pressure output set to [target_pressure] kPa") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/binary/passive_gate/update_icon_nopipes() cut_overlays() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm index 931920732752b..c331332213517 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm @@ -30,13 +30,15 @@ update_appearance() return ..() -/obj/machinery/atmospherics/components/binary/pressure_valve/AltClick(mob/user) - if(can_interact(user)) - target_pressure = MAX_OUTPUT_PRESSURE - investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "target pressure set to [target_pressure] kPa") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/binary/pressure_valve/click_alt(mob/user) + if(target_pressure == MAX_OUTPUT_PRESSURE) + return CLICK_ACTION_BLOCKING + + target_pressure = MAX_OUTPUT_PRESSURE + investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "target pressure set to [target_pressure] kPa") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/binary/pressure_valve/update_icon_nopipes() if(on && is_operational && is_gas_flowing) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm index 3c1ba634caeed..035f3a0f99603 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm @@ -43,13 +43,15 @@ update_appearance() return ..() -/obj/machinery/atmospherics/components/binary/pump/AltClick(mob/user) - if(can_interact(user)) - target_pressure = MAX_OUTPUT_PRESSURE - investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "pressure output set to [target_pressure] kPa") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/binary/pump/click_alt(mob/user) + if(target_pressure == MAX_OUTPUT_PRESSURE) + return CLICK_ACTION_BLOCKING + + target_pressure = MAX_OUTPUT_PRESSURE + investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "pressure output set to [target_pressure] kPa") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/binary/pump/update_icon_nopipes() icon_state = (on && is_operational) ? "pump_on-[set_overlay_offset(piping_layer)]" : "pump_off-[set_overlay_offset(piping_layer)]" diff --git a/code/modules/atmospherics/machinery/components/binary_devices/temperature_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/temperature_gate.dm index bbe788bac5364..d1202dbec942b 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/temperature_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/temperature_gate.dm @@ -35,13 +35,15 @@ update_appearance() return ..() -/obj/machinery/atmospherics/components/binary/temperature_gate/AltClick(mob/user) - if(can_interact(user)) - target_temperature = max_temperature - investigate_log("was set to [target_temperature] K by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "target temperature set to [target_temperature] K") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/binary/temperature_gate/click_alt(mob/user) + if(target_temperature == max_temperature) + return CLICK_ACTION_BLOCKING + + target_temperature = max_temperature + investigate_log("was set to [target_temperature] K by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "target temperature set to [target_temperature] K") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/binary/temperature_gate/examine(mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm index 0fdb5aca6a3fe..2615b964ed802 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm @@ -30,13 +30,15 @@ update_appearance() return ..() -/obj/machinery/atmospherics/components/binary/temperature_pump/AltClick(mob/user) - if(can_interact(user) && !(heat_transfer_rate == max_heat_transfer_rate)) - heat_transfer_rate = max_heat_transfer_rate - investigate_log("was set to [heat_transfer_rate]% by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "transfer rate set to [heat_transfer_rate]%") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/binary/temperature_pump/click_alt(mob/user) + if(heat_transfer_rate == max_heat_transfer_rate) + return CLICK_ACTION_BLOCKING + + heat_transfer_rate = max_heat_transfer_rate + investigate_log("was set to [heat_transfer_rate]% by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "transfer rate set to [heat_transfer_rate]%") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/binary/temperature_pump/update_icon_nopipes() icon_state = "tpump_[on && is_operational ? "on" : "off"]-[set_overlay_offset(piping_layer)]" diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm index 139cbe71b36ca..41dc549b85833 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm @@ -41,13 +41,15 @@ update_appearance() return ..() -/obj/machinery/atmospherics/components/binary/volume_pump/AltClick(mob/user) - if(can_interact(user)) - transfer_rate = MAX_TRANSFER_RATE - investigate_log("was set to [transfer_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "volume output set to [transfer_rate] L/s") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/binary/volume_pump/click_alt(mob/user) + if(transfer_rate == MAX_TRANSFER_RATE) + return CLICK_ACTION_BLOCKING + + transfer_rate = MAX_TRANSFER_RATE + investigate_log("was set to [transfer_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "volume output set to [transfer_rate] L/s") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/binary/volume_pump/update_icon_nopipes() icon_state = on && is_operational ? "volpump_on-[set_overlay_offset(piping_layer)]" : "volpump_off-[set_overlay_offset(piping_layer)]" diff --git a/code/modules/atmospherics/machinery/components/electrolyzer/electrolyzer.dm b/code/modules/atmospherics/machinery/components/electrolyzer/electrolyzer.dm index 0ab8427c0ae51..2da9ac752b549 100644 --- a/code/modules/atmospherics/machinery/components/electrolyzer/electrolyzer.dm +++ b/code/modules/atmospherics/machinery/components/electrolyzer/electrolyzer.dm @@ -127,7 +127,7 @@ if(anchored) use_energy(power_to_use) else - cell.use(power_to_use KILO JOULES) + cell.use(power_to_use) /obj/machinery/electrolyzer/proc/call_reactions(datum/gas_mixture/env) for(var/reaction in GLOB.electrolyzer_reactions) @@ -187,14 +187,12 @@ return return ..() -/obj/machinery/electrolyzer/AltClick(mob/user) - . = ..() +/obj/machinery/electrolyzer/click_alt(mob/user) if(panel_open) balloon_alert(user, "close panel!") - return - if(!can_interact(user)) - return + return CLICK_ACTION_BLOCKING toggle_power(user) + return CLICK_ACTION_SUCCESS /obj/machinery/electrolyzer/proc/toggle_power(mob/user) if(!anchored && !cell) diff --git a/code/modules/atmospherics/machinery/components/tank.dm b/code/modules/atmospherics/machinery/components/tank.dm index cf18488f0522c..a9fcaf93ec680 100644 --- a/code/modules/atmospherics/machinery/components/tank.dm +++ b/code/modules/atmospherics/machinery/components/tank.dm @@ -104,7 +104,7 @@ // We late initialize here so all stationary tanks have time to set up their // initial gas mixes and signal registrations. -/obj/machinery/atmospherics/components/tank/LateInitialize() +/obj/machinery/atmospherics/components/tank/post_machine_initialize() . = ..() GetMergeGroup(merger_id, merger_typecache) @@ -459,11 +459,10 @@ var/welder_hint = EXAMINE_HINT("welder") . += span_notice("The plating has been firmly attached and would need a [crowbar_hint] to detach, but still needs to be sealed by a [welder_hint].") -/obj/structure/tank_frame/deconstruct(disassembled) +/obj/structure/tank_frame/atom_deconstruct(disassembled) if(disassembled) for(var/datum/material/mat as anything in custom_materials) new mat.sheet_type(drop_location(), custom_materials[mat] / SHEET_MATERIAL_AMOUNT) - return ..() /obj/structure/tank_frame/update_icon(updates) . = ..() diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index 1727d4877b5e5..c6b4bd43be473 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -32,13 +32,15 @@ update_appearance() return ..() -/obj/machinery/atmospherics/components/trinary/filter/AltClick(mob/user) - if(can_interact(user)) - transfer_rate = MAX_TRANSFER_RATE - investigate_log("was set to [transfer_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "volume output set to [transfer_rate] L/s") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/trinary/filter/click_alt(mob/user) + if(transfer_rate == MAX_TRANSFER_RATE) + return CLICK_ACTION_BLOCKING + + transfer_rate = MAX_TRANSFER_RATE + investigate_log("was set to [transfer_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "volume output set to [transfer_rate] L/s") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/trinary/filter/update_overlays() . = ..() diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm index 862fbc65c894d..f832adcb4ea2e 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm @@ -35,13 +35,15 @@ update_appearance() return ..() -/obj/machinery/atmospherics/components/trinary/mixer/AltClick(mob/user) - if(can_interact(user)) - target_pressure = MAX_OUTPUT_PRESSURE - investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "pressure output on set to [target_pressure] kPa") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/trinary/mixer/click_alt(mob/user) + if(target_pressure == MAX_OUTPUT_PRESSURE) + return CLICK_ACTION_BLOCKING + + target_pressure = MAX_OUTPUT_PRESSURE + investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "pressure output on set to [target_pressure] kPa") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/trinary/mixer/update_overlays() . = ..() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index beded509497c2..232c047a2b2ce 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -429,7 +429,7 @@ user.visible_message(span_notice("You see [user] kicking against the glass of [src]!"), \ span_notice("You struggle inside [src], kicking the release with your foot... (this will take about [DisplayTimeText(CRYO_BREAKOUT_TIME)].)"), \ span_hear("You hear a thump from [src].")) - if(do_after(user, CRYO_BREAKOUT_TIME, target = src)) + if(do_after(user, CRYO_BREAKOUT_TIME, target = src, hidden = TRUE)) if(!user || user.stat != CONSCIOUS || user.loc != src ) return user.visible_message(span_warning("[user] successfully broke out of [src]!"), \ @@ -644,14 +644,13 @@ balloon_alert(user, "turned [on ? "on" : "off"]") return ..() -/obj/machinery/cryo_cell/AltClick(mob/user) - if(can_interact(user)) - if(state_open) - close_machine() - else - open_machine() - balloon_alert(user, "door [state_open ? "opened" : "closed"]") - return ..() +/obj/machinery/cryo_cell/click_alt(mob/user) + if(state_open) + close_machine() + else + open_machine() + balloon_alert(user, "door [state_open ? "opened" : "closed"]") + return CLICK_ACTION_SUCCESS /obj/machinery/cryo_cell/get_remote_view_fullscreens(mob/user) user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm index dc1c2d6282f0a..157cbae9af0df 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm @@ -5,14 +5,12 @@ var/obj/machinery/atmospherics/components/unary/gas_connector /datum/gas_machine_connector/New(location, obj/machinery/connecting_machine = null, direction = SOUTH, gas_volume) - gas_connector = new(location) - connected_machine = connecting_machine if(!connected_machine) - QDEL_NULL(gas_connector) qdel(src) return + gas_connector = new(location) gas_connector.dir = connected_machine.dir gas_connector.airs[1].volume = gas_volume @@ -41,7 +39,8 @@ RegisterSignal(connected_machine, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(pre_move_connected_machine)) RegisterSignal(connected_machine, COMSIG_MOVABLE_MOVED, PROC_REF(moved_connected_machine)) RegisterSignal(connected_machine, COMSIG_MACHINERY_DEFAULT_ROTATE_WRENCH, PROC_REF(wrenched_connected_machine)) - RegisterSignal(connected_machine, COMSIG_QDELETING, PROC_REF(deconstruct_connected_machine)) + RegisterSignal(connected_machine, COMSIG_OBJ_DECONSTRUCT, PROC_REF(deconstruct_connected_machine)) + RegisterSignal(connected_machine, COMSIG_QDELETING, PROC_REF(destroy_connected_machine)) /** * Unregister the signals previously registered @@ -51,7 +50,8 @@ COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_PRE_MOVE, COMSIG_MACHINERY_DEFAULT_ROTATE_WRENCH, - COMSIG_QDELETING, + COMSIG_OBJ_DECONSTRUCT, + COMSIG_QDELETING )) /** @@ -82,12 +82,18 @@ */ /datum/gas_machine_connector/proc/deconstruct_connected_machine() SIGNAL_HANDLER + relocate_airs() + +/** + * Called when the machine has been destroyed + */ +/datum/gas_machine_connector/proc/destroy_connected_machine() + SIGNAL_HANDLER + disconnect_connector() SSair.stop_processing_machine(connected_machine) unregister_from_machine() - connected_machine = null - QDEL_NULL(gas_connector) qdel(src) /** diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm index 4161a30ed7d72..771301b60e438 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm @@ -62,13 +62,15 @@ update_appearance() return ..() -/obj/machinery/atmospherics/components/unary/outlet_injector/AltClick(mob/user) - if(can_interact(user)) - volume_rate = MAX_TRANSFER_RATE - investigate_log("was set to [volume_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) - balloon_alert(user, "volume output set to [volume_rate] L/s") - update_appearance() - return ..() +/obj/machinery/atmospherics/components/unary/outlet_injector/click_alt(mob/user) + if(volume_rate == MAX_TRANSFER_RATE) + return CLICK_ACTION_BLOCKING + + volume_rate = MAX_TRANSFER_RATE + investigate_log("was set to [volume_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "volume output set to [volume_rate] L/s") + update_appearance() + return CLICK_ACTION_SUCCESS /obj/machinery/atmospherics/components/unary/outlet_injector/update_icon_nopipes() cut_overlays() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm index 17f6c761f129d..4ac0e959e405d 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm @@ -12,6 +12,8 @@ pipe_state = "pvent" has_cap_visuals = TRUE vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED + interaction_flags_click = NEED_VENTCRAWL + /obj/machinery/atmospherics/components/unary/passive_vent/update_icon_nopipes() cut_overlays() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm index 0af962ac0f341..01def672bf7aa 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -144,12 +144,10 @@ . += span_notice("Heat capacity at [heat_capacity] Joules per Kelvin.") . += span_notice("Temperature range [min_temperature]K - [max_temperature]K ([(T0C-min_temperature)*-1]C - [(T0C-max_temperature)*-1]C).") -/obj/machinery/atmospherics/components/unary/thermomachine/AltClick(mob/living/user) +/obj/machinery/atmospherics/components/unary/thermomachine/click_alt(mob/living/user) if(panel_open) balloon_alert(user, "close panel!") - return - if(!can_interact(user)) - return + return CLICK_ACTION_BLOCKING if(target_temperature == T20C) target_temperature = max_temperature @@ -161,6 +159,7 @@ investigate_log("was set to [target_temperature] K by [key_name(user)]", INVESTIGATE_ATMOS) balloon_alert(user, "temperature reset to [target_temperature] K") update_appearance() + return CLICK_ACTION_SUCCESS /// Performs heat calculation for the freezer. /// We just equalize the gasmix with an object at temp = var/target_temperature and heat cap = var/heat_capacity diff --git a/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm b/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm index 4d876fd458618..c8bfd8628e9b6 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm @@ -17,6 +17,12 @@ ..() update_appearance() + +/obj/machinery/atmospherics/components/unary/click_alt(mob/living/beno) + beno.handle_ventcrawl(src) + return CLICK_ACTION_SUCCESS + + /obj/machinery/atmospherics/components/unary/proc/assign_uid_vents() uid = num2text(gl_uid++) return uid diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm index bece67572b6f5..02f0d20354496 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm @@ -18,6 +18,7 @@ vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED // vents are more complex machinery and so are less resistant to damage max_integrity = 100 + interaction_flags_click = NEED_VENTCRAWL ///Direction of pumping the gas (ATMOS_DIRECTION_RELEASING or ATMOS_DIRECTION_SIPHONING) var/pump_direction = ATMOS_DIRECTION_RELEASING @@ -352,7 +353,7 @@ update_icon_nopipes() /obj/machinery/atmospherics/components/unary/vent_pump/attack_alien(mob/user, list/modifiers) - if(!welded || !(do_after(user, 20, target = src))) + if(!welded || !(do_after(user, 2 SECONDS, target = src))) return user.visible_message(span_warning("[user] furiously claws at [src]!"), span_notice("You manage to clear away the stuff blocking the vent."), span_hear("You hear loud scraping noises.")) welded = FALSE diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm index 102728fb59149..20a0b86b41c29 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm @@ -15,6 +15,7 @@ has_cap_visuals = TRUE vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED processing_flags = NONE + interaction_flags_click = NEED_VENTCRAWL ///The mode of the scrubber (ATMOS_DIRECTION_SCRUBBING or ATMOS_DIRECTION_SIPHONING) var/scrubbing = ATMOS_DIRECTION_SCRUBBING @@ -84,21 +85,6 @@ . = ..() disconnect_from_area(area_to_unregister) -///adds a gas or list of gases to our filter_types. used so that the scrubber can check if its supposed to be processing after each change -/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/add_filters(filter_or_filters) - if(!islist(filter_or_filters)) - filter_or_filters = list(filter_or_filters) - - for(var/gas_to_filter in filter_or_filters) - var/translated_gas = istext(gas_to_filter) ? gas_id2path(gas_to_filter) : gas_to_filter - - if(ispath(translated_gas, /datum/gas)) - filter_types |= translated_gas - continue - - atmos_conditions_changed() - return TRUE - ///remove a gas or list of gases from our filter_types.used so that the scrubber can check if its supposed to be processing after each change /obj/machinery/atmospherics/components/unary/vent_scrubber/proc/remove_filters(filter_or_filters) if(!islist(filter_or_filters)) @@ -328,7 +314,7 @@ . += "It seems welded shut." /obj/machinery/atmospherics/components/unary/vent_scrubber/attack_alien(mob/user, list/modifiers) - if(!welded || !(do_after(user, 20, target = src))) + if(!welded || !(do_after(user, 2 SECONDS, target = src))) return user.visible_message(span_warning("[user] furiously claws at [src]!"), span_notice("You manage to clear away the stuff blocking the scrubber."), span_hear("You hear loud scraping noises.")) welded = FALSE diff --git a/code/modules/atmospherics/machinery/other/meter.dm b/code/modules/atmospherics/machinery/other/meter.dm index ee1d052b7ed81..97bff1ddaeacb 100644 --- a/code/modules/atmospherics/machinery/other/meter.dm +++ b/code/modules/atmospherics/machinery/other/meter.dm @@ -22,7 +22,9 @@ /obj/machinery/meter/Destroy() SSair.stop_processing_machine(src) - target = null + if(!isnull(target)) + UnregisterSignal(target, COMSIG_QDELETING) + target = null return ..() /obj/machinery/meter/Initialize(mapload, new_piping_layer) @@ -45,8 +47,14 @@ candidate = pipe if(candidate) target = candidate + RegisterSignal(target, COMSIG_QDELETING, PROC_REF(drop_meter)) setAttachLayer(candidate.piping_layer) +///Called when the parent pipe is removed +/obj/machinery/meter/proc/drop_meter() + SIGNAL_HANDLER + deconstruct(FALSE) + /obj/machinery/meter/proc/setAttachLayer(new_layer) target_layer = new_layer PIPING_LAYER_DOUBLE_SHIFT(src, target_layer) @@ -135,7 +143,8 @@ return TRUE /obj/machinery/meter/on_deconstruction(disassembled) - new /obj/item/pipe_meter(loc) + var/obj/item/pipe_meter/meter_object = new /obj/item/pipe_meter(get_turf(src)) + transfer_fingerprints_to(meter_object) /obj/machinery/meter/interact(mob/user) if(machine_stat & (NOPOWER|BROKEN)) diff --git a/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm b/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm index 6b1997cc3c718..75c85d2a665f4 100644 --- a/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm +++ b/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm @@ -1,7 +1,4 @@ -/client/proc/GeneratePipeSpritesheet() - set name = "Generate Pipe Spritesheet" - set category = "Debug" - +ADMIN_VERB(generate_pipe_spritesheet, R_DEBUG, "Generate Pipe Spritesheet", "Generates the pipe spritesheets.", ADMIN_CATEGORY_DEBUG) var/datum/pipe_icon_generator/generator = new generator.Start() fcopy(generator.generated_icons, "icons/obj/pipes_n_cables/!pipes_bitmask.dmi") diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index c0dc18c0e8edc..40258db903ff0 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -34,18 +34,18 @@ if(hide) AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) //if changing this, change the subtypes RemoveElements too, because thats how bespoke works -/obj/machinery/atmospherics/pipe/Destroy() +/obj/machinery/atmospherics/pipe/on_deconstruction(disassembled) + //we delete the parent here so it initializes air_temporary for us. See /datum/pipeline/Destroy() which calls temporarily_store_air() QDEL_NULL(parent) - releaseAirToTurf() + if(air_temporary) + var/turf/T = loc + T.assume_air(air_temporary) - var/turf/local_turf = loc - for(var/obj/machinery/meter/meter in local_turf) - if(meter.target != src) - continue - var/obj/item/pipe_meter/meter_object = new (local_turf) - meter.transfer_fingerprints_to(meter_object) - qdel(meter) + return ..() + +/obj/machinery/atmospherics/pipe/Destroy() + QDEL_NULL(parent) return ..() //----------------- @@ -66,11 +66,6 @@ replace_pipenet(parent, new /datum/pipeline) return list(parent) -/obj/machinery/atmospherics/pipe/proc/releaseAirToTurf() - if(air_temporary) - var/turf/T = loc - T.assume_air(air_temporary) - /obj/machinery/atmospherics/pipe/return_air() if(air_temporary) return air_temporary diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 75152798bba71..6d4a8ad714a41 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -483,7 +483,7 @@ var/energy_consumed = energy_factor * 250 * seconds_per_tick if(powered(AREA_USAGE_EQUIP, ignore_use_power = TRUE)) use_energy(energy_consumed, channel = AREA_USAGE_EQUIP) - else if(!internal_cell?.use(energy_consumed * 0.025 KILO JOULES)) + else if(!internal_cell?.use(energy_consumed * 0.025)) shielding_powered = FALSE SSair.start_processing_machine(src) investigate_log("shielding turned off due to power loss") diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm index 389de6e3701c0..3713958fbaa26 100644 --- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm +++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm @@ -8,6 +8,7 @@ armor_type = /datum/armor/machinery_portable_atmospherics anchored = FALSE layer = ABOVE_OBJ_LAYER + interaction_flags_click = NEED_DEXTERITY ///Stores the gas mixture of the portable component. Don't access this directly, use return_air() so you support the temporary processing it provides var/datum/gas_mixture/air_contents @@ -46,14 +47,17 @@ AddElement(/datum/element/climbable, climb_time = 3 SECONDS, climb_stun = 3 SECONDS) AddElement(/datum/element/elevation, pixel_shift = 8) +/obj/machinery/portable_atmospherics/on_deconstruction(disassembled) + if(nob_crystal_inserted) + new /obj/item/hypernoblium_crystal(src) + + return ..() + /obj/machinery/portable_atmospherics/Destroy() disconnect() air_contents = null SSair.stop_processing_machine(src) - if(nob_crystal_inserted) - new /obj/item/hypernoblium_crystal(src) - return ..() /obj/machinery/portable_atmospherics/examine(mob/user) @@ -159,14 +163,12 @@ update_appearance() return TRUE -/obj/machinery/portable_atmospherics/AltClick(mob/living/user) - . = ..() - if(!istype(user) || !user.can_perform_action(src, NEED_DEXTERITY) || !can_interact(user)) - return +/obj/machinery/portable_atmospherics/click_alt(mob/living/user) if(!holding) - return + return CLICK_ACTION_BLOCKING to_chat(user, span_notice("You remove [holding] from [src].")) replace_tank(user, TRUE) + return CLICK_ACTION_SUCCESS /obj/machinery/portable_atmospherics/examine(mob/user) . = ..() diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm index e7dfc229a39d3..7b0dbef314ec0 100644 --- a/code/modules/atmospherics/machinery/portable/pump.dm +++ b/code/modules/atmospherics/machinery/portable/pump.dm @@ -12,7 +12,7 @@ volume = 1000 -/obj/machinery/portable_atmospherics/pump/Destroy() +/obj/machinery/portable_atmospherics/pump/on_deconstruction(disassembled) var/turf/local_turf = get_turf(src) local_turf.assume_air(air_contents) return ..() diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index dc148d96e1ecf..09c6c64709b9a 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -31,9 +31,9 @@ /datum/gas/halon, ) -/obj/machinery/portable_atmospherics/scrubber/Destroy() - var/turf/T = get_turf(src) - T.assume_air(air_contents) +/obj/machinery/portable_atmospherics/scrubber/on_deconstruction(disassembled) + var/turf/local_turf = get_turf(src) + local_turf.assume_air(air_contents) return ..() /obj/machinery/portable_atmospherics/scrubber/update_icon_state() diff --git a/code/modules/awaymissions/away_props.dm b/code/modules/awaymissions/away_props.dm index 1ed0a1ec0ffdb..22d9f532efcbd 100644 --- a/code/modules/awaymissions/away_props.dm +++ b/code/modules/awaymissions/away_props.dm @@ -96,7 +96,7 @@ obj_flags |= BLOCK_Z_OUT_DOWN | BLOCK_Z_IN_UP SET_PLANE_IMPLICIT(src, ABOVE_LIGHTING_PLANE) //What matters it's one above openspace, so our animation is not dependant on what's there. Up to revision with 513 animate(src,alpha = talpha,time = 10) - addtimer(CALLBACK(src, PROC_REF(reset_plane)),10) + addtimer(CALLBACK(src, PROC_REF(reset_plane)), 1 SECONDS) if(hidden) update_openspace() var/turf/T = get_turf(src) diff --git a/code/modules/awaymissions/mission_code/murderdome.dm b/code/modules/awaymissions/mission_code/murderdome.dm index 520372e68ac07..a59a491d4926f 100644 --- a/code/modules/awaymissions/mission_code/murderdome.dm +++ b/code/modules/awaymissions/mission_code/murderdome.dm @@ -1,20 +1,27 @@ /obj/structure/window/reinforced/fulltile/indestructible name = "robust window" - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION flags_1 = PREVENT_CLICK_UNDER_1 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF -/obj/structure/window/reinforced/fulltile/indestructible/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - return FALSE +/obj/structure/window/reinforced/fulltile/indestructible/screwdriver_act(mob/living/user, obj/item/tool) + return NONE +/obj/structure/window/reinforced/fulltile/indestructible/wrench_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/window/reinforced/fulltile/indestructible/crowbar_act(mob/living/user, obj/item/tool) + return NONE /obj/structure/grille/indestructible - obj_flags = CONDUCTS_ELECTRICITY | NO_DECONSTRUCTION + obj_flags = CONDUCTS_ELECTRICITY resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF -/obj/structure/grille/indestructible/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - return FALSE +/obj/structure/grille/indestructible/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/grille/indestructible/wirecutter_act(mob/living/user, obj/item/tool) + return NONE /obj/effect/spawner/structure/window/reinforced/indestructible spawn_list = list(/obj/structure/grille/indestructible, /obj/structure/window/reinforced/fulltile/indestructible) diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm index 2b8d4e806633d..cc35b4a79efca 100644 --- a/code/modules/awaymissions/mission_code/snowdin.dm +++ b/code/modules/awaymissions/mission_code/snowdin.dm @@ -369,7 +369,7 @@ /obj/structure/barricade/wooden/snowed name = "crude plank barricade" desc = "This space is blocked off by a wooden barricade. It seems to be covered in a layer of snow." - icon_state = "woodenbarricade-snow" + icon_state = "woodenbarricade_snow" max_integrity = 125 /obj/item/clothing/under/syndicate/coldres diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm index c4bb2d1761067..0fdc5093511f2 100644 --- a/code/modules/awaymissions/zlevel.dm +++ b/code/modules/awaymissions/zlevel.dm @@ -62,10 +62,10 @@ GLOBAL_LIST_INIT(potentialConfigRandomZlevels, generate_map_list_from_directory( var/name = null if (pos) - name = lowertext(copytext(t, 1, pos)) + name = LOWER_TEXT(copytext(t, 1, pos)) else - name = lowertext(t) + name = LOWER_TEXT(t) if (!name) continue diff --git a/code/modules/bitrunning/antagonists/_parent.dm b/code/modules/bitrunning/antagonists/_parent.dm index a6fc71b4e4291..8bd061d72a1df 100644 --- a/code/modules/bitrunning/antagonists/_parent.dm +++ b/code/modules/bitrunning/antagonists/_parent.dm @@ -60,13 +60,33 @@ return TRUE + /// Sets up the agent so that they look like cyber police && don't have an account ID -/datum/antagonist/bitrunning_glitch/proc/convert_agent(mob/living/carbon/human/player, datum/outfit/agent_outfit) +/datum/antagonist/bitrunning_glitch/proc/convert_agent() + if(!ishuman(owner.current)) + return + + var/mob/living/carbon/human/player = owner.current + player.set_service_style() - player.equipOutfit(agent_outfit) + player.equipOutfit(preview_outfit) player.fully_replace_character_name(player.name, pick(GLOB.cyberauth_names)) + fix_agent_id() + + +/// Resets the agent's ID and name. Needed so this doesn't show as "unknown" +/datum/antagonist/bitrunning_glitch/proc/fix_agent_id() + if(!ishuman(owner.current)) + return + + var/mob/living/carbon/human/player = owner.current var/obj/item/card/id/outfit_id = player.wear_id - if(outfit_id) - outfit_id.registered_account = new() - outfit_id.registered_account.replaceable = FALSE + if(isnull(outfit_id)) + return + + outfit_id.registered_account = new() + outfit_id.registered_account.replaceable = FALSE + outfit_id.registered_account.account_id = null + outfit_id.registered_name = player.name + outfit_id.update_label() diff --git a/code/modules/bitrunning/antagonists/cyber_police.dm b/code/modules/bitrunning/antagonists/cyber_police.dm index e6b7cc37cfdcf..bb137607ec423 100644 --- a/code/modules/bitrunning/antagonists/cyber_police.dm +++ b/code/modules/bitrunning/antagonists/cyber_police.dm @@ -9,11 +9,10 @@ stack_trace("humans only for this position") return - var/mob/living/player = owner.current - convert_agent(player, /datum/outfit/cyber_police) + convert_agent() var/datum/martial_art/the_sleeping_carp/carp = new() - carp.teach(player) + carp.teach(owner.current) /datum/outfit/cyber_police name = ROLE_CYBER_POLICE diff --git a/code/modules/bitrunning/antagonists/cyber_tac.dm b/code/modules/bitrunning/antagonists/cyber_tac.dm index 4df44563ce67c..26ad05081e89d 100644 --- a/code/modules/bitrunning/antagonists/cyber_tac.dm +++ b/code/modules/bitrunning/antagonists/cyber_tac.dm @@ -11,7 +11,7 @@ stack_trace("humans only for this position") return - convert_agent(owner.current, /datum/outfit/cyber_police/tactical) + convert_agent() /datum/outfit/cyber_police/tactical name = ROLE_CYBER_TAC diff --git a/code/modules/bitrunning/antagonists/ghost_role.dm b/code/modules/bitrunning/antagonists/ghost_role.dm new file mode 100644 index 0000000000000..3bf88e16dfb21 --- /dev/null +++ b/code/modules/bitrunning/antagonists/ghost_role.dm @@ -0,0 +1,22 @@ +/datum/antagonist/domain_ghost_actor + name = "Virtual Domain Actor" + antagpanel_category = ANTAG_GROUP_GLITCH + job_rank = ROLE_GLITCH + show_to_ghosts = TRUE + suicide_cry = "FATAL ERROR" + ui_name = "AntagInfoGlitch" + +/datum/antagonist/domain_ghost_actor/on_gain() + . = ..() + owner.current.AddComponent(/datum/component/npc_friendly) //Just in case + forge_objectives() + +/datum/antagonist/domain_ghost_actor/forge_objectives() + var/datum/objective/bitrunner_ghost_fluff/objective = new() + objective.owner = owner + objectives += objective + +/datum/objective/bitrunner_ghost_fluff + +/datum/objective/bitrunner_ghost_fluff/New() + explanation_text = "Defend your domain from the intruders!" diff --git a/code/modules/bitrunning/antagonists/netguardian.dm b/code/modules/bitrunning/antagonists/netguardian.dm index 39d646753345e..f0ea7822985f4 100644 --- a/code/modules/bitrunning/antagonists/netguardian.dm +++ b/code/modules/bitrunning/antagonists/netguardian.dm @@ -45,12 +45,17 @@ speech_span = SPAN_ROBOT death_message = "malfunctions!" + lighting_cutoff_red = 30 + lighting_cutoff_green = 5 + lighting_cutoff_blue = 20 + habitable_atmos = null minimum_survivable_temperature = TCMB ai_controller = /datum/ai_controller/basic_controller/netguardian /mob/living/basic/netguardian/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT) AddComponent(/datum/component/ranged_attacks, \ casing_type = /obj/item/ammo_casing/c46x30mm, \ projectile_sound = 'sound/weapons/gun/smg/shot.ogg', \ @@ -62,12 +67,19 @@ ai_controller.set_blackboard_key(BB_NETGUARDIAN_ROCKET_ABILITY, rockets) AddElement(/datum/element/simple_flying) + update_appearance(UPDATE_OVERLAYS) /mob/living/basic/netguardian/death(gibbed) do_sparks(number = 3, cardinal_only = TRUE, source = src) playsound(src, 'sound/mecha/weapdestr.ogg', 100) return ..() +/mob/living/basic/netguardian/update_overlays() + . = ..() + if (stat == DEAD) + return + . += emissive_appearance(icon, "netguardian_emissive", src) + /datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/netguardian name = "2E Rocket Launcher" button_icon = 'icons/obj/weapons/guns/ammo.dmi' @@ -82,9 +94,11 @@ playsound(player, 'sound/mecha/skyfall_power_up.ogg', 120) player.say("target acquired.", "machine") - var/mutable_appearance/scan_effect = mutable_appearance('icons/mob/nonhuman-player/netguardian.dmi', "scan") - var/mutable_appearance/rocket_effect = mutable_appearance('icons/mob/nonhuman-player/netguardian.dmi', "rockets") - var/list/overlays = list(scan_effect, rocket_effect) + var/overlay_icon = 'icons/mob/nonhuman-player/netguardian.dmi' + var/list/overlays = list() + overlays += mutable_appearance(overlay_icon, "scan") + overlays += mutable_appearance(overlay_icon, "rockets") + overlays += emissive_appearance(overlay_icon, "scan", player) player.add_overlay(overlays) StartCooldown() diff --git a/code/modules/bitrunning/areas.dm b/code/modules/bitrunning/areas.dm index 8ac07bcc8f2de..31a2fef9f3ca1 100644 --- a/code/modules/bitrunning/areas.dm +++ b/code/modules/bitrunning/areas.dm @@ -26,7 +26,7 @@ /area/virtual_domain/safehouse name = "Virtual Domain Safehouse" - area_flags = UNIQUE_AREA | NOTELEPORT | ABDUCTOR_PROOF | EVENT_PROTECTED + area_flags = UNIQUE_AREA | NOTELEPORT | ABDUCTOR_PROOF | EVENT_PROTECTED | VIRTUAL_SAFE_AREA icon_state = "bit_safe" requires_power = FALSE sound_environment = SOUND_ENVIRONMENT_ROOM @@ -49,3 +49,13 @@ icon_state = "bit_space" area_flags = UNIQUE_AREA | NOTELEPORT | ABDUCTOR_PROOF | EVENT_PROTECTED | HIDDEN_AREA +///Areas that virtual entities should not be in + +/area/virtual_domain/protected_space + name = "Virtual Domain Safe Zone" + area_flags = UNIQUE_AREA | NOTELEPORT | ABDUCTOR_PROOF | EVENT_PROTECTED | VIRTUAL_SAFE_AREA + icon_state = "bit_safe" + +/area/virtual_domain/protected_space/fullbright + static_lighting = FALSE + base_lighting_alpha = 255 diff --git a/code/modules/bitrunning/components/virtual_entity.dm b/code/modules/bitrunning/components/virtual_entity.dm new file mode 100644 index 0000000000000..12e5305ba9adc --- /dev/null +++ b/code/modules/bitrunning/components/virtual_entity.dm @@ -0,0 +1,36 @@ +/// Handles all special considerations for "virtual entities" such as bitrunning ghost roles or digital anomaly antagonists. +/datum/component/virtual_entity + ///The cooldown for balloon alerts, so the player isn't spammed while trying to enter a restricted area. + COOLDOWN_DECLARE(OOB_cooldown) + +/datum/component/virtual_entity/Initialize(obj/machinery/quantum_server) + . = ..() + + if(quantum_server.obj_flags & EMAGGED) + jailbreak_mobs() //This just sends a message and self-deletes, a bit messy but it works. + return + + RegisterSignal(parent, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_parent_pre_move)) + RegisterSignal(quantum_server, COMSIG_ATOM_EMAG_ACT, PROC_REF(jailbreak_mobs)) + +///Prevents entry to a certain area if it has flags preventing virtual entities from entering. +/datum/component/virtual_entity/proc/on_parent_pre_move(atom/movable/source, atom/new_location) + SIGNAL_HANDLER + + var/area/location_area = get_area(new_location) + if(!location_area) + stack_trace("Virtual entity entered a location with no area!") + return + + if(location_area.area_flags & VIRTUAL_SAFE_AREA) + source.balloon_alert(source, "out of bounds!") + COOLDOWN_START(src, OOB_cooldown, 2 SECONDS) + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + +///Self-destructs the component, allowing free-roam by all entities with this restriction. +/datum/component/virtual_entity/proc/jailbreak_mobs() + SIGNAL_HANDLER + + to_chat(parent, span_big("You shiver for a moment, then suddenly feel a sense of clarity you haven't felt before. \ + You can go anywhere, do anything! You could leave this simulation right now if you wanted!")) + qdel(src) diff --git a/code/modules/bitrunning/objects/byteforge.dm b/code/modules/bitrunning/objects/byteforge.dm index f8212b7666b99..b971cdae75ddc 100644 --- a/code/modules/bitrunning/objects/byteforge.dm +++ b/code/modules/bitrunning/objects/byteforge.dm @@ -14,7 +14,7 @@ return INITIALIZE_HINT_LATELOAD -/obj/machinery/byteforge/LateInitialize() +/obj/machinery/byteforge/post_machine_initialize() . = ..() setup_particles() diff --git a/code/modules/bitrunning/objects/disks.dm b/code/modules/bitrunning/objects/disks.dm index d6b44a60518d4..6e166d5eb7fdb 100644 --- a/code/modules/bitrunning/objects/disks.dm +++ b/code/modules/bitrunning/objects/disks.dm @@ -48,7 +48,7 @@ names += initial(thing.name) var/choice = tgui_input_list(user, message = "Select an ability", title = "Bitrunning Program", items = names) - if(isnull(choice)) + if(isnull(choice) || !user.is_holding(src)) return for(var/datum/action/thing as anything in selectable_actions) @@ -105,7 +105,7 @@ names += initial(thing.name) var/choice = tgui_input_list(user, message = "Select an ability", title = "Bitrunning Program", items = names) - if(isnull(choice)) + if(isnull(choice) || !user.is_holding(src)) return for(var/obj/thing as anything in selectable_items) diff --git a/code/modules/bitrunning/objects/netpod.dm b/code/modules/bitrunning/objects/netpod.dm index 2d4e995b19b29..a1a681cab055f 100644 --- a/code/modules/bitrunning/objects/netpod.dm +++ b/code/modules/bitrunning/objects/netpod.dm @@ -24,12 +24,7 @@ /// Static list of outfits to select from var/list/cached_outfits = list() -/obj/machinery/netpod/Initialize(mapload) - . = ..() - - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/netpod/LateInitialize() +/obj/machinery/netpod/post_machine_initialize() . = ..() disconnect_damage = BASE_DISCONNECT_DAMAGE @@ -443,8 +438,16 @@ /// Resolves a path to an outfit. /obj/machinery/netpod/proc/resolve_outfit(text) var/path = text2path(text) - if(ispath(path, /datum/outfit)) - return path + if(!ispath(path, /datum/outfit)) + return + + for(var/wardrobe in cached_outfits) + for(var/outfit in wardrobe["outfits"]) + if(path == outfit["path"]) + return path + + message_admins("[usr]:[usr.ckey] attempted to select an unavailable outfit from a netpod") + return /// Severs the connection with the current avatar /obj/machinery/netpod/proc/sever_connection() diff --git a/code/modules/bitrunning/objects/quantum_console.dm b/code/modules/bitrunning/objects/quantum_console.dm index 9dc829c48cd46..9a0f48ae80b85 100644 --- a/code/modules/bitrunning/objects/quantum_console.dm +++ b/code/modules/bitrunning/objects/quantum_console.dm @@ -12,11 +12,8 @@ . = ..() desc = "Even in the distant year [CURRENT_STATION_YEAR], Nanostrasen is still using REST APIs. How grim." - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/computer/quantum_console/LateInitialize() +/obj/machinery/computer/quantum_console/post_machine_initialize() . = ..() - find_server() /obj/machinery/computer/quantum_console/ui_interact(mob/user, datum/tgui/ui) diff --git a/code/modules/bitrunning/orders/bepis.dm b/code/modules/bitrunning/orders/bepis.dm index 286e9817f3c52..4b7253bdaf24a 100644 --- a/code/modules/bitrunning/orders/bepis.dm +++ b/code/modules/bitrunning/orders/bepis.dm @@ -17,7 +17,3 @@ /datum/orderable_item/bepis/sprayoncan item_path = /obj/item/toy/sprayoncan cost_per_order = 750 - -/datum/orderable_item/bepis/pristine - item_path = /obj/item/disk/design_disk/bepis/remove_tech - cost_per_order = 1000 diff --git a/code/modules/bitrunning/server/_parent.dm b/code/modules/bitrunning/server/_parent.dm index b9d8808607eae..113ed6b212625 100644 --- a/code/modules/bitrunning/server/_parent.dm +++ b/code/modules/bitrunning/server/_parent.dm @@ -49,12 +49,7 @@ /// Cooldown between being able to toggle broadcasting COOLDOWN_DECLARE(broadcast_toggle_cd) -/obj/machinery/quantum_server/Initialize(mapload) - . = ..() - - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/quantum_server/LateInitialize() +/obj/machinery/quantum_server/post_machine_initialize() . = ..() radio = new(src) @@ -93,11 +88,14 @@ /obj/machinery/quantum_server/emag_act(mob/user, obj/item/card/emag/emag_card) . = ..() + if(obj_flags & EMAGGED) + return + obj_flags |= EMAGGED glitch_chance = 0.09 add_overlay(mutable_appearance('icons/obj/machines/bitrunning.dmi', "emag_overlay")) - balloon_alert(user, "bzzzt...") + balloon_alert(user, "system jailbroken...") playsound(src, 'sound/effects/sparks1.ogg', 35, vary = TRUE) /obj/machinery/quantum_server/update_appearance(updates) diff --git a/code/modules/bitrunning/server/loot.dm b/code/modules/bitrunning/server/loot.dm index cb4902abfe3ab..aa7b99d6e922a 100644 --- a/code/modules/bitrunning/server/loot.dm +++ b/code/modules/bitrunning/server/loot.dm @@ -1,3 +1,9 @@ +#define GRADE_D "D" +#define GRADE_C "C" +#define GRADE_B "B" +#define GRADE_A "A" +#define GRADE_S "S" + /// Handles calculating rewards based on number of players, parts, threats, etc /obj/machinery/quantum_server/proc/calculate_rewards() var/rewards_base = 0.8 @@ -28,8 +34,11 @@ var/bonus = calculate_rewards() + var/time_difference = world.time - generated_domain.start_time + var/grade = grade_completion(time_difference) + var/obj/item/paper/certificate = new() - certificate.add_raw_text(get_completion_certificate()) + certificate.add_raw_text(get_completion_certificate(time_difference, grade)) certificate.name = "certificate of domain completion" certificate.update_appearance() @@ -37,6 +46,10 @@ reward_cache.manifest = certificate reward_cache.update_appearance() + if(can_generate_tech_disk(grade)) + new /obj/item/disk/design_disk/bepis/remove_tech(reward_cache) + generated_domain.disk_reward_spawned = TRUE + chosen_forge.start_to_spawn(reward_cache) return TRUE @@ -50,7 +63,7 @@ return TRUE /// Returns the markdown text containing domain completion information -/obj/machinery/quantum_server/proc/get_completion_certificate() +/obj/machinery/quantum_server/proc/get_completion_certificate(time_difference, grade) var/base_points = generated_domain.reward_points if(domain_randomized) base_points -= 1 @@ -59,11 +72,9 @@ var/domain_threats = length(spawned_threat_refs) - var/time_difference = world.time - generated_domain.start_time - var/completion_time = "### Completion Time: [DisplayTimeText(time_difference)]\n" - var/grade = "\n---\n\n# Rating: [grade_completion(time_difference)]" + var/completion_grade = "\n---\n\n# Rating: [grade]" var/text = "# Certificate of Domain Completion\n\n---\n\n" @@ -75,7 +86,7 @@ if(bonuses <= 1) text += completion_time - text += grade + text += completion_grade return text text += "### Bonuses\n" @@ -94,10 +105,24 @@ text += "- **Components:** + [servo_rating]\n" text += completion_time - text += grade + text += completion_grade return text +/// Checks if the players should get a bepis reward +/obj/machinery/quantum_server/proc/can_generate_tech_disk(grade) + if(generated_domain.disk_reward_spawned) + return FALSE + + if(!LAZYLEN(SSresearch.techweb_nodes_experimental)) + return FALSE + + var/static/list/passing_grades = list() + if(!passing_grades.len) + passing_grades = list(GRADE_A,GRADE_S) + + return generated_domain.difficulty >= BITRUNNER_DIFFICULTY_MEDIUM && (grade in passing_grades) + /// Grades the player's run based on several factors /obj/machinery/quantum_server/proc/grade_completion(completion_time) var/score = length(spawned_threat_refs) * 5 @@ -124,13 +149,18 @@ switch(score) if(1 to 4) - return "D" + return GRADE_D if(5 to 7) - return "C" + return GRADE_C if(8 to 10) - return "B" + return GRADE_B if(11 to 13) - return "A" + return GRADE_A else - return "S" + return GRADE_S +#undef GRADE_D +#undef GRADE_C +#undef GRADE_B +#undef GRADE_A +#undef GRADE_S diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm index 0cc923d6b3c24..641d906cc5989 100644 --- a/code/modules/bitrunning/server/obj_generation.dm +++ b/code/modules/bitrunning/server/obj_generation.dm @@ -43,6 +43,7 @@ var/datum/outfit/to_wear = new outfit_path() to_wear.belt = /obj/item/bitrunning_host_monitor + to_wear.ears = null to_wear.glasses = null to_wear.gloves = null to_wear.l_pocket = null diff --git a/code/modules/bitrunning/server/threats.dm b/code/modules/bitrunning/server/threats.dm index 6c42322d0cf01..66a96d9971fe4 100644 --- a/code/modules/bitrunning/server/threats.dm +++ b/code/modules/bitrunning/server/threats.dm @@ -2,6 +2,7 @@ /obj/machinery/quantum_server/proc/add_threats(mob/living/threat) spawned_threat_refs.Add(WEAKREF(threat)) SEND_SIGNAL(src, COMSIG_BITRUNNER_THREAT_CREATED) + threat.AddComponent(/datum/component/virtual_entity, src) /// Choses which antagonist role is spawned based on threat /obj/machinery/quantum_server/proc/get_antagonist_role() @@ -75,7 +76,7 @@ checked_target = mutation_target, ignore_category = POLL_IGNORE_GLITCH, alert_pic = mutation_target, - role_name_text = "Bitrunning Malfunction: [role_name]", + role_name_text = "Malfunction: [role_name]", ) spawn_glitch(chosen_role, mutation_target, chosen_one) return mutation_target diff --git a/code/modules/bitrunning/server/util.dm b/code/modules/bitrunning/server/util.dm index a657122082dbb..ac3e60b51ba64 100644 --- a/code/modules/bitrunning/server/util.dm +++ b/code/modules/bitrunning/server/util.dm @@ -63,9 +63,10 @@ return initial(selected.key) + /// Removes all blacklisted items from a mob and returns them to base state /obj/machinery/quantum_server/proc/reset_equipment(mob/living/carbon/human/person) - for(var/item in person.get_contents()) + for(var/obj/item in person.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)) qdel(item) var/datum/antagonist/bitrunning_glitch/antag_datum = locate() in person.mind?.antag_datums @@ -74,6 +75,9 @@ person.equipOutfit(antag_datum.preview_outfit) + antag_datum.fix_agent_id() + + /// Severs any connected users /obj/machinery/quantum_server/proc/sever_connections() if(isnull(generated_domain) || !length(avatar_connection_refs)) diff --git a/code/modules/bitrunning/spawners.dm b/code/modules/bitrunning/spawners.dm new file mode 100644 index 0000000000000..4f8aab322ffac --- /dev/null +++ b/code/modules/bitrunning/spawners.dm @@ -0,0 +1,51 @@ +/obj/effect/mob_spawn/ghost_role/human/virtual_domain + outfit = /datum/outfit/pirate + prompt_name = "a virtual domain debug entity" + flavour_text = "You probably shouldn't be seeing this, contact a coder!" + you_are_text = "You are NOT supposed to be here. How did you let this happen?" + +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/Initialize(mapload) + . = ..() + notify_ghosts("The [name] has been created. The virtual world calls for aid!", src, "Virtual Insanity!") + +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/special(mob/living/spawned_mob, mob/mob_possessor) + . = ..() + + spawned_mob.mind.add_antag_datum(/datum/antagonist/domain_ghost_actor) + +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/pirate + name = "Virtual Pirate Remains" + desc = "Some inanimate bones. They feel like they could spring to life at any moment!" + density = FALSE + icon = 'icons/effects/blood.dmi' + icon_state = "remains" + prompt_name = "a virtual skeleton pirate" + you_are_text = "You are a virtual pirate. Yarrr!" + flavour_text = "You have awoken, without instruction. There's a LANDLUBBER after yer booty. Stop them!" + +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/pirate/special(mob/living/spawned_mob, mob/mob_possessor) + . = ..() + spawned_mob.fully_replace_character_name(spawned_mob.real_name, "[pick(strings(PIRATE_NAMES_FILE, "generic_beginnings"))][pick(strings(PIRATE_NAMES_FILE, "generic_endings"))]") + +/obj/effect/mob_spawn/ghost_role/human/virtual_domain/syndie + name = "Virtual Syndicate Sleeper" + icon = 'icons/obj/machines/sleeper.dmi' + icon_state = "sleeper_s" + prompt_name = "a virtual syndicate operative" + you_are_text = "You are a virtual syndicate operative." + flavour_text = "You have awoken, without instruction. Alarms blare! We are being boarded!" + outfit = /datum/outfit/virtual_syndicate + spawner_job_path = /datum/job/space_syndicate + +/datum/outfit/virtual_syndicate + name = "Virtual Syndie" + id = /obj/item/card/id/advanced/chameleon + id_trim = /datum/id_trim/chameleon/operative + uniform = /obj/item/clothing/under/syndicate + back = /obj/item/storage/backpack + gloves = /obj/item/clothing/gloves/tackler/combat/insulated + shoes = /obj/item/clothing/shoes/combat + implants = list(/obj/item/implant/weapons_auth) + +/datum/outfit/virtual_syndicate/post_equip(mob/living/carbon/human/user, visualsOnly) + user.faction |= ROLE_SYNDICATE diff --git a/code/modules/bitrunning/virtual_domain/virtual_domain.dm b/code/modules/bitrunning/virtual_domain/virtual_domain.dm index b316bb97cae1e..21898daad72d7 100644 --- a/code/modules/bitrunning/virtual_domain/virtual_domain.dm +++ b/code/modules/bitrunning/virtual_domain/virtual_domain.dm @@ -44,6 +44,8 @@ var/start_time /// This map is specifically for unit tests. Shouldn't display in game var/test_only = FALSE + /// Has this domain been beaten with high enough score to spawn a tech disk? + var/disk_reward_spawned = FALSE /// Sends a point to any loot signals on the map /datum/lazy_template/virtual_domain/proc/add_points(points_to_add) diff --git a/code/modules/capture_the_flag/ctf_game.dm b/code/modules/capture_the_flag/ctf_game.dm index e3b9fb37869f4..38a7318b5548e 100644 --- a/code/modules/capture_the_flag/ctf_game.dm +++ b/code/modules/capture_the_flag/ctf_game.dm @@ -221,7 +221,6 @@ return INITIALIZE_HINT_LATELOAD /obj/item/ctf_flag/LateInitialize() - . = ..() ctf_game = GLOB.ctf_games[game_id] //Flags don't create ctf games by themselves since you can get ctf flags from christmas trees. /obj/item/ctf_flag/Destroy() @@ -464,7 +463,12 @@ /obj/structure/table/reinforced/ctf resistance_flags = INDESTRUCTIBLE - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/structure/table/reinforced/ctf/wrench_act_secondary(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/table/reinforced/ctf/screwdriver_act_secondary(mob/living/user, obj/item/tool) + return NONE #define CTF_LOADING_UNLOADED 0 #define CTF_LOADING_LOADING 1 diff --git a/code/modules/capture_the_flag/medieval_sim/medisim_game.dm b/code/modules/capture_the_flag/medieval_sim/medisim_game.dm index 3546ce0881d62..18e1cd13e7ede 100644 --- a/code/modules/capture_the_flag/medieval_sim/medisim_game.dm +++ b/code/modules/capture_the_flag/medieval_sim/medisim_game.dm @@ -12,9 +12,8 @@ /obj/machinery/ctf/spawner/medisim/Initialize(mapload) . = ..() ctf_game.setup_rules(victory_rejoin_text = "Teams have been cleared. The next game is starting automatically. Rejoin a team if you wish!", auto_restart = TRUE) - return INITIALIZE_HINT_LATELOAD //Start CTF needs to run after both medisim spawners have initalized. -/obj/machinery/ctf/spawner/medisim/LateInitialize() +/obj/machinery/ctf/spawner/medisim/post_machine_initialize() . = ..() ctf_game.start_ctf() diff --git a/code/modules/cards/deck/deck.dm b/code/modules/cards/deck/deck.dm index 6a199bec4d73c..ccce356024956 100644 --- a/code/modules/cards/deck/deck.dm +++ b/code/modules/cards/deck/deck.dm @@ -11,6 +11,7 @@ hitsound = null attack_verb_continuous = list("attacks") attack_verb_simple = list("attack") + interaction_flags_click = NEED_DEXTERITY|FORBID_TELEKINESIS_REACH|ALLOW_RESTING /// The amount of time it takes to shuffle var/shuffle_time = DECK_SHUFFLE_TIME /// Deck shuffling cooldown. @@ -116,15 +117,17 @@ if(length(card_players) >= 2) // need at least 2 people to play a cardgame, duh! for(var/mob/living/carbon/player in card_players) - var/other_players = english_list(card_players - player) + var/other_players = card_players - player var/obj/item/toy/held_card_item = card_players[player] player.add_mood_event("playing_cards", /datum/mood_event/playing_cards) - player.add_mob_memory(/datum/memory/playing_cards, \ + player.add_mob_memory( \ + /datum/memory/playing_cards, \ deuteragonist = dealer, \ game = cardgame_desc, \ protagonist_held_card = held_card_item, \ - other_players = other_players) + other_players = other_players, \ + ) /obj/item/toy/cards/deck/attack_hand(mob/living/user, list/modifiers, flip_card = FALSE) if(!ishuman(user) || !user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH)) @@ -143,13 +146,13 @@ attack_hand(user, modifiers, flip_card = TRUE) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN -/obj/item/toy/cards/deck/AltClick(mob/living/user) - if(user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH)) - if(HAS_TRAIT(src, TRAIT_WIELDED)) - shuffle_cards(user) - else - to_chat(user, span_notice("You must hold the [src] with both hands to shuffle.")) - return ..() +/obj/item/toy/cards/deck/click_alt(mob/living/user) + if(!HAS_TRAIT(src, TRAIT_WIELDED)) + to_chat(user, span_notice("You must hold the [src] with both hands to shuffle.")) + return CLICK_ACTION_BLOCKING + + shuffle_cards(user) + return CLICK_ACTION_SUCCESS /obj/item/toy/cards/deck/update_icon_state() switch(count_cards()) diff --git a/code/modules/cards/singlecard.dm b/code/modules/cards/singlecard.dm index 169715c51d909..0c228fbbb1723 100644 --- a/code/modules/cards/singlecard.dm +++ b/code/modules/cards/singlecard.dm @@ -14,6 +14,7 @@ throw_range = 7 attack_verb_continuous = list("attacks") attack_verb_simple = list("attack") + interaction_flags_click = NEED_DEXTERITY|FORBID_TELEKINESIS_REACH|ALLOW_RESTING /// Artistic style of the deck var/deckstyle = "nanotrasen" /// If the cards in the deck have different icon states (blank and CAS decks do not) @@ -237,8 +238,7 @@ if(isturf(src.loc)) // only display tihs message when flipping in a visible spot like on a table user.balloon_alert_to_viewers("flips a card") -/obj/item/toy/singlecard/AltClick(mob/living/carbon/human/user) - if(user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH)) - transform = turn(transform, 90) +/obj/item/toy/singlecard/click_alt(mob/living/carbon/human/user) + transform = turn(transform, 90) // use the simple_rotation component to make this turn with Alt+RMB & Alt+LMB at some point in the future - TimT - return ..() + return CLICK_ACTION_SUCCESS diff --git a/code/modules/cargo/bounties/assistant.dm b/code/modules/cargo/bounties/assistant.dm index 7d345802eef12..d4ef4b6a148e0 100644 --- a/code/modules/cargo/bounties/assistant.dm +++ b/code/modules/cargo/bounties/assistant.dm @@ -198,11 +198,11 @@ wanted_types = list(/obj/item/pneumatic_cannon/ghetto = TRUE) /datum/bounty/item/assistant/improvised_shells - name = "Improvised Shotgun Shells" - description = "Budget cuts are hitting our security department pretty hard. Send some improvised shotgun shells when you can." + name = "Junk Shells" + description = "Our assistant militia has chewed through all our iron supplies. To stop them making bullets out of station property, we need junk shells, pronto." reward = CARGO_CRATE_VALUE * 4 required_count = 5 - wanted_types = list(/obj/item/ammo_casing/shotgun/improvised = TRUE) + wanted_types = list(/obj/item/ammo_casing/junk = TRUE) /datum/bounty/item/assistant/flamethrower name = "Flamethrower" @@ -257,7 +257,7 @@ ..() fluid_type = pick(AQUARIUM_FLUID_FRESHWATER, AQUARIUM_FLUID_SALTWATER, AQUARIUM_FLUID_SULPHWATEVER) name = "[fluid_type] Fish" - description = "We need [lowertext(fluid_type)] fish to populate our aquariums with. Fishes that are dead or bought from cargo will only be paid half as much." + description = "We need [LOWER_TEXT(fluid_type)] fish to populate our aquariums with. Fishes that are dead or bought from cargo will only be paid half as much." /datum/bounty/item/assistant/fish/fluid/can_ship_fish(obj/item/fish/fishie) return compatible_fluid_type(fishie.required_fluid_type, fluid_type) diff --git a/code/modules/cargo/bounties/mining.dm b/code/modules/cargo/bounties/mining.dm index a552e62aeb1f7..c49fc982a3ab9 100644 --- a/code/modules/cargo/bounties/mining.dm +++ b/code/modules/cargo/bounties/mining.dm @@ -43,6 +43,20 @@ required_count = 3 wanted_types = list(/obj/item/clothing/accessory/talisman = TRUE) +/datum/bounty/item/mining/watcher_wreath + name = "Watcher Wreaths" + description = "Station 14's Research Director thinks they're onto a break-through on the cultural icons of some pagan beliefs. Ship them a few watcher wreaths for analysis." + reward = CARGO_CRATE_VALUE * 15 + required_count = 3 + wanted_types = list(/obj/item/clothing/neck/wreath = FALSE) + +/datum/bounty/item/mining/icewing_wreath + name = "Icewing Wreath" + description = "We're getting some....weird messages from Station 14's Research Director. And most of what they said was incoherent. But they apparently want an icewing wreath. Could you send them one?" + reward = CARGO_CRATE_VALUE * 30 + required_count = 1 + wanted_types = list(/obj/item/clothing/neck/wreath/icewing = FALSE) + /datum/bounty/item/mining/bone_dagger name = "Bone Daggers" description = "Central Command's canteen is undergoing budget cuts. Ship over some bone daggers so our chef can keep working." diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm index 218aed8c681b4..cf4a5dfc8759f 100644 --- a/code/modules/cargo/centcom_podlauncher.dm +++ b/code/modules/cargo/centcom_podlauncher.dm @@ -16,11 +16,8 @@ //The user can change properties of the supplypod using the UI, and change the way that items are taken from the bay (One at a time, ordered, random, etc) //Many of the effects of the supplypod set here are put into action in supplypod.dm -/client/proc/centcom_podlauncher() //Creates a verb for admins to open up the ui - set name = "Config/Launch Supplypod" - set desc = "Configure and launch a CentCom supplypod full of whatever your heart desires!" - set category = "Admin.Events" - new /datum/centcom_podlauncher(usr)//create the datum +ADMIN_VERB(centcom_podlauncher, R_ADMIN, "Config/Launch Supplypod", "Configure and launch a CentCom supplypod full of whatever your heart desires!", ADMIN_CATEGORY_EVENTS) + new /datum/centcom_podlauncher(user.mob) //Variables declared to change how items in the launch bay are picked and launched. (Almost) all of these are changed in the ui_act proc //Some effect groups are choices, while other are booleans. This is because some effects can stack, while others dont (ex: you can stack explosion and quiet, but you cant stack ordered launch and random launch) diff --git a/code/modules/cargo/gondolapod.dm b/code/modules/cargo/gondolapod.dm index 36ceff8ad5114..2491084ab7039 100644 --- a/code/modules/cargo/gondolapod.dm +++ b/code/modules/cargo/gondolapod.dm @@ -67,7 +67,7 @@ opened = TRUE layer = initial(layer) update_appearance() - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, setClosed)), 50) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, setClosed)), 5 SECONDS) /mob/living/simple_animal/pet/gondola/gondolapod/setClosed() opened = FALSE diff --git a/code/modules/cargo/goodies.dm b/code/modules/cargo/goodies.dm index d733677c5528c..e09c3e2bc958d 100644 --- a/code/modules/cargo/goodies.dm +++ b/code/modules/cargo/goodies.dm @@ -12,21 +12,21 @@ contains = list(/obj/item/modular_computer/pda/clear) /datum/supply_pack/goody/dumdum38 - name = ".38 DumDum Speedloader" + name = ".38 DumDum Speedloader Single-Pack" desc = "Contains one speedloader of .38 DumDum ammunition, good for embedding in soft targets." cost = PAYCHECK_CREW * 2 access_view = ACCESS_WEAPONS contains = list(/obj/item/ammo_box/c38/dumdum) /datum/supply_pack/goody/match38 - name = ".38 Match Grade Speedloader" + name = ".38 Match Grade Speedloader Single-Pack" desc = "Contains one speedloader of match grade .38 ammunition, perfect for showing off trickshots." cost = PAYCHECK_CREW * 2 access_view = ACCESS_WEAPONS contains = list(/obj/item/ammo_box/c38/match) /datum/supply_pack/goody/rubber - name = ".38 Rubber Speedloader" + name = ".38 Rubber Speedloader Single-Pack" desc = "Contains one speedloader of bouncy rubber .38 ammunition, for when you want to bounce your shots off anything and everything." cost = PAYCHECK_CREW * 1.5 access_view = ACCESS_WEAPONS @@ -41,14 +41,14 @@ /datum/supply_pack/goody/stingbang name = "Stingbang Single-Pack" - desc = "Contains one \"stingbang\" grenade, perfect for playing meanhearted pranks." + desc = "Contains one \"Stingbang\" grenade, perfect for playing meanhearted pranks." cost = PAYCHECK_COMMAND * 2.5 access_view = ACCESS_WEAPONS contains = list(/obj/item/grenade/stingbang) /datum/supply_pack/goody/Survivalknives_single name = "Survival Knife Single-Pack" - desc = "Contains one sharpened survival knive. Guaranteed to fit snugly inside any Nanotrasen-standard boot." + desc = "Contains one sharpened survival knife. Guaranteed to fit snugly inside any Nanotrasen-standard boot." cost = PAYCHECK_COMMAND * 1.75 contains = list(/obj/item/knife/combat/survival) @@ -61,21 +61,21 @@ /datum/supply_pack/goody/disabler_single name = "Disabler Single-Pack" - desc = "Contains one disabler, the nonlethal workhorse of Nanotrasen security everywehere. Comes in a energy holster, just in case you happen to have an extra disabler." + desc = "Contains one disabler, the non-lethal workhorse of Nanotrasen security everywhere. Comes in a energy holster, just in case you happen to have an extra disabler." cost = PAYCHECK_COMMAND * 3 access_view = ACCESS_WEAPONS contains = list(/obj/item/storage/belt/holster/energy/disabler) /datum/supply_pack/goody/energy_single name = "Energy Gun Single-Pack" - desc = "Contains one energy gun, capable of firing both nonlethal and lethal blasts of light." + desc = "Contains one energy gun, capable of firing both non-lethal and lethal blasts of light." cost = PAYCHECK_COMMAND * 12 access_view = ACCESS_WEAPONS contains = list(/obj/item/gun/energy/e_gun) /datum/supply_pack/goody/laser_single name = "Laser Gun Single-Pack" - desc = "Contains one laser gun, the lethal workhorse of Nanotrasen security everywehere." + desc = "Contains one laser gun, the lethal workhorse of Nanotrasen security everywhere." cost = PAYCHECK_COMMAND * 6 access_view = ACCESS_WEAPONS contains = list(/obj/item/gun/energy/laser) @@ -161,7 +161,7 @@ contains = list(/obj/item/toy/plush/beeplushie) /datum/supply_pack/goody/blahaj - name = "Shark plushie" + name = "Shark Plushie" desc = "A soft, warm companion for midday naps." cost = PAYCHECK_CREW * 5 contains = list(/obj/item/toy/plush/shark) @@ -179,7 +179,7 @@ contains = list(/obj/item/dyespray) /datum/supply_pack/goody/beach_ball - name = "Beach Ball" + name = "Beach Ball Single-Pack" // uses desc from item cost = PAYCHECK_CREW contains = list(/obj/item/toy/beach_ball/branded) @@ -208,19 +208,19 @@ contains = list(/obj/item/food/ready_donk) /datum/supply_pack/goody/pill_mutadone - name = "Emergency Mutadone Pill" + name = "Emergency Mutadone Pill Single-Pack" desc = "A single pill for curing genetic defects. Useful for when you can't procure one from medbay." cost = PAYCHECK_CREW * 2.5 contains = list(/obj/item/reagent_containers/pill/mutadone) /datum/supply_pack/goody/rapid_lighting_device - name = "Rapid Lighting Device (RLD)" + name = "Rapid Lighting Device (RLD) Single-Pack" desc = "A device used to rapidly provide lighting sources to an area. Reload with iron, plasteel, glass or compressed matter cartridges." cost = PAYCHECK_CREW * 10 contains = list(/obj/item/construction/rld) /datum/supply_pack/goody/fishing_toolbox - name = "Fishing toolbox" + name = "Fishing Toolbox" desc = "Complete toolbox set for your fishing adventure. Advanced hooks and lines sold separetely." cost = PAYCHECK_CREW * 2 contains = list(/obj/item/storage/toolbox/fishing) @@ -238,86 +238,86 @@ contains = list(/obj/item/storage/box/fishing_lines) /datum/supply_pack/goody/fishing_hook_rescue - name = "Rescue Fishing Hook" + name = "Rescue Fishing Hook Single-Pack" desc = "For when your fellow miner has inevitably fallen into a chasm, and it's up to you to save them." cost = PAYCHECK_CREW * 12 contains = list(/obj/item/fishing_hook/rescue) /datum/supply_pack/goody/premium_bait - name = "Deluxe fishing bait" + name = "Deluxe Fishing Bait Single-Pack" desc = "When the standard variety is not good enough for you." cost = PAYCHECK_CREW contains = list(/obj/item/bait_can/worm/premium) /datum/supply_pack/goody/fish_feed - name = "Can of fish food" + name = "Can of Fish Food Single-Pack" desc = "For keeping your little friends fed and alive." cost = PAYCHECK_CREW * 1 contains = list(/obj/item/fish_feed) /datum/supply_pack/goody/naturalbait - name = "Freshness Jars full of Natural Bait" + name = "Freshness Jars full of Natural Bait Single-Pack" desc = "Homemade in the Spinward Sector." cost = PAYCHECK_CREW * 4 //rock on contains = list(/obj/item/storage/pill_bottle/naturalbait) /datum/supply_pack/goody/telescopic_fishing_rod - name = "Telescopic Fishing Rod" + name = "Telescopic Fishing Rod Single-Pack" desc = "A collapsible fishing rod that can fit within a backpack." cost = PAYCHECK_CREW * 8 contains = list(/obj/item/fishing_rod/telescopic) /datum/supply_pack/goody/fish_analyzer - name = "Fish Analyzer" + name = "Fish Analyzer Single-Pack" desc = "A single analyzer to monitor fish's status and traits with, in case you don't have the technology to print one." cost = PAYCHECK_CREW * 2.5 contains = list(/obj/item/fish_analyzer) /datum/supply_pack/goody/fish_catalog - name = "Fishing Catalog" + name = "Fishing Catalog Single-Pack" desc = "A catalog containing all the fishy info you'll ever need." cost = PAYCHECK_LOWER contains = list(/obj/item/book/manual/fish_catalog) /datum/supply_pack/goody/coffee_mug - name = "Coffee Mug" + name = "Coffee Mug Single-Pack" desc = "A bog standard coffee mug, for drinking coffee." cost = PAYCHECK_LOWER contains = list(/obj/item/reagent_containers/cup/glass/mug) /datum/supply_pack/goody/nt_mug - name = "Nanotrasen Coffee Mug" + name = "Nanotrasen Coffee Mug Single-Pack" desc = "A blue mug bearing the logo of your corporate masters. Usually given out at inductions or events, we'll send one out special for a nominal fee." cost = PAYCHECK_LOWER contains = list(/obj/item/reagent_containers/cup/glass/mug/nanotrasen) /datum/supply_pack/goody/coffee_cartridge - name = "Coffee Cartridge" + name = "Coffee Cartridge Single-Pack" desc = "A basic cartridge for a coffeemaker. Makes 4 pots." cost = PAYCHECK_LOWER contains = list(/obj/item/coffee_cartridge) /datum/supply_pack/goody/coffee_cartridge_fancy - name = "Fancy Coffee Cartridge" + name = "Fancy Coffee Cartridge Single-Pack" desc = "A fancy cartridge for a coffeemaker. Makes 4 pots." cost = PAYCHECK_CREW contains = list(/obj/item/coffee_cartridge/fancy) /datum/supply_pack/goody/coffeepot - name = "Coffeepot" + name = "Coffeepot Single-Pack" desc = "A standard-sized coffeepot, for use with a coffeemaker." cost = PAYCHECK_CREW contains = list(/obj/item/reagent_containers/cup/coffeepot) /datum/supply_pack/goody/climbing_hook - name = "Climbing hook" + name = "Climbing Hook Single-Pack" desc = "A less cheap imported climbing hook. Absolutely no use outside of planetary stations." cost = PAYCHECK_CREW * 5 contains = list(/obj/item/climbing_hook) /datum/supply_pack/goody/double_barrel - name = "Double Barrel Shotgun" - desc = "Lost your beloved bunny to a demonic invasion? Clown broke in and stole your beloved gun? No worries! Get a new gun so long as you can pay the absurd fees." + name = "Double-barreled Shotgun Single-Pack" + desc = "Lost your beloved bunny to a demonic invasion? Clown broke in and stole your beloved gun? No worries! Get a new gun as long as you can pay the absurd fees." cost = PAYCHECK_COMMAND * 18 access_view = ACCESS_WEAPONS contains = list(/obj/item/gun/ballistic/shotgun/doublebarrel) diff --git a/code/modules/cargo/markets/market_item.dm b/code/modules/cargo/markets/market_item.dm index 51651ffdc47f6..21ff3d01deb3b 100644 --- a/code/modules/cargo/markets/market_item.dm +++ b/code/modules/cargo/markets/market_item.dm @@ -16,6 +16,9 @@ /// Path to or the item itself what this entry is for, this should be set even if you override spawn_item to spawn your item. var/atom/movable/item + /// Used to exclude abstract/special paths from the unit test if the value matches the type itself. + var/abstract_path + /// Minimum price for the item if generated randomly. var/price_min = 0 /// Maximum price for the item if generated randomly. @@ -25,7 +28,7 @@ /// Maximum amount that there should be of this item in the market if generated randomly. var/stock_max = 0 /// Probability for this item to be available. Used by SSblackmarket on init. - var/availability_prob = 0 + var/availability_prob ///The identifier for the market item, generated on runtime and used to access them in the market categories. var/identifier diff --git a/code/modules/cargo/markets/market_items/clothing.dm b/code/modules/cargo/markets/market_items/clothing.dm index bf705e8b57251..82bda848eb8e9 100644 --- a/code/modules/cargo/markets/market_items/clothing.dm +++ b/code/modules/cargo/markets/market_items/clothing.dm @@ -1,5 +1,6 @@ /datum/market_item/clothing category = "Clothing" + abstract_path = /datum/market_item/clothing /datum/market_item/clothing/ninja_mask name = "Space Ninja Mask" diff --git a/code/modules/cargo/markets/market_items/consumables.dm b/code/modules/cargo/markets/market_items/consumables.dm index 5550d31c5f865..f002ff994249d 100644 --- a/code/modules/cargo/markets/market_items/consumables.dm +++ b/code/modules/cargo/markets/market_items/consumables.dm @@ -1,5 +1,6 @@ /datum/market_item/consumable category = "Consumables" + abstract_path = /datum/market_item/consumable /datum/market_item/consumable/clown_tears name = "Bottle of Clown's Tears" diff --git a/code/modules/cargo/markets/market_items/hostages.dm b/code/modules/cargo/markets/market_items/hostages.dm index 6551ee6156b46..ed5b1f10a7fcf 100644 --- a/code/modules/cargo/markets/market_items/hostages.dm +++ b/code/modules/cargo/markets/market_items/hostages.dm @@ -1,6 +1,7 @@ ///A special category for mobs captured by pirates, tots and contractors, should someone ever want to get them back in advance. /datum/market_item/hostage category = "Hostages" + abstract_path = /datum/market_item/hostage stock = 1 availability_prob = 100 shipping_override = list(SHIPPING_METHOD_LTSRBT = 0, SHIPPING_METHOD_SUPPLYPOD = 350) diff --git a/code/modules/cargo/markets/market_items/misc.dm b/code/modules/cargo/markets/market_items/misc.dm index de0fcaa9256a4..435396c15f251 100644 --- a/code/modules/cargo/markets/market_items/misc.dm +++ b/code/modules/cargo/markets/market_items/misc.dm @@ -1,5 +1,6 @@ /datum/market_item/misc category = "Miscellaneous" + abstract_path = /datum/market_item/misc /datum/market_item/misc/Clear_PDA name = "Clear PDA" @@ -53,6 +54,7 @@ /datum/market_item/misc/shove_blocker name = "MOD Bulwark Module" desc = "You have no idea how much effort it took us to extract this module from that damn safeguard MODsuit last shift." + item = /obj/item/mod/module/shove_blocker price_min = CARGO_CRATE_VALUE * 4 price_max = CARGO_CRATE_VALUE * 5.75 stock_max = 1 @@ -108,6 +110,7 @@ /datum/market_item/misc/jawed_hook name = "Jawed Fishing Hook" desc = "The thing ya use if y'are strugglin' with fishes. Just rememeber to whoop yer rod before it's too late, 'cause this thing's gonna hurt them like an Arkansas toothpick." + item = /obj/item/fishing_hook/jaws price_min = CARGO_CRATE_VALUE * 0.75 price_max = CARGO_CRATE_VALUE * 2 stock_max = 3 diff --git a/code/modules/cargo/markets/market_items/stolen_goods.dm b/code/modules/cargo/markets/market_items/stolen_goods.dm index c9c17f1d2b6c8..02a72f05d26d1 100644 --- a/code/modules/cargo/markets/market_items/stolen_goods.dm +++ b/code/modules/cargo/markets/market_items/stolen_goods.dm @@ -1,6 +1,7 @@ ///A special category for goods stolen by spies for their bounties. /datum/market_item/stolen_good category = "Fenced Goods" + abstract_path = /datum/market_item/stolen_good stock = 1 availability_prob = 100 diff --git a/code/modules/cargo/markets/market_items/tools.dm b/code/modules/cargo/markets/market_items/tools.dm index 5d036fae0ef5b..9576810b3a3c9 100644 --- a/code/modules/cargo/markets/market_items/tools.dm +++ b/code/modules/cargo/markets/market_items/tools.dm @@ -1,5 +1,6 @@ /datum/market_item/tool category = "Tools" + abstract_path = /datum/market_item/tool /datum/market_item/tool/blackmarket_telepad name = "Black Market LTSRBT" diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm index 11f242d57c874..3323e16916234 100644 --- a/code/modules/cargo/markets/market_items/weapons.dm +++ b/code/modules/cargo/markets/market_items/weapons.dm @@ -1,5 +1,6 @@ /datum/market_item/weapon category = "Weapons" + abstract_path = /datum/market_item/weapon /datum/market_item/weapon/bear_trap name = "Bear Trap" diff --git a/code/modules/cargo/packs/costumes_toys.dm b/code/modules/cargo/packs/costumes_toys.dm index e23e6112a4bfc..de84a263597da 100644 --- a/code/modules/cargo/packs/costumes_toys.dm +++ b/code/modules/cargo/packs/costumes_toys.dm @@ -268,3 +268,15 @@ crate_name = "corgi pinata kit" crate_type = /obj/structure/closet/crate/wooden discountable = SUPPLY_PACK_STD_DISCOUNTABLE + +/datum/supply_pack/costumes_toys/balloons + name = "Long Balloons Kit" + desc = "This crate contains a box of long balloons, plus a skillchip for non-clowns to join the fun! Extra layer of safety so clowns at CentCom won't get to them." + cost = CARGO_CRATE_VALUE * 4 + contains = list( + /obj/item/storage/box/balloons, + /obj/item/skillchip/job/clown, + ) + crate_name = "long balloons kit" + crate_type = /obj/structure/closet/crate/wooden + discountable = SUPPLY_PACK_STD_DISCOUNTABLE diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm index 7fa9013c686cf..425137cd9ed77 100644 --- a/code/modules/cargo/packs/science.dm +++ b/code/modules/cargo/packs/science.dm @@ -119,7 +119,7 @@ /datum/supply_pack/science/rped name = "RPED crate" - desc = "Need to rebuild the ORM but science got annihialted after a bomb test? \ + desc = "Need to rebuild the ORM but science got annihilated after a bomb test? \ Buy this for the most advanced parts NT can give you." cost = CARGO_CRATE_VALUE * 3 contains = list(/obj/item/storage/part_replacer/cargo) diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm index b8e93f2815c0d..e36f9f84cacf1 100644 --- a/code/modules/cargo/packs/security.dm +++ b/code/modules/cargo/packs/security.dm @@ -169,6 +169,7 @@ /obj/item/clothing/mask/whistle, /obj/item/conversion_kit, ) + crate_name = "traditional equipment crate" discountable = SUPPLY_PACK_RARE_DISCOUNTABLE /// Armory packs diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm index 511f9af6541e8..82b8d5b63a254 100644 --- a/code/modules/cargo/supplypod.dm +++ b/code/modules/cargo/supplypod.dm @@ -99,6 +99,23 @@ delays = list(POD_TRANSIT = 20, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30) resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF +/obj/structure/closet/supplypod/centcompod/sisyphus + delays = list(POD_TRANSIT = 0, POD_FALLING = 0, POD_OPENING = 0, POD_LEAVING = 0.2) + reverse_delays = list(POD_TRANSIT = 0, POD_FALLING = 1.5 SECONDS, POD_OPENING = 0.6 SECONDS, POD_LEAVING = 0) + custom_rev_delay = TRUE + effectStealth = TRUE + reversing = TRUE + reverse_option_list = list( + "Mobs" = TRUE, + "Objects" = FALSE, + "Anchored" = FALSE, + "Underfloor" = FALSE, + "Wallmounted" = FALSE, + "Floors" = FALSE, + "Walls" = FALSE, + "Mecha" = TRUE, + ) + /obj/structure/closet/supplypod/back_to_station name = "blood-red supply pod" desc = "An intimidating supply pod, covered in the blood-red markings" diff --git a/code/modules/cargo/supplypod_beacon.dm b/code/modules/cargo/supplypod_beacon.dm index 999e7d76eecc8..8f1166002def8 100644 --- a/code/modules/cargo/supplypod_beacon.dm +++ b/code/modules/cargo/supplypod_beacon.dm @@ -9,9 +9,14 @@ w_class = WEIGHT_CLASS_SMALL armor_type = /datum/armor/supplypod_beacon resistance_flags = FIRE_PROOF + interaction_flags_click = ALLOW_SILICON_REACH + /// The linked console var/obj/machinery/computer/cargo/express/express_console + /// If linked var/linked = FALSE + /// If this is ready to launch var/ready = FALSE + /// If it's been launched var/launched = FALSE /datum/armor/supplypod_beacon @@ -90,13 +95,12 @@ update_status(SP_READY) to_chat(user, span_notice("[src] linked to [C].")) -/obj/item/supplypod_beacon/AltClick(mob/user) - if (!user.can_perform_action(src, ALLOW_SILICON_REACH)) - return - if (express_console) - unlink_console() - else +/obj/item/supplypod_beacon/click_alt(mob/user) + if(!express_console) to_chat(user, span_alert("There is no linked console.")) + return CLICK_ACTION_BLOCKING + unlink_console() + return CLICK_ACTION_SUCCESS /obj/item/supplypod_beacon/attackby(obj/item/W, mob/user) if(!istype(W, /obj/item/pen)) //give a tag that is visible from the linked express console diff --git a/code/modules/cargo/universal_scanner.dm b/code/modules/cargo/universal_scanner.dm index 68fe533959acb..80a821a1f5e29 100644 --- a/code/modules/cargo/universal_scanner.dm +++ b/code/modules/cargo/universal_scanner.dm @@ -129,15 +129,15 @@ payments_acc = null to_chat(user, span_notice("You clear the registered account.")) -/obj/item/universal_scanner/AltClick(mob/user) - . = ..() +/obj/item/universal_scanner/click_alt(mob/user) if(!scanning_mode == SCAN_SALES_TAG) - return + return CLICK_ACTION_BLOCKING var/potential_cut = input("How much would you like to pay out to the registered card?","Percentage Profit ([round(cut_min*100)]% - [round(cut_max*100)]%)") as num|null if(!potential_cut) cut_multiplier = initial(cut_multiplier) cut_multiplier = clamp(round(potential_cut/100, cut_min), cut_min, cut_max) to_chat(user, span_notice("[round(cut_multiplier*100)]% profit will be received if a package with a barcode is sold.")) + return CLICK_ACTION_SUCCESS /obj/item/universal_scanner/examine(mob/user) . = ..() diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm index 6fa3bb36f3fb8..1209b5c35823c 100644 --- a/code/modules/client/client_colour.dm +++ b/code/modules/client/client_colour.dm @@ -228,7 +228,7 @@ /datum/client_colour/bloodlust/New(mob/owner) ..() if(owner) - addtimer(CALLBACK(src, PROC_REF(update_colour), list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0), 10, SINE_EASING|EASE_OUT), 1) + addtimer(CALLBACK(src, PROC_REF(update_colour), list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0), 10, SINE_EASING|EASE_OUT), 0.1 SECONDS) /datum/client_colour/rave priority = PRIORITY_LOW diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 45ccda8b92bd1..3272620a86555 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -194,8 +194,6 @@ var/list/spell_tabs = list() ///A lazy list of atoms we've examined in the last RECENT_EXAMINE_MAX_WINDOW (default 2) seconds, so that we will call [/atom/proc/examine_more] instead of [/atom/proc/examine] on them when examining var/list/recent_examines - ///Our object window datum. It stores info about and handles behavior for the object tab - var/datum/object_window_info/obj_window var/list/parallax_layers var/list/parallax_layers_cached @@ -266,3 +264,6 @@ /// Does this client have typing indicators enabled? var/typing_indicators = FALSE + + /// Loot panel for the client + var/datum/lootpanel/loot_panel diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 1ba96157dc89f..ab1c5ffdcb7ab 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -34,7 +34,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( return #ifndef TESTING - if (lowertext(hsrc_command) == "_debug") //disable the integrated byond vv in the client side debugging tools since it doesn't respect vv read protections + if (LOWER_TEXT(hsrc_command) == "_debug") //disable the integrated byond vv in the client side debugging tools since it doesn't respect vv read protections return #endif @@ -121,6 +121,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( no_tgui_adminhelp(input(src, "Enter your ahelp", "Ahelp") as null|message) return + if(href_list["commandbar_typing"]) + handle_commandbar_typing(href_list) + switch(href_list["_src_"]) if("holder") hsrc = holder @@ -153,6 +156,15 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Only 10 bucks for 3 months! Click Here to find out more.") return FALSE return TRUE + +/client/proc/is_localhost() + var/static/localhost_addresses = list( + "127.0.0.1", + "::1", + null, + ) + return address in localhost_addresses + /* * Call back proc that should be checked in all paths where a client can send messages * @@ -245,32 +257,13 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( tgui_say = new(src, "tgui_say") + initialize_commandbar_spy() + set_right_click_menu_mode(TRUE) GLOB.ahelp_tickets.ClientLogin(src) GLOB.interviews.client_login(src) GLOB.requests.client_login(src) - var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins. - //Admin Authorisation - var/datum/admins/admin_datum = GLOB.admin_datums[ckey] - if (!isnull(admin_datum)) - admin_datum.associate(src) - connecting_admin = TRUE - else if(GLOB.deadmins[ckey]) - add_verb(src, /client/proc/readmin) - connecting_admin = TRUE - if(CONFIG_GET(flag/autoadmin)) - if(!GLOB.admin_datums[ckey]) - var/list/autoadmin_ranks = ranks_from_rank_name(CONFIG_GET(string/autoadmin_rank)) - if (autoadmin_ranks.len == 0) - to_chat(world, "Autoadmin rank not found") - else - new /datum/admins(autoadmin_ranks, ckey) - if(CONFIG_GET(flag/enable_localhost_rank) && !connecting_admin) - var/localhost_addresses = list("127.0.0.1", "::1") - if(isnull(address) || (address in localhost_addresses)) - var/datum/admin_rank/localhost_rank = new("!localhost!", R_EVERYTHING, R_DBRANKS, R_EVERYTHING) //+EVERYTHING -DBRANKS *EVERYTHING - new /datum/admins(list(localhost_rank), ckey, 1, 1) //preferences datum - also holds some persistent data for the client (because we may as well keep these datums to a minimum) prefs = GLOB.preferences_datums[ckey] if(prefs) @@ -343,6 +336,29 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( . = ..() //calls mob.Login() + + // Admin Verbs need the client's mob to exist. Must be after ..() + var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins. + //Admin Authorisation + var/datum/admins/admin_datum = GLOB.admin_datums[ckey] + if (!isnull(admin_datum)) + admin_datum.associate(src) + connecting_admin = TRUE + else if(GLOB.deadmins[ckey]) + add_verb(src, /client/proc/readmin) + connecting_admin = TRUE + if(CONFIG_GET(flag/autoadmin)) + if(!GLOB.admin_datums[ckey]) + var/list/autoadmin_ranks = ranks_from_rank_name(CONFIG_GET(string/autoadmin_rank)) + if (autoadmin_ranks.len == 0) + to_chat(world, "Autoadmin rank not found") + else + new /datum/admins(autoadmin_ranks, ckey) + + if(CONFIG_GET(flag/enable_localhost_rank) && !connecting_admin && is_localhost()) + var/datum/admin_rank/localhost_rank = new("!localhost!", R_EVERYTHING, R_DBRANKS, R_EVERYTHING) //+EVERYTHING -DBRANKS *EVERYTHING + new /datum/admins(list(localhost_rank), ckey, 1, 1) + if (length(GLOB.stickybanadminexemptions)) GLOB.stickybanadminexemptions -= ckey if (!length(GLOB.stickybanadminexemptions)) @@ -491,7 +507,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( "[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age == 1?"":"s")] old, created on [account_join_date].[new_player_alert_role ? " <@&[new_player_alert_role]>" : ""]" ) scream_about_watchlists(src) - check_ip_intel() validate_key_in_db() // If we aren't already generating a ban cache, fire off a build request // This way hopefully any users of request_ban_cache will never need to yield @@ -521,6 +536,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( to_chat(src, span_warning("Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.")) update_ambience_pref() + check_ip_intel() //This is down here because of the browse() calls in tooltip/New() if(!tooltips) @@ -529,6 +545,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if (!interviewee) initialize_menus() + loot_panel = new(src) + view_size = new(src, getScreenSize(prefs.read_preference(/datum/preference/toggle/widescreen))) view_size.resetFormat() view_size.setZoomMode() @@ -569,8 +587,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( SSserver_maint.UpdateHubStatus() if(credits) QDEL_LIST(credits) - if(obj_window) - QDEL_NULL(obj_window) if(holder) adminGreet(1) holder.owner = null @@ -600,6 +616,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( QDEL_NULL(view_size) QDEL_NULL(void) QDEL_NULL(tooltips) + QDEL_NULL(loot_panel) seen_messages = null Master.UpdateTickRate() ..() //Even though we're going to be hard deleted there are still some things that want to know the destroy is happening @@ -816,15 +833,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( qdel(query_get_notes) create_message("note", key, system_ckey, message, null, null, 0, 0, null, 0, 0) - -/client/proc/check_ip_intel() - set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep - if (CONFIG_GET(string/ipintel_email)) - var/datum/ipintel/res = get_ip_intel(address) - if (res.intel >= CONFIG_GET(number/ipintel_rating_bad)) - message_admins(span_adminnotice("Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a Proxy/VPN.")) - ip_intel = res.intel - /client/Click(atom/object, atom/location, control, params) if(click_intercept_time) if(click_intercept_time >= world.time) @@ -1165,7 +1173,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( return 0 if(!isnum(player_age) || player_age < 0) - return 0 + return 0 if(!isnum(days_needed)) return 0 @@ -1175,13 +1183,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( /// Attempts to make the client orbit the given object, for administrative purposes. /// If they are not an observer, will try to aghost them. /client/proc/admin_follow(atom/movable/target) - var/can_ghost = TRUE - - if (!isobserver(mob)) - can_ghost = admin_ghost() - - if(!can_ghost) - return FALSE + if(!isobserver(mob)) + SSadmin_verbs.dynamic_invoke_verb(src, /datum/admin_verb/admin_ghost) + if(!isobserver(mob)) + return var/mob/dead/observer/observer = mob observer.ManualFollow(target) diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index 644d57b6d24d1..5fbf5c6953d6a 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -331,7 +331,7 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) ) var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] if (!(savefile_key in species.get_features())) return FALSE diff --git a/code/modules/client/preferences/junkie.dm b/code/modules/client/preferences/addict.dm similarity index 100% rename from code/modules/client/preferences/junkie.dm rename to code/modules/client/preferences/addict.dm diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm index cf200ad1ffd65..d0ec072ba472f 100644 --- a/code/modules/client/preferences/clothing.dm +++ b/code/modules/client/preferences/clothing.dm @@ -95,7 +95,7 @@ should_generate_icons = TRUE /datum/preference/choiced/socks/init_possible_values() - return assoc_to_keys_features(GLOB.socks_list) + return assoc_to_keys_features(SSaccessories.socks_list) /datum/preference/choiced/socks/icon_for(value) var/static/icon/lower_half @@ -105,7 +105,7 @@ lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_leg"), ICON_OVERLAY) lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_leg"), ICON_OVERLAY) - return generate_underwear_icon(GLOB.socks_list[value], lower_half) + return generate_underwear_icon(SSaccessories.socks_list[value], lower_half) /datum/preference/choiced/socks/apply_to_human(mob/living/carbon/human/target, value) target.socks = value @@ -119,7 +119,7 @@ should_generate_icons = TRUE /datum/preference/choiced/undershirt/init_possible_values() - return assoc_to_keys_features(GLOB.undershirt_list) + return assoc_to_keys_features(SSaccessories.undershirt_list) /datum/preference/choiced/undershirt/icon_for(value) var/static/icon/body @@ -135,7 +135,7 @@ var/icon/icon_with_undershirt = icon(body) if (value != "Nude") - var/datum/sprite_accessory/accessory = GLOB.undershirt_list[value] + var/datum/sprite_accessory/accessory = SSaccessories.undershirt_list[value] icon_with_undershirt.Blend(icon('icons/mob/clothing/underwear.dmi', accessory.icon_state), ICON_OVERLAY) icon_with_undershirt.Crop(9, 9, 23, 23) @@ -154,7 +154,7 @@ should_generate_icons = TRUE /datum/preference/choiced/underwear/init_possible_values() - return assoc_to_keys_features(GLOB.underwear_list) + return assoc_to_keys_features(SSaccessories.underwear_list) /datum/preference/choiced/underwear/icon_for(value) var/static/icon/lower_half @@ -165,7 +165,7 @@ lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_leg"), ICON_OVERLAY) lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_leg"), ICON_OVERLAY) - return generate_underwear_icon(GLOB.underwear_list[value], lower_half, COLOR_ALMOST_BLACK) + return generate_underwear_icon(SSaccessories.underwear_list[value], lower_half, COLOR_ALMOST_BLACK) /datum/preference/choiced/underwear/apply_to_human(mob/living/carbon/human/target, value) target.underwear = value @@ -175,7 +175,7 @@ return FALSE var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) /datum/preference/choiced/underwear/compile_constant_data() diff --git a/code/modules/client/preferences/glasses.dm b/code/modules/client/preferences/glasses.dm index 03c975abce786..a08f15955eaa4 100644 --- a/code/modules/client/preferences/glasses.dm +++ b/code/modules/client/preferences/glasses.dm @@ -11,7 +11,7 @@ if (value == "Random") return icon('icons/effects/random_spawners.dmi', "questionmark") else - return icon('icons/obj/clothing/glasses.dmi', "glasses_[lowertext(value)]") + return icon('icons/obj/clothing/glasses.dmi', "glasses_[LOWER_TEXT(value)]") /datum/preference/choiced/glasses/is_accessible(datum/preferences/preferences) if (!..(preferences)) diff --git a/code/modules/client/preferences/middleware/antags.dm b/code/modules/client/preferences/middleware/antags.dm index 13e3bfa718f75..abd9495d09a66 100644 --- a/code/modules/client/preferences/middleware/antags.dm +++ b/code/modules/client/preferences/middleware/antags.dm @@ -1,3 +1,11 @@ +// Antagonists that don't have a dynamic ruleset, but do have a preference +GLOBAL_LIST_INIT(non_ruleset_antagonists, list( + ROLE_GLITCH = /datum/antagonist/bitrunning_glitch, + ROLE_FUGITIVE = /datum/antagonist/fugitive, + ROLE_LONE_OPERATIVE = /datum/antagonist/nukeop/lone, + ROLE_SENTIENCE = /datum/antagonist/sentient_creature, + )) + /datum/preference_middleware/antags action_delegations = list( "set_antags" = PROC_REF(set_antags), @@ -69,6 +77,12 @@ if (is_banned_from(preferences.parent.ckey, list(antag_flag_override || antag_flag, ROLE_SYNDICATE))) antag_bans += serialize_antag_name(antag_flag) + for(var/antag_key in GLOB.non_ruleset_antagonists) + var/datum/antagonist/antag = GLOB.non_ruleset_antagonists[antag_key] + var/antag_flag = initial(antag.job_rank) + if(is_banned_from(preferences.parent.ckey, list(antag_flag, ROLE_SYNDICATE))) + antag_bans += serialize_antag_name(antag_flag) + return antag_bans /datum/preference_middleware/antags/proc/get_antag_days_left() @@ -91,6 +105,17 @@ if (days_needed > 0) antag_days_left[serialize_antag_name(antag_flag)] = days_needed + for(var/antag_key in GLOB.non_ruleset_antagonists) + var/datum/antagonist/antag = GLOB.non_ruleset_antagonists[antag_key] + var/antag_flag = initial(antag.job_rank) + + var/days_needed = preferences.parent?.get_remaining_days( + GLOB.special_roles[antag_flag] + ) + + if (days_needed > 0) + antag_days_left[serialize_antag_name(antag_flag)] = days_needed + return antag_days_left /datum/preference_middleware/antags/proc/get_serialized_antags() @@ -113,15 +138,7 @@ var/list/antag_icons = list() /datum/asset/spritesheet/antagonists/create_spritesheets() - // Antagonists that don't have a dynamic ruleset, but do have a preference - var/static/list/non_ruleset_antagonists = list( - ROLE_GLITCH = /datum/antagonist/bitrunning_glitch, - ROLE_FUGITIVE = /datum/antagonist/fugitive, - ROLE_LONE_OPERATIVE = /datum/antagonist/nukeop/lone, - ROLE_SENTIENCE = /datum/antagonist/sentient_creature, - ) - - var/list/antagonists = non_ruleset_antagonists.Copy() + var/list/antagonists = GLOB.non_ruleset_antagonists.Copy() for (var/datum/dynamic_ruleset/ruleset as anything in subtypesof(/datum/dynamic_ruleset)) var/datum/antagonist/antagonist_type = initial(ruleset.antag_datum) @@ -163,4 +180,4 @@ /// Serializes an antag name to be used for preferences UI /proc/serialize_antag_name(antag_name) // These are sent through CSS, so they need to be safe to use as class names. - return lowertext(sanitize_css_class_name(antag_name)) + return LOWER_TEXT(sanitize_css_class_name(antag_name)) diff --git a/code/modules/client/preferences/names.dm b/code/modules/client/preferences/names.dm index 476fc7381a28f..9afc8da18c1aa 100644 --- a/code/modules/client/preferences/names.dm +++ b/code/modules/client/preferences/names.dm @@ -45,12 +45,11 @@ target.log_mob_tag("TAG: [target.tag] RENAMED: [key_name(target)]") /datum/preference/name/real_name/create_informed_default_value(datum/preferences/preferences) - var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/gender = preferences.read_preference(/datum/preference/choiced/gender) - - var/datum/species/species = new species_type - - return species.random_name(gender, unique = TRUE) + return generate_random_name_species_based( + preferences.read_preference(/datum/preference/choiced/gender), + TRUE, + preferences.read_preference(/datum/preference/choiced/species), + ) /datum/preference/name/real_name/deserialize(input, datum/preferences/preferences) input = ..(input) @@ -73,9 +72,7 @@ savefile_key = "human_name" /datum/preference/name/backup_human/create_informed_default_value(datum/preferences/preferences) - var/gender = preferences.read_preference(/datum/preference/choiced/gender) - - return random_unique_name(gender) + return generate_random_name(preferences.read_preference(/datum/preference/choiced/gender)) /datum/preference/name/clown savefile_key = "clown_name" diff --git a/code/modules/client/preferences/species.dm b/code/modules/client/preferences/species.dm index 9e4923d2b11da..1c74d7981b655 100644 --- a/code/modules/client/preferences/species.dm +++ b/code/modules/client/preferences/species.dm @@ -34,7 +34,7 @@ for (var/species_id in get_selectable_species()) var/species_type = GLOB.species_list[species_id] - var/datum/species/species = new species_type() + var/datum/species/species = GLOB.species_prototypes[species_type] data[species_id] = list() data[species_id]["name"] = species.name @@ -47,6 +47,4 @@ data[species_id]["perks"] = species.get_species_perks() data[species_id]["diet"] = species.get_species_diet() - qdel(species) - return data diff --git a/code/modules/client/preferences/species_features/basic.dm b/code/modules/client/preferences/species_features/basic.dm index abf4ea0e44e20..3f101ad9e44a5 100644 --- a/code/modules/client/preferences/species_features/basic.dm +++ b/code/modules/client/preferences/species_features/basic.dm @@ -7,7 +7,7 @@ var/icon/final_icon = new(head_icon) if (!isnull(sprite_accessory)) ASSERT(istype(sprite_accessory)) - + var/icon/head_accessory_icon = icon(sprite_accessory.icon, sprite_accessory.icon_state) if(y_offset) head_accessory_icon.Shift(NORTH, y_offset) @@ -61,10 +61,10 @@ relevant_head_flag = HEAD_FACIAL_HAIR /datum/preference/choiced/facial_hairstyle/init_possible_values() - return assoc_to_keys_features(GLOB.facial_hairstyles_list) + return assoc_to_keys_features(SSaccessories.facial_hairstyles_list) /datum/preference/choiced/facial_hairstyle/icon_for(value) - return generate_icon_with_head_accessory(GLOB.facial_hairstyles_list[value]) + return generate_icon_with_head_accessory(SSaccessories.facial_hairstyles_list[value]) /datum/preference/choiced/facial_hairstyle/apply_to_human(mob/living/carbon/human/target, value) target.set_facial_hairstyle(value, update = FALSE) @@ -94,7 +94,7 @@ relevant_head_flag = HEAD_FACIAL_HAIR /datum/preference/choiced/facial_hair_gradient/init_possible_values() - return assoc_to_keys_features(GLOB.facial_hair_gradients_list) + return assoc_to_keys_features(SSaccessories.facial_hair_gradients_list) /datum/preference/choiced/facial_hair_gradient/apply_to_human(mob/living/carbon/human/target, value) target.set_facial_hair_gradient_style(new_style = value, update = FALSE) @@ -137,10 +137,10 @@ relevant_head_flag = HEAD_HAIR /datum/preference/choiced/hairstyle/init_possible_values() - return assoc_to_keys_features(GLOB.hairstyles_list) + return assoc_to_keys_features(SSaccessories.hairstyles_list) /datum/preference/choiced/hairstyle/icon_for(value) - var/datum/sprite_accessory/hair/hairstyle = GLOB.hairstyles_list[value] + var/datum/sprite_accessory/hair/hairstyle = SSaccessories.hairstyles_list[value] return generate_icon_with_head_accessory(hairstyle, hairstyle?.y_offset) /datum/preference/choiced/hairstyle/apply_to_human(mob/living/carbon/human/target, value) @@ -161,7 +161,7 @@ relevant_head_flag = HEAD_HAIR /datum/preference/choiced/hair_gradient/init_possible_values() - return assoc_to_keys_features(GLOB.hair_gradients_list) + return assoc_to_keys_features(SSaccessories.hair_gradients_list) /datum/preference/choiced/hair_gradient/apply_to_human(mob/living/carbon/human/target, value) target.set_hair_gradient_style(new_style = value, update = FALSE) diff --git a/code/modules/client/preferences/species_features/felinid.dm b/code/modules/client/preferences/species_features/felinid.dm index b9f3c7bfa337b..a6d43736cf46c 100644 --- a/code/modules/client/preferences/species_features/felinid.dm +++ b/code/modules/client/preferences/species_features/felinid.dm @@ -6,7 +6,7 @@ relevant_external_organ = /obj/item/organ/external/tail/cat /datum/preference/choiced/tail_human/init_possible_values() - return assoc_to_keys_features(GLOB.tails_list_human) + return assoc_to_keys_features(SSaccessories.tails_list_human) /datum/preference/choiced/tail_human/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["tail_cat"] = value @@ -23,7 +23,7 @@ relevant_mutant_bodypart = "ears" /datum/preference/choiced/ears/init_possible_values() - return assoc_to_keys_features(GLOB.ears_list) + return assoc_to_keys_features(SSaccessories.ears_list) /datum/preference/choiced/ears/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["ears"] = value diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm index 4ce09715483ad..bee57300ec4a4 100644 --- a/code/modules/client/preferences/species_features/lizard.dm +++ b/code/modules/client/preferences/species_features/lizard.dm @@ -32,10 +32,10 @@ relevant_mutant_bodypart = "body_markings" /datum/preference/choiced/lizard_body_markings/init_possible_values() - return assoc_to_keys_features(GLOB.body_markings_list) + return assoc_to_keys_features(SSaccessories.body_markings_list) /datum/preference/choiced/lizard_body_markings/icon_for(value) - var/datum/sprite_accessory/sprite_accessory = GLOB.body_markings_list[value] + var/datum/sprite_accessory/sprite_accessory = SSaccessories.body_markings_list[value] var/icon/final_icon = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_chest_m") @@ -65,10 +65,10 @@ should_generate_icons = TRUE /datum/preference/choiced/lizard_frills/init_possible_values() - return assoc_to_keys_features(GLOB.frills_list) + return assoc_to_keys_features(SSaccessories.frills_list) /datum/preference/choiced/lizard_frills/icon_for(value) - return generate_lizard_side_shot(GLOB.frills_list[value], "frills") + return generate_lizard_side_shot(SSaccessories.frills_list[value], "frills") /datum/preference/choiced/lizard_frills/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["frills"] = value @@ -81,10 +81,10 @@ should_generate_icons = TRUE /datum/preference/choiced/lizard_horns/init_possible_values() - return assoc_to_keys_features(GLOB.horns_list) + return assoc_to_keys_features(SSaccessories.horns_list) /datum/preference/choiced/lizard_horns/icon_for(value) - return generate_lizard_side_shot(GLOB.horns_list[value], "horns") + return generate_lizard_side_shot(SSaccessories.horns_list[value], "horns") /datum/preference/choiced/lizard_horns/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["horns"] = value @@ -96,7 +96,7 @@ relevant_mutant_bodypart = "legs" /datum/preference/choiced/lizard_legs/init_possible_values() - return assoc_to_keys_features(GLOB.legs_list) + return assoc_to_keys_features(SSaccessories.legs_list) /datum/preference/choiced/lizard_legs/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["legs"] = value @@ -109,10 +109,10 @@ should_generate_icons = TRUE /datum/preference/choiced/lizard_snout/init_possible_values() - return assoc_to_keys_features(GLOB.snouts_list) + return assoc_to_keys_features(SSaccessories.snouts_list) /datum/preference/choiced/lizard_snout/icon_for(value) - return generate_lizard_side_shot(GLOB.snouts_list[value], "snout", include_snout = FALSE) + return generate_lizard_side_shot(SSaccessories.snouts_list[value], "snout", include_snout = FALSE) /datum/preference/choiced/lizard_snout/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["snout"] = value @@ -124,7 +124,7 @@ relevant_mutant_bodypart = "spines" /datum/preference/choiced/lizard_spines/init_possible_values() - return assoc_to_keys_features(GLOB.spines_list) + return assoc_to_keys_features(SSaccessories.spines_list) /datum/preference/choiced/lizard_spines/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["spines"] = value @@ -136,7 +136,7 @@ relevant_external_organ = /obj/item/organ/external/tail/lizard /datum/preference/choiced/lizard_tail/init_possible_values() - return assoc_to_keys_features(GLOB.tails_list_lizard) + return assoc_to_keys_features(SSaccessories.tails_list_lizard) /datum/preference/choiced/lizard_tail/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["tail_lizard"] = value diff --git a/code/modules/client/preferences/species_features/monkey.dm b/code/modules/client/preferences/species_features/monkey.dm new file mode 100644 index 0000000000000..adf9e367723de --- /dev/null +++ b/code/modules/client/preferences/species_features/monkey.dm @@ -0,0 +1,15 @@ +/datum/preference/choiced/monkey_tail + savefile_key = "feature_monkey_tail" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + relevant_external_organ = /obj/item/organ/external/tail/monkey + +/datum/preference/choiced/monkey_tail/init_possible_values() + return assoc_to_keys_features(SSaccessories.tails_list_monkey) + +/datum/preference/choiced/monkey_tail/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["tail_monkey"] = value + +/datum/preference/choiced/monkey_tail/create_default_value() + var/datum/sprite_accessory/tails/monkey/default/tail = /datum/sprite_accessory/tails/monkey/default + return initial(tail.name) diff --git a/code/modules/client/preferences/species_features/moth.dm b/code/modules/client/preferences/species_features/moth.dm index 120a7ea822bec..745e6fb917b8f 100644 --- a/code/modules/client/preferences/species_features/moth.dm +++ b/code/modules/client/preferences/species_features/moth.dm @@ -6,7 +6,7 @@ should_generate_icons = TRUE /datum/preference/choiced/moth_antennae/init_possible_values() - return assoc_to_keys_features(GLOB.moth_antennae_list) + return assoc_to_keys_features(SSaccessories.moth_antennae_list) /datum/preference/choiced/moth_antennae/icon_for(value) var/static/icon/moth_head @@ -16,7 +16,7 @@ moth_head.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_l"), ICON_OVERLAY) moth_head.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_r"), ICON_OVERLAY) - var/datum/sprite_accessory/antennae = GLOB.moth_antennae_list[value] + var/datum/sprite_accessory/antennae = SSaccessories.moth_antennae_list[value] var/icon/icon_with_antennae = new(moth_head) icon_with_antennae.Blend(icon(antennae.icon, "m_moth_antennae_[antennae.icon_state]_FRONT"), ICON_OVERLAY) @@ -37,7 +37,7 @@ relevant_mutant_bodypart = "moth_markings" /datum/preference/choiced/moth_markings/init_possible_values() - return assoc_to_keys_features(GLOB.moth_markings_list) + return assoc_to_keys_features(SSaccessories.moth_markings_list) /datum/preference/choiced/moth_markings/icon_for(value) var/static/list/body_parts = list( @@ -59,7 +59,7 @@ moth_body.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_l"), ICON_OVERLAY) moth_body.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_r"), ICON_OVERLAY) - var/datum/sprite_accessory/markings = GLOB.moth_markings_list[value] + var/datum/sprite_accessory/markings = SSaccessories.moth_markings_list[value] var/icon/icon_with_markings = new(moth_body) if (value != "None") @@ -88,10 +88,10 @@ should_generate_icons = TRUE /datum/preference/choiced/moth_wings/init_possible_values() - return assoc_to_keys_features(GLOB.moth_wings_list) + return assoc_to_keys_features(SSaccessories.moth_wings_list) /datum/preference/choiced/moth_wings/icon_for(value) - var/datum/sprite_accessory/moth_wings = GLOB.moth_wings_list[value] + var/datum/sprite_accessory/moth_wings = SSaccessories.moth_wings_list[value] var/icon/final_icon = icon(moth_wings.icon, "m_moth_wings_[moth_wings.icon_state]_BEHIND") final_icon.Blend(icon(moth_wings.icon, "m_moth_wings_[moth_wings.icon_state]_FRONT"), ICON_OVERLAY) return final_icon diff --git a/code/modules/client/preferences/species_features/mushperson.dm b/code/modules/client/preferences/species_features/mushperson.dm index f5e6a08ac92d2..45bd9c4b72620 100644 --- a/code/modules/client/preferences/species_features/mushperson.dm +++ b/code/modules/client/preferences/species_features/mushperson.dm @@ -5,7 +5,7 @@ relevant_mutant_bodypart = "cap" /datum/preference/choiced/mushroom_cap/init_possible_values() - return assoc_to_keys_features(GLOB.caps_list) + return assoc_to_keys_features(SSaccessories.caps_list) /datum/preference/choiced/mushroom_cap/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["caps"] = value diff --git a/code/modules/client/preferences/species_features/mutants.dm b/code/modules/client/preferences/species_features/mutants.dm index 7ecf25d9abce5..1d18c78ee1ad1 100644 --- a/code/modules/client/preferences/species_features/mutants.dm +++ b/code/modules/client/preferences/species_features/mutants.dm @@ -9,7 +9,7 @@ return FALSE var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] return !(TRAIT_FIXED_MUTANT_COLORS in species.inherent_traits) /datum/preference/color/mutant_color/create_default_value() diff --git a/code/modules/client/preferences/species_features/pod.dm b/code/modules/client/preferences/species_features/pod.dm index 5280308fa8930..de3d5221f7a41 100644 --- a/code/modules/client/preferences/species_features/pod.dm +++ b/code/modules/client/preferences/species_features/pod.dm @@ -6,10 +6,10 @@ should_generate_icons = TRUE /datum/preference/choiced/pod_hair/init_possible_values() - return assoc_to_keys_features(GLOB.pod_hair_list) + return assoc_to_keys_features(SSaccessories.pod_hair_list) /datum/preference/choiced/pod_hair/icon_for(value) - var/datum/sprite_accessory/pod_hair = GLOB.pod_hair_list[value] + var/datum/sprite_accessory/pod_hair = SSaccessories.pod_hair_list[value] var/icon/icon_with_hair = icon('icons/mob/human/bodyparts_greyscale.dmi', "pod_head_m") @@ -24,7 +24,7 @@ return icon_with_hair /datum/preference/choiced/pod_hair/create_default_value() - return pick(assoc_to_keys_features(GLOB.pod_hair_list)) + return pick(assoc_to_keys_features(SSaccessories.pod_hair_list)) /datum/preference/choiced/pod_hair/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["pod_hair"] = value diff --git a/code/modules/client/preferences/trans_prosthetic.dm b/code/modules/client/preferences/trans_prosthetic.dm new file mode 100644 index 0000000000000..fd28cb1ecf8c8 --- /dev/null +++ b/code/modules/client/preferences/trans_prosthetic.dm @@ -0,0 +1,17 @@ +/datum/preference/choiced/trans_prosthetic + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "trans_prosthetic" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/choiced/trans_prosthetic/init_possible_values() + return list("Random") + GLOB.part_choice_transhuman + +/datum/preference/choiced/trans_prosthetic/is_accessible(datum/preferences/preferences) + . = ..() + if (!.) + return FALSE + + return "Transhumanist" in preferences.all_quirks + +/datum/preference/choiced/trans_prosthetic/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/code/modules/client/preferences/underwear_color.dm b/code/modules/client/preferences/underwear_color.dm index 6e64b4423e50a..1304bdaf2da8d 100644 --- a/code/modules/client/preferences/underwear_color.dm +++ b/code/modules/client/preferences/underwear_color.dm @@ -8,7 +8,7 @@ return FALSE var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) /datum/preference/color/underwear_color/apply_to_human(mob/living/carbon/human/target, value) diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index 1009cc8a6afd7..49583ce70152a 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -139,33 +139,28 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8") set category = "Server" if(IsAdminAdvancedProcCall()) return - var/newColor = input(src, "Please select the new player OOC color.", "OOC color") as color|null + +ADMIN_VERB(set_ooc_color, R_FUN, "Set Player OOC Color", "Modifies the global OOC color.", ADMIN_CATEGORY_SERVER) + var/newColor = input(user, "Please select the new player OOC color.", "OOC color") as color|null if(isnull(newColor)) return - if(!check_rights(R_FUN)) - message_admins("[usr.key] has attempted to use the Set Player OOC Color verb!") - log_admin("[key_name(usr)] tried to set player ooc color without authorization.") - return var/new_color = sanitize_color(newColor) - message_admins("[key_name_admin(usr)] has set the players' ooc color to [new_color].") - log_admin("[key_name_admin(usr)] has set the player ooc color to [new_color].") + message_admins("[key_name_admin(user)] has set the players' ooc color to [new_color].") + log_admin("[key_name_admin(user)] has set the player ooc color to [new_color].") GLOB.OOC_COLOR = new_color - /client/proc/reset_ooc() set name = "Reset Player OOC Color" set desc = "Returns player OOC Color to default" set category = "Server" if(IsAdminAdvancedProcCall()) return - if(tgui_alert(usr, "Are you sure you want to reset the OOC color of all players?", "Reset Player OOC Color", list("Yes", "No")) != "Yes") - return - if(!check_rights(R_FUN)) - message_admins("[usr.key] has attempted to use the Reset Player OOC Color verb!") - log_admin("[key_name(usr)] tried to reset player ooc color without authorization.") + +ADMIN_VERB(reset_ooc_color, R_FUN, "Reset Player OOC Color", "Returns player OOC color to default.", ADMIN_CATEGORY_SERVER) + if(tgui_alert(user, "Are you sure you want to reset the OOC color of all players?", "Reset Player OOC Color", list("Yes", "No")) != "Yes") return - message_admins("[key_name_admin(usr)] has reset the players' ooc color.") - log_admin("[key_name_admin(usr)] has reset player ooc color.") + message_admins("[key_name_admin(user)] has reset the players' ooc color.") + log_admin("[key_name_admin(user)] has reset player ooc color.") GLOB.OOC_COLOR = null //Checks admin notice diff --git a/code/modules/client/verbs/typing.dm b/code/modules/client/verbs/typing.dm new file mode 100644 index 0000000000000..b7a7362261486 --- /dev/null +++ b/code/modules/client/verbs/typing.dm @@ -0,0 +1,70 @@ +#define IC_VERBS list("say", "me", "whisper") + +/client/var/commandbar_thinking = FALSE +/client/var/commandbar_typing = FALSE + +/client/proc/initialize_commandbar_spy() + src << output('html/typing_indicator.html', "commandbar_spy") + +/client/proc/handle_commandbar_typing(href_list) + if (!typing_indicators) //check pref + return + if (length(href_list["verb"]) < 1 || !(LOWER_TEXT(href_list["verb"]) in IC_VERBS) || text2num(href_list["argument_length"]) < 1) + if (commandbar_typing) + commandbar_typing = FALSE + stop_typing() + + if (commandbar_thinking) + commandbar_thinking = FALSE + stop_thinking() + return + + if (!commandbar_thinking) + commandbar_thinking = TRUE + start_thinking() + + if (!commandbar_typing) + commandbar_typing = TRUE + start_typing() + + +/** Sets the mob as "thinking" - with indicator and the TRAIT_THINKING_IN_CHARACTER trait */ +/client/proc/start_thinking() + if(!typing_indicators) + return FALSE + /// Special exemptions + if(isabductor(mob)) + return FALSE + ADD_TRAIT(mob, TRAIT_THINKING_IN_CHARACTER, CURRENTLY_TYPING_TRAIT) + mob.create_thinking_indicator() + +/** Removes typing/thinking indicators and flags the mob as not thinking */ +/client/proc/stop_thinking() + mob?.remove_all_indicators() + +/** + * Handles the user typing. After a brief period of inactivity, + * signals the client mob to revert to the "thinking" icon. + */ +/client/proc/start_typing() + var/mob/client_mob = mob + client_mob.remove_thinking_indicator() + if(!typing_indicators || !HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER)) + return FALSE + client_mob.create_typing_indicator() + addtimer(CALLBACK(src, PROC_REF(stop_typing)), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE) + +/** + * Callback to remove the typing indicator after a brief period of inactivity. + * If the user was typing IC, the thinking indicator is shown. + */ +/client/proc/stop_typing() + if(isnull(mob)) + return FALSE + var/mob/client_mob = mob + client_mob.remove_typing_indicator() + if(!typing_indicators || !HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER)) + return FALSE + client_mob.create_thinking_indicator() + +#undef IC_VERBS diff --git a/code/modules/clothing/chameleon/chameleon_scanner.dm b/code/modules/clothing/chameleon/chameleon_scanner.dm index 343ceb5c001cb..5023997cefebf 100644 --- a/code/modules/clothing/chameleon/chameleon_scanner.dm +++ b/code/modules/clothing/chameleon/chameleon_scanner.dm @@ -89,7 +89,7 @@ balloon_alert(scanner, "too far away!") return // Very short scan timer, keep you on your toes - if(!do_after(scanner, 0.5 SECONDS, scanned)) + if(!do_after(scanner, 0.5 SECONDS, scanned, hidden = TRUE)) return var/list/all_scanned_items = list() diff --git a/code/modules/clothing/chameleon/generic_chameleon_clothing.dm b/code/modules/clothing/chameleon/generic_chameleon_clothing.dm index f73b5b13da7b2..63bede9ec88c8 100644 --- a/code/modules/clothing/chameleon/generic_chameleon_clothing.dm +++ b/code/modules/clothing/chameleon/generic_chameleon_clothing.dm @@ -3,6 +3,7 @@ do { \ var/datum/action/item_action/chameleon/change/_action = locate() in item.actions; \ _action?.emp_randomise(INFINITY); \ + item.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF); \ } while(FALSE) // Cham jumpsuit diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 7722cf791a6db..d13f025e0b138 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -8,11 +8,11 @@ ///What level of bright light protection item has. var/flash_protect = FLASH_PROTECTION_NONE var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect - var/up = 0 //but separated to allow items to protect but not impair vision, like space helmets - var/visor_flags = 0 //flags that are added/removed when an item is adjusted up/down - var/visor_flags_inv = 0 //same as visor_flags, but for flags_inv - var/visor_flags_cover = 0 //same as above, but for flags_cover - ///What to toggle when toggled with weldingvisortoggle() + var/up = FALSE //but separated to allow items to protect but not impair vision, like space helmets + var/visor_flags = NONE //flags that are added/removed when an item is adjusted up/down + var/visor_flags_inv = NONE //same as visor_flags, but for flags_inv + var/visor_flags_cover = NONE //same as above, but for flags_cover + ///What to toggle when toggled with adjust_visor() var/visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT | VISOR_VISIONFLAGS | VISOR_INVISVIEW var/clothing_flags = NONE @@ -195,13 +195,16 @@ if(!(def_zone in covered_limbs)) return - var/zone_name = parse_zone(def_zone) + var/zone_name var/break_verb = ((damage_type == BRUTE) ? "torn" : "burned") if(iscarbon(loc)) - var/mob/living/carbon/C = loc - C.visible_message(span_danger("The [zone_name] on [C]'s [src.name] is [break_verb] away!"), span_userdanger("The [zone_name] on your [src.name] is [break_verb] away!"), vision_distance = COMBAT_MESSAGE_RANGE) - RegisterSignal(C, COMSIG_MOVABLE_MOVED, PROC_REF(bristle), override = TRUE) + var/mob/living/carbon/carbon_loc = loc + zone_name = carbon_loc.parse_zone_with_bodypart(def_zone) + carbon_loc.visible_message(span_danger("The [zone_name] on [carbon_loc]'s [src.name] is [break_verb] away!"), span_userdanger("The [zone_name] on your [src.name] is [break_verb] away!"), vision_distance = COMBAT_MESSAGE_RANGE) + RegisterSignal(carbon_loc, COMSIG_MOVABLE_MOVED, PROC_REF(bristle), override = TRUE) + else + zone_name = parse_zone(def_zone) zones_disabled++ body_parts_covered &= ~body_zone2cover_flags(def_zone) @@ -233,7 +236,9 @@ UnregisterSignal(user, COMSIG_MOVABLE_MOVED) for(var/trait in clothing_traits) REMOVE_CLOTHING_TRAIT(user, trait) - + if(iscarbon(user) && tint) + var/mob/living/carbon/carbon_user = user + carbon_user.update_tint() if(LAZYLEN(user_vars_remembered)) for(var/variable in user_vars_remembered) if(variable in user.vars) @@ -250,6 +255,9 @@ RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(bristle), override = TRUE) for(var/trait in clothing_traits) ADD_CLOTHING_TRAIT(user, trait) + if(iscarbon(user) && tint) + var/mob/living/carbon/carbon_user = user + carbon_user.update_tint() if (LAZYLEN(user_vars_to_edit)) for(var/variable in user_vars_to_edit) if(variable in user.vars) @@ -465,50 +473,48 @@ BLIND // can't see anything female_clothing_icon = fcopy_rsc(female_clothing_icon) GLOB.female_clothing_icons[index] = female_clothing_icon -/obj/item/clothing/proc/weldingvisortoggle(mob/user) //proc to toggle welding visors on helmets, masks, goggles, etc. +/// Proc that adjusts the clothing item, used by things like breathing masks, welding helmets, welding goggles etc. +/obj/item/clothing/proc/adjust_visor(mob/living/user) if(!can_use(user)) return FALSE visor_toggling() - to_chat(user, span_notice("You adjust \the [src] [up ? "up" : "down"].")) + to_chat(user, span_notice("You adjust [src] [up ? "up" : "down"].")) - if(iscarbon(user)) - var/mob/living/carbon/C = user - C.head_update(src, forced = 1) update_item_action_buttons() - return TRUE -/obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags - up = !up - SEND_SIGNAL(src, COMSIG_CLOTHING_VISOR_TOGGLE, up) - clothing_flags ^= visor_flags - flags_inv ^= visor_flags_inv - flags_cover ^= initial(flags_cover) - icon_state = "[initial(icon_state)][up ? "up" : ""]" - if(visor_vars_to_toggle & VISOR_FLASHPROTECT) - flash_protect ^= initial(flash_protect) + if(user.is_holding(src)) + user.update_held_items() + return TRUE + if(up) + user.update_obscured_slots(visor_flags_inv) + user.update_clothing(slot_flags) + if(!iscarbon(user)) + return TRUE + var/mob/living/carbon/carbon_user = user if(visor_vars_to_toggle & VISOR_TINT) - tint ^= initial(tint) + carbon_user.update_tint() + if((visor_flags & (MASKINTERNALS|HEADINTERNALS)) && carbon_user.invalid_internals()) + carbon_user.cutoff_internals() + return TRUE -/obj/item/clothing/head/helmet/space/plasmaman/visor_toggling() //handles all the actual toggling of flags +/obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags up = !up SEND_SIGNAL(src, COMSIG_CLOTHING_VISOR_TOGGLE, up) clothing_flags ^= visor_flags flags_inv ^= visor_flags_inv - icon_state = "[initial(icon_state)]" + flags_cover ^= visor_flags_cover if(visor_vars_to_toggle & VISOR_FLASHPROTECT) flash_protect ^= initial(flash_protect) if(visor_vars_to_toggle & VISOR_TINT) tint ^= initial(tint) + update_appearance() //most of the time the sprite changes /obj/item/clothing/proc/can_use(mob/user) - if(user && ismob(user)) - if(!user.incapacitated()) - return 1 - return 0 + return istype(user) && !user.incapacitated() -/obj/item/clothing/proc/_spawn_shreds() +/obj/item/clothing/proc/spawn_shreds() new /obj/effect/decal/cleanable/shreds(get_turf(src), name) /obj/item/clothing/atom_destruction(damage_flag) @@ -516,7 +522,7 @@ BLIND // can't see anything return ..() if(damage_flag == BOMB) //so the shred survives potential turf change from the explosion. - addtimer(CALLBACK(src, PROC_REF(_spawn_shreds)), 1) + addtimer(CALLBACK(src, PROC_REF(spawn_shreds)), 0.1 SECONDS) deconstruct(FALSE) if(damage_flag == CONSUME) //This allows for moths to fully consume clothing, rather than damaging it like other sources like brute var/turf/current_position = get_turf(src) diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 9fe43df5856bd..358bff5ce80d5 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -37,20 +37,17 @@ . += span_notice("Alt-click to toggle [p_their()] colors.") /obj/item/clothing/glasses/visor_toggling() - ..() + . = ..() + alternate_worn_layer = up ? ABOVE_BODY_FRONT_HEAD_LAYER : null if(visor_vars_to_toggle & VISOR_VISIONFLAGS) vision_flags ^= initial(vision_flags) if(visor_vars_to_toggle & VISOR_INVISVIEW) invis_view ^= initial(invis_view) -/obj/item/clothing/glasses/weldingvisortoggle(mob/user) +/obj/item/clothing/glasses/adjust_visor(mob/living/user) . = ..() - alternate_worn_layer = up ? ABOVE_BODY_FRONT_HEAD_LAYER : null - if(. && user) + if(. && !user.is_holding(src) && (visor_vars_to_toggle & (VISOR_VISIONFLAGS|VISOR_INVISVIEW))) user.update_sight() - if(iscarbon(user)) - var/mob/living/carbon/carbon_user = user - carbon_user.head_update(src, forced = TRUE) //called when thermal glasses are emped. /obj/item/clothing/glasses/proc/thermal_overload() @@ -65,22 +62,19 @@ H.set_eye_blur_if_lower(10 SECONDS) eyes.apply_organ_damage(5) -/obj/item/clothing/glasses/AltClick(mob/user) - if(glass_colour_type && !forced_glass_color && ishuman(user)) - var/mob/living/carbon/human/human_user = user - - if (human_user.glasses != src) - return ..() - - if (HAS_TRAIT_FROM(human_user, TRAIT_SEE_GLASS_COLORS, GLASSES_TRAIT)) - REMOVE_TRAIT(human_user, TRAIT_SEE_GLASS_COLORS, GLASSES_TRAIT) - to_chat(human_user, span_notice("You will no longer see glasses colors.")) - else - ADD_TRAIT(human_user, TRAIT_SEE_GLASS_COLORS, GLASSES_TRAIT) - to_chat(human_user, span_notice("You will now see glasses colors.")) - human_user.update_glasses_color(src, TRUE) +/obj/item/clothing/glasses/click_alt(mob/user) + if(isnull(glass_colour_type) || forced_glass_color || !ishuman(user)) + return NONE + var/mob/living/carbon/human/human_user = user + + if (HAS_TRAIT_FROM(human_user, TRAIT_SEE_GLASS_COLORS, GLASSES_TRAIT)) + REMOVE_TRAIT(human_user, TRAIT_SEE_GLASS_COLORS, GLASSES_TRAIT) + to_chat(human_user, span_notice("You will no longer see glasses colors.")) else - return ..() + ADD_TRAIT(human_user, TRAIT_SEE_GLASS_COLORS, GLASSES_TRAIT) + to_chat(human_user, span_notice("You will now see glasses colors.")) + human_user.update_glasses_color(src, TRUE) + return CLICK_ACTION_SUCCESS /obj/item/clothing/glasses/proc/change_glass_color(mob/living/carbon/human/H, datum/client_colour/glass_colour/new_color_type) var/old_colour_type = glass_colour_type @@ -454,7 +448,11 @@ glass_colour_type = /datum/client_colour/glass_colour/gray /obj/item/clothing/glasses/welding/attack_self(mob/user) - weldingvisortoggle(user) + adjust_visor(user) + +/obj/item/clothing/glasses/welding/update_icon_state() + . = ..() + icon_state = "[initial(icon_state)][up ? "up" : ""]" /obj/item/clothing/glasses/welding/up/Initialize(mapload) . = ..() @@ -485,27 +483,10 @@ var/colored_before = FALSE /obj/item/clothing/glasses/blindfold/white/visual_equipped(mob/living/carbon/human/user, slot) - if(ishuman(user) && (slot & ITEM_SLOT_EYES)) - update_icon(ALL, user) - user.update_worn_glasses() //Color might have been changed by update_icon. - ..() - -/obj/item/clothing/glasses/blindfold/white/update_icon(updates=ALL, mob/living/carbon/human/user) - . = ..() - if(ishuman(user) && !colored_before) + if(ishuman(user) && (slot & ITEM_SLOT_EYES) && !colored_before) add_atom_colour(BlendRGB(user.eye_color_left, user.eye_color_right, 0.5), FIXED_COLOUR_PRIORITY) colored_before = TRUE - -/obj/item/clothing/glasses/blindfold/white/worn_overlays(mutable_appearance/standing, isinhands = FALSE, file2use) - . = ..() - if(isinhands || !ishuman(loc) || colored_before) - return - - var/mob/living/carbon/human/H = loc - var/mutable_appearance/M = mutable_appearance('icons/mob/clothing/eyes.dmi', "blindfoldwhite") - M.appearance_flags |= RESET_COLOR - M.color = H.eye_color_left - . += M + return ..() /obj/item/clothing/glasses/sunglasses/big desc = "Strangely ancient technology used to help provide rudimentary eye cover. Larger than average enhanced shielding blocks flashes." @@ -656,18 +637,19 @@ var/datum/atom_hud/our_hud = GLOB.huds[hud] our_hud.hide_from(user) -/obj/item/clothing/glasses/debug/AltClick(mob/user) - . = ..() - if(ishuman(user)) - if(xray) - vision_flags &= ~SEE_MOBS|SEE_OBJS - REMOVE_TRAIT(user, TRAIT_XRAY_VISION, GLASSES_TRAIT) - else - vision_flags |= SEE_MOBS|SEE_OBJS - ADD_TRAIT(user, TRAIT_XRAY_VISION, GLASSES_TRAIT) - xray = !xray - var/mob/living/carbon/human/human_user = user - human_user.update_sight() +/obj/item/clothing/glasses/debug/click_alt(mob/user) + if(!ishuman(user)) + return CLICK_ACTION_BLOCKING + if(xray) + vision_flags &= ~SEE_MOBS|SEE_OBJS + REMOVE_TRAIT(user, TRAIT_XRAY_VISION, GLASSES_TRAIT) + else + vision_flags |= SEE_MOBS|SEE_OBJS + ADD_TRAIT(user, TRAIT_XRAY_VISION, GLASSES_TRAIT) + xray = !xray + var/mob/living/carbon/human/human_user = user + human_user.update_sight() + return CLICK_ACTION_SUCCESS /obj/item/clothing/glasses/regular/kim name = "binoclard lenses" diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index 0c48cb102b248..5f63e0c3464bf 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -16,6 +16,8 @@ attack_verb_simple = list("challenge") strip_delay = 20 equip_delay_other = 40 + article = "a pair of" + // Path variable. If defined, will produced the type through interaction with wirecutters. var/cut_type = null /// Used for handling bloody gloves leaving behind bloodstains on objects. Will be decremented whenever a bloodstain is left behind, and be incremented when the gloves become bloody. diff --git a/code/modules/clothing/gloves/boxing.dm b/code/modules/clothing/gloves/boxing.dm index deed90b169636..03b1cbb5bf782 100644 --- a/code/modules/clothing/gloves/boxing.dm +++ b/code/modules/clothing/gloves/boxing.dm @@ -6,6 +6,25 @@ equip_delay_other = 60 species_exception = list(/datum/species/golem) // now you too can be a golem boxing champion clothing_traits = list(TRAIT_CHUNKYFINGERS) + /// Determines the version of boxing (or any martial art for that matter) that the boxing gloves gives + var/style_to_give = /datum/martial_art/boxing + +/obj/item/clothing/gloves/boxing/Initialize(mapload) + . = ..() + var/static/list/slapcraft_recipe_list = list(/datum/crafting_recipe/extendohand_l, /datum/crafting_recipe/extendohand_r) + + AddComponent( + /datum/component/slapcrafting,\ + slapcraft_recipes = slapcraft_recipe_list,\ + ) + + AddComponent(/datum/component/martial_art_giver, style_to_give) + +/obj/item/clothing/gloves/boxing/evil + name = "evil boxing gloves" + desc = "These strange gloves radiate an unsually evil aura." + greyscale_colors = "#21211f" + style_to_give = /datum/martial_art/boxing/evil /obj/item/clothing/gloves/boxing/green icon_state = "boxinggreen" @@ -18,3 +37,16 @@ /obj/item/clothing/gloves/boxing/yellow icon_state = "boxingyellow" greyscale_colors = "#d2a800" + +/obj/item/clothing/gloves/boxing/golden + name = "golden gloves" + desc = "The reigning champ of the station!" + icon_state = "boxinggold" + custom_materials = list(/datum/material/gold = SHEET_MATERIAL_AMOUNT*1) //LITERALLY GOLD + material_flags = MATERIAL_EFFECTS | MATERIAL_AFFECT_STATISTICS + equip_delay_other = 120 + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE + +/obj/item/clothing/gloves/boxing/golden/Initialize(mapload) + . = ..() + AddElement(/datum/element/skill_reward, /datum/skill/athletics) diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index c2e4b9c9ef7f6..018543d93a33c 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -130,25 +130,20 @@ ///Icon state of the welding visor. var/visor_state = "weldvisor" -/obj/item/clothing/head/utility/hardhat/welding/Initialize(mapload) - . = ..() - update_appearance() - /obj/item/clothing/head/utility/hardhat/welding/attack_self_secondary(mob/user, modifiers) - toggle_welding_screen(user) + adjust_visor(user) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/item/clothing/head/utility/hardhat/welding/ui_action_click(mob/user, actiontype) if(istype(actiontype, /datum/action/item_action/toggle_welding_screen)) - toggle_welding_screen(user) + adjust_visor(user) return - return ..() -/obj/item/clothing/head/utility/hardhat/welding/proc/toggle_welding_screen(mob/living/user) - if(weldingvisortoggle(user)) - playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing - update_appearance() +/obj/item/clothing/head/utility/hardhat/welding/adjust_visor(mob/living/user) + . = ..() + if(.) + playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) /obj/item/clothing/head/utility/hardhat/welding/worn_overlays(mutable_appearance/standing, isinhands) . = ..() @@ -199,7 +194,8 @@ min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF visor_flags_cover = NONE - flags_inv = HIDEEARS|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT + flags_inv = HIDEEARS|HIDEHAIR|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT + transparent_protection = HIDEMASK|HIDEEYES visor_flags_inv = NONE visor_state = "weldvisor_atmos" diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 7741251f3f5b2..0122cda397824 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -142,6 +142,7 @@ /obj/item/clothing/head/helmet/toggleable + visor_vars_to_toggle = NONE dog_fashion = null ///chat message when the visor is toggled down. var/toggle_message @@ -149,26 +150,11 @@ var/alt_toggle_message /obj/item/clothing/head/helmet/toggleable/attack_self(mob/user) + adjust_visor(user) + +/obj/item/clothing/head/helmet/toggleable/update_icon_state() . = ..() - if(.) - return - if(user.incapacitated() || !try_toggle()) - return - up = !up - flags_1 ^= visor_flags - flags_inv ^= visor_flags_inv - flags_cover ^= visor_flags_cover icon_state = "[initial(icon_state)][up ? "up" : ""]" - to_chat(user, span_notice("[up ? alt_toggle_message : toggle_message] \the [src].")) - - user.update_worn_head() - if(iscarbon(user)) - var/mob/living/carbon/carbon_user = user - carbon_user.head_update(src, forced = TRUE) - -///Attempt to toggle the visor. Returns true if it does the thing. -/obj/item/clothing/head/helmet/toggleable/proc/try_toggle() - return TRUE /obj/item/clothing/head/helmet/toggleable/riot name = "riot helmet" @@ -195,6 +181,21 @@ acid = 80 wound = 15 +/obj/item/clothing/head/helmet/balloon + name = "balloon helmet" + desc = "A helmet made out of balloons. Its likes saw great usage in the Great Clown - Mime War. Surprisingly resistant to fire. Mimes were doing unspeakable things." + icon_state = "helmet_balloon" + inhand_icon_state = "helmet_balloon" + armor_type = /datum/armor/balloon + flags_inv = HIDEHAIR|HIDEEARS|HIDESNOUT + resistance_flags = FIRE_PROOF + dog_fashion = null + +/datum/armor/balloon + melee = 10 + fire = 60 + acid = 50 + /obj/item/clothing/head/helmet/toggleable/justice name = "helmet of justice" desc = "WEEEEOOO. WEEEEEOOO. WEEEEOOOO." @@ -208,11 +209,18 @@ ///Looping sound datum for the siren helmet var/datum/looping_sound/siren/weewooloop -/obj/item/clothing/head/helmet/toggleable/justice/try_toggle() +/obj/item/clothing/head/helmet/toggleable/justice/adjust_visor(mob/living/user) if(!COOLDOWN_FINISHED(src, visor_toggle_cooldown)) return FALSE COOLDOWN_START(src, visor_toggle_cooldown, 2 SECONDS) - return TRUE + return ..() + +/obj/item/clothing/head/helmet/toggleable/justice/visor_toggling() + . = ..() + if(up) + weewooloop.start() + else + weewooloop.stop() /obj/item/clothing/head/helmet/toggleable/justice/Initialize(mapload) . = ..() @@ -222,13 +230,6 @@ QDEL_NULL(weewooloop) return ..() -/obj/item/clothing/head/helmet/toggleable/justice/attack_self(mob/user) - . = ..() - if(up) - weewooloop.start() - else - weewooloop.stop() - /obj/item/clothing/head/helmet/toggleable/justice/escape name = "alarm helmet" desc = "WEEEEOOO. WEEEEEOOO. STOP THAT MONKEY. WEEEOOOO." @@ -423,16 +424,6 @@ armor_type = /datum/armor/knight_greyscale material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix -/datum/armor/knight_greyscale - melee = 35 - bullet = 10 - laser = 10 - energy = 10 - bomb = 10 - bio = 10 - fire = 40 - acid = 40 - /obj/item/clothing/head/helmet/skull name = "skull helmet" desc = "An intimidating tribal helmet, it doesn't look very comfortable." @@ -533,3 +524,48 @@ fire = 65 acid = 40 wound = 15 + +/obj/item/clothing/head/helmet/military + name = "Crude Helmet" + desc = "A cheaply made kettle helmet with an added faceplate to protect your eyes and mouth." + icon_state = "military" + inhand_icon_state = "knight_helmet" + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT + flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF + strip_delay = 80 + dog_fashion = null + armor_type = /datum/armor/helmet_military + +/datum/armor/helmet_military + melee = 45 + bullet = 25 + laser = 25 + energy = 25 + bomb = 25 + fire = 10 + acid = 50 + wound = 20 + +/obj/item/clothing/head/helmet/military/Initialize(mapload) + . = ..() + AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) + +/obj/item/clothing/head/helmet/knight/warlord + name = "golden barbute helmet" + desc = "There is no man behind the helmet, only a terrible thought." + icon_state = "warlord" + inhand_icon_state = null + armor_type = /datum/armor/helmet_warlord + flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT + flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF + slowdown = 0.2 + +/datum/armor/helmet_warlord + melee = 70 + bullet = 60 + laser = 70 + energy = 70 + bomb = 40 + fire = 50 + acid = 50 + wound = 30 diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index 67ecc0d485908..1ea2acb78a61f 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -166,6 +166,8 @@ desc = "An opulent hat that functions as a radio to God. Or as a lightning rod, depending on who you ask." icon_state = "bishopmitre" +#define CANDY_CD_TIME 2 MINUTES + //Detective /obj/item/clothing/head/fedora/det_hat name = "detective's fedora" @@ -173,10 +175,13 @@ armor_type = /datum/armor/fedora_det_hat icon_state = "detective" inhand_icon_state = "det_hat" - var/candy_cooldown = 0 + interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING dog_fashion = /datum/dog_fashion/head/detective - ///Path for the flask that spawns inside their hat roundstart + /// Path for the flask that spawns inside their hat roundstart var/flask_path = /obj/item/reagent_containers/cup/glass/flask/det + /// Cooldown for retrieving precious candy corn with rmb + COOLDOWN_DECLARE(candy_cooldown) + /datum/armor/fedora_det_hat melee = 25 @@ -187,28 +192,45 @@ acid = 50 wound = 5 + /obj/item/clothing/head/fedora/det_hat/Initialize(mapload) . = ..() create_storage(storage_type = /datum/storage/pockets/small/fedora/detective) + register_context() + new flask_path(src) + /obj/item/clothing/head/fedora/det_hat/examine(mob/user) . = ..() . += span_notice("Alt-click to take a candy corn.") -/obj/item/clothing/head/fedora/det_hat/AltClick(mob/user) + +/obj/item/clothing/head/fedora/det_hat/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() - if(loc != user || !user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) - return - if(candy_cooldown < world.time) - var/obj/item/food/candy_corn/CC = new /obj/item/food/candy_corn(src) - user.put_in_hands(CC) - to_chat(user, span_notice("You slip a candy corn from your hat.")) - candy_cooldown = world.time+1200 - else + + context[SCREENTIP_CONTEXT_ALT_LMB] = "Candy Time" + + return CONTEXTUAL_SCREENTIP_SET + + +/// Now to solve where all these keep coming from +/obj/item/clothing/head/fedora/det_hat/click_alt(mob/user) + if(!COOLDOWN_FINISHED(src, candy_cooldown)) to_chat(user, span_warning("You just took a candy corn! You should wait a couple minutes, lest you burn through your stash.")) + return CLICK_ACTION_BLOCKING + + var/obj/item/food/candy_corn/sweets = new /obj/item/food/candy_corn(src) + user.put_in_hands(sweets) + to_chat(user, span_notice("You slip a candy corn from your hat.")) + COOLDOWN_START(src, candy_cooldown, CANDY_CD_TIME) + + return CLICK_ACTION_SUCCESS + + +#undef CANDY_CD_TIME /obj/item/clothing/head/fedora/det_hat/minor flask_path = /obj/item/reagent_containers/cup/glass/flask/det/minor @@ -221,10 +243,13 @@ icon_state = "detective" inhand_icon_state = "det_hat" dog_fashion = /datum/dog_fashion/head/detective + interaction_flags_click = FORBID_TELEKINESIS_REACH|ALLOW_RESTING ///prefix our phrases must begin with var/prefix = "go go gadget" - ///an assoc list of phrase = item (like gun = revolver) - var/list/items_by_phrase = list() + ///an assoc list of regex = item (like regex datum = revolver item) + var/list/items_by_regex = list() + ///A an assoc list of regex = phrase (like regex datum = gun text) + var/list/phrases_by_regex = list() ///how many gadgets can we hold var/max_items = 4 ///items above this weight cannot be put in the hat @@ -235,36 +260,58 @@ become_hearing_sensitive(ROUNDSTART_TRAIT) QDEL_NULL(atom_storage) +/obj/item/clothing/head/fedora/inspector_hat/proc/set_prefix(desired_prefix) + + prefix = desired_prefix + + // Regenerated the phrases here. + for(var/old_regex in phrases_by_regex) + var/old_phrase = phrases_by_regex[old_regex] + var/obj/item/old_item = items_by_regex[old_regex] + items_by_regex -= old_regex + phrases_by_regex -= old_regex + set_phrase(old_phrase,old_item) + + return TRUE + +/obj/item/clothing/head/fedora/inspector_hat/proc/set_phrase(desired_phrase,obj/item/associated_item) + + var/regex/phrase_regex = regex("[prefix]\[\\s\\W\]+[desired_phrase]","i") + + phrases_by_regex[phrase_regex] = desired_phrase + items_by_regex[phrase_regex] = associated_item + + return TRUE + /obj/item/clothing/head/fedora/inspector_hat/examine(mob/user) . = ..() . += span_notice("You can put items inside, and get them out by saying a phrase, or using it in-hand!") . += span_notice("The prefix is [prefix], and you can change it with alt-click!\n") - for(var/phrase in items_by_phrase) - var/obj/item/item = items_by_phrase[phrase] - . += span_notice("[icon2html(item, user)] You can remove [item] by saying \"[prefix] [phrase]\"!") + for(var/found_regex in phrases_by_regex) + var/found_phrase = phrases_by_regex[found_regex] + var/obj/item/found_item = items_by_regex[found_regex] + . += span_notice("[icon2html(found_item, user)] You can remove [found_item] by saying \"[prefix] [found_phrase]\"!") /obj/item/clothing/head/fedora/inspector_hat/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range) . = ..() var/mob/living/carbon/wearer = loc if(!istype(wearer) || speaker != wearer) //if we are worn - return FALSE + return raw_message = htmlrendertext(raw_message) - var/prefix_index = findtext(raw_message, prefix) - if(prefix_index != 1) - return FALSE - - var/the_phrase = trim_left(replacetext(raw_message, prefix, "")) - var/obj/item/result = items_by_phrase[the_phrase] - if(!result) - return FALSE - if(wearer.put_in_active_hand(result)) - wearer.visible_message(span_warning("[src] drops [result] into the hands of [wearer]!")) - else - balloon_alert(wearer, "cant put in hands!") - - return TRUE + for(var/regex/found_regex as anything in phrases_by_regex) + if(!found_regex.Find(raw_message)) + continue + var/obj/item/found_item = items_by_regex[found_regex] + if(wearer.put_in_hands(found_item)) + wearer.visible_message(span_warning("[src] drops [found_item] into the hands of [wearer]!")) + . = TRUE + else + balloon_alert(wearer, "can't put in hands!") + break + + return . /obj/item/clothing/head/fedora/inspector_hat/attackby(obj/item/item, mob/user, params) . = ..() @@ -276,51 +323,61 @@ balloon_alert(user, "too big!") return - var/input = tgui_input_text(user, "What is the activation phrase?", "Activation phrase", "gadget", max_length = 26) - if(!input) - return - if(input in items_by_phrase) - balloon_alert(user, "already used!") + var/desired_phrase = tgui_input_text(user, "What is the activation phrase?", "Activation phrase", "gadget", max_length = 26) + if(!desired_phrase || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return if(item.loc != user || !user.transferItemToLoc(item, src)) return - to_chat(user, span_notice("You install [item] into the [thtotext(contents.len)] slot in [src].")) + to_chat(user, span_notice("You install [item] into the [thtotext(contents.len)] slot of [src].")) playsound(src, 'sound/machines/click.ogg', 30, TRUE) - items_by_phrase[input] = item + set_phrase(desired_phrase,item) -/obj/item/clothing/head/fedora/inspector_hat/attack_self(mob/user) - . = ..() - var/phrase = tgui_input_list(user, "What item do you want to remove by phrase?", "Item Removal", items_by_phrase) - if(!phrase) - return - user.put_in_inactive_hand(items_by_phrase[phrase]) + return TRUE -/obj/item/clothing/head/fedora/inspector_hat/AltClick(mob/user) +/obj/item/clothing/head/fedora/inspector_hat/attack_self(mob/user) . = ..() + if(!length(items_by_regex)) + return CLICK_ACTION_BLOCKING + var/list/found_items = list() + for(var/found_regex in items_by_regex) + found_items += items_by_regex[found_regex] + var/obj/found_item = tgui_input_list(user, "What item do you want to remove?", "Item Removal", found_items) + if(!found_item || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + return CLICK_ACTION_BLOCKING + user.put_in_inactive_hand(found_item) + +/obj/item/clothing/head/fedora/inspector_hat/click_alt(mob/user) var/new_prefix = tgui_input_text(user, "What should be the new prefix?", "Activation prefix", prefix, max_length = 24) - if(!new_prefix) - return - prefix = new_prefix + if(!new_prefix || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + return CLICK_ACTION_BLOCKING + set_prefix(new_prefix) + return CLICK_ACTION_SUCCESS /obj/item/clothing/head/fedora/inspector_hat/Exited(atom/movable/gone, direction) . = ..() - for(var/phrase in items_by_phrase) - var/obj/item/result = items_by_phrase[phrase] - if(gone == result) - items_by_phrase -= phrase - return + for(var/found_regex in items_by_regex) + var/obj/item/found_item = items_by_regex[found_regex] + if(gone != found_item) + continue + items_by_regex -= found_regex + phrases_by_regex -= found_regex + break /obj/item/clothing/head/fedora/inspector_hat/atom_destruction(damage_flag) - for(var/phrase in items_by_phrase) - var/obj/item/result = items_by_phrase[phrase] - result.forceMove(drop_location()) - items_by_phrase = null + + var/atom/atom_location = drop_location() + for(var/found_regex in items_by_regex) + var/obj/item/result = items_by_regex[found_regex] + result.forceMove(atom_location) + items_by_regex -= found_regex + phrases_by_regex -= found_regex + return ..() /obj/item/clothing/head/fedora/inspector_hat/Destroy() - QDEL_LIST_ASSOC(items_by_phrase) + QDEL_LIST_ASSOC(items_by_regex) //Anything that failed to drop gets deleted. return ..() //Mime diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm index 0b0a6fb4d50cb..3003e9a76ee15 100644 --- a/code/modules/clothing/head/soft_caps.dm +++ b/code/modules/clothing/head/soft_caps.dm @@ -5,11 +5,14 @@ worn_icon = 'icons/mob/clothing/head/hats.dmi' icon_state = "cargosoft" inhand_icon_state = "greyscale_softcap" //todo wip + interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING + /// For setting icon archetype var/soft_type = "cargo" + /// If there is a suffix to append var/soft_suffix = "soft" dog_fashion = /datum/dog_fashion/head/cargo_tech - + /// Whether this is on backwards... Woah, cool var/flipped = FALSE /obj/item/clothing/head/soft/dropped() @@ -24,10 +27,9 @@ flip(usr) -/obj/item/clothing/head/soft/AltClick(mob/user) - ..() - if(user.can_perform_action(src, NEED_DEXTERITY)) - flip(user) +/obj/item/clothing/head/soft/click_alt(mob/user) + flip(user) + return CLICK_ACTION_SUCCESS /obj/item/clothing/head/soft/proc/flip(mob/user) diff --git a/code/modules/clothing/head/tophat.dm b/code/modules/clothing/head/tophat.dm index 26087ab6232e0..2affc4c63da18 100644 --- a/code/modules/clothing/head/tophat.dm +++ b/code/modules/clothing/head/tophat.dm @@ -36,4 +36,13 @@ var/mob/living/basic/rabbit/bunbun = new(get_turf(magician)) bunbun.mob_try_pickup(magician, instant=TRUE) +/obj/item/clothing/head/hats/tophat/balloon + name = "balloon top-hat" + desc = "It's an colourful looking top-hat to match yout colourful personality." + icon_state = "balloon_tophat" + inhand_icon_state = "balloon_that" + throwforce = 0 + resistance_flags = FIRE_PROOF + dog_fashion = null + #undef RABBIT_CD_TIME diff --git a/code/modules/clothing/head/welding.dm b/code/modules/clothing/head/welding.dm index bccb1d4524db0..cb785447174f7 100644 --- a/code/modules/clothing/head/welding.dm +++ b/code/modules/clothing/head/welding.dm @@ -14,6 +14,7 @@ actions_types = list(/datum/action/item_action/toggle) visor_flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDESNOUT visor_flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF + visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT resistance_flags = FIRE_PROOF clothing_flags = SNUG_FIT | STACKABLE_HELMET_EXEMPT @@ -23,9 +24,9 @@ acid = 60 /obj/item/clothing/head/utility/welding/attack_self(mob/user) - weldingvisortoggle(user) + adjust_visor(user) -/obj/item/clothing/head/utility/welding/visor_toggling() +/obj/item/clothing/head/utility/welding/update_icon_state() . = ..() + icon_state = "[initial(icon_state)][up ? "up" : ""]" inhand_icon_state = "[initial(inhand_icon_state)][up ? "off" : ""]" - diff --git a/code/modules/clothing/head/wig.dm b/code/modules/clothing/head/wig.dm index 70e3f8a6b7218..ecd70742ba889 100644 --- a/code/modules/clothing/head/wig.dm +++ b/code/modules/clothing/head/wig.dm @@ -25,30 +25,18 @@ item_flags &= ~EXAMINE_SKIP /obj/item/clothing/head/wig/update_icon_state() - var/datum/sprite_accessory/hair/hair_style = GLOB.hairstyles_list[hairstyle] + var/datum/sprite_accessory/hair/hair_style = SSaccessories.hairstyles_list[hairstyle] if(hair_style) icon = hair_style.icon icon_state = hair_style.icon_state return ..() - -/obj/item/clothing/head/wig/build_worn_icon( - default_layer = 0, - default_icon_file = null, - isinhands = FALSE, - female_uniform = NO_FEMALE_UNIFORM, - override_state = null, - override_file = null, - use_height_offset = TRUE, -) - return ..(default_layer, default_icon_file, isinhands, female_uniform, override_state, override_file, use_height_offset = FALSE) - /obj/item/clothing/head/wig/worn_overlays(mutable_appearance/standing, isinhands = FALSE, file2use) . = ..() if(isinhands) return - var/datum/sprite_accessory/hair/hair = GLOB.hairstyles_list[hairstyle] + var/datum/sprite_accessory/hair/hair = SSaccessories.hairstyles_list[hairstyle] if(!hair) return @@ -61,7 +49,7 @@ hair_overlay.overlays += emissive_blocker(hair_overlay.icon, hair_overlay.icon_state, src, alpha = hair_overlay.alpha) /obj/item/clothing/head/wig/attack_self(mob/user) - var/new_style = tgui_input_list(user, "Select a hairstyle", "Wig Styling", GLOB.hairstyles_list - "Bald") + var/new_style = tgui_input_list(user, "Select a hairstyle", "Wig Styling", SSaccessories.hairstyles_list - "Bald") var/newcolor = adjustablecolor ? input(usr,"","Choose Color",color) as color|null : null if(!user.can_perform_action(src)) return @@ -104,7 +92,7 @@ update_appearance() /obj/item/clothing/head/wig/random/Initialize(mapload) - hairstyle = pick(GLOB.hairstyles_list - "Bald") //Don't want invisible wig + hairstyle = pick(SSaccessories.hairstyles_list - "Bald") //Don't want invisible wig add_atom_colour("#[random_short_color()]", FIXED_COLOUR_PRIORITY) . = ..() @@ -116,7 +104,7 @@ custom_price = PAYCHECK_COMMAND /obj/item/clothing/head/wig/natural/Initialize(mapload) - hairstyle = pick(GLOB.hairstyles_list - "Bald") + hairstyle = pick(SSaccessories.hairstyles_list - "Bald") . = ..() /obj/item/clothing/head/wig/natural/visual_equipped(mob/living/carbon/human/user, slot) diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm index 23fc2272229af..c1d29d65c8641 100644 --- a/code/modules/clothing/masks/_masks.dm +++ b/code/modules/clothing/masks/_masks.dm @@ -7,9 +7,8 @@ slot_flags = ITEM_SLOT_MASK strip_delay = 40 equip_delay_other = 40 + visor_vars_to_toggle = NONE var/modifies_speech = FALSE - ///Whether the mask is pushed out of the food hole or not. - var/mask_adjusted = FALSE var/adjusted_flags = null ///Did we install a filtering cloth? var/has_filter = FALSE @@ -69,33 +68,17 @@ M.update_worn_mask() //Proc that moves gas/breath masks out of the way, disabling them and allowing pill/food consumption -/obj/item/clothing/mask/proc/adjustmask(mob/living/carbon/user) - if(user?.incapacitated()) - return - mask_adjusted = !mask_adjusted - if(!mask_adjusted) - icon_state = initial(icon_state) - clothing_flags |= visor_flags - flags_inv |= visor_flags_inv - flags_cover |= visor_flags_cover - to_chat(user, span_notice("You push \the [src] back into place.")) - slot_flags = initial(slot_flags) - else - icon_state += "_up" - to_chat(user, span_notice("You push \the [src] out of the way.")) - clothing_flags &= ~visor_flags - flags_inv &= ~visor_flags_inv - flags_cover &= ~visor_flags_cover +/obj/item/clothing/mask/visor_toggling(mob/living/user) + . = ..() + if(up) if(adjusted_flags) slot_flags = adjusted_flags - if(!istype(user)) - return - // Update the mob if it's wearing the mask. - if(user.wear_mask == src) - user.wear_mask_update(src, toggle_off = mask_adjusted) - if(loc == user) - // Update action button icon for adjusted mask, if someone is holding it. - user.update_mob_action_buttons() + else + slot_flags = initial(slot_flags) + +/obj/item/clothing/mask/update_icon_state() + . = ..() + icon_state = "[initial(icon_state)][up ? "_up" : ""]" /** * Proc called in lungs.dm to act if wearing a mask with filters, used to reduce the filters durability, return a changed gas mixture depending on the filter status diff --git a/code/modules/clothing/masks/animal_masks.dm b/code/modules/clothing/masks/animal_masks.dm index c2013b99177b4..5df5c6738d8e5 100644 --- a/code/modules/clothing/masks/animal_masks.dm +++ b/code/modules/clothing/masks/animal_masks.dm @@ -46,11 +46,12 @@ GLOBAL_LIST_INIT(cursed_animal_masks, list( if(clothing_flags & VOICEBOX_TOGGLABLE) . += span_notice("Its voicebox is currently [clothing_flags & VOICEBOX_DISABLED ? "disabled" : "enabled"]. Alt-click to toggle it.") -/obj/item/clothing/mask/animal/AltClick(mob/user) - . = ..() - if(clothing_flags & VOICEBOX_TOGGLABLE) - clothing_flags ^= VOICEBOX_DISABLED - to_chat(user, span_notice("You [clothing_flags & VOICEBOX_DISABLED ? "disabled" : "enabled"] [src]'s voicebox.")) +/obj/item/clothing/mask/animal/click_alt(mob/user) + if(!(clothing_flags & VOICEBOX_TOGGLABLE)) + return NONE + clothing_flags ^= VOICEBOX_DISABLED + to_chat(user, span_notice("You [clothing_flags & VOICEBOX_DISABLED ? "disabled" : "enabled"] [src]'s voicebox.")) + return CLICK_ACTION_SUCCESS /obj/item/clothing/mask/animal/proc/make_cursed() //apply cursed effects. ADD_TRAIT(src, TRAIT_NODROP, CURSED_MASK_TRAIT) diff --git a/code/modules/clothing/masks/bandana.dm b/code/modules/clothing/masks/bandana.dm index 2c2dc81a1f0d3..c43c49a3995e5 100644 --- a/code/modules/clothing/masks/bandana.dm +++ b/code/modules/clothing/masks/bandana.dm @@ -22,7 +22,7 @@ /obj/item/clothing/mask/bandana/examine(mob/user) . = ..() - if(mask_adjusted) + if(up) . += "Use in-hand to untie it to wear as a mask!" return if(slot_flags & ITEM_SLOT_NECK) @@ -32,48 +32,51 @@ . += "Alt-click to tie it up to wear on your neck!" /obj/item/clothing/mask/bandana/attack_self(mob/user) + adjust_visor(user) + +/obj/item/clothing/mask/bandana/adjust_visor(mob/living/user) if(slot_flags & ITEM_SLOT_NECK) to_chat(user, span_warning("You must undo [src] in order to push it into a hat!")) - return - adjustmask(user) + return FALSE + return ..() -/obj/item/clothing/mask/bandana/adjustmask(mob/living/user) +/obj/item/clothing/mask/bandana/visor_toggling() . = ..() - if(mask_adjusted) + if(up) undyeable = TRUE else - inhand_icon_state = initial(inhand_icon_state) - worn_icon_state = initial(worn_icon_state) undyeable = initial(undyeable) -/obj/item/clothing/mask/bandana/AltClick(mob/user) - . = ..() - if(iscarbon(user)) - var/mob/living/carbon/char = user - var/matrix/widen = matrix() - if((char.get_item_by_slot(ITEM_SLOT_NECK) == src) || (char.get_item_by_slot(ITEM_SLOT_MASK) == src) || (char.get_item_by_slot(ITEM_SLOT_HEAD) == src)) - to_chat(user, span_warning("You can't tie [src] while wearing it!")) - return - else if(slot_flags & ITEM_SLOT_HEAD) - to_chat(user, span_warning("You must undo [src] before you can tie it into a neckerchief!")) - return - else if(!user.is_holding(src)) - to_chat(user, span_warning("You must be holding [src] in order to tie it!")) - return - - if(slot_flags & ITEM_SLOT_MASK) - undyeable = TRUE - slot_flags = ITEM_SLOT_NECK - worn_y_offset = -3 - widen.Scale(1.25, 1) - transform = widen - user.visible_message(span_notice("[user] ties [src] up like a neckerchief."), span_notice("You tie [src] up like a neckerchief.")) - else - undyeable = initial(undyeable) - slot_flags = initial(slot_flags) - worn_y_offset = initial(worn_y_offset) - transform = initial(transform) - user.visible_message(span_notice("[user] unties the neckercheif."), span_notice("You untie the neckercheif.")) +/obj/item/clothing/mask/bandana/click_alt(mob/user) + if(!iscarbon(user)) + return NONE + + var/mob/living/carbon/char = user + var/matrix/widen = matrix() + if((char.get_item_by_slot(ITEM_SLOT_NECK) == src) || (char.get_item_by_slot(ITEM_SLOT_MASK) == src) || (char.get_item_by_slot(ITEM_SLOT_HEAD) == src)) + to_chat(user, span_warning("You can't tie [src] while wearing it!")) + return CLICK_ACTION_BLOCKING + else if(slot_flags & ITEM_SLOT_HEAD) + to_chat(user, span_warning("You must undo [src] before you can tie it into a neckerchief!")) + return CLICK_ACTION_BLOCKING + else if(!user.is_holding(src)) + to_chat(user, span_warning("You must be holding [src] in order to tie it!")) + return CLICK_ACTION_BLOCKING + + if(slot_flags & ITEM_SLOT_MASK) + undyeable = TRUE + slot_flags = ITEM_SLOT_NECK + worn_y_offset = -3 + widen.Scale(1.25, 1) + transform = widen + user.visible_message(span_notice("[user] ties [src] up like a neckerchief."), span_notice("You tie [src] up like a neckerchief.")) + else + undyeable = initial(undyeable) + slot_flags = initial(slot_flags) + worn_y_offset = initial(worn_y_offset) + transform = initial(transform) + user.visible_message(span_notice("[user] unties the neckercheif."), span_notice("You untie the neckercheif.")) + return CLICK_ACTION_SUCCESS /obj/item/clothing/mask/bandana/red name = "red bandana" @@ -222,11 +225,15 @@ greyscale_config_inhand_left = /datum/greyscale_config/facescarf/inhands_left greyscale_config_inhand_right = /datum/greyscale_config/facescarf/inhands_right flags_1 = IS_PLAYER_COLORABLE_1 + interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING + +/obj/item/clothing/mask/facescarf/attack_self(mob/user) + adjust_visor(user) + +/obj/item/clothing/mask/facescarf/click_alt(mob/user) + adjust_visor(user) + return CLICK_ACTION_SUCCESS -/obj/item/clothing/mask/facescarf/AltClick(mob/user) - ..() - if(user.can_perform_action(src, NEED_DEXTERITY)) - adjustmask(user) /obj/item/clothing/mask/facescarf/examine(mob/user) . = ..() diff --git a/code/modules/clothing/masks/boxing.dm b/code/modules/clothing/masks/boxing.dm index 78ba0764b81ec..468b1272f8604 100644 --- a/code/modules/clothing/masks/boxing.dm +++ b/code/modules/clothing/masks/boxing.dm @@ -10,7 +10,7 @@ actions_types = list(/datum/action/item_action/adjust) /obj/item/clothing/mask/balaclava/attack_self(mob/user) - adjustmask(user) + adjust_visor(user) /obj/item/clothing/mask/floortilebalaclava name = "floortile balaclava" @@ -25,7 +25,7 @@ actions_types = list(/datum/action/item_action/adjust) /obj/item/clothing/mask/floortilebalaclava/attack_self(mob/user) - adjustmask(user) + adjust_visor(user) /obj/item/clothing/mask/luchador name = "Luchador Mask" diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm index 8ba15fe521d56..73f91f7c6b87c 100644 --- a/code/modules/clothing/masks/breath.dm +++ b/code/modules/clothing/masks/breath.dm @@ -12,6 +12,7 @@ flags_cover = MASKCOVERSMOUTH visor_flags_cover = MASKCOVERSMOUTH resistance_flags = NONE + interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING /datum/armor/mask_breath bio = 50 @@ -21,12 +22,11 @@ return OXYLOSS /obj/item/clothing/mask/breath/attack_self(mob/user) - adjustmask(user) + adjust_visor(user) -/obj/item/clothing/mask/breath/AltClick(mob/user) - ..() - if(user.can_perform_action(src, NEED_DEXTERITY)) - adjustmask(user) +/obj/item/clothing/mask/breath/click_alt(mob/user) + adjust_visor(user) + return CLICK_ACTION_SUCCESS /obj/item/clothing/mask/breath/examine(mob/user) . = ..() diff --git a/code/modules/clothing/masks/costume.dm b/code/modules/clothing/masks/costume.dm index 893455dcdd0f8..844b823880ac4 100644 --- a/code/modules/clothing/masks/costume.dm +++ b/code/modules/clothing/masks/costume.dm @@ -4,6 +4,7 @@ icon_state = "joy" clothing_flags = MASKINTERNALS flags_inv = HIDESNOUT + obj_flags = parent_type::obj_flags | INFINITE_RESKIN unique_reskin = list( "Joy" = "joy", "Flushed" = "flushed", @@ -12,19 +13,10 @@ "Pleading" = "pleading" ) -/obj/item/clothing/mask/joy/Initialize(mapload) - . = ..() - register_context() - -/obj/item/clothing/mask/joy/add_context(atom/source, list/context, obj/item/held_item, mob/user) - . = ..() - context[SCREENTIP_CONTEXT_ALT_LMB] = "Change Emotion" - return CONTEXTUAL_SCREENTIP_SET /obj/item/clothing/mask/joy/reskin_obj(mob/user) . = ..() user.update_worn_mask() - current_skin = null//so we can infinitely reskin /obj/item/clothing/mask/mummy name = "mummy mask" diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index f5653bcacba91..e6f3d7294c9b3 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -57,11 +57,11 @@ GLOBAL_LIST_INIT(clown_mask_options, list( cig?.equipped(equipee, slot) return ..() -/obj/item/clothing/mask/gas/adjustmask(mob/living/carbon/user) - if(isnull(cig)) - return ..() - balloon_alert(user, "there's a cig in the way!") - +/obj/item/clothing/mask/gas/adjust_visor(mob/living/user) + if(!isnull(cig)) + balloon_alert(user, "cig in the way!") + return FALSE + return ..() /obj/item/clothing/mask/gas/examine(mob/user) . = ..() @@ -219,6 +219,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list( flags_cover = MASKCOVERSEYES visor_flags_inv = HIDEEYES visor_flags_cover = MASKCOVERSEYES + visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT resistance_flags = FIRE_PROOF /datum/armor/gas_welding @@ -228,10 +229,16 @@ GLOBAL_LIST_INIT(clown_mask_options, list( acid = 55 /obj/item/clothing/mask/gas/welding/attack_self(mob/user) - if(weldingvisortoggle(user)) + adjust_visor(user) + +/obj/item/clothing/mask/gas/welding/adjust_visor(mob/living/user) + . = ..() + if(.) playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) -/obj/item/clothing/mask/gas/welding/up +/obj/item/clothing/mask/gas/welding/update_icon_state() + . = ..() + icon_state = "[initial(icon_state)][up ? "up" : ""]" /obj/item/clothing/mask/gas/welding/up/Initialize(mapload) . = ..() diff --git a/code/modules/clothing/masks/hailer.dm b/code/modules/clothing/masks/hailer.dm index 7c351d3ad3408..cbfbc166cbcab 100644 --- a/code/modules/clothing/masks/hailer.dm +++ b/code/modules/clothing/masks/hailer.dm @@ -124,7 +124,7 @@ GLOBAL_LIST_INIT(hailer_phrases, list( if(istype(action, /datum/action/item_action/halt)) halt() else - adjustmask(user) + adjust_visor(user) /obj/item/clothing/mask/gas/sechailer/attack_self() halt() diff --git a/code/modules/clothing/masks/surgical.dm b/code/modules/clothing/masks/surgical.dm index b754dc4301419..4e8390edae751 100644 --- a/code/modules/clothing/masks/surgical.dm +++ b/code/modules/clothing/masks/surgical.dm @@ -15,4 +15,4 @@ bio = 100 /obj/item/clothing/mask/surgical/attack_self(mob/user) - adjustmask(user) + adjust_visor(user) diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index b9d684cbbbf7b..ddc7a3c7d9760 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -44,6 +44,7 @@ icon = 'icons/obj/clothing/neck.dmi' icon_state = "tie_greyscale_tied" inhand_icon_state = "" //no inhands + alternate_worn_layer = LOW_NECK_LAYER // So that it renders below suit jackets, MODsuits, etc w_class = WEIGHT_CLASS_SMALL custom_price = PAYCHECK_CREW greyscale_config = /datum/greyscale_config/ties @@ -66,6 +67,7 @@ /obj/item/clothing/neck/tie/examine(mob/user) . = ..() + . += span_notice("The tie can be worn above or below your suit. Alt-Right-click to toggle.") if(clip_on) . += span_notice("Looking closely, you can see that it's actually a cleverly disguised clip-on.") else if(!is_tied) @@ -73,10 +75,9 @@ else . += span_notice("The tie can be untied with Alt-Click.") -/obj/item/clothing/neck/tie/AltClick(mob/user) - . = ..() +/obj/item/clothing/neck/tie/click_alt(mob/user) if(clip_on) - return + return NONE to_chat(user, span_notice("You concentrate as you begin [is_tied ? "untying" : "tying"] [src]...")) var/tie_timer_actual = tie_timer // Mirrors give you a boost to your tying speed. I realize this stacks and I think that's hilarious. @@ -88,11 +89,11 @@ // Tie/Untie our tie if(!do_after(user, tie_timer_actual)) to_chat(user, span_notice("Your fingers fumble away from [src] as your concentration breaks.")) - return + return CLICK_ACTION_BLOCKING // Clumsy & Dumb people have trouble tying their ties. if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) to_chat(user, span_notice("You just can't seem to get a proper grip on [src]!")) - return + return CLICK_ACTION_BLOCKING // Success! is_tied = !is_tied user.visible_message( @@ -101,6 +102,15 @@ ) update_appearance(UPDATE_ICON) user.update_clothing(ITEM_SLOT_NECK) + return CLICK_ACTION_SUCCESS + +/obj/item/clothing/neck/tie/alt_click_secondary(mob/user) + . = ..() + if(!user.can_perform_action(src, NEED_DEXTERITY)) + return + alternate_worn_layer = alternate_worn_layer == initial(alternate_worn_layer) ? NONE : initial(alternate_worn_layer) + user.update_clothing(ITEM_SLOT_NECK) + balloon_alert(user, "wearing [alternate_worn_layer == initial(alternate_worn_layer) ? "below" : "above"] suits") /obj/item/clothing/neck/tie/update_icon() . = ..() @@ -120,6 +130,7 @@ /obj/item/clothing/neck/tie/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() + context[SCREENTIP_CONTEXT_ALT_RMB] = "Wear [alternate_worn_layer == initial(alternate_worn_layer) ? "above" : "below"] suit" if(clip_on) return if(is_tied) @@ -128,6 +139,17 @@ context[SCREENTIP_CONTEXT_ALT_LMB] = "Tie" return CONTEXTUAL_SCREENTIP_SET +/obj/item/clothing/neck/tie/worn_overlays(mutable_appearance/standing, isinhands) + . = ..() + var/mob/living/carbon/human/wearer = loc + if(!ishuman(wearer) || !wearer.w_uniform) + return + var/obj/item/clothing/under/undershirt = wearer.w_uniform + if(!istype(undershirt) || !LAZYLEN(undershirt.attached_accessories)) + return + if(alternate_worn_layer) + . += undershirt.accessory_overlay + /obj/item/clothing/neck/tie/blue name = "blue tie" icon_state = "tie_greyscale_untied" @@ -198,14 +220,14 @@ user.visible_message(span_suicide("[user] puts \the [src] to [user.p_their()] chest! It looks like [user.p_they()] won't hear much!")) return OXYLOSS -/obj/item/clothing/neck/stethoscope/attack(mob/living/M, mob/living/user) - if(!ishuman(M) || !isliving(user)) +/obj/item/clothing/neck/stethoscope/attack(mob/living/target, mob/living/user) + if(!ishuman(target) || !isliving(user)) return ..() if(user.combat_mode) return - var/mob/living/carbon/carbon_patient = M - var/body_part = parse_zone(user.zone_selected) + var/mob/living/carbon/carbon_patient = target + var/body_part = carbon_patient.parse_zone_with_bodypart(user.zone_selected) var/oxy_loss = carbon_patient.getOxyLoss() var/heart_strength @@ -235,13 +257,13 @@ || (HAS_TRAIT(carbon_patient, TRAIT_NOBREATH))\ || carbon_patient.failed_last_breath \ || carbon_patient.losebreath)//If pt is dead or otherwise not breathing - render_list += "[M.p_Theyre()] not breathing!\n" + render_list += "[target.p_Theyre()] not breathing!\n" else if(lungs.damage > 10)//if breathing, check for lung damage - render_list += "You hear fluid in [M.p_their()] lungs!\n" + render_list += "You hear fluid in [target.p_their()] lungs!\n" else if(oxy_loss > 10)//if they have suffocation damage - render_list += "[M.p_Theyre()] breathing heavily!\n" + render_list += "[target.p_Theyre()] breathing heavily!\n" else - render_list += "[M.p_Theyre()] breathing normally.\n"//they're okay :D + render_list += "[target.p_Theyre()] breathing normally.\n"//they're okay :D //assess heart if(body_part == BODY_ZONE_CHEST)//if we're listening to the chest @@ -261,20 +283,20 @@ var/appendix_okay = TRUE var/liver_okay = TRUE if(!liver)//sanity check, ensure the patient actually has a liver - render_list += "You can't feel anything where [M.p_their()] liver would be.\n" + render_list += "You can't feel anything where [target.p_their()] liver would be.\n" liver_okay = FALSE else if(liver.damage > 10) - render_list += "[M.p_Their()] liver feels firm.\n"//their liver is damaged + render_list += "[target.p_Their()] liver feels firm.\n"//their liver is damaged liver_okay = FALSE if(!appendix)//sanity check, ensure the patient actually has an appendix - render_list += "You can't feel anything where [M.p_their()] appendix would be.\n" + render_list += "You can't feel anything where [target.p_their()] appendix would be.\n" appendix_okay = FALSE else if(appendix.damage > 10 && carbon_patient.stat == CONSCIOUS) - render_list += "[M] screams when you lift your hand from [M.p_their()] appendix!\n"//scream if their appendix is damaged and they're awake - M.emote("scream") + render_list += "[target] screams when you lift your hand from [target.p_their()] appendix!\n"//scream if their appendix is damaged and they're awake + target.emote("scream") appendix_okay = FALSE if(liver_okay && appendix_okay)//if they have all their organs and have no detectable damage @@ -310,7 +332,7 @@ else pulse_pressure = span_notice("strong")//they're okay :D - render_list += "[M.p_Their()] pulse is [pulse_pressure] and [heart_strength].\n" + render_list += "[target.p_Their()] pulse is [pulse_pressure] and [heart_strength].\n" //display our packaged information in an examine block for easy reading to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO) @@ -487,3 +509,23 @@ /obj/item/clothing/neck/beads/Initialize(mapload) . = ..() color = color = pick("#ff0077","#d400ff","#2600ff","#00ccff","#00ff2a","#e5ff00","#ffae00","#ff0000", "#ffffff") + +/obj/item/clothing/neck/wreath + name = "\improper Watcher Wreath" + desc = "An elaborate crown made from the twisted flesh and sinew of a watcher. \ + Wearing it makes you feel like you have eyes in the back of your head." + icon_state = "watcher_wreath" + worn_y_offset = 10 + alternate_worn_layer = ABOVE_BODY_FRONT_HEAD_LAYER + resistance_flags = FIRE_PROOF + +/obj/item/clothing/neck/wreath/worn_overlays(mutable_appearance/standing, isinhands, icon_file) + . = ..() + if(!isinhands) + . += emissive_appearance(icon_file, "wreath_emissive", src, alpha = src.alpha) + +/obj/item/clothing/neck/wreath/icewing + name = "\improper Icewing Wreath" + desc = "An elaborate crown made from the twisted flesh and sinew of an icewing watcher. \ + Wearing it sends shivers down your spine just from being near it." + icon_state = "icewing_wreath" diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm index 6d9646b49ee27..db20562039b23 100644 --- a/code/modules/clothing/outfits/ert.dm +++ b/code/modules/clothing/outfits/ert.dm @@ -388,7 +388,7 @@ ) head = /obj/item/clothing/head/utility/hardhat/welding mask = /obj/item/clothing/mask/gas/atmos - l_hand = /obj/item/areaeditor/blueprints + l_hand = /obj/item/blueprints /datum/outfit/centcom/ert/clown/party name = "ERP Comedian" diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index fcf0de64a5e47..4470a398168c5 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -12,6 +12,8 @@ armor_type = /datum/armor/clothing_shoes slowdown = SHOES_SLOWDOWN strip_delay = 1 SECONDS + article = "a pair of" + var/offset = 0 var/equipped_before_drop = FALSE ///Whether these shoes have laces that can be tied/untied @@ -172,8 +174,7 @@ adjust_laces(SHOES_UNTIED, user) else // if they're someone else's shoes, go knot-wards - var/mob/living/L = user - if(istype(L) && L.body_position == STANDING_UP) + if(istype(living_user) && living_user.body_position == STANDING_UP) to_chat(user, span_warning("You must be on the floor to interact with [src]!")) return if(tied == SHOES_KNOTTED) @@ -188,7 +189,7 @@ if(HAS_TRAIT(user, TRAIT_CLUMSY)) // based clowns trained their whole lives for this mod_time *= 0.75 - if(do_after(user, mod_time, target = our_guy, extra_checks = CALLBACK(src, PROC_REF(still_shoed), our_guy))) + if(do_after(user, mod_time, target = our_guy, extra_checks = CALLBACK(src, PROC_REF(still_shoed), our_guy), hidden = TRUE)) to_chat(user, span_notice("You [tied ? "untie" : "knot"] the laces on [loc]'s [src.name].")) if(tied == SHOES_UNTIED) adjust_laces(SHOES_KNOTTED, user) @@ -198,12 +199,12 @@ user.visible_message(span_danger("[our_guy] stamps on [user]'s hand, mid-shoelace [tied ? "knotting" : "untying"]!"), span_userdanger("Ow! [our_guy] stamps on your hand!"), list(our_guy)) to_chat(our_guy, span_userdanger("You stamp on [user]'s hand! What the- [user.p_they()] [user.p_were()] [tied ? "knotting" : "untying"] your shoelaces!")) user.emote("scream") - if(istype(L)) - var/obj/item/bodypart/ouchie = L.get_bodypart(pick(GLOB.arm_zones)) + if(istype(living_user)) + var/obj/item/bodypart/ouchie = living_user.get_bodypart(pick(GLOB.arm_zones)) if(ouchie) ouchie.receive_damage(brute = 10) - L.adjustStaminaLoss(40) - L.Paralyze(10) + living_user.adjustStaminaLoss(40) + living_user.Paralyze(10) ///checking to make sure we're still on the person we're supposed to be, for lacing do_after's /obj/item/clothing/shoes/proc/still_shoed(mob/living/carbon/our_guy) diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm index a033a561439ff..73c5a9d0d958c 100644 --- a/code/modules/clothing/shoes/cowboy.dm +++ b/code/modules/clothing/shoes/cowboy.dm @@ -4,8 +4,8 @@ icon_state = "cowboy_brown" armor_type = /datum/armor/shoes_cowboy custom_price = PAYCHECK_CREW - var/max_occupants = 4 can_be_tied = FALSE + var/max_occupants = 4 /// Do these boots have spur sounds? var/has_spurs = FALSE /// The jingle jangle jingle of our spurs @@ -64,7 +64,7 @@ to_chat(user, span_notice("[target] slithers into [src].")) /obj/item/clothing/shoes/cowboy/container_resist_act(mob/living/user) - if(!do_after(user, 10, target = user)) + if(!do_after(user, 1 SECONDS, target = user)) return user.forceMove(drop_location()) diff --git a/code/modules/clothing/shoes/gunboots.dm b/code/modules/clothing/shoes/gunboots.dm index d8335b5fcb0ed..de74703d449ed 100644 --- a/code/modules/clothing/shoes/gunboots.dm +++ b/code/modules/clothing/shoes/gunboots.dm @@ -59,7 +59,7 @@ shot.original = target shot.fired_from = src shot.firer = wearer // don't hit ourself that would be really annoying - shot.impacted = list(wearer = TRUE) + shot.impacted = list(WEAKREF(wearer) = TRUE) shot.def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) // they're fired from boots after all shot.preparePixelProjectile(target, wearer) if(!shot.suppressed) diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index b145516fdd905..bb8ee57b15cf4 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -1,5 +1,5 @@ /// Charge per tick consumed by the thermal regulator -#define THERMAL_REGULATOR_COST (18 KILO JOULES) +#define THERMAL_REGULATOR_COST (0.018 * STANDARD_CELL_CHARGE) //Note: Everything in modules/clothing/spacesuits should have the entire suit grouped together. // Meaning the the suit is defined directly after the corrisponding helmet. Just like below! @@ -58,11 +58,17 @@ equip_delay_other = 80 resistance_flags = NONE actions_types = list(/datum/action/item_action/toggle_spacesuit) - var/temperature_setting = BODYTEMP_NORMAL /// The default temperature setting - var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell/high /// If this is a path, this gets created as an object in Initialize. - var/cell_cover_open = FALSE /// Status of the cell cover on the suit - var/thermal_on = FALSE /// Status of the thermal regulator - var/show_hud = TRUE /// If this is FALSE the batery status UI will be disabled. This is used for suits that don't use bateries like the changeling's flesh suit mutation. + interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING + /// The default temperature setting + var/temperature_setting = BODYTEMP_NORMAL + /// If this is a path, this gets created as an object in Initialize. + var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell/high + /// Status of the cell cover on the suit + var/cell_cover_open = FALSE + /// Status of the thermal regulator + var/thermal_on = FALSE + /// If this is FALSE the batery status UI will be disabled. This is used for suits that don't use bateries like the changeling's flesh suit mutation. + var/show_hud = TRUE /datum/armor/suit_space bio = 100 @@ -190,10 +196,9 @@ return /// Open the cell cover when ALT+Click on the suit -/obj/item/clothing/suit/space/AltClick(mob/living/user) - if(!user.can_perform_action(src, NEED_DEXTERITY)) - return ..() +/obj/item/clothing/suit/space/click_alt(mob/living/user) toggle_spacesuit_cell(user) + return CLICK_ACTION_SUCCESS /// Remove the cell whent he cover is open on CTRL+Click /obj/item/clothing/suit/space/CtrlClick(mob/living/user) diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index 5bdec24b96739..bd20874f88d65 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -87,27 +87,26 @@ else . += span_notice("There's nothing placed on the helmet.") -/obj/item/clothing/head/helmet/space/plasmaman/AltClick(mob/user) +/obj/item/clothing/head/helmet/space/plasmaman/click_alt(mob/user) if(user.can_perform_action(src)) - toggle_welding_screen(user) + adjust_visor(user) /obj/item/clothing/head/helmet/space/plasmaman/ui_action_click(mob/user, action) if(istype(action, /datum/action/item_action/toggle_welding_screen)) - toggle_welding_screen(user) + adjust_visor(user) return return ..() -/obj/item/clothing/head/helmet/space/plasmaman/proc/toggle_welding_screen(mob/living/user) - if(weldingvisortoggle(user)) - if(helmet_on) - to_chat(user, span_notice("Your helmet's torch can't pass through your welding visor!")) - helmet_on = FALSE - playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing - update_appearance() - else - playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing - update_appearance() +/obj/item/clothing/head/helmet/space/plasmaman/adjust_visor(mob/living/user) + . = ..() + if(!.) + return + if(helmet_on) + to_chat(user, span_notice("Your helmet's torch can't pass through your welding visor!")) + helmet_on = FALSE + playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing + update_appearance() /obj/item/clothing/head/helmet/space/plasmaman/update_icon_state() . = ..() @@ -116,7 +115,8 @@ /obj/item/clothing/head/helmet/space/plasmaman/update_overlays() . = ..() - . += visor_icon + if(!up) + . += visor_icon /obj/item/clothing/head/helmet/space/plasmaman/attackby(obj/item/hitting_item, mob/living/user) . = ..() @@ -124,7 +124,7 @@ if(smile == FALSE) var/obj/item/toy/crayon/CR = hitting_item to_chat(user, span_notice("You start drawing a smiley face on the helmet's visor..")) - if(do_after(user, 25, target = src)) + if(do_after(user, 2.5 SECONDS, target = src)) smile = TRUE smile_color = CR.paint_color to_chat(user, "You draw a smiley on the helmet visor.") diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 47bd32280ed89..b12a220c2f07b 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -312,6 +312,40 @@ acid = 50 wound = 10 +/obj/item/clothing/suit/armor/balloon_vest + name = "balloon vest" + desc = "A vest made entirely from balloons, resistant to any evil forces a mime could throw at you, including electricity and fire. Just a strike with something sharp, though..." + icon_state = "balloon-vest" + inhand_icon_state = "balloon_armor" + blood_overlay_type = "armor" + armor_type = /datum/armor/balloon_vest + siemens_coefficient = 0 + strip_delay = 70 + equip_delay_other = 50 + +/datum/armor/balloon_vest + melee = 10 + laser = 10 + energy = 10 + fire = 60 + acid = 50 + +/obj/item/clothing/suit/armor/balloon_vest/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) + if(isitem(hitby)) + var/obj/item/item_hit = hitby + if(item_hit.sharpness) + pop() + + if(istype(hitby, /obj/projectile/bullet)) + pop() + + return ..() + +/obj/item/clothing/suit/armor/balloon_vest/proc/pop() + playsound(src, 'sound/effects/cartoon_pop.ogg', 50, vary = TRUE) + qdel(src) + + /obj/item/clothing/suit/armor/bulletproof name = "bulletproof armor" desc = "A Type III heavy bulletproof vest that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent." @@ -507,6 +541,16 @@ material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS//Can change color and add prefix armor_type = /datum/armor/knight_greyscale +/datum/armor/knight_greyscale + melee = 35 + bullet = 10 + laser = 10 + energy = 10 + bomb = 10 + bio = 10 + fire = 40 + acid = 40 + /obj/item/clothing/suit/armor/vest/durathread name = "durathread vest" desc = "A vest made of durathread with strips of leather acting as trauma plates." @@ -572,7 +616,7 @@ desc = "A superb armor made with the toughest and rarest materials available to man." icon_state = "h2armor" inhand_icon_state = null - material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS//Can change color and add prefix + material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix armor_type = /datum/armor/armor_elder_atmosian body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS @@ -644,3 +688,48 @@ fire = 40 acid = 50 wound = 30 + +/obj/item/clothing/suit/armor/vest/military + name = "Crude chestplate" + desc = "It may look rough, rusty and battered, but it's also made out of junk and uncomfortable to wear." + icon_state = "military" + inhand_icon_state = "armor" + dog_fashion = null + armor_type = /datum/armor/military + allowed = list( + /obj/item/banner, + /obj/item/claymore/shortsword, + /obj/item/nullrod, + /obj/item/spear, + /obj/item/gun/ballistic/bow + ) + +/datum/armor/military + melee = 45 + bullet = 25 + laser = 25 + energy = 25 + bomb = 25 + fire = 10 + acid = 50 + wound = 20 + +/obj/item/clothing/suit/armor/riot/knight/warlord + name = "golden plate armor" + desc = "This bulky set of armor is coated with a shiny layer of gold. It seems to almost reflect all light sources." + icon_state = "warlord" + inhand_icon_state = null + armor_type = /datum/armor/armor_warlord + w_class = WEIGHT_CLASS_BULKY + clothing_flags = THICKMATERIAL + slowdown = 0.8 + +/datum/armor/armor_warlord + melee = 70 + bullet = 60 + laser = 70 + energy = 70 + bomb = 40 + fire = 50 + acid = 50 + wound = 30 diff --git a/code/modules/clothing/suits/ghostsheet.dm b/code/modules/clothing/suits/ghostsheet.dm index 268cca461993f..9bd8753f50b41 100644 --- a/code/modules/clothing/suits/ghostsheet.dm +++ b/code/modules/clothing/suits/ghostsheet.dm @@ -19,9 +19,8 @@ /obj/item/clothing/suit/costume/ghost_sheet/worn_overlays(mutable_appearance/standing, isinhands, icon_file) . = ..() - if(check_holidays(HALLOWEEN)) - if(!isinhands) - . += emissive_appearance('icons/mob/simple/mob.dmi', "ghost", offset_spokesman = src, alpha = src.alpha) + if(!isinhands && check_holidays(HALLOWEEN)) + . += emissive_appearance('icons/mob/simple/mob.dmi', "ghost", offset_spokesman = src, alpha = src.alpha) /obj/item/clothing/suit/costume/ghost_sheet/spooky name = "spooky ghost" diff --git a/code/modules/clothing/suits/jacket.dm b/code/modules/clothing/suits/jacket.dm index 6db889032c064..9004f773e35ba 100644 --- a/code/modules/clothing/suits/jacket.dm +++ b/code/modules/clothing/suits/jacket.dm @@ -54,6 +54,16 @@ desc = "Aviators not included." icon_state = "bomberjacket" inhand_icon_state = "brownjsuit" + allowed = list( + /obj/item/flashlight, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/plasmaman, + /obj/item/toy, + /obj/item/storage/fancy/cigarettes, + /obj/item/lighter, + /obj/item/gun/ballistic/rifle/boltaction/pipegun, + /obj/item/radio, + ) /obj/item/clothing/suit/jacket/leather name = "leather jacket" @@ -62,7 +72,19 @@ inhand_icon_state = "hostrench" resistance_flags = NONE max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT - allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver, /obj/item/gun/ballistic/revolver/c38/detective, /obj/item/radio) + allowed = list( + /obj/item/flashlight, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/plasmaman, + /obj/item/toy, + /obj/item/storage/fancy/cigarettes, + /obj/item/lighter, + /obj/item/gun/ballistic/automatic/pistol, + /obj/item/gun/ballistic/revolver, + /obj/item/gun/ballistic/revolver/c38/detective, + /obj/item/gun/ballistic/rifle/boltaction/pipegun, + /obj/item/radio, + ) /obj/item/clothing/suit/jacket/leather/biker name = "biker jacket" @@ -96,7 +118,19 @@ desc = "A canvas jacket styled after classical American military garb. Feels sturdy, yet comfortable." icon_state = "militaryjacket" inhand_icon_state = null - allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver, /obj/item/radio) + allowed = list( + /obj/item/flashlight, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/plasmaman, + /obj/item/toy, + /obj/item/storage/fancy/cigarettes, + /obj/item/lighter, + /obj/item/gun/ballistic/automatic/pistol, + /obj/item/gun/ballistic/revolver, + /obj/item/gun/ballistic/revolver/c38/detective, + /obj/item/gun/ballistic/rifle/boltaction/pipegun, + /obj/item/radio, + ) /obj/item/clothing/suit/jacket/letterman name = "letterman jacket" @@ -118,6 +152,19 @@ icon_state = "letterman_s" inhand_icon_state = null species_exception = list(/datum/species/golem) + allowed = list( + /obj/item/flashlight, + /obj/item/tank/internals/emergency_oxygen, + /obj/item/tank/internals/plasmaman, + /obj/item/toy, + /obj/item/storage/fancy/cigarettes, + /obj/item/lighter, + /obj/item/gun/ballistic/automatic/pistol, + /obj/item/gun/ballistic/revolver, + /obj/item/gun/ballistic/revolver/c38/detective, + /obj/item/gun/ballistic/rifle/boltaction/pipegun, + /obj/item/radio, + ) /obj/item/clothing/suit/jacket/letterman_nanotrasen name = "blue letterman jacket" diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index f73fb78c2886d..fe6fce092a40c 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -179,7 +179,7 @@ /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/t_scanner, - /obj/item/gun/ballistic/rifle/boltaction/pipegun/prime, + /obj/item/gun/ballistic/rifle/boltaction/pipegun, ) resistance_flags = NONE species_exception = list(/datum/species/golem) @@ -425,6 +425,7 @@ /obj/item/t_scanner, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, + /obj/item/extinguisher, ) /datum/armor/atmos_overalls diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm index 9a3d94e1dbf4b..f48e49c11b701 100644 --- a/code/modules/clothing/suits/labcoat.dm +++ b/code/modules/clothing/suits/labcoat.dm @@ -106,6 +106,9 @@ allowed += list( /obj/item/autopsy_scanner, /obj/item/scythe, + /obj/item/shovel, + /obj/item/shovel/serrated, + /obj/item/trench_tool, ) /obj/item/clothing/suit/toggle/labcoat/science diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index c867349f6564a..c04b68ab553a8 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -99,6 +99,11 @@ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF resistance_flags = NONE +/obj/item/clothing/head/utility/bomb_hood/Initialize(mapload) + . = ..() + if(flags_inv & HIDEFACE) + AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) + /datum/armor/utility_bomb_hood melee = 20 laser = 20 @@ -169,6 +174,11 @@ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF resistance_flags = NONE +/obj/item/clothing/head/utility/radiation/Initialize(mapload) + . = ..() + if(flags_inv & HIDEFACE) + AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) + /datum/armor/utility_radiation bio = 60 fire = 30 diff --git a/code/modules/clothing/suits/wetfloor.dm b/code/modules/clothing/suits/wetfloor.dm index 390a529710aef..17bef117ca644 100644 --- a/code/modules/clothing/suits/wetfloor.dm +++ b/code/modules/clothing/suits/wetfloor.dm @@ -19,7 +19,7 @@ allowed = list( /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, - /obj/item/gun/ballistic/rifle/boltaction/pipegun/prime, + /obj/item/gun/ballistic/rifle/boltaction/pipegun, ) /datum/armor/suit_caution diff --git a/code/modules/clothing/suits/wintercoats.dm b/code/modules/clothing/suits/wintercoats.dm index a5a1fef7903bc..05b9c612a7ba3 100644 --- a/code/modules/clothing/suits/wintercoats.dm +++ b/code/modules/clothing/suits/wintercoats.dm @@ -47,12 +47,7 @@ . += span_notice("Alt-click to [zipped ? "un" : ""]zip.") -/obj/item/clothing/suit/hooded/wintercoat/AltClick(mob/user) - . = ..() - - if (. == FALSE) // Direct check for FALSE, because that's the specific case we want to propagate, not just null. - return FALSE - +/obj/item/clothing/suit/hooded/wintercoat/click_alt(mob/user) zipped = !zipped worn_icon_state = "[initial(icon_state)][zipped ? "_t" : ""]" balloon_alert(user, "[zipped ? "" : "un"]zipped") @@ -60,6 +55,7 @@ if(ishuman(loc)) var/mob/living/carbon/human/wearer = loc wearer.update_worn_oversuit() + return CLICK_ACTION_SUCCESS /obj/item/clothing/head/hooded/winterhood name = "winter hood" @@ -388,6 +384,9 @@ allowed += list( /obj/item/autopsy_scanner, /obj/item/scythe, + /obj/item/shovel, + /obj/item/shovel/serrated, + /obj/item/trench_tool, ) /obj/item/clothing/head/hooded/winterhood/medical/coroner @@ -633,6 +632,8 @@ /obj/item/storage/bag/ore, /obj/item/t_scanner/adv_mining_scanner, /obj/item/tank/internals, + /obj/item/shovel, + /obj/item/trench_tool, ) armor_type = /datum/armor/wintercoat_miner hoodtype = /obj/item/clothing/head/hooded/winterhood/miner diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 20a117e112e48..8b80a28dd4af1 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -11,6 +11,7 @@ drop_sound = 'sound/items/handling/cloth_drop.ogg' pickup_sound = 'sound/items/handling/cloth_pickup.ogg' limb_integrity = 30 + interaction_flags_click = ALLOW_RESTING /// Has this undersuit been freshly laundered and, as such, imparts a mood bonus for wearing var/freshly_laundered = FALSE @@ -52,32 +53,43 @@ //make the sensor mode favor higher levels, except coords. sensor_mode = pick(SENSOR_VITALS, SENSOR_VITALS, SENSOR_VITALS, SENSOR_LIVING, SENSOR_LIVING, SENSOR_COORDS, SENSOR_COORDS, SENSOR_OFF) register_context() - AddElement(/datum/element/update_icon_updates_onmob, flags = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING, body = TRUE) + AddElement(/datum/element/update_icon_updates_onmob, flags = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING|ITEM_SLOT_NECK, body = TRUE) + +/obj/item/clothing/under/setup_reskinning() + if(!check_setup_reskinning()) + return + + // We already register context in Initialize. + RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin)) /obj/item/clothing/under/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) - . = NONE + . = ..() + + var/changed = FALSE if(isnull(held_item) && has_sensor == HAS_SENSORS) context[SCREENTIP_CONTEXT_RMB] = "Toggle suit sensors" - . = CONTEXTUAL_SCREENTIP_SET + context[SCREENTIP_CONTEXT_CTRL_LMB] = "Set suit sensors to tracking" + changed = TRUE if(istype(held_item, /obj/item/clothing/accessory) && length(attached_accessories) < max_number_of_accessories) context[SCREENTIP_CONTEXT_LMB] = "Attach accessory" - . = CONTEXTUAL_SCREENTIP_SET + changed = TRUE if(LAZYLEN(attached_accessories)) context[SCREENTIP_CONTEXT_ALT_RMB] = "Remove accessory" - . = CONTEXTUAL_SCREENTIP_SET + changed = TRUE if(istype(held_item, /obj/item/stack/cable_coil) && has_sensor == BROKEN_SENSORS) context[SCREENTIP_CONTEXT_LMB] = "Repair suit sensors" - . = CONTEXTUAL_SCREENTIP_SET + changed = TRUE if(can_adjust && adjusted != DIGITIGRADE_STYLE) context[SCREENTIP_CONTEXT_ALT_LMB] = "Wear [adjusted == ALT_STYLE ? "normally" : "casually"]" - . = CONTEXTUAL_SCREENTIP_SET + changed = TRUE + + return changed ? CONTEXTUAL_SCREENTIP_SET : . - return . /obj/item/clothing/under/worn_overlays(mutable_appearance/standing, isinhands = FALSE) . = ..() @@ -326,6 +338,16 @@ if(H.w_uniform == src) H.update_suit_sensors() +/obj/item/clothing/under/CtrlClick(mob/user) + . = ..() + if(!.) + return + if(!can_toggle_sensors(user)) + return + + sensor_mode = SENSOR_COORDS + balloon_alert(user, "set to tracking") + /// Checks if the toggler is allowed to toggle suit sensors currently /obj/item/clothing/under/proc/can_toggle_sensors(mob/toggler) if(!can_use(toggler) || toggler.stat == DEAD) //make sure they didn't hold the window open. @@ -347,17 +369,14 @@ return TRUE -/obj/item/clothing/under/AltClick(mob/user) - . = ..() - if(.) - return - +/obj/item/clothing/under/click_alt(mob/user) if(!can_adjust) balloon_alert(user, "can't be adjusted!") - return + return CLICK_ACTION_BLOCKING if(!can_use(user)) - return + return NONE rolldown() + return CLICK_ACTION_SUCCESS /obj/item/clothing/under/alt_click_secondary(mob/user) . = ..() diff --git a/code/modules/clothing/under/accessories/_accessories.dm b/code/modules/clothing/under/accessories/_accessories.dm index 67c2768ad237d..91854bc386bf0 100644 --- a/code/modules/clothing/under/accessories/_accessories.dm +++ b/code/modules/clothing/under/accessories/_accessories.dm @@ -30,6 +30,13 @@ . = ..() register_context() +/obj/item/clothing/accessory/setup_reskinning() + if(!check_setup_reskinning()) + return + + // We already register context regardless in Initialize. + RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin)) + /** * Can we be attached to the passed clothing article? */ @@ -158,11 +165,12 @@ SIGNAL_HANDLER accessory_dropped(source, user) - user.update_clothing(ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING) + user.update_clothing(ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING|ITEM_SLOT_NECK) /// Called when the uniform this accessory is pinned to is equipped in a valid slot /obj/item/clothing/accessory/proc/accessory_equipped(obj/item/clothing/under/clothes, mob/living/user) equipped(user, user.get_slot_by_item(clothes)) // so we get any actions, item_flags get set, etc + user.update_clothing(ITEM_SLOT_OCLOTHING|ITEM_SLOT_NECK) return /// Called when the uniform this accessory is pinned to is dropped @@ -203,8 +211,9 @@ . += "It can be worn above or below your suit. Right-click to toggle." /obj/item/clothing/accessory/add_context(atom/source, list/context, obj/item/held_item, mob/user) - if(!isnull(held_item)) - return NONE + . = ..() + if(held_item != source) + return . context[SCREENTIP_CONTEXT_RMB] = "Wear [above_suit ? "below" : "above"] suit" return CONTEXTUAL_SCREENTIP_SET diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm index ffb2b0431ec57..bbafb4a132b1b 100644 --- a/code/modules/clothing/under/accessories/badges.dm +++ b/code/modules/clothing/under/accessories/badges.dm @@ -172,7 +172,7 @@ display = span_notice("The dogtag is all scratched up.") /obj/item/clothing/accessory/dogtag/borg_ready - name = "Pre-Approved Cyborg Cantidate dogtag" + name = "Pre-Approved Cyborg Candidate dogtag" display = "This employee has been screened for negative mental traits to an acceptable level of accuracy, and is approved for the NT Cyborg program as an alternative to medical resuscitation." /// Reskins for the pride pin accessory, mapped by display name to icon state @@ -193,9 +193,13 @@ GLOBAL_LIST_INIT(pride_pin_reskins, list( icon_state = "pride" obj_flags = UNIQUE_RENAME | INFINITE_RESKIN -/obj/item/clothing/accessory/pride/Initialize(mapload) - . = ..() +/obj/item/clothing/accessory/pride/setup_reskinning() unique_reskin = GLOB.pride_pin_reskins + if(!check_setup_reskinning()) + return + + // We already register context regardless in Initialize. + RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(on_click_alt_reskin)) /obj/item/clothing/accessory/deaf_pin name = "deaf personnel pin" diff --git a/code/modules/clothing/under/costume.dm b/code/modules/clothing/under/costume.dm index e2ecb135720f3..080d1afe70ad5 100644 --- a/code/modules/clothing/under/costume.dm +++ b/code/modules/clothing/under/costume.dm @@ -239,6 +239,7 @@ "Black" = "black_mech_suit", ) + /obj/item/clothing/under/costume/russian_officer name = "\improper Russian officer's uniform" desc = "The latest in fashionable russian outfits." @@ -427,3 +428,17 @@ body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS|HEAD flags_inv = HIDEGLOVES|HIDESHOES|HIDEEARS|HIDEEYES|HIDEHAIR +/obj/item/clothing/under/costume/gamberson + name = "re-enactor's Gamberson" + desc = "A colorful set of clothes made to look like a medieval gamberson." + icon_state = "gamberson" + inhand_icon_state = null + female_sprite_flags = NO_FEMALE_UNIFORM + can_adjust = FALSE + +/obj/item/clothing/under/costume/gamberson/military + name = "swordsman's Gamberson" + desc = "A padded medieval gamberson. Has enough woolen layers to dull a strike from any small weapon." + armor_type = /datum/armor/clothing_under/rank_security + has_sensor = NO_SENSORS + diff --git a/code/modules/clothing/under/suits.dm b/code/modules/clothing/under/suits.dm index 02f047c2f4894..0dbf1880d7d2f 100644 --- a/code/modules/clothing/under/suits.dm +++ b/code/modules/clothing/under/suits.dm @@ -84,7 +84,6 @@ desc = "It's a very smart uniform with a special pocket for tip." icon_state = "waiter" inhand_icon_state = "waiter" - supports_variations_flags = CLOTHING_MONKEY_VARIATION /obj/item/clothing/under/suit/black_really name = "executive suit" diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm index 3a27ee6c1ebb2..ff3061d3e5992 100644 --- a/code/modules/clothing/under/syndicate.dm +++ b/code/modules/clothing/under/syndicate.dm @@ -8,7 +8,6 @@ alt_covers_chest = TRUE icon = 'icons/obj/clothing/under/syndicate.dmi' worn_icon = 'icons/mob/clothing/under/syndicate.dmi' - supports_variations_flags = CLOTHING_MONKEY_VARIATION /datum/armor/clothing_under/syndicate melee = 10 diff --git a/code/modules/deathmatch/deathmatch_loadouts.dm b/code/modules/deathmatch/deathmatch_loadouts.dm index 341b85fb92680..ae5f22975a031 100644 --- a/code/modules/deathmatch/deathmatch_loadouts.dm +++ b/code/modules/deathmatch/deathmatch_loadouts.dm @@ -21,6 +21,9 @@ user.set_species(/datum/species/human) for(var/datum/action/act as anything in granted_spells) var/datum/action/new_ability = new act(user) + if(istype(new_ability, /datum/action/cooldown/spell)) + var/datum/action/cooldown/spell/new_spell = new_ability + new_spell.spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC new_ability.Grant(user) /datum/outfit/deathmatch_loadout/naked @@ -173,6 +176,7 @@ name = "Deathmatch: Druid" display_name = "Druid" desc = "How can plants help you?" + species_override = /datum/species/pod l_hand = /obj/item/gun/ballistic/bow r_hand = /obj/item/ammo_casing/arrow @@ -240,7 +244,6 @@ l_pocket = /obj/item/reagent_containers/hypospray/combat r_pocket = /obj/item/reagent_containers/hypospray/medipen/penthrite l_hand = /obj/item/chainsaw - backpack_contents = list( /obj/item/storage/medkit/tactical, /obj/item/reagent_containers/hypospray/medipen/stimulants, @@ -274,7 +277,6 @@ l_pocket = /obj/item/melee/energy/sword/bananium r_pocket = /obj/item/shield/energy/bananium gloves = /obj/item/clothing/gloves/tackler/rocket - backpack_contents = list( /obj/item/reagent_containers/spray/waterflower = 1, /obj/item/instrument/bikehorn = 1, @@ -377,3 +379,167 @@ shoes = /obj/item/clothing/shoes/cowboy belt = /obj/item/storage/belt/holster/detective/full head = /obj/item/clothing/head/cowboy/brown + +/// wizards + +/datum/outfit/deathmatch_loadout/wizard + name = "Deathmatch: Wizard" + display_name = "Wizard" + desc = "It's wizard time, motherfucker! FIREBALL!!" + + l_hand = /obj/item/staff + uniform = /datum/outfit/wizard::uniform + suit = /datum/outfit/wizard::suit + head = /datum/outfit/wizard::head + shoes = /datum/outfit/wizard::shoes + granted_spells = list( + /datum/action/cooldown/spell/aoe/magic_missile, + /datum/action/cooldown/spell/forcewall, + /datum/action/cooldown/spell/jaunt/ethereal_jaunt, + ) + +/datum/outfit/deathmatch_loadout/wizard/pyro + name = "Deathmatch: Pyromancer" + display_name = "Pyromancer" + desc = "Burninating the station-side! Burninating all the wizards!" + + suit = /obj/item/clothing/suit/wizrobe/red + head = /obj/item/clothing/head/wizard/red + mask = /obj/item/clothing/mask/cigarette + granted_spells = list( + /datum/action/cooldown/spell/pointed/projectile/fireball, + /datum/action/cooldown/spell/smoke, + ) + +/datum/outfit/deathmatch_loadout/wizard/electro + name = "Deathmatch: Electromancer" + display_name = "Electromancer" + desc = "Batons are so last century." + + suit = /obj/item/clothing/suit/wizrobe/magusred + head = /obj/item/clothing/head/wizard/magus + granted_spells = list( + /datum/action/cooldown/spell/pointed/projectile/lightningbolt, + /datum/action/cooldown/spell/charged/beam/tesla, + ) + +/datum/outfit/deathmatch_loadout/wizard/necromancer + name = "Deathmatch: Necromancer" + display_name = "Necromancer" + desc = "I've got a BONE to pick- Yeah, sorry." + + species_override = /datum/species/skeleton + suit = /obj/item/clothing/suit/wizrobe/black + head = /obj/item/clothing/head/wizard/black + granted_spells = list( + /datum/action/cooldown/spell/touch/scream_for_me, + /datum/action/cooldown/spell/teleport/radius_turf/blink, + ) + +/datum/outfit/deathmatch_loadout/wizard/larp + name = "Deathmatch: LARPer" + display_name = "LARPer" + desc = "Lightning bolt! Lightning bolt! Lightning bolt!" + + l_hand = /obj/item/staff/stick + suit = /obj/item/clothing/suit/wizrobe/fake + head = /obj/item/clothing/head/wizard/fake + shoes = /obj/item/clothing/shoes/sandal + granted_spells = list( + /datum/action/cooldown/spell/conjure_item/spellpacket, + /datum/action/cooldown/spell/aoe/repulse/wizard, + ) + +/datum/outfit/deathmatch_loadout/wizard/chuuni + name = "Deathmatch: Chuuni" + display_name = "Chuunibyou" + desc = "Darkness blacker than black and darker than dark, I beseech thee..." + + l_hand = /obj/item/staff/broom + suit = /obj/item/clothing/suit/wizrobe/marisa + head = /obj/item/clothing/head/wizard/marisa + shoes = /obj/item/clothing/shoes/sneakers/marisa + granted_spells = list( + /datum/action/cooldown/spell/chuuni_invocations, + /datum/action/cooldown/spell/pointed/projectile/spell_cards, + ) + +/datum/outfit/deathmatch_loadout/wizard/battle + name = "Deathmatch: Battlemage" + display_name = "Battlemage" + desc = "Have you heard of the High Elves?" + + l_hand = /obj/item/mjollnir + suit = /obj/item/clothing/suit/wizrobe/magusblue + head = /obj/item/clothing/head/wizard/magus + granted_spells = list( + /datum/action/cooldown/spell/summonitem, + ) + +/datum/outfit/deathmatch_loadout/wizard/apprentice + name = "Deathmatch: Apprentice" + display_name = "Apprentice" + desc = "You feel severely under-leveled for this encounter..." + + l_hand = null + granted_spells = list( + /datum/action/cooldown/spell/charge, + ) + +/datum/outfit/deathmatch_loadout/wizard/gunmancer + name = "Deathmatch: Gunmancer" + display_name = "Gunmancer" + desc = "Magic is lame." + + l_hand = /obj/item/gun/ballistic/automatic/pistol/m1911 + suit = /obj/item/clothing/suit/wizrobe/tape + head = /obj/item/clothing/head/wizard/tape + shoes = /obj/item/clothing/shoes/jackboots + granted_spells = list( + /datum/action/cooldown/spell/conjure_item/infinite_guns/gun, + /datum/action/cooldown/spell/aoe/knock, + ) + +/datum/outfit/deathmatch_loadout/wizard/chaos + name = "Deathmatch: Chaos" + display_name = "Chaosmancer" + desc = "Hardcore Random Body ONLY!" + + l_hand = /obj/item/gun/magic/staff/chaos + uniform = /obj/item/clothing/under/color/rainbow + suit = /obj/item/clothing/suit/costume/hawaiian + head = /obj/item/clothing/head/wizard/red + shoes = /obj/item/clothing/shoes/sneakers/marisa + granted_spells = list( + /datum/action/cooldown/spell/rod_form, + /datum/action/cooldown/spell/conjure/the_traps, + ) + +/datum/outfit/deathmatch_loadout/wizard/clown + name = "Deathmatch: Clown" + display_name = "Funnymancer" + desc = "Honk NATH!" + + l_hand = /obj/item/gun/magic/staff/honk + uniform = /obj/item/clothing/under/rank/civilian/clown + suit = /obj/item/clothing/suit/chaplainsuit/clownpriest + head = /obj/item/clothing/head/chaplain/clownmitre + mask = /obj/item/clothing/mask/gas/clown_hat + back = /obj/item/storage/backpack/clown + shoes = /obj/item/clothing/shoes/clown_shoes + granted_spells = null + +/datum/outfit/deathmatch_loadout/wizard/monkey + name = "Deathmatch: Monkey" + display_name = "Monkeymancer" + desc = "Ook eek aaa ooo eee!" + + species_override = /datum/species/monkey + l_hand = /obj/item/food/grown/banana + uniform = null + suit = null + head = /obj/item/clothing/head/wizard + shoes = null + granted_spells = list( + /datum/action/cooldown/spell/conjure/simian, + ) diff --git a/code/modules/deathmatch/deathmatch_lobby.dm b/code/modules/deathmatch/deathmatch_lobby.dm index 5dfdba213ca55..1f4678ba1685d 100644 --- a/code/modules/deathmatch/deathmatch_lobby.dm +++ b/code/modules/deathmatch/deathmatch_lobby.dm @@ -47,6 +47,7 @@ clear_reservation() players = null observers = null + map?.template_in_use = FALSE //just incase map = null location = null loadouts = null @@ -55,13 +56,18 @@ /datum/deathmatch_lobby/proc/start_game() if (playing) return + if(map.template_in_use) + to_chat(get_mob_by_ckey(host), span_warning("This map is currently loading for another lobby. Please wait until that other map finishes loading. It would be a disaster if these two mixed up.")) + return playing = DEATHMATCH_PRE_PLAYING + map.template_in_use = TRUE RegisterSignal(map, COMSIG_LAZY_TEMPLATE_LOADED, PROC_REF(find_spawns_and_start_delay)) location = map.lazy_load() if (!location) to_chat(get_mob_by_ckey(host), span_warning("Couldn't reserve/load a map location (all locations used?), try again later, or contact a coder.")) playing = FALSE + map.template_in_use = FALSE UnregisterSignal(map, COMSIG_LAZY_TEMPLATE_LOADED) return FALSE @@ -72,6 +78,7 @@ player_spawns += thing UnregisterSignal(source, COMSIG_LAZY_TEMPLATE_LOADED) + map.template_in_use = FALSE addtimer(CALLBACK(src, PROC_REF(start_game_after_delay)), 8 SECONDS) /datum/deathmatch_lobby/proc/start_game_after_delay() @@ -202,7 +209,7 @@ announce(span_reallybig("[player.real_name] HAS DIED.
    [players.len] REMAIN.")) - if(!gibbed && !QDELING(player)) // for some reason dusting or deleting in chasm storage messes up tgui bad + if(!gibbed && !QDELING(player)) if(!HAS_TRAIT(src, TRAIT_DEATHMATCH_EXPLOSIVE_IMPLANTS)) player.dust(TRUE, TRUE, TRUE) if (players.len <= 1) @@ -334,70 +341,54 @@ /datum/deathmatch_lobby/ui_data(mob/user) - . = list() + var/list/data = list() + var/is_player = !isnull(players[user.ckey]) var/is_host = (user.ckey == host) var/is_admin = check_rights_for(user.client, R_ADMIN) - .["self"] = user.ckey - .["host"] = is_host - .["admin"] = is_admin - .["playing"] = playing - .["loadouts"] = list("Randomize") + var/has_auth = is_host || is_admin + + data["active_mods"] = "No modifiers selected" + data["admin"] = is_admin + data["host"] = is_host + data["loadouts"] = list("Randomize") + for (var/datum/outfit/deathmatch_loadout/loadout as anything in loadouts) - .["loadouts"] += initial(loadout.display_name) - .["map"] = list() - .["map"]["name"] = map.name - .["map"]["desc"] = map.desc - .["map"]["time"] = map.automatic_gameend_time - .["map"]["min_players"] = map.min_players - .["map"]["max_players"] = map.max_players - - .["mod_menu_open"] = FALSE - if((is_host || is_admin) && mod_menu_open) - .["mod_menu_open"] = TRUE - for(var/modpath in GLOB.deathmatch_game.modifiers) - var/datum/deathmatch_modifier/mod = GLOB.deathmatch_game.modifiers[modpath] - .["modifiers"] += list(list( - "name" = mod.name, - "desc" = mod.description, - "modpath" = "[modpath]", - "selected" = (modpath in modifiers), - "selectable" = is_host && mod.selectable(src), - )) - .["active_mods"] = "No modifiers selected" + data["loadouts"] += loadout::display_name + + data["map"] = list() + data["map"]["name"] = map.name + data["map"]["desc"] = map.desc + data["map"]["time"] = map.automatic_gameend_time + data["map"]["min_players"] = map.min_players + data["map"]["max_players"] = map.max_players + + data["mod_menu_open"] = FALSE + data["modifiers"] = has_auth ? list() : get_modifier_list(is_host, mod_menu_open) + data["observers"] = get_observer_list() + data["players"] = get_player_list() + data["playing"] = playing + data["self"] = user.ckey + if(length(modifiers)) var/list/mod_names = list() for(var/datum/deathmatch_modifier/modpath as anything in modifiers) - mod_names += initial(modpath.name) - .["active_mods"] = "Selected modifiers: [english_list(mod_names)]" + mod_names += modpath::name + data["active_mods"] = "Selected modifiers: [english_list(mod_names)]" if(is_player && !isnull(players[user.ckey]["loadout"])) var/datum/outfit/deathmatch_loadout/loadout = players[user.ckey]["loadout"] - .["loadoutdesc"] = initial(loadout.desc) + data["loadoutdesc"] = loadout::desc else - .["loadoutdesc"] = "You are an observer! As an observer, you can hear lobby announcements." - .["players"] = list() - for (var/player_key in players) - var/list/player_info = players[player_key] - var/mob/player_mob = player_info["mob"] - if (isnull(player_mob) || !player_mob.client) - leave(player_key) - continue - .["players"][player_key] = player_info.Copy() - var/datum/outfit/deathmatch_loadout/dm_loadout = player_info["loadout"] - .["players"][player_key]["loadout"] = initial(dm_loadout.display_name) - .["observers"] = list() - for (var/observer_key in observers) - var/mob/observer = observers[observer_key]["mob"] - if (isnull(observer) || !observer.client) - leave(observer_key) - continue - .["observers"][observer_key] = observers[observer_key] + data["loadoutdesc"] = "You are an observer! As an observer, you can hear lobby announcements." + + return data /datum/deathmatch_lobby/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(. || !isobserver(usr)) return + switch(action) if ("start_game") if (usr.ckey != host) @@ -407,6 +398,7 @@ return FALSE start_game() return TRUE + if ("leave_game") if (playing) return FALSE @@ -414,6 +406,7 @@ ui.close() GLOB.deathmatch_game.ui_interact(usr) return TRUE + if ("change_loadout") if (playing) return FALSE @@ -428,6 +421,7 @@ players[params["player"]]["loadout"] = possible_loadout break return TRUE + if ("observe") if (playing) return FALSE @@ -439,16 +433,19 @@ remove_ckey_from_play(usr.ckey) add_player(usr, loadouts[1], host == usr.ckey) return TRUE + if ("ready") players[usr.ckey]["ready"] ^= 1 // Toggle. ready_count += (players[usr.ckey]["ready"] * 2) - 1 // scared? if (ready_count >= players.len && players.len >= map.min_players) start_game() return TRUE + if ("host") // Host functions if (playing || (usr.ckey != host && !check_rights(R_ADMIN))) return FALSE var/uckey = params["id"] + switch (params["func"]) if ("Kick") leave(uckey) @@ -477,12 +474,15 @@ return FALSE change_map(params["map"]) return TRUE + if("open_mod_menu") mod_menu_open = TRUE return TRUE + if("exit_mod_menu") mod_menu_open = FALSE return TRUE + if("toggle_modifier") var/datum/deathmatch_modifier/modpath = text2path(params["modpath"]) if(!ispath(modpath)) @@ -498,6 +498,7 @@ chosen_modifier.on_select(src) modifiers += modpath return TRUE + if ("admin") // Admin functions if (!check_rights(R_ADMIN)) message_admins("[usr.key] has attempted to use admin functions in a deathmatch lobby!") @@ -508,7 +509,73 @@ log_admin("[key_name(usr)] force started deathmatch lobby [host].") start_game() + return FALSE + + /datum/deathmatch_lobby/ui_close(mob/user) . = ..() if(user.ckey == host) mod_menu_open = FALSE + +/// Helper proc to get modifier data +/datum/deathmatch_lobby/proc/get_modifier_list(is_host, mod_menu_open) + var/list/modifier_list = list() + + if(!mod_menu_open) + return modifier_list + + for(var/modpath in GLOB.deathmatch_game.modifiers) + var/datum/deathmatch_modifier/mod = GLOB.deathmatch_game.modifiers[modpath] + + UNTYPED_LIST_ADD(modifier_list, list( + "name" = mod.name, + "desc" = mod.description, + "modpath" = "[modpath]", + "selected" = (modpath in modifiers), + "selectable" = is_host && mod.selectable(src), + )) + + return modifier_list + + +/// Helper proc for getting observer data +/datum/deathmatch_lobby/proc/get_observer_list() + var/list/observer_list = list() + + for (var/observer_key in observers) + var/list/observer_info = observers[observer_key] + var/mob/observer_mob = observer_info["mob"] + + if (isnull(observer_mob) || !observer_mob.client) + leave(observer_key) + continue + + var/list/observer = observer_info.Copy() + observer["key"] = observer_key + + UNTYPED_LIST_ADD(observer_list, observer) + + return observer_list + + +/// Helper proc for getting player data +/datum/deathmatch_lobby/proc/get_player_list() + var/list/player_list = list() + + for (var/player_key in players) + var/list/player_info = players[player_key] + var/mob/player_mob = player_info["mob"] + + if (isnull(player_mob) || !player_mob.client) + leave(player_key) + continue + + var/list/player = player_info.Copy() + + var/datum/outfit/deathmatch_loadout/dm_loadout = player_info["loadout"] + player["loadout"] = dm_loadout::display_name + player["key"] = player_key + + UNTYPED_LIST_ADD(player_list, player) + + return player_list diff --git a/code/modules/deathmatch/deathmatch_mapping.dm b/code/modules/deathmatch/deathmatch_mapping.dm index c3e10279363ea..5fa04d6c5fb22 100644 --- a/code/modules/deathmatch/deathmatch_mapping.dm +++ b/code/modules/deathmatch/deathmatch_mapping.dm @@ -10,3 +10,18 @@ /obj/effect/landmark/deathmatch_player_spawn name = "Deathmatch Player Spawner" + +/area/deathmatch/teleport //Prevent access to cross-z teleportation in the map itself (no wands of safety/teleportation scrolls). Cordons should prevent same-z teleportations outside of the arena. + area_flags = UNIQUE_AREA | ABDUCTOR_PROOF | EVENT_PROTECTED | QUIET_LOGS + +// for the illusion of a moving train +/turf/open/chasm/true/no_smooth/fake_motion_sand + name = "air" + desc = "Dont jump off, unless you want to fall a really long distance." + icon_state = "sandmoving" + base_icon_state = "sandmoving" + icon = 'icons/turf/floors.dmi' + +/turf/open/chasm/true/no_smooth/fake_motion_sand/fast + icon_state = "sandmovingfast" + base_icon_state = "sandmovingfast" diff --git a/code/modules/deathmatch/deathmatch_maps.dm b/code/modules/deathmatch/deathmatch_maps.dm index e594ab24fcba4..b2396915473c6 100644 --- a/code/modules/deathmatch/deathmatch_maps.dm +++ b/code/modules/deathmatch/deathmatch_maps.dm @@ -13,6 +13,9 @@ var/automatic_gameend_time = 8 MINUTES /// List of allowed loadouts for this map, otherwise defaults to all loadouts var/list/allowed_loadouts = list() + /// whether we are currently being loaded by a lobby + var/template_in_use = FALSE + /datum/lazy_template/deathmatch/ragecage name = "Ragecage" @@ -150,3 +153,37 @@ ) map_name = "backalley" key = "backalley" + +/datum/lazy_template/deathmatch/raginmages + name = "Ragin' Mages" + desc = "Greetings! We're the wizards of the wizard federation!" + max_players = 8 + automatic_gameend_time = 4 MINUTES // ill be surprised if this lasts more than two minutes + allowed_loadouts = list( + /datum/outfit/deathmatch_loadout/wizard, + /datum/outfit/deathmatch_loadout/wizard/pyro, + /datum/outfit/deathmatch_loadout/wizard/electro, + /datum/outfit/deathmatch_loadout/wizard/necromancer, + /datum/outfit/deathmatch_loadout/wizard/larp, + /datum/outfit/deathmatch_loadout/wizard/chuuni, + /datum/outfit/deathmatch_loadout/wizard/battle, + /datum/outfit/deathmatch_loadout/wizard/apprentice, + /datum/outfit/deathmatch_loadout/wizard/gunmancer, + /datum/outfit/deathmatch_loadout/wizard/monkey, + /datum/outfit/deathmatch_loadout/wizard/chaos, + /datum/outfit/deathmatch_loadout/wizard/clown, + ) + map_name = "ragin_mages" + key = "ragin_mages" + +/datum/lazy_template/deathmatch/train + name = "Trainship Hijack" + desc = "Trouble stirs in Tizira..." + max_players = 8 + allowed_loadouts = list(/datum/outfit/deathmatch_loadout/battler/cowboy) + map_name = "train" + key = "train" + turf_reservation_type = /datum/turf_reservation/indestructible_plating + +/datum/turf_reservation/indestructible_plating + turf_type = /turf/open/indestructible/plating //a little hacky but i guess it has to be done diff --git a/code/modules/deathmatch/deathmatch_modifier.dm b/code/modules/deathmatch/deathmatch_modifier.dm index 5037b3c3ae36c..127700b734f1e 100644 --- a/code/modules/deathmatch/deathmatch_modifier.dm +++ b/code/modules/deathmatch/deathmatch_modifier.dm @@ -149,7 +149,7 @@ blacklisted_modifiers = list(/datum/deathmatch_modifier/no_gravity) /datum/deathmatch_modifier/snail_crawl/apply(mob/living/carbon/player, datum/deathmatch_lobby/lobby) - player.AddElement(/datum/element/snailcrawl) + player.AddElement(/datum/element/lube_walking, require_resting = TRUE) /datum/deathmatch_modifier/blinking_and_breathing name = "Manual Blinking/Breathing" diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/evidence.dm index e22235084f927..c10648e3315c6 100644 --- a/code/modules/detectivework/evidence.dm +++ b/code/modules/detectivework/evidence.dm @@ -22,7 +22,7 @@ /obj/item/evidencebag/Exited(atom/movable/gone, direction) . = ..() cut_overlays() - w_class = initial(w_class) + update_weight_class(initial(w_class)) icon_state = initial(icon_state) desc = initial(desc) @@ -78,7 +78,7 @@ desc = "An evidence bag containing [I]. [I.desc]" I.forceMove(src) - w_class = I.w_class + update_weight_class(I.w_class) return 1 /obj/item/evidencebag/attack_self(mob/user) @@ -88,7 +88,7 @@ span_hear("You hear someone rustle around in a plastic bag, and remove something.")) cut_overlays() //remove the overlays user.put_in_hands(I) - w_class = WEIGHT_CLASS_TINY + update_weight_class(WEIGHT_CLASS_TINY) icon_state = "evidenceobj" desc = "An empty evidence bag." diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index 6ce6b0e67a6a6..82c77839da75b 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -218,20 +218,20 @@ /proc/get_timestamp() return time2text(world.time + 432000, ":ss") -/obj/item/detective_scanner/AltClick(mob/living/user) - // Best way for checking if a player can use while not incapacitated, etc - if(!user.can_perform_action(src)) - return +/obj/item/detective_scanner/click_alt(mob/living/user) if(!LAZYLEN(log)) balloon_alert(user, "no logs!") - return + return CLICK_ACTION_BLOCKING if(scanner_busy) balloon_alert(user, "scanner busy!") - return + return CLICK_ACTION_BLOCKING balloon_alert(user, "deleting logs...") - if(do_after(user, 3 SECONDS, target = src)) - balloon_alert(user, "logs cleared") - log = list() + if(!do_after(user, 3 SECONDS, target = src)) + return CLICK_ACTION_BLOCKING + balloon_alert(user, "logs cleared") + log = list() + return CLICK_ACTION_SUCCESS + /obj/item/detective_scanner/examine(mob/user) . = ..() diff --git a/code/modules/economy/holopay.dm b/code/modules/economy/holopay.dm index 3f11d0962050c..15247d19d572f 100644 --- a/code/modules/economy/holopay.dm +++ b/code/modules/economy/holopay.dm @@ -65,9 +65,8 @@ if(BURN) playsound(loc, 'sound/weapons/egloves.ogg', 80, TRUE) -/obj/structure/holopay/deconstruct() +/obj/structure/holopay/atom_deconstruct(dissambled = TRUE) dissipate() - return ..() /obj/structure/holopay/Destroy() linked_card?.my_store = null diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm index 533628eedf46d..fa9b9ea0d5e6e 100644 --- a/code/modules/emoji/emoji_parse.dm +++ b/code/modules/emoji/emoji_parse.dm @@ -16,7 +16,7 @@ pos = search search = findtext(text, ":", pos + length(text[pos])) if(search) - emoji = lowertext(copytext(text, pos + length(text[pos]), search)) + emoji = LOWER_TEXT(copytext(text, pos + length(text[pos]), search)) var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat) var/tag = sheet.icon_tag("emoji-[emoji]") if(tag) @@ -46,9 +46,9 @@ pos = search search = findtext(text, ":", pos + length(text[pos])) if(search) - var/word = lowertext(copytext(text, pos + length(text[pos]), search)) + var/word = LOWER_TEXT(copytext(text, pos + length(text[pos]), search)) if(word in emojis) - final += lowertext(copytext(text, pos, search + length(text[search]))) + final += LOWER_TEXT(copytext(text, pos, search + length(text[search]))) pos = search + length(text[search]) continue break diff --git a/code/modules/escape_menu/home_page.dm b/code/modules/escape_menu/home_page.dm index 48e6147a33b7e..a05aaf351e0df 100644 --- a/code/modules/escape_menu/home_page.dm +++ b/code/modules/escape_menu/home_page.dm @@ -5,7 +5,7 @@ /* hud_owner = */ src, src, "Resume", - /* offset = */ 0, + /* offset = */ 1, CALLBACK(src, PROC_REF(home_resume)), ) ) @@ -16,7 +16,7 @@ /* hud_owner = */ null, src, "Settings", - /* offset = */ 1, + /* offset = */ 2, CALLBACK(src, PROC_REF(home_open_settings)), ) ) @@ -27,7 +27,7 @@ /* hud_owner = */ src, src, "Admin Help", - /* offset = */ 2, + /* offset = */ 3, ) ) @@ -37,7 +37,7 @@ /* hud_owner = */ src, src, "Leave Body", - /* offset = */ 3, + /* offset = */ 4, CALLBACK(src, PROC_REF(open_leave_body)), ) ) diff --git a/code/modules/events/ghost_role/abductor.dm b/code/modules/events/ghost_role/abductor.dm index dfa20885f0c29..7ad20cff1eb4e 100644 --- a/code/modules/events/ghost_role/abductor.dm +++ b/code/modules/events/ghost_role/abductor.dm @@ -16,7 +16,7 @@ /datum/round_event/ghost_role/abductor/spawn_role() var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ABDUCTOR, role = ROLE_ABDUCTOR, alert_pic = /obj/item/melee/baton/abductor, role_name_text = role_name, amount_to_pick = 2) - if(candidates.len < 2) + if(length(candidates) < 2) return NOT_ENOUGH_PLAYERS SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_ABDUCTOR_SHIPS) diff --git a/code/modules/events/ghost_role/alien_infestation.dm b/code/modules/events/ghost_role/alien_infestation.dm index 88e79fd7d60c3..1c0c938ce89fc 100644 --- a/code/modules/events/ghost_role/alien_infestation.dm +++ b/code/modules/events/ghost_role/alien_infestation.dm @@ -64,7 +64,7 @@ var/list/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_ALIEN, role = ROLE_ALIEN, alert_pic = /mob/living/carbon/alien/larva, role_name_text = role_name) - if(!candidates.len) + if(!length(candidates)) return NOT_ENOUGH_PLAYERS while(spawncount > 0 && vents.len && candidates.len) diff --git a/code/modules/events/ghost_role/sentience.dm b/code/modules/events/ghost_role/sentience.dm index 3aeebd298f43e..e60498a90d0ba 100644 --- a/code/modules/events/ghost_role/sentience.dm +++ b/code/modules/events/ghost_role/sentience.dm @@ -49,8 +49,9 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list( priority_announce(sentience_report,"[command_name()] Medium-Priority Update") /datum/round_event/ghost_role/sentience/spawn_role() - var/list/mob/dead/observer/candidates - candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, alert_pic = /obj/item/slimepotion/slime/sentience, role_name_text = role_name) + var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates(check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, alert_pic = /obj/item/slimepotion/slime/sentience, role_name_text = role_name) + if(!length(candidates)) + return NOT_ENOUGH_PLAYERS // find our chosen mob to breathe life into // Mobs have to be simple animals, mindless, on station, and NOT holograms. diff --git a/code/modules/events/ghost_role/slaughter_event.dm b/code/modules/events/ghost_role/slaughter_event.dm index 2ea86551b799c..f7af4c22d1ace 100644 --- a/code/modules/events/ghost_role/slaughter_event.dm +++ b/code/modules/events/ghost_role/slaughter_event.dm @@ -29,7 +29,6 @@ new /obj/effect/dummy/phased_mob(spawn_location, spawned) player_mind.transfer_to(spawned) - spawned.generate_antagonist_status() message_admins("[ADMIN_LOOKUPFLW(spawned)] has been made into a slaughter demon by an event.") spawned.log_message("was spawned as a slaughter demon by an event.", LOG_GAME) diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm index 20c4af94abdc3..eeed75d2299eb 100644 --- a/code/modules/events/holiday/xmas.dm +++ b/code/modules/events/holiday/xmas.dm @@ -70,23 +70,25 @@ /datum/round_event_control/santa name = "Visit by Santa" holidayID = CHRISTMAS - typepath = /datum/round_event/santa + typepath = /datum/round_event/ghost_role/santa weight = 20 max_occurrences = 1 earliest_start = 30 MINUTES category = EVENT_CATEGORY_HOLIDAY description = "Spawns santa, who shall roam the station, handing out gifts." -/datum/round_event/santa +/datum/round_event/ghost_role/santa + role_name = "Santa" var/mob/living/carbon/human/santa //who is our santa? -/datum/round_event/santa/announce(fake) +/datum/round_event/ghost_role/santa/announce(fake) priority_announce("Santa is coming to town!", "Unknown Transmission") -/datum/round_event/santa/start() +/datum/round_event/ghost_role/santa/start() var/mob/chosen_one = SSpolling.poll_ghost_candidates("Santa is coming to town! Do you want to be [span_notice("Santa")]?", poll_time = 15 SECONDS, alert_pic = /obj/item/clothing/head/costume/santa, role_name_text = "santa", amount_to_pick = 1) - if(chosen_one) - santa = new /mob/living/carbon/human(pick(GLOB.blobstart)) - santa.key = chosen_one.key - var/datum/antagonist/santa/A = new - santa.mind.add_antag_datum(A) + if(isnull(chosen_one)) + return NOT_ENOUGH_PLAYERS + santa = new /mob/living/carbon/human(pick(GLOB.blobstart)) + santa.key = chosen_one.key + var/datum/antagonist/santa/A = new + santa.mind.add_antag_datum(A) diff --git a/code/modules/events/immovable_rod/immovable_rod.dm b/code/modules/events/immovable_rod/immovable_rod.dm index a4cc4d4d6835a..e9d2995218d56 100644 --- a/code/modules/events/immovable_rod/immovable_rod.dm +++ b/code/modules/events/immovable_rod/immovable_rod.dm @@ -45,9 +45,9 @@ RegisterSignal(src, COMSIG_ATOM_ENTERING, PROC_REF(on_entering_atom)) if(special_target) - SSmove_manager.home_onto(src, special_target) + GLOB.move_manager.home_onto(src, special_target) else - SSmove_manager.move_towards(src, real_destination) + GLOB.move_manager.move_towards(src, real_destination) /obj/effect/immovablerod/Destroy(force) UnregisterSignal(src, COMSIG_ATOM_ENTERING) @@ -76,11 +76,6 @@ if(istype(ghost)) ghost.ManualFollow(src) -/obj/effect/immovablerod/proc/on_entered_over_movable(datum/source, atom/movable/atom_crossed_over) - SIGNAL_HANDLER - if((atom_crossed_over.density || isliving(atom_crossed_over)) && !QDELETED(atom_crossed_over)) - Bump(atom_crossed_over) - /obj/effect/immovablerod/proc/on_entering_atom(datum/source, atom/destination, atom/old_loc, list/atom/old_locs) SIGNAL_HANDLER if(destination.density && isturf(destination)) @@ -113,7 +108,7 @@ return visible_message(span_danger("[src] phases into reality.")) - SSmove_manager.home_onto(src, special_target) + GLOB.move_manager.home_onto(src, special_target) if(loc == target_turf) complete_trajectory() @@ -264,7 +259,7 @@ * Stops your rod's automated movement. Sit... Stay... Good rod! */ /obj/effect/immovablerod/proc/sit_stay_good_rod() - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) /** * Allows your rod to release restraint level zero and go for a walk. @@ -278,7 +273,7 @@ /obj/effect/immovablerod/proc/go_for_a_walk(walkies_location = null) if(walkies_location) special_target = walkies_location - SSmove_manager.home_onto(src, special_target) + GLOB.move_manager.home_onto(src, special_target) return complete_trajectory() @@ -294,7 +289,7 @@ */ /obj/effect/immovablerod/proc/walk_in_direction(direction) destination_turf = get_edge_target_turf(src, direction) - SSmove_manager.move_towards(src, destination_turf) + GLOB.move_manager.move_towards(src, destination_turf) /** * Rod will push the tram to a landmark if it hits the tram from the front/back diff --git a/code/modules/events/shuttle_insurance.dm b/code/modules/events/shuttle_insurance.dm index 4fce9c556b8b5..4442291a9ed9a 100644 --- a/code/modules/events/shuttle_insurance.dm +++ b/code/modules/events/shuttle_insurance.dm @@ -43,7 +43,7 @@ /datum/round_event/shuttle_insurance/start() insurance_message = new("Shuttle Insurance", "Hey, pal, this is the [ship_name]. Can't help but notice you're rocking a wild and crazy shuttle there with NO INSURANCE! Crazy. What if something happened to it, huh?! We've done a quick evaluation on your rates in this sector and we're offering [insurance_evaluation] to cover for your shuttle in case of any disaster.", list("Purchase Insurance.","Reject Offer.")) insurance_message.answer_callback = CALLBACK(src, PROC_REF(answered)) - SScommunications.send_message(insurance_message, unique = TRUE) + GLOB.communications_controller.send_message(insurance_message, unique = TRUE) /datum/round_event/shuttle_insurance/proc/answered() if(EMERGENCY_AT_LEAST_DOCKED) diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm index c6f52ab50cad2..fbd9b746d0303 100644 --- a/code/modules/events/vent_clog.dm +++ b/code/modules/events/vent_clog.dm @@ -177,9 +177,9 @@ to_chat(user, span_notice("You cannot pump [vent] if it's welded shut!")) return - to_chat(user, span_notice("You begin pumping [vent] with your plunger.")) + user.balloon_alert_to_viewers("plunging vent...", "plunging clogged vent...") if(do_after(user, 6 SECONDS, target = vent)) - to_chat(user, span_notice("You finish pumping [vent].")) + user.balloon_alert_to_viewers("finished plunging") clear_signals() kill() diff --git a/code/modules/events/wizard/curseditems.dm b/code/modules/events/wizard/curseditems.dm index cd7ab72cd8339..683b36304a367 100644 --- a/code/modules/events/wizard/curseditems.dm +++ b/code/modules/events/wizard/curseditems.dm @@ -32,30 +32,30 @@ VOICE_MODULATORS, WIZARD_MIMICRY, ) - var/list/loadout[SLOTS_AMT] + var/list/loadout = list() var/ruins_spaceworthiness = FALSE var/ruins_wizard_loadout = FALSE switch(item_set) if(BIG_FAT_DOOBIE) - loadout[ITEM_SLOT_MASK] = /obj/item/clothing/mask/cigarette/rollie/trippy + loadout += /obj/item/clothing/mask/cigarette/rollie/trippy ruins_spaceworthiness = TRUE if(BOXING) - loadout[ITEM_SLOT_MASK] = /obj/item/clothing/mask/luchador - loadout[ITEM_SLOT_GLOVES] = /obj/item/clothing/gloves/boxing + loadout += /obj/item/clothing/mask/luchador + loadout += /obj/item/clothing/gloves/boxing ruins_spaceworthiness = TRUE if(CATGIRLS_2015) - loadout[ITEM_SLOT_HEAD] = /obj/item/clothing/head/costume/kitty - ruins_spaceworthiness = TRUE - ruins_wizard_loadout = TRUE + loadout += /obj/item/clothing/head/costume/kitty + ruins_spaceworthiness += TRUE + ruins_wizard_loadout += TRUE if(CURSED_SWORDS) - loadout[ITEM_SLOT_HANDS] = /obj/item/katana/cursed + loadout += /obj/item/katana/cursed if(VOICE_MODULATORS) - loadout[ITEM_SLOT_MASK] = /obj/item/clothing/mask/chameleon + loadout += /obj/item/clothing/mask/chameleon if(WIZARD_MIMICRY) - loadout[ITEM_SLOT_OCLOTHING] = /obj/item/clothing/suit/wizrobe - loadout[ITEM_SLOT_FEET] = /obj/item/clothing/shoes/sandal/magic - loadout[ITEM_SLOT_HEAD] = /obj/item/clothing/head/wizard + loadout += /obj/item/clothing/suit/wizrobe + loadout += /obj/item/clothing/shoes/sandal/magic + loadout += /obj/item/clothing/head/wizard ruins_spaceworthiness = TRUE var/list/mob/living/carbon/human/victims = list() @@ -67,18 +67,18 @@ continue if(item_set == CATGIRLS_2015) //Wizard code means never having to say you're sorry target.gender = FEMALE - for(var/iterable in 1 to loadout.len) - if(!loadout[iterable]) - continue - - var/obj/item/item_type = loadout[iterable] - var/obj/item/thing = new item_type //dumb but required because of byond throwing a fit anytime new gets too close to a list + for(var/item_to_equip in loadout) + var/obj/item/new_item = new item_to_equip + var/slot_to_equip_to = ITEM_SLOT_HANDS + if(isclothing(new_item)) + var/obj/item/clothing/clothing_item = new_item + slot_to_equip_to = clothing_item.slot_flags - target.dropItemToGround(target.get_item_by_slot(iterable), TRUE) - target.equip_to_slot_or_del(thing, iterable, indirect_action = TRUE) - ADD_TRAIT(thing, TRAIT_NODROP, CURSED_ITEM_TRAIT(thing)) - thing.item_flags |= DROPDEL - thing.name = "cursed " + thing.name + target.dropItemToGround(target.get_item_by_slot(slot_to_equip_to), TRUE) + target.equip_to_slot_or_del(new_item, slot_to_equip_to, indirect_action = TRUE) + ADD_TRAIT(new_item, TRAIT_NODROP, CURSED_ITEM_TRAIT(new_item)) + new_item.item_flags |= DROPDEL + new_item.name = "cursed " + new_item.name victims += target diff --git a/code/modules/experisci/destructive_scanner.dm b/code/modules/experisci/destructive_scanner.dm index 5740b715bd42f..d5d87eb631163 100644 --- a/code/modules/experisci/destructive_scanner.dm +++ b/code/modules/experisci/destructive_scanner.dm @@ -12,12 +12,8 @@ layer = MOB_LAYER var/scanning = FALSE -/obj/machinery/destructive_scanner/Initialize(mapload) - ..() - return INITIALIZE_HINT_LATELOAD - // Late load to ensure the component initialization occurs after the machines are initialized -/obj/machinery/destructive_scanner/LateInitialize() +/obj/machinery/destructive_scanner/post_machine_initialize() . = ..() var/static/list/destructive_signals = list( diff --git a/code/modules/experisci/experiment/handlers/experiment_handler.dm b/code/modules/experisci/experiment/handlers/experiment_handler.dm index 389140bff1c16..d1482c61c98c0 100644 --- a/code/modules/experisci/experiment/handlers/experiment_handler.dm +++ b/code/modules/experisci/experiment/handlers/experiment_handler.dm @@ -236,6 +236,7 @@ /datum/component/experiment_handler/proc/configure_experiment(datum/source, mob/user) SIGNAL_HANDLER INVOKE_ASYNC(src, PROC_REF(ui_interact), user) + return CLICK_ACTION_SUCCESS /** * Attempts to show the user the experiment configuration panel diff --git a/code/modules/experisci/experiment/types/scanning.dm b/code/modules/experisci/experiment/types/scanning.dm index 197158c56f375..08ddf066f9b79 100644 --- a/code/modules/experisci/experiment/types/scanning.dm +++ b/code/modules/experisci/experiment/types/scanning.dm @@ -106,17 +106,20 @@ * * target - The atom to attempt to scan */ /datum/experiment/scanning/proc/experiment_requirements(datum/component/experiment_handler/experiment_handler, atom/target) + var/destructive = (traits & EXPERIMENT_TRAIT_DESTRUCTIVE) for (var/req_atom in required_atoms) - if (istype(target, req_atom)) - // Try to select a required atom that this scanned atom would contribute towards - var/destructive = traits & EXPERIMENT_TRAIT_DESTRUCTIVE - var/list/seen = scanned[req_atom] - var/selected = destructive && (req_atom in scanned) && seen < required_atoms[req_atom] - if (!selected) - selected = !destructive && seen.len < required_atoms[req_atom] && !(WEAKREF(target) in seen) - // Run any additonal checks if necessary - if (selected && final_contributing_index_checks(experiment_handler, target, selected)) - return req_atom + if (!istype(target, req_atom)) + continue + // Try to select a required atom that this scanned atom would contribute towards + var/selected + var/list/seen = scanned[req_atom] + if (destructive && (req_atom in scanned) && scanned[req_atom] < required_atoms[req_atom]) + selected = req_atom + else if (!destructive && seen.len < required_atoms[req_atom] && !(WEAKREF(target) in seen)) + selected = req_atom + // Run any additonal checks if necessary + if (selected && final_contributing_index_checks(experiment_handler, target, selected)) + return selected /** * Performs any additional checks against the atom being considered for selection as a contributing index diff --git a/code/modules/experisci/handheld_scanner.dm b/code/modules/experisci/handheld_scanner.dm index 32309336e3cac..390937e0dd4e4 100644 --- a/code/modules/experisci/handheld_scanner.dm +++ b/code/modules/experisci/handheld_scanner.dm @@ -18,7 +18,6 @@ // Late initialize to allow for the rnd servers to initialize first /obj/item/experi_scanner/LateInitialize() - . = ..() var/static/list/handheld_signals = list( COMSIG_ITEM_PRE_ATTACK = TYPE_PROC_REF(/datum/component/experiment_handler, try_run_handheld_experiment), COMSIG_ITEM_AFTERATTACK = TYPE_PROC_REF(/datum/component/experiment_handler, ignored_handheld_experiment_attempt), diff --git a/code/modules/explorer_drone/loot.dm b/code/modules/explorer_drone/loot.dm index 88cd5f38275e7..727731239686f 100644 --- a/code/modules/explorer_drone/loot.dm +++ b/code/modules/explorer_drone/loot.dm @@ -175,7 +175,7 @@ GLOBAL_LIST_INIT(adventure_loot_generator_index,generate_generator_index()) return if(LAZYACCESS(user.do_afters, "firelance")) return - if(!cell.use(200 KILO JOULES)) + if(!cell.use(0.2 * STANDARD_CELL_CHARGE)) to_chat(user,span_warning("[src] battery ran dry!")) return ADD_TRAIT(user, TRAIT_IMMOBILIZED, REF(src)) diff --git a/code/modules/explorer_drone/manager.dm b/code/modules/explorer_drone/manager.dm index 00909d03abf9d..ee51a2d5db398 100644 --- a/code/modules/explorer_drone/manager.dm +++ b/code/modules/explorer_drone/manager.dm @@ -83,11 +83,6 @@ . = ..() QDEL_NULL(temp_adventure) -/client/proc/adventure_manager() - set category = "Debug" - set name = "Adventure Manager" - - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB(adventure_manager, R_DEBUG, "Adventure Manager", "View and edit adventures.", ADMIN_CATEGORY_DEBUG) var/datum/adventure_browser/browser = new() - browser.ui_interact(usr) + browser.ui_interact(user.mob) diff --git a/code/modules/explorer_drone/scanner_array.dm b/code/modules/explorer_drone/scanner_array.dm index 05f1d9a8b8fa4..6317ee273bed4 100644 --- a/code/modules/explorer_drone/scanner_array.dm +++ b/code/modules/explorer_drone/scanner_array.dm @@ -181,11 +181,7 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions()) failed_popup = TRUE SStgui.update_uis(src) -/obj/machinery/computer/exoscanner_control/Initialize(mapload) - ..() - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/computer/exoscanner_control/LateInitialize() +/obj/machinery/computer/exoscanner_control/post_machine_initialize() . = ..() AddComponent(/datum/component/experiment_handler, \ allowed_experiments = list(/datum/experiment/exploration_scan), \ diff --git a/code/modules/fishing/admin.dm b/code/modules/fishing/admin.dm index d1d2c0ae2c574..0a9cfc9d51dd9 100644 --- a/code/modules/fishing/admin.dm +++ b/code/modules/fishing/admin.dm @@ -1,12 +1,6 @@ -// Helper tool to see fishing probabilities with different setups -/datum/admins/proc/fishing_calculator() - set name = "Fishing Calculator" - set category = "Debug" - - if(!check_rights(R_DEBUG)) - return - var/datum/fishing_calculator/ui = new(usr) - ui.ui_interact(usr) +ADMIN_VERB(fishing_calculator, R_DEBUG, "Fishing Calculator", "A calculator... for fishes?", ADMIN_CATEGORY_DEBUG) + var/datum/fishing_calculator/ui = new + ui.ui_interact(user.mob) /datum/fishing_calculator var/list/current_table diff --git a/code/modules/fishing/aquarium/aquarium.dm b/code/modules/fishing/aquarium/aquarium.dm index 48c7b8e24e924..8a719c16f7046 100644 --- a/code/modules/fishing/aquarium/aquarium.dm +++ b/code/modules/fishing/aquarium/aquarium.dm @@ -159,10 +159,7 @@ if(panel_open && reagents.total_volume) . += span_notice("You can use a plunger to empty the feed storage.") -/obj/structure/aquarium/AltClick(mob/living/user) - . = ..() - if(!user.can_perform_action(src)) - return +/obj/structure/aquarium/click_alt(mob/living/user) panel_open = !panel_open balloon_alert(user, "panel [panel_open ? "open" : "closed"]") if(panel_open) @@ -170,6 +167,7 @@ else reagents.flags &= ~(TRANSPARENT|REFILLABLE) update_appearance() + return CLICK_ACTION_SUCCESS /obj/structure/aquarium/wrench_act(mob/living/user, obj/item/tool) . = ..() @@ -179,9 +177,9 @@ /obj/structure/aquarium/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) if(!panel_open) return - to_chat(user, span_notice("You start plunging [name].")) + user.balloon_alert_to_viewers("plunging...") if(do_after(user, 3 SECONDS, target = src)) - to_chat(user, span_notice("You finish plunging the [name].")) + user.balloon_alert_to_viewers("finished plunging") reagents.expose(get_turf(src), TOUCH) //splash on the floor reagents.clear_reagents() diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index 90fb2afc796b8..00c52eb338a42 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -204,20 +204,20 @@ size = new_size switch(size) if(0 to FISH_SIZE_TINY_MAX) - w_class = WEIGHT_CLASS_TINY + update_weight_class(WEIGHT_CLASS_TINY) inhand_icon_state = "fish_small" if(FISH_SIZE_TINY_MAX to FISH_SIZE_SMALL_MAX) inhand_icon_state = "fish_small" - w_class = WEIGHT_CLASS_SMALL + update_weight_class(WEIGHT_CLASS_SMALL) if(FISH_SIZE_SMALL_MAX to FISH_SIZE_NORMAL_MAX) inhand_icon_state = "fish_normal" - w_class = WEIGHT_CLASS_NORMAL + update_weight_class(WEIGHT_CLASS_NORMAL) if(FISH_SIZE_NORMAL_MAX to FISH_SIZE_BULKY_MAX) inhand_icon_state = "fish_bulky" - w_class = WEIGHT_CLASS_BULKY + update_weight_class(WEIGHT_CLASS_BULKY) if(FISH_SIZE_BULKY_MAX to INFINITY) inhand_icon_state = "fish_huge" - w_class = WEIGHT_CLASS_HUGE + update_weight_class(WEIGHT_CLASS_HUGE) if(fillet_type) var/init_fillets = initial(num_fillets) var/amount = max(round(init_fillets * size / FISH_FILLET_NUMBER_SIZE_DIVISOR, 1), 1) diff --git a/code/modules/fishing/fishing_minigame.dm b/code/modules/fishing/fishing_minigame.dm index 14c1d88390ccb..e3b44e8465be1 100644 --- a/code/modules/fishing/fishing_minigame.dm +++ b/code/modules/fishing/fishing_minigame.dm @@ -644,8 +644,12 @@ hud_completion = new(null, null, challenge) vis_contents += list(hud_bait, hud_fish, hud_completion) challenge.user.client.screen += src + master_ref = WEAKREF(challenge) /atom/movable/screen/fishing_hud/Destroy() + var/datum/fishing_challenge/challenge = master_ref?.resolve() + if(!isnull(challenge)) + challenge.user.client.screen -= src QDEL_NULL(hud_fish) QDEL_NULL(hud_bait) QDEL_NULL(hud_completion) diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm index 0578ffb078907..a0fa77dc51431 100644 --- a/code/modules/fishing/fishing_rod.dm +++ b/code/modules/fishing/fishing_rod.dm @@ -234,7 +234,7 @@ cast_projectile.original = target cast_projectile.fired_from = src cast_projectile.firer = user - cast_projectile.impacted = list(user = TRUE) + cast_projectile.impacted = list(WEAKREF(user) = TRUE) cast_projectile.preparePixelProjectile(target, user) cast_projectile.fire() COOLDOWN_START(src, casting_cd, 1 SECONDS) diff --git a/code/modules/food_and_drinks/machinery/coffeemaker.dm b/code/modules/food_and_drinks/machinery/coffeemaker.dm index d79eebc993abc..5fdd296d7fc69 100644 --- a/code/modules/food_and_drinks/machinery/coffeemaker.dm +++ b/code/modules/food_and_drinks/machinery/coffeemaker.dm @@ -715,9 +715,32 @@ if(!try_brew()) return operate_for(brew_time) - coffeepot.reagents.add_reagent_list(list(/datum/reagent/consumable/coffee = 120)) - coffee.Cut(1,2) //remove the first item from the list + + // create a reference bean reagent list + var/list/reference_bean_reagents = list() + var/obj/item/food/grown/coffee/reference_bean = new /obj/item/food/grown/coffee(src) + for(var/datum/reagent/ref_bean_reagent as anything in reference_bean.reagents.reagent_list) + reference_bean_reagents += ref_bean_reagent.name + + // add all the reagents from the coffee beans to the coffeepot (ommit the ones from the reference bean) + var/list/reagent_delta = list() + var/obj/item/food/grown/coffee/bean = coffee[coffee_amount] + for(var/datum/reagent/substance as anything in bean.reagents.reagent_list) + if(!(reference_bean_reagents.Find(substance.name))) // we only add the reagent if it's a non-standard for coffee beans + reagent_delta += list(substance.type = substance.volume) + coffeepot.reagents.add_reagent_list(reagent_delta) + + qdel(reference_bean) + + // remove the coffee beans from the machine + coffee.Cut(1,2) coffee_amount-- + + // fill the rest of the pot with coffee + if(coffeepot.reagents.total_volume < 120) + var/extra_coffee_amount = 120 - coffeepot.reagents.total_volume + coffeepot.reagents.add_reagent(/datum/reagent/consumable/coffee, extra_coffee_amount) + update_appearance(UPDATE_OVERLAYS) #undef BEAN_CAPACITY diff --git a/code/modules/food_and_drinks/machinery/deep_fryer.dm b/code/modules/food_and_drinks/machinery/deep_fryer.dm index 07b7c4a1d7696..75d894ee00c38 100644 --- a/code/modules/food_and_drinks/machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/machinery/deep_fryer.dm @@ -12,6 +12,7 @@ GLOBAL_LIST_INIT(oilfry_blacklisted_items, typecacheof(list( /obj/item/reagent_containers/condiment, /obj/item/reagent_containers/cup, /obj/item/reagent_containers/syringe, + /obj/item/reagent_containers/hypospray/medipen, //letting medipens become edible opens them to being injected/drained with IV drip & saltshakers ))) /obj/machinery/deepfryer @@ -146,7 +147,11 @@ GLOBAL_LIST_INIT(oilfry_blacklisted_items, typecacheof(list( audible_message(span_notice("[src] dings!")) else if (cook_time >= DEEPFRYER_BURNTIME && !frying_burnt) frying_burnt = TRUE - visible_message(span_warning("[src] emits an acrid smell!")) + var/list/asomnia_hadders = list() + for(var/mob/smeller in get_hearers_in_view(DEFAULT_MESSAGE_RANGE, src)) + if(HAS_TRAIT(smeller, TRAIT_ANOSMIA)) + asomnia_hadders += smeller + visible_message(span_warning("[src] emits an acrid smell!"), ignored_mobs = asomnia_hadders) use_energy(active_power_usage) diff --git a/code/modules/food_and_drinks/machinery/food_cart.dm b/code/modules/food_and_drinks/machinery/food_cart.dm index e068b7b8ce290..a14ea3593c51a 100644 --- a/code/modules/food_and_drinks/machinery/food_cart.dm +++ b/code/modules/food_and_drinks/machinery/food_cart.dm @@ -8,7 +8,7 @@ anchored = FALSE use_power = NO_POWER_USE req_access = list(ACCESS_KITCHEN) - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + obj_flags = parent_type::obj_flags | NO_DEBRIS_AFTER_DECONSTRUCTION var/unpacked = FALSE var/obj/machinery/griddle/stand/cart_griddle var/obj/machinery/smartfridge/food/cart_smartfridge diff --git a/code/modules/food_and_drinks/machinery/griddle.dm b/code/modules/food_and_drinks/machinery/griddle.dm index f997b049feb2c..e0c45e6c9af10 100644 --- a/code/modules/food_and_drinks/machinery/griddle.dm +++ b/code/modules/food_and_drinks/machinery/griddle.dm @@ -37,8 +37,6 @@ /obj/machinery/griddle/crowbar_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(default_deconstruction_crowbar(I, ignore_panel = TRUE)) return variant = rand(1,3) @@ -65,6 +63,7 @@ /obj/machinery/griddle/attackby(obj/item/I, mob/user, params) + if(griddled_objects.len >= max_items) to_chat(user, span_notice("[src] can't fit more items!")) return @@ -81,6 +80,43 @@ else return ..() +/obj/machinery/griddle/item_interaction_secondary(mob/living/user, obj/item/item, list/modifiers) + if(isnull(item.atom_storage)) + return NONE + + for(var/obj/tray_item in griddled_objects) + item.atom_storage.attempt_insert(tray_item, user, TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/griddle/item_interaction(mob/living/user, obj/item/item, list/modifiers) + if(isnull(item.atom_storage)) + return NONE + + if(length(contents) >= max_items) + balloon_alert(user, "it's full!") + return ITEM_INTERACT_BLOCKING + + if(!istype(item, /obj/item/storage/bag/tray)) + // Non-tray dumping requires a do_after + to_chat(user, span_notice("You start dumping out the contents of [item] into [src]...")) + if(!do_after(user, 2 SECONDS, target = item)) + return ITEM_INTERACT_BLOCKING + + var/loaded = 0 + for(var/obj/tray_item in item) + if(!IS_EDIBLE(tray_item)) + continue + if(length(contents) >= max_items) + break + if(item.atom_storage.attempt_remove(tray_item, src)) + loaded++ + AddToGrill(tray_item, user) + if(loaded) + to_chat(user, span_notice("You insert [loaded] item\s into [src].")) + update_appearance() + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING + /obj/machinery/griddle/attack_hand(mob/user, list/modifiers) . = ..() toggle_mode() diff --git a/code/modules/food_and_drinks/machinery/grill.dm b/code/modules/food_and_drinks/machinery/grill.dm index d170a77f23051..a52749280dd6d 100644 --- a/code/modules/food_and_drinks/machinery/grill.dm +++ b/code/modules/food_and_drinks/machinery/grill.dm @@ -125,15 +125,15 @@ grill_fuel += boost update_appearance(UPDATE_ICON_STATE) -/obj/machinery/grill/item_interaction(mob/living/user, obj/item/weapon, list/modifiers, is_right_clicking) +/obj/machinery/grill/item_interaction(mob/living/user, obj/item/weapon, list/modifiers) if(user.combat_mode || (weapon.item_flags & ABSTRACT) || (weapon.flags_1 & HOLOGRAM_1) || (weapon.resistance_flags & INDESTRUCTIBLE)) - return ..() + return NONE if(istype(weapon, /obj/item/stack/sheet/mineral/coal) || istype(weapon, /obj/item/stack/sheet/mineral/wood)) if(!QDELETED(grilled_item)) - return ..() + return NONE if(!anchored) - balloon_alert(user, "anchor first!") + balloon_alert(user, "anchor it first!") return ITEM_INTERACT_BLOCKING //required for amount subtypes @@ -150,7 +150,7 @@ if(!istype(stored, target_type)) continue if(stored.amount == MAX_STACK_SIZE) - to_chat(user, span_warning("No space for [weapon]")) + balloon_alert(user, "no space!") return ITEM_INTERACT_BLOCKING target.merge(stored) merged = TRUE @@ -158,7 +158,7 @@ if(!merged) weapon.forceMove(src) - to_chat(user, span_notice("You add [src] to the fuel stack")) + to_chat(user, span_notice("You add [src] to the fuel stack.")) if(!grill_fuel) burn_stack() begin_processing() @@ -167,9 +167,9 @@ if(is_reagent_container(weapon) && weapon.is_open_container()) var/obj/item/reagent_containers/container = weapon if(!QDELETED(grilled_item)) - return ..() + return NONE if(!anchored) - balloon_alert(user, "anchor first!") + balloon_alert(user, "anchor it first!") return ITEM_INTERACT_BLOCKING var/transfered_amount = weapon.reagents.trans_to(src, container.amount_per_transfer_from_this) @@ -202,11 +202,11 @@ update_appearance(UPDATE_ICON_STATE) //feedback - to_chat(user, span_notice("You transfer [transfered_amount]u to the fuel source")) + to_chat(user, span_notice("You transfer [transfered_amount]u to the fuel source.")) return ITEM_INTERACT_SUCCESS - else - to_chat(user, span_warning("No fuel was transfered")) - return ITEM_INTERACT_BLOCKING + + balloon_alert(user, "no fuel transfered!") + return ITEM_INTERACT_BLOCKING if(IS_EDIBLE(weapon)) //sanity checks @@ -218,10 +218,10 @@ if(!QDELETED(grilled_item)) balloon_alert(user, "remove item first!") return ITEM_INTERACT_BLOCKING - else if(grill_fuel <= 0) + if(grill_fuel <= 0) balloon_alert(user, "no fuel!") return ITEM_INTERACT_BLOCKING - else if(!user.transferItemToLoc(weapon, src)) + if(!user.transferItemToLoc(weapon, src)) balloon_alert(user, "[weapon] is stuck in your hand!") return ITEM_INTERACT_BLOCKING @@ -236,7 +236,7 @@ grill_loop.start() return ITEM_INTERACT_SUCCESS - return ..() + return NONE /obj/machinery/grill/wrench_act(mob/living/user, obj/item/tool) if(user.combat_mode) diff --git a/code/modules/food_and_drinks/machinery/icecream_vat.dm b/code/modules/food_and_drinks/machinery/icecream_vat.dm index d4de599199544..cae1b26024933 100644 --- a/code/modules/food_and_drinks/machinery/icecream_vat.dm +++ b/code/modules/food_and_drinks/machinery/icecream_vat.dm @@ -154,13 +154,12 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN return ..() -/obj/machinery/icecream_vat/AltClick(mob/user) - if(!user.can_interact_with(src)) - return FALSE - if(custom_ice_cream_beaker) - balloon_alert(user, "removed beaker") - try_put_in_hand(custom_ice_cream_beaker, user) - return ..() +/obj/machinery/icecream_vat/click_alt(mob/user) + if(!custom_ice_cream_beaker) + return CLICK_ACTION_BLOCKING + balloon_alert(user, "removed beaker") + try_put_in_hand(custom_ice_cream_beaker, user) + return CLICK_ACTION_SUCCESS /obj/machinery/icecream_vat/interact(mob/living/user) . = ..() diff --git a/code/modules/food_and_drinks/machinery/microwave.dm b/code/modules/food_and_drinks/machinery/microwave.dm index dfb6ac9b2dee1..0f1be89410a41 100644 --- a/code/modules/food_and_drinks/machinery/microwave.dm +++ b/code/modules/food_and_drinks/machinery/microwave.dm @@ -15,7 +15,7 @@ #define MAX_MICROWAVE_DIRTINESS 100 /// For the wireless version, and display fluff -#define TIER_1_CELL_CHARGE_RATE (250 KILO JOULES) +#define TIER_1_CELL_CHARGE_RATE (0.25 * STANDARD_CELL_CHARGE) /obj/machinery/microwave name = "microwave oven" @@ -31,6 +31,7 @@ light_color = LIGHT_COLOR_DIM_YELLOW light_power = 3 anchored_tabletop_offset = 6 + interaction_flags_click = ALLOW_SILICON_REACH /// Is its function wire cut? var/wire_disabled = FALSE /// Wire cut to run mode backwards @@ -364,21 +365,15 @@ update_appearance() return ITEM_INTERACT_SUCCESS -/obj/machinery/microwave/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/machinery/microwave/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(operating) - return + return ITEM_INTERACT_SKIP_TO_ATTACK // Don't use tools if we're dirty if(dirty >= MAX_MICROWAVE_DIRTINESS) - return - - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . - + return ITEM_INTERACT_SKIP_TO_ATTACK // Don't insert items if we're dirty if(panel_open && is_wire_tool(tool)) wires.interact(user) return ITEM_INTERACT_SUCCESS - - return . + return NONE /obj/machinery/microwave/attackby(obj/item/item, mob/living/user, params) if(operating) @@ -473,16 +468,16 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN -/obj/machinery/microwave/AltClick(mob/user, list/modifiers) - if(user.can_perform_action(src, ALLOW_SILICON_REACH)) - if(!vampire_charging_capable) - return +/obj/machinery/microwave/click_alt(mob/user, list/modifiers) + if(!vampire_charging_capable) + return NONE - vampire_charging_enabled = !vampire_charging_enabled - balloon_alert(user, "set to [vampire_charging_enabled ? "charge" : "cook"]") - playsound(src, 'sound/machines/twobeep_high.ogg', 50, FALSE) - if(HAS_SILICON_ACCESS(user)) - visible_message(span_notice("[user] sets \the [src] to [vampire_charging_enabled ? "charge" : "cook"]."), blind_message = span_notice("You hear \the [src] make an informative beep!")) + vampire_charging_enabled = !vampire_charging_enabled + balloon_alert(user, "set to [vampire_charging_enabled ? "charge" : "cook"]") + playsound(src, 'sound/machines/twobeep_high.ogg', 50, FALSE) + if(HAS_SILICON_ACCESS(user)) + visible_message(span_notice("[user] sets \the [src] to [vampire_charging_enabled ? "charge" : "cook"]."), blind_message = span_notice("You hear \the [src] make an informative beep!")) + return CLICK_ACTION_SUCCESS /obj/machinery/microwave/CtrlClick(mob/user) . = ..() diff --git a/code/modules/food_and_drinks/machinery/oven.dm b/code/modules/food_and_drinks/machinery/oven.dm index 517e25c6dcba7..c997f34924145 100644 --- a/code/modules/food_and_drinks/machinery/oven.dm +++ b/code/modules/food_and_drinks/machinery/oven.dm @@ -90,20 +90,33 @@ baked_item.fire_act(1000) //Hot hot hot! if(SPT_PROB(10, seconds_per_tick)) - visible_message(span_danger("You smell a burnt smell coming from [src]!")) + var/list/asomnia_hadders = list() + for(var/mob/smeller in get_hearers_in_view(DEFAULT_MESSAGE_RANGE, src)) + if(HAS_TRAIT(smeller, TRAIT_ANOSMIA)) + asomnia_hadders += smeller + visible_message(span_danger("You smell a burnt smell coming from [src]!"), ignored_mobs = asomnia_hadders) set_smoke_state(worst_cooked_food_state) update_appearance() use_energy(active_power_usage) - -/obj/machinery/oven/attackby(obj/item/I, mob/user, params) - if(open && !used_tray && istype(I, /obj/item/plate/oven_tray)) - if(user.transferItemToLoc(I, src, silent = FALSE)) - to_chat(user, span_notice("You put [I] in [src].")) - add_tray_to_oven(I, user) - else +/obj/machinery/oven/attackby(obj/item/item, mob/user, params) + if(!open || used_tray || !istype(item, /obj/item/plate/oven_tray)) return ..() + if(user.transferItemToLoc(item, src, silent = FALSE)) + to_chat(user, span_notice("You put [item] in [src].")) + add_tray_to_oven(item, user) + +/obj/machinery/oven/item_interaction(mob/living/user, obj/item/item, list/modifiers) + if(open && used_tray && item.atom_storage) + return used_tray.item_interaction(user, item, modifiers) + return NONE + +/obj/machinery/oven/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers) + if(open && used_tray && tool.atom_storage) + return used_tray.item_interaction_secondary(user, tool, modifiers) + return NONE + ///Adds a tray to the oven, making sure the shit can get baked. /obj/machinery/oven/proc/add_tray_to_oven(obj/item/plate/oven_tray, mob/baker) used_tray = oven_tray @@ -239,6 +252,43 @@ max_items = 6 biggest_w_class = WEIGHT_CLASS_BULKY +/obj/item/plate/oven_tray/item_interaction_secondary(mob/living/user, obj/item/item, list/modifiers) + if(isnull(item.atom_storage)) + return NONE + + for(var/obj/tray_item in src) + item.atom_storage.attempt_insert(tray_item, user, TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/item/plate/oven_tray/item_interaction(mob/living/user, obj/item/item, list/modifiers) + if(isnull(item.atom_storage)) + return NONE + + if(length(contents) >= max_items) + balloon_alert(user, "it's full!") + return ITEM_INTERACT_BLOCKING + + if(!istype(item, /obj/item/storage/bag/tray)) + // Non-tray dumping requires a do_after + to_chat(user, span_notice("You start dumping out the contents of [item] into [src]...")) + if(!do_after(user, 2 SECONDS, target = item)) + return ITEM_INTERACT_BLOCKING + + var/loaded = 0 + for(var/obj/tray_item in item) + if(!IS_EDIBLE(tray_item)) + continue + if(length(contents) >= max_items) + break + if(item.atom_storage.attempt_remove(tray_item, src)) + loaded++ + AddToPlate(tray_item, user) + if(loaded) + to_chat(user, span_notice("You insert [loaded] item\s into [src].")) + update_appearance() + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING + #undef OVEN_SMOKE_STATE_NONE #undef OVEN_SMOKE_STATE_GOOD #undef OVEN_SMOKE_STATE_NEUTRAL diff --git a/code/modules/food_and_drinks/machinery/stove.dm b/code/modules/food_and_drinks/machinery/stove.dm index 38f98cfa8a8bf..6cc0ec527894f 100644 --- a/code/modules/food_and_drinks/machinery/stove.dm +++ b/code/modules/food_and_drinks/machinery/stove.dm @@ -115,6 +115,34 @@ . = ..() LAZYREMOVE(added_ingredients, gone) +/** + * Adds items to a soup pot without invoking any procs that call sleep() when using in a component. + * + * Args: + * * transfer_from: The container that's being used to add items to the soup pot. Must not be null. + * * user: the entity adding ingredients via a container to a soup pot. Must not be null. + */ +/obj/item/reagent_containers/cup/soup_pot/proc/transfer_from_container_to_pot(obj/item/transfer_from, mob/user) + if(!transfer_from.atom_storage) + return + + var/obj/item/storage/tray = transfer_from + var/loaded = 0 + + for(var/obj/tray_item in tray.contents) + if(!can_add_ingredient(tray_item)) + continue + if(LAZYLEN(added_ingredients) >= max_ingredients) + balloon_alert(user, "it's full!") + return TRUE + if(tray.atom_storage.attempt_remove(tray_item, src)) + loaded++ + LAZYADD(added_ingredients, tray_item) + if(loaded) + to_chat(user, span_notice("You insert [loaded] items into \the [src].")) + update_appearance(UPDATE_OVERLAYS) + return TRUE + /obj/item/reagent_containers/cup/soup_pot/attackby(obj/item/attacking_item, mob/user, params) . = ..() if(.) @@ -140,6 +168,12 @@ update_appearance(UPDATE_OVERLAYS) return TRUE +/obj/item/reagent_containers/cup/soup_pot/item_interaction(mob/living/user, obj/item/item, list/modifiers) + if(LAZYACCESS(modifiers, RIGHT_CLICK)) + return NONE + + return transfer_from_container_to_pot(item, user) + /obj/item/reagent_containers/cup/soup_pot/attack_hand_secondary(mob/user, list/modifiers) if(!LAZYLEN(added_ingredients)) return SECONDARY_ATTACK_CALL_NORMAL diff --git a/code/modules/food_and_drinks/machinery/stove_component.dm b/code/modules/food_and_drinks/machinery/stove_component.dm index 1a39c3b205746..d46434ce111d6 100644 --- a/code/modules/food_and_drinks/machinery/stove_component.dm +++ b/code/modules/food_and_drinks/machinery/stove_component.dm @@ -128,6 +128,14 @@ /datum/component/stove/proc/on_attackby(obj/machinery/source, obj/item/attacking_item, mob/user, params) SIGNAL_HANDLER + if(istype(source, /obj/machinery/oven/range) && istype(attacking_item, /obj/item/storage/bag/tray) && container) + var/obj/machinery/oven/range/range = source + var/obj/item/reagent_containers/cup/soup_pot/soup_pot = container + + if(!range.open) + soup_pot.transfer_from_container_to_pot(attacking_item, user) + return COMPONENT_NO_AFTERATTACK + if(!attacking_item.is_open_container()) return if(!isnull(container)) @@ -249,7 +257,7 @@ return // this gets badly murdered by sidemap soup_smoke = new(parent, particle_type) - soup_smoke.set_particle_position(list(container_x, round(world.icon_size * 0.66), 0)) + soup_smoke.set_particle_position(container_x, round(world.icon_size * 0.66), 0) return QDEL_NULL(soup_smoke) diff --git a/code/modules/food_and_drinks/plate.dm b/code/modules/food_and_drinks/plate.dm index 1df1d7c24bb91..4ae6bf19e1d4c 100644 --- a/code/modules/food_and_drinks/plate.dm +++ b/code/modules/food_and_drinks/plate.dm @@ -70,7 +70,7 @@ update_appearance() // If the incoming item is the same weight class as the plate, bump us up a class if(item_to_plate.w_class == w_class) - w_class += 1 + update_weight_class(w_class + 1) ///This proc cleans up any signals on the item when it is removed from a plate, and ensures it has the correct state again. /obj/item/plate/proc/ItemRemovedFromPlate(obj/item/removed_item) @@ -85,12 +85,14 @@ removed_item.pixel_z = 0 // We need to ensure the weight class is accurate now that we've lost something // that may or may not have been of equal weight - w_class = initial(w_class) + var/new_w_class = initial(w_class) for(var/obj/item/on_board in src) if(on_board.w_class == w_class) - w_class += 1 + new_w_class += 1 break + update_weight_class(new_w_class) + ///This proc is called by signals that remove the food from the plate. /obj/item/plate/proc/ItemMoved(obj/item/moved_item, atom/OldLoc, Dir, Forced) SIGNAL_HANDLER diff --git a/code/modules/food_and_drinks/recipes/food_mixtures.dm b/code/modules/food_and_drinks/recipes/food_mixtures.dm index d5e7f1b15ea80..c04edf6fee79d 100644 --- a/code/modules/food_and_drinks/recipes/food_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm @@ -1,4 +1,5 @@ /datum/crafting_recipe/food + mass_craftable = TRUE /datum/crafting_recipe/food/on_craft_completion(mob/user, atom/result) SHOULD_CALL_PARENT(TRUE) @@ -263,7 +264,7 @@ required_reagents = list(/datum/reagent/consumable/olivepaste = 4, /datum/reagent/water = 1) reaction_flags = REACTION_INSTANT -/datum/chemical_reaction/food/vinegar +/datum/chemical_reaction/food/wine_vinegar results = list(/datum/reagent/consumable/vinegar = 5) required_reagents = list(/datum/reagent/consumable/ethanol/wine = 1, /datum/reagent/water = 1, /datum/reagent/consumable/sugar = 1) reaction_flags = REACTION_INSTANT @@ -276,12 +277,12 @@ reaction_flags = REACTION_INSTANT /datum/chemical_reaction/food/martian_batter - results = list(/datum/reagent/consumable/martian_batter = 2) - required_reagents = list(/datum/reagent/consumable/flour = 1, /datum/reagent/consumable/nutriment/soup/dashi = 1) + results = list(/datum/reagent/consumable/martian_batter = 10) + required_reagents = list(/datum/reagent/consumable/flour = 5, /datum/reagent/consumable/nutriment/soup/dashi = 5) mix_message = "A smooth batter forms." reaction_flags = REACTION_INSTANT -/datum/chemical_reaction/food/vinegar +/datum/chemical_reaction/food/grape_vinegar results = list(/datum/reagent/consumable/vinegar = 5) required_reagents = list(/datum/reagent/consumable/grapejuice = 5) required_catalysts = list(/datum/reagent/consumable/enzyme = 5) diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm index c05446d35218e..8f78cb01ebc23 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm @@ -150,7 +150,7 @@ ) result = /obj/item/food/croissant/throwing category = CAT_BREAD - always_available = FALSE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/breaddog name = "Living dog/bread hybrid" diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm index b34cc5f36e965..4b56874eb7c6b 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm @@ -184,7 +184,6 @@ /datum/crafting_recipe/food/clowncake name = "clown cake" - always_available = FALSE reqs = list( /obj/item/food/cake/plain = 1, /obj/item/food/sundae = 2, @@ -192,16 +191,17 @@ ) result = /obj/item/food/cake/clown_cake category = CAT_CAKE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/vanillacake name = "vanilla cake" - always_available = FALSE reqs = list( /obj/item/food/cake/plain = 1, /obj/item/food/grown/vanillapod = 2 ) result = /obj/item/food/cake/vanilla_cake category = CAT_CAKE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/trumpetcake name = "Spaceman's Cake" diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm index a9f1ad23d8e26..c0c99bbe6523b 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm @@ -132,7 +132,6 @@ /datum/crafting_recipe/food/mimetart name = "Mime tart" - always_available = FALSE reqs = list( /datum/reagent/consumable/milk = 5, /datum/reagent/consumable/sugar = 5, @@ -141,10 +140,10 @@ ) result = /obj/item/food/pie/mimetart category = CAT_PIE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/berrytart name = "Berry tart" - always_available = FALSE reqs = list( /datum/reagent/consumable/milk = 5, /datum/reagent/consumable/sugar = 5, @@ -153,10 +152,10 @@ ) result = /obj/item/food/pie/berrytart category = CAT_PIE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/cocolavatart name = "Chocolate Lava tart" - always_available = FALSE reqs = list( /datum/reagent/consumable/milk = 5, /datum/reagent/consumable/sugar = 5, @@ -166,6 +165,7 @@ ) result = /obj/item/food/pie/cocolavatart category = CAT_PIE + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/blumpkinpie name = "Blumpkin pie" diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm index b0c44629e1853..7761a57fcfdbd 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm @@ -118,7 +118,6 @@ /datum/crafting_recipe/food/death_sandwich name = "Death Sandwich" - always_available = FALSE reqs = list( /obj/item/food/breadslice/plain = 2, /obj/item/food/salami = 4, @@ -127,6 +126,7 @@ ) result = /obj/item/food/sandwich/death category = CAT_SANDWICH + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/toast_sandwich name = "Toast Sandwich" diff --git a/code/modules/food_and_drinks/restaurant/customers/_customer.dm b/code/modules/food_and_drinks/restaurant/customers/_customer.dm index 47bb843d755c7..15e4659338d0c 100644 --- a/code/modules/food_and_drinks/restaurant/customers/_customer.dm +++ b/code/modules/food_and_drinks/restaurant/customers/_customer.dm @@ -306,7 +306,7 @@ /datum/customer_data/moth/proc/get_wings(mob/living/basic/robot_customer/customer) var/customer_ref = WEAKREF(customer) if (!LAZYACCESS(wings_chosen, customer_ref)) - LAZYSET(wings_chosen, customer_ref, GLOB.moth_wings_list[pick(GLOB.moth_wings_list)]) + LAZYSET(wings_chosen, customer_ref, SSaccessories.moth_wings_list[pick(SSaccessories.moth_wings_list)]) return wings_chosen[customer_ref] /datum/customer_data/moth/get_underlays(mob/living/basic/robot_customer/customer) diff --git a/code/modules/hallucination/fake_message.dm b/code/modules/hallucination/fake_message.dm index a1040496f5ea6..de5616d83c6c3 100644 --- a/code/modules/hallucination/fake_message.dm +++ b/code/modules/hallucination/fake_message.dm @@ -25,7 +25,7 @@ // in the future, this could / should be de-harcoded and // just draw from a pool uplink, theft, and antag item typepaths var/static/list/stash_item_paths = list( - /obj/item/areaeditor/blueprints, + /obj/item/blueprints, /obj/item/assembly/flash, /obj/item/card/id/advanced/gold/captains_spare, /obj/item/card/emag, diff --git a/code/modules/hallucination/fake_sound.dm b/code/modules/hallucination/fake_sound.dm index aaf8ef468230c..f5d750a114427 100644 --- a/code/modules/hallucination/fake_sound.dm +++ b/code/modules/hallucination/fake_sound.dm @@ -169,7 +169,7 @@ sound_type = list( 'sound/ambience/antag/bloodcult/bloodcult_gain.ogg', 'sound/ambience/antag/clockcultalr.ogg', - 'sound/ambience/antag/ecult_op.ogg', + 'sound/ambience/antag/heretic/heretic_gain.ogg', 'sound/ambience/antag/ling_alert.ogg', 'sound/ambience/antag/malf.ogg', 'sound/ambience/antag/ops.ogg', diff --git a/code/modules/hallucination/inhand_fake_item.dm b/code/modules/hallucination/inhand_fake_item.dm index 8f1a720cf0dfe..ba791f3a56c7c 100644 --- a/code/modules/hallucination/inhand_fake_item.dm +++ b/code/modules/hallucination/inhand_fake_item.dm @@ -43,7 +43,7 @@ hallucinated_item.desc = initial(template_item_type.desc) hallucinated_item.icon = initial(template_item_type.icon) hallucinated_item.icon_state = initial(template_item_type.icon_state) - hallucinated_item.w_class = initial(template_item_type.w_class) // Not strictly necessary, but keen eyed people will notice + hallucinated_item.update_weight_class(initial(template_item_type.w_class)) // Not strictly necessary, but keen eyed people will notice return hallucinated_item diff --git a/code/modules/hallucination/station_message.dm b/code/modules/hallucination/station_message.dm index 97b37e77cd9e2..976b88f662097 100644 --- a/code/modules/hallucination/station_message.dm +++ b/code/modules/hallucination/station_message.dm @@ -40,11 +40,26 @@ /// This is gross and will probably easily be outdated in some time but c'est la vie. /// Maybe if someone datumizes heretic paths or something this can be improved var/static/list/ascension_bodies = list( - "Fear the blaze, for the Ashlord, %FAKENAME% has ascended! The flames shall consume all!", - "Master of blades, the Torn Champion's disciple, %FAKENAME% has ascended! Their steel is that which will cut reality in a maelstom of silver!", - "Ever coiling vortex. Reality unfolded. ARMS OUTREACHED, THE LORD OF THE NIGHT, %FAKENAME% has ascended! Fear the ever twisting hand!", - "Fear the decay, for the Rustbringer, %FAKENAME% has ascended! None shall escape the corrosion!", - "The nobleman of void %FAKENAME% has arrived, stepping along the Waltz that ends worlds!", + list( + "text" = "Fear the blaze, for the Ashlord, %FAKENAME% has ascended! The flames shall consume all!", + "sound" = 'sound/ambience/antag/heretic/ascend_blade.ogg', + ), + list( + "text" = "Master of blades, the Torn Champion's disciple, %FAKENAME% has ascended! Their steel is that which will cut reality in a maelstom of silver!", + "sound" = 'sound/ambience/antag/heretic/ascend_blade.ogg', + ), + list( + "text" = "Ever coiling vortex. Reality unfolded. ARMS OUTREACHED, THE LORD OF THE NIGHT, %FAKENAME% has ascended! Fear the ever twisting hand!", + "sound" = 'sound/ambience/antag/heretic/ascend_flesh.ogg', + ), + list( + "text" = "Fear the decay, for the Rustbringer, %FAKENAME% has ascended! None shall escape the corrosion!", + "sound" = 'sound/ambience/antag/heretic/ascend_rust.ogg', + ), + list( + "text" = "The nobleman of void %FAKENAME% has arrived, stepping along the Waltz that ends worlds!", + "sound" = 'sound/ambience/antag/heretic/ascend_void.ogg', + ) ) /datum/hallucination/station_message/heretic/start() @@ -53,12 +68,12 @@ if(!totally_real_heretic) return FALSE - var/message_with_name = pick(ascension_bodies) - message_with_name = replacetext(message_with_name, "%FAKENAME%", totally_real_heretic.real_name) + var/list/fake_ascension = pick(ascension_bodies) + var/announcement_text = replacetext(fake_ascension["text"], "%FAKENAME%", totally_real_heretic.real_name) priority_announce( - text = "[generate_heretic_text()] [message_with_name] [generate_heretic_text()]", + text = "[generate_heretic_text()] [announcement_text] [generate_heretic_text()]", title = "[generate_heretic_text()]", - sound = ANNOUNCER_SPANOMALIES, + sound = fake_ascension["sound"], players = list(hallucinator), color_override = "pink", ) diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index f75a1329246b3..1ff5bc47a5518 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -84,11 +84,8 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf //creates the timer that determines if another program can be manually loaded COOLDOWN_DECLARE(holodeck_cooldown) -/obj/machinery/computer/holodeck/Initialize(mapload) - ..() - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/computer/holodeck/LateInitialize()//from here linked is populated and the program list is generated. its also set to load the offline program +/obj/machinery/computer/holodeck/post_machine_initialize() //from here linked is populated and the program list is generated. its also set to load the offline program + . = ..() linked = GLOB.areas_by_type[mapped_start_area] if(!linked) log_mapping("[src] at [AREACOORD(src)] has no matching holodeck area.") @@ -295,12 +292,12 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf holo_object.resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF if(isstructure(holo_object)) - holo_object.obj_flags |= NO_DECONSTRUCTION + holo_object.obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION return if(ismachinery(holo_object)) var/obj/machinery/holo_machine = holo_object - holo_machine.obj_flags |= NO_DECONSTRUCTION + holo_machine.obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION holo_machine.power_change() if(istype(holo_machine, /obj/machinery/button)) @@ -380,7 +377,7 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf if(toggleOn) if(last_program && (last_program != offline_program)) - addtimer(CALLBACK(src, PROC_REF(load_program), last_program, TRUE), 25) + addtimer(CALLBACK(src, PROC_REF(load_program), last_program, TRUE), 2.5 SECONDS) active = TRUE else last_program = program diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm index afd4c2270388f..caa5b425ca4b3 100644 --- a/code/modules/holodeck/holo_effect.dm +++ b/code/modules/holodeck/holo_effect.dm @@ -50,7 +50,7 @@ var/newtype = pick(subtypesof(/obj/item/book/manual) - banned_books) var/obj/item/book/manual/to_spawn = new newtype(loc) to_spawn.flags_1 |= HOLOGRAM_1 - to_spawn.obj_flags |= NO_DECONSTRUCTION + to_spawn.obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION return to_spawn /obj/effect/holodeck_effect/mobspawner diff --git a/code/modules/holodeck/items.dm b/code/modules/holodeck/items.dm index eb0261739adbf..3d80ef6d968c0 100644 --- a/code/modules/holodeck/items.dm +++ b/code/modules/holodeck/items.dm @@ -140,7 +140,7 @@ for (var/list/zlevel_turfs as anything in currentarea.get_zlevel_turf_lists()) for(var/turf/area_turf as anything in zlevel_turfs) for(var/obj/structure/window/barrier in area_turf) - if((barrier.obj_flags & NO_DECONSTRUCTION) || (barrier.flags_1 & HOLOGRAM_1))// Just in case: only holo-windows + if(barrier.flags_1 & HOLOGRAM_1)// Just in case: only holo-windows qdel(barrier) for(var/mob/contestant in area_turf) diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm index 15a82c5aa5577..51e09f8ab9a2c 100644 --- a/code/modules/holodeck/turfs.dm +++ b/code/modules/holodeck/turfs.dm @@ -8,9 +8,8 @@ /turf/open/floor/holofloor/attackby(obj/item/I, mob/living/user) return // HOLOFLOOR DOES NOT GIVE A FUCK -/turf/open/floor/holofloor/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - SHOULD_CALL_PARENT(FALSE) - return NONE // Fuck you +/turf/open/floor/holofloor/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + return ITEM_INTERACT_BLOCKING // Fuck you /turf/open/floor/holofloor/burn_tile() return //you can't burn a hologram! @@ -158,7 +157,7 @@ /turf/open/floor/holofloor/carpet/Initialize(mapload) . = ..() - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 1) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 0.1 SECONDS) /turf/open/floor/holofloor/carpet/update_icon(updates=ALL) . = ..() diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm index 6636fedd25cab..521afd6b53903 100644 --- a/code/modules/hydroponics/beekeeping/beebox.dm +++ b/code/modules/hydroponics/beekeeping/beebox.dm @@ -249,7 +249,7 @@ visible_message(span_notice("[user] removes the queen from the apiary.")) queen_bee = null -/obj/structure/beebox/deconstruct(disassembled = TRUE) +/obj/structure/beebox/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood (loc, 20) for(var/mob/living/basic/bee/worker as anything in bees) if(worker.loc == src) @@ -260,7 +260,6 @@ if(frame.loc == src) frame.forceMove(get_turf(src)) honey_frames -= frame - qdel(src) /obj/structure/beebox/unwrenched anchored = FALSE diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index 260c4042a0a76..35bf611b506a6 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -13,6 +13,7 @@ density = TRUE circuit = /obj/item/circuitboard/machine/biogenerator processing_flags = START_PROCESSING_MANUALLY + interaction_flags_click = FORBID_TELEKINESIS_REACH /// Whether the biogenerator is currently processing biomass or not. var/processing = FALSE /// The reagent container that is currently inside of the biomass generator. Can be null. @@ -272,10 +273,9 @@ to_chat(user, span_warning("You cannot put \the [attacking_item] in \the [src]!")) -/obj/machinery/biogenerator/AltClick(mob/living/user) - . = ..() - if(user.can_perform_action(src, FORBID_TELEKINESIS_REACH) && can_interact(user)) - eject_beaker(user) +/obj/machinery/biogenerator/click_alt(mob/living/user) + eject_beaker(user) + return CLICK_ACTION_SUCCESS /// Activates biomass processing and converts all inserted food products into biomass diff --git a/code/modules/hydroponics/fermenting_barrel.dm b/code/modules/hydroponics/fermenting_barrel.dm index a971b2b6a7403..676c0cec7bbc6 100644 --- a/code/modules/hydroponics/fermenting_barrel.dm +++ b/code/modules/hydroponics/fermenting_barrel.dm @@ -163,3 +163,13 @@ /obj/structure/fermenting_barrel/gunpowder/Initialize(mapload) . = ..() reagents.add_reagent(/datum/reagent/gunpowder, 500) + +/// Medieval pirates can have a barrel as a treat +/obj/structure/fermenting_barrel/thermite + name = "thermite barrel" + desc = "A large wooden barrel for holding thermite. Use this to make a big flipping hole on walls." + can_open = FALSE + +/obj/structure/fermenting_barrel/thermite/Initialize(mapload) + . = ..() + reagents.add_reagent(/datum/reagent/thermite, 500) diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm index c4e3b27673ae4..31c0b7f81df64 100644 --- a/code/modules/hydroponics/grown/replicapod.dm +++ b/code/modules/hydroponics/grown/replicapod.dm @@ -197,7 +197,7 @@ if(!features["mcolor"]) features["mcolor"] = "#59CE00" if(!features["pod_hair"]) - features["pod_hair"] = pick(GLOB.pod_hair_list) + features["pod_hair"] = pick(SSaccessories.pod_hair_list) for(var/V in quirks) new V(podman) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 0752d418a4eff..9b23f0b25b0f3 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -1099,8 +1099,6 @@ set_self_sustaining(!self_sustaining) to_chat(user, span_notice("You [self_sustaining ? "activate" : "deactivated"] [src]'s autogrow function[self_sustaining ? ", maintaining the tray's health while using high amounts of power" : ""].")) -/obj/machinery/hydroponics/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/machinery/hydroponics/attack_hand_secondary(mob/user, list/modifiers) . = ..() @@ -1159,11 +1157,16 @@ circuit = null density = FALSE use_power = NO_POWER_USE - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION unwrenchable = FALSE self_sustaining_overlay_icon_state = null maxnutri = 15 +/obj/machinery/hydroponics/soil/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/hydroponics/soil/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/machinery/hydroponics/soil/update_icon(updates=ALL) . = ..() if(self_sustaining) diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index 8a6e028336b86..b273cfb6d5854 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -589,7 +589,7 @@ var/obj/item/stock_parts/cell/potato/pocell = new /obj/item/stock_parts/cell/potato(user.loc) pocell.icon = our_plant.icon // Just in case the plant icons get spread out in different files eventually, this trait won't cause error sprites (also yay downstreams) pocell.icon_state = our_plant.icon_state - pocell.maxcharge = our_seed.potency * 20 KILO JOULES + pocell.maxcharge = our_seed.potency * 0.02 * STANDARD_CELL_CHARGE // The secret of potato supercells! var/datum/plant_gene/trait/cell_charge/electrical_gene = our_seed.get_gene(/datum/plant_gene/trait/cell_charge) diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index d079323e3a9c9..f46f4c3912a0f 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -234,7 +234,7 @@ else t_prod = new product(output_loc, new_seed = src) if(parent.myseed.plantname != initial(parent.myseed.plantname)) - t_prod.name = lowertext(parent.myseed.plantname) + t_prod.name = LOWER_TEXT(parent.myseed.plantname) if(productdesc) t_prod.desc = productdesc t_prod.seed.name = parent.myseed.name @@ -475,7 +475,7 @@ return if(!user.can_perform_action(src)) return - name = "[lowertext(newplantname)]" + name = "[LOWER_TEXT(newplantname)]" plantname = newplantname if("Seed Description") var/newdesc = tgui_input_text(user, "Write a new seed description", "Seed Description", desc, 180) diff --git a/code/modules/instruments/songs/play_legacy.dm b/code/modules/instruments/songs/play_legacy.dm index 7094de85a8963..c49122d464196 100644 --- a/code/modules/instruments/songs/play_legacy.dm +++ b/code/modules/instruments/songs/play_legacy.dm @@ -9,7 +9,7 @@ var/list/octaves = list(3, 3, 3, 3, 3, 3, 3) var/list/accents = list("n", "n", "n", "n", "n", "n", "n") for(var/line in lines) - var/list/chords = splittext(lowertext(line), ",") + var/list/chords = splittext(LOWER_TEXT(line), ",") for(var/chord in chords) var/list/compiled_chord = list() var/tempodiv = 1 diff --git a/code/modules/instruments/songs/play_synthesized.dm b/code/modules/instruments/songs/play_synthesized.dm index 836c2fdd86bce..05e23a8c97aac 100644 --- a/code/modules/instruments/songs/play_synthesized.dm +++ b/code/modules/instruments/songs/play_synthesized.dm @@ -9,7 +9,7 @@ var/list/octaves = list(3, 3, 3, 3, 3, 3, 3) var/list/accents = list("n", "n", "n", "n", "n", "n", "n") for(var/line in lines) - var/list/chords = splittext(lowertext(line), ",") + var/list/chords = splittext(LOWER_TEXT(line), ",") for(var/chord in chords) var/list/compiled_chord = list() var/tempodiv = 1 diff --git a/code/modules/interview/interview.dm b/code/modules/interview/interview.dm index 923d11fc76f4a..a1703b9c06974 100644 --- a/code/modules/interview/interview.dm +++ b/code/modules/interview/interview.dm @@ -58,7 +58,7 @@ SEND_SOUND(owner, sound('sound/effects/adminhelp.ogg')) to_chat(owner, "-- Interview Update --" \ + "\n[span_adminsay("Your interview was approved, you will now be reconnected in 5 seconds.")]", confidential = TRUE) - addtimer(CALLBACK(src, PROC_REF(reconnect_owner)), 50) + addtimer(CALLBACK(src, PROC_REF(reconnect_owner)), 5 SECONDS) /** * Denies the interview and adds the owner to the cooldown for new interviews. @@ -73,7 +73,7 @@ GLOB.interviews.cooldown_ckeys |= owner_ckey log_admin_private("[key_name(denied_by)] has denied interview #[id] for [owner_ckey][!owner ? "(DC)": ""].") message_admins(span_adminnotice("[key_name(denied_by)] has denied [link_self()] for [owner_ckey][!owner ? "(DC)": ""].")) - addtimer(CALLBACK(GLOB.interviews, TYPE_PROC_REF(/datum/interview_manager, release_from_cooldown), owner_ckey), 180) + addtimer(CALLBACK(GLOB.interviews, TYPE_PROC_REF(/datum/interview_manager, release_from_cooldown), owner_ckey), 18 SECONDS) if (owner) SEND_SOUND(owner, sound('sound/effects/adminhelp.ogg')) to_chat(owner, "-- Interview Update --" \ diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index 2055080710e4e..b31574bec33e3 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -19,6 +19,12 @@ if(isAdminGhostAI(accessor)) //Access can't stop the abuse return TRUE + //If the mob has the simple_access component with the requried access, we let them in. + var/attempted_access = SEND_SIGNAL(accessor, COMSIG_MOB_TRIED_ACCESS, src) + if(attempted_access & ACCESS_ALLOWED) + return TRUE + if(attempted_access & ACCESS_DISALLOWED) + return FALSE if(HAS_SILICON_ACCESS(accessor)) if(ispAI(accessor)) return FALSE @@ -28,9 +34,6 @@ if(onSyndieBase() && loc != accessor) return FALSE return TRUE //AI can do whatever it wants - //If the mob has the simple_access component with the requried access, we let them in. - else if(SEND_SIGNAL(accessor, COMSIG_MOB_TRIED_ACCESS, src) & ACCESS_ALLOWED) - return TRUE //If the mob is holding a valid ID, we let them in. get_active_held_item() is on the mob level, so no need to copypasta everywhere. else if(check_access(accessor.get_active_held_item()) || check_access(accessor.get_inactive_held_item())) return TRUE diff --git a/code/modules/jobs/departments/departments.dm b/code/modules/jobs/departments/departments.dm index ce21920eced01..c87e1dc31c5e4 100644 --- a/code/modules/jobs/departments/departments.dm +++ b/code/modules/jobs/departments/departments.dm @@ -28,15 +28,6 @@ /// A list of generic access flags people in this department generally have. var/list/department_access = list() -/datum/job_department/New() - . = ..() - for(var/delivery_area_type in department_delivery_areas) - if(GLOB.areas_by_type[delivery_area_type]) - return - //every area fallback didn't exist on this map so throw a mapping error and set some generic area that uuuh please exist okay - log_mapping("[type] has no valid areas to deliver to on this map, add some more fallback areas to its \"department_delivery_areas\" var.") - department_delivery_areas = list(/area/station/hallway/primary/central) //if this doesn't exist like honestly fuck your map man - /// Handles adding jobs to the department and setting up the job bitflags. /datum/job_department/proc/add_job(datum/job/job) department_jobs += job @@ -111,7 +102,10 @@ label_class = "engineering" ui_color = "#dfb567" nation_prefixes = list("Atomo", "Engino", "Power", "Teleco") - department_delivery_areas = list(/area/station/engineering/main) + department_delivery_areas = list( + /area/station/engineering/main, + /area/station/engineering/lobby, + ) associated_cargo_groups = list("Engineering", "Engine Construction", "Canisters & Materials") head_of_staff_access = ACCESS_CE department_access = REGION_ACCESS_ENGINEERING @@ -144,7 +138,11 @@ label_class = "science" ui_color = "#c973c9" nation_prefixes = list("Sci", "Griffa", "Geneti", "Explosi", "Mecha", "Xeno", "Nani", "Cyto") - department_delivery_areas = list(/area/station/science/research) + department_delivery_areas = list( + /area/station/science/research, + /area/station/science/lobby, + /area/station/science/lab, + ) associated_cargo_groups = list("Science", "Livestock", "Canisters & Materials") head_of_staff_access = ACCESS_RD department_access = REGION_ACCESS_RESEARCH diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 6c5c2f4f03967..9cbd711d98161 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -117,7 +117,7 @@ /// RPG job names, for the memes var/rpg_title - /// Alternate titles to register as pointing to this job. + /// Alternate titles to register as pointing to this job. var/list/alternate_titles /// Does this job ignore human authority? @@ -543,11 +543,11 @@ dna.species.roundstart_changed = TRUE apply_pref_name(/datum/preference/name/backup_human, player_client) if(CONFIG_GET(flag/force_random_names)) - var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type - - var/gender = player_client.prefs.read_preference(/datum/preference/choiced/gender) - real_name = species.random_name(gender, TRUE) + real_name = generate_random_name_species_based( + player_client.prefs.read_preference(/datum/preference/choiced/gender), + TRUE, + player_client.prefs.read_preference(/datum/preference/choiced/species), + ) dna.update_dna_identity() @@ -569,9 +569,11 @@ if(!player_client) return // Disconnected while checking the appearance ban. - var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type - organic_name = species.random_name(player_client.prefs.read_preference(/datum/preference/choiced/gender), TRUE) + organic_name = generate_random_name_species_based( + player_client.prefs.read_preference(/datum/preference/choiced/gender), + TRUE, + player_client.prefs.read_preference(/datum/preference/choiced/species), + ) else if(!player_client) return // Disconnected while checking the appearance ban. diff --git a/code/modules/jobs/job_types/chaplain/chaplain.dm b/code/modules/jobs/job_types/chaplain/chaplain.dm index 58821ec535876..8bcfaefcfc67a 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain.dm @@ -69,7 +69,7 @@ var/new_bible = player_client?.prefs?.read_preference(/datum/preference/name/bible) || DEFAULT_BIBLE holy_bible.deity_name = new_deity - switch(lowertext(new_religion)) + switch(LOWER_TEXT(new_religion)) if("homosexuality", "gay", "penis", "ass", "cock", "cocks") new_bible = pick("Guys Gone Wild","Coming Out of The Closet","War of Cocks") switch(new_bible) diff --git a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm index 74b1cdcf627d2..ec484ebe6ebc5 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm @@ -154,7 +154,7 @@ If the scythe isn't empowered when you sheath it, you take a heap of damage and if(do_after(user, 15 SECONDS * death_knell_speed_mod, target = potential_reaping)) playsound(get_turf(potential_reaping), 'sound/weapons/bladeslice.ogg', 250, TRUE) reaped_head.dismember() - user.visible_message(span_danger("[user] swings the [src] down, slicing [potential_reaping]'s [head_name] clean off! You think the [src] may have grown stronger!"), span_notice("As you perform the death knell on [potential_reaping], the [src] gains power! For a time...")) + user.visible_message(span_danger("[user] swings [src] down, slicing [potential_reaping]'s [head_name] clean off! You think [src] may have grown stronger!"), span_notice("As you perform the death knell on [potential_reaping], [src] gains power! For a time...")) if(potential_empowerment == SCYTHE_SATED) //We don't want actual player heads to go wandering off, but it'll be funny if a bunch of monkeyhuman heads started floating around reaped_head.AddComponent(/datum/component/haunted_item, \ haunt_color = "#7be595", \ diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm index 01d144b4a5171..e9b40d43e05e6 100644 --- a/code/modules/jobs/job_types/clown.dm +++ b/code/modules/jobs/job_types/clown.dm @@ -57,6 +57,7 @@ /obj/item/reagent_containers/spray/waterflower = 1, /obj/item/food/grown/banana = 1, /obj/item/instrument/bikehorn = 1, + /obj/item/storage/box/balloons = 1, ) belt = /obj/item/modular_computer/pda/clown ears = /obj/item/radio/headset/headset_srv @@ -72,6 +73,7 @@ box = /obj/item/storage/box/survival/hug chameleon_extras = /obj/item/stamp/clown implants = list(/obj/item/implant/sad_trombone) + skillchips = list(/obj/item/skillchip/job/clown) /datum/outfit/job/clown/mod name = "Clown (MODsuit)" diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index e3a396609eb26..a0f2971df2306 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -4,8 +4,8 @@ scan everyone in sight" department_head = list(JOB_CHIEF_MEDICAL_OFFICER) faction = FACTION_STATION - total_positions = 5 - spawn_positions = 3 + total_positions = 6 + spawn_positions = 4 supervisors = SUPERVISOR_CMO exp_granted_type = EXP_TYPE_CREW config_tag = "MEDICAL_DOCTOR" diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm index fd6f0f939d68a..1d4be888e9678 100644 --- a/code/modules/jobs/job_types/prisoner.dm +++ b/code/modules/jobs/job_types/prisoner.dm @@ -69,9 +69,9 @@ . = ..() var/crime_name = new_prisoner.client?.prefs?.read_preference(/datum/preference/choiced/prisoner_crime) - if(!crime_name) - return var/datum/prisoner_crime/crime = GLOB.prisoner_crimes[crime_name] + if (isnull(crime)) + return var/list/limbs_to_tat = new_prisoner.bodyparts.Copy() for(var/i in 1 to crime.tattoos) if(!length(SSpersistence.prison_tattoos_to_use) || visualsOnly) diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 1142ba033ff75..bcf34c372285d 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -76,7 +76,7 @@ messenger = /obj/item/storage/backpack/messenger/science chameleon_extras = /obj/item/stamp/head/rd - skillchips = list(/obj/item/skillchip/job/research_director) + skillchips = list(/obj/item/skillchip/research_director, /obj/item/skillchip/job/roboticist) /datum/outfit/job/rd/mod name = "Research Director (MODsuit)" diff --git a/code/modules/jobs/job_types/station_trait/human_ai.dm b/code/modules/jobs/job_types/station_trait/human_ai.dm index 285479a691261..af80df69fe8c4 100644 --- a/code/modules/jobs/job_types/station_trait/human_ai.dm +++ b/code/modules/jobs/job_types/station_trait/human_ai.dm @@ -148,8 +148,8 @@ return ..() /obj/item/secure_camera_console_pod - name = "advanced camera control pod" - desc = "Calls down a secure camera console to use for all your AI stuff, may only be activated in the SAT." + name = "pre-packaged advanced camera control" + desc = "A pre-packaged camera console used for all your AI stuff, programmed to only active in the SAT." icon = 'icons/obj/devices/remote.dmi' icon_state = "botpad_controller" inhand_icon_state = "radio" @@ -163,9 +163,9 @@ if(!is_type_in_typecache(current_area, allowed_areas)) user.balloon_alert(user, "not in the sat!") return - podspawn(list( - "target" = get_turf(src), - "style" = STYLE_BLUESPACE, - "spawn" = /obj/machinery/computer/camera_advanced, - )) + user.balloon_alert(user, "unpacking...") + if(!do_after(user, 5 SECONDS, src)) + return + playsound(src, 'sound/items/drill_use.ogg', 40, TRUE) + new /obj/machinery/computer/camera_advanced/human_ai(get_turf(src)) qdel(src) diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm deleted file mode 100644 index bdbfd7d687ca4..0000000000000 --- a/code/modules/jobs/job_types/virologist.dm +++ /dev/null @@ -1,60 +0,0 @@ -/datum/job/virologist - title = JOB_VIROLOGIST - description = "Study the effects of various diseases and synthesize a \ - vaccine for them. Engineer beneficial viruses." - department_head = list(JOB_CHIEF_MEDICAL_OFFICER) - faction = FACTION_STATION - total_positions = 1 - spawn_positions = 1 - supervisors = SUPERVISOR_CMO - exp_requirements = 60 - exp_required_type = EXP_TYPE_CREW - exp_granted_type = EXP_TYPE_CREW - config_tag = "VIROLOGIST" - - outfit = /datum/outfit/job/virologist - plasmaman_outfit = /datum/outfit/plasmaman/viro - - paycheck = PAYCHECK_CREW - paycheck_department = ACCOUNT_MED - - liver_traits = list(TRAIT_MEDICAL_METABOLISM) - - display_order = JOB_DISPLAY_ORDER_VIROLOGIST - bounty_types = CIV_JOB_VIRO - departments_list = list( - /datum/job_department/medical, - ) - - family_heirlooms = list(/obj/item/reagent_containers/syringe, /obj/item/statuebust/hippocratic) - - mail_goodies = list( - /obj/item/reagent_containers/cup/bottle/random_virus = 15, - /obj/item/reagent_containers/cup/bottle/formaldehyde = 10, - /obj/item/reagent_containers/cup/bottle/synaptizine = 10, - /obj/item/stack/sheet/mineral/plasma = 10, - /obj/item/stack/sheet/mineral/uranium = 5, - ) - rpg_title = "Plague Doctor" - job_flags = STATION_JOB_FLAGS - - -/datum/outfit/job/virologist - name = "Virologist" - jobtype = /datum/job/virologist - - id_trim = /datum/id_trim/job/virologist - uniform = /obj/item/clothing/under/rank/medical/virologist - suit = /obj/item/clothing/suit/toggle/labcoat/virologist - suit_store = /obj/item/flashlight/pen - belt = /obj/item/modular_computer/pda/viro - ears = /obj/item/radio/headset/headset_med - mask = /obj/item/clothing/mask/surgical - shoes = /obj/item/clothing/shoes/sneakers/white - - backpack = /obj/item/storage/backpack/virology - satchel = /obj/item/storage/backpack/satchel/vir - duffelbag = /obj/item/storage/backpack/duffelbag/virology - messenger = /obj/item/storage/backpack/messenger/vir - - box = /obj/item/storage/box/survival/medical diff --git a/code/modules/jobs/jobs.dm b/code/modules/jobs/jobs.dm index a0b0ebee560e8..0c2731c268e7d 100644 --- a/code/modules/jobs/jobs.dm +++ b/code/modules/jobs/jobs.dm @@ -56,7 +56,7 @@ GLOBAL_PROTECT(exp_specialmap) var/static/regex/chef_expand = new("chef") var/static/regex/borg_expand = new("(? SCRAMBLE_CACHE_LEN) + scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1) + +/datum/language/proc/scramble(input) + + if(!length(syllables)) + return stars(input) + + // If the input is cached already, move it to the end of the cache and return it + var/lookup = check_cache(input) + if(lookup) + return lookup + + var/input_size = length_char(input) + var/scrambled_text = "" + var/capitalize = TRUE + + while(length_char(scrambled_text) < input_size) + var/next = (length(scrambled_text) && length(special_characters) && prob(1)) ? pick(special_characters) : pick_weight_recursive(syllables) + if(capitalize) + next = capitalize(next) + capitalize = FALSE + scrambled_text += next + var/chance = rand(100) + if(chance <= sentence_chance) + scrambled_text += ". " + capitalize = TRUE + else if(chance > sentence_chance && chance <= space_chance) + scrambled_text += " " + + scrambled_text = trim(scrambled_text) + var/ending = copytext_char(scrambled_text, -1) + if(ending == ".") + scrambled_text = copytext_char(scrambled_text, 1, -2) + var/input_ending = copytext_char(input, -1) + if(input_ending in list("!","?",".")) + scrambled_text += input_ending + + add_to_cache(input, scrambled_text) + + return scrambled_text + +#undef SCRAMBLE_CACHE_LEN diff --git a/code/modules/language/language_holder.dm b/code/modules/language/_language_holder.dm similarity index 100% rename from code/modules/language/language_holder.dm rename to code/modules/language/_language_holder.dm diff --git a/code/modules/language/language_manuals.dm b/code/modules/language/_language_manuals.dm similarity index 100% rename from code/modules/language/language_manuals.dm rename to code/modules/language/_language_manuals.dm diff --git a/code/modules/language/language_menu.dm b/code/modules/language/_language_menu.dm similarity index 100% rename from code/modules/language/language_menu.dm rename to code/modules/language/_language_menu.dm diff --git a/code/modules/language/aphasia.dm b/code/modules/language/aphasia.dm index 9d4e317c4d881..2d82b79892ee7 100644 --- a/code/modules/language/aphasia.dm +++ b/code/modules/language/aphasia.dm @@ -7,3 +7,4 @@ space_chance = 20 default_priority = 10 icon_state = "aphasia" + always_use_default_namelist = TRUE // Shouldn't generate names for this anyways diff --git a/code/modules/language/beachbum.dm b/code/modules/language/beachbum.dm index d78be9788f35b..bd319e717ffd0 100644 --- a/code/modules/language/beachbum.dm +++ b/code/modules/language/beachbum.dm @@ -17,5 +17,5 @@ "heavy", "stellar", "excellent", "triumphant", "babe", "four", "tail", "trim", "tube", "wobble", "roll", "gnarly", "epic", ) - icon_state = "beach" + always_use_default_namelist = TRUE diff --git a/code/modules/language/buzzwords.dm b/code/modules/language/buzzwords.dm index c46088c0ad5b9..2ed033bca345b 100644 --- a/code/modules/language/buzzwords.dm +++ b/code/modules/language/buzzwords.dm @@ -8,3 +8,4 @@ ) icon_state = "buzz" default_priority = 90 + always_use_default_namelist = TRUE // Otherwise we get Bzzbzbz Zzzbzbz. diff --git a/code/modules/language/calcic.dm b/code/modules/language/calcic.dm index f4882e1105b95..477e442203bc1 100644 --- a/code/modules/language/calcic.dm +++ b/code/modules/language/calcic.dm @@ -13,4 +13,16 @@ icon_state = "calcic" default_priority = 90 +/datum/language/calcic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + + return "[pick(GLOB.plasmaman_names)] \Roman[rand(1, 99)]" + // Yeah, this goes to skeletons too, since it's basically just skeleton clacking. diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm index 09db7ef511b4b..242095b3bb7fa 100644 --- a/code/modules/language/codespeak.dm +++ b/code/modules/language/codespeak.dm @@ -5,6 +5,7 @@ default_priority = 0 flags = TONGUELESS_SPEECH | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD icon_state = "codespeak" + always_use_default_namelist = TRUE // No syllables anyways /datum/language/codespeak/scramble(input) var/lookup = check_cache(input) diff --git a/code/modules/language/common.dm b/code/modules/language/common.dm index 2dc7294983c0a..6bad808fef262 100644 --- a/code/modules/language/common.dm +++ b/code/modules/language/common.dm @@ -7,50 +7,51 @@ default_priority = 100 icon_state = "galcom" - -//Syllable Lists -/* - This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed, - and the english syllables had to be duplicated so that there is roughly a 50-50 weighting. - - Sources: - http://www.sttmedia.com/syllablefrequency-english - http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm -*/ -/datum/language/common/syllables = list( - // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese - list( - "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", - "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", - "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", - "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", - "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", - "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", - "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", - "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", - "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", - "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", - "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", - "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", - "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", - "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", - "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", - "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", - "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", - "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", - "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", - "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", - "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", - "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", - "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", - "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", - "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", - "zong", "zou", "zuan", "zui", "zun", "zuo", "zu", - ), - list( - "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", - "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", - "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", - "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", - ), -) + // Default namelist is the human namelist, and common is the human language, so might as well. + // Feel free to remove this at some point because common can generate some pretty cool names. + always_use_default_namelist = TRUE + /** + * This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed, + * and the english syllables had to be duplicated so that there is roughly a 50-50 weighting. + * + * Sources: + * http://www.sttmedia.com/syllablefrequency-english + * http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm + */ + syllables = list( + // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese + list( + "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", + "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", + "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", + "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", + "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", + "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", + "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", + "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", + "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", + "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", + "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", + "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", + "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", + "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", + "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", + "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", + "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", + "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", + "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", + "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", + "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", + "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", + "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", + "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", + "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", + "zong", "zou", "zuan", "zui", "zun", "zuo", "zu", + ), + list( + "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", + "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", + "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", + "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", + ), + ) diff --git a/code/modules/language/draconic.dm b/code/modules/language/draconic.dm index f812c8dc1311a..55ebd1ec20267 100644 --- a/code/modules/language/draconic.dm +++ b/code/modules/language/draconic.dm @@ -13,5 +13,25 @@ "ra", "ar", "re", "er", "ri", "ir", "ro", "or", "ru", "ur", "rs", "sr", "a", "a", "e", "e", "i", "i", "o", "o", "u", "u", "s", "s" ) + special_characters = list("-") icon_state = "lizard" default_priority = 90 + default_name_syllable_min = 3 + default_name_syllable_max = 5 + random_name_spacer = "-" + +/datum/language/draconic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + if(gender != MALE) + gender = pick(MALE, FEMALE) + + if(gender == MALE) + return "[pick(GLOB.lizard_names_male)][random_name_spacer][pick(GLOB.lizard_names_male)]" + return "[pick(GLOB.lizard_names_female)][random_name_spacer][pick(GLOB.lizard_names_female)]" diff --git a/code/modules/language/drone.dm b/code/modules/language/drone.dm index 5b47533d45e3a..09fb6546e4a16 100644 --- a/code/modules/language/drone.dm +++ b/code/modules/language/drone.dm @@ -11,3 +11,4 @@ default_priority = 20 icon_state = "drone" + always_use_default_namelist = TRUE // Nonsense language diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm deleted file mode 100644 index a47d097dd1407..0000000000000 --- a/code/modules/language/language.dm +++ /dev/null @@ -1,107 +0,0 @@ -#define SCRAMBLE_CACHE_LEN 50 //maximum of 50 specific scrambled lines per language - -/* - Datum based languages. Easily editable and modular. -*/ - -/datum/language - var/name = "an unknown language" // Fluff name of language if any. - var/desc = "A language." // Short description for 'Check Languages'. - var/key // Character used to speak in language - // If key is null, then the language isn't real or learnable. - var/flags // Various language flags. - var/list/syllables // Used when scrambling text for a non-speaker. - var/sentence_chance = 5 // Likelihood of making a new sentence after each syllable. - var/space_chance = 55 // Likelihood of getting a space in the random scramble string - var/list/spans = list() - var/list/scramble_cache = list() - var/default_priority = 0 // the language that an atom knows with the highest "default_priority" is selected by default. - - // if you are seeing someone speak popcorn language, then something is wrong. - var/icon = 'icons/misc/language.dmi' - var/icon_state = "popcorn" - -/datum/language/proc/display_icon(atom/movable/hearer) - var/understands = hearer.has_language(src.type) - if(flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD && understands) - return FALSE - if(flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD && !understands) - return FALSE - return TRUE - -/datum/language/proc/get_icon() - var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat) - return sheet.icon_tag("language-[icon_state]") - -/datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) - if(!syllables || !syllables.len) - if(gender == FEMALE) - return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) - else - return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - - var/full_name = "" - var/new_name = "" - - for(var/i in 0 to name_count) - new_name = "" - var/Y = rand(FLOOR(syllable_count/syllable_divisor, 1), syllable_count) - for(var/x in Y to 0) - new_name += pick_weight_recursive(syllables) - full_name += " [capitalize(lowertext(new_name))]" - - return "[trim(full_name)]" - -/datum/language/proc/check_cache(input) - var/lookup = scramble_cache[input] - if(lookup) - scramble_cache -= input - scramble_cache[input] = lookup - . = lookup - -/datum/language/proc/add_to_cache(input, scrambled_text) - // Add it to cache, cutting old entries if the list is too long - scramble_cache[input] = scrambled_text - if(scramble_cache.len > SCRAMBLE_CACHE_LEN) - scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1) - -/datum/language/proc/scramble(input) - - if(!syllables || !syllables.len) - return stars(input) - - // If the input is cached already, move it to the end of the cache and return it - var/lookup = check_cache(input) - if(lookup) - return lookup - - var/input_size = length_char(input) - var/scrambled_text = "" - var/capitalize = TRUE - - while(length_char(scrambled_text) < input_size) - var/next = pick_weight_recursive(syllables) - if(capitalize) - next = capitalize(next) - capitalize = FALSE - scrambled_text += next - var/chance = rand(100) - if(chance <= sentence_chance) - scrambled_text += ". " - capitalize = TRUE - else if(chance > sentence_chance && chance <= space_chance) - scrambled_text += " " - - scrambled_text = trim(scrambled_text) - var/ending = copytext_char(scrambled_text, -1) - if(ending == ".") - scrambled_text = copytext_char(scrambled_text, 1, -2) - var/input_ending = copytext_char(input, -1) - if(input_ending in list("!","?",".")) - scrambled_text += input_ending - - add_to_cache(input, scrambled_text) - - return scrambled_text - -#undef SCRAMBLE_CACHE_LEN diff --git a/code/modules/language/machine.dm b/code/modules/language/machine.dm index 36962a712a1b5..4be282a5e2812 100644 --- a/code/modules/language/machine.dm +++ b/code/modules/language/machine.dm @@ -14,7 +14,16 @@ icon_state = "eal" -/datum/language/machine/get_random_name() +/datum/language/machine/get_random_name( + gender = NEUTER, + name_count = 2, + syllable_min = 2, + syllable_max = 4, + unique = FALSE, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() if(prob(70)) return "[pick(GLOB.posibrain_names)]-[rand(100, 999)]" return pick(GLOB.ai_names) diff --git a/code/modules/language/moffic.dm b/code/modules/language/moffic.dm index 1d0aea96697fb..fb8dea63dcc83 100644 --- a/code/modules/language/moffic.dm +++ b/code/modules/language/moffic.dm @@ -13,4 +13,20 @@ icon_state = "moth" default_priority = 90 + default_name_syllable_min = 5 + default_name_syllable_max = 10 + +/datum/language/moffic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + + return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]" + + // Fuck guest accounts, and fuck language testing. diff --git a/code/modules/language/monkey.dm b/code/modules/language/monkey.dm index e44f6a6268e25..423e94f22bd8c 100644 --- a/code/modules/language/monkey.dm +++ b/code/modules/language/monkey.dm @@ -7,3 +7,12 @@ default_priority = 80 icon_state = "animal" + +/datum/language/monkey/get_random_name( + gender = NEUTER, + name_count = 2, + syllable_min = 2, + syllable_max = 4, + force_use_syllables = FALSE, +) + return "monkey ([rand(1, 999)])" diff --git a/code/modules/language/mushroom.dm b/code/modules/language/mushroom.dm index 08d494cc04d64..910489fd6dd9e 100644 --- a/code/modules/language/mushroom.dm +++ b/code/modules/language/mushroom.dm @@ -5,3 +5,5 @@ sentence_chance = 0 default_priority = 80 syllables = list("poof", "pff", "pFfF", "piff", "puff", "pooof", "pfffff", "piffpiff", "puffpuff", "poofpoof", "pifpafpofpuf") + default_name_syllable_min = 1 + default_name_syllable_max = 2 diff --git a/code/modules/language/nekomimetic.dm b/code/modules/language/nekomimetic.dm index 82edc2afcb57a..4be943f84417a 100644 --- a/code/modules/language/nekomimetic.dm +++ b/code/modules/language/nekomimetic.dm @@ -12,3 +12,16 @@ ) icon_state = "neko" default_priority = 90 + default_name_syllable_min = 2 + default_name_syllable_max = 2 + +/datum/language/nekomimetic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(prob(33)) + return default_name(gender) + return ..() diff --git a/code/modules/language/piratespeak.dm b/code/modules/language/piratespeak.dm index 5f6cb4897715d..a2faddb544f7c 100644 --- a/code/modules/language/piratespeak.dm +++ b/code/modules/language/piratespeak.dm @@ -10,3 +10,4 @@ "shiver", "timbers", "matey", "swashbuckler" ) icon_state = "pirate" + always_use_default_namelist = TRUE diff --git a/code/modules/language/shadowtongue.dm b/code/modules/language/shadowtongue.dm index 9c0adb5eea3ff..351589393856b 100644 --- a/code/modules/language/shadowtongue.dm +++ b/code/modules/language/shadowtongue.dm @@ -16,3 +16,5 @@ ) icon_state = "shadow" default_priority = 90 + default_name_syllable_min = 2 + default_name_syllable_max = 3 diff --git a/code/modules/language/slime.dm b/code/modules/language/slime.dm index fcb471774118a..15960898673d6 100644 --- a/code/modules/language/slime.dm +++ b/code/modules/language/slime.dm @@ -2,7 +2,8 @@ name = "Slime" desc = "A melodic and complex language spoken by slimes. Some of the notes are inaudible to humans." key = "k" - syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!") + syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix") + special_characters = list("!","*") default_priority = 70 icon_state = "slime" diff --git a/code/modules/language/sylvan.dm b/code/modules/language/sylvan.dm index 68cb73f9d525a..4f66fb5931c1a 100644 --- a/code/modules/language/sylvan.dm +++ b/code/modules/language/sylvan.dm @@ -13,3 +13,5 @@ ) icon_state = "plant" default_priority = 90 + default_name_syllable_min = 2 + default_name_syllable_max = 3 diff --git a/code/modules/language/terrum.dm b/code/modules/language/terrum.dm index 361106ed16c93..63b527202f4ca 100644 --- a/code/modules/language/terrum.dm +++ b/code/modules/language/terrum.dm @@ -7,8 +7,25 @@ "sha", "vu", "nah", "ha", "yom", "ma", "cha", "ar", "et", "mol", "lua", "ch", "na", "sh", "ni", "yah", "bes", "ol", "hish", "ev", "la", "ot", "la", "khe", "tza", "chak", "hak", "hin", "hok", "lir", "tov", "yef", "yfe", - "cho", "ar", "kas", "kal", "ra", "lom", "im", "'", "'", "'", "'", "bok", + "cho", "ar", "kas", "kal", "ra", "lom", "im", "bok", "erev", "shlo", "lo", "ta", "im", "yom" ) + special_characters = list("'") icon_state = "golem" default_priority = 90 + +/datum/language/terrum/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + + var/name = pick(GLOB.golem_names) + // 3% chance to be given a human surname for "lore reasons" + if (prob(3)) + name += " [pick(GLOB.last_names)]" + return name diff --git a/code/modules/language/voltaic.dm b/code/modules/language/voltaic.dm index 40fa9dcb1e826..90ab90dbe48e0 100644 --- a/code/modules/language/voltaic.dm +++ b/code/modules/language/voltaic.dm @@ -12,3 +12,21 @@ ) icon_state = "volt" default_priority = 90 + default_name_syllable_min = 2 + default_name_syllable_max = 3 + + +/datum/language/voltaic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + + var/picked = "[pick(GLOB.ethereal_names)] [random_capital_letter()]" + if(prob(65)) + picked += random_capital_letter() + return picked diff --git a/code/modules/language/xenocommon.dm b/code/modules/language/xenocommon.dm index c5e6366715d8e..f4949b7d73cb4 100644 --- a/code/modules/language/xenocommon.dm +++ b/code/modules/language/xenocommon.dm @@ -6,3 +6,4 @@ default_priority = 50 icon_state = "xeno" + always_use_default_namelist = TRUE // Sssss Ssss? diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 656c90d77bbda..31630c550a1d5 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -324,6 +324,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( if(cultist) cultist.silent = TRUE cultist.on_removal() + SSblackbox.record_feedback("tally", "cult_shade_purified", 1) shade.theme = THEME_HOLY shade.name = "Purified [shade.real_name]" shade.update_appearance(UPDATE_ICON_STATE) diff --git a/code/modules/library/bookcase.dm b/code/modules/library/bookcase.dm index be2beca42bad7..822e4ae583c97 100644 --- a/code/modules/library/bookcase.dm +++ b/code/modules/library/bookcase.dm @@ -172,14 +172,13 @@ choice.forceMove(drop_location()) update_appearance() -/obj/structure/bookcase/deconstruct(disassembled = TRUE) +/obj/structure/bookcase/atom_deconstruct(disassembled = TRUE) var/atom/Tsec = drop_location() new /obj/item/stack/sheet/mineral/wood(Tsec, 4) for(var/obj/item/I in contents) if(!isbook(I)) //Wake me up inside continue I.forceMove(Tsec) - return ..() /obj/structure/bookcase/update_icon_state() if(state == BOOKCASE_UNANCHORED || state == BOOKCASE_ANCHORED) diff --git a/code/modules/library/skill_learning/job_skillchips/research_director.dm b/code/modules/library/skill_learning/generic_skillchips/rod_suplex.dm similarity index 85% rename from code/modules/library/skill_learning/job_skillchips/research_director.dm rename to code/modules/library/skill_learning/generic_skillchips/rod_suplex.dm index 899defb1fd5af..b889073909d61 100644 --- a/code/modules/library/skill_learning/job_skillchips/research_director.dm +++ b/code/modules/library/skill_learning/generic_skillchips/rod_suplex.dm @@ -1,4 +1,4 @@ -/obj/item/skillchip/job/research_director +/obj/item/skillchip/research_director name = "R.D.S.P.L.X. skillchip" desc = "Knowledge of how to solve the ancient conumdrum; what happens when an unstoppable force meets an immovable object." auto_traits = list(TRAIT_ROD_SUPLEX) @@ -7,3 +7,6 @@ skill_icon = "dumbbell" activate_message = "You realise if you apply the correct force, at the correct angle, it is possible to make the immovable permanently movable." deactivate_message = "You forget how to permanently anchor a paradoxical object." + chip_category = SKILLCHIP_CATEGORY_GENERAL + skillchip_flags = NONE + slot_use = 1 diff --git a/code/modules/library/skill_learning/job_skillchips/_job.dm b/code/modules/library/skill_learning/job_skillchips/_job.dm index 87f2d47ac9cd5..23381d06066b2 100644 --- a/code/modules/library/skill_learning/job_skillchips/_job.dm +++ b/code/modules/library/skill_learning/job_skillchips/_job.dm @@ -1,11 +1,6 @@ -/// Job related skillchip category -#define SKILLCHIP_CATEGORY_JOB "job" - /obj/item/skillchip/job skillchip_flags = SKILLCHIP_RESTRICTED_CATEGORIES chip_category = SKILLCHIP_CATEGORY_JOB incompatibility_list = list(SKILLCHIP_CATEGORY_JOB) abstract_parent_type = /obj/item/skillchip/job slot_use = 2 - -#undef SKILLCHIP_CATEGORY_JOB diff --git a/code/modules/library/skill_learning/job_skillchips/clown.dm b/code/modules/library/skill_learning/job_skillchips/clown.dm new file mode 100644 index 0000000000000..3cd88ff70963d --- /dev/null +++ b/code/modules/library/skill_learning/job_skillchips/clown.dm @@ -0,0 +1,10 @@ +/obj/item/skillchip/job/clown + name = "B@L00NY skillchip" + desc = "This biochip contain several terabytes of uncannily religious, Honkmother praising guides on how to reshape balloons into silly animals." + auto_traits = list(TRAIT_BALLOON_SUTRA) + skill_name = "Balloon Sutra" + skill_description = "Learn the the ancient Honkmotherian arts of balloon-sutra." + skill_icon = "face-grin-tears" + activate_message = span_notice("Blessed wisdom of Honkmother enwraps you, and with it, governship upon form of balloonkind.") + deactivate_message = span_notice("'Remember, then, that true clownery requires freedom and willingness to bend, like ones of a floating balloon.'... Whatever that meant?") + diff --git a/code/modules/library/skill_learning/skillchip.dm b/code/modules/library/skill_learning/skillchip.dm index 9657a33052729..ae40b84c64be9 100644 --- a/code/modules/library/skill_learning/skillchip.dm +++ b/code/modules/library/skill_learning/skillchip.dm @@ -1,10 +1,3 @@ -// Skillchip categories -//Various skillchip categories. Use these when setting which categories a skillchip restricts being paired with -//while using the SKILLCHIP_RESTRICTED_CATEGORIES flag -/// General related skillchip category -#define SKILLCHIP_CATEGORY_GENERAL "general" - - /obj/item/skillchip name = "skillchip" desc = "This biochip integrates with user's brain to enable mastery of specific skill. Consult certified Nanotrasen neurosurgeon before use." @@ -531,5 +524,3 @@ ADD_TRAIT(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT) source.adjustStaminaLoss(20) addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT), FLIP_EMOTE_DURATION + 0.1 SECONDS) - -#undef SKILLCHIP_CATEGORY_GENERAL diff --git a/code/modules/logging/log_holder.dm b/code/modules/logging/log_holder.dm index 1102df45f4f2a..85a436076c84e 100644 --- a/code/modules/logging/log_holder.dm +++ b/code/modules/logging/log_holder.dm @@ -32,10 +32,8 @@ GLOBAL_REAL(logger, /datum/log_holder) GENERAL_PROTECT_DATUM(/datum/log_holder) -/client/proc/log_viewer_new() - set name = "View Round Logs" - set category = "Admin" - logger.ui_interact(mob) +ADMIN_VERB(log_viewer_new, R_ADMIN|R_DEBUG, "View Round Logs", "View the rounds logs.", ADMIN_CATEGORY_MAIN) + logger.ui_interact(user.mob) /datum/log_holder/ui_interact(mob/user, datum/tgui/ui) if(!check_rights_for(user.client, R_ADMIN)) @@ -107,11 +105,10 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) return switch(action) - if("re-render") + if("refresh") cache_ui_data() SStgui.update_uis(src) return TRUE - else stack_trace("unknown ui_act action [action] for [type]") diff --git a/code/modules/lootpanel/_lootpanel.dm b/code/modules/lootpanel/_lootpanel.dm new file mode 100644 index 0000000000000..339a79d77fa6f --- /dev/null +++ b/code/modules/lootpanel/_lootpanel.dm @@ -0,0 +1,75 @@ +/** + * ## Loot panel + * A datum that stores info containing the contents of a turf. + * Handles opening the lootpanel UI and searching the turf for items. + */ +/datum/lootpanel + /// The owner of the panel + var/client/owner + /// The list of all search objects indexed. + var/list/datum/search_object/contents = list() + /// The list of search_objects needing processed + var/list/datum/search_object/to_image = list() + /// We've been notified about client version + var/notified = FALSE + /// The turf being searched + var/turf/source_turf + + +/datum/lootpanel/New(client/owner) + . = ..() + + src.owner = owner + + +/datum/lootpanel/Destroy(force) + reset_contents() + owner = null + source_turf = null + + return ..() + + +/datum/lootpanel/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "LootPanel") + ui.set_autoupdate(FALSE) + ui.open() + + +/datum/lootpanel/ui_close(mob/user) + . = ..() + + source_turf = null + reset_contents() + + +/datum/lootpanel/ui_data(mob/user) + var/list/data = list() + + data["contents"] = get_contents() + data["searching"] = length(to_image) + + return data + + +/datum/lootpanel/ui_status(mob/user, datum/ui_state/state) + if(user.incapacitated()) + return UI_DISABLED + + return UI_INTERACTIVE + + +/datum/lootpanel/ui_act(action, list/params) + . = ..() + if(.) + return + + switch(action) + if("grab") + return grab(usr, params) + if("refresh") + return populate_contents() + + return FALSE diff --git a/code/modules/lootpanel/contents.dm b/code/modules/lootpanel/contents.dm new file mode 100644 index 0000000000000..4bb255b15611b --- /dev/null +++ b/code/modules/lootpanel/contents.dm @@ -0,0 +1,49 @@ +/// Adds the item to contents and to_image (if needed) +/datum/lootpanel/proc/add_to_index(datum/search_object/index) + RegisterSignal(index, COMSIG_QDELETING, PROC_REF(on_searchable_deleted)) + if(isnull(index.icon)) + to_image += index + + contents += index + + +/// Used to populate contents and start generating if needed +/datum/lootpanel/proc/populate_contents() + if(length(contents)) + reset_contents() + + // Add source turf first + var/datum/search_object/source = new(owner, source_turf) + add_to_index(source) + + for(var/atom/thing as anything in source_turf.contents) + // validate + if(thing.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) + continue + if(thing.IsObscured()) + continue + if(thing.invisibility > owner.mob.see_invisible) + continue + + // convert + var/datum/search_object/index = new(owner, thing) + add_to_index(index) + + var/datum/tgui/window = SStgui.get_open_ui(owner.mob, src) + window?.send_update() + + if(length(to_image)) + SSlooting.backlog += src + + +/// For: Resetting to empty. Ignores the searchable qdel event +/datum/lootpanel/proc/reset_contents() + for(var/datum/search_object/index as anything in contents) + contents -= index + to_image -= index + + if(QDELETED(index)) + continue + + UnregisterSignal(index, COMSIG_QDELETING) + qdel(index) diff --git a/code/modules/lootpanel/handlers.dm b/code/modules/lootpanel/handlers.dm new file mode 100644 index 0000000000000..40a76974ed4a7 --- /dev/null +++ b/code/modules/lootpanel/handlers.dm @@ -0,0 +1,19 @@ +/// On contents change, either reset or update +/datum/lootpanel/proc/on_searchable_deleted(datum/search_object/source) + SIGNAL_HANDLER + + contents -= source + to_image -= source + + var/datum/tgui/window = SStgui.get_open_ui(owner.mob, src) +#if !defined(UNIT_TESTS) // we dont want to delete contents if we're testing + if(isnull(window)) + reset_contents() + return +#endif + + if(isturf(source.item)) + populate_contents() + return + + window?.send_update() diff --git a/code/modules/lootpanel/misc.dm b/code/modules/lootpanel/misc.dm new file mode 100644 index 0000000000000..6e8448b820528 --- /dev/null +++ b/code/modules/lootpanel/misc.dm @@ -0,0 +1,48 @@ +/// Helper to open the panel +/datum/lootpanel/proc/open(turf/tile) + source_turf = tile + +#if !defined(OPENDREAM) && !defined(UNIT_TESTS) + if(!notified) + var/build = owner.byond_build + var/version = owner.byond_version + if(build < 515 || (build == 515 && version < 1635)) + to_chat(owner.mob, examine_block(span_info("\ + Your version of Byond doesn't support fast image loading.\n\ + Detected: [version].[build]\n\ + Required version for this feature: 515.1635 or later.\n\ + Visit BYOND's website to get the latest version of BYOND.\n\ + "))) + + notified = TRUE +#endif + + populate_contents() + ui_interact(owner.mob) + + +/** + * Called by SSlooting whenever this datum is added to its backlog. + * Iterates over to_image list to create icons, then removes them. + * Returns boolean - whether this proc has finished the queue or not. + */ +/datum/lootpanel/proc/process_images() + for(var/datum/search_object/index as anything in to_image) + to_image -= index + + if(QDELETED(index) || index.icon) + continue + + index.generate_icon(owner) + + if(TICK_CHECK) + break + + var/datum/tgui/window = SStgui.get_open_ui(owner.mob, src) + if(isnull(window)) + reset_contents() + return TRUE + + window.send_update() + + return !length(to_image) diff --git a/code/modules/lootpanel/search_object.dm b/code/modules/lootpanel/search_object.dm new file mode 100644 index 0000000000000..4de60b04a678a --- /dev/null +++ b/code/modules/lootpanel/search_object.dm @@ -0,0 +1,82 @@ +/** + * ## Search Object + * An object for content lists. Compacted item data. + */ +/datum/search_object + /// Item we're indexing + var/atom/item + /// Url to the image of the object + var/icon + /// Icon state, for inexpensive icons + var/icon_state + /// Name of the original object + var/name + /// Typepath of the original object for ui grouping + var/path + + +/datum/search_object/New(client/owner, atom/item) + . = ..() + + src.item = item + name = item.name + if(isobj(item)) + path = item.type + + if(isturf(item)) + RegisterSignal(item, COMSIG_TURF_CHANGE, PROC_REF(on_turf_change)) + else + RegisterSignals(item, list( + COMSIG_ITEM_PICKUP, + COMSIG_MOVABLE_MOVED, + COMSIG_QDELETING, + ), PROC_REF(on_item_moved)) + + // Icon generation conditions ////////////// + // Condition 1: Icon is complex + if(ismob(item) || length(item.overlays) > 2) + return + + // Condition 2: Can't get icon path + if(!isfile(item.icon) || !length("[item.icon]")) + return + + // Condition 3: Using opendream +#if defined(OPENDREAM) || defined(UNIT_TESTS) + return +#endif + + // Condition 4: Using older byond version + var/build = owner.byond_build + var/version = owner.byond_version + if(build < 515 || (build == 515 && version < 1635)) + icon = "n/a" + return + + icon = "[item.icon]" + icon_state = item.icon_state + + +/datum/search_object/Destroy(force) + item = null + + return ..() + + +/// Generates the icon for the search object. This is the expensive part. +/datum/search_object/proc/generate_icon(client/owner) + icon = costly_icon2html(item, owner, sourceonly = TRUE) + + +/// Parent item has been altered, search object no longer valid +/datum/search_object/proc/on_item_moved(atom/source) + SIGNAL_HANDLER + + qdel(src) + + +/// Parent tile has been altered, entire search needs reset +/datum/search_object/proc/on_turf_change(turf/source, path, list/new_baseturfs, flags, list/post_change_callbacks) + SIGNAL_HANDLER + + post_change_callbacks += CALLBACK(src, GLOBAL_PROC_REF(qdel), src) diff --git a/code/modules/lootpanel/ss_looting.dm b/code/modules/lootpanel/ss_looting.dm new file mode 100644 index 0000000000000..94e12f88f9521 --- /dev/null +++ b/code/modules/lootpanel/ss_looting.dm @@ -0,0 +1,40 @@ + +/// Queues image generation for search objects without icons +SUBSYSTEM_DEF(looting) + name = "Loot Icon Generation" + flags = SS_NO_INIT + priority = FIRE_PRIORITY_PROCESS + runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT + wait = 0.5 SECONDS + /// Backlog of items. Gets put into processing + var/list/datum/lootpanel/backlog = list() + /// Actively processing items + var/list/datum/lootpanel/processing = list() + + +/datum/controller/subsystem/looting/stat_entry(msg) + msg = "P:[length(backlog)]" + return ..() + + +/datum/controller/subsystem/looting/fire(resumed) + if(!length(backlog)) + return + + if(!resumed) + processing = backlog + backlog = list() + + while(length(processing)) + var/datum/lootpanel/panel = processing[length(processing)] + if(QDELETED(panel) || !length(panel.to_image)) + processing.len-- + continue + + if(!panel.process_images()) + backlog += panel + + if(MC_TICK_CHECK) + return + + processing.len-- diff --git a/code/modules/lootpanel/ui.dm b/code/modules/lootpanel/ui.dm new file mode 100644 index 0000000000000..14d41b02b7946 --- /dev/null +++ b/code/modules/lootpanel/ui.dm @@ -0,0 +1,47 @@ +/// UI helper for converting the associative list to a list of lists +/datum/lootpanel/proc/get_contents() + var/list/items = list() + + for(var/datum/search_object/index as anything in contents) + UNTYPED_LIST_ADD(items, list( + "icon_state" = index.icon_state, + "icon" = index.icon, + "name" = index.name, + "path" = index.path, + "ref" = REF(index), + )) + + return items + + +/// Clicks an object from the contents. Validates the object and the user +/datum/lootpanel/proc/grab(mob/user, list/params) + var/ref = params["ref"] + if(isnull(ref)) + return FALSE + + var/datum/search_object/index = locate(ref) in contents + var/atom/thing = index?.item + if(QDELETED(index) || QDELETED(thing)) // Obj is gone + return FALSE + + if(thing != source_turf && !(locate(thing) in source_turf.contents)) + qdel(index) // Item has moved + return TRUE + + var/modifiers = "" + if(params["ctrl"]) + modifiers += "ctrl=1;" + if(params["middle"]) + modifiers += "middle=1;" + if(params["shift"]) + modifiers += "shift=1;" + if(params["alt"]) + modifiers += "alt=1;" + if(params["right"]) + modifiers += "right=1;" + + + user.ClickOn(thing, modifiers) + + return TRUE diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/biodome_winter.dm b/code/modules/mapfluff/ruins/lavalandruin_code/biodome_winter.dm index 770d787f8ad54..7f1c8d781f4f8 100644 --- a/code/modules/mapfluff/ruins/lavalandruin_code/biodome_winter.dm +++ b/code/modules/mapfluff/ruins/lavalandruin_code/biodome_winter.dm @@ -32,7 +32,7 @@ if(ismovable(hit_atom) && !caught && (!thrown_by || thrown_by && COOLDOWN_FINISHED(src, freeze_cooldown))) freeze_hit_atom(hit_atom) if(thrown_by && !caught) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, throw_range+2, throw_speed, null, TRUE), 1) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, throw_range+2, throw_speed, null, TRUE), 0.1 SECONDS) /obj/item/freeze_cube/proc/freeze_hit_atom(atom/movable/hit_atom) playsound(src, 'sound/effects/glassbr3.ogg', 50, TRUE) @@ -45,5 +45,5 @@ else if(isliving(hit_atom)) var/mob/living/hit_mob = hit_atom - SSmove_manager.stop_looping(hit_mob) //stops them mid pathing even if they're stunimmune + GLOB.move_manager.stop_looping(hit_mob) //stops them mid pathing even if they're stunimmune hit_mob.apply_status_effect(/datum/status_effect/ice_block_talisman, 3 SECONDS) diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm index 97a543fa7e727..3c29a6a39450c 100644 --- a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm +++ b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm @@ -107,7 +107,7 @@ /obj/structure/sink/oil_well/attackby(obj/item/O, mob/living/user, params) flick("puddle-oil-splash",src) - if(O.tool_behaviour == TOOL_SHOVEL && !(obj_flags & NO_DECONSTRUCTION)) //attempt to deconstruct the puddle with a shovel + if(O.tool_behaviour == TOOL_SHOVEL) //attempt to deconstruct the puddle with a shovel to_chat(user, "You fill in the oil well with soil.") O.play_tool_sound(src) deconstruct() diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm b/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm index a1391f92ed35e..21c96f0aeaa10 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm @@ -35,11 +35,10 @@ STOP_PROCESSING(SSprocessing, src) return ..() -/obj/structure/lavaland/ash_walker/deconstruct(disassembled) +/obj/structure/lavaland/ash_walker/atom_deconstruct(disassembled) var/core_to_drop = pick(subtypesof(/obj/item/assembly/signaler/anomaly)) new core_to_drop (get_step(loc, pick(GLOB.alldirs))) new /obj/effect/collapse(loc) - return ..() /obj/structure/lavaland/ash_walker/process() consume() diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm b/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm index 8a2949f98935e..1c0a5392fb9b2 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm @@ -159,9 +159,14 @@ mask = /obj/item/clothing/mask/fakemoustache/italian /obj/machinery/vending/hotdog/museum - obj_flags = parent_type::obj_flags|NO_DECONSTRUCTION onstation_override = TRUE +/obj/machinery/vending/hotdog/museum/screwdriver_act(mob/living/user, obj/item/attack_item) + return NONE + +/obj/machinery/vending/hotdog/museum/crowbar_act(mob/living/user, obj/item/attack_item) + return NONE + #define CAFE_KEYCARD_TOILETS "museum_cafe_key_toilets" ///Do not place these beyond the cafeteria shutters, or you might lock people out of reaching it. @@ -185,7 +190,6 @@ return INITIALIZE_HINT_LATELOAD /obj/item/keycard/cafeteria/LateInitialize() - . = ..() if(SSqueuelinks.queues[CAFE_KEYCARD_TOILETS]) SSqueuelinks.pop_link(CAFE_KEYCARD_TOILETS) diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm index 6ce6056b477e7..8dc9cec326d95 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm @@ -262,7 +262,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate) var/static/list/give_turf_traits if(!give_turf_traits) - give_turf_traits = string_list(list(TRAIT_LAVA_STOPPED, TRAIT_CHASM_STOPPED)) + give_turf_traits = string_list(list(TRAIT_LAVA_STOPPED, TRAIT_CHASM_STOPPED, TRAIT_IMMERSE_STOPPED)) AddElement(/datum/element/give_turf_traits, give_turf_traits) /obj/structure/stone_tile/singularity_pull() diff --git a/code/modules/mapfluff/ruins/spaceruin_code/anomalyresearch.dm b/code/modules/mapfluff/ruins/spaceruin_code/anomalyresearch.dm index ba311d44a2ae6..f290c06d78f10 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/anomalyresearch.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/anomalyresearch.dm @@ -17,7 +17,7 @@ /obj/effect/anomaly/flux, /obj/effect/anomaly/bluespace, /obj/effect/anomaly/hallucination, - /obj/effect/anomaly/bioscrambler + /obj/effect/anomaly/bioscrambler/docile ) ///Do we anchor the anomaly? Set to true if you don't want anomalies drifting away (like if theyre in space or something) diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm index 98349ac1cae2f..8906a6d2555cb 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm @@ -344,20 +344,21 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) if(get_dist(get_turf(src), get_turf(user)) <= 1) promptExit(user) -/turf/closed/indestructible/hoteldoor/AltClick(mob/user) - . = ..() - if(get_dist(get_turf(src), get_turf(user)) <= 1) - to_chat(user, span_notice("You peak through the door's bluespace peephole...")) - user.reset_perspective(parentSphere) - var/datum/action/peephole_cancel/PHC = new - user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1) - PHC.Grant(user) - RegisterSignal(user, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/atom/, check_eye), user) - -/turf/closed/indestructible/hoteldoor/check_eye(mob/user) - if(get_dist(get_turf(src), get_turf(user)) >= 2) - for(var/datum/action/peephole_cancel/PHC in user.actions) - INVOKE_ASYNC(PHC, TYPE_PROC_REF(/datum/action/peephole_cancel, Trigger)) +/turf/closed/indestructible/hoteldoor/click_alt(mob/user) + to_chat(user, span_notice("You peak through the door's bluespace peephole...")) + user.reset_perspective(parentSphere) + var/datum/action/peephole_cancel/PHC = new + user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1) + PHC.Grant(user) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(check_eye)) + return CLICK_ACTION_SUCCESS + +/turf/closed/indestructible/hoteldoor/proc/check_eye(mob/user, atom/oldloc, direction) + SIGNAL_HANDLER + if(get_dist(get_turf(src), get_turf(user)) < 2) + return + for(var/datum/action/peephole_cancel/PHC in user.actions) + INVOKE_ASYNC(PHC, TYPE_PROC_REF(/datum/action/peephole_cancel, Trigger)) /datum/action/peephole_cancel name = "Cancel View" diff --git a/code/modules/mapping/mail_sorting_helpers.dm b/code/modules/mapping/mail_sorting_helpers.dm index 964a499860041..259b9ef8f37df 100644 --- a/code/modules/mapping/mail_sorting_helpers.dm +++ b/code/modules/mapping/mail_sorting_helpers.dm @@ -3,10 +3,6 @@ late = TRUE var/sort_type = SORT_TYPE_WASTE -/obj/effect/mapping_helpers/mail_sorting/Initialize(mapload) - ..() - return INITIALIZE_HINT_LATELOAD - /obj/effect/mapping_helpers/mail_sorting/LateInitialize() var/obj/structure/disposalpipe/sorting/mail/mail_sorter = locate(/obj/structure/disposalpipe/sorting/mail) in loc if(mail_sorter) diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index e601256a8b6d5..ff46cfc0b64e7 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -138,7 +138,6 @@ payload(airlock) /obj/effect/mapping_helpers/airlock/LateInitialize() - . = ..() var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc if(!airlock) qdel(src) @@ -283,7 +282,6 @@ return INITIALIZE_HINT_LATELOAD /obj/effect/mapping_helpers/airalarm/LateInitialize() - . = ..() var/obj/machinery/airalarm/target = locate(/obj/machinery/airalarm) in loc if(isnull(target)) @@ -442,7 +440,6 @@ return INITIALIZE_HINT_LATELOAD /obj/effect/mapping_helpers/apc/LateInitialize() - . = ..() var/obj/machinery/power/apc/target = locate(/obj/machinery/power/apc) in loc if(isnull(target)) @@ -917,8 +914,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) var/datum/species/new_human_species = GLOB.species_list[species_to_pick] if(new_human_species) new_human.set_species(new_human_species) - new_human_species = new_human.dna.species - new_human.fully_replace_character_name(new_human.real_name, new_human_species.random_name(new_human.gender, TRUE, TRUE)) + new_human.fully_replace_character_name(new_human.real_name, new_human.generate_random_mob_name()) else stack_trace("failed to spawn cadaver with species ID [species_to_pick]") //if it's invalid they'll just be a human, so no need to worry too much aside from yelling at the server owner lol. else @@ -1106,8 +1102,8 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) */ /obj/effect/mapping_helpers/trapdoor_placer name = "trapdoor placer" - late = TRUE icon_state = "trapdoor" + late = TRUE /obj/effect/mapping_helpers/trapdoor_placer/LateInitialize() var/turf/component_target = get_turf(src) @@ -1187,12 +1183,8 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) name = "broken floor" icon = 'icons/turf/damaged.dmi' icon_state = "damaged1" - late = TRUE layer = ABOVE_NORMAL_TURF_LAYER - -/obj/effect/mapping_helpers/broken_floor/Initialize(mapload) - .=..() - return INITIALIZE_HINT_LATELOAD + late = TRUE /obj/effect/mapping_helpers/broken_floor/LateInitialize() var/turf/open/floor/floor = get_turf(src) @@ -1203,12 +1195,8 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) name = "burnt floor" icon = 'icons/turf/damaged.dmi' icon_state = "floorscorched1" - late = TRUE layer = ABOVE_NORMAL_TURF_LAYER - -/obj/effect/mapping_helpers/burnt_floor/Initialize(mapload) - .=..() - return INITIALIZE_HINT_LATELOAD + late = TRUE /obj/effect/mapping_helpers/burnt_floor/LateInitialize() var/turf/open/floor/floor = get_turf(src) @@ -1237,7 +1225,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) return INITIALIZE_HINT_LATELOAD /obj/effect/mapping_helpers/broken_machine/LateInitialize() - . = ..() var/obj/machinery/target = locate(/obj/machinery) in loc if(isnull(target)) @@ -1271,7 +1258,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) return INITIALIZE_HINT_LATELOAD /obj/effect/mapping_helpers/damaged_window/LateInitialize() - . = ..() var/obj/structure/window/target = locate(/obj/structure/window) in loc if(isnull(target)) @@ -1304,7 +1290,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) return INITIALIZE_HINT_LATELOAD -/obj/effect/mapping_helpers/requests_console/LateInitialize(mapload) +/obj/effect/mapping_helpers/requests_console/LateInitialize() var/obj/machinery/airalarm/target = locate(/obj/machinery/requests_console) in loc if(isnull(target)) var/area/target_area = get_area(target) @@ -1441,7 +1427,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) return INITIALIZE_HINT_QDEL /obj/effect/mapping_helpers/basic_mob_flags/LateInitialize() - . = ..() var/had_any_mobs = FALSE for(var/mob/living/basic/basic_mobs in loc) had_any_mobs = TRUE diff --git a/code/modules/meteors/meteor_types.dm b/code/modules/meteors/meteor_types.dm index 2b37a55aaa413..120352f14c56a 100644 --- a/code/modules/meteors/meteor_types.dm +++ b/code/modules/meteors/meteor_types.dm @@ -76,7 +76,7 @@ /obj/effect/meteor/proc/chase_target(atom/chasing, delay, home) if(!isatom(chasing)) return - var/datum/move_loop/new_loop = SSmove_manager.move_towards(src, chasing, delay, home, lifetime) + var/datum/move_loop/new_loop = GLOB.move_manager.move_towards(src, chasing, delay, home, lifetime) if(!new_loop) return diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index ce42eaa43c28d..0b029bc3b63db 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -60,10 +60,9 @@ return ..() -/obj/structure/closet/crate/secure/loot/AltClick(mob/living/user) - if(!user.can_perform_action(src)) - return - return attack_hand(user) //this helps you not blow up so easily by overriding unlocking which results in an immediate boom. +/obj/structure/closet/crate/secure/loot/click_alt(mob/living/user) + attack_hand(user) //this helps you not blow up so easily by overriding unlocking which results in an immediate boom. + return CLICK_ACTION_SUCCESS /obj/structure/closet/crate/secure/loot/attackby(obj/item/W, mob/user) if(locked) @@ -121,7 +120,7 @@ return return ..() -/obj/structure/closet/crate/secure/loot/deconstruct(disassembled = TRUE) +/obj/structure/closet/crate/secure/loot/atom_deconstruct(disassembled = TRUE) if(locked) boom() return diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm index 5dd9832a8b01c..a1503b7f63420 100644 --- a/code/modules/mining/aux_base.dm +++ b/code/modules/mining/aux_base.dm @@ -273,7 +273,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/auxiliary_base, 32) to_chat(user, span_notice("You begin setting the landing zone parameters...")) setting = TRUE - if(!do_after(user, 50, target = user)) //You get a few seconds to cancel if you do not want to drop there. + if(!do_after(user, 5 SECONDS, target = user)) //You get a few seconds to cancel if you do not want to drop there. setting = FALSE return setting = FALSE @@ -355,7 +355,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/auxiliary_base, 32) return anti_spam_cd = 1 - addtimer(CALLBACK(src, PROC_REF(clear_cooldown)), 50) + addtimer(CALLBACK(src, PROC_REF(clear_cooldown)), 5 SECONDS) var/turf/landing_spot = get_turf(src) diff --git a/code/modules/mining/boulder_processing/_boulder_processing.dm b/code/modules/mining/boulder_processing/_boulder_processing.dm index 0dfc43cf7f788..5795eed1d7490 100644 --- a/code/modules/mining/boulder_processing/_boulder_processing.dm +++ b/code/modules/mining/boulder_processing/_boulder_processing.dm @@ -38,7 +38,7 @@ register_context() -/obj/machinery/bouldertech/LateInitialize() +/obj/machinery/bouldertech/post_machine_initialize() . = ..() var/static/list/loc_connections = list( COMSIG_ATOM_ENTERED = PROC_REF(on_entered), @@ -244,9 +244,9 @@ return FALSE -/obj/machinery/bouldertech/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/machinery/bouldertech/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(panel_open || user.combat_mode) - return ..() + return NONE if(istype(tool, /obj/item/boulder)) var/obj/item/boulder/my_boulder = tool @@ -276,7 +276,7 @@ to_chat(user, span_notice("You claim [amount] mining points from \the [src] to [id_card].")) return ITEM_INTERACT_SUCCESS - return ..() + return NONE /obj/machinery/bouldertech/wrench_act(mob/living/user, obj/item/tool) . = ITEM_INTERACT_BLOCKING diff --git a/code/modules/mining/boulder_processing/boulder.dm b/code/modules/mining/boulder_processing/boulder.dm index 796e382b21af4..555ea50dff3bf 100644 --- a/code/modules/mining/boulder_processing/boulder.dm +++ b/code/modules/mining/boulder_processing/boulder.dm @@ -8,9 +8,10 @@ desc = "This rocks." icon_state = "ore" icon = 'icons/obj/ore.dmi' - item_flags = NO_MAT_REDEMPTION + item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND throw_range = 2 throw_speed = 0.5 + slowdown = 1.5 drag_slowdown = 1.5 // It's still a big rock. ///When a refinery machine is working on this boulder, we'll set this. Re reset when the process is finished, but the boulder may still be refined/operated on further. @@ -26,6 +27,7 @@ . = ..() register_context() AddComponent(/datum/component/two_handed, require_twohands = TRUE, force_unwielded = 0, force_wielded = 5) //Heavy as all hell, it's a boulder, dude. + AddComponent(/datum/component/sisyphus_awarder) /obj/item/boulder/Destroy(force) SSore_generation.available_boulders -= src diff --git a/code/modules/mining/boulder_processing/boulder_types.dm b/code/modules/mining/boulder_processing/boulder_types.dm index 08ed961404c3a..1ffce8737bdd4 100644 --- a/code/modules/mining/boulder_processing/boulder_types.dm +++ b/code/modules/mining/boulder_processing/boulder_types.dm @@ -44,7 +44,7 @@ /datum/material/uranium = 3, ) - set_custom_materials(list(pick_weight(gulag_minerals) = SHEET_MATERIAL_AMOUNT * rand(1, 3))) + set_custom_materials(list(pick_weight(gulag_minerals) = SHEET_MATERIAL_AMOUNT)) ///Boulders usually spawned in lavaland labour camp area but with bluespace material /obj/item/boulder/gulag_expanded @@ -66,7 +66,7 @@ /datum/material/uranium = 3, ) - set_custom_materials(list(pick_weight(expanded_gulag_minerals) = SHEET_MATERIAL_AMOUNT * rand(1, 3))) + set_custom_materials(list(pick_weight(expanded_gulag_minerals) = SHEET_MATERIAL_AMOUNT)) ///lowgrade boulder, most commonly spawned /obj/item/boulder/shabby diff --git a/code/modules/mining/boulder_processing/brm.dm b/code/modules/mining/boulder_processing/brm.dm index 259c3eed5f651..61c5469b45901 100644 --- a/code/modules/mining/boulder_processing/brm.dm +++ b/code/modules/mining/boulder_processing/brm.dm @@ -101,7 +101,7 @@ if(default_deconstruction_crowbar(tool)) return ITEM_INTERACT_SUCCESS -///To allow boulders on a conveyer belt to move unobstructed if multiple machines are made on a single line +///To allow boulders on a conveyor belt to move unobstructed if multiple machines are made on a single line /obj/machinery/brm/CanAllowThrough(atom/movable/mover, border_dir) if(!anchored) return FALSE diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm index 38df199b251bc..5485ce72f22cd 100644 --- a/code/modules/mining/equipment/explorer_gear.dm +++ b/code/modules/mining/equipment/explorer_gear.dm @@ -85,20 +85,20 @@ starting_filter_type = /obj/item/gas_filter/plasmaman /obj/item/clothing/mask/gas/explorer/attack_self(mob/user) - adjustmask(user) + adjust_visor(user) -/obj/item/clothing/mask/gas/explorer/adjustmask(mob/user) +/obj/item/clothing/mask/gas/explorer/visor_toggling() . = ..() // adjusted = out of the way = smaller = can fit in boxes - w_class = mask_adjusted ? WEIGHT_CLASS_SMALL : WEIGHT_CLASS_NORMAL - inhand_icon_state = mask_adjusted ? "[initial(inhand_icon_state)]_up" : initial(inhand_icon_state) - if(user) - user.update_held_items() + update_weight_class(up ? WEIGHT_CLASS_SMALL : WEIGHT_CLASS_NORMAL) +/obj/item/clothing/mask/gas/explorer/update_icon_state() + . = ..() + inhand_icon_state = "[initial(inhand_icon_state)][up ? "_up" : ""]" /obj/item/clothing/mask/gas/explorer/examine(mob/user) . = ..() - if(mask_adjusted || w_class == WEIGHT_CLASS_SMALL) + if(up || w_class == WEIGHT_CLASS_SMALL) return . += span_notice("You could fit this into a box if you adjusted it.") @@ -107,7 +107,7 @@ /obj/item/clothing/mask/gas/explorer/folded/Initialize(mapload) . = ..() - adjustmask() + visor_toggling() /obj/item/clothing/suit/hooded/cloak icon = 'icons/obj/clothing/suits/armor.dmi' @@ -131,24 +131,25 @@ hoodtype = /obj/item/clothing/head/hooded/cloakhood/goliath body_parts_covered = CHEST|GROIN|ARMS -/obj/item/clothing/suit/hooded/cloak/goliath/AltClick(mob/user) - . = ..() - if(iscarbon(user)) - var/mob/living/carbon/char = user - if((char.get_item_by_slot(ITEM_SLOT_NECK) == src) || (char.get_item_by_slot(ITEM_SLOT_OCLOTHING) == src)) - to_chat(user, span_warning("You can't adjust [src] while wearing it!")) - return - if(!user.is_holding(src)) - to_chat(user, span_warning("You must be holding [src] in order to adjust it!")) - return - if(slot_flags & ITEM_SLOT_OCLOTHING) - slot_flags = ITEM_SLOT_NECK - set_armor(/datum/armor/none) - user.visible_message(span_notice("[user] adjusts their [src] for ceremonial use."), span_notice("You adjust your [src] for ceremonial use.")) - else - slot_flags = initial(slot_flags) - set_armor(initial(armor_type)) - user.visible_message(span_notice("[user] adjusts their [src] for defensive use."), span_notice("You adjust your [src] for defensive use.")) +/obj/item/clothing/suit/hooded/cloak/goliath/click_alt(mob/user) + if(!iscarbon(user)) + return NONE + var/mob/living/carbon/char = user + if((char.get_item_by_slot(ITEM_SLOT_NECK) == src) || (char.get_item_by_slot(ITEM_SLOT_OCLOTHING) == src)) + to_chat(user, span_warning("You can't adjust [src] while wearing it!")) + return CLICK_ACTION_BLOCKING + if(!user.is_holding(src)) + to_chat(user, span_warning("You must be holding [src] in order to adjust it!")) + return CLICK_ACTION_BLOCKING + if(slot_flags & ITEM_SLOT_OCLOTHING) + slot_flags = ITEM_SLOT_NECK + set_armor(/datum/armor/none) + user.visible_message(span_notice("[user] adjusts their [src] for ceremonial use."), span_notice("You adjust your [src] for ceremonial use.")) + else + slot_flags = initial(slot_flags) + set_armor(initial(armor_type)) + user.visible_message(span_notice("[user] adjusts their [src] for defensive use."), span_notice("You adjust your [src] for defensive use.")) + return CLICK_ACTION_SUCCESS /datum/armor/cloak_goliath melee = 35 @@ -353,4 +354,3 @@ desc = "An armoured hood for exploring harsh environments." icon_state = "explorer_syndicate" armor_type = /datum/armor/hooded_explorer_syndicate - diff --git a/code/modules/mining/equipment/grapple_gun.dm b/code/modules/mining/equipment/grapple_gun.dm new file mode 100644 index 0000000000000..c7c91ede73e6f --- /dev/null +++ b/code/modules/mining/equipment/grapple_gun.dm @@ -0,0 +1,183 @@ +#define DAMAGE_ON_IMPACT 20 + +/obj/item/grapple_gun + name = "grapple gun" + desc = "A handy tool for traversing the land-scape of lava-land!" + icon = 'icons/obj/mining.dmi' + icon_state = "grapple_gun" + lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + inhand_icon_state = "gun" + item_flags = NOBLUDGEON + ///overlay when the hook is retracted + var/static/mutable_appearance/hook_overlay = new(icon = 'icons/obj/mining.dmi', icon_state = "grapple_gun_hooked") + ///is the hook retracted + var/hooked = TRUE + ///addtimer id for launching the user + var/grapple_timer_id + ///traits we apply to the user when being launched + var/static/list/traits_on_zipline = list( + TRAIT_IMMOBILIZED, + TRAIT_MOVE_FLOATING, + TRAIT_FORCED_STANDING, + ) + ///the beam we draw + var/datum/beam/zipline + ///our user currently ziplining + var/datum/weakref/zipliner + ///ziplining sound + var/datum/looping_sound/zipline/zipline_sound + ///our initial matrix + var/matrix/initial_matrix + +/obj/item/grapple_gun/Initialize(mapload) + . = ..() + zipline_sound = new(src) + update_appearance() + +/obj/item/grapple_gun/afterattack(atom/target, mob/living/user, proximity) + . = ..() + + if(isgroundlessturf(target)) + return + + if(!lavaland_equipment_pressure_check(get_turf(user))) + user.balloon_alert(user, "gun mechanism wont work here!") + return + + if(target == user || !hooked) + return + + if(get_dist(user, target) > 9) + user.balloon_alert(user, "too far away!") + return + + var/turf/attacked_atom = get_turf(target) + if(isnull(attacked_atom)) + return + + var/list/turf_list = (get_line(user, attacked_atom) - get_turf(src)) + for(var/turf/singular_turf as anything in turf_list) + if(ischasm(singular_turf)) + continue + if(!singular_turf.is_blocked_turf()) + continue + attacked_atom = singular_turf + break + + if(user.CanReach(attacked_atom)) + return + + . |= AFTERATTACK_PROCESSED_ITEM + + var/atom/bullet = fire_projectile(/obj/projectile/grapple_hook, attacked_atom, 'sound/weapons/zipline_fire.ogg') + zipline = user.Beam(bullet, icon_state = "zipline_hook", maxdistance = 9, layer = BELOW_MOB_LAYER) + hooked = FALSE + RegisterSignal(bullet, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_grapple_hit)) + RegisterSignal(bullet, COMSIG_PREQDELETED, PROC_REF(on_grapple_fail)) + zipliner = WEAKREF(user) + update_appearance() + +/obj/item/grapple_gun/proc/on_grapple_hit(datum/source, atom/movable/firer, atom/target, Angle) + SIGNAL_HANDLER + + UnregisterSignal(source, list(COMSIG_PROJECTILE_ON_HIT, COMSIG_PREQDELETED)) + QDEL_NULL(zipline) + var/mob/living/user = zipliner?.resolve() + if(isnull(user) || isnull(target)) + cancel_hook() + return + + zipline = user.Beam(target, icon_state = "zipline_hook", maxdistance = 9, layer = BELOW_MOB_LAYER) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(determine_distance)) + RegisterSignal(user, COMSIG_MOVABLE_PRE_THROW, PROC_REF(apply_throw_traits)) + grapple_timer_id = addtimer(CALLBACK(src, PROC_REF(launch_user), target), 1.5 SECONDS, TIMER_STOPPABLE) + +/obj/item/grapple_gun/proc/on_grapple_fail(datum/source) + SIGNAL_HANDLER + cancel_hook() + +/obj/item/grapple_gun/proc/determine_distance(atom/movable/source) + SIGNAL_HANDLER + + if(isnull(zipline)) + return + var/atom/target = zipline.target + if(isnull(target)) + return + if(get_dist(source, target) > zipline.max_distance) + cancel_hook() + +/obj/item/grapple_gun/proc/apply_throw_traits(mob/living/source, list/arguements) + SIGNAL_HANDLER + var/atom/target_atom = arguements[1] + if(isnull(target_atom)) + return + var/dir_to_turn = get_angle(source, target_atom) + if(dir_to_turn > 175 && dir_to_turn < 190) + dir_to_turn = 0 + source.add_traits(traits_on_zipline, LEAPING_TRAIT) + initial_matrix = source.transform + animate(source, transform = matrix().Turn(dir_to_turn), time = 0.1 SECONDS) + +/obj/item/grapple_gun/proc/launch_user(atom/target_atom) + var/mob/living/my_user = zipliner?.resolve() + if(isnull(my_user) || isnull(target_atom) || my_user.buckled) + cancel_hook() + return + zipline_sound.start() + new /obj/effect/temp_visual/mook_dust(drop_location()) + RegisterSignal(my_user, COMSIG_MOVABLE_IMPACT, PROC_REF(strike_target)) + my_user.throw_at(target = target_atom, range = 9, speed = 1, spin = FALSE, gentle = TRUE, callback = CALLBACK(src, PROC_REF(post_land))) + +/obj/item/grapple_gun/proc/strike_target(mob/living/source, mob/living/victim, datum/thrownthing/throwingdatum) + SIGNAL_HANDLER + + if(!istype(victim)) + return + + victim.apply_damage(DAMAGE_ON_IMPACT) + playsound(victim, 'sound/effects/hit_kick.ogg', 50) + var/turf/target_turf = get_ranged_target_turf(victim, source.dir, 3) + if(isnull(target_turf)) + return + victim.throw_at(target = target_turf, speed = 1, spin = TRUE, range = 3) + + +/obj/item/grapple_gun/proc/post_land() + var/mob/living/my_user = zipliner?.resolve() + if(!isnull(my_user)) + my_user.transform = initial_matrix + my_user.remove_traits(traits_on_zipline, LEAPING_TRAIT) + new /obj/effect/temp_visual/mook_dust(drop_location()) + cancel_hook() + +/obj/item/grapple_gun/proc/cancel_hook() + var/atom/my_zipliner = zipliner?.resolve() + if(!isnull(my_zipliner)) + UnregisterSignal(my_zipliner, list(COMSIG_MOVABLE_IMPACT, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_PRE_THROW)) + QDEL_NULL(zipline) + zipliner = null + if(grapple_timer_id) + deltimer(grapple_timer_id) + grapple_timer_id = null + hooked = TRUE + zipline_sound.stop() + initial_matrix = null + update_appearance() + +/obj/item/grapple_gun/update_overlays() + . = ..() + if(hooked) + . += hook_overlay + +/obj/projectile/grapple_hook + name = "grapple hook" + icon_state = "grapple_hook" + damage = 0 + range = 9 + speed = 0.1 + can_hit_turfs = TRUE + hitsound = 'sound/weapons/zipline_hit.ogg' + +#undef DAMAGE_ON_IMPACT diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm index 67eb767f7673e..c33181dd8068d 100644 --- a/code/modules/mining/equipment/marker_beacons.dm +++ b/code/modules/mining/equipment/marker_beacons.dm @@ -43,7 +43,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list( "Alt-click to select a color. Current color is [picked_color].
    " /obj/item/stack/marker_beacon/update_icon_state() - icon_state = "[initial(icon_state)][lowertext(picked_color)]" + icon_state = "[initial(icon_state)][LOWER_TEXT(picked_color)]" return ..() /obj/item/stack/marker_beacon/attack_self(mob/user) @@ -59,16 +59,15 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list( var/obj/structure/marker_beacon/M = new(user.loc, picked_color) transfer_fingerprints_to(M) -/obj/item/stack/marker_beacon/AltClick(mob/living/user) - if(!istype(user) || !user.can_perform_action(src)) - return +/obj/item/stack/marker_beacon/click_alt(mob/living/user) var/input_color = tgui_input_list(user, "Choose a color", "Beacon Color", GLOB.marker_beacon_colors) if(isnull(input_color)) - return - if(!istype(user) || !user.can_perform_action(src)) - return + return CLICK_ACTION_BLOCKING + if(!user.can_perform_action(src)) + return CLICK_ACTION_BLOCKING picked_color = input_color update_appearance() + return CLICK_ACTION_SUCCESS /obj/structure/marker_beacon name = "marker beacon" @@ -99,12 +98,10 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list( picked_color = set_color update_appearance() -/obj/structure/marker_beacon/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/stack/marker_beacon/M = new(loc) - M.picked_color = picked_color - M.update_appearance() - qdel(src) +/obj/structure/marker_beacon/atom_deconstruct(disassembled = TRUE) + var/obj/item/stack/marker_beacon/beacon = new(loc) + beacon.picked_color = picked_color + beacon.update_appearance() /obj/structure/marker_beacon/examine(mob/user) . = ..() @@ -118,7 +115,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list( set_light(light_range, light_power, GLOB.marker_beacon_colors[picked_color]) /obj/structure/marker_beacon/update_icon_state() - icon_state = "[icon_prefix][lowertext(picked_color)]-on" + icon_state = "[icon_prefix][LOWER_TEXT(picked_color)]-on" return ..() /obj/structure/marker_beacon/attack_hand(mob/living/user, list/modifiers) @@ -156,17 +153,15 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list( return return ..() -/obj/structure/marker_beacon/AltClick(mob/living/user) - ..() - if(!istype(user) || !user.can_perform_action(src)) - return +/obj/structure/marker_beacon/click_alt(mob/living/user) var/input_color = tgui_input_list(user, "Choose a color", "Beacon Color", GLOB.marker_beacon_colors) if(isnull(input_color)) - return - if(!istype(user) || !user.can_perform_action(src)) - return + return CLICK_ACTION_BLOCKING + if(!user.can_perform_action(src)) + return NONE picked_color = input_color update_appearance() + return CLICK_ACTION_SUCCESS /* Preset marker beacon types, for mapping */ diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm index 9fdb772c4bc2a..4fdd997fcab32 100644 --- a/code/modules/mining/equipment/mining_tools.dm +++ b/code/modules/mining/equipment/mining_tools.dm @@ -257,7 +257,7 @@ tool_behaviour = TOOL_WRENCH sharpness = NONE toolspeed = 0.75 - w_class = WEIGHT_CLASS_SMALL + update_weight_class(WEIGHT_CLASS_SMALL) usesound = 'sound/items/ratchet.ogg' attack_verb_continuous = list("bashes", "bludgeons", "thrashes", "whacks") attack_verb_simple = list("bash", "bludgeon", "thrash", "whack") @@ -265,7 +265,7 @@ tool_behaviour = TOOL_SHOVEL sharpness = SHARP_EDGED toolspeed = 0.25 - w_class = WEIGHT_CLASS_NORMAL + update_weight_class(WEIGHT_CLASS_NORMAL) usesound = 'sound/effects/shovel_dig.ogg' attack_verb_continuous = list("slashes", "impales", "stabs", "slices") attack_verb_simple = list("slash", "impale", "stab", "slice") @@ -273,7 +273,7 @@ tool_behaviour = TOOL_MINING sharpness = SHARP_POINTY toolspeed = 0.5 - w_class = WEIGHT_CLASS_NORMAL + update_weight_class(WEIGHT_CLASS_NORMAL) usesound = 'sound/effects/picaxe1.ogg' attack_verb_continuous = list("hits", "pierces", "slices", "attacks") attack_verb_simple = list("hit", "pierce", "slice", "attack") @@ -372,7 +372,7 @@ var/atom/throw_target = get_edge_target_turf(target_mob, get_dir(user, get_step_away(target_mob, user))) target_mob.throw_at(throw_target, 2, 2, user, gentle = TRUE) target_mob.Knockdown(2 SECONDS) - var/body_zone = pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + var/body_zone = pick(GLOB.all_body_zones) user.apply_damage(force / recoil_factor, BRUTE, body_zone, user.run_armor_check(body_zone, MELEE)) to_chat(user, span_danger("The weight of the Big Slappy recoils!")) log_combat(user, user, "recoiled Big Slappy into") diff --git a/code/modules/mining/equipment/monster_organs/rush_gland.dm b/code/modules/mining/equipment/monster_organs/rush_gland.dm index b3dbc683da438..f9cfa1b88f1c3 100644 --- a/code/modules/mining/equipment/monster_organs/rush_gland.dm +++ b/code/modules/mining/equipment/monster_organs/rush_gland.dm @@ -45,6 +45,7 @@ id = "lobster_rush" duration = 3 SECONDS alert_type = /atom/movable/screen/alert/status_effect/lobster_rush + show_duration = TRUE var/spawned_last_move = FALSE /atom/movable/screen/alert/status_effect/lobster_rush diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index f4463434066c7..b22603f52d92b 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -214,8 +214,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/survival_pod/left, 0) /obj/item/gps/computer/wrench_act(mob/living/user, obj/item/I) ..() - if(obj_flags & NO_DECONSTRUCTION) - return TRUE user.visible_message(span_warning("[user] disassembles [src]."), span_notice("You start to disassemble [src]..."), span_hear("You hear clanking and banging noises.")) @@ -251,7 +249,18 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/survival_pod/left, 0) light_color = COLOR_VERY_PALE_LIME_GREEN max_n_of_items = 10 pixel_y = -4 - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/machinery/smartfridge/survival_pod/welder_act(mob/living/user, obj/item/tool) + return NONE + +/obj/machinery/smartfridge/survival_pod/wrench_act(mob/living/user, obj/item/tool) + return NONE + +/obj/machinery/smartfridge/survival_pod/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/machinery/smartfridge/survival_pod/crowbar_act(mob/living/user, obj/item/tool) + return NONE /obj/machinery/smartfridge/survival_pod/Initialize(mapload) AddElement(/datum/element/update_icon_blocker) diff --git a/code/modules/mining/equipment/vent_pointer.dm b/code/modules/mining/equipment/vent_pointer.dm new file mode 100644 index 0000000000000..4edab185597b2 --- /dev/null +++ b/code/modules/mining/equipment/vent_pointer.dm @@ -0,0 +1,19 @@ +/obj/item/pinpointer/vent + name = "ventpointer" + desc = "A handheld tracking device. It will locate and point to nearby vents. A bit unreliable though." + icon_state = "pinpointer_vent" + minimum_range = 14 //gotta use them eyes + +/obj/item/pinpointer/vent/scan_for_target() + var/closest_dist = INFINITY + + for(var/obj/structure/ore_vent/vent in SSore_generation.possible_vents) + if(vent.discovered || vent.tapped) + continue + if(vent.z != loc.z) + continue + + var/target_dist = get_dist(src, vent) + if(target_dist < closest_dist) + closest_dist = target_dist + target = vent diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm index b4165a13cd0af..d5b7bb7b529bc 100644 --- a/code/modules/mining/equipment/wormhole_jaunter.dm +++ b/code/modules/mining/equipment/wormhole_jaunter.dm @@ -61,7 +61,7 @@ else if(adjacent) try_move_adjacent(tunnel) - playsound(src,'sound/effects/sparks4.ogg',50,TRUE) + playsound(src, "sound/effects/portal_travel.ogg",50,TRUE) qdel(src) return FALSE // used for chasm code @@ -114,4 +114,4 @@ L.Paralyze(60) if(ishuman(L)) shake_camera(L, 20, 1) - addtimer(CALLBACK(L, TYPE_PROC_REF(/mob/living/carbon, vomit)), 20) + addtimer(CALLBACK(L, TYPE_PROC_REF(/mob/living/carbon, vomit)), 2 SECONDS) diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 8a7ffeec88f66..8b82d4b7d7796 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -1,4 +1,4 @@ -GLOBAL_LIST(labor_sheet_values) +#define SHEET_POINT_VALUE 33 /**********************Prisoners' Console**************************/ @@ -22,14 +22,6 @@ GLOBAL_LIST(labor_sheet_values) if(!stacking_machine) return INITIALIZE_HINT_QDEL - if(!GLOB.labor_sheet_values) - var/sheet_list = list() - for(var/obj/item/stack/sheet/sheet as anything in subtypesof(/obj/item/stack/sheet)) - if(!initial(sheet.point_value) || (initial(sheet.merge_type) && initial(sheet.merge_type) != sheet)) //ignore no-value sheets and x/fifty subtypes - continue - sheet_list += list(list("ore" = initial(sheet.name), "value" = initial(sheet.point_value))) - GLOB.labor_sheet_values = sort_list(sheet_list, GLOBAL_PROC_REF(cmp_sheet_list)) - /obj/machinery/mineral/labor_claim_console/Destroy() QDEL_NULL(security_radio) if(stacking_machine) @@ -46,11 +38,6 @@ GLOBAL_LIST(labor_sheet_values) ui = new(user, src, "LaborClaimConsole", name) ui.open() -/obj/machinery/mineral/labor_claim_console/ui_static_data(mob/user) - var/list/data = list() - data["ores"] = GLOB.labor_sheet_values - return data - /obj/machinery/mineral/labor_claim_console/ui_data(mob/user) var/list/data = list() var/can_go_home = FALSE @@ -119,7 +106,10 @@ GLOBAL_LIST(labor_sheet_values) else if(!(obj_flags & EMAGGED)) security_radio.set_frequency(FREQ_SECURITY) - security_radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) + var/datum/record/crew/target = find_record(user_mob.real_name) + target?.wanted_status = WANTED_PAROLE + + security_radio.talk_into(src, "/p [user_mob.name] returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) user_mob.log_message("has completed their labor points goal and is now sending the gulag shuttle back to the station.", LOG_GAME) to_chat(user_mob, span_notice("Shuttle received message and will be sent shortly.")) return TRUE @@ -155,8 +145,9 @@ GLOBAL_LIST(labor_sheet_values) labor_console = null return ..() -/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp) - points += inp.point_value * inp.amount +/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/input) + if (input.manufactured && input.gulag_valid) + points += SHEET_POINT_VALUE * input.amount return ..() /obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/weapon, mob/user, params) @@ -190,3 +181,5 @@ GLOBAL_LIST(labor_sheet_values) say("ID: [prisoner_id.registered_name].") say("Points Collected: [prisoner_id.points] / [prisoner_id.goal].") say("Collect points by bringing smelted minerals to the Labor Shuttle stacking machine. Reach your quota to earn your release.") + +#undef SHEET_POINT_VALUE diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index 25240b0330fb3..626543f40604d 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -120,7 +120,7 @@ if(isturf(user.loc)) user.visible_message(span_hierophant_warning("[user] starts fiddling with [src]'s pommel..."), \ span_notice("You start detaching the hierophant beacon...")) - if(do_after(user, 50, target = user) && !beacon) + if(do_after(user, 5 SECONDS, target = user) && !beacon) var/turf/user_turf = get_turf(user) playsound(user_turf,'sound/magic/blind.ogg', 200, TRUE, -4) new /obj/effect/temp_visual/hierophant/telegraph/teleport(user_turf, user) @@ -149,7 +149,7 @@ beacon.icon_state = "hierophant_tele_on" var/obj/effect/temp_visual/hierophant/telegraph/edge/user_telegraph = new /obj/effect/temp_visual/hierophant/telegraph/edge(user.loc) var/obj/effect/temp_visual/hierophant/telegraph/edge/beacon_telegraph = new /obj/effect/temp_visual/hierophant/telegraph/edge(beacon.loc) - if(do_after(user, 40, target = user) && user && beacon) + if(do_after(user, 4 SECONDS, target = user) && user && beacon) var/turf/destination = get_turf(beacon) var/turf/source = get_turf(user) if(destination.is_blocked_turf(TRUE)) @@ -162,7 +162,7 @@ new /obj/effect/temp_visual/hierophant/telegraph(source, user) playsound(destination,'sound/magic/wand_teleport.ogg', 200, TRUE) playsound(source,'sound/machines/airlockopen.ogg', 200, TRUE) - if(!do_after(user, 3, target = user) || !user || !beacon || QDELETED(beacon)) //no walking away shitlord + if(!do_after(user, 0.3 SECONDS, target = user) || !user || !beacon || QDELETED(beacon)) //no walking away shitlord teleporting = FALSE if(user) user.update_mob_action_buttons() @@ -290,7 +290,10 @@ if(prob(7.5)) wearer.cause_hallucination(/datum/hallucination/oh_yeah, "H.E.C.K suit", haunt_them = TRUE) else - to_chat(wearer, span_warning("[pick("You hear faint whispers.","You smell ash.","You feel hot.","You hear a roar in the distance.")]")) + if(HAS_TRAIT(wearer, TRAIT_ANOSMIA)) //Anosmia quirk holder cannot fell any smell + to_chat(wearer, span_warning("[pick("You hear faint whispers.","You feel hot.","You hear a roar in the distance.")]")) + else + to_chat(wearer, span_warning("[pick("You hear faint whispers.","You smell ash.","You feel hot.","You hear a roar in the distance.")]")) /obj/item/clothing/head/hooded/hostile_environment name = "H.E.C.K. helmet" diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index 764c1ddb98f39..8a90f0e548c30 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -105,22 +105,22 @@ return var/failText = span_warning("The snake seems unsatisfied with your incomplete oath and returns to its previous place on the rod, returning to its dormant, wooden state. You must stand still while completing your oath!") to_chat(itemUser, span_notice("The wooden snake that was carved into the rod seems to suddenly come alive and begins to slither down your arm! The compulsion to help others grows abnormally strong...")) - if(do_after(itemUser, 40, target = itemUser)) + if(do_after(itemUser, 4 SECONDS, target = itemUser)) itemUser.say("I swear to fulfill, to the best of my ability and judgment, this covenant:", forced = "hippocratic oath") else to_chat(itemUser, failText) return - if(do_after(itemUser, 20, target = itemUser)) + if(do_after(itemUser, 2 SECONDS, target = itemUser)) itemUser.say("I will apply, for the benefit of the sick, all measures that are required, avoiding those twin traps of overtreatment and therapeutic nihilism.", forced = "hippocratic oath") else to_chat(itemUser, failText) return - if(do_after(itemUser, 30, target = itemUser)) + if(do_after(itemUser, 3 SECONDS, target = itemUser)) itemUser.say("I will remember that I remain a member of society, with special obligations to all my fellow human beings, those sound of mind and body as well as the infirm.", forced = "hippocratic oath") else to_chat(itemUser, failText) return - if(do_after(itemUser, 30, target = itemUser)) + if(do_after(itemUser, 3 SECONDS, target = itemUser)) itemUser.say("If I do not violate this oath, may I enjoy life and art, respected while I live and remembered with affection thereafter. May I always act so as to preserve the finest traditions of my calling and may I long experience the joy of healing those who seek my help.", forced = "hippocratic oath") else to_chat(itemUser, failText) @@ -163,7 +163,7 @@ /obj/item/clothing/neck/necklace/memento_mori/proc/memento(mob/living/carbon/human/user) to_chat(user, span_warning("You feel your life being drained by the pendant...")) - if(do_after(user, 40, target = user)) + if(do_after(user, 4 SECONDS, target = user)) to_chat(user, span_notice("Your lifeforce is now linked to the pendant! You feel like removing it would kill you, and yet you instinctively know that until then, you won't die.")) user.add_traits(list(TRAIT_NODEATH, TRAIT_NOHARDCRIT, TRAIT_NOCRITDAMAGE), CLOTHING_TRAIT) RegisterSignal(user, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(check_health)) @@ -566,7 +566,7 @@ var/list/name2type = list() for(var/obj/item/organ/external/wings/functional/possible_type as anything in wing_types) var/datum/sprite_accessory/accessory = initial(possible_type.sprite_accessory_override) //get the type - accessory = GLOB.wings_list[initial(accessory.name)] //get the singleton instance + accessory = SSaccessories.wings_list[initial(accessory.name)] //get the singleton instance var/image/img = image(icon = accessory.icon, icon_state = "m_wingsopen_[accessory.icon_state]_BEHIND") //Process the HUD elements img.transform *= 0.5 img.pixel_x = -32 diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index 11a941c409861..61318f63b92a5 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -143,6 +143,8 @@ var/datum/proximity_monitor/proximity_monitor ///Material container for materials var/datum/component/material_container/materials + /// What can be input into the machine? + var/accepted_type = /obj/item/stack /obj/machinery/mineral/processing_unit/Initialize(mapload) . = ..() @@ -153,7 +155,7 @@ SSmaterials.materials_by_category[MAT_CATEGORY_SILO], \ INFINITY, \ MATCONTAINER_EXAMINE, \ - allowed_items = /obj/item/stack \ + allowed_items = accepted_type \ ) if(!GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter]) GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter] = new /datum/techweb/autounlocking/smelter @@ -166,7 +168,7 @@ stored_research = null return ..() -/obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/ore/O) +/obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/O) if(QDELETED(O)) return var/material_amount = materials.get_item_material_amount(O) @@ -225,7 +227,7 @@ /obj/machinery/mineral/processing_unit/pickup_item(datum/source, atom/movable/target, direction) if(QDELETED(target)) return - if(istype(target, /obj/item/stack/ore)) + if(istype(target, accepted_type)) process_ore(target) /obj/machinery/mineral/processing_unit/process(seconds_per_tick) @@ -282,4 +284,8 @@ var/O = new P(src) unload_mineral(O) +/// Only accepts ore, for the work camp +/obj/machinery/mineral/processing_unit/gulag + accepted_type = /obj/item/stack/ore + #undef SMELT_AMOUNT diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index 0b9b7895c6bde..14460cffb1b66 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -203,18 +203,16 @@ default_unfasten_wrench(user, tool) return ITEM_INTERACT_SUCCESS -/obj/machinery/mineral/ore_redemption/AltClick(mob/living/user) - . = ..() - if(!user.can_perform_action(src)) - return - if(panel_open) - input_dir = turn(input_dir, -90) - output_dir = turn(output_dir, -90) - to_chat(user, span_notice("You change [src]'s I/O settings, setting the input to [dir2text(input_dir)] and the output to [dir2text(output_dir)].")) - unregister_input_turf() // someone just rotated the input and output directions, unregister the old turf - register_input_turf() // register the new one - update_appearance(UPDATE_OVERLAYS) - return TRUE +/obj/machinery/mineral/ore_redemption/click_alt(mob/living/user) + if(!panel_open) + return CLICK_ACTION_BLOCKING + input_dir = turn(input_dir, -90) + output_dir = turn(output_dir, -90) + to_chat(user, span_notice("You change [src]'s I/O settings, setting the input to [dir2text(input_dir)] and the output to [dir2text(output_dir)].")) + unregister_input_turf() // someone just rotated the input and output directions, unregister the old turf + register_input_turf() // register the new one + update_appearance(UPDATE_OVERLAYS) + return CLICK_ACTION_SUCCESS /obj/machinery/mineral/ore_redemption/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index 286317a5d74eb..1f9a29a6e3714 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -137,26 +137,26 @@ if (input_dir == output_dir) rotate(input) -/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/inp) - if(QDELETED(inp)) +/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/input) + if(QDELETED(input)) return // Dump the sheets to the silo if attached if(materials.silo && !materials.on_hold()) - var/matlist = inp.custom_materials & materials.mat_container.materials + var/matlist = input.custom_materials & materials.mat_container.materials if (length(matlist)) - materials.mat_container.insert_item(inp, context = src) + materials.insert_item(input) return // No silo attached process to internal storage - var/key = inp.merge_type + var/key = input.merge_type var/obj/item/stack/sheet/storage = stack_list[key] if(!storage) //It's the first of this sheet added - stack_list[key] = storage = new inp.type(src, 0) - storage.amount += inp.amount //Stack the sheets - qdel(inp) + stack_list[key] = storage = new input.type(src, 0) + storage.amount += input.amount //Stack the sheets + qdel(input) while(storage.amount >= stack_amt) //Get rid of excessive stackage - var/obj/item/stack/sheet/out = new inp.type(null, stack_amt) + var/obj/item/stack/sheet/out = new input.type(null, stack_amt) unload_mineral(out) storage.amount -= stack_amt diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 248e3cb890dd8..3d10c3f5c47fd 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -150,10 +150,405 @@ /obj/docking_port/stationary/mining_home/common/northstar roundstart_template = /datum/map_template/shuttle/mining_common/northstar -/**********************Mining car (Crate like thing, not the rail car)**************************/ - /obj/structure/closet/crate/miningcar - desc = "A mining car. This one doesn't work on rails, but has to be dragged." - name = "Mining car (not for rails)" + name = "mine cart" + desc = "A cart for use on rails. Or off rails, if you're so inclined." icon_state = "miningcar" base_icon_state = "miningcar" + drag_slowdown = 2 + open_sound = 'sound/machines/trapdoor/trapdoor_open.ogg' + close_sound = 'sound/machines/trapdoor/trapdoor_shut.ogg' + set_dir_on_move = TRUE + can_buckle = TRUE + /// Whether we're on a set of rails or just on the ground + var/on_rails = FALSE + /// How many turfs we are travelling, also functions as speed (more momentum = faster) + var/momentum = 0 + +/obj/structure/closet/crate/miningcar/Initialize(mapload) + . = ..() + AddElement(/datum/element/noisy_movement, 'sound/effects/tank_treads.ogg', 50) + if(locate(/obj/structure/minecart_rail) in loc) + update_rail_state(TRUE) + +/obj/structure/closet/crate/miningcar/examine(mob/user) + . = ..() + if(on_rails) + . += span_notice("You can give this a bump to send it on its way, or drag it off the rails to drag it around.") + else + . += span_notice("Drag this onto a mine cart rail to set it on its way.") + +/obj/structure/closet/crate/miningcar/Move(atom/newloc, direct, glide_size_override, update_dir) + if(isnull(newloc)) + return ..() + if(!on_rails) + return ..() + // Allows people to drag minecarts along the rails rather than solely shoving it + if(can_travel_on_turf(get_turf(newloc), direct)) + return ..() + momentum = 0 + return FALSE + +/obj/structure/closet/crate/miningcar/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + if(!on_rails || momentum <= 0) + return + + // Handling running OVER people + for(var/mob/living/smacked in loc) + if(smacked.body_position != LYING_DOWN) + continue + if(momentum <= 8) + momentum = floor(momentum / 2) + break + smack(smacked, 3, 1.5) + if(QDELETED(src)) + break + +/obj/structure/closet/crate/miningcar/is_buckle_possible(mob/living/target, force, check_loc) + return !opened && ..() + +/obj/structure/closet/crate/miningcar/after_open(mob/living/user, force) + . = ..() + unbuckle_all_mobs() + +// Hack: If a mob is buckled onto the cart, bumping the cart will instead bump the mob (because higher layer) +// So if we want to allow people to shove carts people are riding, we gotta check the mob for bumped and redirect it +/obj/structure/closet/crate/miningcar/post_buckle_mob(mob/living/buckled_mob) + RegisterSignal(buckled_mob, COMSIG_ATOM_BUMPED, PROC_REF(buckled_bumped)) + RegisterSignal(buckled_mob, COMSIG_MOVABLE_BUMP_PUSHED, PROC_REF(block_bump_push)) + +/obj/structure/closet/crate/miningcar/post_unbuckle_mob(mob/living/unbuckled_mob) + UnregisterSignal(unbuckled_mob, list(COMSIG_ATOM_BUMPED, COMSIG_MOVABLE_BUMP_PUSHED)) + +/obj/structure/closet/crate/miningcar/proc/buckled_bumped(datum/source, atom/bumper) + SIGNAL_HANDLER + INVOKE_ASYNC(src, PROC_REF(shove_off), bumper) + +/** + * Called when the minecart smacks into someone. + * + * * smacked - The mob that was smacked. + * * damage_mod - How much to multiply the momentum by to get the damage. + * * momentum_mod - How much to divide the momentum by after the smack. + */ +/obj/structure/closet/crate/miningcar/proc/smack(mob/living/smacked, damage_mod = 2, momentum_mod = 2) + ASSERT(momentum_mod >= 1) + if(!smacked.apply_damage(damage_mod * momentum, BRUTE, BODY_ZONE_CHEST, wound_bonus = damage_mod * 10, attack_direction = dir)) + return + if(get_integrity() <= max_integrity * 0.05) + smacked.visible_message( + span_danger("[src] smashes into [smacked], breaking into pieces!"), + span_userdanger("You are smacked by [src] as it breaks into pieces!"), + ) + playsound(src, 'sound/effects/break_stone.ogg', 50, vary = TRUE) + momentum = 0 + + else + smacked.visible_message( + span_danger("[src] smashes into [smacked]!"), + span_userdanger("You are smacked by [src]!"), + ) + playsound(src, 'sound/effects/bang.ogg', 50, vary = TRUE) + take_damage(max_integrity * 0.05) + momentum = floor(momentum / momentum_mod) + if(smacked.body_position == LYING_DOWN) + smacked.Paralyze(4 SECONDS) + return + + smacked.Knockdown(5 SECONDS) + for(var/side_dir in shuffle(GLOB.alldirs)) + // Don't throw people in front of the cart, and + // don't throw people in any direction behind us + if(side_dir == dir || (side_dir & REVERSE_DIR(dir))) + continue + var/turf/open/open_turf = get_step(src, side_dir) + if(!istype(open_turf)) + continue + smacked.safe_throw_at(open_turf, 1, 3, spin = FALSE, gentle = TRUE) + +/** + * Updates the state of the minecart to be on or off rails. + */ +/obj/structure/closet/crate/miningcar/proc/update_rail_state(new_state) + if(on_rails == new_state) + return + on_rails = new_state + if(on_rails) + drag_slowdown = 0.5 + RegisterSignal(src, COMSIG_MOVABLE_BUMP_PUSHED, PROC_REF(block_bump_push)) + else + drag_slowdown = 2 + UnregisterSignal(src, COMSIG_MOVABLE_BUMP_PUSHED) + +// We want a low move resistance so people can drag it along the tracks +// But we also don't want people to nudge it with a push (since it requires a do_after to set off) +/obj/structure/closet/crate/miningcar/proc/block_bump_push(datum/source, mob/living/bumper, force) + SIGNAL_HANDLER + if(on_rails) + return COMPONENT_NO_PUSH + if(force < MOVE_FORCE_STRONG) + return COMPONENT_NO_PUSH + return NONE + +/obj/structure/closet/crate/miningcar/forceMove(atom/destination) + update_rail_state(FALSE) + return ..() + +/obj/structure/closet/crate/miningcar/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) + . = ..() + if(!isliving(usr) || !usr.Adjacent(over) || !usr.Adjacent(src)) + return + if(on_rails) + if(isopenturf(over)) + try_take_off_rails(usr, over) + return + + if(istype(over, /obj/structure/minecart_rail) || (isopenturf(over) && (locate(/obj/structure/minecart_rail) in over))) + try_put_on_rails(usr, get_turf(over)) + return + +/** + * Attempt to remove the cart from rails + * + * * user - The user attempting to remove the cart from the rails. + * * new_destination - The turf the cart will be moved to. + */ +/obj/structure/closet/crate/miningcar/proc/try_take_off_rails(mob/living/user, turf/open/new_destination) + balloon_alert(user, "removing from rails...") + if(!do_after(user, 2 SECONDS, src)) + return + update_rail_state(FALSE) + Move(new_destination) + var/sound/thud_sound = sound('sound/weapons/thudswoosh.ogg') + thud_sound.pitch = 0.5 + playsound(src, thud_sound, 50, TRUE) + +/** + * Attempt to put the cart on rails + * + * * user - The user attempting to put the cart on the rails. + * * new_destination - The turf the cart will be moved to. + */ +/obj/structure/closet/crate/miningcar/proc/try_put_on_rails(mob/living/user, turf/open/new_destination) + balloon_alert(user, "putting on rails...") + if(!do_after(user, 2 SECONDS, src)) + return + var/obj/structure/minecart_rail/set_rail = locate() in new_destination + if(isnull(set_rail)) + return + Move(new_destination) + setDir(set_rail.dir) + update_rail_state(TRUE) + var/sound/click_sound = sound('sound/machines/click.ogg') + click_sound.pitch = 0.5 + playsound(src, click_sound, 50, TRUE) + +/obj/structure/closet/crate/miningcar/Bump(atom/bumped_atom) + . = ..() + if(.) + return + + // Handling running INTO people + if(!isliving(bumped_atom) || momentum <= 0) + return + if(momentum <= 8) + momentum = floor(momentum / 2) + return + smack(bumped_atom) + +/obj/structure/closet/crate/miningcar/Bumped(atom/movable/bumped_atom) + . = ..() + INVOKE_ASYNC(src, PROC_REF(shove_off), bumped_atom) + +/// Starts the cart moving automatically. +/obj/structure/closet/crate/miningcar/proc/shove_off(atom/movable/bumped_atom) + if(!on_rails || momentum > 0) + return + + var/movedir = bumped_atom.dir + var/turf/next_turf = get_step(src, movedir) + if(!can_travel_on_turf(next_turf, movedir)) + return + + if(isliving(bumped_atom)) + var/obj/structure/minecart_rail/rail = locate() in loc + var/mob/living/bumper = bumped_atom + if(bumper.mob_size <= MOB_SIZE_SMALL) + return + if(DOING_INTERACTION_WITH_TARGET(bumper, src)) + return + balloon_alert(bumper, "setting off...") + if(!do_after(bumper, 1.5 SECONDS, src)) + return + if(QDELETED(rail) || !on_rails || !can_travel_on_turf(next_turf, movedir)) + return + momentum += 20 + + else if(isitem(bumped_atom)) + var/obj/item/bumped_item = bumped_atom + if(bumped_item.w_class <= WEIGHT_CLASS_SMALL) + return + momentum += bumped_item.w_class + + else if(istype(bumped_atom, /obj/structure/closet/crate/miningcar)) + var/obj/structure/closet/crate/miningcar/bumped_car = bumped_atom + if(bumped_car.momentum <= 0) + return + momentum += bumped_car.momentum + bumped_car.momentum = 0 + + if(momentum <= 0) + return + + setDir(movedir) + var/datum/move_loop/loop = GLOB.move_manager.move(src, dir, delay = calculate_delay(), subsystem = SSconveyors, flags = MOVEMENT_LOOP_START_FAST|MOVEMENT_LOOP_IGNORE_PRIORITY) + RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(check_rail)) + RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(decay_momentum)) + +/obj/structure/closet/crate/miningcar/proc/check_rail(datum/move_loop/move/source) + SIGNAL_HANDLER + + if(momentum <= 0) + stack_trace("Mine cart moving on 0 momentum!") + GLOB.move_manager.stop_looping(src, SSconveyors) + return MOVELOOP_SKIP_STEP + // Forced to not move + if(anchored || !has_gravity()) + return MOVELOOP_SKIP_STEP + // Going straight + if(can_travel_on_turf(get_step(src, dir))) + return NONE + // Trying to turn + for(var/next_dir in shuffle(list(turn(dir, 90), turn(dir, -90)))) + if(!can_travel_on_turf(get_step(src, next_dir), dir|next_dir)) + continue + momentum -= 1 // Extra cost for turning + if(momentum <= 0) + break + source.direction = next_dir + return NONE + // Can't go straight and cant turn = STOP + GLOB.move_manager.stop_looping(src, SSconveyors) + if(momentum >= 8) + visible_message(span_warning("[src] comes to a halt!")) + throw_contents() + else + visible_message(span_notice("[src] comes to a slow stop.")) + momentum = 0 + return MOVELOOP_SKIP_STEP + +/obj/structure/closet/crate/miningcar/proc/decay_momentum(datum/move_loop/move/source) + SIGNAL_HANDLER + + if(momentum > 0) + var/obj/structure/minecart_rail/railbreak/stop_break = locate() in loc + var/obj/structure/cable/cable = locate() in loc + // There is a break and it is powered, so STOP + if(stop_break && cable?.avail(10 KILO JOULES)) + if(momentum >= 8) + visible_message(span_notice("[src] comes to a sudden stop.")) + else + visible_message(span_notice("[src] comes to a stop.")) + momentum = 0 + GLOB.move_manager.stop_looping(src, SSconveyors) + cable.add_delayedload(10 KILO JOULES) + return + // This is a powered rail, so maintain speed + if(cable?.avail(1 KILO JOULES)) + // Speeds up the cart to 5 or 10, then stops decay + if(momentum <= 5) + momentum = 5 + cable.add_delayedload(0.5 KILO JOULES) + else if(momentum <= 10) + momentum = 10 + cable.add_delayedload(1 KILO JOULES) + return + // Here is where actual slowdown happens + momentum -= 1 + + // No more momentum = STOP + if(momentum <= 0) + GLOB.move_manager.stop_looping(src, SSconveyors) + visible_message(span_notice("[src] comes to a slow stop.")) + return + + // Handles slowing down the move loop / cart + var/datum/move_loop/loop = GLOB.move_manager.processing_on(src, SSconveyors) + loop?.set_delay(calculate_delay()) + +/// Calculates how fast the cart is going +/obj/structure/closet/crate/miningcar/proc/calculate_delay() + return (-0.05 SECONDS * momentum) + 1.1 SECONDS + +/// Checks if we can travel on the passed turf +/obj/structure/closet/crate/miningcar/proc/can_travel_on_turf(turf/next_turf, dir_to_check = dir) + for(var/obj/structure/minecart_rail/rail in next_turf) + if(rail.dir & (dir_to_check|REVERSE_DIR(dir_to_check))) + return TRUE + + return FALSE + +/// Throws all the contents of the cart out ahead +/obj/structure/closet/crate/miningcar/proc/throw_contents() + var/was_open = opened + var/list/to_yeet = contents.Copy() + var/yeet_rider = has_buckled_mobs() + if(yeet_rider) + to_yeet += buckled_mobs + unbuckle_all_mobs() + + bust_open() + if(!opened) + return + + if(!length(to_yeet)) + if(!was_open) + visible_message(span_warning("[src] breaks open!")) + return + + var/throw_distance = clamp(ceil(momentum / 3) - 4, 1, 5) + var/turf/some_distant_turf = get_edge_target_turf(src, dir) + for(var/atom/movable/yeeten in to_yeet) + yeeten.throw_at(some_distant_turf, throw_distance, 3, quickstart = TRUE) + + if(was_open) + visible_message(span_warning("[src] spills its contents!")) + else + // Update this message if someone allows multiple people to ride one minecart + visible_message(span_warning("[src] breaks open, spilling its contents[yeet_rider ? " and throwing its rider":""]!")) + +/obj/structure/minecart_rail + name = "cart rail" + desc = "Carries carts along the track." + icon = 'icons/obj/track.dmi' + icon_state = "track" + layer = TRAM_RAIL_LAYER + plane = FLOOR_PLANE + anchored = TRUE + move_resist = INFINITY + +/obj/structure/minecart_rail/Initialize(mapload) + . = ..() + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_TURF_IGNORE_SLOWDOWN))) + AddElement(/datum/element/footstep_override, footstep = FOOTSTEP_CATWALK) + for(var/obj/structure/closet/crate/miningcar/cart in loc) + cart.update_rail_state(TRUE) + +/obj/structure/minecart_rail/examine(mob/user) + . = ..() + . += rail_examine() + +/obj/structure/minecart_rail/proc/rail_examine() + return span_notice("Run a powered cable underneath it to power carts as they travel, maintaining their speed.") + +/obj/structure/minecart_rail/railbreak + name = "cart rail brake" + desc = "Stops carts in their tracks. On the tracks. You get what I mean." + icon_state = "track_break" + can_buckle = TRUE + buckle_requires_restraints = TRUE + buckle_lying = NO_BUCKLE_LYING + +/obj/structure/minecart_rail/railbreak/rail_examine() + return span_notice("Run a powered cable underneath it to stop carts that pass over it.") diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 4fe26281b10a7..65644b00cc87a 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -107,9 +107,9 @@ merge_type = /obj/item/stack/ore/glass GLOBAL_LIST_INIT(sand_recipes, list(\ - new /datum/stack_recipe("pile of dirt", /obj/machinery/hydroponics/soil, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \ - new /datum/stack_recipe("sandstone", /obj/item/stack/sheet/mineral/sandstone, 1, 1, 50, check_density = FALSE, category = CAT_MISC),\ - new /datum/stack_recipe("aesthetic volcanic floor tile", /obj/item/stack/tile/basalt, 2, 1, 50, check_density = FALSE, category = CAT_TILES)\ + new /datum/stack_recipe("pile of dirt", /obj/machinery/hydroponics/soil, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \ + new /datum/stack_recipe("sandstone", /obj/item/stack/sheet/mineral/sandstone, 1, 1, 50, crafting_flags = NONE, category = CAT_MISC),\ + new /datum/stack_recipe("aesthetic volcanic floor tile", /obj/item/stack/tile/basalt, 2, 1, 50, crafting_flags = NONE, category = CAT_TILES)\ )) /obj/item/stack/ore/glass/Initialize(mapload, new_amount, merge, list/mat_override, mat_amt) @@ -453,7 +453,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ if (!attack_self(user)) user.visible_message(span_suicide("[user] couldn't flip \the [src]!")) return SHAME - addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 10)//10 = time takes for flip animation + addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 1 SECONDS)//10 = time takes for flip animation return MANUAL_SUICIDE_NONLETHAL /obj/item/coin/proc/manual_suicide(mob/living/user) diff --git a/code/modules/mining/satchel_ore_box.dm b/code/modules/mining/satchel_ore_box.dm index 3b2a5ce054c1d..b94796b161433 100644 --- a/code/modules/mining/satchel_ore_box.dm +++ b/code/modules/mining/satchel_ore_box.dm @@ -19,13 +19,11 @@ for(var/obj/item/weapon in src) weapon.forceMove(drop) -/obj/structure/ore_box/deconstruct(disassembled = TRUE) +/obj/structure/ore_box/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(loc, 4) dump_box_contents() - return ..() - /obj/structure/ore_box/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = NONE if(isnull(held_item)) diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 615eb55898c92..30d273db7daae 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -90,16 +90,20 @@ INITIALIZE_IMMEDIATE(/mob/dead) #undef SERVER_HOPPER_TRAIT -/mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister - if (registered_z != new_z) - if (registered_z) - SSmobs.dead_players_by_zlevel[registered_z] -= src - if (client) - if (new_z) - SSmobs.dead_players_by_zlevel[new_z] += src - registered_z = new_z - else - registered_z = null +/** + * updates the Z level for dead players + * If they don't have a new z, we'll keep the old one, preventing bugs from ghosting and re-entering, among others + */ +/mob/dead/proc/update_z(new_z) + if(registered_z == new_z) + return + if(registered_z) + SSmobs.dead_players_by_zlevel[registered_z] -= src + if(isnull(client)) + registered_z = null + return + registered_z = new_z + SSmobs.dead_players_by_zlevel[new_z] += src /mob/dead/Login() . = ..() diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index 4135f8d22faff..c239817a30e14 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -14,10 +14,6 @@ preferred_form = client.prefs.read_preference(/datum/preference/choiced/ghost_form) ghost_orbit = client.prefs.read_preference(/datum/preference/choiced/ghost_orbit) - var/turf/T = get_turf(src) - if (isturf(T)) - update_z(T.z) - update_icon(ALL, preferred_form) updateghostimages() client.set_right_click_menu_mode(FALSE) diff --git a/code/modules/mob/dead/observer/logout.dm b/code/modules/mob/dead/observer/logout.dm index 4ba701c0ae091..53db92d91e32c 100644 --- a/code/modules/mob/dead/observer/logout.dm +++ b/code/modules/mob/dead/observer/logout.dm @@ -1,5 +1,4 @@ /mob/dead/observer/Logout() - update_z(null) if (client) client.images -= (GLOB.ghost_images_default+GLOB.ghost_images_simple) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 0f7d5b16cce55..2ef79e5465cbb 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -60,6 +60,9 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) var/datum/spawners_menu/spawners_menu var/datum/minigames_menu/minigames_menu + /// The POI we're orbiting (orbit menu) + var/orbiting_ref + /mob/dead/observer/Initialize(mapload) set_invisibility(GLOB.observer_default_invisibility) @@ -89,15 +92,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) gender = body.gender if(body.mind && body.mind.name) - if(body.mind.ghostname) - name = body.mind.ghostname - else - name = body.mind.name + name = body.mind.ghostname || body.mind.name else - if(body.real_name) - name = body.real_name - else - name = random_unique_name(gender) + name = body.real_name || generate_random_mob_name(gender) + mind = body.mind //we don't transfer the mind but we keep a reference to it. @@ -125,8 +123,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) abstract_move(T) - if(!name) //To prevent nameless ghosts - name = random_unique_name(gender) + //To prevent nameless ghosts + name ||= generate_random_mob_name(FALSE) real_name = name if(!fun_verbs) @@ -161,7 +159,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) var/old_color = color color = COLOR_CULT_RED animate(src, color = old_color, time = 10, flags = ANIMATION_PARALLEL) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 10) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 1 SECONDS) /mob/dead/observer/Destroy() if(data_huds_on) @@ -221,7 +219,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) if(ghost_accs == GHOST_ACCS_FULL && (icon_state in GLOB.ghost_forms_with_accessories_list)) //check if this form supports accessories and if the client wants to show them if(facial_hairstyle) - var/datum/sprite_accessory/S = GLOB.facial_hairstyles_list[facial_hairstyle] + var/datum/sprite_accessory/S = SSaccessories.facial_hairstyles_list[facial_hairstyle] if(S) facial_hair_overlay = mutable_appearance(S.icon, "[S.icon_state]", -HAIR_LAYER) if(facial_hair_color) @@ -229,7 +227,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) facial_hair_overlay.alpha = 200 add_overlay(facial_hair_overlay) if(hairstyle) - var/datum/sprite_accessory/hair/S = GLOB.hairstyles_list[hairstyle] + var/datum/sprite_accessory/hair/S = SSaccessories.hairstyles_list[hairstyle] if(S) hair_overlay = mutable_appearance(S.icon, "[S.icon_state]", -HAIR_LAYER) if(hair_color) @@ -340,7 +338,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set_glide_size(glide_size_override) if(NewLoc) abstract_move(NewLoc) - update_parallax_contents() else var/turf/destination = get_turf(src) @@ -462,7 +459,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return usr.abstract_move(pick(L)) - update_parallax_contents() /mob/dead/observer/verb/follow() set category = "Ghost" @@ -533,7 +529,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(isturf(destination_turf)) source_mob.abstract_move(destination_turf) - source_mob.update_parallax_contents() else to_chat(source_mob, span_danger("This mob is not located in the game world.")) @@ -841,7 +836,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp client.prefs.apply_character_randomization_prefs() var/species_type = client.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] if(species.check_head_flags(HEAD_HAIR)) hairstyle = client.prefs.read_preference(/datum/preference/choiced/hairstyle) hair_color = ghostify_color(client.prefs.read_preference(/datum/preference/color/hair_color)) @@ -850,8 +845,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp facial_hairstyle = client.prefs.read_preference(/datum/preference/choiced/facial_hairstyle) facial_hair_color = ghostify_color(client.prefs.read_preference(/datum/preference/color/facial_hair_color)) - qdel(species) - update_appearance() /mob/dead/observer/can_perform_action(atom/movable/target, action_bitflags) @@ -1087,3 +1080,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!prefs || (client?.combo_hud_enabled && prefs.toggles & COMBOHUD_LIGHTING)) return ..() return GLOB.ghost_lighting_options[prefs.read_preference(/datum/preference/choiced/ghost_lighting)] + + +/// Called when we exit the orbiting state +/mob/dead/observer/proc/on_deorbit(datum/source) + SIGNAL_HANDLER + + orbiting_ref = null diff --git a/code/modules/mob/dead/observer/observer_say.dm b/code/modules/mob/dead/observer/observer_say.dm index e43086349b34e..a8fd0094934c3 100644 --- a/code/modules/mob/dead/observer/observer_say.dm +++ b/code/modules/mob/dead/observer/observer_say.dm @@ -5,7 +5,7 @@ /mob/dead/observer/get_message_mods(message, list/mods) var/key = message[1] if((key in GLOB.department_radio_prefixes) && length(message) > length(key) + 1 && !mods[RADIO_EXTENSION]) - mods[RADIO_KEY] = lowertext(message[1 + length(key)]) + mods[RADIO_KEY] = LOWER_TEXT(message[1 + length(key)]) mods[RADIO_EXTENSION] = GLOB.department_radio_keys[mods[RADIO_KEY]] return message @@ -44,9 +44,9 @@ message = trim_left(copytext_char(message, length(message_mods[RADIO_KEY]) + 2)) switch(message_mods[RADIO_EXTENSION]) if(MODE_ADMIN) - client.cmd_admin_say(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, message) if(MODE_DEADMIN) - client.dsay(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/dsay, message) if(MODE_PUPPET) if(!mind.current.say(message)) to_chat(src, span_warning("Your linked body was unable to speak!")) diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index db6acc346b158..ee0b4528995ef 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -36,19 +36,33 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) var/mob/dead/observer/user = usr user.ManualFollow(poi) user.reset_perspective(null) + user.orbiting_ref = ref if (auto_observe) user.do_observe(poi) return TRUE if ("refresh") - update_static_data(usr, ui) + ui.send_full_update() return TRUE + return FALSE + + +/datum/orbit_menu/ui_data(mob/user) + var/list/data = list() + + if(isobserver(user)) + data["orbiting"] = get_currently_orbiting(user) + + return data + + /datum/orbit_menu/ui_static_data(mob/user) var/list/new_mob_pois = SSpoints_of_interest.get_mob_pois(CALLBACK(src, PROC_REF(validate_mob_poi)), append_dead_role = FALSE) var/list/new_other_pois = SSpoints_of_interest.get_other_pois() var/list/alive = list() var/list/antagonists = list() + var/list/critical = list() var/list/deadchat_controlled = list() var/list/dead = list() var/list/ghosts = list() @@ -57,14 +71,10 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) for(var/name in new_mob_pois) var/list/serialized = list() - var/mob/mob_poi = new_mob_pois[name] - - var/poi_ref = REF(mob_poi) - var/number_of_orbiters = length(mob_poi.get_all_orbiters()) - serialized["ref"] = poi_ref + serialized["ref"] = REF(mob_poi) serialized["full_name"] = name if(number_of_orbiters) serialized["orbiters"] = number_of_orbiters @@ -81,33 +91,26 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) continue if(isnull(mob_poi.mind)) + if(isliving(mob_poi)) + var/mob/living/npc = mob_poi + serialized["health"] = FLOOR((npc.health / npc.maxHealth * 100), 1) + npcs += list(serialized) continue - var/datum/mind/mind = mob_poi.mind - var/was_antagonist = FALSE - + serialized["client"] = !!mob_poi.client serialized["name"] = mob_poi.real_name - if(isliving(mob_poi)) // handles edge cases like blob - var/mob/living/player = mob_poi - serialized["health"] = FLOOR((player.health / player.maxHealth * 100), 1) - if(issilicon(player)) - serialized["job"] = player.job - else - var/obj/item/card/id/id_card = player.get_idcard(hand_first = FALSE) - serialized["job"] = id_card?.get_trim_assignment() - - for(var/datum/antagonist/antag_datum as anything in mind.antag_datums) - if (antag_datum.show_to_ghosts) - was_antagonist = TRUE - serialized["antag"] = antag_datum.name - serialized["antag_group"] = antag_datum.antagpanel_category - antagonists += list(serialized) - break - - if(!was_antagonist) - alive += list(serialized) + if(isliving(mob_poi)) + serialized += get_living_data(mob_poi) + + var/list/antag_data = get_antag_data(mob_poi.mind) + if(length(antag_data)) + serialized += antag_data + antagonists += list(serialized) + continue + + alive += list(serialized) for(var/name in new_other_pois) var/atom/atom_poi = new_other_pois[name] @@ -122,32 +125,18 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) )) continue - misc += list(list( - "ref" = REF(atom_poi), - "full_name" = name, - )) + var/list/other_data = get_misc_data(atom_poi) + var/misc_data = list(other_data[1]) - // Display the supermatter crystal integrity - if(istype(atom_poi, /obj/machinery/power/supermatter_crystal)) - var/obj/machinery/power/supermatter_crystal/crystal = atom_poi - misc[length(misc)]["extra"] = "Integrity: [round(crystal.get_integrity_percent())]%" - continue - // Display the nuke timer - if(istype(atom_poi, /obj/machinery/nuclearbomb)) - var/obj/machinery/nuclearbomb/bomb = atom_poi - if(bomb.timing) - misc[length(misc)]["extra"] = "Timer: [bomb.countdown?.displayed_text]s" - continue - // Display the holder if its a nuke disk - if(istype(atom_poi, /obj/item/disk/nuclear)) - var/obj/item/disk/nuclear/disk = atom_poi - var/mob/holder = disk.pulledby || get(disk, /mob) - misc[length(misc)]["extra"] = "Location: [holder?.real_name || "Unsecured"]" - continue + misc += misc_data + + if(other_data[2]) // Critical = TRUE + critical += misc_data return list( "alive" = alive, "antagonists" = antagonists, + "critical" = critical, "deadchat_controlled" = deadchat_controlled, "dead" = dead, "ghosts" = ghosts, @@ -155,10 +144,131 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) "npcs" = npcs, ) + /// Shows the UI to the specified user. /datum/orbit_menu/proc/show(mob/user) ui_interact(user) + +/// Helper function to get threat type, group, overrides for job and icon +/datum/orbit_menu/proc/get_antag_data(datum/mind/poi_mind) as /list + var/list/serialized = list() + + for(var/datum/antagonist/antag as anything in poi_mind.antag_datums) + if(!antag.show_to_ghosts) + continue + + serialized["antag"] = antag.name + serialized["antag_group"] = antag.antagpanel_category + serialized["job"] = antag.name + serialized["icon"] = antag.antag_hud_name + + return serialized + + +/// Helper to get the current thing we're orbiting (if any) +/datum/orbit_menu/proc/get_currently_orbiting(mob/dead/observer/user) + if(isnull(user.orbiting_ref)) + return + + var/atom/poi = SSpoints_of_interest.get_poi_atom_by_ref(user.orbiting_ref) + if(isnull(poi)) + user.orbiting_ref = null + return + + if((ismob(poi) && !SSpoints_of_interest.is_valid_poi(poi, CALLBACK(src, PROC_REF(validate_mob_poi)))) \ + || !SSpoints_of_interest.is_valid_poi(poi) + ) + user.orbiting_ref = null + return + + var/list/serialized = list() + + if(!ismob(poi)) + var/list/misc_info = get_misc_data(poi) + serialized += misc_info[1] + return serialized + + var/mob/mob_poi = poi + serialized["full_name"] = mob_poi.name + serialized["ref"] = REF(poi) + + if(mob_poi.mind) + serialized["client"] = !!mob_poi.client + serialized["name"] = mob_poi.real_name + + if(isliving(mob_poi)) + serialized += get_living_data(mob_poi) + + return serialized + + +/// Helper function to get job / icon / health data for a living mob +/datum/orbit_menu/proc/get_living_data(mob/living/player) as /list + var/list/serialized = list() + + serialized["health"] = FLOOR((player.health / player.maxHealth * 100), 1) + if(issilicon(player)) + serialized["job"] = player.job + serialized["icon"] = "borg" + else + var/obj/item/card/id/id_card = player.get_idcard(hand_first = FALSE) + serialized["job"] = id_card?.get_trim_assignment() + serialized["icon"] = id_card?.get_trim_sechud_icon_state() + + return serialized + + +/// Gets a list: Misc data and whether it's critical. Handles all snowflakey type cases +/datum/orbit_menu/proc/get_misc_data(atom/movable/atom_poi) as /list + var/list/misc = list() + var/critical = FALSE + + misc["ref"] = REF(atom_poi) + misc["full_name"] = atom_poi.name + + // Display the supermatter crystal integrity + if(istype(atom_poi, /obj/machinery/power/supermatter_crystal)) + var/obj/machinery/power/supermatter_crystal/crystal = atom_poi + var/integrity = round(crystal.get_integrity_percent()) + misc["extra"] = "Integrity: [integrity]%" + + if(integrity < 10) + critical = TRUE + + return list(misc, critical) + + // Display the nuke timer + if(istype(atom_poi, /obj/machinery/nuclearbomb)) + var/obj/machinery/nuclearbomb/bomb = atom_poi + + if(bomb.timing) + misc["extra"] = "Timer: [bomb.countdown?.displayed_text]s" + critical = TRUE + + return list(misc, critical) + + // Display the holder if its a nuke disk + if(istype(atom_poi, /obj/item/disk/nuclear)) + var/obj/item/disk/nuclear/disk = atom_poi + var/mob/holder = disk.pulledby || get(disk, /mob) + misc["extra"] = "Location: [holder?.real_name || "Unsecured"]" + + return list(misc, critical) + + // Display singuloths if they exist + if(istype(atom_poi, /obj/singularity)) + var/obj/singularity/singulo = atom_poi + misc["extra"] = "Energy: [round(singulo.energy)]" + + if(singulo.current_size > 2) + critical = TRUE + + return list(misc, critical) + + return list(misc, critical) + + /** * Helper POI validation function passed as a callback to various SSpoints_of_interest procs. * @@ -181,3 +291,4 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) return FALSE return potential_poi.validate() + diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index bf9e099e5c97e..c1822ff0e51c4 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -19,7 +19,7 @@ param = copytext(act, custom_param + length(act[custom_param])) act = copytext(act, 1, custom_param) - act = lowertext(act) + act = LOWER_TEXT(act) var/list/key_emotes = GLOB.emote_list[act] if(!length(key_emotes)) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index bc44e6518686e..b118de06f057a 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -429,10 +429,10 @@ var/obscured = NONE var/hidden_slots = NONE - for(var/obj/item/I in get_all_worn_items()) - hidden_slots |= I.flags_inv + for(var/obj/item/equipped_item in get_equipped_items()) + hidden_slots |= equipped_item.flags_inv if(transparent_protection) - hidden_slots |= I.transparent_protection + hidden_slots |= equipped_item.transparent_protection if(hidden_slots & HIDENECK) obscured |= ITEM_SLOT_NECK @@ -456,26 +456,32 @@ return obscured -/obj/item/proc/equip_to_best_slot(mob/M) - if(M.equip_to_appropriate_slot(src)) - M.update_held_items() +/// Tries to equip an item, store it in open storage, or in next best storage +/obj/item/proc/equip_to_best_slot(mob/user) + if(user.equip_to_appropriate_slot(src)) + user.update_held_items() return TRUE else if(equip_delay_self) return - if(M.active_storage?.attempt_insert(src, M)) + if(user.active_storage?.attempt_insert(src, user, messages = FALSE)) return TRUE - var/list/obj/item/possible = list(M.get_inactive_held_item(), M.get_item_by_slot(ITEM_SLOT_BELT), M.get_item_by_slot(ITEM_SLOT_DEX_STORAGE), M.get_item_by_slot(ITEM_SLOT_BACK)) - for(var/i in possible) - if(!i) + var/list/obj/item/possible = list( + user.get_inactive_held_item(), + user.get_item_by_slot(ITEM_SLOT_BELT), + user.get_item_by_slot(ITEM_SLOT_DEX_STORAGE), + user.get_item_by_slot(ITEM_SLOT_BACK), + ) + for(var/thing in possible) + if(isnull(thing)) continue - var/obj/item/I = i - if(I.atom_storage?.attempt_insert(src, M)) + var/obj/item/gear = thing + if(gear.atom_storage?.attempt_insert(src, user, messages = FALSE)) return TRUE - to_chat(M, span_warning("You are unable to equip that!")) + to_chat(user, span_warning("You are unable to equip that!")) return FALSE @@ -504,12 +510,8 @@ if(!I) to_chat(src, span_warning("You are not holding anything to equip!")) return - if (temporarilyRemoveItemFromInventory(I) && !QDELETED(I)) - if(I.equip_to_best_slot(src)) - return - if(put_in_active_hand(I)) - return - I.forceMove(drop_location()) + if(!QDELETED(I)) + I.equip_to_best_slot(src) //used in code for items usable by both carbon and drones, this gives the proper back slot for each mob.(defibrillator, backpack watertank, ...) /mob/proc/getBackSlot() diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index 3e26246829827..98a771a06a99d 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -121,6 +121,7 @@ return apply_atmos_requirements(mapload) apply_temperature_requirements(mapload) + apply_target_randomisation() /mob/living/basic/proc/on_ssair_init(datum/source) SIGNAL_HANDLER @@ -142,6 +143,11 @@ return AddElement(/datum/element/body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage, mapload) +/mob/living/basic/proc/apply_target_randomisation() + if (basic_mob_flags & PRECISE_ATTACK_ZONES) + return + AddElement(/datum/element/attack_zone_randomiser) + /mob/living/basic/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() if(staminaloss > 0) diff --git a/code/modules/mob/living/basic/blob_minions/blob_zombie.dm b/code/modules/mob/living/basic/blob_minions/blob_zombie.dm index 3cbce54cf29db..50299a38b3fee 100644 --- a/code/modules/mob/living/basic/blob_minions/blob_zombie.dm +++ b/code/modules/mob/living/basic/blob_minions/blob_zombie.dm @@ -87,7 +87,7 @@ /mob/living/basic/blob_minion/zombie/controlled/consume_corpse(mob/living/carbon/human/new_corpse) . = ..() - if (!isnull(client)) + if (!isnull(client) || SSticker.current_state == GAME_STATE_FINISHED) return AddComponent(\ /datum/component/ghost_direct_control,\ diff --git a/code/modules/mob/living/basic/bots/_bots.dm b/code/modules/mob/living/basic/bots/_bots.dm index 206ba88b317e7..d98369294e018 100644 --- a/code/modules/mob/living/basic/bots/_bots.dm +++ b/code/modules/mob/living/basic/bots/_bots.dm @@ -6,6 +6,8 @@ GLOBAL_LIST_INIT(command_strings, list( "home" = "RETURN HOME", )) +#define SENTIENT_BOT_RESET_TIMER 45 SECONDS + /mob/living/basic/bot icon = 'icons/mob/silicon/aibots.dmi' layer = MOB_LAYER @@ -39,6 +41,7 @@ GLOBAL_LIST_INIT(command_strings, list( light_power = 0.6 speed = 3 req_one_access = list(ACCESS_ROBOTICS) + interaction_flags_click = ALLOW_SILICON_REACH ///The Robot arm attached to this robot - has a 50% chance to drop on death. var/robot_arm = /obj/item/bodypart/arm/right/robot ///The inserted (if any) pAI in this bot. @@ -360,13 +363,9 @@ GLOBAL_LIST_INIT(command_strings, list( ui = new(user, src, "SimpleBot", name) ui.open() -/mob/living/basic/bot/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return - if(!user.can_perform_action(src, ALLOW_SILICON_REACH)) - return +/mob/living/basic/bot/click_alt(mob/user) unlock_with_id(user) + return CLICK_ACTION_SUCCESS /mob/living/basic/bot/proc/unlock_with_id(mob/living/user) if(bot_access_flags & BOT_COVER_EMAGGED) @@ -758,9 +757,7 @@ GLOBAL_LIST_INIT(command_strings, list( /mob/living/basic/bot/proc/attempt_access(mob/bot, obj/door_attempt) SIGNAL_HANDLER - if(door_attempt.check_access(access_card)) - return ACCESS_ALLOWED - return ACCESS_DISALLOWED + return (door_attempt.check_access(access_card) ? ACCESS_ALLOWED : ACCESS_DISALLOWED) /mob/living/basic/bot/proc/generate_speak_list() return null @@ -783,6 +780,8 @@ GLOBAL_LIST_INIT(command_strings, list( access_card.set_access(access_to_grant) speak("Responding.", radio_channel) update_bot_mode(new_mode = BOT_SUMMON) + if(client) //if we're sentient, we reset ourselves after a short period + addtimer(CALLBACK(src, PROC_REF(bot_reset)), SENTIENT_BOT_RESET_TIMER) return TRUE /mob/living/basic/bot/proc/set_ai_caller(mob/living/caller) @@ -809,3 +808,5 @@ GLOBAL_LIST_INIT(command_strings, list( /mob/living/basic/bot/proc/on_bot_movement(atom/movable/source, atom/oldloc, dir, forced) return + +#undef SENTIENT_BOT_RESET_TIMER diff --git a/code/modules/mob/living/basic/bots/bot_ai.dm b/code/modules/mob/living/basic/bots/bot_ai.dm index 21abafb860e81..1c30f83b2e64c 100644 --- a/code/modules/mob/living/basic/bots/bot_ai.dm +++ b/code/modules/mob/living/basic/bots/bot_ai.dm @@ -2,9 +2,8 @@ blackboard = list( BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_SALUTE_MESSAGES = list( - "salutes", + "performs an elaborate salute for", "nods in appreciation towards", - "fist bumps", ), BB_UNREACHABLE_LIST_COOLDOWN = 45 SECONDS, ) @@ -28,12 +27,20 @@ var/current_pathing_attempts = 0 ///if we cant reach it after this many attempts, add it to our ignore list var/max_pathing_attempts = 25 + can_idle = FALSE // we want these to be running always /datum/ai_controller/basic_controller/bot/TryPossessPawn(atom/new_pawn) . = ..() if(. & AI_CONTROLLER_INCOMPATIBLE) return RegisterSignal(new_pawn, COMSIG_BOT_RESET, PROC_REF(reset_bot)) + RegisterSignal(new_pawn, COMSIG_AI_BLACKBOARD_KEY_CLEARED(BB_BOT_SUMMON_TARGET), PROC_REF(clear_summon)) + +/datum/ai_controller/basic_controller/bot/proc/clear_summon() + SIGNAL_HANDLER + + var/mob/living/basic/bot/bot_pawn = pawn + bot_pawn.bot_reset() /datum/ai_controller/basic_controller/bot/able_to_run() var/mob/living/basic/bot/bot_pawn = pawn @@ -84,10 +91,9 @@ behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION /datum/ai_behavior/manage_unreachable_list/perform(seconds_per_tick, datum/ai_controller/controller, list_key) - . = ..() if(!isnull(controller.blackboard[list_key])) controller.clear_blackboard_key(list_key) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/manage_unreachable_list/finish_action(datum/ai_controller/controller, succeeded) . = ..() @@ -116,7 +122,6 @@ /datum/ai_behavior/find_first_beacon_target /datum/ai_behavior/find_first_beacon_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/closest_distance = INFINITY var/mob/living/basic/bot/bot_pawn = controller.pawn var/atom/final_target @@ -131,19 +136,16 @@ final_target = beacon if(isnull(final_target)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(BB_BEACON_TARGET, final_target) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/find_next_beacon_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/basic/bot/bot_pawn = controller.pawn var/atom/final_target var/obj/machinery/navbeacon/prev_beacon = controller.blackboard[BB_PREVIOUS_BEACON_TARGET] if(QDELETED(prev_beacon)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED for(var/obj/machinery/navbeacon/beacon as anything in GLOB.navbeacons["[bot_pawn.z]"]) if(beacon.location == prev_beacon.codes[NAVBEACON_PATROL_NEXT]) @@ -152,10 +154,10 @@ if(isnull(final_target)) controller.clear_blackboard_key(BB_PREVIOUS_BEACON_TARGET) - finish_action(controller, FALSE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(BB_BEACON_TARGET, final_target) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/travel_towards/beacon @@ -205,7 +207,7 @@ /datum/ai_behavior/find_and_set/valid_authority behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION - action_cooldown = 30 SECONDS + action_cooldown = BOT_COMMISSIONED_SALUTE_DELAY /datum/ai_behavior/find_and_set/valid_authority/search_tactic(datum/ai_controller/controller, locate_path, search_range) for(var/mob/living/nearby_mob in oview(search_range, controller.pawn)) @@ -217,23 +219,19 @@ /datum/ai_behavior/salute_authority /datum/ai_behavior/salute_authority/perform(seconds_per_tick, datum/ai_controller/controller, target_key, salute_keys) - . = ..() if(!controller.blackboard_key_exists(target_key)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/list/salute_list = controller.blackboard[salute_keys] if(!length(salute_list)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/basic/bot/bot_pawn = controller.pawn //special interaction if we are wearing a fedora var/obj/item/our_hat = (locate(/obj/item/clothing/head) in bot_pawn) if(our_hat) salute_list += "tips [our_hat] at " - bot_pawn.manual_emote(pick(salute_list) + " [controller.blackboard[target_key]]") - finish_action(controller, TRUE, target_key) - return + bot_pawn.manual_emote(pick(salute_list) + " [controller.blackboard[target_key]]!") + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/salute_authority/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm index 537490c8431bd..a58a97c7274e0 100644 --- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm +++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm @@ -122,16 +122,14 @@ set_movement_target(controller, target) /datum/ai_behavior/execute_clean/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/basic/living_pawn = controller.pawn var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED living_pawn.UnarmedAttack(target, proximity_flag = TRUE) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/execute_clean/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) . = ..() diff --git a/code/modules/mob/living/basic/bots/hygienebot/hygienebot_ai.dm b/code/modules/mob/living/basic/bots/hygienebot/hygienebot_ai.dm index d982869595bcb..2c614e003c8ab 100644 --- a/code/modules/mob/living/basic/bots/hygienebot/hygienebot_ai.dm +++ b/code/modules/mob/living/basic/bots/hygienebot/hygienebot_ai.dm @@ -80,11 +80,10 @@ break if(isnull(found_target)) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(target_key, found_target) - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED @@ -112,17 +111,15 @@ var/mob/living/carbon/human/unclean_target = controller.blackboard[target_key] var/mob/living/basic/living_pawn = controller.pawn if(QDELETED(unclean_target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(living_pawn.loc == get_turf(unclean_target)) living_pawn.melee_attack(unclean_target) - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED var/frustration_count = controller.blackboard[BB_WASH_FRUSTRATION] controller.set_blackboard_key(BB_WASH_FRUSTRATION, frustration_count + 1) - finish_action(controller, FALSE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/wash_target/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/modules/mob/living/basic/bots/medbot/medbot.dm b/code/modules/mob/living/basic/bots/medbot/medbot.dm index d85adc3ea2364..fcf252c017809 100644 --- a/code/modules/mob/living/basic/bots/medbot/medbot.dm +++ b/code/modules/mob/living/basic/bots/medbot/medbot.dm @@ -7,7 +7,6 @@ icon_state = "medibot0" base_icon_state = "medibot" density = FALSE - anchored = FALSE health = 20 maxHealth = 20 speed = 2 @@ -162,7 +161,6 @@ return INITIALIZE_HINT_LATELOAD /mob/living/basic/bot/medbot/LateInitialize() - . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb) CONNECT_TO_RND_SERVER_ROUNDSTART(linked_techweb, src) diff --git a/code/modules/mob/living/basic/bots/medbot/medbot_ai.dm b/code/modules/mob/living/basic/bots/medbot/medbot_ai.dm index 21f9ab29d1b35..0a4520ad17b26 100644 --- a/code/modules/mob/living/basic/bots/medbot/medbot_ai.dm +++ b/code/modules/mob/living/basic/bots/medbot/medbot_ai.dm @@ -53,7 +53,6 @@ action_cooldown = 2 SECONDS /datum/ai_behavior/find_suitable_patient/perform(seconds_per_tick, datum/ai_controller/basic_controller/bot/controller, target_key, threshold, heal_type, mode_flags, access_flags) - . = ..() search_range = (mode_flags & MEDBOT_STATIONARY_MODE) ? 1 : initial(search_range) var/list/ignore_keys = controller.blackboard[BB_TEMPORARY_IGNORE_LIST] for(var/mob/living/carbon/human/treatable_target in oview(search_range, controller.pawn)) @@ -71,7 +70,10 @@ controller.set_if_can_reach(BB_PATIENT_TARGET, treatable_target, distance = BOT_PATIENT_PATH_LIMIT, bypass_add_to_blacklist = (search_range == 1)) break - finish_action(controller, controller.blackboard_key_exists(BB_PATIENT_TARGET)) + if(controller.blackboard_key_exists(BB_PATIENT_TARGET)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + else + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/find_suitable_patient/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() @@ -91,21 +93,18 @@ set_movement_target(controller, target) /datum/ai_behavior/tend_to_patient/perform(seconds_per_tick, datum/ai_controller/basic_controller/bot/controller, target_key, threshold, damage_type_healer, access_flags, is_stationary) - . = ..() var/mob/living/carbon/human/patient = controller.blackboard[target_key] if(QDELETED(patient) || patient.stat == DEAD) - finish_action(controller, FALSE, target_key, is_stationary) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(check_if_healed(patient, threshold, damage_type_healer, access_flags)) - finish_action(controller, TRUE, target_key, is_stationary, healed_target = TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED var/mob/living/basic/bot/bot_pawn = controller.pawn if(patient.stat >= HARD_CRIT && prob(5)) var/datum/action/cooldown/bot_announcement/announcement = controller.blackboard[BB_ANNOUNCE_ABILITY] announcement?.announce(pick(controller.blackboard[BB_NEAR_DEATH_SPEECH])) bot_pawn.melee_attack(patient) - finish_action(controller, TRUE, target_key, is_stationary) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED // only clear the target if they get healed /datum/ai_behavior/tend_to_patient/finish_action(datum/ai_controller/controller, succeeded, target_key, is_stationary, healed_target = FALSE) @@ -171,11 +170,10 @@ speech_to_pick_from += MEDIBOT_VOICED_CHICKEN if(!length(speech_to_pick_from)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED announcement.announce(pick(speech_to_pick_from)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_planning_subtree/find_and_hunt_target/patients_in_crit target_key = BB_PATIENT_IN_CRIT @@ -202,18 +200,15 @@ behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION /datum/ai_behavior/announce_patient/perform(seconds_per_tick, datum/ai_controller/basic_controller/bot/controller, target_key) - . = ..() var/mob/living/living_target = controller.blackboard[target_key] if(QDELETED(living_target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/datum/action/cooldown/bot_announcement/announcement = controller.blackboard[BB_ANNOUNCE_ABILITY] if(QDELETED(announcement)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/text_to_announce = "Medical emergency! [living_target] is in critical condition at [get_area(living_target)]!" announcement.announce(text_to_announce, controller.blackboard[BB_RADIO_CHANNEL]) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/announce_patient/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index a1a7014b26354..9e8f6950525a7 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -88,7 +88,7 @@ /mob/living/basic/clown/lube/Initialize(mapload) . = ..() - AddElement(/datum/element/snailcrawl) + AddElement(/datum/element/lube_walking) /mob/living/basic/clown/honkling name = "Honkling" diff --git a/code/modules/mob/living/basic/cult/shade.dm b/code/modules/mob/living/basic/cult/shade.dm index fac1d347665ef..bf6fbe13944a1 100644 --- a/code/modules/mob/living/basic/cult/shade.dm +++ b/code/modules/mob/living/basic/cult/shade.dm @@ -54,6 +54,8 @@ icon_living = icon_state /mob/living/basic/shade/death() + if(IS_CULTIST(src)) + SSblackbox.record_feedback("tally", "cult_shade_killed", 1) if(death_message == initial(death_message)) death_message = "lets out a contented sigh as [p_their()] form unwinds." ..() @@ -63,6 +65,11 @@ return FALSE return ..() +/mob/living/basic/shade/suicide_log(obj/item/suicide_tool) + if(IS_CULTIST(src)) + SSblackbox.record_feedback("tally", "cult_shade_suicided", 1) + ..() + /mob/living/basic/shade/attackby(obj/item/item, mob/user, params) if(istype(item, /obj/item/soulstone)) var/obj/item/soulstone/stone = item diff --git a/code/modules/mob/living/basic/drone/drone_tools.dm b/code/modules/mob/living/basic/drone/drone_tools.dm index 2350ec9cafbf4..1fa3aa7884b2a 100644 --- a/code/modules/mob/living/basic/drone/drone_tools.dm +++ b/code/modules/mob/living/basic/drone/drone_tools.dm @@ -48,7 +48,7 @@ name = "built-in crowbar" desc = "A crowbar built into your chassis." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "crowbar_cyborg" + icon_state = "toolkit_engiborg_crowbar" inhand_icon_state = "crowbar" item_flags = NO_MAT_REDEMPTION @@ -56,7 +56,7 @@ name = "built-in screwdriver" desc = "A screwdriver built into your chassis." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "screwdriver_cyborg" + icon_state = "toolkit_engiborg_screwdriver" inhand_icon_state = "screwdriver" item_flags = NO_MAT_REDEMPTION random_color = FALSE @@ -75,7 +75,7 @@ name = "built-in wrench" desc = "A wrench built into your chassis." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "wrench_cyborg" + icon_state = "toolkit_engiborg_wrench" inhand_icon_state = "wrench" item_flags = NO_MAT_REDEMPTION @@ -90,7 +90,7 @@ name = "built-in wirecutters" desc = "Wirecutters built into your chassis." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "wirecutters_cyborg" + icon_state = "toolkit_engiborg_cutters" inhand_icon_state = "cutters" item_flags = NO_MAT_REDEMPTION random_color = FALSE @@ -99,6 +99,6 @@ name = "built-in multitool" desc = "A multitool built into your chassis." icon = 'icons/obj/items_cyborg.dmi' - icon_state = "multitool_cyborg" + icon_state = "toolkit_engiborg_multitool" item_flags = NO_MAT_REDEMPTION toolspeed = 0.5 diff --git a/code/modules/mob/living/basic/drone/interaction.dm b/code/modules/mob/living/basic/drone/interaction.dm index c528dafcbd6de..0b0247c1c45f3 100644 --- a/code/modules/mob/living/basic/drone/interaction.dm +++ b/code/modules/mob/living/basic/drone/interaction.dm @@ -14,7 +14,7 @@ to_chat(drone, span_warning("You're already in perfect condition!")) return drone.visible_message(span_notice("[drone] begins to cannibalize parts from [src]."), span_notice("You begin to cannibalize parts from [src]...")) - if(do_after(drone, 60, 0, target = src)) + if(do_after(drone, 6 SECONDS, 0, target = src)) drone.visible_message(span_notice("[drone] repairs itself using [src]'s remains!"), span_notice("You repair yourself using [src]'s remains.")) drone.adjustBruteLoss(-src.maxHealth) new /obj/effect/decal/cleanable/oil/streak(get_turf(src)) @@ -67,7 +67,7 @@ to_chat(user, span_warning("You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)].")) return user.visible_message(span_notice("[user] begins to reactivate [src]."), span_notice("You begin to reactivate [src]...")) - if(do_after(user, 30, 1, target = src)) + if(do_after(user, 3 SECONDS, 1, target = src)) revive(HEAL_ALL) user.visible_message(span_notice("[user] reactivates [src]!"), span_notice("You reactivate [src].")) alert_drones(DRONE_NET_CONNECT) diff --git a/code/modules/mob/living/basic/drone/visuals_icons.dm b/code/modules/mob/living/basic/drone/visuals_icons.dm index ec01d7d2d7892..7a2122022f81b 100644 --- a/code/modules/mob/living/basic/drone/visuals_icons.dm +++ b/code/modules/mob/living/basic/drone/visuals_icons.dm @@ -27,7 +27,7 @@ client.screen += internal_storage -/mob/living/basic/drone/update_worn_head() +/mob/living/basic/drone/update_worn_head(update_obscured = TRUE) remove_overlay(DRONE_HEAD_LAYER) if(head) @@ -44,7 +44,7 @@ apply_overlay(DRONE_HEAD_LAYER) -/mob/living/basic/drone/update_worn_mask() +/mob/living/basic/drone/update_worn_mask(update_obscured = TRUE) update_worn_head() /mob/living/basic/drone/regenerate_icons() diff --git a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm index 0c48a9453811d..b4d73ad59273a 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm @@ -25,7 +25,6 @@ set_movement_target(controller, target) /datum/ai_behavior/enter_exit_hive/perform(seconds_per_tick, datum/ai_controller/controller, target_key, attack_key) - . = ..() var/obj/structure/beebox/current_home = controller.blackboard[target_key] var/mob/living/bee_pawn = controller.pawn var/atom/attack_target = controller.blackboard[attack_key] @@ -35,7 +34,7 @@ var/datum/callback/callback = CALLBACK(bee_pawn, TYPE_PROC_REF(/mob/living/basic/bee, handle_habitation), current_home) callback.Invoke() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/inhabit_hive behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH @@ -48,17 +47,15 @@ set_movement_target(controller, target) /datum/ai_behavior/inhabit_hive/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/obj/structure/beebox/potential_home = controller.blackboard[target_key] var/mob/living/bee_pawn = controller.pawn if(!potential_home.habitable(bee_pawn)) //the house become full before we get to it - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/datum/callback/callback = CALLBACK(bee_pawn, TYPE_PROC_REF(/mob/living/basic/bee, handle_habitation), potential_home) callback.Invoke() - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/inhabit_hive/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() @@ -158,19 +155,18 @@ set_movement_target(controller, target) /datum/ai_behavior/swirl_around_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/atom/target = controller.blackboard[target_key] var/mob/living/living_pawn = controller.pawn if(QDELETED(target)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED if(get_dist(target, living_pawn) > 1) set_movement_target(controller, target) - return + return AI_BEHAVIOR_DELAY if(!SPT_PROB(swirl_chance, seconds_per_tick)) - return + return AI_BEHAVIOR_DELAY var/list/possible_turfs = list() @@ -180,10 +176,11 @@ possible_turfs += possible_turf if(!length(possible_turfs)) - return + return AI_BEHAVIOR_DELAY if(isnull(controller.movement_target_source) || controller.movement_target_source == type) set_movement_target(controller, pick(possible_turfs)) + return AI_BEHAVIOR_DELAY /datum/pet_command/beehive diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm index e9dc43837fff6..423f3b8c3975f 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -68,6 +68,13 @@ AddComponent(/datum/component/basic_inhands, y_offset = -1) ai_controller?.set_blackboard_key(BB_BASIC_FOODS, typecacheof(gorilla_food)) +/mob/living/basic/gorilla/examine(mob/user) + . = ..() + if (!HAS_MIND_TRAIT(user, TRAIT_EXAMINE_FITNESS)) + return + . += span_notice("This animal appears to be in peak physical condition and yet it has probably never worked out a day in its life. \ + The untapped potential is almost frightening.") + /mob/living/basic/gorilla/update_overlays() . = ..() if (is_holding_items()) diff --git a/code/modules/mob/living/basic/festivus_pole.dm b/code/modules/mob/living/basic/festivus_pole.dm index 90eca4b272d3c..838674c081124 100644 --- a/code/modules/mob/living/basic/festivus_pole.dm +++ b/code/modules/mob/living/basic/festivus_pole.dm @@ -1,3 +1,6 @@ +///how much charge we give off to cells around us when rubbed +#define FESTIVUS_RECHARGE_VALUE (0.075 * STANDARD_CELL_CHARGE) + /mob/living/basic/festivus name = "festivus pole" desc = "Serenity now... SERENITY NOW!" @@ -37,10 +40,6 @@ ai_controller = /datum/ai_controller/basic_controller/festivus_pole - ///how much charge we give off to cells around us when rubbed - var/recharge_value = 75 KILO JOULES - - /mob/living/basic/festivus/Initialize(mapload) . = ..() AddComponent(/datum/component/seethrough_mob) @@ -71,16 +70,16 @@ for(var/atom/affected in range(2, get_turf(src))) if(istype(affected, /obj/item/stock_parts/cell)) var/obj/item/stock_parts/cell/cell = affected - cell.give(recharge_value) + cell.give(FESTIVUS_RECHARGE_VALUE) cell.update_appearance() if(istype(affected, /mob/living/silicon/robot)) var/mob/living/silicon/robot/robot = affected if(robot.cell) - robot.cell.give(recharge_value) + robot.cell.give(FESTIVUS_RECHARGE_VALUE) if(istype(affected, /obj/machinery/power/apc)) var/obj/machinery/power/apc/apc_target = affected if(apc_target.cell) - apc_target.cell.give(recharge_value) + apc_target.cell.give(FESTIVUS_RECHARGE_VALUE) /datum/ai_planning_subtree/find_and_hunt_target/look_for_apcs hunting_behavior = /datum/ai_behavior/hunt_target/apcs @@ -118,3 +117,5 @@ return FALSE return can_see(source, dinner, radius) + +#undef FESTIVUS_RECHARGE_VALUE diff --git a/code/modules/mob/living/basic/heretic/rust_walker.dm b/code/modules/mob/living/basic/heretic/rust_walker.dm index ff56c311f7346..24b77d4d0b8e0 100644 --- a/code/modules/mob/living/basic/heretic/rust_walker.dm +++ b/code/modules/mob/living/basic/heretic/rust_walker.dm @@ -6,8 +6,8 @@ icon_state = "rust_walker_s" base_icon_state = "rust_walker" icon_living = "rust_walker_s" - maxHealth = 75 - health = 75 + maxHealth = 100 + health = 100 melee_damage_lower = 15 melee_damage_upper = 20 sight = SEE_TURFS diff --git a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_ai.dm b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_ai.dm index 20bcd8a69a130..8a900b0308a9d 100644 --- a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_ai.dm +++ b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon_ai.dm @@ -48,13 +48,11 @@ /datum/ai_behavior/find_valid_teleport_location /datum/ai_behavior/find_valid_teleport_location/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, types_to_hunt, hunt_range) - . = ..() var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] var/list/possible_turfs = list() if(QDELETED(target)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED for(var/turf/open/potential_turf in oview(hunt_range, target)) //we check for turfs around the target if(potential_turf.is_blocked_turf()) @@ -64,11 +62,10 @@ possible_turfs += potential_turf if(!length(possible_turfs)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(hunting_target_key, pick(possible_turfs)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/hunt_target/use_ability_on_target/demon_teleport hunt_cooldown = 2 SECONDS diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm index 725dcc09b5ec9..53d7e7191ef05 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm @@ -38,8 +38,7 @@ /datum/ai_behavior/hunt_target/unarmed_attack_target/dragon_cannibalise/perform(seconds_per_tick, datum/ai_controller/controller, target_key, attack_key) var/mob/living/target = controller.blackboard[target_key] if(QDELETED(target) || target.stat != DEAD || target.pulledby) //we were too slow - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED return ..() /datum/ai_behavior/cannibalize/finish_action(datum/ai_controller/controller, succeeded, target_key) @@ -67,17 +66,14 @@ set_movement_target(controller, target) /datum/ai_behavior/sculpt_statue/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - var/atom/target = controller.blackboard[target_key] var/mob/living/basic/living_pawn = controller.pawn if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED living_pawn.melee_attack(target) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/sculpt_statue/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() @@ -123,8 +119,6 @@ /datum/ai_behavior/set_target_tree /datum/ai_behavior/set_target_tree/perform(seconds_per_tick, datum/ai_controller/controller, tree_key) - . = ..() - var/mob/living_pawn = controller.pawn var/list/possible_trees = list() @@ -134,11 +128,10 @@ possible_trees += possible_tree if(!length(possible_trees)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(tree_key, pick(possible_trees)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/targeted_mob_ability/and_clear_target/burn_trees behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm index 21169ffd36889..61f31f7044dbc 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm @@ -44,7 +44,7 @@ StartCooldown() return TRUE - do_after(owner, delay = beam_duration, target = owner) + do_after(owner, delay = beam_duration, target = owner, hidden = TRUE) extinguish_laser() StartCooldown() return TRUE diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm index 0012aff294d40..98025373b4100 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm @@ -43,6 +43,5 @@ /datum/ai_behavior/targeted_mob_ability/brimbeam/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key) var/mob/living/target = controller.blackboard[target_key] if (QDELETED(target) || !(get_dir(controller.pawn, target) in GLOB.cardinals) || get_dist(controller.pawn, target) > max_target_distance) - finish_action(controller, succeeded = FALSE, ability_key = ability_key, target_key = target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED return ..() diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm index 76c230520df34..86ba1e003208f 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm @@ -36,8 +36,7 @@ if (ismecha(target) || (isliving(target) && !target.has_status_effect(/datum/status_effect/incapacitating/stun/goliath_tentacled))) var/datum/action/cooldown/using_action = controller.blackboard[BB_GOLIATH_TENTACLES] if (using_action?.IsAvailable()) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED return ..() /datum/ai_planning_subtree/targeted_mob_ability/goliath_tentacles @@ -67,20 +66,18 @@ var/scan_range = 3 /datum/ai_behavior/goliath_find_diggable_turf/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/turf/target_turf = controller.blackboard[target_key] if (is_valid_turf(target_turf)) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/pawn = controller.pawn var/list/nearby_turfs = RANGE_TURFS(scan_range, pawn) var/turf/check_turf = pick(nearby_turfs) // This isn't an efficient search algorithm but we don't need it to be if (!is_valid_turf(check_turf)) - finish_action(controller, succeeded = FALSE) // Otherwise they won't perform idle wanderin - return + // Otherwise they won't perform idle wanderin + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(target_key, check_turf) - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /// Return true if this is a turf we can dig /datum/ai_behavior/goliath_find_diggable_turf/proc/is_valid_turf(turf/check_turf) @@ -112,13 +109,12 @@ set_movement_target(controller, target_turf) /datum/ai_behavior/goliath_dig/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/turf/target_turf = controller.blackboard[target_key] var/mob/living/basic/basic_mob = controller.pawn if(!basic_mob.CanReach(target_turf)) - return + return AI_BEHAVIOR_DELAY basic_mob.melee_attack(target_turf) - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/goliath_dig/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm index 1ac43c13eb443..0180c4f179775 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm @@ -1,34 +1,31 @@ -/obj/structure/ore_container/gutlunch_trough - name = "gutlunch trough" - desc = "The gutlunches will eat out of it!" - icon = 'icons/obj/structures.dmi' - icon_state = "gutlunch_trough" +/obj/structure/ore_container/food_trough density = TRUE anchored = TRUE ///list of materials in the trough var/list/list_of_materials = list() + ///x offsets for materials to be placed + var/list/x_offsets = list() + ///y offsets for materials to be placed + var/list/y_offsets = list() -/obj/structure/ore_container/gutlunch_trough/Entered(atom/movable/mover) +/obj/structure/ore_container/food_trough/Entered(atom/movable/mover) if(!istype(mover, /obj/item/stack/ore)) return ..() if(list_of_materials[mover.type]) return ..() - list_of_materials[mover.type] = list("pixel_x" = rand(-5, 8), "pixel_y" = rand(-2, -7)) + list_of_materials[mover.type] = list("pixel_x" = rand(x_offsets[1], x_offsets[2]), "pixel_y" = rand(y_offsets[1], y_offsets[2])) return ..() -/obj/structure/ore_container/gutlunch_trough/Exited(atom/movable/mover) +/obj/structure/ore_container/food_trough/Exited(atom/movable/mover) if(!istype(mover, /obj/item/stack/ore) || !isnull(locate(mover.type) in contents)) return ..() list_of_materials -= mover.type return ..() -/obj/structure/ore_container/gutlunch_trough/deconstruct(disassembled = TRUE) - if(obj_flags & NO_DECONSTRUCTION) - return +/obj/structure/ore_container/food_trough/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(drop_location(), 5) - qdel(src) -/obj/structure/ore_container/gutlunch_trough/update_overlays() +/obj/structure/ore_container/food_trough/update_overlays() . = ..() for(var/ore_entry in list_of_materials) var/obj/item/ore_item = ore_entry @@ -38,3 +35,11 @@ ore_icon.pixel_x = pixel_positions["pixel_x"] ore_icon.pixel_y = pixel_positions["pixel_y"] . += ore_icon + +/obj/structure/ore_container/food_trough/gutlunch_trough + name = "gutlunch trough" + desc = "The gutlunches will eat out of it!" + icon = 'icons/obj/structures.dmi' + icon_state = "gutlunch_trough" + x_offsets = list(-5, 8) + y_offsets = list(-2, -7) diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm index 6d8f91ff8ce5c..f9e1d458ef2ed 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm @@ -55,7 +55,7 @@ /mob/living/basic/mining/gutlunch/proc/pre_attack(mob/living/puncher, atom/target) SIGNAL_HANDLER - if(!istype(target, /obj/structure/ore_container/gutlunch_trough)) + if(!istype(target, /obj/structure/ore_container/food_trough/gutlunch_trough)) return var/obj/ore_food = locate(/obj/item/stack/ore) in target diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm index be45879c64bf1..c7f7e86c86680 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm @@ -44,12 +44,9 @@ continue living_pawn.befriend(potential_friend) to_chat(potential_friend, span_nicegreen("[living_pawn] looks at you with endearing eyes!")) - finish_action(controller, TRUE) - return - - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_controller/basic_controller/gutlunch/gutlunch_baby @@ -78,7 +75,7 @@ target_key = BB_TROUGH_TARGET hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/food_trough finding_behavior = /datum/ai_behavior/find_hunt_target/food_trough - hunt_targets = list(/obj/structure/ore_container/gutlunch_trough) + hunt_targets = list(/obj/structure/ore_container/food_trough/gutlunch_trough) hunt_chance = 75 hunt_range = 9 diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm index b80d5d6b9f79a..c8e294f3e0644 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm @@ -47,8 +47,8 @@ if (!is_vulnerable) controller.set_blackboard_key(BB_BASIC_MOB_STOP_FLEEING, FALSE) if (!controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) - finish_action(controller = controller, succeeded = TRUE, target_key = target_key) // We don't want to clear our target - return + // We don't want to clear our target + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED return ..() /datum/ai_planning_subtree/flee_target/lobster @@ -72,8 +72,7 @@ if (!HAS_TRAIT(target, trait)) continue controller.set_blackboard_key(BB_BASIC_MOB_STOP_FLEEING, TRUE) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED var/mob/living/us = controller.pawn if (us.pulling == target) @@ -132,14 +131,12 @@ set_movement_target(controller, current_target) /datum/ai_behavior/grab_fingers/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - var/atom/current_target = controller.blackboard[target_key] if (QDELETED(current_target)) - return + return AI_BEHAVIOR_DELAY var/mob/living/living_pawn = controller.pawn living_pawn.start_pulling(current_target) - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /// How far we'll try to go before eating an arm #define FLEE_TO_RANGE 9 @@ -159,14 +156,18 @@ if (QDELETED(current_target)) set_movement_target(controller, get_turf(controller.pawn)) return - target_step_away(controller, current_target, target_key) + var/perform_flags = target_step_away(controller, current_target, target_key) + if (perform_flags & AI_BEHAVIOR_SUCCEEDED) + finish_action(controller, TRUE, target_key) + else if(perform_flags & AI_BEHAVIOR_FAILED) + finish_action(controller, FALSE, target_key) /// Find the next step to take away from the current target /datum/ai_behavior/hoard_fingers/proc/target_step_away(datum/ai_controller/controller, atom/current_target, target_key) var/turf/next_step = get_step_away(controller.pawn, current_target) if (!isnull(next_step) && !next_step.is_blocked_turf(exclude_mobs = TRUE)) set_movement_target(controller, next_step) - return + return NONE var/list/all_dirs = GLOB.alldirs.Copy() all_dirs -= get_dir(controller.pawn, next_step) all_dirs -= get_dir(controller.pawn, current_target) @@ -175,37 +176,37 @@ next_step = get_step(controller.pawn, dir) if (!isnull(next_step) && !next_step.is_blocked_turf(exclude_mobs = TRUE)) set_movement_target(controller, next_step) - return - finish_action(controller, succeeded = FALSE, target_key = target_key) - return + return NONE + return AI_BEHAVIOR_FAILED /datum/ai_behavior/hoard_fingers/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/current_patience = controller.blackboard[patience_key] + 1 if (current_patience >= MAX_LOBSTROSITY_PATIENCE) - eat_fingers(controller, target_key) - return + if(eat_fingers(controller, target_key)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(patience_key, current_patience) var/mob/living/living_pawn = controller.pawn if (isnull(living_pawn.pulling)) - finish_action(controller, succeeded = FALSE, target_key = target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/atom/current_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] if (QDELETED(current_target) || !can_see(controller.pawn, current_target, FLEE_TO_RANGE)) - eat_fingers(controller, target_key) - return - target_step_away(controller, current_target, target_key) + if(eat_fingers(controller, target_key)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + if(target_step_away(controller, current_target, target_key)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /// Finally consume those delicious digits /datum/ai_behavior/hoard_fingers/proc/eat_fingers(datum/ai_controller/controller, target_key) var/mob/living/basic/living_pawn = controller.pawn var/atom/fingers = controller.blackboard[target_key] if (QDELETED(fingers) || living_pawn.pulling != fingers) - finish_action(controller, succeeded = FALSE, target_key = target_key) - return + return AI_BEHAVIOR_FAILED living_pawn.melee_attack(fingers) - finish_action(controller, succeeded = TRUE, target_key = target_key) + return AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/hoard_fingers/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm index cf79eb06aa605..eeefc7a8b5c72 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm @@ -26,6 +26,7 @@ GLOBAL_LIST_INIT(mook_commands, list( /datum/ai_planning_subtree/mine_walls/mook, /datum/ai_planning_subtree/wander_away_from_village, ) + can_idle = FALSE // these guys are intended to operate even if nobody's around ///check for faction if not a ash walker, otherwise just attack /datum/targeting_strategy/basic/mook/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) @@ -116,15 +117,13 @@ GLOBAL_LIST_INIT(mook_commands, list( /datum/ai_behavior/find_village /datum/ai_behavior/find_village/perform(seconds_per_tick, datum/ai_controller/controller, village_key) - . = ..() var/obj/effect/landmark/home_marker = locate(/obj/effect/landmark/mook_village) in GLOB.landmarks_list if(isnull(home_marker)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(village_key, home_marker) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED ///explore the lands away from the village to look for ore /datum/ai_planning_subtree/wander_away_from_village @@ -189,8 +188,7 @@ GLOBAL_LIST_INIT(mook_commands, list( return return_turf /datum/ai_behavior/wander/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key) - . = ..() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_planning_subtree/mine_walls/mook find_wall_behavior = /datum/ai_behavior/find_mineral_wall/mook @@ -366,23 +364,20 @@ GLOBAL_LIST_INIT(mook_commands, list( action_cooldown = 5 SECONDS /datum/ai_behavior/issue_commands/perform(seconds_per_tick, datum/ai_controller/controller, target_key, command_path) - . = ..() var/mob/living/basic/living_pawn = controller.pawn var/atom/target = controller.blackboard[target_key] if(isnull(target)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/datum/pet_command/to_command = locate(command_path) in GLOB.mook_commands if(isnull(to_command)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/issue_command = pick(to_command.speech_commands) living_pawn.say(issue_command, forced = "controller") living_pawn._pointed(target) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED ///find an ore, only pick it up when a mook brings it close to us diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm new file mode 100644 index 0000000000000..78c4e9c61ea9c --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -0,0 +1,306 @@ +GLOBAL_LIST_INIT(raptor_growth_paths, list( + /mob/living/basic/mining/raptor/baby_raptor/red = list(RAPTOR_PURPLE, RAPTOR_WHITE), + /mob/living/basic/mining/raptor/baby_raptor/white = list(RAPTOR_GREEN, RAPTOR_PURPLE), + /mob/living/basic/mining/raptor/baby_raptor/purple = list(RAPTOR_GREEN, RAPTOR_WHITE), + /mob/living/basic/mining/raptor/baby_raptor/yellow = list(RAPTOR_GREEN, RAPTOR_RED), + /mob/living/basic/mining/raptor/baby_raptor/green = list(RAPTOR_RED, RAPTOR_YELLOW), + /mob/living/basic/mining/raptor/baby_raptor/blue = list(RAPTOR_RED, RAPTOR_PURPLE) +)) + +GLOBAL_LIST_INIT(raptor_inherit_traits, list( + BB_BASIC_DEPRESSED = "Depressed", + BB_RAPTOR_MOTHERLY = "Motherly", + BB_RAPTOR_PLAYFUL = "Playful", + BB_RAPTOR_COWARD = "Coward", + BB_RAPTOR_TROUBLE_MAKER = "Trouble Maker", +)) + +GLOBAL_LIST_EMPTY(raptor_population) + +#define HAPPINESS_BOOST_DAMPENER 0.3 + +/mob/living/basic/mining/raptor + name = "raptor" + desc = "A trusty powerful stead. Taming it might prove difficult..." + icon = 'icons/mob/simple/lavaland/raptor_big.dmi' + speed = 2 + mob_biotypes = MOB_ORGANIC|MOB_BEAST + maxHealth = 400 + health = 400 + melee_damage_lower = 10 + melee_damage_upper = 15 + sentience_type = SENTIENCE_BOSS + attack_verb_continuous = "pecks" + attack_verb_simple = "chomps" + attack_sound = 'sound/weapons/punch1.ogg' + faction = list(FACTION_RAPTOR, FACTION_NEUTRAL) + speak_emote = list("screeches") + ai_controller = /datum/ai_controller/basic_controller/raptor + ///can this mob breed + var/can_breed = TRUE + ///should we change offsets on direction change? + var/change_offsets = TRUE + ///can we ride this mob + var/ridable_component = /datum/component/riding/creature/raptor + //pet commands when we tame the raptor + var/static/list/pet_commands = list( + /datum/pet_command/idle, + /datum/pet_command/free, + /datum/pet_command/point_targeting/attack, + /datum/pet_command/follow, + /datum/pet_command/point_targeting/fetch, + ) + ///things we inherited from our parent + var/datum/raptor_inheritance/inherited_stats + ///our color + var/raptor_color + ///the description that appears in the dex + var/dex_description + ///path of our child + var/child_path + + +/mob/living/basic/mining/raptor/Initialize(mapload) + . = ..() + if(SSmapping.is_planetary()) + change_offsets = FALSE + icon = 'icons/mob/simple/lavaland/raptor_icebox.dmi' + + if(!mapload) + GLOB.raptor_population += REF(src) + AddComponent(/datum/component/obeys_commands, pet_commands) + + AddElement(\ + /datum/element/change_force_on_death,\ + move_resist = MOVE_RESIST_DEFAULT,\ + ) + + var/static/list/display_emote = list( + BB_EMOTE_SAY = list("Chirp chirp chirp!", "Kweh!", "Bwark!"), + BB_EMOTE_SEE = list("shakes its feathers!", "stretches!", "flaps it's wings!", "pecks at the ground!"), + BB_EMOTE_SOUND = list( + 'sound/creatures/raptor_1.ogg', + 'sound/creatures/raptor_2.ogg', + 'sound/creatures/raptor_3.ogg', + 'sound/creatures/raptor_4.ogg', + 'sound/creatures/raptor_5.ogg', + ), + BB_SPEAK_CHANCE = 2, + ) + + ai_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, display_emote) + inherited_stats = new + inherit_properties() + RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) + var/static/list/my_food = list(/obj/item/stack/ore) + AddElement(/datum/element/basic_eating, food_types = my_food) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/ai_flee_while_injured, stop_fleeing_at = 0.5, start_fleeing_below = 0.2) + + if(ridable_component) + AddElement(/datum/element/ridable, ridable_component) + + if(can_breed) + AddComponent(\ + /datum/component/breed,\ + can_breed_with = typecacheof(list(/mob/living/basic/mining/raptor)),\ + baby_path = /obj/item/food/egg/raptor_egg,\ + post_birth = CALLBACK(src, PROC_REF(egg_inherit)),\ + breed_timer = 3 MINUTES,\ + ) + AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW) + RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_dir_change)) + adjust_offsets(dir) + add_happiness_component() + + +/mob/living/basic/mining/raptor/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, buckle_mob_flags= NONE) + if(!iscarbon(target)) + return + return ..() + +/mob/living/basic/mining/raptor/proc/add_happiness_component() + var/static/list/percentage_callbacks = list(0, 15, 25, 35, 50, 75, 90, 100) + AddComponent(\ + /datum/component/happiness,\ + on_petted_change = 100,\ + on_groom_change = 100,\ + on_eat_change = 400,\ + callback_percentages = percentage_callbacks,\ + happiness_callback = CALLBACK(src, PROC_REF(happiness_change)),\ + ) + +/mob/living/basic/mining/raptor/proc/on_dir_change(datum/source, old_dir, new_dir) + SIGNAL_HANDLER + adjust_offsets(new_dir) + +/mob/living/basic/mining/raptor/proc/adjust_offsets(direction) + if(!change_offsets) + return + pixel_x = (direction & EAST) ? -20 : 0 + pixel_y = (direction & NORTH) ? -5 : 0 + + +/mob/living/basic/mining/raptor/proc/pre_attack(mob/living/puncher, atom/target) + SIGNAL_HANDLER + + if(!istype(target, /obj/structure/ore_container/food_trough/raptor_trough)) + return + + var/obj/ore_food = locate(/obj/item/stack/ore) in target + + if(isnull(ore_food)) + balloon_alert(src, "no food!") + else + INVOKE_ASYNC(src, PROC_REF(melee_attack), ore_food) + return COMPONENT_HOSTILE_NO_ATTACK + +/mob/living/basic/mining/raptor/melee_attack(mob/living/target, list/modifiers, ignore_cooldown) + if(!combat_mode && istype(target, /mob/living/basic/mining/raptor/baby_raptor)) + target.attack_hand(src, list(LEFT_CLICK = TRUE)) + return + return ..() + +/mob/living/basic/mining/raptor/death(gibbed) + . = ..() + GLOB.raptor_population -= REF(src) + +/mob/living/basic/mining/raptor/proc/happiness_change(percent_value) + var/attack_boost = round(initial(melee_damage_lower) * percent_value * HAPPINESS_BOOST_DAMPENER, 1) + melee_damage_lower = initial(melee_damage_lower) + attack_boost + melee_damage_upper = melee_damage_lower + 5 + + +///pass down our inheritance to the egg +/mob/living/basic/mining/raptor/proc/egg_inherit(obj/item/food/egg/raptor_egg/baby_egg, mob/living/basic/mining/raptor/partner) + var/datum/raptor_inheritance/inherit = new + inherit.set_parents(inherited_stats, partner.inherited_stats) + baby_egg.inherited_stats = inherit + baby_egg.determine_growth_path(src, partner) + +/mob/living/basic/mining/raptor/proc/inherit_properties() + if(isnull(inherited_stats)) + return + for(var/trait in GLOB.raptor_inherit_traits) // done this way to allow overriding of traits when assigned new inherit datum + var/should_inherit = (trait in inherited_stats.inherit_traits) + ai_controller?.set_blackboard_key(trait, should_inherit) + melee_damage_lower += inherited_stats.attack_modifier + melee_damage_upper += melee_damage_lower + 5 + maxHealth += inherited_stats.health_modifier + heal_overall_damage(maxHealth) + +/mob/living/basic/mining/raptor/Destroy() + QDEL_NULL(inherited_stats) + return ..() + +/mob/living/basic/mining/raptor/red + name = "red raptor" + icon_state = "raptor_red" + icon_living = "raptor_red" + icon_dead = "raptor_red_dead" + melee_damage_lower = 15 + melee_damage_upper = 20 + raptor_color = RAPTOR_RED + dex_description = "A resilient breed of raptors, battle-tested and bred for the purpose of humbling its foes in combat, \ + This breed demonstrates higher combat capabilities than its peers and oozes rutheless aggression." + child_path = /mob/living/basic/mining/raptor/baby_raptor/red + +/mob/living/basic/mining/raptor/purple + name = "purple raptor" + icon_state = "raptor_purple" + icon_living = "raptor_purple" + icon_dead = "raptor_purple_dead" + raptor_color = RAPTOR_PURPLE + dex_description = "A dependable mount, bred for the purpose of long distance pilgrimages. This breed is also able to store its rider's possessions." + child_path = /mob/living/basic/mining/raptor/baby_raptor/purple + +/mob/living/basic/mining/raptor/purple/Initialize(mapload) + . = ..() + create_storage( + max_specific_storage = WEIGHT_CLASS_NORMAL, + max_total_storage = 10, + storage_type = /datum/storage/raptor_storage, + ) + +/mob/living/basic/mining/raptor/green + name = "green raptor" + icon_state = "raptor_green" + icon_living = "raptor_green" + icon_dead = "raptor_green_dead" + maxHealth = 460 + health = 460 + raptor_color = RAPTOR_GREEN + dex_description = "A tough breed of raptor, made to withstand the harshest of punishment and to laugh in the face of pain, \ + This breed is able to withstand more beating than its peers." + child_path = /mob/living/basic/mining/raptor/baby_raptor/green + +/mob/living/basic/mining/raptor/green/Initialize(mapload) + . = ..() + AddElement(/datum/element/proficient_miner) + +/mob/living/basic/mining/raptor/white + name = "white raptor" + icon_state = "raptor_white" + icon_living = "raptor_white" + icon_dead = "raptor_white_dead" + raptor_color = RAPTOR_WHITE + dex_description = "A loving sort, it cares for it peers and rushes to their aid with reckless abandon. It is able to heal any raptors' ailments." + child_path = /mob/living/basic/mining/raptor/baby_raptor/white + +/mob/living/basic/mining/raptor/white/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/healing_touch,\ + heal_brute = melee_damage_upper,\ + heal_burn = melee_damage_upper,\ + heal_time = 0,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/mining/raptor)),\ + ) + +/mob/living/basic/mining/raptor/black + name = "black raptor" + icon_state = "raptor_black" + icon_living = "raptor_black" + icon_dead = "raptor_black_dead" + maxHealth = 460 + health = 460 + speed = 1 + ridable_component = /datum/component/riding/creature/raptor/fast + melee_damage_lower = 20 + melee_damage_upper = 25 + raptor_color = RAPTOR_BLACK + dex_description = "An ultra rare breed. Due to its sparse nature, not much is known about this sort. However it is said to possess many of its peers' abilities." + child_path = /mob/living/basic/mining/raptor/baby_raptor/black + +/mob/living/basic/mining/raptor/yellow + name = "yellow raptor" + icon_state = "raptor_yellow" + icon_living = "raptor_yellow" + icon_dead = "raptor_yellow_dead" + ridable_component = /datum/component/riding/creature/raptor/fast + speed = 1 + raptor_color = RAPTOR_YELLOW + dex_description = "This breed possesses greasy fast speed, DEMON speed, making light work of long pilgrimages. It's said that a thunderclap could be heard when this breed reaches its maximum speed." + child_path = /mob/living/basic/mining/raptor/baby_raptor/yellow + +/mob/living/basic/mining/raptor/blue + name = "blue raptor" + icon_state = "raptor_blue" + icon_living = "raptor_blue" + icon_dead = "raptor_blue_dead" + raptor_color = RAPTOR_BLUE + dex_description = "Known to produce nutritous and equally delicious milk, which is also said to possess healing properties." + child_path = /mob/living/basic/mining/raptor/baby_raptor/blue + +/mob/living/basic/mining/raptor/blue/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/udder,\ + udder_type = /obj/item/udder/raptor,\ + ) + +/datum/storage/raptor_storage + animated = FALSE + insert_on_attack = FALSE + +#undef HAPPINESS_BOOST_DAMPENER diff --git a/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm new file mode 100644 index 0000000000000..a0a4f6aebc12a --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm @@ -0,0 +1,102 @@ +/mob/living/basic/mining/raptor/baby_raptor + name = "baby raptor" + desc = "Will this grow into something useful?" + icon = 'icons/mob/simple/lavaland/raptor_baby.dmi' + speed = 5 + maxHealth = 25 + health = 25 + melee_damage_lower = 3 + melee_damage_upper = 5 + density = FALSE + can_breed = FALSE + move_resist = MOVE_RESIST_DEFAULT + ai_controller = /datum/ai_controller/basic_controller/baby_raptor + ridable_component = null + change_offsets = FALSE + dex_description = "A cute baby raptor, Having it near a parent or a birds-nest could encourage it to grow faster, \ + grooming it and feeding it could also ensure that it grows up quicker!" + ///what do we grow into + var/growth_path + ///probability we are to be rolled + var/roll_rate = 100 + +/mob/living/basic/mining/raptor/baby_raptor/Initialize(mapload) + . = ..() + if(isnull(growth_path)) + return + AddComponent(\ + /datum/component/growth_and_differentiation,\ + growth_time = null,\ + growth_path = growth_path,\ + growth_probability = 80,\ + lower_growth_value = 0.5,\ + upper_growth_value = 0.8,\ + signals_to_kill_on = list(COMSIG_MOB_CLIENT_LOGIN),\ + optional_checks = CALLBACK(src, PROC_REF(check_grow)),\ + optional_grow_behavior = CALLBACK(src, PROC_REF(ready_to_grow)),\ + ) + +/mob/living/basic/mining/raptor/baby_raptor/add_happiness_component() + AddComponent(/datum/component/happiness, on_petted_change = 100) + +/mob/living/basic/mining/raptor/baby_raptor/proc/check_grow() + return (stat != DEAD) + +/mob/living/basic/mining/raptor/baby_raptor/proc/ready_to_grow() + var/mob/living/basic/mining/raptor/grown_mob = new growth_path(get_turf(src)) + QDEL_NULL(grown_mob.inherited_stats) + grown_mob.inherited_stats = inherited_stats + inherited_stats = null + grown_mob.inherit_properties() + ADD_TRAIT(grown_mob, TRAIT_MOB_HATCHED, INNATE_TRAIT) //pass on the hatched trait + qdel(src) + +/mob/living/basic/mining/raptor/baby_raptor/black + name = "baby black raptor" + icon_state = "baby_black" + icon_living = "baby_black" + icon_dead = "baby_black_dead" + growth_path = /mob/living/basic/mining/raptor/black + roll_rate = 10 + +/mob/living/basic/mining/raptor/baby_raptor/red + name = "baby red raptor" + icon_state = "baby_red" + icon_living = "baby_red" + icon_dead = "baby_red_dead" + growth_path = /mob/living/basic/mining/raptor/red + +/mob/living/basic/mining/raptor/baby_raptor/purple + name = "baby purple raptor" + icon_state = "baby_purple" + icon_living = "baby_purple" + icon_dead = "baby_purple_dead" + growth_path = /mob/living/basic/mining/raptor/purple + +/mob/living/basic/mining/raptor/baby_raptor/white + name = "baby white raptor" + icon_state = "baby_white" + icon_living = "baby_white" + icon_dead = "baby_white_dead" + growth_path = /mob/living/basic/mining/raptor/white + +/mob/living/basic/mining/raptor/baby_raptor/yellow + name = "baby yellow raptor" + icon_state = "baby_yellow" + icon_living = "baby_yellow" + icon_dead = "baby_yellow_dead" + growth_path = /mob/living/basic/mining/raptor/yellow + +/mob/living/basic/mining/raptor/baby_raptor/green + name = "baby green raptor" + icon_state = "baby_green" + icon_living = "baby_green" + icon_dead = "baby_green_dead" + growth_path = /mob/living/basic/mining/raptor/green + +/mob/living/basic/mining/raptor/baby_raptor/blue + name = "baby blue raptor" + icon_state = "baby_blue" + icon_living = "baby_blue" + icon_dead = "baby_blue_dead" + growth_path = /mob/living/basic/mining/raptor/blue diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_behavior.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_behavior.dm new file mode 100644 index 0000000000000..33a655869072a --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_behavior.dm @@ -0,0 +1,54 @@ +/datum/ai_behavior/hunt_target/unarmed_attack_target/heal_raptor + always_reset_target = TRUE + +/datum/ai_behavior/find_hunt_target/injured_raptor + +/datum/ai_behavior/find_hunt_target/injured_raptor/valid_dinner(mob/living/source, mob/living/target, radius) + return (source != target && target.health < target.maxHealth) + +/datum/ai_behavior/find_hunt_target/raptor_victim + +/datum/ai_behavior/find_hunt_target/raptor_victim/valid_dinner(mob/living/source, mob/living/target, radius) + if(target.ai_controller?.blackboard[BB_RAPTOR_TROUBLE_MAKER]) + return FALSE + return target.stat != DEAD && can_see(source, target, radius) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/bully_raptors + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/unarmed_attack_target/bully_raptors/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key) + if(succeeded) + controller.set_blackboard_key(BB_RAPTOR_TROUBLE_COOLDOWN, world.time + 2 MINUTES) + return ..() + +/datum/ai_behavior/find_hunt_target/raptor_baby/valid_dinner(mob/living/source, mob/living/target, radius) + return can_see(source, target, radius) && target.stat != DEAD + +/datum/ai_behavior/hunt_target/care_for_young + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/care_for_young/target_caught(mob/living/hunter, atom/hunted) + hunter.manual_emote("grooms [hunted]!") + hunter.set_combat_mode(FALSE) + hunter.ClickOn(hunted) + +/datum/ai_behavior/hunt_target/care_for_young/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key) + var/mob/living/living_pawn = controller.pawn + living_pawn.set_combat_mode(initial(living_pawn.combat_mode)) + return ..() + +/datum/ai_behavior/find_hunt_target/raptor_trough + +/datum/ai_behavior/find_hunt_target/raptor_trough/valid_dinner(mob/living/source, atom/movable/trough, radius) + return !!(locate(/obj/item/stack/ore) in trough.contents) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/raptor_trough + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/unarmed_attack_target/raptor_trough/target_caught(mob/living/hunter, atom/hunted) + hunter.set_combat_mode(FALSE) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/raptor_trough/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key) + var/mob/living/living_pawn = controller.pawn + living_pawn.set_combat_mode(initial(living_pawn.combat_mode)) + return ..() diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm new file mode 100644 index 0000000000000..40c2d836554b1 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm @@ -0,0 +1,64 @@ +#define NEXT_EAT_COOLDOWN 45 SECONDS + +/datum/ai_controller/basic_controller/raptor + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/raptor, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/raptor, + BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/mining/raptor), + BB_BABIES_CHILD_TYPES = list(/mob/living/basic/mining/raptor/baby_raptor), + BB_MAX_CHILDREN = 5, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor, + /datum/ai_planning_subtree/flee_target/from_flee_key, + /datum/ai_planning_subtree/find_and_hunt_target/heal_raptors, + /datum/ai_planning_subtree/random_speech/blackboard, + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/find_and_hunt_target/raptor_trough, + /datum/ai_planning_subtree/find_and_hunt_target/care_for_young, + /datum/ai_planning_subtree/make_babies, + /datum/ai_planning_subtree/find_and_hunt_target/raptor_start_trouble, + /datum/ai_planning_subtree/express_happiness, + ) + +/datum/ai_controller/basic_controller/raptor/TryPossessPawn(atom/new_pawn) + . = ..() + if(. & AI_CONTROLLER_INCOMPATIBLE) + return + RegisterSignal(new_pawn, COMSIG_MOB_ATE, PROC_REF(post_eat)) + +/datum/ai_controller/basic_controller/raptor/proc/post_eat() + clear_blackboard_key(BB_RAPTOR_TROUGH_TARGET) + set_blackboard_key(BB_RAPTOR_EAT_COOLDOWN, world.time + NEXT_EAT_COOLDOWN) + +/datum/targeting_strategy/basic/raptor + +//dont attack anyone with the neutral faction. +/datum/targeting_strategy/basic/raptor/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) + return (the_target.faction.Find(FACTION_NEUTRAL) || the_target.faction.Find(FACTION_RAPTOR)) + +/datum/ai_controller/basic_controller/baby_raptor + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/raptor, + BB_FIND_MOM_TYPES = list(/mob/living/basic/mining/raptor), + BB_IGNORE_MOM_TYPES = list(/mob/living/basic/mining/raptor/baby_raptor), + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/random_speech/blackboard, + /datum/ai_planning_subtree/find_and_hunt_target/raptor_trough, + /datum/ai_planning_subtree/express_happiness, + /datum/ai_planning_subtree/look_for_adult, + ) + +#undef NEXT_EAT_COOLDOWN diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm new file mode 100644 index 0000000000000..2d23268d35c81 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm @@ -0,0 +1,62 @@ +/datum/ai_planning_subtree/find_and_hunt_target/heal_raptors + target_key = BB_INJURED_RAPTOR + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/heal_raptor + finding_behavior = /datum/ai_behavior/find_hunt_target/injured_raptor + hunt_targets = list(/mob/living/basic/mining/raptor) + hunt_chance = 70 + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/heal_raptors/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard[BB_BASIC_MOB_HEALER]) + return + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/raptor_start_trouble + target_key = BB_RAPTOR_VICTIM + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/bully_raptors + finding_behavior = /datum/ai_behavior/find_hunt_target/raptor_victim + hunt_targets = list(/mob/living/basic/mining/raptor) + hunt_chance = 30 + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/raptor_start_trouble/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(controller.blackboard[BB_BASIC_MOB_HEALER] || !controller.blackboard[BB_RAPTOR_TROUBLE_MAKER]) + return + if(world.time < controller.blackboard[BB_RAPTOR_TROUBLE_COOLDOWN]) + return + return ..() + +/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor + target_key = BB_BASIC_MOB_FLEE_TARGET + +/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard[BB_RAPTOR_COWARD]) + return + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/care_for_young + target_key = BB_RAPTOR_BABY + hunting_behavior = /datum/ai_behavior/hunt_target/care_for_young + finding_behavior = /datum/ai_behavior/find_hunt_target/raptor_baby + hunt_targets = list(/mob/living/basic/mining/raptor/baby_raptor) + hunt_chance = 75 + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/care_for_young/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard[BB_RAPTOR_MOTHERLY]) + return + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/raptor_trough + target_key = BB_RAPTOR_TROUGH_TARGET + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target + finding_behavior = /datum/ai_behavior/find_hunt_target/raptor_trough + hunt_targets = list(/obj/structure/ore_container/food_trough/raptor_trough) + hunt_chance = 80 + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/raptor_trough/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(world.time < controller.blackboard[BB_RAPTOR_EAT_COOLDOWN]) + return + return ..() + diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm new file mode 100644 index 0000000000000..7080c91a500c7 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm @@ -0,0 +1,62 @@ +/obj/item/raptor_dex + name = "raptor Dex" + desc = "A device used to analyze lavaland raptors!" + icon = 'icons/obj/devices/scanner.dmi' + icon_state = "raptor_dex" + item_flags = NOBLUDGEON + ///current raptor we are analyzing + var/datum/weakref/raptor + +/obj/item/raptor_dex/ui_interact(mob/user, datum/tgui/ui) + if(isnull(raptor?.resolve())) + balloon_alert(user, "no specimen data!") + return TRUE + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "RaptorDex") + ui.open() + +/obj/item/raptor_dex/ui_static_data(mob/user) + var/list/data = list() + var/mob/living/basic/mining/raptor/my_raptor = raptor.resolve() + + data["raptor_image"] = icon2base64(getFlatIcon(image(icon = my_raptor.icon, icon_state = my_raptor.icon_state))) + data["raptor_attack"] = my_raptor.melee_damage_lower + data["raptor_health"] = my_raptor.maxHealth + data["raptor_speed"] = my_raptor.speed + data["raptor_color"] = my_raptor.name + data["raptor_gender"] = my_raptor.gender + data["raptor_description"] = my_raptor.dex_description + + var/happiness_percentage = my_raptor.ai_controller?.blackboard[BB_BASIC_HAPPINESS] + var/obj/effect/overlay/happiness_overlay/display = new + display.set_hearts(happiness_percentage) + display.pixel_y = world.icon_size * 0.5 + data["raptor_happiness"] = icon2base64(getFlatIcon(display)) + qdel(display) + + var/datum/raptor_inheritance/inherit = my_raptor.inherited_stats + if(isnull(inherit)) + return data + + data["inherited_attack"] = inherit.attack_modifier + data["inherited_attack_max"] = RAPTOR_INHERIT_MAX_ATTACK + data["inherited_health"] = inherit.health_modifier + data["inherited_health_max"] = RAPTOR_INHERIT_MAX_HEALTH + + data["inherited_traits"] = list() + for(var/index in inherit.inherit_traits) + data["inherited_traits"] += GLOB.raptor_inherit_traits[index] + return data + + +/obj/item/raptor_dex/interact_with_atom(atom/attacked_atom, mob/living/user) + if(!istype(attacked_atom, /mob/living/basic/mining/raptor)) + return NONE + + raptor = WEAKREF(attacked_atom) + playsound(src, 'sound/items/orbie_send_out.ogg', 20) + balloon_alert(user, "scanned") + ui_interact(user) + return ITEM_INTERACT_SUCCESS diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_egg.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_egg.dm new file mode 100644 index 0000000000000..9fb72239ca7a3 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_egg.dm @@ -0,0 +1,58 @@ +/obj/item/food/egg/raptor_egg + icon = 'icons/mob/simple/lavaland/raptor_baby.dmi' + icon_state = "raptor_egg" + ///inheritance datum to pass on to the child + var/datum/raptor_inheritance/inherited_stats + +/obj/item/food/egg/raptor_egg/Initialize(mapload) + . = ..() + if(SSmapping.is_planetary()) + icon = 'icons/mob/simple/lavaland/raptor_icebox.dmi' + +/obj/item/food/egg/raptor_egg/proc/determine_growth_path(mob/living/basic/mining/raptor/dad, mob/living/basic/mining/raptor/mom) + if(dad.type == mom.type) + add_growth_component(dad.child_path) + return + var/dad_color = dad.raptor_color + var/mom_color = mom.raptor_color + var/list/my_colors = list(dad_color, mom_color) + sortTim(my_colors, GLOBAL_PROC_REF(cmp_text_asc)) + for(var/path in GLOB.raptor_growth_paths) //guaranteed spawns + var/list/required_colors = GLOB.raptor_growth_paths[path] + if(!compare_list(my_colors, required_colors)) + continue + add_growth_component(path) + return + var/list/valid_subtypes = list() + var/static/list/all_subtypes = subtypesof(/mob/living/basic/mining/raptor/baby_raptor) + for(var/path in all_subtypes) + var/mob/living/basic/mining/raptor/baby_raptor/raptor_path = path + if(!prob(initial(raptor_path.roll_rate))) + continue + valid_subtypes += raptor_path + add_growth_component(pick(valid_subtypes)) + +/obj/item/food/egg/raptor_egg/proc/add_growth_component(growth_path) + if(length(GLOB.raptor_population) >= MAX_RAPTOR_POP) + return + AddComponent(\ + /datum/component/fertile_egg,\ + embryo_type = growth_path,\ + minimum_growth_rate = 0.5,\ + maximum_growth_rate = 1,\ + total_growth_required = 100,\ + current_growth = 0,\ + location_allowlist = typecacheof(list(/turf)),\ + post_hatch = CALLBACK(src, PROC_REF(post_hatch)),\ + ) + +/obj/item/food/egg/raptor_egg/proc/post_hatch(mob/living/basic/mining/raptor/baby) + if(!istype(baby)) + return + QDEL_NULL(baby.inherited_stats) + baby.inherited_stats = inherited_stats + inherited_stats = null + +/obj/item/food/egg/raptor_egg/Destroy() + QDEL_NULL(inherited_stats) + return ..() diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_food_trough.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_food_trough.dm new file mode 100644 index 0000000000000..03289f2d0fe32 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_food_trough.dm @@ -0,0 +1,7 @@ +/obj/structure/ore_container/food_trough/raptor_trough + name = "raptor trough" + desc = "The raptors will eat out of it!" + icon = 'icons/obj/structures.dmi' + icon_state = "raptor_trough" + x_offsets = list(-5, 5) + y_offsets = list(-4, 5) diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm new file mode 100644 index 0000000000000..4f72e37a4cf4b --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm @@ -0,0 +1,31 @@ +#define RANDOM_INHERIT_AMOUNT 2 +/datum/raptor_inheritance + ///list of traits we inherit + var/list/inherit_traits = list() + ///attack modifier + var/attack_modifier + ///health_modifier + var/health_modifier + +/datum/raptor_inheritance/New(datum/raptor_inheritance/father, datum/raptor_inheritance/mother) + . = ..() + randomize_stats() + +/datum/raptor_inheritance/proc/randomize_stats() + attack_modifier = rand(0, RAPTOR_INHERIT_MAX_ATTACK) + health_modifier = rand(0, RAPTOR_INHERIT_MAX_HEALTH) + var/list/traits_to_pick = GLOB.raptor_inherit_traits.Copy() + for(var/i in 1 to RANDOM_INHERIT_AMOUNT) + inherit_traits += pick_n_take(traits_to_pick) + +/datum/raptor_inheritance/proc/set_parents(datum/raptor_inheritance/father, datum/raptor_inheritance/mother) + if(isnull(father) || isnull(mother)) + return + if(length(father.inherit_traits)) + inherit_traits += pick(father.inherit_traits) + if(length(mother.inherit_traits)) + inherit_traits += pick(mother.inherit_traits) + attack_modifier = rand(min(father.attack_modifier, mother.attack_modifier), max(father.attack_modifier, mother.attack_modifier)) + health_modifier = rand(min(father.health_modifier, mother.health_modifier), max(father.health_modifier, mother.health_modifier)) + +#undef RANDOM_INHERIT_AMOUNT diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher_gaze.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher_gaze.dm index 06a221db2dc79..940803299524b 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher_gaze.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher_gaze.dm @@ -115,6 +115,8 @@ var/max_throw = 3 /datum/action/cooldown/mob_cooldown/watcher_gaze/ice/apply_effect(mob/living/viewer) + if(!HAS_TRAIT(viewer, TRAIT_RESISTCOLD)) + return to_chat(viewer, span_warning("You are repulsed by the force of [owner]'s cold stare!")) viewer.apply_status_effect(/datum/status_effect/freon/watcher/extended) viewer.safe_throw_at( diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher_projectiles.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher_projectiles.dm index 40afd58c1da26..19e718d9fee59 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher_projectiles.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher_projectiles.dm @@ -34,4 +34,6 @@ damage = 5 /obj/projectile/temp/watcher/ice_wing/apply_status(mob/living/target) + if(!HAS_TRAIT(target, TRAIT_RESISTCOLD)) + return target.apply_status_effect(/datum/status_effect/freon/watcher) diff --git a/code/modules/mob/living/basic/minebots/minebot.dm b/code/modules/mob/living/basic/minebots/minebot.dm index 26e549cbcf9e3..3361330915f0e 100644 --- a/code/modules/mob/living/basic/minebots/minebot.dm +++ b/code/modules/mob/living/basic/minebots/minebot.dm @@ -203,12 +203,12 @@ combat_overlay.color = selected_color update_appearance() -/mob/living/basic/mining_drone/AltClick(mob/living/user) - . = ..() +/mob/living/basic/mining_drone/click_alt(mob/living/user) if(user.combat_mode) - return + return CLICK_ACTION_BLOCKING set_combat_mode(!combat_mode) balloon_alert(user, "now [combat_mode ? "attacking wildlife" : "collecting loose ore"]") + return CLICK_ACTION_SUCCESS /mob/living/basic/mining_drone/RangedAttack(atom/target) if(!combat_mode) diff --git a/code/modules/mob/living/basic/minebots/minebot_abilities.dm b/code/modules/mob/living/basic/minebots/minebot_abilities.dm index 88cd156d1b121..8d1a93bd42916 100644 --- a/code/modules/mob/living/basic/minebots/minebot_abilities.dm +++ b/code/modules/mob/living/basic/minebots/minebot_abilities.dm @@ -63,7 +63,10 @@ var/wind_up_timer = 1 SECONDS /datum/action/cooldown/mob_cooldown/missile_launcher/IsAvailable(feedback = TRUE) - if(is_mining_level(owner.z)) + . = ..() + if(!.) + return FALSE + if(lavaland_equipment_pressure_check(get_turf(owner))) return TRUE if(feedback) owner.balloon_alert(owner, "cant be used here!") @@ -101,7 +104,10 @@ click_to_activate = FALSE /datum/action/cooldown/mob_cooldown/drop_landmine/IsAvailable(feedback = TRUE) - if(is_mining_level(owner.z)) + . = ..() + if(!.) + return FALSE + if(lavaland_equipment_pressure_check(get_turf(owner))) return TRUE if(feedback) owner.balloon_alert(owner, "cant be used here!") @@ -176,4 +182,9 @@ /obj/effect/mine/minebot/can_trigger(atom/movable/on_who) if(REF(on_who) in ignore_list) return FALSE + if(!isliving(on_who)) + return ..() + var/mob/living/stepped_mob = on_who + if(FACTION_NEUTRAL in stepped_mob.faction) + return FALSE return ..() diff --git a/code/modules/mob/living/basic/minebots/minebot_ai.dm b/code/modules/mob/living/basic/minebots/minebot_ai.dm index 2e585085a104b..959049f957d73 100644 --- a/code/modules/mob/living/basic/minebots/minebot_ai.dm +++ b/code/modules/mob/living/basic/minebots/minebot_ai.dm @@ -15,10 +15,10 @@ idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/launch_missiles, /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/befriend_miners, /datum/ai_planning_subtree/defend_node, - /datum/ai_planning_subtree/launch_missiles, /datum/ai_planning_subtree/minebot_maintain_distance, /datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot, /datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/minebot, @@ -86,15 +86,13 @@ set_movement_target(controller, target) /datum/ai_behavior/repair_drone/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_pawn = controller.pawn living_pawn.say("REPAIRING [target]!") living_pawn.UnarmedAttack(target) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/repair_drone/finish_action(datum/ai_controller/controller, success, target_key) . = ..() @@ -119,20 +117,17 @@ action_cooldown = 2 MINUTES /datum/ai_behavior/send_sos_message/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/carbon/target = controller.blackboard[target_key] var/mob/living/living_pawn = controller.pawn if(QDELETED(target) || is_station_level(target.z)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/turf/target_turf = get_turf(target) var/obj/item/implant/radio/radio_implant = locate(/obj/item/implant/radio) in living_pawn.contents if(!radio_implant) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/message = "ALERT, [target] in need of help at coordinates: [target_turf.x], [target_turf.y], [target_turf.z]!" radio_implant.radio.talk_into(living_pawn, message, RADIO_CHANNEL_SUPPLY) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/send_sos_message/finish_action(datum/ai_controller/controller, success, target_key) . = ..() @@ -182,11 +177,10 @@ minimum_distance = controller.blackboard[BB_MINIMUM_SHOOTING_DISTANCE] ? controller.blackboard[BB_MINIMUM_SHOOTING_DISTANCE] : initial(minimum_distance) var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, target_key, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_pawn = controller.pawn if(get_dist(living_pawn, target) <= minimum_distance) - finish_action(controller, target_key, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED ///mine walls if we are on automated mining mode /datum/ai_planning_subtree/minebot_mining/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) @@ -220,24 +214,20 @@ set_movement_target(controller, target) /datum/ai_behavior/minebot_mine_turf/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/basic/living_pawn = controller.pawn var/turf/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(check_obstacles_in_path(controller, target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED if(!living_pawn.combat_mode) living_pawn.set_combat_mode(TRUE) living_pawn.RangedAttack(target) - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/minebot_mine_turf/proc/check_obstacles_in_path(datum/ai_controller/controller, turf/target) var/mob/living/source = controller.pawn diff --git a/code/modules/mob/living/basic/minebots/minebot_upgrades.dm b/code/modules/mob/living/basic/minebots/minebot_upgrades.dm index d1800072b5dd8..14c62f7fefc51 100644 --- a/code/modules/mob/living/basic/minebots/minebot_upgrades.dm +++ b/code/modules/mob/living/basic/minebots/minebot_upgrades.dm @@ -78,7 +78,7 @@ /obj/effect/overlay/minebot_top_shield mouse_opacity = MOUSE_OPACITY_TRANSPARENT anchored = TRUE - vis_flags = VIS_INHERIT_DIR + vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE icon = 'icons/mob/silicon/aibots.dmi' icon_state = "minebot_shield_top_layer" layer = ABOVE_ALL_MOB_LAYER @@ -86,7 +86,7 @@ /obj/effect/overlay/minebot_bottom_shield mouse_opacity = MOUSE_OPACITY_TRANSPARENT anchored = TRUE - vis_flags = VIS_INHERIT_DIR + vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE icon = 'icons/mob/silicon/aibots.dmi' icon_state = "minebot_shield_bottom_layer" layer = BELOW_MOB_LAYER diff --git a/code/modules/mob/living/basic/pets/cat/cat_ai.dm b/code/modules/mob/living/basic/pets/cat/cat_ai.dm index 7eff8582355e3..d6589d29b407e 100644 --- a/code/modules/mob/living/basic/pets/cat/cat_ai.dm +++ b/code/modules/mob/living/basic/pets/cat/cat_ai.dm @@ -60,15 +60,13 @@ set_movement_target(controller, target) /datum/ai_behavior/enter_cat_home/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/obj/structure/cat_house/home = controller.blackboard[target_key] var/mob/living/basic/living_pawn = controller.pawn if(living_pawn == home.resident_cat || isnull(home.resident_cat)) living_pawn.melee_attack(home) - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED - finish_action(controller, FALSE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/enter_cat_home/finish_action(datum/ai_controller/controller, success, target_key) . = ..() @@ -133,8 +131,7 @@ var/mob/living/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED var/mob/living/living_pawn = controller.pawn var/list/threaten_list = controller.blackboard[cries_key] @@ -149,7 +146,7 @@ loser_controller.set_blackboard_key(BB_BASIC_MOB_FLEE_TARGET, target) target.ai_controller.clear_blackboard_key(BB_TRESSPASSER_TARGET) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/territorial_struggle/finish_action(datum/ai_controller/controller, success, target_key) . = ..() @@ -191,19 +188,16 @@ set_movement_target(controller, target) /datum/ai_behavior/play_with_mouse/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/basic/mouse/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED consume_chance = istype(target, /mob/living/basic/mouse/brown/tom) ? 5 : initial(consume_chance) if(prob(consume_chance)) target.splat() - finish_action(controller, TRUE, target_key) - return - finish_action(controller, FALSE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/play_with_mouse/finish_action(datum/ai_controller/controller, success, target_key) . = ..() @@ -272,22 +266,19 @@ set_movement_target(controller, target) /datum/ai_behavior/deliver_food_to_kitten/perform(seconds_per_tick, datum/ai_controller/controller, target_key, food_key) - . = ..() var/mob/living/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key, food_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_pawn = controller.pawn var/atom/movable/food = controller.blackboard[food_key] if(isnull(food) || !(food in living_pawn)) - finish_action(controller, FALSE, target_key, food_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED food.forceMove(get_turf(living_pawn)) - finish_action(controller, TRUE, target_key, food_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/deliver_food_to_kitten/finish_action(datum/ai_controller/controller, success, target_key, food_key) . = ..() diff --git a/code/modules/mob/living/basic/pets/cat/kitten_ai.dm b/code/modules/mob/living/basic/pets/cat/kitten_ai.dm index 15630c078385c..b694235a39ebc 100644 --- a/code/modules/mob/living/basic/pets/cat/kitten_ai.dm +++ b/code/modules/mob/living/basic/pets/cat/kitten_ai.dm @@ -30,16 +30,15 @@ action_cooldown = 5 SECONDS /datum/ai_behavior/beacon_for_food/perform(seconds_per_tick, datum/ai_controller/controller, target_key, meows_key) - . = ..() var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_pawn = controller.pawn var/list/meowing_list = controller.blackboard[meows_key] if(length(meowing_list)) living_pawn.say(pick(meowing_list), forced = "ai_controller") living_pawn._pointed(target) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/beacon_for_food/finish_action(datum/ai_controller/controller, success, target_key) . = ..() diff --git a/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm b/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm index 854a02094640b..92f433bd08a05 100644 --- a/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm +++ b/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm @@ -65,18 +65,16 @@ set_movement_target(controller, target) /datum/ai_behavior/interact_with_playmate/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/basic/living_pawn = controller.pawn var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED living_pawn.manual_emote("plays with [target]!") living_pawn.spin(spintime = 4, speed = 1) living_pawn.ClickOn(target) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/interact_with_playmate/finish_action(datum/ai_controller/controller, success, target_key) . = ..() @@ -92,16 +90,14 @@ controller.queue_behavior(/datum/ai_behavior/relay_pda_message, BB_LAST_RECIEVED_MESSAGE) /datum/ai_behavior/relay_pda_message/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/mob/living/basic/living_pawn = controller.pawn var/text_to_say = controller.blackboard[target_key] if(isnull(text_to_say)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED living_pawn.say(text_to_say, forced = "AI controller") living_pawn.spin(spintime = 4, speed = 1) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/relay_pda_message/finish_action(datum/ai_controller/controller, success, target_key) . = ..() diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm index ccc3ef92f6ea2..b5b34e30cad51 100644 --- a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm @@ -47,25 +47,21 @@ set_movement_target(controller, target) /datum/ai_behavior/perch_on_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/basic/parrot/living_pawn = controller.pawn if(!ishuman(target)) living_pawn.start_perching(target) - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED if(!check_human_conditions(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED living_pawn.start_perching(target) - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/perch_on_target/proc/check_human_conditions(mob/living/living_human) if(living_human.stat == DEAD || LAZYLEN(living_human.buckled_mobs) >= living_human.max_buckled_mobs) diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm index d1488a60b3bb9..ab8ad3957b1fb 100644 --- a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm @@ -1,3 +1,4 @@ +#define MAXIMUM_PARROT_PITCH 24 /// When a parrot... parrots... /datum/ai_planning_subtree/parrot_as_in_repeat operational_datums = list(/datum/component/listen_and_repeat) @@ -23,28 +24,43 @@ /datum/ai_behavior/perform_speech/parrot action_cooldown = 7.5 SECONDS // gets really annoying (moreso than usual) really fast otherwise -/datum/ai_behavior/perform_speech/parrot/perform(seconds_per_tick, datum/ai_controller/controller, speech, speech_sound) +/datum/ai_behavior/perform_speech/parrot/perform(seconds_per_tick, datum/ai_controller/controller, list/speech, speech_sound) var/mob/living/basic/parrot/speaking_pawn = controller.pawn var/list/available_channels = speaking_pawn.get_available_channels() - var/modified_speech = speech + var/modified_speech = speech["line"] var/use_radio = prob(50) // we might not even use the radio if we even have a channel -#define HAS_CHANNEL_PREFIX (speech[1] in GLOB.department_radio_prefixes) && (copytext_char(speech, 2, 3) in GLOB.department_radio_keys) // determine if we need to crop the channel prefix + var/has_channel_prefix = (modified_speech[1] in GLOB.department_radio_prefixes) && (copytext_char(modified_speech, 2, 3) in GLOB.department_radio_keys) // determine if we need to crop the channel prefix if(!length(available_channels)) // might not even use the radio at all - if(HAS_CHANNEL_PREFIX) - modified_speech = copytext_char(speech, 3) + if(has_channel_prefix) + modified_speech = copytext_char(modified_speech, 3) else - if(HAS_CHANNEL_PREFIX) - modified_speech = "[use_radio ? pick(available_channels) : ""][copytext_char(speech, 3)]" + if(has_channel_prefix) + modified_speech = "[use_radio ? pick(available_channels) : ""][copytext_char(modified_speech, 3)]" else - modified_speech = "[use_radio ? pick(available_channels) : ""][speech]" - + modified_speech = "[use_radio ? pick(available_channels) : ""][modified_speech]" + if(SStts.tts_enabled) + modify_voice(speaking_pawn, speech) speaking_pawn.say(modified_speech, forced = "AI Controller") if(speech_sound) playsound(speaking_pawn, speech_sound, 80, vary = TRUE) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + +/datum/ai_behavior/perform_speech/parrot/proc/modify_voice(mob/living/speaking_pawn, list/speech) + if(SStts.available_speakers.Find(speech["voice"])) + speaking_pawn.voice = speech["voice"] + if(speech["pitch"] && SStts.pitch_enabled) + speaking_pawn.pitch = min(speech["pitch"] + rand(6, 12), MAXIMUM_PARROT_PITCH) + +/datum/ai_behavior/perform_speech/parrot/finish_action(datum/ai_controller/controller, succeeded) + . = ..() + if(!succeeded) + return + var/mob/living/living_pawn = controller.pawn + living_pawn.voice = living_pawn::voice + living_pawn.pitch = living_pawn::pitch -#undef HAS_CHANNEL_PREFIX +#undef MAXIMUM_PARROT_PITCH diff --git a/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm index dc778b5816f74..fb10680991895 100644 --- a/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm +++ b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm @@ -100,25 +100,21 @@ set_movement_target(controller, target) /datum/ai_behavior/activate_rune/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/datum/team/cult/cult_team = controller.blackboard[BB_CULT_TEAM] var/mob/living/revive_mob = locate(/mob/living) in get_turf(target) if(isnull(revive_mob) || revive_mob.stat != DEAD || !(revive_mob.mind in cult_team.members)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/basic/living_pawn = controller.pawn living_pawn.melee_attack(target) - finish_action(controller, TRUE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/activate_rune/finish_action(datum/ai_controller/controller, success, target_key) . = ..() @@ -211,12 +207,10 @@ set_movement_target(controller, target) /datum/ai_behavior/drag_target_to_rune/perform(seconds_per_tick, datum/ai_controller/controller, target_key, cultist_key) - . = ..() var/mob/living/our_pawn = controller.pawn var/atom/cultist_target = controller.blackboard[cultist_key] if(isnull(cultist_target)) - finish_action(controller, FALSE, target_key, cultist_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/list/possible_dirs = GLOB.alldirs.Copy() possible_dirs -= get_dir(our_pawn, cultist_target) for(var/direction in possible_dirs) @@ -225,7 +219,7 @@ possible_dirs -= direction step(our_pawn, pick(possible_dirs)) our_pawn.stop_pulling() - finish_action(controller, TRUE, target_key, cultist_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/drag_target_to_rune/finish_action(datum/ai_controller/controller, success, target_key, cultist_key) diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm index e33cdcad1a1ea..6f46e69070038 100644 --- a/code/modules/mob/living/basic/ruin_defender/flesh.dm +++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm @@ -38,9 +38,16 @@ if(!isnull(limb)) register_to_limb(limb) +/mob/living/basic/living_limb_flesh/apply_target_randomisation() + AddElement(/datum/element/attack_zone_randomiser, GLOB.limb_zones) + /mob/living/basic/living_limb_flesh/Destroy(force) . = ..() - QDEL_NULL(current_bodypart) + if(current_bodypart) + var/obj/item/bodypart/bodypart = current_bodypart + unregister_from_limb(current_bodypart.owner) + if(!QDELETED(bodypart)) + qdel(bodypart) /mob/living/basic/living_limb_flesh/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() @@ -67,6 +74,8 @@ if(!victim.CanReach(movable)) continue candidates += movable + if(!length(candidates)) + return var/atom/movable/candidate = pick(candidates) if(isnull(candidate)) return @@ -119,16 +128,10 @@ part_type = /obj/item/bodypart/leg/right/flesh target.visible_message(span_danger("[src] [target_part ? "tears off and attaches itself" : "attaches itself"] to where [target][target.p_s()] limb used to be!")) - current_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here - current_bodypart.replace_limb(target, TRUE) - forceMove(current_bodypart) - register_to_limb(current_bodypart) - -/mob/living/basic/living_limb_flesh/proc/register_to_limb(obj/item/bodypart/part) - ai_controller.set_ai_status(AI_STATUS_OFF) - RegisterSignal(part, COMSIG_BODYPART_REMOVED, PROC_REF(on_limb_lost)) - RegisterSignal(part.owner, COMSIG_LIVING_DEATH, PROC_REF(owner_died)) - RegisterSignal(part.owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(owner_shocked)) //detach if we are shocked, not beneficial for the host but hey its a sideeffect + var/obj/item/bodypart/new_bodypart = new part_type() + forceMove(new_bodypart) + new_bodypart.replace_limb(target, TRUE) + register_to_limb(new_bodypart) /mob/living/basic/living_limb_flesh/proc/owner_shocked(datum/source, shock_damage, shock_source, siemens_coeff, flags) SIGNAL_HANDLER @@ -154,15 +157,27 @@ /mob/living/basic/living_limb_flesh/proc/on_limb_lost(atom/movable/source, mob/living/carbon/old_owner, special, dismembered) SIGNAL_HANDLER - UnregisterSignal(source, COMSIG_BODYPART_REMOVED) - UnregisterSignal(old_owner, COMSIG_LIVING_ELECTROCUTE_ACT) - UnregisterSignal(old_owner, COMSIG_LIVING_DEATH) + unregister_from_limb(old_owner) addtimer(CALLBACK(src, PROC_REF(wake_up), source), 2 SECONDS) +/mob/living/basic/living_limb_flesh/proc/register_to_limb(obj/item/bodypart/part) + current_bodypart = part + ai_controller.set_ai_status(AI_STATUS_OFF) + RegisterSignal(current_bodypart, COMSIG_BODYPART_REMOVED, PROC_REF(on_limb_lost)) + if(current_bodypart.owner) + RegisterSignal(current_bodypart.owner, COMSIG_LIVING_DEATH, PROC_REF(owner_died)) + RegisterSignal(current_bodypart.owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(owner_shocked)) //detach if we are shocked, not beneficial for the host but hey its a sideeffect + +/mob/living/basic/living_limb_flesh/proc/unregister_from_limb(mob/living/carbon/removing_owner) + UnregisterSignal(current_bodypart, COMSIG_BODYPART_REMOVED) + if(removing_owner) + UnregisterSignal(removing_owner, COMSIG_LIVING_ELECTROCUTE_ACT) + UnregisterSignal(removing_owner, COMSIG_LIVING_DEATH) + current_bodypart = null + /mob/living/basic/living_limb_flesh/proc/wake_up(atom/limb) + visible_message(span_warning("[src] begins flailing around!")) + Shake(6, 6, 0.5 SECONDS) ai_controller.set_ai_status(AI_STATUS_ON) forceMove(limb.drop_location()) - current_bodypart = null qdel(limb) - visible_message(span_warning("[src] begins flailing around!")) - Shake(6, 6, 0.5 SECONDS) diff --git a/code/modules/mob/living/basic/slime/ai/behaviours.dm b/code/modules/mob/living/basic/slime/ai/behaviours.dm index 0db592099bbf8..e573bd57354f7 100644 --- a/code/modules/mob/living/basic/slime/ai/behaviours.dm +++ b/code/modules/mob/living/basic/slime/ai/behaviours.dm @@ -1,10 +1,9 @@ /datum/ai_behavior/perform_change_slime_face /datum/ai_behavior/perform_change_slime_face/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/basic/slime/slime_pawn = controller.pawn if(!istype(slime_pawn)) - return + return AI_BEHAVIOR_DELAY var/current_mood = slime_pawn.current_mood @@ -23,7 +22,7 @@ slime_pawn.current_mood = new_mood slime_pawn.regenerate_icons() - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/find_hunt_target/find_slime_food diff --git a/code/modules/mob/living/basic/slime/ai/controller.dm b/code/modules/mob/living/basic/slime/ai/controller.dm index 9ecf66ad74472..41466b2973498 100644 --- a/code/modules/mob/living/basic/slime/ai/controller.dm +++ b/code/modules/mob/living/basic/slime/ai/controller.dm @@ -19,6 +19,7 @@ /datum/ai_planning_subtree/basic_melee_attack_subtree/slime, /datum/ai_planning_subtree/random_speech/slime, ) + can_idle = FALSE /datum/ai_controller/basic_controller/slime/CancelActions() ..() diff --git a/code/modules/mob/living/basic/slime/defense.dm b/code/modules/mob/living/basic/slime/defense.dm index 17bd22b905ae3..b747c24201971 100644 --- a/code/modules/mob/living/basic/slime/defense.dm +++ b/code/modules/mob/living/basic/slime/defense.dm @@ -31,7 +31,7 @@ return //Checks if the item passes through the slime first. Safe items can be used simply - if(check_item_passthrough(attacking_item)) + if(check_item_passthrough(attacking_item, user)) return try_discipline_slime(attacking_item) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index cf905de5dbf09..ee2073987dae2 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -134,6 +134,8 @@ /// Gives the carp a list of weakrefs of destinations to try and travel between when it has nothing better to do /mob/living/basic/carp/proc/migrate_to(list/datum/weakref/migration_points) + ai_controller.can_idle = FALSE + ai_controller.set_ai_status(AI_STATUS_ON) // We need htem to actually walk to the station var/list/actual_points = list() for(var/datum/weakref/point_ref as anything in migration_points) var/turf/point_resolved = point_ref.resolve() diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm index 9e767bab3af1f..71017bd2207a2 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm @@ -21,8 +21,7 @@ if (QDELETED(using_action)) return ..() if (!controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETING] && using_action.IsAvailable()) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED return ..() /** diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_migration.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_migration.dm index 27fdb25ee22b4..9458877af7fe0 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_migration.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_migration.dm @@ -47,10 +47,8 @@ blackboard_points -= migration_point if(get_dist(controller.pawn, migration_point) > CARP_DESTINATION_SEARCH_RANGE) controller.set_blackboard_key(target_key, migration_point) - finish_action(controller, succeeded = TRUE) - return - - finish_action(controller, succeeded = FALSE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED #undef CARP_DESTINATION_SEARCH_RANGE #undef CARP_PORTAL_SEARCH_RANGE diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm index fc6997896b0d2..84b96ae3ce405 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm @@ -52,21 +52,19 @@ return controller.blackboard[ability_key] && controller.blackboard[target_key] /datum/ai_behavior/make_carp_rift/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key) - . = ..() var/datum/action/cooldown/mob_cooldown/lesser_carp_rift/ability = controller.blackboard[ability_key] var/atom/target = controller.blackboard[target_key] if (!validate_target(controller, target, ability)) - finish_action(controller, FALSE, ability_key, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/turf/target_destination = find_target_turf(controller, target, ability) if (!target_destination) - finish_action(controller, FALSE, ability_key, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED - var/result = ability.InterceptClickOn(controller.pawn, null, target_destination) - finish_action(controller, result, ability_key, target_key) + if(ability.InterceptClickOn(controller.pawn, null, target_destination)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /// Return true if your target is valid for the action /datum/ai_behavior/make_carp_rift/proc/validate_target(datum/ai_controller/controller, atom/target, datum/action/cooldown/mob_cooldown/lesser_carp_rift/ability) diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon.dm b/code/modules/mob/living/basic/space_fauna/demon/demon.dm index f3f5392068983..21eaf66a3e869 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon.dm @@ -61,8 +61,9 @@ return list() /// Proc that just sets up the demon's antagonism status. -/mob/living/basic/demon/proc/generate_antagonist_status() - if(isnull(antag_type)) +/mob/living/basic/demon/mind_initialize() + . = ..() + if(isnull(antag_type) || mind.has_antag_datum(antag_type)) return // we weren't built for this proc to run mind.set_assigned_role(SSjob.GetJobType(/datum/job/slaughter_demon)) diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm index f05ea779763ca..a8073fa8329f7 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm @@ -66,7 +66,7 @@ /// Performs the classic slaughter demon bodyslam on the attack_target. Yeets them a screen away. /mob/living/basic/demon/slaughter/proc/bodyslam(atom/attack_target) - if(!isliving(attack_target)) + if(!isliving(attack_target) || attack_target == src) return if(!Adjacent(attack_target)) diff --git a/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_behavior.dm b/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_behavior.dm index 57ea39c94dd5c..f50fca8c559da 100644 --- a/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_behavior.dm +++ b/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_behavior.dm @@ -1,14 +1,11 @@ /datum/ai_behavior/find_the_blind /datum/ai_behavior/find_the_blind/perform(seconds_per_tick, datum/ai_controller/controller, blind_key, threshold_key) - . = ..() - var/mob/living_pawn = controller.pawn var/list/blind_list = list() var/eye_damage_threshold = controller.blackboard[threshold_key] if(!eye_damage_threshold) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED for(var/mob/living/carbon/blind in oview(9, living_pawn)) var/obj/item/organ/internal/eyes/eyes = blind.get_organ_slot(ORGAN_SLOT_EYES) if(isnull(eyes)) @@ -18,11 +15,10 @@ blind_list += blind if(!length(blind_list)) - finish_action(controller, FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(blind_key, pick(blind_list)) - finish_action(controller, TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/heal_eye_damage behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH @@ -35,19 +31,16 @@ set_movement_target(controller, target) /datum/ai_behavior/heal_eye_damage/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - var/mob/living/carbon/target = controller.blackboard[target_key] var/mob/living/living_pawn = controller.pawn if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/obj/item/organ/internal/eyes/eyes = target.get_organ_slot(ORGAN_SLOT_EYES) var/datum/callback/callback = CALLBACK(living_pawn, TYPE_PROC_REF(/mob/living/basic/eyeball, heal_eye_damage), target, eyes) callback.Invoke() - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/heal_eye_damage/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() @@ -77,17 +70,18 @@ var/mob/living/target = controller.blackboard[target_key] if(QDELETED(ability) || QDELETED(target)) - finish_action(controller, FALSE, ability_key, target_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED var/direction_to_compare = get_dir(target, controller.pawn) var/target_direction = target.dir if(direction_to_compare != target_direction) - finish_action(controller, FALSE, ability_key, target_key) - return + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED var/result = ability.InterceptClickOn(controller.pawn, null, target) - finish_action(controller, result, ability_key, target_key) + if(result == TRUE) + return AI_BEHAVIOR_INSTANT + else + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED /datum/ai_behavior/hunt_target/unarmed_attack_target/carrot hunt_cooldown = 2 SECONDS diff --git a/code/modules/mob/living/basic/space_fauna/ghost.dm b/code/modules/mob/living/basic/space_fauna/ghost.dm index 7545f9cfea394..728c5ead9f4a8 100644 --- a/code/modules/mob/living/basic/space_fauna/ghost.dm +++ b/code/modules/mob/living/basic/space_fauna/ghost.dm @@ -71,7 +71,7 @@ ghost_facial_hair_color = ghost_hair_color if(!isnull(ghost_hairstyle) && ghost_hairstyle != "Bald") //Bald hairstyle and the Shaved facial hairstyle lack an associated sprite and will not properly generate hair, and just cause runtimes. - var/datum/sprite_accessory/hair/hair_style = GLOB.hairstyles_list[ghost_hairstyle] //We use the hairstyle name to get the sprite accessory, which we copy the icon_state from. + var/datum/sprite_accessory/hair/hair_style = SSaccessories.hairstyles_list[ghost_hairstyle] //We use the hairstyle name to get the sprite accessory, which we copy the icon_state from. ghost_hair = mutable_appearance('icons/mob/human/human_face.dmi', "[hair_style.icon_state]", -HAIR_LAYER) ghost_hair.alpha = 200 ghost_hair.color = ghost_hair_color @@ -79,7 +79,7 @@ add_overlay(ghost_hair) if(!isnull(ghost_facial_hairstyle) && ghost_facial_hairstyle != "Shaved") - var/datum/sprite_accessory/facial_hair_style = GLOB.facial_hairstyles_list[ghost_facial_hairstyle] + var/datum/sprite_accessory/facial_hair_style = SSaccessories.facial_hairstyles_list[ghost_facial_hairstyle] ghost_facial_hair = mutable_appearance('icons/mob/human/human_face.dmi', "[facial_hair_style.icon_state]", -HAIR_LAYER) ghost_facial_hair.alpha = 200 ghost_facial_hair.color = ghost_facial_hair_color diff --git a/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_behavior.dm b/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_behavior.dm index 28cffa4ed8e32..7db7a8913fa32 100644 --- a/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_behavior.dm +++ b/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_behavior.dm @@ -30,19 +30,16 @@ /datum/ai_behavior/relay_message/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - var/mob/living/target = controller.blackboard[target_key] var/mob/living/living_pawn = controller.pawn if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/message_relayed = "" for(var/i in 1 to length_of_message) message_relayed += prob(50) ? "1" : "0" living_pawn.say(message_relayed, forced = "AI Controller") - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/relay_message/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm index 51379ce88a0bc..c0fb9b67e7f73 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm @@ -55,6 +55,7 @@ AddElementTrait(TRAIT_WADDLING, INNATE_TRAIT, /datum/element/waddling) AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/door_pryer, pry_time = 5 SECONDS, interaction_key = REGALRAT_INTERACTION) + AddElement(/datum/element/poster_tearer, interaction_key = REGALRAT_INTERACTION) AddComponent(\ /datum/component/ghost_direct_control,\ poll_candidates = poll_ghosts,\ diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm index df7eb0c42b3b5..feb6ebb7c3b66 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm @@ -15,6 +15,15 @@ button_icon_state = "coffer" shared_cooldown = NONE +/datum/action/cooldown/mob_cooldown/domain/IsAvailable(feedback = FALSE) + . = ..() + if (!.) + return FALSE + if (owner.movement_type & VENTCRAWLING) + if (feedback) + owner.balloon_alert(owner, "can't use while ventcrawling!") + return FALSE + /datum/action/cooldown/mob_cooldown/domain/proc/domain() var/turf/location = get_turf(owner) location.atmos_spawn_air("[GAS_MIASMA]=4;[TURF_TEMPERATURE(T20C)]") @@ -69,6 +78,15 @@ /datum/pet_command/point_targeting/attack/glockroach ) +/datum/action/cooldown/mob_cooldown/riot/IsAvailable(feedback = FALSE) + . = ..() + if (!.) + return FALSE + if (owner.movement_type & VENTCRAWLING) + if (feedback) + owner.balloon_alert(owner, "can't use while ventcrawling!") + return FALSE + /datum/action/cooldown/mob_cooldown/riot/Activate(atom/target) StartCooldown(10 SECONDS) riot() diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index 266e7b5b4143f..d2b5edc58cced 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -102,7 +102,7 @@ RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned)) RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move)) RegisterSignal(src, COMSIG_LIVING_LIFE, PROC_REF(on_life)) - set_random_revenant_name() + name = generate_random_mob_name() GLOB.revenant_relay_mobs |= src @@ -204,7 +204,7 @@ ShiftClickOn(A) return if(LAZYACCESS(modifiers, ALT_CLICK)) - AltClickNoInteract(src, A) + base_click_alt(A) return if(LAZYACCESS(modifiers, RIGHT_CLICK)) ranged_secondary_attack(A, modifiers) @@ -357,13 +357,13 @@ returnable_list += span_bold("Be sure to read the wiki page to learn more.") return returnable_list -/mob/living/basic/revenant/proc/set_random_revenant_name() +/mob/living/basic/revenant/generate_random_mob_name() var/list/built_name_strings = list() built_name_strings += pick(strings(REVENANT_NAME_FILE, "spirit_type")) built_name_strings += " of " built_name_strings += pick(strings(REVENANT_NAME_FILE, "adverb")) built_name_strings += pick(strings(REVENANT_NAME_FILE, "theme")) - name = built_name_strings.Join("") + return built_name_strings.Join("") /mob/living/basic/revenant/proc/on_baned(obj/item/weapon, mob/living/user) SIGNAL_HANDLER diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm index b7bbcad2df0c0..9f565dab11253 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm @@ -123,7 +123,7 @@ light_sparks.set_up(4, 0, light) light_sparks.start() new /obj/effect/temp_visual/revenant(get_turf(light)) - addtimer(CALLBACK(src, PROC_REF(overload_shock), light, caster), 20) + addtimer(CALLBACK(src, PROC_REF(overload_shock), light, caster), 2 SECONDS) /datum/action/cooldown/spell/aoe/revenant/overload/proc/overload_shock(obj/machinery/light/to_shock, mob/living/basic/revenant/caster) flick("[to_shock.base_state]2", to_shock) diff --git a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm index 8682c8028e32e..20f6ce4baf08e 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm @@ -13,19 +13,17 @@ var/scan_range = 3 /datum/ai_behavior/find_unwebbed_turf/perform(seconds_per_tick, datum/ai_controller/controller) - . = ..() var/mob/living/spider = controller.pawn var/atom/current_target = controller.blackboard[target_key] if (current_target && !(locate(/obj/structure/spider/stickyweb) in current_target)) - finish_action(controller, succeeded = FALSE) // Already got a target - return + // Already got a target + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.clear_blackboard_key(target_key) var/turf/our_turf = get_turf(spider) if (is_valid_web_turf(our_turf, spider)) controller.set_blackboard_key(target_key, our_turf) - finish_action(controller, succeeded = TRUE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED var/list/turfs_by_range = list() for (var/i in 1 to scan_range) @@ -41,11 +39,10 @@ final_turfs = turfs_by_range[turf_list] break if (!length(final_turfs)) - finish_action(controller, succeeded = FALSE) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED controller.set_blackboard_key(target_key, pick(final_turfs)) - finish_action(controller, succeeded = TRUE) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/find_unwebbed_turf/proc/is_valid_web_turf(turf/target_turf, mob/living/spider) if (locate(/obj/structure/spider/stickyweb) in target_turf) @@ -82,9 +79,10 @@ return ..() /datum/ai_behavior/spin_web/perform(seconds_per_tick, datum/ai_controller/controller, action_key, target_key) - . = ..() var/datum/action/cooldown/web_action = controller.blackboard[action_key] - finish_action(controller, succeeded = web_action?.Trigger(), action_key = action_key, target_key = target_key) + if(web_action?.Trigger()) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED /datum/ai_behavior/spin_web/finish_action(datum/ai_controller/controller, succeeded, action_key, target_key) controller.clear_blackboard_key(target_key) diff --git a/code/modules/mob/living/basic/space_fauna/statue/mannequin.dm b/code/modules/mob/living/basic/space_fauna/statue/mannequin.dm index 7b6bf6c839992..9710421b408a7 100644 --- a/code/modules/mob/living/basic/space_fauna/statue/mannequin.dm +++ b/code/modules/mob/living/basic/space_fauna/statue/mannequin.dm @@ -57,14 +57,13 @@ return ismovable(target) && isturf(target.loc) && ismob(controller.pawn) /datum/ai_behavior/face_target_or_face_initial/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() var/atom/movable/target = controller.blackboard[target_key] var/mob/living/we = controller.pawn if(isnull(target) || get_dist(we, target) > 8) we.dir = controller.blackboard[BB_STARTING_DIRECTION] - finish_action(controller, TRUE) - else - we.face_atom(target) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + we.face_atom(target) + return AI_BEHAVIOR_DELAY /mob/living/basic/statue/mannequin/suspicious name = "mannequin?" diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm index 70b3506527a18..bba6e0eb460c6 100644 --- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm +++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm @@ -39,6 +39,7 @@ id = "wumbo_inflated" duration = 10 SECONDS alert_type = /atom/movable/screen/alert/status_effect/inflated + show_duration = TRUE /atom/movable/screen/alert/status_effect/inflated name = "WUMBO" diff --git a/code/modules/mob/living/basic/trader/trader_ai.dm b/code/modules/mob/living/basic/trader/trader_ai.dm index 5f447ab3229af..d79a12a2d29b6 100644 --- a/code/modules/mob/living/basic/trader/trader_ai.dm +++ b/code/modules/mob/living/basic/trader/trader_ai.dm @@ -61,19 +61,15 @@ return !QDELETED(target) /datum/ai_behavior/setup_shop/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - //We lost track of our costumer or our ability, abort if(!controller.blackboard_key_exists(target_key) || !controller.blackboard_key_exists(BB_SETUP_SHOP)) - finish_action(controller, FALSE, target_key) - return + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/datum/action/setup_shop/shop = controller.blackboard[BB_SETUP_SHOP] shop.Trigger() controller.clear_blackboard_key(BB_FIRST_CUSTOMER) - - finish_action(controller, TRUE, target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/idle_behavior/idle_random_walk/not_while_on_target/trader target_key = BB_SHOP_SPOT diff --git a/code/modules/mob/living/basic/trooper/syndicate.dm b/code/modules/mob/living/basic/trooper/syndicate.dm index c4d1bbd363049..8f8d564693b66 100644 --- a/code/modules/mob/living/basic/trooper/syndicate.dm +++ b/code/modules/mob/living/basic/trooper/syndicate.dm @@ -154,6 +154,13 @@ ranged_cooldown = 3 SECONDS r_hand = /obj/item/gun/ballistic/automatic/c20r +///Spawns from an emagged orion trail machine set to kill the player. +/mob/living/basic/trooper/syndicate/ranged/smg/orion + name = "spaceport security" + desc = "Premier corporate security forces for all spaceports found along the Orion Trail." + faction = list(FACTION_ORION) + loot = list() + /mob/living/basic/trooper/syndicate/ranged/smg/pilot //caravan ambush ruin name = "Syndicate Salvage Pilot" loot = list(/obj/effect/mob_spawn/corpse/human/syndicatepilot) diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 74e5931163b49..56693b20b367b 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -289,10 +289,9 @@ brainmob.emp_damage = min(brainmob.emp_damage + rand(0,10), 30) brainmob.emote("alarm") -/obj/item/mmi/deconstruct(disassembled = TRUE) +/obj/item/mmi/atom_deconstruct(disassembled = TRUE) if(brain) eject_brain() - qdel(src) /obj/item/mmi/examine(mob/user) . = ..() diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm index a59e5021948d8..9df1697e4008a 100644 --- a/code/modules/mob/living/brain/posibrain.dm +++ b/code/modules/mob/living/brain/posibrain.dm @@ -75,17 +75,16 @@ GLOBAL_VAR(posibrain_notify_cooldown) update_appearance() addtimer(CALLBACK(src, PROC_REF(check_success)), ask_delay) -/obj/item/mmi/posibrain/AltClick(mob/living/user) - if(!istype(user) || !user.can_perform_action(src)) - return +/obj/item/mmi/posibrain/click_alt(mob/living/user) var/input_seed = tgui_input_text(user, "Enter a personality seed", "Enter seed", ask_role, MAX_NAME_LEN) if(isnull(input_seed)) - return - if(!istype(user) || !user.can_perform_action(src)) + return CLICK_ACTION_BLOCKING + if(!user.can_perform_action(src)) return to_chat(user, span_notice("You set the personality seed to \"[input_seed]\".")) ask_role = input_seed update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/mmi/posibrain/proc/check_success() searching = FALSE diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 874942f5feb64..f8210c77368cc 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -122,18 +122,32 @@ Des: Removes all infected images from the alien. span_alertalien("[src] begins to twist and contort!"), span_noticealien("You begin to evolve!"), ) + new_xeno.setDir(dir) - if(numba && unique_name) - new_xeno.numba = numba - new_xeno.set_name() - if(!alien_name_regex.Find(name)) - new_xeno.name = name - new_xeno.real_name = real_name + new_xeno.change_name(name, real_name, numba) + if(mind) mind.name = new_xeno.real_name mind.transfer_to(new_xeno) + qdel(src) +/// Changes the name of the xeno we are evolving into in order to keep the same numerical identifier the old xeno had. +/mob/living/carbon/alien/proc/change_name(old_name, old_real_name, old_number) + if(!alien_name_regex.Find(old_name)) // check to make sure there's no admins doing funny stuff with naming these aliens + name = old_name + real_name = old_real_name + return + + if(!unique_name) + return + + if(old_number != 0) + numba = old_number + name = initial(name) // prevent chicanery like two different numerical identifiers tied to the same mob + + set_name() + /mob/living/carbon/alien/can_hold_items(obj/item/I) return (I && (I.item_flags & XENOMORPH_HOLDABLE || ISADVANCEDTOOLUSER(src)) && ..()) diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index cffdd1f648fbb..d068610b28f7a 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -108,7 +108,7 @@ return if(stat == CONSCIOUS) icon_state = "[base_icon_state]_thrown" - addtimer(CALLBACK(src, PROC_REF(clear_throw_icon_state)), 15) + addtimer(CALLBACK(src, PROC_REF(clear_throw_icon_state)), 1.5 SECONDS) /obj/item/clothing/mask/facehugger/proc/clear_throw_icon_state() if(icon_state == "[base_icon_state]_thrown") diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 657fec3705380..f901be8340b6a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -234,25 +234,34 @@ return TRUE return FALSE + /mob/living/carbon/resist_buckle() - if(HAS_TRAIT(src, TRAIT_RESTRAINED)) - changeNext_move(CLICK_CD_BREAKOUT) - last_special = world.time + CLICK_CD_BREAKOUT - var/buckle_cd = 60 SECONDS - if(handcuffed) - var/obj/item/restraints/O = src.get_item_by_slot(ITEM_SLOT_HANDCUFFED) - buckle_cd = O.breakouttime - visible_message(span_warning("[src] attempts to unbuckle [p_them()]self!"), \ - span_notice("You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)")) - if(do_after(src, buckle_cd, target = src, timed_action_flags = IGNORE_HELD_ITEM)) - if(!buckled) - return - buckled.user_unbuckle_mob(src,src) - else - if(src && buckled) - to_chat(src, span_warning("You fail to unbuckle yourself!")) - else - buckled.user_unbuckle_mob(src,src) + if(!HAS_TRAIT(src, TRAIT_RESTRAINED)) + buckled.user_unbuckle_mob(src, src) + return + + changeNext_move(CLICK_CD_BREAKOUT) + last_special = world.time + CLICK_CD_BREAKOUT + var/buckle_cd = 1 MINUTES + + if(handcuffed) + var/obj/item/restraints/cuffs = src.get_item_by_slot(ITEM_SLOT_HANDCUFFED) + buckle_cd = cuffs.breakouttime + + visible_message(span_warning("[src] attempts to unbuckle [p_them()]self!"), + span_notice("You attempt to unbuckle yourself... \ + (This will take around [DisplayTimeText(buckle_cd)] and you must stay still.)")) + + if(!do_after(src, buckle_cd, target = src, timed_action_flags = IGNORE_HELD_ITEM, hidden = TRUE)) + if(buckled) + to_chat(src, span_warning("You fail to unbuckle yourself!")) + return + + if(QDELETED(src) || isnull(buckled)) + return + + buckled.user_unbuckle_mob(src, src) + /mob/living/carbon/resist_fire() return !!apply_status_effect(/datum/status_effect/stop_drop_roll) @@ -268,42 +277,48 @@ type = 2 if(I) if(type == 1) - changeNext_move(CLICK_CD_BREAKOUT) - last_special = world.time + CLICK_CD_BREAKOUT + changeNext_move(I.resist_cooldown) + last_special = world.time + I.resist_cooldown if(type == 2) changeNext_move(CLICK_CD_RANGE) last_special = world.time + CLICK_CD_RANGE cuff_resist(I) -/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 1 MINUTES, cuff_break = 0) - if((cuff_break != INSTANT_CUFFBREAK) && (SEND_SIGNAL(src, COMSIG_MOB_REMOVING_CUFFS, I) & COMSIG_MOB_BLOCK_CUFF_REMOVAL)) +/** + * Helper to break the cuffs from hands + * @param {obj/item} cuffs - The cuffs to break + * @param {number} breakouttime - The time it takes to break the cuffs. Use SECONDS/MINUTES defines + * @param {number} cuff_break - Speed multiplier, 0 is default, see _DEFINES\combat.dm + */ +/mob/living/carbon/proc/cuff_resist(obj/item/cuffs, breakouttime = 1 MINUTES, cuff_break = 0) + if((cuff_break != INSTANT_CUFFBREAK) && (SEND_SIGNAL(src, COMSIG_MOB_REMOVING_CUFFS, cuffs) & COMSIG_MOB_BLOCK_CUFF_REMOVAL)) return //The blocking object should sent a fluff-appropriate to_chat about cuff removal being blocked - if(I.item_flags & BEING_REMOVED) - to_chat(src, span_warning("You're already attempting to remove [I]!")) + if(cuffs.item_flags & BEING_REMOVED) + to_chat(src, span_warning("You're already attempting to remove [cuffs]!")) return - I.item_flags |= BEING_REMOVED - breakouttime = I.breakouttime + cuffs.item_flags |= BEING_REMOVED + breakouttime = cuffs.breakouttime if(!cuff_break) - visible_message(span_warning("[src] attempts to remove [I]!")) - to_chat(src, span_notice("You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")) - if(do_after(src, breakouttime, target = src, timed_action_flags = IGNORE_HELD_ITEM)) - . = clear_cuffs(I, cuff_break) + visible_message(span_warning("[src] attempts to remove [cuffs]!")) + to_chat(src, span_notice("You attempt to remove [cuffs]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")) + if(do_after(src, breakouttime, target = src, timed_action_flags = IGNORE_HELD_ITEM, hidden = TRUE)) + . = clear_cuffs(cuffs, cuff_break) else - to_chat(src, span_warning("You fail to remove [I]!")) + to_chat(src, span_warning("You fail to remove [cuffs]!")) else if(cuff_break == FAST_CUFFBREAK) - breakouttime = 50 - visible_message(span_warning("[src] is trying to break [I]!")) - to_chat(src, span_notice("You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)")) + breakouttime = 5 SECONDS + visible_message(span_warning("[src] is trying to break [cuffs]!")) + to_chat(src, span_notice("You attempt to break [cuffs]... (This will take around 5 seconds and you need to stand still.)")) if(do_after(src, breakouttime, target = src, timed_action_flags = IGNORE_HELD_ITEM)) - . = clear_cuffs(I, cuff_break) + . = clear_cuffs(cuffs, cuff_break) else - to_chat(src, span_warning("You fail to break [I]!")) + to_chat(src, span_warning("You fail to break [cuffs]!")) else if(cuff_break == INSTANT_CUFFBREAK) - . = clear_cuffs(I, cuff_break) - I.item_flags &= ~BEING_REMOVED + . = clear_cuffs(cuffs, cuff_break) + cuffs.item_flags &= ~BEING_REMOVED /mob/living/carbon/proc/uncuff() if (handcuffed) @@ -404,6 +419,9 @@ if((HAS_TRAIT(src, TRAIT_NOHUNGER) || HAS_TRAIT(src, TRAIT_TOXINLOVER)) && !force) return TRUE + if(!force && HAS_TRAIT(src, TRAIT_STRONG_STOMACH)) + lost_nutrition *= 0.5 + SEND_SIGNAL(src, COMSIG_CARBON_VOMITED, distance, force) // cache some stuff that we'll need later (at least multiple times) @@ -420,7 +438,10 @@ span_userdanger("You try to throw up, but there's nothing in your stomach!"), ) if(stun) - Stun(20 SECONDS) + var/stun_time = 20 SECONDS + if(HAS_TRAIT(src, TRAIT_STRONG_STOMACH)) + stun_time *= 0.5 + Stun(stun_time) if(knockdown) Knockdown(20 SECONDS) return TRUE @@ -443,11 +464,14 @@ add_mood_event("vomit", /datum/mood_event/vomit) if(stun) - Stun(8 SECONDS) + var/stun_time = 8 SECONDS + if(!blood && HAS_TRAIT(src, TRAIT_STRONG_STOMACH)) + stun_time *= 0.5 + Stun(stun_time) if(knockdown) Knockdown(8 SECONDS) - playsound(get_turf(src), 'sound/effects/splat.ogg', 50, TRUE) + playsound(src, 'sound/effects/splat.ogg', 50, TRUE) var/need_mob_update = FALSE var/turf/location = get_turf(src) @@ -627,12 +651,8 @@ */ /mob/living/carbon/proc/update_tint() var/tint = 0 - if(isclothing(head)) - tint += head.tint - if(isclothing(wear_mask)) - tint += wear_mask.tint - if(isclothing(glasses)) - tint += glasses.tint + for(var/obj/item/clothing/worn_item in get_equipped_items()) + tint += worn_item.tint var/obj/item/organ/internal/eyes/eyes = get_organ_slot(ORGAN_SLOT_EYES) if(eyes) @@ -888,7 +908,11 @@ if(!HAS_TRAIT(src, TRAIT_LIVERLESS_METABOLISM) && !isnull(dna?.species.mutantliver) && !get_organ_slot(ORGAN_SLOT_LIVER)) return FALSE - return ..() + . = ..() + if(.) // if revived successfully + set_heartattack(FALSE) + + return . /mob/living/carbon/fully_heal(heal_flags = HEAL_ALL) @@ -1101,14 +1125,14 @@ return var/list/limb_list = list() if(edit_action == "remove") - for(var/obj/item/bodypart/B as anything in bodyparts) - limb_list += B.body_zone + for(var/obj/item/bodypart/iter_part as anything in bodyparts) + limb_list += iter_part.body_zone limb_list -= BODY_ZONE_CHEST else limb_list = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_CHEST) var/result = input(usr, "Please choose which bodypart to [edit_action]","[capitalize(edit_action)] Bodypart") as null|anything in sort_list(limb_list) if(result) - var/obj/item/bodypart/BP = get_bodypart(result) + var/obj/item/bodypart/part = get_bodypart(result) var/list/limbtypes = list() switch(result) if(BODY_ZONE_CHEST) @@ -1125,9 +1149,9 @@ limbtypes = typesof(/obj/item/bodypart/leg/right) switch(edit_action) if("remove") - if(BP) - BP.drop_limb() - admin_ticket_log("[key_name_admin(usr)] has removed [src]'s [parse_zone(BP.body_zone)]") + if(part) + part.drop_limb() + admin_ticket_log("[key_name_admin(usr)] has removed [src]'s [part.plaintext_zone]") else to_chat(usr, span_boldwarning("[src] doesn't have such bodypart.")) admin_ticket_log("[key_name_admin(usr)] has attempted to modify the bodyparts of [src]") @@ -1135,16 +1159,14 @@ var/limb2add = input(usr, "Select a bodypart type to add", "Add/Replace Bodypart") as null|anything in sort_list(limbtypes) var/obj/item/bodypart/new_bp = new limb2add() if(new_bp.replace_limb(src, special = TRUE)) - admin_ticket_log("key_name_admin(usr)] has replaced [src]'s [BP.type] with [new_bp.type]") - qdel(BP) + admin_ticket_log("key_name_admin(usr)] has replaced [src]'s [part.type] with [new_bp.type]") + qdel(part) else to_chat(usr, "Failed to replace bodypart! They might be incompatible.") admin_ticket_log("[key_name_admin(usr)] has attempted to modify the bodyparts of [src]") if(href_list[VV_HK_MODIFY_ORGANS]) - if(!check_rights(NONE)) - return - usr.client.manipulate_organs(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/manipulate_organs, src) if(href_list[VV_HK_MARTIAL_ART]) if(!check_rights(NONE)) @@ -1218,35 +1240,35 @@ update_worn_back(0) . = TRUE - if(head?.wash(clean_types)) - update_worn_head() - . = TRUE - // Check and wash stuff that can be covered var/obscured = check_obscured_slots() + if(!(obscured & ITEM_SLOT_HEAD) && head?.wash(clean_types)) + update_worn_head() + . = TRUE + // If the eyes are covered by anything but glasses, that thing will be covering any potential glasses as well. - if(glasses && is_eyes_covered(ITEM_SLOT_MASK|ITEM_SLOT_HEAD) && glasses.wash(clean_types)) + if(is_eyes_covered(ITEM_SLOT_MASK|ITEM_SLOT_HEAD) && glasses?.wash(clean_types)) update_worn_glasses() . = TRUE - if(wear_mask && !(obscured & ITEM_SLOT_MASK) && wear_mask.wash(clean_types)) + if(!(obscured & ITEM_SLOT_MASK) && wear_mask?.wash(clean_types)) update_worn_mask() . = TRUE - if(ears && !(obscured & ITEM_SLOT_EARS) && ears.wash(clean_types)) - update_inv_ears() + if(!(obscured & ITEM_SLOT_EARS) && ears?.wash(clean_types)) + update_worn_ears() . = TRUE - if(wear_neck && !(obscured & ITEM_SLOT_NECK) && wear_neck.wash(clean_types)) + if(!(obscured & ITEM_SLOT_NECK) && wear_neck?.wash(clean_types)) update_worn_neck() . = TRUE - if(shoes && !(obscured & ITEM_SLOT_FEET) && shoes.wash(clean_types)) + if(!(obscured & ITEM_SLOT_FEET) && shoes?.wash(clean_types)) update_worn_shoes() . = TRUE - if(gloves && !(obscured & ITEM_SLOT_GLOVES) && gloves.wash(clean_types)) + if(!(obscured & ITEM_SLOT_GLOVES) && gloves?.wash(clean_types)) update_worn_gloves() . = TRUE @@ -1451,3 +1473,20 @@ if(!unwagged) return FALSE return unwagged.stop_wag(src) + +/mob/living/carbon/itch(obj/item/bodypart/target_part = null, damage = 0.5, can_scratch = TRUE, silent = FALSE) + if (isnull(target_part)) + target_part = get_bodypart(get_random_valid_zone(even_weights = TRUE)) + if (!IS_ORGANIC_LIMB(target_part) || (target_part.bodypart_flags & BODYPART_PSEUDOPART)) + return FALSE + return ..() + +/mob/living/carbon/ominous_nosebleed() + var/obj/item/bodypart/head = get_bodypart(BODY_ZONE_HEAD) + if(isnull(head)) + return ..() + if(HAS_TRAIT(src, TRAIT_NOBLOOD)) + to_chat(src, span_notice("You get a headache.")) + return + head.adjustBleedStacks(5) + visible_message(span_notice("[src] gets a nosebleed."), span_warning("You get a nosebleed.")) diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index 8dfa0be5e2b0c..00e502bad0451 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -1,38 +1,7 @@ -/mob/living/carbon/human/update_clothing(slot_flags) - if(slot_flags & ITEM_SLOT_BACK) - update_worn_back() - if(slot_flags & ITEM_SLOT_MASK) - update_worn_mask() - if(slot_flags & ITEM_SLOT_NECK) - update_worn_neck() - if(slot_flags & ITEM_SLOT_HANDCUFFED) - update_worn_handcuffs() - if(slot_flags & ITEM_SLOT_LEGCUFFED) - update_worn_legcuffs() - if(slot_flags & ITEM_SLOT_BELT) - update_worn_belt() - if(slot_flags & ITEM_SLOT_ID) - update_worn_id() - if(slot_flags & ITEM_SLOT_EARS) - update_inv_ears() - if(slot_flags & ITEM_SLOT_EYES) - update_worn_glasses() - if(slot_flags & ITEM_SLOT_GLOVES) - update_worn_gloves() - if(slot_flags & ITEM_SLOT_HEAD) - update_worn_head() - if(slot_flags & ITEM_SLOT_FEET) - update_worn_shoes() - if(slot_flags & ITEM_SLOT_OCLOTHING) - update_worn_oversuit() - if(slot_flags & ITEM_SLOT_ICLOTHING) - update_worn_undersuit() - if(slot_flags & ITEM_SLOT_SUITSTORE) - update_suit_storage() - if(slot_flags & (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET)) - update_pockets() - if(slot_flags & ITEM_SLOT_HANDS) - update_held_items() +/mob/living/carbon/update_obscured_slots(obscured_flags) + ..() + if(obscured_flags & (HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT|HIDEMUTWINGS)) + update_body() /// Updates features and clothing attached to a specific limb with limb-specific offsets /mob/living/carbon/proc/update_features(feature_key) @@ -46,7 +15,7 @@ if(OFFSET_GLASSES) update_worn_glasses() if(OFFSET_EARS) - update_inv_ears() + update_worn_ears() if(OFFSET_SHOES) update_worn_shoes() if(OFFSET_S_STORE) @@ -331,31 +300,39 @@ /mob/living/carbon/update_damage_overlays() remove_overlay(DAMAGE_LAYER) - var/mutable_appearance/damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "blank", -DAMAGE_LAYER) - overlays_standing[DAMAGE_LAYER] = damage_overlay - + var/mutable_appearance/damage_overlay for(var/obj/item/bodypart/iter_part as anything in bodyparts) - if(iter_part.dmg_overlay_type) - if(iter_part.brutestate) - damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0") //we're adding icon_states of the base image as overlays - if(iter_part.burnstate) - damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_0[iter_part.burnstate]") + if(!iter_part.dmg_overlay_type) + continue + if(isnull(damage_overlay) && (iter_part.brutestate || iter_part.burnstate)) + damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "blank", -DAMAGE_LAYER, appearance_flags = KEEP_TOGETHER) + if(iter_part.brutestate) + damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0") //we're adding icon_states of the base image as overlays + if(iter_part.burnstate) + damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_0[iter_part.burnstate]") + + if(isnull(damage_overlay)) + return + overlays_standing[DAMAGE_LAYER] = damage_overlay apply_overlay(DAMAGE_LAYER) /mob/living/carbon/update_wound_overlays() remove_overlay(WOUND_LAYER) - var/mutable_appearance/wound_overlay = mutable_appearance('icons/mob/effects/bleed_overlays.dmi', "blank", -WOUND_LAYER) - overlays_standing[WOUND_LAYER] = wound_overlay - + var/mutable_appearance/wound_overlay for(var/obj/item/bodypart/iter_part as anything in bodyparts) if(iter_part.bleed_overlay_icon) + wound_overlay ||= mutable_appearance('icons/mob/effects/bleed_overlays.dmi', "blank", -WOUND_LAYER, appearance_flags = KEEP_TOGETHER) wound_overlay.add_overlay(iter_part.bleed_overlay_icon) + if(isnull(wound_overlay)) + return + + overlays_standing[WOUND_LAYER] = wound_overlay apply_overlay(WOUND_LAYER) -/mob/living/carbon/update_worn_mask() +/mob/living/carbon/update_worn_mask(update_obscured = TRUE) remove_overlay(FACEMASK_LAYER) if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated @@ -366,13 +343,15 @@ inv.update_appearance() if(wear_mask) + if(update_obscured) + update_obscured_slots(wear_mask.flags_inv) if(!(check_obscured_slots() & ITEM_SLOT_MASK)) overlays_standing[FACEMASK_LAYER] = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/clothing/mask.dmi') update_hud_wear_mask(wear_mask) apply_overlay(FACEMASK_LAYER) -/mob/living/carbon/update_worn_neck() +/mob/living/carbon/update_worn_neck(update_obscured = TRUE) remove_overlay(NECK_LAYER) if(client && hud_used?.inv_slots[TOBITSHIFT(ITEM_SLOT_NECK) + 1]) @@ -380,13 +359,15 @@ inv.update_appearance() if(wear_neck) + if(update_obscured) + update_obscured_slots(wear_neck.flags_inv) if(!(check_obscured_slots() & ITEM_SLOT_NECK)) overlays_standing[NECK_LAYER] = wear_neck.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = 'icons/mob/clothing/neck.dmi') update_hud_neck(wear_neck) apply_overlay(NECK_LAYER) -/mob/living/carbon/update_worn_back() +/mob/living/carbon/update_worn_back(update_obscured = TRUE) remove_overlay(BACK_LAYER) if(client && hud_used?.inv_slots[TOBITSHIFT(ITEM_SLOT_BACK) + 1]) @@ -394,20 +375,24 @@ inv.update_appearance() if(back) + if(update_obscured) + update_obscured_slots(back.flags_inv) overlays_standing[BACK_LAYER] = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = 'icons/mob/clothing/back.dmi') update_hud_back(back) apply_overlay(BACK_LAYER) -/mob/living/carbon/update_worn_legcuffs() +/mob/living/carbon/update_worn_legcuffs(update_obscured = TRUE) remove_overlay(LEGCUFF_LAYER) clear_alert("legcuffed") if(legcuffed) + if(update_obscured) + update_obscured_slots(legcuffed.flags_inv) overlays_standing[LEGCUFF_LAYER] = mutable_appearance('icons/mob/simple/mob.dmi', "legcuff1", -LEGCUFF_LAYER) apply_overlay(LEGCUFF_LAYER) throw_alert("legcuffed", /atom/movable/screen/alert/restrained/legcuffed, new_master = src.legcuffed) -/mob/living/carbon/update_worn_head() +/mob/living/carbon/update_worn_head(update_obscured = TRUE) remove_overlay(HEAD_LAYER) if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated @@ -418,15 +403,20 @@ inv.update_appearance() if(head) - overlays_standing[HEAD_LAYER] = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/clothing/head/default.dmi') + if(update_obscured) + update_obscured_slots(head.flags_inv) + if(!(check_obscured_slots() & ITEM_SLOT_HEAD)) + overlays_standing[HEAD_LAYER] = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/clothing/head/default.dmi') update_hud_head(head) apply_overlay(HEAD_LAYER) -/mob/living/carbon/update_worn_handcuffs() +/mob/living/carbon/update_worn_handcuffs(update_obscured = TRUE) remove_overlay(HANDCUFF_LAYER) if(handcuffed) + if(update_obscured) + update_obscured_slots(handcuffed.flags_inv) var/mutable_appearance/handcuff_overlay = mutable_appearance('icons/mob/simple/mob.dmi', "handcuff1", -HANDCUFF_LAYER) if(handcuffed.blocks_emissive != EMISSIVE_BLOCK_NONE) handcuff_overlay.overlays += emissive_blocker(handcuff_overlay.icon, handcuff_overlay.icon_state, src, alpha = handcuff_overlay.alpha) @@ -485,7 +475,7 @@ var/old_key = icon_render_keys?[limb.body_zone] //Checks the mob's icon render key list for the bodypart icon_render_keys[limb.body_zone] = (limb.is_husked) ? limb.generate_husk_key().Join() : limb.generate_icon_key().Join() //Generates a key for the current bodypart - if(icon_render_keys[limb.body_zone] != old_key || get_top_offset() != last_top_offset) //If the keys match, that means the limb doesn't need to be redrawn + if(icon_render_keys[limb.body_zone] != old_key) //If the keys match, that means the limb doesn't need to be redrawn needs_update += limb var/list/missing_bodyparts = get_missing_limbs() @@ -502,15 +492,10 @@ for(var/obj/item/bodypart/limb as anything in bodyparts) if(limb in needs_update) var/bodypart_icon = limb.get_limb_icon() - if(!istype(limb, /obj/item/bodypart/leg)) - var/top_offset = get_top_offset() - for(var/image/image as anything in bodypart_icon) - image.pixel_y += top_offset new_limbs += bodypart_icon limb_icon_cache[icon_render_keys[limb.body_zone]] = bodypart_icon //Caches the icon with the bodypart key, as it is new else new_limbs += limb_icon_cache[icon_render_keys[limb.body_zone]] //Pulls existing sprites from the cache - last_top_offset = get_top_offset() remove_overlay(BODYPARTS_LAYER) @@ -520,19 +505,6 @@ apply_overlay(BODYPARTS_LAYER) -/// This looks at the chest and legs of the mob and decides how much our chest, arms, and head should be adjusted. This is useful for limbs that are larger or smaller than the scope of normal human height while keeping the feet anchored to the bottom of the tile -/mob/living/carbon/proc/get_top_offset() - var/from_chest - var/from_leg - for(var/obj/item/bodypart/leg/leg_checked in bodyparts) - if(leg_checked.top_offset > from_leg || isnull(from_leg)) // We find the tallest leg available - from_leg = leg_checked.top_offset - if(isnull(from_leg)) - from_leg = 0 // If we have no legs, we set this to zero to avoid any math issues that might stem from it being NULL - for(var/obj/item/bodypart/chest/chest_checked in bodyparts) // Take the height from the chest - from_chest = chest_checked.top_offset - return (from_chest + from_leg) // The total hight of the chest and legs together - ///////////////////////// // Limb Icon Cache 2.0 // ///////////////////////// diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index eafb6f8ba22e1..41a958518c597 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -19,7 +19,7 @@ BT.on_death() /mob/living/carbon/proc/inflate_gib() // Plays an animation that makes mobs appear to inflate before finally gibbing - addtimer(CALLBACK(src, PROC_REF(gib), DROP_BRAIN|DROP_ORGANS|DROP_ITEMS), 25) + addtimer(CALLBACK(src, PROC_REF(gib), DROP_BRAIN|DROP_ORGANS|DROP_ITEMS), 2.5 SECONDS) var/matrix/M = matrix() M.Scale(1.8, 1.2) animate(src, time = 40, transform = M, easing = SINE_EASING) diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm index 9ba533a33b5d2..e01315094a11b 100644 --- a/code/modules/mob/living/carbon/emote.dm +++ b/code/modules/mob/living/carbon/emote.dm @@ -160,7 +160,7 @@ key_third_person = "snaps" message = "snaps their fingers." message_param = "snaps their fingers at %t." - emote_type = EMOTE_AUDIBLE + emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE hands_use_check = TRUE muzzle_ignore = TRUE diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 46e0b0e967cbe..24a35e683e36d 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -211,6 +211,7 @@ GLOBAL_LIST_EMPTY(features_by_species) GLOB.roundstart_races = generate_selectable_species_and_languages() return GLOB.roundstart_races + /** * Generates species available to choose in character setup at roundstart * @@ -221,14 +222,12 @@ GLOBAL_LIST_EMPTY(features_by_species) var/list/selectable_species = list() for(var/species_type in subtypesof(/datum/species)) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] if(species.check_roundstart_eligible()) selectable_species += species.id - var/datum/language_holder/temp_holder = new species.species_language_holder + var/datum/language_holder/temp_holder = GLOB.prototype_language_holders[species.species_language_holder] for(var/datum/language/spoken_language as anything in temp_holder.understood_languages) GLOB.uncommon_roundstart_languages |= spoken_language - qdel(temp_holder) - qdel(species) GLOB.uncommon_roundstart_languages -= /datum/language/common if(!selectable_species.len) @@ -247,32 +246,6 @@ GLOBAL_LIST_EMPTY(features_by_species) return TRUE return FALSE -/** - * Generates a random name for a carbon. - * - * This generates a random unique name based on a human's species and gender. - * Arguments: - * * gender - The gender that the name should adhere to. Use MALE for male names, use anything else for female names. - * * unique - If true, ensures that this new name is not a duplicate of anyone else's name currently on the station. - * * last_name - Do we use a given last name or pick a random new one? - */ -/datum/species/proc/random_name(gender, unique, last_name) - if(unique) - return random_unique_name(gender) - - var/randname - if(gender == MALE) - randname = pick(GLOB.first_names_male) - else - randname = pick(GLOB.first_names_female) - - if(last_name) - randname += " [last_name]" - else - randname += " [pick(GLOB.last_names)]" - - return randname - /** * Copies some vars and properties over that should be kept when creating a copy of this species. * @@ -427,7 +400,7 @@ GLOBAL_LIST_EMPTY(features_by_species) replacement.Insert(organ_holder, special=TRUE, movement_flags = DELETE_IF_REPLACED) /datum/species/proc/worn_items_fit_body_check(mob/living/carbon/wearer) - for(var/obj/item/equipped_item in wearer.get_all_worn_items()) + for(var/obj/item/equipped_item in wearer.get_equipped_items(include_pockets = TRUE)) var/equipped_item_slot = wearer.get_slot_by_item(equipped_item) if(!equipped_item.mob_can_equip(wearer, equipped_item_slot, bypass_equip_delay_self = TRUE, ignore_equipped = TRUE)) wearer.dropItemToGround(equipped_item, force = TRUE) @@ -574,7 +547,6 @@ GLOBAL_LIST_EMPTY(features_by_species) */ /datum/species/proc/handle_body(mob/living/carbon/human/species_human) species_human.remove_overlay(BODY_LAYER) - var/height_offset = species_human.get_top_offset() // From high changed by varying limb height if(HAS_TRAIT(species_human, TRAIT_INVISIBLE_MAN)) return handle_mutant_bodyparts(species_human) var/list/standing = list() @@ -586,9 +558,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/organ/internal/eyes/eye_organ = species_human.get_organ_slot(ORGAN_SLOT_EYES) if(eye_organ) eye_organ.refresh(call_update = FALSE) - for(var/mutable_appearance/eye_overlay in eye_organ.generate_body_overlay(species_human)) - eye_overlay.pixel_y += height_offset - standing += eye_overlay + standing += eye_organ.generate_body_overlay(species_human) // organic body markings (oh my god this is terrible please rework this to be done on the limbs themselves i beg you) if(HAS_TRAIT(species_human, TRAIT_HAS_MARKINGS)) @@ -597,39 +567,39 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/bodypart/arm/left/left_arm = species_human.get_bodypart(BODY_ZONE_L_ARM) var/obj/item/bodypart/leg/right/right_leg = species_human.get_bodypart(BODY_ZONE_R_LEG) var/obj/item/bodypart/leg/left/left_leg = species_human.get_bodypart(BODY_ZONE_L_LEG) - var/datum/sprite_accessory/markings = GLOB.moth_markings_list[species_human.dna.features["moth_markings"]] + var/datum/sprite_accessory/markings = SSaccessories.moth_markings_list[species_human.dna.features["moth_markings"]] + var/mutable_appearance/marking = mutable_appearance(layer = -BODY_LAYER, appearance_flags = KEEP_TOGETHER) + if(noggin && (IS_ORGANIC_LIMB(noggin))) - var/mutable_appearance/markings_head_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_head", -BODY_LAYER) - markings_head_overlay.pixel_y += height_offset - standing += markings_head_overlay + var/mutable_appearance/markings_head_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_head") + marking.overlays += markings_head_overlay if(chest && (IS_ORGANIC_LIMB(chest))) - var/mutable_appearance/markings_chest_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_chest", -BODY_LAYER) - markings_chest_overlay.pixel_y += height_offset - standing += markings_chest_overlay + var/mutable_appearance/markings_chest_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_chest") + marking.overlays += markings_chest_overlay if(right_arm && (IS_ORGANIC_LIMB(right_arm))) - var/mutable_appearance/markings_r_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_arm", -BODY_LAYER) - markings_r_arm_overlay.pixel_y += height_offset - standing += markings_r_arm_overlay + var/mutable_appearance/markings_r_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_arm") + marking.overlays += markings_r_arm_overlay if(left_arm && (IS_ORGANIC_LIMB(left_arm))) - var/mutable_appearance/markings_l_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_arm", -BODY_LAYER) - markings_l_arm_overlay.pixel_y += height_offset - standing += markings_l_arm_overlay + var/mutable_appearance/markings_l_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_arm") + marking.overlays += markings_l_arm_overlay if(right_leg && (IS_ORGANIC_LIMB(right_leg))) - var/mutable_appearance/markings_r_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_leg", -BODY_LAYER) - standing += markings_r_leg_overlay + var/mutable_appearance/markings_r_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_leg") + marking.overlays += markings_r_leg_overlay if(left_leg && (IS_ORGANIC_LIMB(left_leg))) - var/mutable_appearance/markings_l_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_leg", -BODY_LAYER) - standing += markings_l_leg_overlay + var/mutable_appearance/markings_l_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_leg") + marking.overlays += markings_l_leg_overlay + + standing += marking //Underwear, Undershirts & Socks if(!HAS_TRAIT(species_human, TRAIT_NO_UNDERWEAR)) if(species_human.underwear) - var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[species_human.underwear] + var/datum/sprite_accessory/underwear/underwear = SSaccessories.underwear_list[species_human.underwear] var/mutable_appearance/underwear_overlay if(underwear) if(species_human.dna.species.sexes && species_human.physique == FEMALE && (underwear.gender == MALE)) @@ -638,22 +608,20 @@ GLOBAL_LIST_EMPTY(features_by_species) underwear_overlay = mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) if(!underwear.use_static) underwear_overlay.color = species_human.underwear_color - underwear_overlay.pixel_y += height_offset standing += underwear_overlay if(species_human.undershirt) - var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[species_human.undershirt] + var/datum/sprite_accessory/undershirt/undershirt = SSaccessories.undershirt_list[species_human.undershirt] if(undershirt) var/mutable_appearance/working_shirt if(species_human.dna.species.sexes && species_human.physique == FEMALE) working_shirt = wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) else working_shirt = mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) - working_shirt.pixel_y += height_offset standing += working_shirt if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodyshape & BODYSHAPE_DIGITIGRADE)) - var/datum/sprite_accessory/socks/socks = GLOB.socks_list[species_human.socks] + var/datum/sprite_accessory/socks/socks = SSaccessories.socks_list[species_human.socks] if(socks) standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) @@ -703,11 +671,11 @@ GLOBAL_LIST_EMPTY(features_by_species) var/datum/sprite_accessory/accessory switch(bodypart) if("ears") - accessory = GLOB.ears_list[source.dna.features["ears"]] + accessory = SSaccessories.ears_list[source.dna.features["ears"]] if("body_markings") - accessory = GLOB.body_markings_list[source.dna.features["body_markings"]] + accessory = SSaccessories.body_markings_list[source.dna.features["body_markings"]] if("legs") - accessory = GLOB.legs_list[source.dna.features["legs"]] + accessory = SSaccessories.legs_list[source.dna.features["legs"]] if(!accessory || accessory.icon_state == "none") continue @@ -833,7 +801,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(!(I.slot_flags & slot)) var/excused = FALSE // Anything that's small or smaller can fit into a pocket by default - if((slot & (ITEM_SLOT_RPOCKET|ITEM_SLOT_LPOCKET)) && I.w_class <= WEIGHT_CLASS_SMALL) + if((slot & (ITEM_SLOT_RPOCKET|ITEM_SLOT_LPOCKET)) && I.w_class <= POCKET_WEIGHT_CLASS) excused = TRUE else if(slot & (ITEM_SLOT_SUITSTORE|ITEM_SLOT_BACKPACK|ITEM_SLOT_HANDS)) excused = TRUE @@ -892,12 +860,6 @@ GLOBAL_LIST_EMPTY(features_by_species) return FALSE return equip_delay_self_check(I, H, bypass_equip_delay_self) if(ITEM_SLOT_ICLOTHING) - var/obj/item/bodypart/chest = H.get_bodypart(BODY_ZONE_CHEST) - if(chest && (chest.bodyshape & BODYSHAPE_MONKEY)) - if(!(I.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) - if(!disable_warning) - to_chat(H, span_warning("[I] doesn't fit your [chest.name]!")) - return FALSE return equip_delay_self_check(I, H, bypass_equip_delay_self) if(ITEM_SLOT_ID) var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST) @@ -1079,7 +1041,7 @@ GLOBAL_LIST_EMPTY(features_by_species) attacking_bodypart = brain.get_attacking_limb(target) if(!attacking_bodypart) attacking_bodypart = user.get_active_hand() - var/atk_verb = attacking_bodypart.unarmed_attack_verb + var/atk_verb = pick(attacking_bodypart.unarmed_attack_verbs) var/atk_effect = attacking_bodypart.unarmed_attack_effect if(atk_effect == ATTACK_EFFECT_BITE) @@ -1143,25 +1105,12 @@ GLOBAL_LIST_EMPTY(features_by_species) target.force_say() log_combat(user, target, grappled ? "grapple punched" : "kicked") target.apply_damage(damage, attack_type, affecting, armor_block - limb_accuracy, attack_direction = attack_direction) - target.apply_damage(damage*1.5, STAMINA, affecting, armor_block - limb_accuracy) else // Normal attacks do not gain the benefit of armor penetration. target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction) - target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) if(damage >= 9) target.force_say() log_combat(user, target, "punched") - //If we rolled a punch high enough to hit our stun threshold, or our target is staggered and they have at least 40 damage+stamina loss, we knock them down - //This does not work against opponents who are knockdown immune, such as from wearing riot armor. - if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) - if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) - target.visible_message(span_danger("[user] knocks [target] down!"), \ - span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You knock [target] down!")) - var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration - target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block) - log_combat(user, target, "got a stun punch with their previous punch") - /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(user.body_position != STANDING_UP) return FALSE @@ -1587,10 +1536,26 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/prepare_human_for_preview(mob/living/carbon/human/human) return -/// Returns the species's scream sound. +/// Returns the species' scream sound. /datum/species/proc/get_scream_sound(mob/living/carbon/human/human) return +/// Returns the species' cry sound. +/datum/species/proc/get_cry_sound(mob/living/carbon/human/human) + return + +/// Returns the species' cough sound. +/datum/species/proc/get_cough_sound(mob/living/carbon/human/human) + return + +/// Returns the species' laugh sound +/datum/species/proc/get_laugh_sound(mob/living/carbon/human/human) + return + +/// Returns the species' sneeze sound. +/datum/species/proc/get_sneeze_sound(mob/living/carbon/human/human) + return + /datum/species/proc/get_types_to_preload() var/list/to_store = list() to_store += mutant_organs diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index eabca79d281b5..627745cba929e 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -41,7 +41,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) //Instead of just deleting our equipment, we save what we can and reinsert it into SSwardrobe's store //Hopefully this makes preference reloading not the worst thing ever /mob/living/carbon/human/dummy/delete_equipment() - var/list/items_to_check = get_all_worn_items() + held_items + var/list/items_to_check = get_equipped_items(include_pockets = TRUE) + held_items var/list/to_nuke = list() //List of items queued for deletion, can't qdel them before iterating their contents in case they hold something ///Travel to the bottom of the contents chain, expanding it out for(var/i = 1; i <= length(items_to_check); i++) //Needs to be a c style loop since it can expand @@ -68,6 +68,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) qdel(delete) /mob/living/carbon/human/dummy/has_equipped(obj/item/item, slot, initial = FALSE) + item.item_flags |= IN_INVENTORY return item.visual_equipped(src, slot, initial) /mob/living/carbon/human/dummy/proc/wipe_state() @@ -80,6 +81,19 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /mob/living/carbon/human/dummy/log_mob_tag(text) return +// To speed up the preference menu, we apply 1 filter to the entire mob +/mob/living/carbon/human/dummy/regenerate_icons() + . = ..() + apply_height_filters(src, TRUE) + +/mob/living/carbon/human/dummy/apply_height_filters(image/appearance, only_apply_in_prefs = FALSE) + if(only_apply_in_prefs) + return ..() + +// Not necessary with above +/mob/living/carbon/human/dummy/apply_height_offsets(image/appearance, upper_torso) + return + /// Takes in an accessory list and returns the first entry from that list, ensuring that we dont return SPRITE_ACCESSORY_NONE in the process. /proc/get_consistent_feature_entry(list/accessory_feature_list) var/consistent_entry = (accessory_feature_list- SPRITE_ACCESSORY_NONE)[1] @@ -89,18 +103,19 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /proc/create_consistent_human_dna(mob/living/carbon/human/target) target.dna.features["mcolor"] = COLOR_VIBRANT_LIME target.dna.features["ethcolor"] = COLOR_WHITE - target.dna.features["body_markings"] = get_consistent_feature_entry(GLOB.body_markings_list) - target.dna.features["ears"] = get_consistent_feature_entry(GLOB.ears_list) - target.dna.features["frills"] = get_consistent_feature_entry(GLOB.frills_list) - target.dna.features["horns"] = get_consistent_feature_entry(GLOB.horns_list) - target.dna.features["moth_antennae"] = get_consistent_feature_entry(GLOB.moth_antennae_list) - target.dna.features["moth_markings"] = get_consistent_feature_entry(GLOB.moth_markings_list) - target.dna.features["moth_wings"] = get_consistent_feature_entry(GLOB.moth_wings_list) - target.dna.features["snout"] = get_consistent_feature_entry(GLOB.snouts_list) - target.dna.features["spines"] = get_consistent_feature_entry(GLOB.spines_list) - target.dna.features["tail_cat"] = get_consistent_feature_entry(GLOB.tails_list_human) // it's a lie - target.dna.features["tail_lizard"] = get_consistent_feature_entry(GLOB.tails_list_lizard) - target.dna.features["pod_hair"] = get_consistent_feature_entry(GLOB.pod_hair_list) + target.dna.features["body_markings"] = get_consistent_feature_entry(SSaccessories.body_markings_list) + target.dna.features["ears"] = get_consistent_feature_entry(SSaccessories.ears_list) + target.dna.features["frills"] = get_consistent_feature_entry(SSaccessories.frills_list) + target.dna.features["horns"] = get_consistent_feature_entry(SSaccessories.horns_list) + target.dna.features["moth_antennae"] = get_consistent_feature_entry(SSaccessories.moth_antennae_list) + target.dna.features["moth_markings"] = get_consistent_feature_entry(SSaccessories.moth_markings_list) + target.dna.features["moth_wings"] = get_consistent_feature_entry(SSaccessories.moth_wings_list) + target.dna.features["snout"] = get_consistent_feature_entry(SSaccessories.snouts_list) + target.dna.features["spines"] = get_consistent_feature_entry(SSaccessories.spines_list) + target.dna.features["tail_cat"] = get_consistent_feature_entry(SSaccessories.tails_list_human) // it's a lie + target.dna.features["tail_lizard"] = get_consistent_feature_entry(SSaccessories.tails_list_lizard) + target.dna.features["tail_monkey"] = get_consistent_feature_entry(SSaccessories.tails_list_monkey) + target.dna.features["pod_hair"] = get_consistent_feature_entry(SSaccessories.pod_hair_list) target.dna.initialize_dna(create_mutation_blocks = FALSE, randomize_features = FALSE) // UF and UI are nondeterministic, even though the features are the same some blocks will randomize slightly // In practice this doesn't matter, but this is for the sake of 100%(ish) consistency diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index b205eb2e2e217..c9f0ffe504618 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -1,12 +1,15 @@ /datum/emote/living/carbon/human mob_type_allowed_typecache = list(/mob/living/carbon/human) + /datum/emote/living/carbon/human/cry key = "cry" key_third_person = "cries" message = "cries." message_mime = "sobs silently." + audio_cooldown = 5 SECONDS emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE + vary = TRUE stat_allowed = SOFT_CRIT /datum/emote/living/carbon/human/cry/run_emote(mob/user, params, type_override, intentional) @@ -16,6 +19,11 @@ var/mob/living/carbon/human/human_user = user QDEL_IN(human_user.give_emote_overlay(/datum/bodypart_overlay/simple/emote/cry), 12.8 SECONDS) +/datum/emote/living/carbon/human/cry/get_sound(mob/living/carbon/human/user) + if(!istype(user)) + return + return user.dna.species.get_cry_sound(user) + /datum/emote/living/carbon/human/dap key = "dap" key_third_person = "daps" @@ -39,6 +47,36 @@ return ..() return FALSE +/datum/emote/living/carbon/human/cough + key = "cough" + key_third_person = "coughs" + message = "coughs!" + message_mime = "acts out an exaggerated cough!" + vary = TRUE + audio_cooldown = 5 SECONDS + emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT + +/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional) + return !HAS_TRAIT(user, TRAIT_SOOTHED_THROAT) && ..() + +/datum/emote/living/carbon/human/cough/get_sound(mob/living/carbon/human/user) + if(!istype(user)) + return + return user.dna.species.get_cough_sound(user) +/datum/emote/living/carbon/human/sneeze + key = "sneeze" + key_third_person = "sneezes" + message = "sneezes." + audio_cooldown = 5 SECONDS + message_mime = "acts out an exaggerated silent sneeze." + vary = TRUE + emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/sneeze/get_sound(mob/living/carbon/human/user) + if(!istype(user)) + return + return user.dna.species.get_sneeze_sound(user) + /datum/emote/living/carbon/human/glasses/run_emote(mob/user, params, type_override, intentional) . = ..() var/image/emote_animation = image('icons/mob/human/emote_visuals.dmi', user, "glasses") diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 1a1827e198fe6..4fe60084c0e93 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -59,7 +59,7 @@ . += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands." else if(GET_ATOM_BLOOD_DNA_LENGTH(src)) if(num_hands) - . += span_warning("[t_He] [t_has] [num_hands > 1 ? "" : "a"] blood-stained hand[num_hands > 1 ? "s" : ""]!") + . += span_warning("[t_He] [t_has] [num_hands > 1 ? "" : "a "]blood-stained hand[num_hands > 1 ? "s" : ""]!") //handcuffed? if(handcuffed) @@ -321,7 +321,7 @@ if(CONSCIOUS) if(HAS_TRAIT(src, TRAIT_DUMB)) msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n" - if(get_organ_by_type(/obj/item/organ/internal/brain)) + if(get_organ_by_type(/obj/item/organ/internal/brain) && isnull(ai_controller)) if(!key) msg += "[span_deadsay("[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely.")]\n" else if(!client) @@ -352,18 +352,20 @@ . += trait_exam if(isliving(user)) - var/mob/living/morbid_weirdo = user - if(HAS_MIND_TRAIT(morbid_weirdo, TRAIT_MORBID)) + var/mob/living/privacy_invader = user + if(HAS_MIND_TRAIT(privacy_invader, TRAIT_MORBID)) if(HAS_TRAIT(src, TRAIT_DISSECTED)) msg += "[span_notice("[t_He] appears to have been dissected. Useless for examination... for now.")]\n" if(HAS_TRAIT(src, TRAIT_SURGICALLY_ANALYZED)) msg += "[span_notice("A skilled hand has mapped this one's internal intricacies. It will be far easier to perform future experimentations upon [t_him]. Exquisite.")]\n" + if(HAS_MIND_TRAIT(privacy_invader, TRAIT_EXAMINE_FITNESS)) + . += compare_fitness(user) var/perpname = get_face_name(get_id_name("")) if(perpname && (HAS_TRAIT(user, TRAIT_SECURITY_HUD) || HAS_TRAIT(user, TRAIT_MEDICAL_HUD))) var/datum/record/crew/target_record = find_record(perpname) if(target_record) - . += "Rank: [target_record.rank]\n\[Front photo\]\[Side photo\]" + . += "Rank: [target_record.rank]\n\[Front photo\]\[Side photo\]" if(HAS_TRAIT(user, TRAIT_MEDICAL_HUD)) var/cyberimp_detect for(var/obj/item/organ/internal/cyberimp/cyberimp in organs) @@ -394,17 +396,17 @@ if(target_record.security_note) security_note = target_record.security_note if(ishuman(user)) - . += "Criminal status: \[[wanted_status]\]" + . += "Criminal status: \[[wanted_status]\]" else - . += "Criminal status: [wanted_status]" - . += "Important Notes: [security_note]" - . += "Security record: \[View\]" + . += "Criminal status: [wanted_status]" + . += "Important Notes: [security_note]" + . += "Security record: \[View\]" if(ishuman(user)) . += jointext(list("\[Add citation\]", "\[Add crime\]", "\[Add note\]"), "") - else if(isobserver(user)) - . += span_info("Quirks: [get_quirk_string(FALSE, CAT_QUIRK_ALL)]") + if(isobserver(user)) + . += span_info("\nQuirks: [get_quirk_string(FALSE, CAT_QUIRK_ALL)]") . += "" SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE, user, .) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 9f1ea960fe5c1..9d3d8c2d5a81b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -87,11 +87,6 @@ /mob/living/carbon/human/Topic(href, href_list) - if(href_list["item"]) //canUseTopic check for this is handled by mob/Topic() - var/slot = text2num(href_list["item"]) - if(check_obscured_slots(TRUE) & slot) - to_chat(usr, span_warning("You can't reach that! Something is covering it.")) - return ///////HUDs/////// if(href_list["hud"]) @@ -584,7 +579,7 @@ // Check and wash stuff that can be covered var/obscured = check_obscured_slots() - if(w_uniform && !(obscured & ITEM_SLOT_ICLOTHING) && w_uniform.wash(clean_types)) + if(!(obscured & ITEM_SLOT_ICLOTHING) && w_uniform?.wash(clean_types)) update_worn_undersuit() . = TRUE @@ -728,6 +723,10 @@ /mob/living/carbon/human/vv_edit_var(var_name, var_value) if(var_name == NAMEOF(src, mob_height)) + var/static/list/monkey_heights = list( + MONKEY_HEIGHT_DWARF, + MONKEY_HEIGHT_MEDIUM, + ) var/static/list/heights = list( HUMAN_HEIGHT_SHORTEST, HUMAN_HEIGHT_SHORT, @@ -736,7 +735,10 @@ HUMAN_HEIGHT_TALLER, HUMAN_HEIGHT_TALLEST ) - if(!(var_value in heights)) + if(ismonkey(src)) + if(!(var_value in monkey_heights)) + return + else if(!(var_value in heights)) return . = set_mob_height(var_value) @@ -813,7 +815,7 @@ if(href_list[VV_HK_SET_SPECIES]) if(!check_rights(R_SPAWN)) return - var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list + var/result = input(usr, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc)) if(result) var/newtype = GLOB.species_list[result] admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src] to [result]") @@ -913,7 +915,7 @@ var/carrydelay = 5 SECONDS //if you have latex you are faster at grabbing var/skills_space - var/fitness_level = mind.get_skill_level(/datum/skill/fitness) - 1 + var/fitness_level = mind.get_skill_level(/datum/skill/athletics) - 1 if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY)) carrydelay -= 2 SECONDS else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY)) @@ -1017,7 +1019,7 @@ /mob/living/carbon/human/species/set_species(datum/species/mrace, icon_update, pref_load) . = ..() if(use_random_name) - fully_replace_character_name(real_name, dna.species.random_name()) + fully_replace_character_name(real_name, generate_random_mob_name()) /mob/living/carbon/human/species/abductor race = /datum/species/abductor diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index ef44318676e77..e2ed47300cc14 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -75,15 +75,15 @@ return "Unknown" //Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when Fluacided or when updating a human's name variable -/mob/living/carbon/human/proc/get_face_name(if_no_face="Unknown") +/mob/living/carbon/human/proc/get_face_name(if_no_face = "Unknown") if(HAS_TRAIT(src, TRAIT_UNKNOWN)) return if_no_face //We're Unknown, no face information for you - if( wear_mask && (wear_mask.flags_inv&HIDEFACE) ) //Wearing a mask which hides our face, use id-name if possible + for(var/obj/item/worn_item in get_equipped_items()) + if(!(worn_item.flags_inv & HIDEFACE)) + continue return if_no_face - if( head && (head.flags_inv&HIDEFACE) ) - return if_no_face //Likewise for hats - var/obj/item/bodypart/O = get_bodypart(BODY_ZONE_HEAD) - if( !O || (HAS_TRAIT(src, TRAIT_DISFIGURED)) || (O.brutestate+O.burnstate)>2 || !real_name || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN)) //disfigured. use id-name if possible + var/obj/item/bodypart/head = get_bodypart(BODY_ZONE_HEAD) + if(isnull(head) || (HAS_TRAIT(src, TRAIT_DISFIGURED)) || (head.brutestate + head.burnstate) > 2 || !real_name || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN)) //disfigured. use id-name if possible return if_no_face return real_name @@ -259,7 +259,7 @@ if (preference.is_randomizable()) preference.apply_to_human(src, preference.create_random_value(preferences)) - fully_replace_character_name(real_name, dna.species.random_name()) + fully_replace_character_name(real_name, generate_random_mob_name()) /** * Setter for mob height @@ -271,8 +271,10 @@ /mob/living/carbon/human/proc/set_mob_height(new_height) if(mob_height == new_height) return FALSE - if(new_height == HUMAN_HEIGHT_DWARF) - CRASH("Don't set height to dwarf height directly, use dwarf trait") + if(new_height == HUMAN_HEIGHT_DWARF || new_height == MONKEY_HEIGHT_DWARF) + CRASH("Don't set height to dwarf height directly, use dwarf trait instead.") + if(new_height == MONKEY_HEIGHT_MEDIUM) + CRASH("Don't set height to monkey height directly, use monkified gene/species instead.") mob_height = new_height regenerate_icons() @@ -287,7 +289,13 @@ */ /mob/living/carbon/human/proc/get_mob_height() if(HAS_TRAIT(src, TRAIT_DWARF)) - return HUMAN_HEIGHT_DWARF + if(ismonkey(src)) + return MONKEY_HEIGHT_DWARF + else + return HUMAN_HEIGHT_DWARF + + else if(ismonkey(src)) + return MONKEY_HEIGHT_MEDIUM return mob_height @@ -320,3 +328,31 @@ clone.domutcheck() return clone + +/mob/living/carbon/human/calculate_fitness() + var/fitness_modifier = 1 + if (HAS_TRAIT(src, TRAIT_HULK)) + fitness_modifier *= 2 + if (HAS_TRAIT(src, TRAIT_STRENGTH)) + fitness_modifier *= 1.5 + if (HAS_TRAIT(src, TRAIT_EASILY_WOUNDED)) + fitness_modifier /= 2 + if (HAS_TRAIT(src, TRAIT_GAMER)) + fitness_modifier /= 1.5 + if (HAS_TRAIT(src, TRAIT_GRABWEAKNESS)) + fitness_modifier /= 1.5 + + var/athletics_level = mind?.get_skill_level(/datum/skill/athletics) || 1 + + var/min_damage = 0 + var/max_damage = 0 + for (var/body_zone in GLOB.limb_zones) + var/obj/item/bodypart/part = get_bodypart(body_zone) + if (isnull(part) || part.unarmed_damage_high <= 0 || HAS_TRAIT(part, TRAIT_PARALYSIS)) + continue + min_damage += part.unarmed_damage_low + max_damage += part.unarmed_damage_high + + var/damage = ((min_damage / 4) + (max_damage / 4)) / 2 // We expect you to have 4 functional limbs- if you have fewer you're probably not going to be so good at lifting + + return ceil(damage * (ceil(athletics_level / 2)) * fitness_modifier * maxHealth) diff --git a/code/modules/mob/living/carbon/human/human_stripping.dm b/code/modules/mob/living/carbon/human/human_stripping.dm index 47b4b54d1bc5d..81300c1f9b4c8 100644 --- a/code/modules/mob/living/carbon/human/human_stripping.dm +++ b/code/modules/mob/living/carbon/human/human_stripping.dm @@ -51,7 +51,7 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list( return null var/list/actions = list() - if(jumpsuit.has_sensor) + if(jumpsuit.has_sensor == HAS_SENSORS) actions += "adjust_sensor" if(jumpsuit.can_adjust) actions += "adjust_jumpsuit" @@ -88,7 +88,7 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list( mob_source.update_body() /datum/strippable_item/mob_item_slot/jumpsuit/proc/do_adjust_sensor(atom/source, mob/user, obj/item/clothing/under/jumpsuit) - if(!jumpsuit.has_sensor) + if(jumpsuit.has_sensor != HAS_SENSORS) return var/static/list/sensor_mode_text_to_num = list( @@ -220,7 +220,7 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list( source.log_message("is being pickpocketed of [item] by [key_name(user)] ([pocket_side])", LOG_VICTIM, color="orange", log_globally=FALSE) item.add_fingerprint(src) - var/result = start_unequip_mob(item, source, user, POCKET_STRIP_DELAY) + var/result = start_unequip_mob(item, source, user, strip_delay = POCKET_STRIP_DELAY, hidden = TRUE) if (!result) warn_owner(source) diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 290fe4ce03b94..bd320079b65d5 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -54,7 +54,7 @@ There are several things that need to be remembered: update_worn_id() update_worn_glasses() update_worn_gloves() - update_inv_ears() + update_worn_ears() update_worn_shoes() update_suit_storage() update_worn_mask() @@ -70,10 +70,15 @@ There are several things that need to be remembered: //damage overlays update_damage_overlays() +/mob/living/carbon/human/update_obscured_slots(obscured_flags) + ..() + if(obscured_flags & HIDEFACE) + sec_hud_set_security_status() + /* --------------------------------------- */ //vvvvvv UPDATE_INV PROCS vvvvvv -/mob/living/carbon/human/update_worn_undersuit() +/mob/living/carbon/human/update_worn_undersuit(update_obscured = TRUE) remove_overlay(UNIFORM_LAYER) if(client && hud_used) @@ -84,6 +89,9 @@ There are several things that need to be remembered: var/obj/item/clothing/under/uniform = w_uniform update_hud_uniform(uniform) + if(update_obscured) + update_obscured_slots(uniform.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_ICLOTHING) return @@ -102,9 +110,7 @@ There are several things that need to be remembered: var/icon_file var/woman //BEGIN SPECIES HANDLING - if((bodyshape & BODYSHAPE_MONKEY) && (uniform.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) - icon_file = MONKEY_UNIFORM_FILE - else if((bodyshape & BODYSHAPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) + if((bodyshape & BODYSHAPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) icon_file = DIGITIGRADE_UNIFORM_FILE //Female sprites have lower priority than digitigrade sprites else if(dna.species.sexes && (bodyshape & BODYSHAPE_HUMANOID) && physique == FEMALE && !(uniform.female_sprite_flags & NO_FEMALE_UNIFORM)) //Agggggggghhhhh @@ -131,7 +137,7 @@ There are several things that need to be remembered: update_mutant_bodyparts() -/mob/living/carbon/human/update_worn_id() +/mob/living/carbon/human/update_worn_id(update_obscured = TRUE) remove_overlay(ID_LAYER) if(client && hud_used) @@ -143,6 +149,10 @@ There are several things that need to be remembered: if(wear_id) var/obj/item/worn_item = wear_id update_hud_id(worn_item) + + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + var/icon_file = 'icons/mob/clothing/id.dmi' id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = icon_file) @@ -157,7 +167,7 @@ There are several things that need to be remembered: apply_overlay(ID_LAYER) -/mob/living/carbon/human/update_worn_gloves() +/mob/living/carbon/human/update_worn_gloves(update_obscured = TRUE) remove_overlay(GLOVES_LAYER) if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_GLOVES) + 1]) @@ -165,21 +175,26 @@ There are several things that need to be remembered: inv.update_icon() //Bloody hands begin - var/mutable_appearance/bloody_lefthand_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands_left", -GLOVES_LAYER) - var/mutable_appearance/bloody_righthand_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands_right", -GLOVES_LAYER) - cut_overlay(bloody_lefthand_overlay) - cut_overlay(bloody_righthand_overlay) - if(!gloves && blood_in_hands && (num_hands > 0)) - if(has_left_hand(check_disabled = FALSE)) - add_overlay(bloody_lefthand_overlay) - if(has_right_hand(check_disabled = FALSE)) - add_overlay(bloody_righthand_overlay) + if(isnull(gloves)) + if(blood_in_hands && num_hands > 0) + // When byond gives us filters that respect dirs we can just use an alpha mask for this but until then, two icons weeeee + var/mutable_appearance/hands_combined = mutable_appearance(layer = -GLOVES_LAYER, appearance_flags = KEEP_TOGETHER) + if(has_left_hand(check_disabled = FALSE)) + hands_combined.overlays += mutable_appearance('icons/effects/blood.dmi', "bloodyhands_left") + if(has_right_hand(check_disabled = FALSE)) + hands_combined.overlays += mutable_appearance('icons/effects/blood.dmi', "bloodyhands_right") + overlays_standing[GLOVES_LAYER] = hands_combined + apply_overlay(GLOVES_LAYER) + return // Bloody hands end if(gloves) var/obj/item/worn_item = gloves update_hud_gloves(worn_item) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_GLOVES) return @@ -199,7 +214,7 @@ There are several things that need to be remembered: apply_overlay(GLOVES_LAYER) -/mob/living/carbon/human/update_worn_glasses() +/mob/living/carbon/human/update_worn_glasses(update_obscured = TRUE) remove_overlay(GLASSES_LAYER) var/obj/item/bodypart/head/my_head = get_bodypart(BODY_ZONE_HEAD) @@ -214,6 +229,9 @@ There are several things that need to be remembered: var/obj/item/worn_item = glasses update_hud_glasses(worn_item) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_EYES) return @@ -225,7 +243,7 @@ There are several things that need to be remembered: apply_overlay(GLASSES_LAYER) -/mob/living/carbon/human/update_inv_ears() +/mob/living/carbon/human/update_worn_ears(update_obscured = TRUE) remove_overlay(EARS_LAYER) var/obj/item/bodypart/head/my_head = get_bodypart(BODY_ZONE_HEAD) @@ -240,6 +258,9 @@ There are several things that need to be remembered: var/obj/item/worn_item = ears update_hud_ears(worn_item) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_EARS) return @@ -250,7 +271,7 @@ There are several things that need to be remembered: overlays_standing[EARS_LAYER] = ears_overlay apply_overlay(EARS_LAYER) -/mob/living/carbon/human/update_worn_neck() +/mob/living/carbon/human/update_worn_neck(update_obscured = TRUE) remove_overlay(NECK_LAYER) if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_NECK) + 1]) @@ -261,6 +282,9 @@ There are several things that need to be remembered: var/obj/item/worn_item = wear_neck update_hud_neck(wear_neck) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_NECK) return @@ -273,7 +297,7 @@ There are several things that need to be remembered: apply_overlay(NECK_LAYER) -/mob/living/carbon/human/update_worn_shoes() +/mob/living/carbon/human/update_worn_shoes(update_obscured = TRUE) remove_overlay(SHOES_LAYER) if(num_legs < 2) @@ -287,6 +311,9 @@ There are several things that need to be remembered: var/obj/item/worn_item = shoes update_hud_shoes(worn_item) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_FEET) return @@ -313,7 +340,7 @@ There are several things that need to be remembered: update_body_parts() -/mob/living/carbon/human/update_suit_storage() +/mob/living/carbon/human/update_suit_storage(update_obscured = TRUE) remove_overlay(SUIT_STORE_LAYER) if(client && hud_used) @@ -324,6 +351,9 @@ There are several things that need to be remembered: var/obj/item/worn_item = s_store update_hud_s_store(worn_item) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_SUITSTORE) return @@ -333,7 +363,7 @@ There are several things that need to be remembered: overlays_standing[SUIT_STORE_LAYER] = s_store_overlay apply_overlay(SUIT_STORE_LAYER) -/mob/living/carbon/human/update_worn_head() +/mob/living/carbon/human/update_worn_head(update_obscured = TRUE) remove_overlay(HEAD_LAYER) if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_BACK) + 1]) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_HEAD) + 1] @@ -343,6 +373,9 @@ There are several things that need to be remembered: var/obj/item/worn_item = head update_hud_head(worn_item) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_HEAD) return @@ -353,10 +386,9 @@ There are several things that need to be remembered: my_head?.worn_head_offset?.apply_offset(head_overlay) overlays_standing[HEAD_LAYER] = head_overlay - update_mutant_bodyparts() apply_overlay(HEAD_LAYER) -/mob/living/carbon/human/update_worn_belt() +/mob/living/carbon/human/update_worn_belt(update_obscured = TRUE) remove_overlay(BELT_LAYER) if(client && hud_used) @@ -367,6 +399,9 @@ There are several things that need to be remembered: var/obj/item/worn_item = belt update_hud_belt(worn_item) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_BELT) return @@ -379,7 +414,7 @@ There are several things that need to be remembered: apply_overlay(BELT_LAYER) -/mob/living/carbon/human/update_worn_oversuit() +/mob/living/carbon/human/update_worn_oversuit(update_obscured = TRUE) remove_overlay(SUIT_LAYER) if(client && hud_used) @@ -389,6 +424,10 @@ There are several things that need to be remembered: if(wear_suit) var/obj/item/worn_item = wear_suit update_hud_wear_suit(worn_item) + + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + var/icon_file = DEFAULT_SUIT_FILE var/mutable_appearance/suit_overlay = wear_suit.build_worn_icon(default_layer = SUIT_LAYER, default_icon_file = icon_file) @@ -422,7 +461,7 @@ There are several things that need to be remembered: client.screen += r_store update_observer_view(r_store) -/mob/living/carbon/human/update_worn_mask() +/mob/living/carbon/human/update_worn_mask(update_obscured = TRUE) remove_overlay(FACEMASK_LAYER) var/obj/item/bodypart/head/my_head = get_bodypart(BODY_ZONE_HEAD) @@ -437,6 +476,9 @@ There are several things that need to be remembered: var/obj/item/worn_item = wear_mask update_hud_wear_mask(worn_item) + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_MASK) return @@ -449,7 +491,7 @@ There are several things that need to be remembered: apply_overlay(FACEMASK_LAYER) update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout -/mob/living/carbon/human/update_worn_back() +/mob/living/carbon/human/update_worn_back(update_obscured = TRUE) remove_overlay(BACK_LAYER) if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_BACK) + 1]) @@ -460,6 +502,10 @@ There are several things that need to be remembered: var/obj/item/worn_item = back var/mutable_appearance/back_overlay update_hud_back(worn_item) + + if(update_obscured) + update_obscured_slots(worn_item.flags_inv) + var/icon_file = 'icons/mob/clothing/back.dmi' back_overlay = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = icon_file) @@ -634,24 +680,14 @@ generate/load female uniform sprites matching all previously decided variables female_uniform = NO_FEMALE_UNIFORM, override_state = null, override_file = null, - use_height_offset = TRUE, ) //Find a valid icon_state from variables+arguments - var/t_state - if(override_state) - t_state = override_state - else - t_state = !isinhands ? (worn_icon_state ? worn_icon_state : icon_state) : (inhand_icon_state ? inhand_icon_state : icon_state) - + var/t_state = override_state || (isinhands ? inhand_icon_state : worn_icon_state) || icon_state //Find a valid icon file from variables+arguments - var/file2use - if(override_file) - file2use = override_file - else - file2use = !isinhands ? (worn_icon ? worn_icon : default_icon_file) : default_icon_file + var/file2use = override_file || (isinhands ? null : worn_icon) || default_icon_file //Find a valid layer from variables+arguments - var/layer2use = alternate_worn_layer ? alternate_worn_layer : default_layer + var/layer2use = alternate_worn_layer || default_layer var/mutable_appearance/standing if(female_uniform) @@ -662,27 +698,8 @@ generate/load female uniform sprites matching all previously decided variables //Get the overlays for this item when it's being worn //eg: ammo counters, primed grenade flashes, etc. var/list/worn_overlays = worn_overlays(standing, isinhands, file2use) - if(worn_overlays?.len) - if(!isinhands && default_layer && ishuman(loc) && use_height_offset) - var/mob/living/carbon/human/human_loc = loc - if(human_loc.get_mob_height() != HUMAN_HEIGHT_MEDIUM) - var/string_form_layer = num2text(default_layer) - var/offset_amount = GLOB.layers_to_offset[string_form_layer] - if(isnull(offset_amount)) - // Worn overlays don't get batched in with standing overlays because they are overlay overlays - // ...So we need to apply human height here as well - for(var/mutable_appearance/applied_appearance as anything in worn_overlays) - if(isnull(applied_appearance)) - continue - human_loc.apply_height_filters(applied_appearance) - - else - for(var/mutable_appearance/applied_appearance in worn_overlays) - if(isnull(applied_appearance)) - continue - human_loc.apply_height_offsets(applied_appearance, offset_amount) - - standing.overlays.Add(worn_overlays) + if(length(worn_overlays)) + standing.overlays += worn_overlays standing = center_image(standing, isinhands ? inhand_x_dimension : worn_x_dimension, isinhands ? inhand_y_dimension : worn_y_dimension) @@ -709,9 +726,6 @@ generate/load female uniform sprites matching all previously decided variables .[2] = offsets["y"] else .[2] = worn_y_offset - if(ishuman(loc) && slot_flags != ITEM_SLOT_FEET) /// we adjust the human body for high given by body parts, execpt shoes, because they are always on the bottom - var/mob/living/carbon/human/human_holder = loc - .[2] += human_holder.get_top_offset() //Can't think of a better way to do this, sadly /mob/proc/get_item_offsets_for_index(i) @@ -764,23 +778,19 @@ generate/load female uniform sprites matching all previously decided variables var/raw_applied = overlays_standing[cache_index] var/string_form_index = num2text(cache_index) - var/offset_amount = GLOB.layers_to_offset[string_form_index] - if(isnull(offset_amount)) + var/offset_type = GLOB.layers_to_offset[string_form_index] + if(isnull(offset_type)) if(islist(raw_applied)) - for(var/mutable_appearance/applied_appearance as anything in raw_applied) - if(isnull(applied_appearance)) - continue + for(var/image/applied_appearance in raw_applied) apply_height_filters(applied_appearance) - else if(!isnull(raw_applied)) + else if(isimage(raw_applied)) apply_height_filters(raw_applied) else if(islist(raw_applied)) - for(var/mutable_appearance/applied_appearance as anything in raw_applied) - if(isnull(applied_appearance)) - continue - apply_height_offsets(applied_appearance, offset_amount) - else if(!isnull(raw_applied)) - apply_height_offsets(raw_applied, offset_amount) + for(var/image/applied_appearance in raw_applied) + apply_height_offsets(applied_appearance, offset_type) + else if(isimage(raw_applied)) + apply_height_offsets(raw_applied, offset_type) return ..() @@ -790,7 +800,7 @@ generate/load female uniform sprites matching all previously decided variables * upper_torso is to specify whether the appearance is locate in the upper half of the mob rather than the lower half, * higher up things (hats for example) need to be offset more due to the location of the filter displacement */ -/mob/living/carbon/human/proc/apply_height_offsets(mutable_appearance/appearance, upper_torso) +/mob/living/carbon/human/proc/apply_height_offsets(image/appearance, upper_torso) var/height_to_use = num2text(get_mob_height()) var/final_offset = 0 switch(upper_torso) @@ -807,7 +817,7 @@ generate/load female uniform sprites matching all previously decided variables /** * Applies a filter to an appearance according to mob height */ -/mob/living/carbon/human/proc/apply_height_filters(mutable_appearance/appearance) +/mob/living/carbon/human/proc/apply_height_filters(image/appearance) var/static/icon/cut_torso_mask = icon('icons/effects/cut.dmi', "Cut1") var/static/icon/cut_legs_mask = icon('icons/effects/cut.dmi', "Cut2") var/static/icon/lenghten_torso_mask = icon('icons/effects/cut.dmi', "Cut3") @@ -820,26 +830,103 @@ generate/load female uniform sprites matching all previously decided variables "Lenghten_Torso", "Gnome_Cut_Torso", "Gnome_Cut_Legs", + "Monkey_Torso", + "Monkey_Legs", + "Monkey_Gnome_Cut_Torso", + "Monkey_Gnome_Cut_Legs", )) switch(get_mob_height()) // Don't set this one directly, use TRAIT_DWARF + if(MONKEY_HEIGHT_DWARF) + appearance.add_filters(list( + list( + "name" = "Monkey_Gnome_Cut_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 3), + ), + list( + "name" = "Monkey_Gnome_Cut_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 4), + ), + )) + if(MONKEY_HEIGHT_MEDIUM) + appearance.add_filters(list( + list( + "name" = "Monkey_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 2), + ), + list( + "name" = "Monkey_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 4), + ), + )) + // Don't set this one directly, use TRAIT_DWARF if(HUMAN_HEIGHT_DWARF) - appearance.add_filter("Gnome_Cut_Torso", 1, displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 2)) - appearance.add_filter("Gnome_Cut_Legs", 1, displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 3)) + appearance.add_filters(list( + list( + "name" = "Gnome_Cut_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 2), + ), + list( + "name" = "Gnome_Cut_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 3), + ), + )) if(HUMAN_HEIGHT_SHORTEST) - appearance.add_filter("Cut_Torso", 1, displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 1)) - appearance.add_filter("Cut_Legs", 1, displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 1)) + appearance.add_filters(list( + list( + "name" = "Cut_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 1), + ), + list( + "name" = "Cut_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 1), + ), + )) if(HUMAN_HEIGHT_SHORT) appearance.add_filter("Cut_Legs", 1, displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 1)) if(HUMAN_HEIGHT_TALL) appearance.add_filter("Lenghten_Legs", 1, displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 1)) if(HUMAN_HEIGHT_TALLER) - appearance.add_filter("Lenghten_Torso", 1, displacement_map_filter(lenghten_torso_mask, x = 0, y = 0, size = 1)) - appearance.add_filter("Lenghten_Legs", 1, displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 1)) + appearance.add_filters(list( + list( + "name" = "Lenghten_Torso", + "priority" = 1, + "params" = displacement_map_filter(lenghten_torso_mask, x = 0, y = 0, size = 1), + ), + list( + "name" = "Lenghten_Legs", + "priority" = 1, + "params" = displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 1), + ), + )) if(HUMAN_HEIGHT_TALLEST) - appearance.add_filter("Lenghten_Torso", 1, displacement_map_filter(lenghten_torso_mask, x = 0, y = 0, size = 1)) - appearance.add_filter("Lenghten_Legs", 1, displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 2)) + appearance.add_filters(list( + list( + "name" = "Lenghten_Torso", + "priority" = 1, + "params" = displacement_map_filter(lenghten_torso_mask, x = 0, y = 0, size = 1), + ), + list( + "name" = "Lenghten_Legs", + "priority" = 1, + "params" = displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 2), + ), + )) + + // Kinda gross but because many humans overlays do not use KEEP_TOGETHER we need to manually propogate the filter + // Otherwise overlays, such as worn overlays on icons, won't have the filter "applied", and the effect kinda breaks + if(!(appearance.appearance_flags & KEEP_TOGETHER)) + for(var/image/overlay in list() + appearance.underlays + appearance.overlays) + apply_height_filters(overlay) return appearance diff --git a/code/modules/mob/living/carbon/human/init_signals.dm b/code/modules/mob/living/carbon/human/init_signals.dm index 6e16781a59ee0..dc5ce972105f6 100644 --- a/code/modules/mob/living/carbon/human/init_signals.dm +++ b/code/modules/mob/living/carbon/human/init_signals.dm @@ -8,6 +8,8 @@ RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_FAT), SIGNAL_REMOVETRAIT(TRAIT_FAT)), PROC_REF(on_fat)) RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_NOHUNGER), SIGNAL_REMOVETRAIT(TRAIT_NOHUNGER)), PROC_REF(on_nohunger)) + RegisterSignal(src, COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED, PROC_REF(check_pocket_weght)) + /// Gaining or losing [TRAIT_UNKNOWN] updates our name and our sechud /mob/living/carbon/human/proc/on_unknown_trait(datum/source) SIGNAL_HANDLER @@ -63,3 +65,19 @@ else hud_used?.hunger?.update_appearance() mob_mood?.update_nutrition_moodlets() + +/// Signal proc for [COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED] to check if an item is suddenly too heavy for our pockets +/mob/living/carbon/human/proc/check_pocket_weght(datum/source, obj/item/changed, old_w_class, new_w_class) + SIGNAL_HANDLER + if(changed != r_store && changed != l_store) + return + if(new_w_class <= POCKET_WEIGHT_CLASS) + return + if(!dropItemToGround(changed, force = TRUE)) + return + visible_message( + span_warning("[changed] falls out of [src]'s pockets!"), + span_warning("[changed] falls out of your pockets!"), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + playsound(src, SFX_RUSTLE, 50, TRUE, -5, frequency = 0.8) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index aede1e69a7289..32ab7ca1b900a 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -70,9 +70,6 @@ return ..() -/mob/living/carbon/human/get_all_worn_items() - . = get_head_slots() | get_body_slots() - /mob/living/carbon/human/proc/get_body_slots() return list( back, @@ -137,15 +134,13 @@ if(ears) return ears = equipping - update_inv_ears() + update_worn_ears() if(ITEM_SLOT_EYES) if(glasses) return glasses = equipping if(glasses.glass_colour_type) update_glasses_color(glasses, 1) - if(glasses.tint) - update_tint() if(glasses.vision_flags || glasses.invis_override || glasses.invis_view || !isnull(glasses.lighting_cutoff)) update_sight() update_worn_glasses() @@ -165,8 +160,6 @@ wear_suit = equipping - if(equipping.flags_inv & HIDEJUMPSUIT) - update_worn_undersuit() if(wear_suit.breakouttime) //when equipping a straightjacket ADD_TRAIT(src, TRAIT_RESTRAINED, SUIT_TRAIT) stop_pulling() //can't pull if restrained @@ -209,6 +202,7 @@ . = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should. if(!. || !I) return + var/not_handled = FALSE //if we actually unequipped an item, this is because we dont want to run this proc twice, once for carbons and once for humans if(I == wear_suit) if(s_store && invdrop) dropItemToGround(s_store, TRUE) //It makes no sense for your suit storage to stay on you if you drop your suit. @@ -218,8 +212,6 @@ update_mob_action_buttons() //certain action buttons may be usable again. wear_suit = null if(!QDELETED(src)) //no need to update we're getting deleted anyway - if(I.flags_inv & HIDEJUMPSUIT) - update_worn_undersuit() update_worn_oversuit() else if(I == w_uniform) w_uniform = null @@ -244,8 +236,6 @@ var/obj/item/clothing/glasses/G = I if(G.glass_colour_type) update_glasses_color(G, 0) - if(G.tint) - update_tint() if(G.vision_flags || G.invis_override || G.invis_view || !isnull(G.lighting_cutoff)) update_sight() if(!QDELETED(src)) @@ -253,7 +243,7 @@ else if(I == ears) ears = null if(!QDELETED(src)) - update_inv_ears() + update_worn_ears() else if(I == shoes) shoes = null if(!QDELETED(src)) @@ -279,12 +269,19 @@ s_store = null if(!QDELETED(src)) update_suit_storage() - update_equipment_speed_mods() + else + not_handled = TRUE // Send a signal for when we unequip an item that used to cover our feet/shoes. Used for bloody feet if((I.body_parts_covered & FEET) || (I.flags_inv | I.transparent_protection) & HIDESHOES) SEND_SIGNAL(src, COMSIG_CARBON_UNEQUIP_SHOECOVER, I, force, newloc, no_move, invdrop, silent) + if(not_handled) + return + + update_equipment_speed_mods() + update_obscured_slots(I.flags_inv) + /mob/living/carbon/human/toggle_internals(obj/item/tank, is_external = FALSE) // Just close the tank if it's the one the mob already has open. var/obj/item/existing_tank = is_external ? external : internal @@ -296,8 +293,8 @@ // Use mask in absence of tube. if(isclothing(wear_mask) && ((wear_mask.visor_flags & MASKINTERNALS) || (wear_mask.clothing_flags & MASKINTERNALS))) // Adjust dishevelled breathing mask back onto face. - if (wear_mask.mask_adjusted) - wear_mask.adjustmask(src) + if (wear_mask.up) + wear_mask.adjust_visor(src) return toggle_open_internals(tank, is_external) // Use helmet in absence of tube or valid mask. if(can_breathe_helmet()) @@ -317,30 +314,6 @@ /mob/living/carbon/human/toggle_externals(obj/item/tank) return toggle_internals(tank, TRUE) -/mob/living/carbon/human/wear_mask_update(obj/item/I, toggle_off = 1) - if((I.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || (initial(I.flags_inv) & (HIDEHAIR|HIDEFACIALHAIR))) - update_body_parts() - // Close internal air tank if mask was the only breathing apparatus. - if(invalid_internals()) - cutoff_internals() - if(I.flags_inv & HIDEEYES) - update_worn_glasses() - sec_hud_set_security_status() - ..() - -/mob/living/carbon/human/head_update(obj/item/I, forced) - if((I.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || forced) - update_body_parts() - // Close internal air tank if helmet was the only breathing apparatus. - if (invalid_internals()) - cutoff_internals() - if(I.flags_inv & HIDEEYES || forced) - update_worn_glasses() - if(I.flags_inv & HIDEEARS || forced) - update_body() - sec_hud_set_security_status() - ..() - /mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE) var/datum/outfit/O = null @@ -374,10 +347,10 @@ //delete all equipment without dropping anything /mob/living/carbon/human/proc/delete_equipment() - for(var/slot in get_all_worn_items())//order matters, dependant slots go first + for(var/slot in get_equipped_items(include_pockets = TRUE))//order matters, dependant slots go first qdel(slot) - for(var/obj/item/I in held_items) - qdel(I) + for(var/obj/item/held_item in held_items) + qdel(held_item) /// take the most recent item out of a slot or place held item in a slot diff --git a/code/modules/mob/living/carbon/human/species_types/abominations.dm b/code/modules/mob/living/carbon/human/species_types/abominations.dm deleted file mode 100644 index 43ca71311c226..0000000000000 --- a/code/modules/mob/living/carbon/human/species_types/abominations.dm +++ /dev/null @@ -1,51 +0,0 @@ -/// These won't appear normally in games, they are meant to for debuging the adjustment of limbs based on the height of a humans bodyparts. -/datum/species/human/tallboy - name = "\improper Tall Boy" - id = SPECIES_TALLBOY - examine_limb_id = SPECIES_HUMAN - changesource_flags = MIRROR_BADMIN | WABBAJACK - bodypart_overrides = list( - BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left, - BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right, - BODY_ZONE_HEAD = /obj/item/bodypart/head, - BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/tallboy, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/tallboy, - BODY_ZONE_CHEST = /obj/item/bodypart/chest, - ) - -/datum/species/monkey/human_legged - name = "human-legged monkey" - id = SPECIES_MONKEY_HUMAN_LEGGED - examine_limb_id = SPECIES_MONKEY - changesource_flags = MIRROR_BADMIN | WABBAJACK - bodypart_overrides = list( - BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/monkey, - BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/monkey, - BODY_ZONE_HEAD = /obj/item/bodypart/head/monkey, - BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right, - BODY_ZONE_CHEST = /obj/item/bodypart/chest/monkey, - ) - -/datum/species/monkey/monkey_freak - name = "human-armed monkey" - id = SPECIES_MONKEY_FREAK - examine_limb_id = SPECIES_MONKEY - changesource_flags = MIRROR_BADMIN | WABBAJACK - bodypart_overrides = list( - BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left, - BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right, - BODY_ZONE_HEAD = /obj/item/bodypart/head/monkey, - BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/monkey, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/monkey, - BODY_ZONE_CHEST = /obj/item/bodypart/chest, - ) - -/mob/living/carbon/human/species/monkey/humand_legged - race = /datum/species/monkey/human_legged - -/mob/living/carbon/human/species/monkey/monkey_freak - race = /datum/species/monkey/monkey_freak - -/mob/living/carbon/human/species/tallboy - race = /datum/species/human/tallboy diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index e37e7ca81447f..4c307107f153d 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -80,14 +80,6 @@ QDEL_NULL(ethereal_light) return ..() -/datum/species/ethereal/random_name(gender,unique,lastname) - if(unique) - return random_unique_ethereal_name() - - var/randname = ethereal_name() - - return randname - /datum/species/ethereal/randomize_features() var/list/features = ..() features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 731b6047a0644..1e8cf9def9463 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -50,6 +50,54 @@ features["ears"] = pick("None", "Cat") return features +/datum/species/human/felinid/get_laugh_sound(mob/living/carbon/human/felinid) + if(felinid.physique == FEMALE) + return 'sound/voice/human/womanlaugh.ogg' + return pick( + 'sound/voice/human/manlaugh1.ogg', + 'sound/voice/human/manlaugh2.ogg', + ) + + +/datum/species/human/felinid/get_cough_sound(mob/living/carbon/human/felinid) + if(felinid.physique == FEMALE) + return pick( + 'sound/voice/human/female_cough1.ogg', + 'sound/voice/human/female_cough2.ogg', + 'sound/voice/human/female_cough3.ogg', + 'sound/voice/human/female_cough4.ogg', + 'sound/voice/human/female_cough5.ogg', + 'sound/voice/human/female_cough6.ogg', + ) + return pick( + 'sound/voice/human/male_cough1.ogg', + 'sound/voice/human/male_cough2.ogg', + 'sound/voice/human/male_cough3.ogg', + 'sound/voice/human/male_cough4.ogg', + 'sound/voice/human/male_cough5.ogg', + 'sound/voice/human/male_cough6.ogg', + ) + + +/datum/species/human/felinid/get_cry_sound(mob/living/carbon/human/felinid) + if(felinid.physique == FEMALE) + return pick( + 'sound/voice/human/female_cry1.ogg', + 'sound/voice/human/female_cry2.ogg', + ) + return pick( + 'sound/voice/human/male_cry1.ogg', + 'sound/voice/human/male_cry2.ogg', + 'sound/voice/human/male_cry3.ogg', + ) + + +/datum/species/human/felinid/get_sneeze_sound(mob/living/carbon/human/felinid) + if(felinid.physique == FEMALE) + return 'sound/voice/human/female_sneeze1.ogg' + return 'sound/voice/human/male_sneeze1.ogg' + + /proc/mass_purrbation() for(var/mob in GLOB.human_list) purrbation_apply(mob) @@ -78,9 +126,6 @@ var/datum/species/human/felinid/cat_species = soon_to_be_felinid.dna.species cat_species.original_felinid = FALSE else - var/obj/item/organ/internal/ears/cat/kitty_ears = new - var/obj/item/organ/external/tail/cat/kitty_tail = new - // This removes the spines if they exist var/obj/item/organ/external/spines/current_spines = soon_to_be_felinid.get_organ_slot(ORGAN_SLOT_EXTERNAL_SPINES) if(current_spines) @@ -91,8 +136,12 @@ // Humans get converted directly to felinids, and the key is handled in on_species_gain. // Now when we get mob.dna.features[feature_key], it returns None, which is why the tail is invisible. // stored_feature_id is only set once (the first time an organ is inserted), so this should be safe. + var/obj/item/organ/internal/ears/cat/kitty_ears = new kitty_ears.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED) - kitty_tail.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED) + if(should_external_organ_apply_to(/obj/item/organ/external/tail/cat, soon_to_be_felinid)) //only give them a tail if they actually have sprites for it / are a compatible subspecies. + var/obj/item/organ/external/tail/cat/kitty_tail = new + kitty_tail.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED) + if(!silent) to_chat(soon_to_be_felinid, span_boldnotice("Something is nya~t right.")) playsound(get_turf(soon_to_be_felinid), 'sound/effects/meow1.ogg', 50, TRUE, -1) @@ -113,6 +162,8 @@ qdel(old_tail) // Locate does not work on assoc lists, so we do it by hand for(var/external_organ in target_species.external_organs) + if(!should_external_organ_apply_to(external_organ, purrbated_human)) + continue if(ispath(external_organ, /obj/item/organ/external/tail)) var/obj/item/organ/external/tail/new_tail = new external_organ() new_tail.Insert(purrbated_human, special = TRUE, movement_flags = DELETE_IF_REPLACED) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 4e860014554e8..13471b2872b98 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -51,15 +51,6 @@ BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem, ) - /// Chance that we will generate a human surname, for lore reasons - var/human_surname_chance = 3 - -/datum/species/golem/random_name(gender,unique,lastname) - var/name = pick(GLOB.golem_names) - if (prob(human_surname_chance)) - name += " [pick(GLOB.last_names)]" - return name - /datum/species/golem/get_physical_attributes() return "Golems are hardy creatures made out of stone, which are thus naturally resistant to many dangers, including asphyxiation, fire, radiation, electricity, and viruses.\ They gain special abilities depending on the type of material consumed, but they need to consume material to keep their body animated." diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index c7a181027e64e..4c575f8e48c05 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -34,6 +34,53 @@ 'sound/voice/human/femalescream_5.ogg', ) +/datum/species/human/get_cough_sound(mob/living/carbon/human/human) + if(human.physique == FEMALE) + return pick( + 'sound/voice/human/female_cough1.ogg', + 'sound/voice/human/female_cough2.ogg', + 'sound/voice/human/female_cough3.ogg', + 'sound/voice/human/female_cough4.ogg', + 'sound/voice/human/female_cough5.ogg', + 'sound/voice/human/female_cough6.ogg', + ) + return pick( + 'sound/voice/human/male_cough1.ogg', + 'sound/voice/human/male_cough2.ogg', + 'sound/voice/human/male_cough3.ogg', + 'sound/voice/human/male_cough4.ogg', + 'sound/voice/human/male_cough5.ogg', + 'sound/voice/human/male_cough6.ogg', + ) + +/datum/species/human/get_cry_sound(mob/living/carbon/human/human) + if(human.physique == FEMALE) + return pick( + 'sound/voice/human/female_cry1.ogg', + 'sound/voice/human/female_cry2.ogg', + ) + return pick( + 'sound/voice/human/male_cry1.ogg', + 'sound/voice/human/male_cry2.ogg', + 'sound/voice/human/male_cry3.ogg', + ) + + +/datum/species/human/get_sneeze_sound(mob/living/carbon/human/human) + if(human.physique == FEMALE) + return 'sound/voice/human/female_sneeze1.ogg' + return 'sound/voice/human/male_sneeze1.ogg' + +/datum/species/human/get_laugh_sound(mob/living/carbon/human/human) + if(!ishuman(human)) + return + if(human.physique == FEMALE) + return 'sound/voice/human/womanlaugh.ogg' + return pick( + 'sound/voice/human/manlaugh1.ogg', + 'sound/voice/human/manlaugh2.ogg', + ) + /datum/species/human/get_species_description() return "Humans are the dominant species in the known galaxy. \ Their kind extend from old Earth to the edges of known space." diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index a40d0d2c35391..c4aad8a0806d5 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -722,10 +722,13 @@ to_chat(telepath, span_warning("You don't see anyone to send your thought to.")) return var/mob/living/recipient = tgui_input_list(telepath, "Choose a telepathic message recipient", "Telepathy", sort_names(recipient_options)) - if(isnull(recipient)) + if(isnull(recipient) || telepath.stat == DEAD || !is_species(telepath, /datum/species/jelly/stargazer)) return var/msg = tgui_input_text(telepath, title = "Telepathy") - if(isnull(msg)) + if(isnull(msg) || telepath.stat == DEAD || !is_species(telepath, /datum/species/jelly/stargazer)) + return + if(!(recipient in oview(telepath))) + to_chat(telepath, span_warning("You can't see [recipient] anymore!")) return if(recipient.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0)) to_chat(telepath, span_warning("As you reach into [recipient]'s mind, you are stopped by a mental blockage. It seems you've been foiled.")) diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 3e20d6b1a7750..488d76cbd2136 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -47,21 +47,9 @@ /datum/species/lizard/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired) return -/datum/species/lizard/random_name(gender,unique,lastname) - if(unique) - return random_unique_lizard_name(gender) - - var/randname = lizard_name(gender) - - if(lastname) - randname += " [lastname]" - - return randname - - /datum/species/lizard/randomize_features() var/list/features = ..() - features["body_markings"] = pick(GLOB.body_markings_list) + features["body_markings"] = pick(SSaccessories.body_markings_list) return features /datum/species/lizard/get_scream_sound(mob/living/carbon/human/lizard) @@ -71,6 +59,49 @@ 'sound/voice/lizard/lizard_scream_3.ogg', ) +/datum/species/lizard/get_cough_sound(mob/living/carbon/human/lizard) + if(lizard.gender == FEMALE) + return pick( + 'sound/voice/human/female_cough1.ogg', + 'sound/voice/human/female_cough2.ogg', + 'sound/voice/human/female_cough3.ogg', + 'sound/voice/human/female_cough4.ogg', + 'sound/voice/human/female_cough5.ogg', + 'sound/voice/human/female_cough6.ogg', + ) + return pick( + 'sound/voice/human/male_cough1.ogg', + 'sound/voice/human/male_cough2.ogg', + 'sound/voice/human/male_cough3.ogg', + 'sound/voice/human/male_cough4.ogg', + 'sound/voice/human/male_cough5.ogg', + 'sound/voice/human/male_cough6.ogg', + ) + + +/datum/species/lizard/get_cry_sound(mob/living/carbon/human/lizard) + if(lizard.gender == FEMALE) + return pick( + 'sound/voice/human/female_cry1.ogg', + 'sound/voice/human/female_cry2.ogg', + ) + return pick( + 'sound/voice/human/male_cry1.ogg', + 'sound/voice/human/male_cry2.ogg', + 'sound/voice/human/male_cry3.ogg', + ) + + +/datum/species/lizard/get_sneeze_sound(mob/living/carbon/human/lizard) + if(lizard.gender == FEMALE) + return 'sound/voice/human/female_sneeze1.ogg' + return 'sound/voice/human/male_sneeze1.ogg' + +/datum/species/lizard/get_laugh_sound(mob/living/carbon/human) + if(!istype(human)) + return + return 'sound/voice/lizard/lizard_laugh1.ogg' + /datum/species/lizard/get_physical_attributes() return "Lizardpeople can withstand slightly higher temperatures than most species, but they are very vulnerable to the cold \ and can't regulate their body-temperature internally, making the vacuum of space extremely deadly to them." diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index 1f371d575ac1e..ddf0963bb5d24 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -4,7 +4,7 @@ name = "Monkey" id = SPECIES_MONKEY external_organs = list( - /obj/item/organ/external/tail/monkey = "Monkey" + /obj/item/organ/external/tail/monkey = "Monkey", ) mutanttongue = /obj/item/organ/internal/tongue/monkey mutantbrain = /obj/item/organ/internal/brain/primate @@ -41,17 +41,14 @@ payday_modifier = 1.5 ai_controlled_species = TRUE -/datum/species/monkey/random_name(gender,unique,lastname) - return "monkey ([rand(1, 999)])" - -/datum/species/monkey/on_species_gain(mob/living/carbon/human/H, datum/species/old_species) +/datum/species/monkey/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load) . = ..() - passtable_on(H, SPECIES_TRAIT) - H.dna.add_mutation(/datum/mutation/human/race, MUT_NORMAL) - H.dna.activate_mutation(/datum/mutation/human/race) - H.AddElement(/datum/element/human_biter) + passtable_on(human_who_gained_species, SPECIES_TRAIT) + human_who_gained_species.dna.add_mutation(/datum/mutation/human/race, MUT_NORMAL) + human_who_gained_species.dna.activate_mutation(/datum/mutation/human/race) + human_who_gained_species.AddElement(/datum/element/human_biter) -/datum/species/monkey/on_species_loss(mob/living/carbon/C) +/datum/species/monkey/on_species_loss(mob/living/carbon/human/C) . = ..() passtable_off(C, SPECIES_TRAIT) C.dna.remove_mutation(/datum/mutation/human/race) @@ -59,6 +56,7 @@ /datum/species/monkey/check_roundstart_eligible() // STOP ADDING MONKEY SUBTYPES YOU HEATHEN + // ok we killed monkey subtypes but we're keeping this in cause we can't trust you fuckers if(check_holidays(MONKEYDAY) && id == SPECIES_MONKEY) return TRUE return ..() @@ -165,27 +163,19 @@ to_chat(monkey_brain.owner, span_notice("You will now stumble while while colliding with people who are in combat mode.")) build_all_button_icons() - /obj/item/organ/internal/brain/primate/on_mob_insert(mob/living/carbon/primate) . = ..() - RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed)) + RegisterSignal(primate, COMSIG_LIVING_MOB_BUMPED, PROC_REF(on_mob_bump)) /obj/item/organ/internal/brain/primate/on_mob_remove(mob/living/carbon/primate) . = ..() - UnregisterSignal(primate, COMSIG_MOVABLE_CROSS) + UnregisterSignal(primate, COMSIG_LIVING_MOB_BUMPED) -/obj/item/organ/internal/brain/primate/proc/on_crossed(datum/source, atom/movable/crossed) +/obj/item/organ/internal/brain/primate/proc/on_mob_bump(mob/source, mob/living/crossing_mob) SIGNAL_HANDLER - if(!tripping) - return - if(IS_DEAD_OR_INCAP(owner) || !isliving(crossed)) - return - var/mob/living/in_the_way_mob = crossed - if(iscarbon(in_the_way_mob) && !in_the_way_mob.combat_mode) - return - if(in_the_way_mob.pass_flags & PASSMOB) + if(!tripping || !crossing_mob.combat_mode) return - in_the_way_mob.knockOver(owner) + crossing_mob.knockOver(owner) /obj/item/organ/internal/brain/primate/get_attacking_limb(mob/living/carbon/human/target) if(!HAS_TRAIT(owner, TRAIT_ADVANCEDTOOLUSER)) diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index 68fb87142f6c9..54d6fe027e32f 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -34,17 +34,6 @@ var/mob/living/carbon/human/H = C handle_mutant_bodyparts(H) -/datum/species/moth/random_name(gender,unique,lastname) - if(unique) - return random_unique_moth_name() - - var/randname = moth_name() - - if(lastname) - randname += " [lastname]" - - return randname - /datum/species/moth/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load) . = ..() RegisterSignal(human_who_gained_species, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness)) @@ -61,12 +50,56 @@ /datum/species/moth/randomize_features() var/list/features = ..() - features["moth_markings"] = pick(GLOB.moth_markings_list) + features["moth_markings"] = pick(SSaccessories.moth_markings_list) return features -/datum/species/moth/get_scream_sound(mob/living/carbon/human/human) +/datum/species/moth/get_scream_sound(mob/living/carbon/human) return 'sound/voice/moth/scream_moth.ogg' +/datum/species/moth/get_cough_sound(mob/living/carbon/human/moth) + if(moth.gender == FEMALE) + return pick( + 'sound/voice/human/female_cough1.ogg', + 'sound/voice/human/female_cough2.ogg', + 'sound/voice/human/female_cough3.ogg', + 'sound/voice/human/female_cough4.ogg', + 'sound/voice/human/female_cough5.ogg', + 'sound/voice/human/female_cough6.ogg', + ) + return pick( + 'sound/voice/human/male_cough1.ogg', + 'sound/voice/human/male_cough2.ogg', + 'sound/voice/human/male_cough3.ogg', + 'sound/voice/human/male_cough4.ogg', + 'sound/voice/human/male_cough5.ogg', + 'sound/voice/human/male_cough6.ogg', + ) + + +/datum/species/moth/get_cry_sound(mob/living/carbon/human/moth) + if(moth.gender == FEMALE) + return pick( + 'sound/voice/human/female_cry1.ogg', + 'sound/voice/human/female_cry2.ogg', + ) + return pick( + 'sound/voice/human/male_cry1.ogg', + 'sound/voice/human/male_cry2.ogg', + 'sound/voice/human/male_cry3.ogg', + ) + + +/datum/species/moth/get_sneeze_sound(mob/living/carbon/human/moth) + if(moth.gender == FEMALE) + return 'sound/voice/human/female_sneeze1.ogg' + return 'sound/voice/human/male_sneeze1.ogg' + + +/datum/species/moth/get_laugh_sound(mob/living/carbon/human) + if(!istype(human)) + return + return 'sound/voice/moth/moth_laugh1.ogg' + /datum/species/moth/get_physical_attributes() return "Moths have large and fluffy wings, which help them navigate the station if gravity is offline by pushing the air around them. \ Due to that, it isn't of much use out in space. Their eyes are very sensitive." diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index f3486f1342f68..14d6c1437f0da 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -83,7 +83,7 @@ feature_key = "caps" /datum/bodypart_overlay/mutant/mushroom_cap/get_global_feature_list() - return GLOB.caps_list + return SSaccessories.caps_list /datum/bodypart_overlay/mutant/mushroom_cap/can_draw_on_bodypart(mob/living/carbon/human/human) if((human.head?.flags_inv & HIDEHAIR) || (human.wear_mask?.flags_inv & HIDEHAIR)) diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index c130b7d3ac729..e63e3c39c4885 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -61,6 +61,7 @@ /datum/outfit/syndicate/reinforcement/interdyne = /datum/outfit/syndicate/reinforcement/plasmaman, /datum/outfit/syndicate/reinforcement/mi13 = /datum/outfit/syndicate/reinforcement/plasmaman, /datum/outfit/syndicate/reinforcement/waffle = /datum/outfit/syndicate/reinforcement/plasmaman, + /datum/outfit/syndicate/support = /datum/outfit/syndicate/support/plasmaman, ) /// If the bones themselves are burning clothes won't help you much @@ -128,17 +129,6 @@ else give_important_for_life(equipping) -/datum/species/plasmaman/random_name(gender,unique,lastname) - if(unique) - return random_unique_plasmaman_name() - - var/randname = plasmaman_name() - - if(lastname) - randname += " [lastname]" - - return randname - /datum/species/plasmaman/get_scream_sound(mob/living/carbon/human) return pick( 'sound/voice/plasmaman/plasmeme_scream_1.ogg', diff --git a/code/modules/mob/living/carbon/human/species_types/snail.dm b/code/modules/mob/living/carbon/human/species_types/snail.dm index 93d88a3a777f2..053953e2a835f 100644 --- a/code/modules/mob/living/carbon/human/species_types/snail.dm +++ b/code/modules/mob/living/carbon/human/species_types/snail.dm @@ -26,6 +26,9 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/snail ) + ///Multiplier for the speed we give them. Positive numbers make it move slower, negative numbers make it move faster. + var/snail_speed_mod = 6 + /datum/species/snail/prepare_human_for_preview(mob/living/carbon/human/human) human.dna.features["mcolor"] = COLOR_BEIGE human.update_body(is_creating = TRUE) @@ -88,11 +91,13 @@ if(!istype(bag, /obj/item/storage/backpack/snail)) if(new_snailperson.dropItemToGround(bag)) //returns TRUE even if its null new_snailperson.equip_to_slot_or_del(new /obj/item/storage/backpack/snail(new_snailperson), ITEM_SLOT_BACK) - new_snailperson.AddElement(/datum/element/snailcrawl) + new_snailperson.AddElement(/datum/element/lube_walking, require_resting = TRUE) + new_snailperson.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/snail, multiplicative_slowdown = snail_speed_mod) /datum/species/snail/on_species_loss(mob/living/carbon/former_snailperson, datum/species/new_species, pref_load) . = ..() - former_snailperson.RemoveElement(/datum/element/snailcrawl) + former_snailperson.remove_movespeed_modifier(/datum/movespeed_modifier/snail) + former_snailperson.RemoveElement(/datum/element/lube_walking, require_resting = TRUE) var/obj/item/storage/backpack/bag = former_snailperson.get_item_by_slot(ITEM_SLOT_BACK) if(istype(bag, /obj/item/storage/backpack/snail)) bag.emptyStorage() diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index fbd56846ecbaf..111b35cb7f7bf 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -186,7 +186,7 @@ victim.show_message(span_warning("[H] tries to bite you, but recoils in disgust!")) to_chat(H, span_warning("[victim] reeks of garlic! you can't bring yourself to drain such tainted blood.")) return - if(!do_after(H, 3 SECONDS, target = victim)) + if(!do_after(H, 3 SECONDS, target = victim, hidden = TRUE)) return var/blood_volume_difference = BLOOD_VOLUME_MAXIMUM - H.blood_volume //How much capacity we have left to absorb blood var/drained_blood = min(victim.blood_volume, VAMP_DRAIN_AMOUNT, blood_volume_difference) diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 6c119a31f0097..c763127a4be7b 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -14,6 +14,7 @@ TRAIT_LIVERLESS_METABOLISM, TRAIT_NOBREATH, TRAIT_NODEATH, + TRAIT_NOCRITDAMAGE, TRAIT_NOHUNGER, TRAIT_NO_DNA_COPY, TRAIT_NO_ZOMBIFY, @@ -107,6 +108,7 @@ TRAIT_LIMBATTACHMENT, TRAIT_LIVERLESS_METABOLISM, TRAIT_NOBREATH, + TRAIT_NOCRITDAMAGE, TRAIT_NODEATH, TRAIT_NOHUNGER, TRAIT_NO_DNA_COPY, diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index e0a24d0ab51f0..45ca4487184e3 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -39,16 +39,6 @@ return ..() -/mob/living/carbon/proc/get_all_worn_items() - return list( - back, - wear_mask, - wear_neck, - head, - handcuffed, - legcuffed, - ) - /// Returns items which are currently visible on the mob /mob/living/carbon/proc/get_visible_items() var/static/list/visible_slots = list( @@ -126,13 +116,13 @@ if(wear_mask) return wear_mask = equipping - wear_mask_update(equipping, toggle_off = 0) + update_worn_mask() if(ITEM_SLOT_HEAD) if(head) return head = equipping SEND_SIGNAL(src, COMSIG_CARBON_EQUIP_HAT, equipping) - head_update(equipping) + update_worn_head() if(ITEM_SLOT_NECK) if(wear_neck) return @@ -162,7 +152,7 @@ return not_handled /mob/living/carbon/get_equipped_speed_mod_items() - return ..() + get_all_worn_items() + return ..() + get_equipped_items() /// This proc is called after an item has been successfully handled and equipped to a slot. /mob/living/carbon/proc/has_equipped(obj/item/item, slot, initial = FALSE) @@ -173,11 +163,12 @@ if(!. || !I) //We don't want to set anything to null if the parent returned 0. return + var/not_handled = FALSE //if we actually unequipped an item, this is because we dont want to run this proc twice, once for carbons and once for humans if(I == head) head = null SEND_SIGNAL(src, COMSIG_CARBON_UNEQUIP_HAT, I, force, newloc, no_move, invdrop, silent) if(!QDELETED(src)) - head_update(I) + update_worn_head() else if(I == back) back = null if(!QDELETED(src)) @@ -185,8 +176,8 @@ else if(I == wear_mask) wear_mask = null if(!QDELETED(src)) - wear_mask_update(I, toggle_off = 1) - if(I == wear_neck) + update_worn_mask() + else if(I == wear_neck) wear_neck = null if(!QDELETED(src)) update_worn_neck(I) @@ -200,6 +191,8 @@ legcuffed = null if(!QDELETED(src)) update_worn_legcuffs() + else + not_handled = TRUE // Not an else-if because we're probably equipped in another slot if(I == internal && (QDELETED(src) || QDELETED(I) || I.loc != src)) @@ -207,7 +200,11 @@ if(!QDELETED(src)) update_mob_action_buttons(UPDATE_BUTTON_STATUS) + if(not_handled) + return + update_equipment_speed_mods() + update_obscured_slots(I.flags_inv) /// Returns TRUE if an air tank compatible helmet is equipped. /mob/living/carbon/proc/can_breathe_helmet() @@ -357,27 +354,6 @@ // Carbons can't open their own externals tanks. return FALSE -/// Handle stuff to update when a mob equips/unequips a mask. -/mob/living/proc/wear_mask_update(obj/item/I, toggle_off = 1) - update_worn_mask() - -/mob/living/carbon/wear_mask_update(obj/item/I, toggle_off = 1) - var/obj/item/clothing/C = I - if(istype(C) && (C.tint || initial(C.tint))) - update_tint() - update_worn_mask() - -/// Handle stuff to update when a mob equips/unequips a headgear. -/mob/living/carbon/proc/head_update(obj/item/I, forced) - if(isclothing(I)) - var/obj/item/clothing/C = I - if(C.tint || initial(C.tint)) - update_tint() - update_sight() - if(I.flags_inv & HIDEMASK || forced) - update_worn_mask() - update_worn_head() - /mob/living/carbon/proc/get_holding_bodypart_of_item(obj/item/I) var/index = get_held_index_of_item(I) return index && hand_bodyparts[index] @@ -475,7 +451,7 @@ SHOULD_NOT_OVERRIDE(TRUE) var/covered_flags = NONE - var/list/all_worn_items = get_all_worn_items() + var/list/all_worn_items = get_equipped_items() for(var/obj/item/worn_item in all_worn_items) covered_flags |= worn_item.body_parts_covered @@ -486,7 +462,7 @@ SHOULD_NOT_OVERRIDE(TRUE) var/covered_flags = NONE - var/list/all_worn_items = get_all_worn_items() + var/list/all_worn_items = get_equipped_items() for(var/obj/item/worn_item in all_worn_items) covered_flags |= worn_item.body_parts_covered diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index fde1c91c11af7..e5f91b1b1b81a 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -244,7 +244,8 @@ if(!can_breathe_vacuum && (o2_pp < safe_oxygen_min)) // Breathe insufficient amount of O2. oxygen_used = handle_suffocation(o2_pp, safe_oxygen_min, breath_gases[/datum/gas/oxygen][MOLES]) - throw_alert(ALERT_NOT_ENOUGH_OXYGEN, /atom/movable/screen/alert/not_enough_oxy) + if(!HAS_TRAIT(src, TRAIT_ANOSMIA)) + throw_alert(ALERT_NOT_ENOUGH_OXYGEN, /atom/movable/screen/alert/not_enough_oxy) else // Enough oxygen to breathe. failed_last_breath = FALSE @@ -271,7 +272,8 @@ if(!co2overloadtime) co2overloadtime = world.time else if((world.time - co2overloadtime) > 12 SECONDS) - throw_alert(ALERT_TOO_MUCH_CO2, /atom/movable/screen/alert/too_much_co2) + if(!HAS_TRAIT(src, TRAIT_ANOSMIA)) + throw_alert(ALERT_TOO_MUCH_CO2, /atom/movable/screen/alert/too_much_co2) Unconscious(6 SECONDS) // Lets hurt em a little, let them know we mean business. adjustOxyLoss(3) @@ -289,7 +291,8 @@ // Plasma side-effects. var/ratio = (breath_gases[/datum/gas/plasma][MOLES] / safe_plas_max) * 10 adjustToxLoss(clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE)) - throw_alert(ALERT_TOO_MUCH_PLASMA, /atom/movable/screen/alert/too_much_plas) + if(!HAS_TRAIT(src, TRAIT_ANOSMIA)) + throw_alert(ALERT_TOO_MUCH_PLASMA, /atom/movable/screen/alert/too_much_plas) else // Reset side-effects. clear_alert(ALERT_TOO_MUCH_PLASMA) @@ -320,6 +323,8 @@ miasma_disease.name = "Unknown" ForceContractDisease(miasma_disease, make_copy = TRUE, del_on_fail = TRUE) // Miasma side-effects. + if (HAS_TRAIT(src, TRAIT_ANOSMIA)) //We can't feel miasma without sense of smell + return switch(miasma_pp) if(0.25 to 5) // At lower pp, give out a little warning @@ -350,7 +355,8 @@ if(n2o_pp > n2o_para_min) // More N2O, more severe side-effects. Causes stun/sleep. n2o_euphoria = EUPHORIA_ACTIVE - throw_alert(ALERT_TOO_MUCH_N2O, /atom/movable/screen/alert/too_much_n2o) + if(!HAS_TRAIT(src, TRAIT_ANOSMIA)) + throw_alert(ALERT_TOO_MUCH_N2O, /atom/movable/screen/alert/too_much_n2o) // give them one second of grace to wake up and run away a bit! if(!HAS_TRAIT(src, TRAIT_SLEEPIMMUNE)) Unconscious(6 SECONDS) @@ -781,7 +787,7 @@ * Returns TRUE if heart status was changed (heart attack -> no heart attack, or visa versa) */ /mob/living/carbon/proc/set_heartattack(status) - if(!can_heartattack()) + if(status && !can_heartattack()) return FALSE var/obj/item/organ/internal/heart/heart = get_organ_slot(ORGAN_SLOT_HEART) diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm index dc0b659fbec44..ba19418e2e220 100644 --- a/code/modules/mob/living/carbon/status_procs.dm +++ b/code/modules/mob/living/carbon/status_procs.dm @@ -10,6 +10,7 @@ return if(check_stun_immunity(CANKNOCKDOWN)) return + SEND_SIGNAL(src, COMSIG_CARBON_ENTER_STAMCRIT) to_chat(src, span_notice("You're too exhausted to keep going...")) add_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_FLOORED), STAMINA) diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 0c228775662d8..53b08719f6a70 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -108,7 +108,6 @@ INVOKE_ASYNC(src, TYPE_PROC_REF(/mob, emote), "deathgasp") set_stat(DEAD) - unset_machine() timeofdeath = world.time station_timestamp_timeofdeath = station_time_timestamp() var/turf/death_turf = get_turf(src) diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 3a19eebadc966..570cf1ec30458 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -67,18 +67,6 @@ var/mob/living/L = user L.Unconscious(40) -/datum/emote/living/cough - key = "cough" - key_third_person = "coughs" - message = "coughs!" - message_mime = "acts out an exaggerated cough!" - emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE - -/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional) - . = ..() - if(HAS_TRAIT(user, TRAIT_SOOTHED_THROAT)) - return FALSE - /datum/emote/living/dance key = "dance" key_third_person = "dances" @@ -138,14 +126,14 @@ key_third_person = "flaps" message = "flaps their wings." hands_use_check = TRUE - var/wing_time = 20 + var/wing_time = 0.35 SECONDS /datum/emote/living/flap/run_emote(mob/user, params, type_override, intentional) . = ..() if(. && ishuman(user)) - var/mob/living/carbon/human/H = user + var/mob/living/carbon/human/human_user = user var/open = FALSE - var/obj/item/organ/external/wings/functional/wings = H.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS) + var/obj/item/organ/external/wings/functional/wings = human_user.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS) // open/close functional wings if(istype(wings)) @@ -156,9 +144,8 @@ wings.open_wings() addtimer(CALLBACK(wings, open ? TYPE_PROC_REF(/obj/item/organ/external/wings/functional, open_wings) : TYPE_PROC_REF(/obj/item/organ/external/wings/functional, close_wings)), wing_time) - // play moth flutter noise if moth wing - if(istype(wings, /obj/item/organ/external/wings/moth)) - playsound(H, 'sound/voice/moth/moth_flutter.ogg', 50, TRUE) + // play a flapping noise if the wing has this implemented + wings.make_flap_sound(human_user) /datum/emote/living/flap/aflap key = "aflap" @@ -286,15 +273,11 @@ /datum/emote/living/laugh/can_run_emote(mob/living/user, status_check = TRUE , intentional) return ..() && user.can_speak(allow_mimes = TRUE) -/datum/emote/living/laugh/get_sound(mob/living/user) +/datum/emote/living/laugh/get_sound(mob/living/carbon/user) if(!ishuman(user)) return var/mob/living/carbon/human/human_user = user - if((ishumanbasic(human_user) || isfelinid(human_user)) && !HAS_MIND_TRAIT(human_user, TRAIT_MIMING)) - if(human_user.gender == FEMALE) - return 'sound/voice/human/womanlaugh.ogg' - else - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') + return human_user.dna.species.get_laugh_sound(user) /datum/emote/living/look key = "look" @@ -328,6 +311,38 @@ H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5) return ..() +/datum/emote/living/carbon/cry + key = "cry" + key_third_person = "cries" + message = "cries." + emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE + stat_allowed = SOFT_CRIT + mob_type_blacklist_typecache = list(/mob/living/carbon/human) //Humans get specialized cry emote with sound and animation. + +/datum/emote/living/sneeze + key = "sneeze" + key_third_person = "sneezes" + message = "sneezes." + emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE + mob_type_blacklist_typecache = list(/mob/living/carbon/human) //Humans get specialized sneeze emote with sound. + +/datum/emote/living/carbon/human/glasses/run_emote(mob/user, params, type_override, intentional) + . = ..() + var/image/emote_animation = image('icons/mob/human/emote_visuals.dmi', user, "glasses") + flick_overlay_global(emote_animation, GLOB.clients, 1.6 SECONDS) + +/datum/emote/living/carbon/cough + key = "cough" + key_third_person = "coughs" + message = "coughs!" + message_mime = "acts out an exaggerated cough!" + emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT + mob_type_blacklist_typecache = list(/mob/living/carbon/human) //Humans get specialized cough emote with sound. + +/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional) + return !HAS_TRAIT(user, TRAIT_SOOTHED_THROAT) && ..() + + /datum/emote/living/pout key = "pout" key_third_person = "pouts" @@ -403,13 +418,6 @@ key_third_person = "smiles" message = "smiles." -/datum/emote/living/sneeze - key = "sneeze" - key_third_person = "sneezes" - message = "sneezes." - message_mime = "acts out an exaggerated silent sneeze." - emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE - /datum/emote/living/smug key = "smug" key_third_person = "smugs" @@ -633,20 +641,20 @@ to_chat(user, span_warning("\"[input]\"")) REPORT_CHAT_FILTER_TO_USER(user, filter_result) log_filter("IC Emote", input, filter_result) - SSblackbox.record_feedback("tally", "ic_blocked_words", 1, lowertext(config.ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "ic_blocked_words", 1, LOWER_TEXT(config.ic_filter_regex.match)) return FALSE filter_result = is_soft_ic_filtered(input) if(filter_result) if(tgui_alert(user,"Your emote contains \"[filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to emote it?", "Soft Blocked Word", list("Yes", "No")) != "Yes") - SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, LOWER_TEXT(config.soft_ic_filter_regex.match)) log_filter("Soft IC Emote", input, filter_result) return FALSE message_admins("[ADMIN_LOOKUPFLW(user)] has passed the soft filter for emote \"[filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Emote: \"[input]\"") log_admin_private("[key_name(user)] has passed the soft filter for emote \"[filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Emote: \"[input]\"") - SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, LOWER_TEXT(config.soft_ic_filter_regex.match)) log_filter("Soft IC Emote (Passed)", input, filter_result) return TRUE @@ -732,3 +740,17 @@ message = "says a swear word!" message_mime = "makes a rude gesture!" emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/whistle + key = "whistle" + key_third_person = "whistles" + message = "whistles." + message_mime = "whistles silently!" + audio_cooldown = 5 SECONDS + vary = TRUE + emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE + +/datum/emote/living/carbon/whistle/get_sound(mob/living/user) + if(!istype(user)) + return + return 'sound/voice/human/whistle1.ogg' diff --git a/code/modules/mob/living/inhand_holder.dm b/code/modules/mob/living/inhand_holder.dm index b4c9fbd34aa1b..808c8973963d8 100644 --- a/code/modules/mob/living/inhand_holder.dm +++ b/code/modules/mob/living/inhand_holder.dm @@ -20,7 +20,7 @@ righthand_file = rh_icon if(worn_slot_flags) slot_flags = worn_slot_flags - w_class = M.held_w_class + update_weight_class(M.held_w_class) deposit(M) . = ..() diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm index ed496c0c84b6f..8415881a83a24 100644 --- a/code/modules/mob/living/init_signals.dm +++ b/code/modules/mob/living/init_signals.dm @@ -98,7 +98,7 @@ SIGNAL_HANDLER mobility_flags &= ~MOBILITY_MOVE if(living_flags & MOVES_ON_ITS_OWN) - SSmove_manager.stop_looping(src) //stop mid walk //This is also really dumb + GLOB.move_manager.stop_looping(src) //stop mid walk //This is also really dumb /// Called when [TRAIT_IMMOBILIZED] is removed from the mob. /mob/living/proc/on_immobilized_trait_loss(datum/source) @@ -157,7 +157,6 @@ /mob/living/proc/on_ui_blocked_trait_gain(datum/source) SIGNAL_HANDLER mobility_flags &= ~(MOBILITY_UI) - unset_machine() update_mob_action_buttons() /// Called when [TRAIT_UI_BLOCKED] is removed from the mob. diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 35866514b79e7..dd7e8a17c9bf2 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -66,9 +66,6 @@ handle_wounds(seconds_per_tick, times_fired) - if(machine) - machine.check_eye(src) - if(stat != DEAD) return 1 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0af9c50416525..1b1e02c83d910 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -68,11 +68,19 @@ if(levels <= 1 && can_help_themselves) var/obj/item/organ/external/wings/gliders = get_organ_by_type(/obj/item/organ/external/wings) if(HAS_TRAIT(src, TRAIT_FREERUNNING) || gliders?.can_soften_fall()) // the power of parkour or wings allows falling short distances unscathed + var/graceful_landing = HAS_TRAIT(src, TRAIT_CATLIKE_GRACE) + + if(graceful_landing) + add_movespeed_modifier(/datum/movespeed_modifier/landed_on_feet) + addtimer(CALLBACK(src, TYPE_PROC_REF(/mob, remove_movespeed_modifier), /datum/movespeed_modifier/landed_on_feet), levels * 3 SECONDS) + else + Knockdown(levels * 4 SECONDS) + emote("spin") + visible_message( - span_notice("[src] makes a hard landing on [impacted_turf] but remains unharmed from the fall."), - span_notice("You brace for the fall. You make a hard landing on [impacted_turf], but remain unharmed."), + span_notice("[src] makes a hard landing on [impacted_turf] but remains unharmed from the fall[graceful_landing ? " and stays on [p_their()] feet" : " by tucking in rolling into the landing"]."), + span_notice("You brace for the fall. You make a hard landing on [impacted_turf], but remain unharmed[graceful_landing ? " while landing on your feet" : " by tucking in and rolling into the landing"]."), ) - Knockdown(levels * 4 SECONDS) return . | ZIMPACT_NO_MESSAGE var/incoming_damage = (levels * 5) ** 1.5 @@ -148,6 +156,7 @@ return TRUE SEND_SIGNAL(src, COMSIG_LIVING_MOB_BUMP, M) + SEND_SIGNAL(M, COMSIG_LIVING_MOB_BUMPED, src) //Even if we don't push/swap places, we "touched" them, so spread fire spreadFire(M) @@ -286,6 +295,8 @@ return TRUE if(!client && (mob_size < MOB_SIZE_SMALL)) return + if(SEND_SIGNAL(AM, COMSIG_MOVABLE_BUMP_PUSHED, src, force) & COMPONENT_NO_PUSH) + return now_pushing = TRUE SEND_SIGNAL(src, COMSIG_LIVING_PUSHING_MOVABLE, AM) var/dir_to_target = get_dir(src, AM) @@ -669,7 +680,7 @@ /mob/living/proc/get_up(instant = FALSE) set waitfor = FALSE - if(!instant && !do_after(src, 1 SECONDS, src, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM), extra_checks = CALLBACK(src, TYPE_PROC_REF(/mob/living, rest_checks_callback)), interaction_key = DOAFTER_SOURCE_GETTING_UP)) + if(!instant && !do_after(src, 1 SECONDS, src, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM), extra_checks = CALLBACK(src, TYPE_PROC_REF(/mob/living, rest_checks_callback)), interaction_key = DOAFTER_SOURCE_GETTING_UP, hidden = TRUE)) return if(resting || body_position == STANDING_UP || HAS_TRAIT(src, TRAIT_FLOORED)) return @@ -1078,6 +1089,20 @@ else return pick("trails_1", "trails_2") +/// Print a message about an annoying sensation you are feeling. Returns TRUE if successful. +/mob/living/proc/itch(obj/item/bodypart/target_part = null, damage = 0.5, can_scratch = TRUE, silent = FALSE) + if ((mob_biotypes & (MOB_ROBOTIC | MOB_SPIRIT))) + return FALSE + var/will_scratch = can_scratch && !incapacitated() + var/applied_damage = 0 + if (will_scratch && damage) + applied_damage = apply_damage(damage, damagetype = BRUTE, def_zone = target_part) + if (silent) + return applied_damage > 0 + var/visible_part = isnull(target_part) ? "side" : target_part.plaintext_zone + visible_message("[can_scratch ? span_warning("[src] scratches [p_their()] [visible_part].") : ""]", span_warning("Your [visible_part] itches. [can_scratch ? "You scratch it." : ""]")) + return TRUE + /mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0) playsound(src, 'sound/effects/space_wind.ogg', 50, TRUE) if(buckled || mob_negates_gravity()) @@ -1267,9 +1292,9 @@ return FALSE if(invisibility || alpha <= 50)//cloaked return FALSE - if(!isturf(src.loc)) //The reason why we don't just use get_turf is because they could be in a closet, disposals, or a vehicle. + if(!isturf(loc)) //The reason why we don't just use get_turf is because they could be in a closet, disposals, or a vehicle. return FALSE - var/turf/T = src.loc + var/turf/T = loc if(is_centcom_level(T.z)) //dont detect mobs on centcom return FALSE if(is_away_level(T.z)) @@ -1307,7 +1332,8 @@ if(!Adjacent(target) && (target.loc != src) && !recursive_loc_check(src, target)) if(HAS_SILICON_ACCESS(src) && !ispAI(src)) if(!(action_bitflags & ALLOW_SILICON_REACH)) // silicons can ignore range checks (except pAIs) - to_chat(src, span_warning("You are too far away!")) + if(!(action_bitflags & SILENT_ADJACENCY)) + to_chat(src, span_warning("You are too far away!")) return FALSE else // just a normal carbon mob if((action_bitflags & FORBID_TELEKINESIS_REACH)) @@ -1316,9 +1342,14 @@ var/datum/dna/mob_DNA = has_dna() if(!mob_DNA || !mob_DNA.check_mutation(/datum/mutation/human/telekinesis) || !tkMaxRangeCheck(src, target)) - to_chat(src, span_warning("You are too far away!")) + if(!(action_bitflags & SILENT_ADJACENCY)) + to_chat(src, span_warning("You are too far away!")) return FALSE + if((action_bitflags & NEED_VENTCRAWL) && !HAS_TRAIT(src, TRAIT_VENTCRAWLER_NUDE) && !HAS_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS)) + to_chat(src, span_warning("You wouldn't fit!")) + return FALSE + if((action_bitflags & NEED_DEXTERITY) && !ISADVANCEDTOOLUSER(src)) to_chat(src, span_warning("You don't have the dexterity to do this!")) return FALSE @@ -1748,32 +1779,36 @@ GLOBAL_LIST_EMPTY(fire_appearances) /mob/living/proc/update_z(new_z) // 1+ to register, null to unregister - if (registered_z != new_z) - if (registered_z) - SSmobs.clients_by_zlevel[registered_z] -= src - if (client) - if (new_z) - //Figure out how many clients were here before - var/oldlen = SSmobs.clients_by_zlevel[new_z].len - SSmobs.clients_by_zlevel[new_z] += src - for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511 - var/mob/living/simple_animal/SA = SSidlenpcpool.idle_mobs_by_zlevel[new_z][I] - if (SA) - if(oldlen == 0) - //Start AI idle if nobody else was on this z level before (mobs will switch off when this is the case) - SA.toggle_ai(AI_IDLE) - - //If they are also within a close distance ask the AI if it wants to wake up - if(get_dist(get_turf(src), get_turf(SA)) < MAX_SIMPLEMOB_WAKEUP_RANGE) - SA.consider_wakeup() // Ask the mob if it wants to turn on it's AI - //They should clean up in destroy, but often don't so we get them here - else - SSidlenpcpool.idle_mobs_by_zlevel[new_z] -= SA - - - registered_z = new_z - else - registered_z = null + if(registered_z == new_z) + return + if(registered_z) + SSmobs.clients_by_zlevel[registered_z] -= src + if(isnull(client)) + registered_z = null + return + + //Check the amount of clients exists on the Z level we're leaving from, + //this excludes us because at this point we are not registered to any z level. + var/old_level_new_clients = (registered_z ? SSmobs.clients_by_zlevel[registered_z].len : null) + //No one is left after we're gone, shut off inactive ones + if(registered_z && old_level_new_clients == 0) + for(var/datum/ai_controller/controller as anything in SSai_controllers.ai_controllers_by_zlevel[registered_z]) + controller.set_ai_status(AI_STATUS_OFF) + + if(new_z) + //Check the amount of clients exists on the Z level we're moving towards, excluding ourselves. + var/new_level_old_clients = SSmobs.clients_by_zlevel[new_z].len + + //We'll add ourselves to the list now so get_expected_ai_status() will know we're on the z level. + SSmobs.clients_by_zlevel[new_z] += src + + if(new_level_old_clients == 0) //No one was here before, wake up all the AIs. + for (var/datum/ai_controller/controller as anything in SSai_controllers.ai_controllers_by_zlevel[new_z]) + //We don't set them directly on, for instances like AIs acting while dead and other cases that may exist in the future. + //This isn't a problem for AIs with a client since the client will prevent this from being called anyway. + controller.set_ai_status(controller.get_expected_ai_status()) + + registered_z = new_z /mob/living/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) ..() @@ -1794,7 +1829,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) user.put_in_hands(holder) /mob/living/proc/set_name() - if(!numba) + if(numba == 0) numba = rand(1, 1000) name = "[name] ([numba])" real_name = name @@ -1915,6 +1950,7 @@ GLOBAL_LIST_EMPTY(fire_appearances) VV_DROPDOWN_OPTION(VV_HK_GIVE_HALLUCINATION, "Give Hallucination") VV_DROPDOWN_OPTION(VV_HK_GIVE_DELUSION_HALLUCINATION, "Give Delusion Hallucination") VV_DROPDOWN_OPTION(VV_HK_GIVE_GUARDIAN_SPIRIT, "Give Guardian Spirit") + VV_DROPDOWN_OPTION(VV_HK_ADMIN_RENAME, "Force Change Name") /mob/living/vv_do_topic(list/href_list) . = ..() @@ -1952,6 +1988,29 @@ GLOBAL_LIST_EMPTY(fire_appearances) return admin_give_guardian(usr) + if(href_list[VV_HK_ADMIN_RENAME]) + if(!check_rights(R_ADMIN)) + return + + var/old_name = real_name + var/new_name = sanitize_name(tgui_input_text(usr, "Enter the new name.", "Admin Rename", real_name)) + if(!new_name || new_name == real_name) + return + + fully_replace_character_name(real_name, new_name) + var/replace_preferences = !isnull(client) && (tgui_alert(usr, "Would you like to update the client's preference with the new name?", "Pref Overwrite", list("Yes", "No")) == "Yes") + if(replace_preferences) + client.prefs.write_preference(GLOB.preference_entries[/datum/preference/name/real_name], new_name) + + log_admin("forced rename", list( + "admin" = key_name(usr), + "player" = key_name(src), + "old_name" = old_name, + "new_name" = new_name, + "updated_prefs" = replace_preferences, + )) + message_admins("[key_name_admin(usr)] has forcibly changed the real name of [key_name(src)] from '[old_name]' to '[real_name]'[(replace_preferences ? " and their preferences" : "")]") + /mob/living/proc/move_to_error_room() var/obj/effect/landmark/error/error_landmark = locate(/obj/effect/landmark/error) in GLOB.landmarks_list if(error_landmark) @@ -2343,10 +2402,10 @@ GLOBAL_LIST_EMPTY(fire_appearances) /// Proc to append behavior to the condition of being floored. Called when the condition starts. /mob/living/proc/on_floored_start() + on_fall() if(body_position == STANDING_UP) //force them on the ground set_body_position(LYING_DOWN) set_lying_angle(pick(90, 270)) - on_fall() /// Proc to append behavior to the condition of being floored. Called when the condition ends. @@ -2410,6 +2469,10 @@ GLOBAL_LIST_EMPTY(fire_appearances) apply_damage(rand(5,10), BRUTE, BODY_ZONE_CHEST) lattice.deconstruct(FALSE) +/// Prints an ominous message if something bad is going to happen to you +/mob/living/proc/ominous_nosebleed() + to_chat(src, span_warning("You feel a bit nauseous for just a moment.")) + /** * Proc used by different station pets such as Ian and Poly so that some of their data can persist between rounds. * This base definition only contains a trait and comsig to stop memory from being (over)written. @@ -2662,3 +2725,26 @@ GLOBAL_LIST_EMPTY(fire_appearances) physical_cash_total += counted_credit.get_item_credit_value() counted_money += counted_credit return round(physical_cash_total) + +/// Returns an arbitrary number which very roughly correlates with how buff you look +/mob/living/proc/calculate_fitness() + var/athletics_level = mind?.get_skill_level(/datum/skill/athletics) || 1 + var/damage = (melee_damage_lower + melee_damage_upper) / 2 + + return ceil(damage * (ceil(athletics_level / 2)) * maxHealth) + +/// Create a report string about how strong this person looks, generated in a somewhat arbitrary fashion +/mob/living/proc/compare_fitness(mob/living/scouter) + if (HAS_TRAIT(src, TRAIT_UNKNOWN)) + return span_warning("It's impossible to tell whether this person lifts.") + + var/our_fitness_level = calculate_fitness() + var/their_fitness_level = scouter.calculate_fitness() + + var/comparative_fitness = our_fitness_level / their_fitness_level + + if (comparative_fitness > 2) + scouter.set_jitter_if_lower(comparative_fitness SECONDS) + return "[span_notice("You'd estimate [p_their()] fitness level at about...")] [span_boldwarning("What?!? [our_fitness_level]???")]" + + return span_notice("You'd estimate [p_their()] fitness level at about [our_fitness_level]. [comparative_fitness <= 0.33 ? "Pathetic." : ""]") diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index ec366f0f26ce8..42a1f90dde696 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -202,7 +202,7 @@ span_userdanger("You're hit by [thrown_item]!")) if(!thrown_item.throwforce) return - var/armor = run_armor_check(zone, MELEE, "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", thrown_item.armour_penetration, "", FALSE, thrown_item.weak_against_armour) + var/armor = run_armor_check(zone, MELEE, "Your armor has protected your [parse_zone_with_bodypart(zone)].", "Your armor has softened hit to your [parse_zone_with_bodypart(zone)].", thrown_item.armour_penetration, "", FALSE, thrown_item.weak_against_armour) apply_damage(thrown_item.throwforce, thrown_item.damtype, zone, armor, sharpness = thrown_item.get_sharpness(), wound_bonus = (nosell_hit * CANT_WOUND)) if(QDELETED(src)) //Damage can delete the mob. return @@ -545,8 +545,8 @@ if((GLOB.cult_narsie.souls == GLOB.cult_narsie.soul_goal) && (GLOB.cult_narsie.resolved == FALSE)) GLOB.cult_narsie.resolved = TRUE sound_to_playing_players('sound/machines/alarm.ogg') - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_VICTORY_MASS_CONVERSION), 120) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ending_helper)), 270) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_VICTORY_MASS_CONVERSION), 12 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ending_helper)), 27 SECONDS) if(client) make_new_construct(/mob/living/basic/construct/harvester, src, cultoverride = TRUE) else diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 5ce6aa04379b3..bbcf77986ac79 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -122,11 +122,11 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( return if(message_mods[RADIO_EXTENSION] == MODE_ADMIN) - client?.cmd_admin_say(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, message) return if(message_mods[RADIO_EXTENSION] == MODE_DEADMIN) - client?.dsay(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/dsay, message) return // dead is the only state you can never emote @@ -208,9 +208,9 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( spans |= speech_span - if(language) - var/datum/language/L = GLOB.language_datum_instances[language] - spans |= L.spans + var/datum/language/spoken_lang = GLOB.language_datum_instances[language] + if(LAZYLEN(spoken_lang?.spans)) + spans |= spoken_lang.spans if(message_mods[MODE_SING]) var/randomnote = pick("\u2669", "\u266A", "\u266B") @@ -412,7 +412,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( var/mob/living/carbon/human/human_speaker = src if(istype(human_speaker.wear_mask, /obj/item/clothing/mask)) var/obj/item/clothing/mask/worn_mask = human_speaker.wear_mask - if(!worn_mask.mask_adjusted) + if(!worn_mask.up) if(worn_mask.voice_override) voice_to_use = worn_mask.voice_override if(worn_mask.voice_filter) diff --git a/code/modules/mob/living/silicon/ai/_preferences.dm b/code/modules/mob/living/silicon/ai/_preferences.dm index 4b0aaaecc250a..10958b2adc4f5 100644 --- a/code/modules/mob/living/silicon/ai/_preferences.dm +++ b/code/modules/mob/living/silicon/ai/_preferences.dm @@ -115,7 +115,7 @@ GLOBAL_LIST_INIT(ai_core_display_screens, sort_list(list( else if(input == "Random") input = pick(GLOB.ai_core_display_screens - "Random") - return "ai-[lowertext(input)]" + return "ai-[LOWER_TEXT(input)]" /proc/resolve_ai_icon(input) if (input == "Portrait") diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 2b79d0dbcbf9f..dfd9afeec4516 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1,17 +1,5 @@ #define CALL_BOT_COOLDOWN 900 -//Not sure why this is necessary... -/proc/AutoUpdateAI(obj/subject) - var/is_in_use = 0 - if (subject != null) - for(var/A in GLOB.ai_list) - var/mob/living/silicon/ai/M = A - if ((M.client && M.machine == subject)) - is_in_use = 1 - subject.attack_ai(M) - return is_in_use - - /mob/living/silicon/ai name = "AI" real_name = "AI" @@ -53,12 +41,13 @@ var/shunted = FALSE //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead var/obj/machinery/ai_voicechanger/ai_voicechanger = null // reference to machine that holds the voicechanger var/malfhacking = FALSE // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite + /// List of hacked APCs + var/list/hacked_apcs = list() var/malf_cooldown = 0 //Cooldown var for malf modules, stores a worldtime + cooldown var/obj/machinery/power/apc/malfhack var/explosive = FALSE //does the AI explode when it dies? - var/mob/living/silicon/ai/parent var/camera_light_on = FALSE var/list/obj/machinery/camera/lit_cameras = list() @@ -451,6 +440,10 @@ qdel(src) return ai_core +/mob/living/silicon/ai/proc/break_core_link() + to_chat(src, span_danger("Your core has been destroyed!")) + linked_core = null + /mob/living/silicon/ai/proc/make_mmi_drop_and_transfer(obj/item/mmi/the_mmi, the_core) var/mmi_type if(posibrain_inside) @@ -644,7 +637,6 @@ /mob/living/silicon/ai/proc/ai_network_change() set category = "AI Commands" set name = "Jump To Network" - unset_machine() ai_tracking_tool.reset_tracking() var/cameralist[0] @@ -959,6 +951,9 @@ module_picker.ui_interact(owner) /mob/living/silicon/ai/proc/add_malf_picker() + if (malf_picker) + stack_trace("Attempted to give malf AI malf picker to \[[src]\], who already has a malf picker.") + return to_chat(src, "In the top left corner of the screen you will find the Malfunction Modules button, where you can purchase various abilities, from upgraded surveillance to station ending doomsday devices.") to_chat(src, "You are also capable of hacking APCs, which grants you more points to spend on your Malfunction powers. The drawback is that a hacked APC will give you away if spotted by the crew. Hacking an APC takes 60 seconds.") view_core() //A BYOND bug requires you to be viewing your core before your verbs update @@ -1036,13 +1031,16 @@ malf_ai_datum.update_static_data_for_all_viewers() else //combat software AIs use a different UI malf_picker.update_static_data_for_all_viewers() - - apc.malfai = parent || src + if(apc.malfai) // another malf hacked this one; counter-hack! + to_chat(apc.malfai, span_warning("An adversarial subroutine has counter-hacked [apc]!")) + apc.malfai.hacked_apcs -= apc + apc.malfai = src apc.malfhack = TRUE apc.locked = TRUE apc.coverlocked = TRUE apc.flicker_hacked_icon() apc.set_hacked_hud() + hacked_apcs += apc playsound(get_turf(src), 'sound/machines/ding.ogg', 50, TRUE, ignore_walls = FALSE) to_chat(src, "Hack complete. [apc] is now under your exclusive control.") diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm index 1148b639d0113..a80b84b95aa8a 100644 --- a/code/modules/mob/living/silicon/ai/ai_defense.dm +++ b/code/modules/mob/living/silicon/ai/ai_defense.dm @@ -2,6 +2,7 @@ /mob/living/silicon/ai/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/ai_module)) var/obj/item/ai_module/MOD = W + disconnect_shell() if(!mind) //A player mind is required for law procs to run antag checks. to_chat(user, span_warning("[src] is entirely unresponsive!")) return @@ -137,7 +138,7 @@ return ITEM_INTERACT_SUCCESS balloon_alert(src, "neural network being disconnected...") balloon_alert(user, "disconnecting neural network...") - if(!tool.use_tool(src, user, (stat == DEAD ? 40 SECONDS : 5 SECONDS))) + if(!tool.use_tool(src, user, (stat == DEAD ? 5 SECONDS : 40 SECONDS))) return ITEM_INTERACT_SUCCESS if(IS_MALF_AI(src)) to_chat(user, span_userdanger("The voltage inside the wires rises dramatically!")) diff --git a/code/modules/mob/living/silicon/ai/ai_say.dm b/code/modules/mob/living/silicon/ai/ai_say.dm index 6a4cd255a6ae5..48b3cdc437350 100644 --- a/code/modules/mob/living/silicon/ai/ai_say.dm +++ b/code/modules/mob/living/silicon/ai/ai_say.dm @@ -1,20 +1,3 @@ -/mob/living/silicon/ai/say( - message, - bubble_type, - list/spans = list(), - sanitize = TRUE, - datum/language/language, - ignore_spam = FALSE, - forced, - filterproof = FALSE, - message_range = 7, - datum/saymode/saymode, - list/message_mods = list(), -) - if(istype(parent) && parent.stat != DEAD) //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead. - return parent.say(arglist(args)) - return ..() - /mob/living/silicon/ai/compose_track_href(atom/movable/speaker, namepart) var/mob/M = speaker.GetSource() if(M) @@ -126,7 +109,7 @@ words.len = 30 for(var/word in words) - word = lowertext(trim(word)) + word = LOWER_TEXT(trim(word)) if(!word) words -= word continue @@ -156,7 +139,7 @@ /proc/play_vox_word(word, ai_turf, mob/only_listener) - word = lowertext(word) + word = LOWER_TEXT(word) if(GLOB.vox_sounds[word]) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 03824857c4efc..79e14d649fc38 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -1,4 +1,4 @@ -/mob/living/silicon/ai/death(gibbed) +/mob/living/silicon/ai/death(gibbed, drop_mmi = TRUE) if(stat == DEAD) return @@ -33,7 +33,7 @@ ShutOffDoomsdayDevice() - if(gibbed) + if(gibbed && drop_mmi) make_mmi_drop_and_transfer() if(explosive) diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index e8c1919b020f9..98a2e629776b1 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -202,7 +202,6 @@ current = null if(ai_tracking_tool) ai_tracking_tool.reset_tracking() - unset_machine() if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc)) to_chat(src, "ERROR: Eyeobj not found. Creating new eye...") diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 331291db4ea2f..b11f125d38ce4 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -12,9 +12,6 @@ if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc)) view_core() - if(machine) - machine.check_eye(src) - // Handle power damage (oxy) if(aiRestorePowerRoutine) // Lost power @@ -164,4 +161,4 @@ adjust_temp_blindness(2 SECONDS) update_sight() to_chat(src, span_alert("You've lost power!")) - addtimer(CALLBACK(src, PROC_REF(start_RestorePowerRoutine)), 20) + addtimer(CALLBACK(src, PROC_REF(start_RestorePowerRoutine)), 2 SECONDS) diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 2a9631339fc61..0f1cbfa65a51b 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -18,7 +18,7 @@ /mob/living/silicon/robot/proc/use_energy(seconds_per_tick, times_fired) if(cell?.charge) - if(cell.charge <= (10 KILO JOULES)) + if(cell.charge <= 0.01 * STANDARD_CELL_CHARGE) drop_all_held_items() var/energy_consumption = max(lamp_power_consumption * lamp_enabled * lamp_intensity * seconds_per_tick, BORG_MINIMUM_POWER_CONSUMPTION * seconds_per_tick) //Lamp will use a max of 5 * [BORG_LAMP_POWER_CONSUMPTION], depending on brightness of lamp. If lamp is off, borg systems consume [BORG_MINIMUM_POWER_CONSUMPTION], or the rest of the cell if it's lower than that. cell.use(energy_consumption, force = TRUE) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 1bcd703365102..3fa78b9dda155 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -3,7 +3,7 @@ spark_system.set_up(5, 0, src) spark_system.attach(src) - add_traits(list(TRAIT_CAN_STRIP, TRAIT_FORCED_STANDING), INNATE_TRAIT) + add_traits(list(TRAIT_CAN_STRIP, TRAIT_FORCED_STANDING, TRAIT_KNOW_ENGI_WIRES), INNATE_TRAIT) AddComponent(/datum/component/tippable, \ tip_time = 3 SECONDS, \ untip_time = 2 SECONDS, \ @@ -226,7 +226,7 @@ if(!ionpulse_on) return - if(!cell.use(10 KILO JOULES)) + if(!cell.use(0.01 * STANDARD_CELL_CHARGE)) toggle_ionpulse() return return TRUE @@ -319,7 +319,7 @@ update_appearance(UPDATE_OVERLAYS) /mob/living/silicon/robot/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) - if(same_z_layer) + if(same_z_layer || QDELING(src)) return ..() cut_overlay(eye_lights) SET_PLANE_EXPLICIT(eye_lights, PLANE_TO_TRUE(eye_lights.plane), src) @@ -950,13 +950,14 @@ /mob/living/silicon/robot/proc/charge(datum/source, datum/callback/charge_cell, seconds_per_tick, repairs, sendmats) SIGNAL_HANDLER - charge_cell.Invoke(cell, seconds_per_tick) + if(model) - model.respawn_consumable(src, cell.use(cell.chargerate * 0.005)) + model.respawn_consumable(src, cell.use(cell.charge * 0.005)) if(sendmats) model.restock_consumable() if(repairs) heal_bodypart_damage(repairs, repairs) + charge_cell.Invoke(cell, seconds_per_tick) /mob/living/silicon/robot/proc/set_connected_ai(new_ai) if(connected_ai == new_ai) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 722b92835c8e0..70e7d8b34ab25 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -11,7 +11,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real if (getFireLoss() > 0 || getToxLoss() > 0) if(src == user) to_chat(user, span_notice("You start fixing yourself...")) - if(!do_after(user, 50, target = src)) + if(!do_after(user, 5 SECONDS, target = src)) return if (coil.use(1)) adjustFireLoss(-30) @@ -52,7 +52,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real return to_chat(user, span_notice("You begin to place [W] on [src]'s head...")) to_chat(src, span_notice("[user] is placing [W] on your head...")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) if (user.temporarilyRemoveItemFromInventory(W, TRUE)) place_on_head(W) return @@ -227,7 +227,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real return spark_system.start() step_away(src, user, 15) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), src, get_turf(user), 15), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), src, get_turf(user), 15), 0.3 SECONDS) /mob/living/silicon/robot/get_shove_flags(mob/living/shover, obj/item/weapon) . = ..() diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index 04aadc7e5bc9d..0701584476cd2 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -106,6 +106,7 @@ ///Random serial number generated for each cyborg upon its initialization var/ident = 0 var/locked = TRUE + req_one_access = list(ACCESS_ROBOTICS) ///Whether the robot has no charge left. var/low_power_mode = FALSE diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm index fe57733b391e6..176125ec8240f 100644 --- a/code/modules/mob/living/silicon/robot/robot_model.dm +++ b/code/modules/mob/living/silicon/robot/robot_model.dm @@ -360,15 +360,12 @@ /obj/item/pipe_dispenser, /obj/item/extinguisher, /obj/item/weldingtool/largetank/cyborg, - /obj/item/screwdriver/cyborg, - /obj/item/wrench/cyborg, - /obj/item/crowbar/cyborg, - /obj/item/wirecutters/cyborg, - /obj/item/multitool/cyborg, + /obj/item/borg/cyborg_omnitool/engineering, + /obj/item/borg/cyborg_omnitool/engineering, /obj/item/t_scanner, /obj/item/analyzer, /obj/item/assembly/signaler/cyborg, - /obj/item/areaeditor/blueprints/cyborg, + /obj/item/blueprints/cyborg, /obj/item/electroadaptive_pseudocircuit, /obj/item/stack/sheet/iron, /obj/item/stack/sheet/glass, @@ -655,14 +652,8 @@ /obj/item/borg/apparatus/beaker, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, - /obj/item/surgical_drapes, - /obj/item/retractor, - /obj/item/hemostat, - /obj/item/cautery, - /obj/item/surgicaldrill, - /obj/item/scalpel, - /obj/item/circular_saw, - /obj/item/bonesetter, + /obj/item/borg/cyborg_omnitool/medical, + /obj/item/borg/cyborg_omnitool/medical, /obj/item/blood_filter, /obj/item/extinguisher/mini, /obj/item/emergency_bed/silicon, @@ -856,15 +847,10 @@ /obj/item/reagent_containers/borghypo/syndicate, /obj/item/shockpaddles/syndicate/cyborg, /obj/item/healthanalyzer, - /obj/item/surgical_drapes, - /obj/item/retractor, - /obj/item/hemostat, - /obj/item/cautery, - /obj/item/surgicaldrill, - /obj/item/scalpel, - /obj/item/melee/energy/sword/cyborg/saw, - /obj/item/bonesetter, + /obj/item/borg/cyborg_omnitool/medical, + /obj/item/borg/cyborg_omnitool/medical, /obj/item/blood_filter, + /obj/item/melee/energy/sword/cyborg/saw, /obj/item/emergency_bed/silicon, /obj/item/crowbar/cyborg, /obj/item/extinguisher/mini, @@ -889,12 +875,9 @@ /obj/item/restraints/handcuffs/cable/zipties, /obj/item/extinguisher, /obj/item/weldingtool/largetank/cyborg, - /obj/item/screwdriver/nuke, - /obj/item/wrench/cyborg, - /obj/item/crowbar/cyborg, - /obj/item/wirecutters/cyborg, /obj/item/analyzer, - /obj/item/multitool/cyborg, + /obj/item/borg/cyborg_omnitool/engineering, + /obj/item/borg/cyborg_omnitool/engineering, /obj/item/stack/sheet/iron, /obj/item/stack/sheet/glass, /obj/item/borg/apparatus/sheet_manipulator, diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index b43a625b1e482..95e2e6ed13379 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -306,7 +306,7 @@ ///Gives you a link-driven interface for deciding what laws the statelaws() proc will share with the crew. /mob/living/silicon/proc/checklaws() laws_sanity_check() - var/list = "Which laws do you want to include when stating them for the crew?

    " + var/list = "Which laws do you want to include when stating them for the crew?

    " var/law_display = "Yes" if (laws.zeroth) @@ -480,3 +480,11 @@ stack_trace("Silicon [src] ( [type] ) was somehow missing their integrated tablet. Please make a bug report.") create_modularInterface() modularInterface.imprint_id(name = newname) + +/mob/living/silicon/can_track(mob/living/user) + //if their camera is online, it's safe to assume they are in cameranets + //since it takes a while for camera vis to update, this lets us bypass that so AIs can always see their borgs, + //without making cameras constantly update every time a borg moves. + if(builtInCamera && builtInCamera.can_use()) + return TRUE + return ..() diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index 8bf51bbffd4e0..f09361e9bdf48 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -61,7 +61,7 @@ weapon.attack(C, src) playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE, -1) if(C.stat == DEAD) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 2) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 0.2 SECONDS) back_to_idle() @@ -71,7 +71,7 @@ switch(mode) if(BOT_IDLE) // idle update_appearance() - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) look_for_perp() // see if any criminals are in range if(!mode && bot_mode_flags & BOT_MODE_AUTOPATROL) // still idle, and set to patrol mode = BOT_START_PATROL // switch to patrol mode @@ -80,7 +80,7 @@ playsound(src,'sound/effects/beepskyspinsabre.ogg',100,TRUE,-1) // general beepsky doesn't give up so easily, jedi scum if(frustration >= 20) - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) back_to_idle() return if(target) // make sure target exists @@ -91,7 +91,7 @@ return else // not next to perp var/turf/olddist = get_dist(src, target) - SSmove_manager.move_to(src, target, 1, 4) + GLOB.move_manager.move_to(src, target, 1, 4) if((get_dist(src, target)) >= (olddist)) frustration++ else diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index c8f512d78f8a1..944a00af9b63e 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -29,6 +29,7 @@ light_power = 0.6 del_on_death = TRUE req_one_access = list(ACCESS_ROBOTICS) + interaction_flags_click = ALLOW_SILICON_REACH ///Cooldown between salutations for commissioned bots COOLDOWN_DECLARE(next_salute_check) @@ -203,6 +204,7 @@ pa_system = new(src, automated_announcements = automated_announcements) pa_system.Grant(src) + RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(attempt_access)) /mob/living/simple_animal/bot/Destroy() GLOB.bots_list -= src @@ -380,7 +382,7 @@ COOLDOWN_START(src, next_salute_check, BOT_COMMISSIONED_SALUTE_DELAY) for(var/mob/living/simple_animal/bot/B in view(5, src)) if(!HAS_TRAIT(B, TRAIT_COMMISSIONED) && B.bot_mode_flags & BOT_MODE_ON) - visible_message("[B] performs an elaborate salute for [src]!") + manual_emote("performs an elaborate salute for [src]!") break switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command. @@ -411,13 +413,9 @@ ui = new(user, src, "SimpleBot", name) ui.open() -/mob/living/simple_animal/bot/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return - if(!user.can_perform_action(src, ALLOW_SILICON_REACH)) - return +/mob/living/simple_animal/bot/click_alt(mob/user) unlock_with_id(user) + return CLICK_ACTION_SUCCESS /mob/living/simple_animal/bot/proc/unlock_with_id(mob/user) if(bot_cover_flags & BOT_COVER_EMAGGED) @@ -760,7 +758,7 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/bot_patrol() patrol_step() - addtimer(CALLBACK(src, PROC_REF(do_patrol)), 5) + addtimer(CALLBACK(src, PROC_REF(do_patrol)), 0.5 SECONDS) /mob/living/simple_animal/bot/proc/do_patrol() if(mode == BOT_PATROL) @@ -814,7 +812,7 @@ Pass a positive integer as an argument to override a bot's default speed. var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move if(!moved) //Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times - addtimer(CALLBACK(src, PROC_REF(patrol_step_not_moved)), 2) + addtimer(CALLBACK(src, PROC_REF(patrol_step_not_moved)), 0.2 SECONDS) else // no path, so calculate new one mode = BOT_START_PATROL @@ -945,7 +943,7 @@ Pass a positive integer as an argument to override a bot's default speed. var/moved = bot_move(summon_target, 3) // Move attempt if(!moved) - addtimer(CALLBACK(src, PROC_REF(summon_step_not_moved)), 2) + addtimer(CALLBACK(src, PROC_REF(summon_step_not_moved)), 0.2 SECONDS) else // no path, so calculate new one calc_summon_path() @@ -954,13 +952,13 @@ Pass a positive integer as an argument to override a bot's default speed. calc_summon_path() tries = 0 -/mob/living/simple_animal/bot/Bump(atom/A) //Leave no door unopened! - . = ..() - if((istype(A, /obj/machinery/door/airlock) || istype(A, /obj/machinery/door/window)) && (!isnull(access_card))) - var/obj/machinery/door/D = A - if(D.check_access(access_card)) - D.open() - frustration = 0 +/mob/living/simple_animal/bot/proc/attempt_access(mob/bot, obj/door_attempt) + SIGNAL_HANDLER + + if(door_attempt.check_access(access_card)) + frustration = 0 + return ACCESS_ALLOWED + return ACCESS_DISALLOWED /mob/living/simple_animal/bot/ui_data(mob/user) var/list/data = list() diff --git a/code/modules/mob/living/simple_animal/bot/bot_announcement.dm b/code/modules/mob/living/simple_animal/bot/bot_announcement.dm index 30a30b81fd270..eade5a291c439 100644 --- a/code/modules/mob/living/simple_animal/bot/bot_announcement.dm +++ b/code/modules/mob/living/simple_animal/bot/bot_announcement.dm @@ -4,7 +4,7 @@ desc = "Play a prerecorded message for the benefit of those around you." background_icon_state = "bg_tech_blue" overlay_icon_state = "bg_tech_blue_border" - button_icon = 'icons/mob/actions/actions_AI.dmi' + button_icon = 'icons/obj/machines/wallmounts.dmi' button_icon_state = "intercom" cooldown_time = 10 SECONDS melee_cooldown_time = 0 SECONDS diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 698b62a1c2e9f..1bef64de8a66b 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -163,7 +163,7 @@ to_chat(user, span_warning("You need one length of cable to wire the ED-209!")) return to_chat(user, span_notice("You start to wire [src]...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(coil.get_amount() >= 1 && build_step == ASSEMBLY_SEVENTH_STEP) coil.use(1) to_chat(user, span_notice("You wire [src].")) @@ -546,7 +546,7 @@ to_chat(user, span_warning("You need one fluid duct to finish [src]")) return to_chat(user, span_notice("You start to pipe up [src]...")) - if(do_after(user, 40, target = src) && D.use(1)) + if(do_after(user, 4 SECONDS, target = src) && D.use(1)) to_chat(user, span_notice("You pipe up [src].")) var/mob/living/basic/bot/hygienebot/new_bot = new(drop_location()) new_bot.name = created_name diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 94713a69a12e8..ae1c52d1652da 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -140,7 +140,7 @@ return data // Actions received from TGUI -/mob/living/simple_animal/bot/floorbot/ui_act(action, params) +/mob/living/simple_animal/bot/floorbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr))) return @@ -161,7 +161,7 @@ tilestack.forceMove(drop_location()) if("line_mode") var/setdir = tgui_input_list(usr, "Select construction direction", "Direction", list("north", "east", "south", "west", "disable")) - if(isnull(setdir)) + if(isnull(setdir) || QDELETED(ui) || ui.status != UI_INTERACTIVE) return switch(setdir) if("north") @@ -326,7 +326,7 @@ toggle_magnet() visible_message(span_notice("[targetdirection ? "[src] begins installing a bridge plating." : "[src] begins to repair the hole."] ")) mode = BOT_REPAIRING - if(do_after(src, 50, target = target_turf) && mode == BOT_REPAIRING) + if(do_after(src, 5 SECONDS, target = target_turf) && mode == BOT_REPAIRING) if(autotile) //Build the floor and include a tile. if(replacetiles && tilestack) target_turf.place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) //make sure a hull is actually below the floor tile @@ -348,14 +348,14 @@ toggle_magnet() mode = BOT_REPAIRING visible_message(span_notice("[src] begins [(F.broken || F.burnt) ? "repairing the floor" : "placing a floor tile"].")) - if(do_after(src, 50, target = F) && mode == BOT_REPAIRING) + if(do_after(src, 5 SECONDS, target = F) && mode == BOT_REPAIRING) success = TRUE else if(replacetiles && tilestack && F.type != tilestack.turf_type) toggle_magnet() mode = BOT_REPAIRING visible_message(span_notice("[src] begins replacing the floor tiles.")) - if(do_after(src, 50, target = target_turf) && mode == BOT_REPAIRING && tilestack) + if(do_after(src, 5 SECONDS, target = target_turf) && mode == BOT_REPAIRING && tilestack) success = TRUE if(success) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 9c52ca8e23858..ba0e10484d81d 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -164,7 +164,7 @@ target = null oldtarget_name = null set_anchored(FALSE) - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) last_found = world.time /mob/living/simple_animal/bot/secbot/proc/on_saboteur(datum/source, disrupt_duration) @@ -180,7 +180,7 @@ /mob/living/simple_animal/bot/secbot/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)//shocks only make him angry if(base_speed < initial(base_speed) + 3) base_speed += 3 - addtimer(VARSET_CALLBACK(src, base_speed, base_speed - 3), 60) + addtimer(VARSET_CALLBACK(src, base_speed, base_speed - 3), 6 SECONDS) playsound(src, 'sound/machines/defib_zap.ogg', 50) visible_message(span_warning("[src] shakes and speeds up!")) @@ -389,7 +389,7 @@ switch(mode) if(BOT_IDLE) // idle - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) look_for_perp() // see if any criminals are in range if((mode == BOT_IDLE) && bot_mode_flags & BOT_MODE_AUTOPATROL) // didn't start hunting during look_for_perp, and set to patrol mode = BOT_START_PATROL // switch to patrol mode @@ -397,7 +397,7 @@ if(BOT_HUNT) // hunting for perp // if can't reach perp for long enough, go idle if(frustration >= 8) - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) back_to_idle() return @@ -415,7 +415,7 @@ // not next to perp var/turf/olddist = get_dist(src, target) - SSmove_manager.move_to(src, target, 1, 4) + GLOB.move_manager.move_to(src, target, 1, 4) if((get_dist(src, target)) >= (olddist)) frustration++ else diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 1cde4d4a74058..507563e7c207c 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -104,7 +104,7 @@ /mob/living/simple_animal/hostile/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() if(!.) //dead - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) /mob/living/simple_animal/hostile/handle_automated_action() if(AIStatus == AI_OFF || QDELETED(src)) @@ -339,11 +339,11 @@ if(!target.Adjacent(target_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown OpenFire(target) if(!Process_Spacemove(0)) //Drifting - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) return 1 if(retreat_distance != null) //If we have a retreat distance, check if we need to run from our target if(target_distance <= retreat_distance) //If target's closer than our retreat distance, run - SSmove_manager.move_away(src, target, retreat_distance, move_to_delay, flags = MOVEMENT_LOOP_IGNORE_GLIDE) + GLOB.move_manager.move_away(src, target, retreat_distance, move_to_delay, flags = MOVEMENT_LOOP_IGNORE_GLIDE) else Goto(target,move_to_delay,minimum_distance) //Otherwise, get to our minimum distance so we chase them else @@ -378,7 +378,7 @@ approaching_target = TRUE else approaching_target = FALSE - SSmove_manager.move_to(src, target, minimum_distance, delay, flags = MOVEMENT_LOOP_IGNORE_GLIDE) + GLOB.move_manager.move_to(src, target, minimum_distance, delay, flags = MOVEMENT_LOOP_IGNORE_GLIDE) return TRUE /mob/living/simple_animal/hostile/adjustHealth(amount, updating_health = TRUE, forced = FALSE) @@ -418,7 +418,7 @@ GiveTarget(null) approaching_target = FALSE in_melee = FALSE - SSmove_manager.stop_looping(src) + GLOB.move_manager.stop_looping(src) LoseAggro() //////////////END HOSTILE MOB TARGETING AND AGGRESSION//////////// @@ -615,29 +615,6 @@ value = initial(search_objects) search_objects = value -/mob/living/simple_animal/hostile/consider_wakeup() - ..() - var/list/tlist - var/turf/T = get_turf(src) - - if (!T) - return - - if (!length(SSmobs.clients_by_zlevel[T.z])) // It's fine to use .len here but doesn't compile on 511 - toggle_ai(AI_Z_OFF) - return - - var/cheap_search = isturf(T) && !is_station_level(T.z) - if (cheap_search) - tlist = ListTargetsLazy(T.z) - else - tlist = ListTargets() - - if(AIStatus == AI_IDLE && FindTarget(tlist)) - if(cheap_search) //Try again with full effort - FindTarget() - toggle_ai(AI_ON) - /mob/living/simple_animal/hostile/proc/ListTargetsLazy(_Z)//Step 1, find out what we can see var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha)) . = list() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index 91cf152acb07f..00cc37fe618cb 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -225,7 +225,7 @@ Difficulty: Hard var/turf/targetturf = get_step(src, dir) L.forceMove(targetturf) playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, TRUE, -1) - addtimer(CALLBACK(src, PROC_REF(devour), L), 2) + addtimer(CALLBACK(src, PROC_REF(devour), L), 0.2 SECONDS) SLEEP_CHECK_DEATH(1, src) /mob/living/simple_animal/hostile/megafauna/bubblegum/devour(mob/living/yummy_food) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 40f7f3abd0d79..a71b9f76af399 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -330,7 +330,7 @@ . = ..() if(!.) return FALSE - + for(var/atom/thing as anything in range(1, src)) if(isturf(thing)) new /obj/effect/decal/cleanable/confetti(thing) @@ -340,7 +340,7 @@ continue var/mob/living/carbon/human/new_clown = thing - + if(new_clown.stat != DEAD) continue @@ -349,12 +349,12 @@ var/clown_ref = REF(new_clown) if(clown_ref in clowned_mob_refs) //one clowning per person continue - + for(var/obj/item/to_strip in new_clown.get_equipped_items()) new_clown.dropItemToGround(to_strip) new_clown.dress_up_as_job(SSjob.GetJobType(/datum/job/clown)) clowned_mob_refs += clown_ref - + return TRUE /// Transforms the area to look like a new one @@ -423,18 +423,18 @@ if(!ishuman(thing)) continue - + var/mob/living/carbon/human/to_revive = thing - + if(to_revive.stat != DEAD) continue - + to_revive.set_species(/datum/species/shadow, TRUE) to_revive.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE) //Free revives, but significantly limits your options for reviving except via the crystal //except JK who cares about BADDNA anymore. this even heals suicides. ADD_TRAIT(to_revive, TRAIT_BADDNA, MAGIC_TRAIT) - + return TRUE /obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index d7fceecf0532f..b4cafdb6d538d 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -231,7 +231,7 @@ Difficulty: Hard blinking = TRUE SLEEP_CHECK_DEATH(4 + target_slowness, src) animate(src, color = oldcolor, time = 8) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.8 SECONDS) SLEEP_CHECK_DEATH(8, src) blinking = FALSE else @@ -252,7 +252,7 @@ Difficulty: Hard INVOKE_ASYNC(src, PROC_REF(blasts), target, GLOB.diagonals) SLEEP_CHECK_DEATH(6 + target_slowness, src) animate(src, color = oldcolor, time = 8) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.8 SECONDS) SLEEP_CHECK_DEATH(8, src) blinking = FALSE @@ -280,7 +280,7 @@ Difficulty: Hard SLEEP_CHECK_DEATH(8 + target_slowness, src) update_cooldowns(list(COOLDOWN_UPDATE_SET_CHASER = chaser_cooldown_time)) animate(src, color = oldcolor, time = 8) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.8 SECONDS) SLEEP_CHECK_DEATH(8, src) blinking = FALSE @@ -582,7 +582,7 @@ Difficulty: Hard friendly_fire_check = is_friendly_fire if(new_speed) speed = new_speed - addtimer(CALLBACK(src, PROC_REF(seek_target)), 1) + addtimer(CALLBACK(src, PROC_REF(seek_target)), 0.1 SECONDS) /obj/effect/temp_visual/hierophant/chaser/proc/get_target_dir() . = get_cardinal_dir(src, targetturf) @@ -753,7 +753,7 @@ Difficulty: Hard var/obj/item/hierophant_club/club = attacking_item if(club.beacon == src) to_chat(user, span_notice("You start removing your hierophant beacon...")) - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) playsound(src,'sound/magic/blind.ogg', 100, TRUE, -4) new /obj/effect/temp_visual/hierophant/telegraph/teleport(get_turf(src), user) to_chat(user, span_hierophant_warning("You collect [src], reattaching it to the club!")) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm index 6632dedd2342b..d39c8a3e52bd9 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm @@ -48,7 +48,7 @@ Difficulty: Hard achievement_type = /datum/award/achievement/boss/wendigo_kill crusher_achievement_type = /datum/award/achievement/boss/wendigo_crusher score_achievement_type = /datum/award/score/wendigo_score - death_message = "falls to the ground in a bloody heap, shaking the arena" + death_message = "falls to the ground in a bloody heap, shaking the arena." death_sound = 'sound/effects/gravhit.ogg' footstep_type = FOOTSTEP_MOB_HEAVY attack_action_types = list(/datum/action/innate/megafauna_attack/heavy_stomp, diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm index 3a838ac58cdf3..95744d0a2d310 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm @@ -45,7 +45,7 @@ /mob/living/simple_animal/hostile/asteroid/curseblob/proc/move_loop(move_target, delay) if(our_loop) return - our_loop = SSmove_manager.force_move(src, move_target, delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + our_loop = GLOB.move_manager.force_move(src, move_target, delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) if(!our_loop) return RegisterSignal(move_target, COMSIG_MOB_STATCHANGE, PROC_REF(stat_change)) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index ba34883489fc8..71801a44c95ef 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -169,7 +169,7 @@ While using this makes the system rely on OnFire, it still gives options for tim if(boosted) mychild.playsound_local(get_turf(mychild), 'sound/effects/magic.ogg', 40, 0) to_chat(mychild, "Someone has activated your tumor. You will be returned to fight shortly, get ready!") - addtimer(CALLBACK(src, PROC_REF(return_elite)), 30) + addtimer(CALLBACK(src, PROC_REF(return_elite)), 3 SECONDS) INVOKE_ASYNC(src, PROC_REF(arena_checks)) if(TUMOR_INACTIVE) if(HAS_TRAIT(user, TRAIT_ELITE_CHALLENGER)) @@ -181,7 +181,7 @@ While using this makes the system rely on OnFire, it still gives options for tim visible_message(span_boldwarning("[src] begins to convulse. Your instincts tell you to step back.")) make_activator(user) if(!boosted) - addtimer(CALLBACK(src, PROC_REF(spawn_elite)), 30) + addtimer(CALLBACK(src, PROC_REF(spawn_elite)), 3 SECONDS) return visible_message(span_boldwarning("Something within [src] stirs...")) var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, poll_time = 5 SECONDS, checked_target = src, ignore_category = POLL_IGNORE_LAVALAND_ELITE, alert_pic = src, role_name_text = "lavaland elite") @@ -194,7 +194,7 @@ While using this makes the system rely on OnFire, it still gives options for tim While the opponent might have an upper hand with powerful mining equipment and tools, you have great power normally limited by AI mobs.\n\ If you want to win, you'll have to use your powers in creative ways to ensure the kill. It's suggested you try using them all as soon as possible.\n\ Should you win, you'll receive extra information regarding what to do after. Good luck!") - addtimer(CALLBACK(src, PROC_REF(spawn_elite), elitemind), 100) + addtimer(CALLBACK(src, PROC_REF(spawn_elite), elitemind), 10 SECONDS) else visible_message(span_boldwarning("The stirring stops, and nothing emerges. Perhaps try again later.")) activity = TUMOR_INACTIVE @@ -291,7 +291,7 @@ While using this makes the system rely on OnFire, it still gives options for tim INVOKE_ASYNC(src, PROC_REF(arena_trap)) //Gets another arena trap queued up for when this one runs out. INVOKE_ASYNC(src, PROC_REF(border_check)) //Checks to see if our fighters got out of the arena somehow. if(!QDELETED(src)) - addtimer(CALLBACK(src, PROC_REF(arena_checks)), 50) + addtimer(CALLBACK(src, PROC_REF(arena_checks)), 5 SECONDS) /obj/structure/elite_tumor/proc/fighters_check() if(QDELETED(mychild) || mychild.stat == DEAD) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm index 2b1d638ac495c..f7d86c350deef 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm @@ -146,7 +146,7 @@ color = COLOR_RED set_varspeed(0) move_to_delay = 3 - addtimer(CALLBACK(src, PROC_REF(reset_rage)), 65) + addtimer(CALLBACK(src, PROC_REF(reset_rage)), 6.5 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/reset_rage() color = COLOR_WHITE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm index 77557879ccb93..9f162e0cfdc77 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm @@ -56,7 +56,7 @@ /mob/living/simple_animal/hostile/asteroid/elite/herald/death() . = ..() if(!is_mirror) - addtimer(CALLBACK(src, PROC_REF(become_ghost)), 8) + addtimer(CALLBACK(src, PROC_REF(become_ghost)), 0.8 SECONDS) if(my_mirror != null) qdel(my_mirror) @@ -150,13 +150,13 @@ var/target_turf = get_turf(target) var/angle_to_target = get_angle(src, target_turf) shoot_projectile(target_turf, angle_to_target, FALSE, TRUE) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 2) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 4) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 0.2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 0.4 SECONDS) if(health < maxHealth * 0.5 && !is_mirror) playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 10) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 12) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 14) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 1.2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 1.4 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_circleshot(offset) var/static/list/directional_shot_angles = list(0, 45, 90, 135, 180, 225, 270, 315) @@ -173,11 +173,11 @@ if(!is_mirror) icon_state = "herald_enraged" playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE) - addtimer(CALLBACK(src, PROC_REF(herald_circleshot), 0), 5) + addtimer(CALLBACK(src, PROC_REF(herald_circleshot), 0), 0.5 SECONDS) if(health < maxHealth * 0.5 && !is_mirror) playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE) - addtimer(CALLBACK(src, PROC_REF(herald_circleshot), 22.5), 15) - addtimer(CALLBACK(src, PROC_REF(unenrage)), 20) + addtimer(CALLBACK(src, PROC_REF(herald_circleshot), 22.5), 1.5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(unenrage)), 2 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_teleshot(target) ranged_cooldown = world.time + 30 @@ -283,7 +283,7 @@ owner.visible_message(span_danger("[owner]'s [src] emits a loud noise as [owner] is struck!")) var/static/list/directional_shot_angles = list(0, 45, 90, 135, 180, 225, 270, 315) playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE) - addtimer(CALLBACK(src, PROC_REF(reactionshot), owner), 10) + addtimer(CALLBACK(src, PROC_REF(reactionshot), owner), 1 SECONDS) #undef HERALD_TRISHOT #undef HERALD_DIRECTIONALSHOT diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm index 926f4e96baaef..1ec573dbd6c56 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm @@ -123,7 +123,7 @@ T = get_step(T, dir_to_target) playsound(src,'sound/magic/demon_attack1.ogg', 200, 1) visible_message(span_boldwarning("[src] prepares to charge!")) - addtimer(CALLBACK(src, PROC_REF(legionnaire_charge_2), dir_to_target, 0), 4) + addtimer(CALLBACK(src, PROC_REF(legionnaire_charge_2), dir_to_target, 0), 0.4 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/legionnaire_charge_2(move_dir, times_ran) if(times_ran >= 6) @@ -183,7 +183,7 @@ /mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/onHeadDeath() myhead = null - addtimer(CALLBACK(src, PROC_REF(regain_head)), 50) + addtimer(CALLBACK(src, PROC_REF(regain_head)), 5 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/regain_head() has_head = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm index 2d6cdb39da061..a9babf2eccafa 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm @@ -136,7 +136,7 @@ new /obj/effect/temp_visual/hierophant/telegraph(turf_target, src) new /obj/effect/temp_visual/hierophant/telegraph(source, src) playsound(source,'sound/machines/airlockopen.ogg', 200, 1) - addtimer(CALLBACK(src, PROC_REF(pandora_teleport_2), turf_target, source), 2) + addtimer(CALLBACK(src, PROC_REF(pandora_teleport_2), turf_target, source), 0.2 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/pandora_teleport_2(turf/T, turf/source) new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, src) @@ -148,7 +148,7 @@ animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out visible_message(span_hierophant_warning("[src] fades out!")) ADD_TRAIT(src, TRAIT_UNDENSE, VANISHING_TRAIT) - addtimer(CALLBACK(src, PROC_REF(pandora_teleport_3), T), 2) + addtimer(CALLBACK(src, PROC_REF(pandora_teleport_3), T), 0.2 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/pandora_teleport_3(turf/T) forceMove(T) @@ -161,7 +161,7 @@ var/turf/T = get_turf(target) new /obj/effect/temp_visual/hierophant/blast/damaging/pandora(T, src) var/max_size = 3 - addtimer(CALLBACK(src, PROC_REF(aoe_squares_2), T, 0, max_size), 2) + addtimer(CALLBACK(src, PROC_REF(aoe_squares_2), T, 0, max_size), 0.2 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/aoe_squares_2(turf/T, ring, max_size) if(ring > max_size) diff --git a/code/modules/mob/living/simple_animal/hostile/ooze.dm b/code/modules/mob/living/simple_animal/hostile/ooze.dm index ddfe4c18ee83e..e20ecc2337a4d 100644 --- a/code/modules/mob/living/simple_animal/hostile/ooze.dm +++ b/code/modules/mob/living/simple_animal/hostile/ooze.dm @@ -223,7 +223,7 @@ to_chat(src, span_warning("You are already consuming another creature!")) return FALSE owner.visible_message(span_warning("[ooze] starts attempting to devour [target]!"), span_notice("You start attempting to devour [target].")) - if(!do_after(ooze, 15, target = ooze.pulling)) + if(!do_after(ooze, 1.5 SECONDS, target = ooze.pulling)) return FALSE var/mob/living/eat_target = ooze.pulling diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm index e4b07470c5882..30afc69c8b3e9 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm @@ -144,7 +144,7 @@ /mob/living/simple_animal/hostile/retaliate/goose/proc/choke(obj/item/food/plastic) if(stat == DEAD || choking) return - addtimer(CALLBACK(src, PROC_REF(suffocate)), 300) + addtimer(CALLBACK(src, PROC_REF(suffocate)), 30 SECONDS) /mob/living/simple_animal/hostile/retaliate/goose/vomit/choke(obj/item/food/plastic) if(stat == DEAD || choking) @@ -152,9 +152,9 @@ if(prob(25)) visible_message(span_warning("[src] is gagging on \the [plastic]!")) manual_emote("gags!") - addtimer(CALLBACK(src, PROC_REF(vomit)), 300) + addtimer(CALLBACK(src, PROC_REF(vomit)), 30 SECONDS) else - addtimer(CALLBACK(src, PROC_REF(suffocate)), 300) + addtimer(CALLBACK(src, PROC_REF(suffocate)), 30 SECONDS) /mob/living/simple_animal/hostile/retaliate/goose/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 1c1ea138d23cf..25d0e566b15dd 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -131,7 +131,7 @@ ///Played when someone punches the creature. var/attacked_sound = SFX_PUNCH - ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players). + ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever). var/AIStatus = AI_ON ///once we have become sentient, we can never go back. var/can_have_ai = TRUE @@ -221,10 +221,6 @@ GLOB.simple_animals[AIStatus] -= src SSnpcpool.currentrun -= src - var/turf/T = get_turf(src) - if (T && AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src - return ..() /mob/living/simple_animal/examine(mob/user) @@ -514,29 +510,12 @@ return if (AIStatus != togglestatus) if (togglestatus > 0 && togglestatus < 5) - if (togglestatus == AI_Z_OFF || AIStatus == AI_Z_OFF) - var/turf/T = get_turf(src) - if (T) - if (AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src - else - SSidlenpcpool.idle_mobs_by_zlevel[T.z] += src GLOB.simple_animals[AIStatus] -= src GLOB.simple_animals[togglestatus] += src AIStatus = togglestatus else stack_trace("Something attempted to set simple animals AI to an invalid state: [togglestatus]") -/mob/living/simple_animal/proc/consider_wakeup() - if (pulledby || shouldwakeup) - toggle_ai(AI_ON) - -/mob/living/simple_animal/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) - ..() - if (old_turf && AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[old_turf.z] -= src - toggle_ai(initial(AIStatus)) - ///This proc is used for adding the swabbale element to mobs so that they are able to be biopsied and making sure holograpic and butter-based creatures don't yield viable cells samples. /mob/living/simple_animal/proc/add_cell_sample() return @@ -560,7 +539,7 @@ /mob/living/simple_animal/proc/Goto(target, delay, minimum_distance) if(prevent_goto_movement) return FALSE - SSmove_manager.move_to(src, target, minimum_distance, delay) + GLOB.move_manager.move_to(src, target, minimum_distance, delay) return TRUE //Makes this mob hunt the prey, be it living or an object. Will kill living creatures, and delete objects. diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index b8ceb33a37df7..cf937e42bb74f 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -2,7 +2,6 @@ SEND_SIGNAL(src, COMSIG_MOB_LOGOUT) log_message("[key_name(src)] is no longer owning mob [src]([src.type])", LOG_OWNERSHIP) SStgui.on_logout(src) - unset_machine() remove_from_player_list() ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index fa332d7837ad7..4219e8e3c38d3 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -30,7 +30,6 @@ else if(ckey) stack_trace("Mob without client but with associated ckey, [ckey], has been deleted.") - unset_machine() remove_from_mob_list() remove_from_dead_mob_list() remove_from_alive_mob_list() @@ -262,10 +261,12 @@ * message is output to anyone who can see, e.g. `"The [src] does something!"` * * Vars: + * * message is the message output to anyone who can see. * * self_message (optional) is what the src mob sees e.g. "You do something!" * * blind_message (optional) is what blind people will hear e.g. "You hear something!" * * vision_distance (optional) define how many tiles away the message can be seen. - * * ignored_mob (optional) doesn't show any message to a given mob if TRUE. + * * ignored_mobs (optional) doesn't show any message to any mob in this list. + * * visible_message_flags (optional) is the type of message being sent. */ /atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE) var/turf/T = get_turf(src) @@ -314,8 +315,22 @@ ///Adds the functionality to self_message. /mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE) . = ..() - if(self_message) - show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE) + if(!self_message) + return + var/raw_self_message = self_message + var/self_runechat = FALSE + if(visible_message_flags & EMOTE_MESSAGE) + self_message = "[src] [self_message]" // May make more sense as "You do x" + + if(visible_message_flags & ALWAYS_SHOW_SELF_MESSAGE) + to_chat(src, self_message) + self_runechat = TRUE + + else + self_runechat = show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE) + + if(self_runechat && (visible_message_flags & EMOTE_MESSAGE) && runechat_prefs_check(src, visible_message_flags)) + create_chat_message(src, raw_message = raw_self_message, runechat_flags = visible_message_flags) /** * Show a message to all mobs in earshot of this atom @@ -326,6 +341,8 @@ * * message is the message output to anyone who can hear. * * deaf_message (optional) is what deaf people will see. * * hearing_distance (optional) is the range, how many tiles away the message can be heard. + * * self_message (optional) is what the src mob hears. + * * audible_message_flags (optional) is the type of message being sent. */ /atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE) var/list/hearers = get_hearers_in_view(hearing_distance, src) @@ -352,9 +369,20 @@ */ /mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE) . = ..() - if(self_message) - show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL) + if(!self_message) + return + var/raw_self_message = self_message + var/self_runechat = FALSE + if(audible_message_flags & EMOTE_MESSAGE) + self_message = "[src] [self_message]" + if(audible_message_flags & ALWAYS_SHOW_SELF_MESSAGE) + to_chat(src, self_message) + self_runechat = TRUE + else + self_runechat = show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL) + if(self_runechat && (audible_message_flags & EMOTE_MESSAGE) && runechat_prefs_check(src, audible_message_flags)) + create_chat_message(src, raw_message = raw_self_message, runechat_flags = audible_message_flags) ///Returns the client runechat visible messages preference according to the message type. /atom/proc/runechat_prefs_check(mob/target, visible_message_flags = NONE) @@ -689,7 +717,7 @@ if(!imagined_eye_contact && is_face_visible() && SEND_SIGNAL(examined_mob, COMSIG_MOB_EYECONTACT, src, FALSE) != COMSIG_BLOCK_EYECONTACT) var/msg = span_smallnotice("[src] makes eye contact with you.") - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), examined_mob, msg), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), examined_mob, msg), 0.3 SECONDS) /** * Called by using Activate Held Object with an empty hand/limb @@ -847,7 +875,6 @@ set name = "Cancel Camera View" set category = "OOC" reset_perspective(null) - unset_machine() //suppress the .click/dblclick macros so people can't use them to identify the location of items or aimbot /mob/verb/DisClick(argu = null as anything, sec = "" as text, number1 = 0 as num , number2 = 0 as num) @@ -959,7 +986,7 @@ selected_hand = (active_hand_index % held_items.len)+1 if(istext(selected_hand)) - selected_hand = lowertext(selected_hand) + selected_hand = LOWER_TEXT(selected_hand) if(selected_hand == "right" || selected_hand == "r") selected_hand = 2 if(selected_hand == "left" || selected_hand == "l") @@ -1144,6 +1171,10 @@ * * FORBID_TELEKINESIS_REACH - If telekinesis is forbidden to perform action from a distance (ex. canisters are blacklisted from telekinesis manipulation) * * ALLOW_SILICON_REACH - If silicons are allowed to perform action from a distance (silicons can operate airlocks from far away) * * ALLOW_RESTING - If resting on the floor is allowed to perform action () + * * ALLOW_VENTCRAWL - Mobs with ventcrawl traits can alt-click this to vent + * + * silence_adjacency: Sometimes we want to use this proc to check interaction without allowing it to throw errors for base case adjacency + * Alt click uses this, as otherwise you can detect what is interactable from a distance via the error message **/ /mob/proc/can_perform_action(atom/movable/target, action_bitflags) return @@ -1416,9 +1447,7 @@ regenerate_icons() if(href_list[VV_HK_PLAYER_PANEL]) - if(!check_rights(NONE)) - return - usr.client.holder.show_player_panel(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_player_panel, src) if(href_list[VV_HK_GODMODE]) if(!check_rights(R_ADMIN)) @@ -1426,34 +1455,22 @@ usr.client.cmd_admin_godmode(src) if(href_list[VV_HK_GIVE_MOB_ACTION]) - if(!check_rights(NONE)) - return - usr.client.give_mob_action(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_mob_action, src) if(href_list[VV_HK_REMOVE_MOB_ACTION]) - if(!check_rights(NONE)) - return - usr.client.remove_mob_action(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/remove_mob_action, src) if(href_list[VV_HK_GIVE_SPELL]) - if(!check_rights(NONE)) - return - usr.client.give_spell(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_spell, src) if(href_list[VV_HK_REMOVE_SPELL]) - if(!check_rights(NONE)) - return - usr.client.remove_spell(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/remove_spell, src) if(href_list[VV_HK_GIVE_DISEASE]) - if(!check_rights(NONE)) - return - usr.client.give_disease(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_disease, src) if(href_list[VV_HK_GIB]) - if(!check_rights(R_FUN)) - return - usr.client.cmd_admin_gib(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/gib_them, src) if(href_list[VV_HK_BUILDMODE]) if(!check_rights(R_BUILD)) @@ -1461,19 +1478,13 @@ togglebuildmode(src) if(href_list[VV_HK_DROP_ALL]) - if(!check_rights(NONE)) - return - usr.client.cmd_admin_drop_everything(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/drop_everything, src) if(href_list[VV_HK_DIRECT_CONTROL]) - if(!check_rights(NONE)) - return - usr.client.cmd_assume_direct_control(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_assume_direct_control, src) if(href_list[VV_HK_GIVE_DIRECT_CONTROL]) - if(!check_rights(NONE)) - return - usr.client.cmd_give_direct_control(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_give_direct_control, src) if(href_list[VV_HK_OFFER_GHOSTS]) if(!check_rights(NONE)) @@ -1579,9 +1590,6 @@ /mob/vv_edit_var(var_name, var_value) switch(var_name) - if(NAMEOF(src, machine)) - set_machine(var_value) - . = TRUE if(NAMEOF(src, focus)) set_focus(var_value) . = TRUE diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 7da01f047efe2..2a5be377ecd10 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -79,9 +79,6 @@ var/computer_id = null var/list/logging = list() - /// The machine the mob is interacting with (this is very bad old code btw) - var/obj/machinery/machine = null - /// Tick time the mob can next move var/next_move = null @@ -164,7 +161,7 @@ ///Allows a datum to intercept all click calls this mob is the source of var/datum/click_intercept - ///THe z level this mob is currently registered in + ///The z level this mob is currently registered in var/registered_z = null var/memory_throttle_time = 0 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 11140a7dde397..33a4ea12f753b 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -315,7 +315,7 @@ if(rebound.last_pushoff == world.time) continue if(continuous_move && !pass_allowed) - var/datum/move_loop/move/rebound_engine = SSmove_manager.processing_on(rebound, SSspacedrift) + var/datum/move_loop/move/rebound_engine = GLOB.move_manager.processing_on(rebound, SSspacedrift) // If you're moving toward it and you're both going the same direction, stop if(moving_direction == get_dir(src, pushover) && rebound_engine && moving_direction == rebound_engine.direction) continue @@ -540,7 +540,7 @@ to_chat(src, span_warning("You are not Superman.")) return balloon_alert(src, "moving up...") - if(!do_after(src, 1 SECONDS)) + if(!do_after(src, 1 SECONDS, hidden = TRUE)) return if(zMove(UP, z_move_flags = ZMOVE_FLIGHT_FLAGS|ZMOVE_FEEDBACK|ventcrawling_flag)) to_chat(src, span_notice("You move upwards.")) @@ -566,7 +566,7 @@ var/ventcrawling_flag = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING) ? ZMOVE_VENTCRAWLING : 0 balloon_alert(src, "moving down...") - if(!do_after(src, 1 SECONDS)) + if(!do_after(src, 1 SECONDS, hidden = TRUE)) return if(zMove(DOWN, z_move_flags = ZMOVE_FLIGHT_FLAGS|ZMOVE_FEEDBACK|ventcrawling_flag)) to_chat(src, span_notice("You move down.")) diff --git a/code/modules/mob/mob_say.dm b/code/modules/mob/mob_say.dm index 6b300b2938a3f..e2a840d569b64 100644 --- a/code/modules/mob/mob_say.dm +++ b/code/modules/mob/mob_say.dm @@ -66,17 +66,17 @@ to_chat(src, span_warning("\"[message]\"")) REPORT_CHAT_FILTER_TO_USER(src, filter_result) log_filter("IC", message, filter_result) - SSblackbox.record_feedback("tally", "ic_blocked_words", 1, lowertext(config.ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "ic_blocked_words", 1, LOWER_TEXT(config.ic_filter_regex.match)) return FALSE if(soft_filter_result && !filterproof) if(tgui_alert(usr,"Your message contains \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[soft_filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to say it?", "Soft Blocked Word", list("Yes", "No")) != "Yes") - SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, LOWER_TEXT(config.soft_ic_filter_regex.match)) log_filter("Soft IC", message, filter_result) return FALSE message_admins("[ADMIN_LOOKUPFLW(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Message: \"[message]\"") log_admin_private("[key_name(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Message: \"[message]\"") - SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, LOWER_TEXT(config.soft_ic_filter_regex.match)) log_filter("Soft IC (Passed)", message, filter_result) if(client && !(ignore_spam || forced)) @@ -217,7 +217,7 @@ if(stat == CONSCIOUS) //necessary indentation so it gets stripped of the semicolon anyway. mods[MODE_HEADSET] = TRUE else if((key in GLOB.department_radio_prefixes) && length(message) > length(key) + 1 && !mods[RADIO_EXTENSION]) - mods[RADIO_KEY] = lowertext(message[1 + length(key)]) + mods[RADIO_KEY] = LOWER_TEXT(message[1 + length(key)]) mods[RADIO_EXTENSION] = GLOB.department_radio_keys[mods[RADIO_KEY]] chop_to = length(key) + 2 else if(key == "," && !mods[LANGUAGE_EXTENSION]) diff --git a/code/modules/mob/mob_update_icons.dm b/code/modules/mob/mob_update_icons.dm index b8b84f8782afe..a355a385d9faa 100644 --- a/code/modules/mob/mob_update_icons.dm +++ b/code/modules/mob/mob_update_icons.dm @@ -7,21 +7,75 @@ ///Updates every item slot passed into it. /mob/proc/update_clothing(slot_flags) - return + if(slot_flags & ITEM_SLOT_BACK) + update_worn_back() + if(slot_flags & ITEM_SLOT_MASK) + update_worn_mask() + if(slot_flags & ITEM_SLOT_NECK) + update_worn_neck() + if(slot_flags & ITEM_SLOT_HANDCUFFED) + update_worn_handcuffs() + if(slot_flags & ITEM_SLOT_LEGCUFFED) + update_worn_legcuffs() + if(slot_flags & ITEM_SLOT_BELT) + update_worn_belt() + if(slot_flags & ITEM_SLOT_ID) + update_worn_id() + if(slot_flags & ITEM_SLOT_EARS) + update_worn_ears() + if(slot_flags & ITEM_SLOT_EYES) + update_worn_glasses() + if(slot_flags & ITEM_SLOT_GLOVES) + update_worn_gloves() + if(slot_flags & ITEM_SLOT_HEAD) + update_worn_head() + if(slot_flags & ITEM_SLOT_FEET) + update_worn_shoes() + if(slot_flags & ITEM_SLOT_OCLOTHING) + update_worn_oversuit() + if(slot_flags & ITEM_SLOT_ICLOTHING) + update_worn_undersuit() + if(slot_flags & ITEM_SLOT_SUITSTORE) + update_suit_storage() + if(slot_flags & (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET)) + update_pockets() + if(slot_flags & ITEM_SLOT_HANDS) + update_held_items() + +///Updates item slots obscured by this item (or using an override of flags to check) +/mob/proc/update_obscured_slots(obscured_flags) + if(obscured_flags & HIDEGLOVES) + update_worn_gloves(update_obscured = FALSE) + if(obscured_flags & HIDESUITSTORAGE) + update_suit_storage(update_obscured = FALSE) + if(obscured_flags & HIDEJUMPSUIT) + update_worn_undersuit(update_obscured = FALSE) + if(obscured_flags & HIDESHOES) + update_worn_shoes(update_obscured = FALSE) + if(obscured_flags & HIDEMASK) + update_worn_mask(update_obscured = FALSE) + if(obscured_flags & HIDEEARS) + update_worn_ears(update_obscured = FALSE) + if(obscured_flags & HIDEEYES) + update_worn_glasses(update_obscured = FALSE) + if(obscured_flags & HIDENECK) + update_worn_neck(update_obscured = FALSE) + if(obscured_flags & HIDEHEADGEAR) + update_worn_head(update_obscured = FALSE) /mob/proc/update_icons() return ///Updates the handcuff overlay & HUD element. -/mob/proc/update_worn_handcuffs() +/mob/proc/update_worn_handcuffs(update_obscured = FALSE) return ///Updates the legcuff overlay & HUD element. -/mob/proc/update_worn_legcuffs() +/mob/proc/update_worn_legcuffs(update_obscured = FALSE) return ///Updates the back overlay & HUD element. -/mob/proc/update_worn_back() +/mob/proc/update_worn_back(update_obscured = FALSE) return ///Updates the held items overlay(s) & HUD element. @@ -30,27 +84,27 @@ SEND_SIGNAL(src, COMSIG_MOB_UPDATE_HELD_ITEMS) ///Updates the mask overlay & HUD element. -/mob/proc/update_worn_mask() +/mob/proc/update_worn_mask(update_obscured = FALSE) return ///Updates the neck overlay & HUD element. -/mob/proc/update_worn_neck() +/mob/proc/update_worn_neck(update_obscured = FALSE) return ///Updates the oversuit overlay & HUD element. -/mob/proc/update_worn_oversuit() +/mob/proc/update_worn_oversuit(update_obscured = FALSE) return ///Updates the undersuit/uniform overlay & HUD element. -/mob/proc/update_worn_undersuit() +/mob/proc/update_worn_undersuit(update_obscured = FALSE) return ///Updates the belt overlay & HUD element. -/mob/proc/update_worn_belt() +/mob/proc/update_worn_belt(update_obscured = FALSE) return ///Updates the on-head overlay & HUD element. -/mob/proc/update_worn_head() +/mob/proc/update_worn_head(update_obscured = FALSE) return ///Updates every part of a carbon's body. Including parts, mutant parts, lips, underwear, and socks. @@ -61,29 +115,29 @@ return ///Updates the glasses overlay & HUD element. -/mob/proc/update_worn_glasses() +/mob/proc/update_worn_glasses(update_obscured = FALSE) return ///Updates the id overlay & HUD element. -/mob/proc/update_worn_id() +/mob/proc/update_worn_id(update_obscured = FALSE) return ///Updates the shoes overlay & HUD element. -/mob/proc/update_worn_shoes() +/mob/proc/update_worn_shoes(update_obscured = FALSE) return ///Updates the glasses overlay & HUD element. -/mob/proc/update_worn_gloves() +/mob/proc/update_worn_gloves(update_obscured = FALSE) return -///Updates the handcuff overlay & HUD element. -/mob/proc/update_suit_storage() +///Updates the suit storage overlay & HUD element. +/mob/proc/update_suit_storage(update_obscured = FALSE) return -///Updates the handcuff overlay & HUD element. +///Updates the pocket overlay & HUD element. /mob/proc/update_pockets() return -///Updates the handcuff overlay & HUD element. -/mob/proc/update_inv_ears() +///Updates the headset overlay & HUD element. +/mob/proc/update_worn_ears(update_obscured = FALSE) return diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index b71a2a46045c4..b4fbd713065aa 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -35,6 +35,7 @@ RemoveInvisibility(type) set_species(/datum/species/monkey) name = "monkey" + regenerate_icons() set_name() SEND_SIGNAL(src, COMSIG_HUMAN_MONKEYIZE) uncuff() @@ -280,6 +281,29 @@ qdel(src) return new_corgi +/** + * Turns the source atom into a crab crab, the peak of evolutionary design. + */ +/mob/living/carbon/human/proc/crabize() + if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) + return + ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT) + Paralyze(1, ignore_canstun = TRUE) + for(var/obj/item/objeto in src) + dropItemToGround(objeto) + regenerate_icons() + icon = null + SetInvisibility(INVISIBILITY_MAXIMUM) + + var/mob/living/basic/crab/new_crab = new (loc) + new_crab.set_combat_mode(TRUE) // snip snip + if(mind) + mind.transfer_to(new_crab) + + to_chat(new_crab, span_boldnotice("You have evolved into a crab!")) + qdel(src) + return new_crab + /mob/living/carbon/proc/gorillize() if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) return diff --git a/code/modules/mob_spawn/ghost_roles/golem_roles.dm b/code/modules/mob_spawn/ghost_roles/golem_roles.dm index b3475e9207f83..5fc643bffa622 100644 --- a/code/modules/mob_spawn/ghost_roles/golem_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/golem_roles.dm @@ -36,8 +36,7 @@ if(forced_name || !iscarbon(spawned_mob)) return ..() - var/datum/species/golem/golem_species = new() - forced_name = golem_species.random_name() + forced_name = generate_random_name_species_based(spawned_mob.gender, TRUE, species_type = /datum/species/golem) return ..() /obj/effect/mob_spawn/ghost_role/human/golem/special(mob/living/new_spawn, mob/mob_possessor) diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm index 208a74a3edbf5..53fa001097039 100644 --- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm @@ -194,9 +194,9 @@ /obj/structure/ash_walker_eggshell/Destroy() if(!egg) return ..() - var/mob/living/carbon/human/yolk = new /mob/living/carbon/human/(get_turf(src)) - yolk.fully_replace_character_name(null,random_unique_lizard_name(gender)) + var/mob/living/carbon/human/yolk = new(get_turf(src)) yolk.set_species(/datum/species/lizard/ashwalker) + yolk.fully_replace_character_name(null, yolk.generate_random_mob_name(TRUE)) yolk.underwear = "Nude" yolk.equipOutfit(/datum/outfit/ashwalker)//this is an authentic mess we're making yolk.update_body() @@ -235,7 +235,7 @@ /obj/effect/mob_spawn/ghost_role/human/ash_walker/special(mob/living/carbon/human/spawned_human) . = ..() - spawned_human.fully_replace_character_name(null,random_unique_lizard_name(gender)) + spawned_human.fully_replace_character_name(null, spawned_human.generate_random_mob_name(TRUE)) to_chat(spawned_human, "Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Invade the strange structure of the outsiders if you must. Do not cause unnecessary destruction, as littering the wastes with ugly wreckage is certain to not gain you favor. Glory to the Necropolis!") spawned_human.mind.add_antag_datum(/datum/antagonist/ashwalker, team) diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm index 086254aae3881..ad8c7e6a03ef0 100644 --- a/code/modules/mob_spawn/mob_spawn.dm +++ b/code/modules/mob_spawn/mob_spawn.dm @@ -78,7 +78,7 @@ if(skin_tone) spawned_human.skin_tone = skin_tone else - spawned_human.skin_tone = random_skin_tone() + spawned_human.skin_tone = pick(GLOB.skin_tones) spawned_human.update_body(is_creating = TRUE) /obj/effect/mob_spawn/proc/name_mob(mob/living/spawned_mob, forced_name) diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index 9e5b8ea5277ed..0d150c15fe61a 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -163,23 +163,23 @@ to_chat(wearer, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) if (ai_assistant) to_chat(ai_assistant, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("[boots] [active ? "relax their grip on your legs" : "seal around your feet"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) seal_part(boots, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("[gauntlets] [active ? "become loose around your fingers" : "tighten around your fingers and wrists"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) seal_part(gauntlets, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("[chestplate] [active ? "releases your chest" : "cinches tightly against your chest"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) seal_part(chestplate, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("[helmet] hisses [active ? "open" : "closed"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) seal_part(helmet, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("Systems [active ? "shut down. Parts unsealed. Goodbye" : "started up. Parts sealed. Welcome"], [wearer].")) if(ai_assistant) to_chat(ai_assistant, span_notice("SYSTEMS [active ? "DEACTIVATED. GOODBYE" : "ACTIVATED. WELCOME"]: \"[ai_assistant]\"")) @@ -212,21 +212,10 @@ part.heat_protection = NONE part.cold_protection = NONE part.alternate_worn_layer = mod_parts[part] - if(part == boots) - wearer.update_worn_shoes() - if(part == gauntlets) - wearer.update_worn_gloves() - if(part == chestplate) - wearer.update_worn_oversuit() - wearer.update_worn_undersuit() - if(part == helmet) - wearer.update_worn_head() - wearer.update_worn_mask() - wearer.update_worn_glasses() - wearer.update_body_parts() - // Close internal air tank if MOD helmet is unsealed and was the only breathing apparatus. - if (!seal && wearer?.invalid_internals()) - wearer.cutoff_internals() + wearer.update_clothing(part.slot_flags) + wearer.update_obscured_slots(part.visor_flags_inv) + if((part.clothing_flags & (MASKINTERNALS|HEADINTERNALS)) && wearer.invalid_internals()) + wearer.cutoff_internals() /// Finishes the suit's activation /obj/item/mod/control/proc/finish_activation(on) diff --git a/code/modules/mod/mod_core.dm b/code/modules/mod/mod_core.dm index 3a765e537ebfe..e62be77fe557e 100644 --- a/code/modules/mod/mod_core.dm +++ b/code/modules/mod/mod_core.dm @@ -262,7 +262,7 @@ /obj/item/mod/core/ethereal/charge_amount() var/obj/item/organ/internal/stomach/ethereal/charge_source = charge_source() - return charge_source?.crystal_charge || ETHEREAL_CHARGE_NONE + return charge_source?.cell.charge() || ETHEREAL_CHARGE_NONE /obj/item/mod/core/ethereal/max_charge_amount() return ETHEREAL_CHARGE_FULL @@ -382,8 +382,8 @@ light_power = 1.5 // Slightly better than the normal plasma core. // Not super sure if this should just be the same, but will see. - maxcharge = 15000 - charge = 15000 + maxcharge = 15 * STANDARD_CELL_CHARGE + charge = 15 * STANDARD_CELL_CHARGE /// The mob to be spawned by the core var/mob/living/spawned_mob_type = /mob/living/basic/butterfly/lavaland/temporary /// Max number of mobs it can spawn diff --git a/code/modules/mod/mod_link.dm b/code/modules/mod/mod_link.dm index 4323d7c00a6e0..40a0fb94f17f7 100644 --- a/code/modules/mod/mod_link.dm +++ b/code/modules/mod/mod_link.dm @@ -187,6 +187,8 @@ /obj/item/clothing/neck/link_scryer/attack_self(mob/user, modifiers) var/new_label = reject_bad_text(tgui_input_text(user, "Change the visible name", "Set Name", label, MAX_NAME_LEN)) + if(!user.is_holding(src)) + return if(!new_label) balloon_alert(user, "invalid name!") return @@ -197,7 +199,7 @@ /obj/item/clothing/neck/link_scryer/process(seconds_per_tick) if(!mod_link.link_call) return - cell.use(20 KILO WATTS * seconds_per_tick, force = TRUE) + cell.use(0.02 * STANDARD_CELL_RATE * seconds_per_tick, force = TRUE) /obj/item/clothing/neck/link_scryer/attackby(obj/item/attacked_by, mob/user, params) . = ..() diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 7cb117ac97b9b..c4c8839bd82a6 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -891,6 +891,7 @@ /obj/item/grown/bananapeel, /obj/item/reagent_containers/spray/waterflower, /obj/item/instrument, + /obj/item/toy/balloon_animal, ) skins = list( "cosmohonk" = list( diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 47f588eb80b9b..2789763e12cd2 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -212,6 +212,7 @@ /obj/item/mod/module/storage, /obj/item/mod/module/waddle, /obj/item/mod/module/bikehorn, + /obj/item/mod/module/balloon_advanced, ) /obj/item/mod/control/pre_equipped/traitor @@ -595,6 +596,7 @@ /obj/item/mod/module/storage/bluespace, /obj/item/mod/module/emp_shield/advanced, /obj/item/mod/module/welding, + /obj/item/mod/module/rad_protection, /obj/item/mod/module/stealth/ninja, /obj/item/mod/module/quick_carry/advanced, /obj/item/mod/module/magboot/advanced, diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index 2462f62a3d332..bd96c5aec5ff4 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -460,10 +460,10 @@ /obj/item/mod/module/plate_compression/on_install() old_size = mod.w_class - mod.w_class = new_size + mod.update_weight_class(new_size) /obj/item/mod/module/plate_compression/on_uninstall(deleting = FALSE) - mod.w_class = old_size + mod.update_weight_class(old_size) old_size = null if(!mod.loc) return diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index f80fd952cefe9..2aec3e361c4b4 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -506,9 +506,16 @@ if(!drain_power(use_energy_cost * levels)) return NONE new /obj/effect/temp_visual/mook_dust(fell_on) - mod.wearer.Stun(levels * 1 SECONDS) + + /// Boolean that tracks whether we fell more than one z-level. If TRUE, we stagger our wearer. + var/extreme_fall = FALSE + + if(levels >= 2) + extreme_fall = TRUE + mod.wearer.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * levels, 10 SECONDS) + mod.wearer.visible_message( - span_notice("[mod.wearer] lands on [fell_on] safely."), + span_notice("[mod.wearer] lands on [fell_on] safely[extreme_fall ? ", but barely manages to stay on [p_their()] feet." : ", and quite stylishly on [p_their()] feet" ]."), span_notice("[src] protects you from the damage!"), ) return ZIMPACT_CANCEL_DAMAGE|ZIMPACT_NO_MESSAGE|ZIMPACT_NO_SPIN diff --git a/code/modules/mod/modules/modules_medical.dm b/code/modules/mod/modules/modules_medical.dm index 6068b18fe1022..0e04de51c86cf 100644 --- a/code/modules/mod/modules/modules_medical.dm +++ b/code/modules/mod/modules/modules_medical.dm @@ -328,7 +328,7 @@ balloon_alert(mod.wearer, "interrupted!") return var/target_zones = body_zone2cover_flags(mod.wearer.zone_selected) - for(var/obj/item/clothing as anything in carbon_target.get_all_worn_items()) + for(var/obj/item/clothing as anything in carbon_target.get_equipped_items()) if(!clothing) continue var/shared_flags = target_zones & clothing.body_parts_covered diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index 868b4a79500a4..d52a5e1fb4c43 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -133,10 +133,6 @@ icon_state = "hacker" removable = FALSE incompatible_modules = list(/obj/item/mod/module/hacker) - /// Minimum amount of energy we can drain in a single drain action - var/mindrain = 200 KILO JOULES - /// Maximum amount of energy we can drain in a single drain action - var/maxdrain = 400 KILO JOULES /// Whether or not the communication console hack was used to summon another antagonist. var/communication_console_hack_success = FALSE /// How many times the module has been used to force open doors. diff --git a/code/modules/mod/modules/modules_service.dm b/code/modules/mod/modules/modules_service.dm index b4870a84ec503..be71c62180298 100644 --- a/code/modules/mod/modules/modules_service.dm +++ b/code/modules/mod/modules/modules_service.dm @@ -19,6 +19,31 @@ playsound(src, 'sound/items/bikehorn.ogg', 100, FALSE) drain_power(use_energy_cost) +///Advanced Balloon Blower - Blows a long balloon. +/obj/item/mod/module/balloon_advanced + name = "MOD advanced balloon blower module" + desc = "A relatively new piece of technology developed by finest clown engineers to make long balloons and balloon animals \ + at party-appropriate rate." + icon_state = "bloon" + module_type = MODULE_USABLE + complexity = 1 + use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 + incompatible_modules = list(/obj/item/mod/module/balloon_advanced) + cooldown_time = 15 SECONDS + +/obj/item/mod/module/balloon_advanced/on_use() + . = ..() + if(!.) + return + if(!do_after(mod.wearer, 15 SECONDS, target = mod)) + return FALSE + mod.wearer.adjustOxyLoss(20) + playsound(src, 'sound/items/modsuit/inflate_bloon.ogg', 50, TRUE) + var/obj/item/toy/balloon/long/l_balloon = new(get_turf(src)) + mod.wearer.put_in_hands(l_balloon) + drain_power(use_energy_cost) + + ///Microwave Beam - Microwaves items instantly. /obj/item/mod/module/microwave_beam name = "MOD microwave beam module" diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index da3e378ef30a5..e2a197a33900c 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -223,19 +223,18 @@ /obj/item/modular_computer/get_cell() return internal_cell -/obj/item/modular_computer/AltClick(mob/user) - . = ..() +/obj/item/modular_computer/click_alt(mob/user) if(issilicon(user)) - return FALSE - if(!user.can_perform_action(src)) - return FALSE + return NONE if(RemoveID(user)) - return TRUE + return CLICK_ACTION_SUCCESS if(istype(inserted_pai)) // Remove pAI remove_pai(user) - return TRUE + return CLICK_ACTION_SUCCESS + + return CLICK_ACTION_BLOCKING // Gets IDs/access levels from card slot. Would be useful when/if PDAs would become modular PCs. //guess what /obj/item/modular_computer/GetAccess() @@ -398,6 +397,9 @@ . += "Its identification card slot is currently occupied." . += span_info("Alt-click [src] to eject the identification card.") + if(internal_cell) + . += span_info("Right-click it with a screwdriver to eject the [internal_cell]") + /obj/item/modular_computer/examine_more(mob/user) . = ..() . += "Storage capacity: [used_capacity]/[max_capacity]GQ" @@ -901,20 +903,18 @@ update_appearance() return ITEM_INTERACT_SUCCESS -/obj/item/modular_computer/deconstruct(disassembled = TRUE) +/obj/item/modular_computer/atom_deconstruct(disassembled = TRUE) remove_pai() eject_aicard() - if(!(obj_flags & NO_DECONSTRUCTION)) - if (disassembled) - internal_cell?.forceMove(drop_location()) - computer_id_slot?.forceMove(drop_location()) - inserted_disk?.forceMove(drop_location()) - new /obj/item/stack/sheet/iron(drop_location(), steel_sheet_cost) - else - physical.visible_message(span_notice("\The [src] breaks apart!")) - new /obj/item/stack/sheet/iron(drop_location(), round(steel_sheet_cost * 0.5)) + if (disassembled) + internal_cell?.forceMove(drop_location()) + computer_id_slot?.forceMove(drop_location()) + inserted_disk?.forceMove(drop_location()) + new /obj/item/stack/sheet/iron(drop_location(), steel_sheet_cost) + else + physical.visible_message(span_notice("\The [src] breaks apart!")) + new /obj/item/stack/sheet/iron(drop_location(), round(steel_sheet_cost * 0.5)) relay_qdel() - return ..() // Ejects the inserted intellicard, if one exists. Used when the computer is deconstructed. /obj/item/modular_computer/proc/eject_aicard() diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm index d3b620cdfc9bf..b55fb6d2ee68a 100644 --- a/code/modules/modular_computers/computers/item/laptop.dm +++ b/code/modules/modular_computers/computers/item/laptop.dm @@ -91,25 +91,22 @@ toggle_open(user) -/obj/item/modular_computer/laptop/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return - if(screen_on) // Close it. - try_toggle_open(user) - else - return ..() +/obj/item/modular_computer/laptop/click_alt(mob/user) + if(!screen_on) + return CLICK_ACTION_BLOCKING + try_toggle_open(user) // Close it. + return CLICK_ACTION_SUCCESS /obj/item/modular_computer/laptop/proc/toggle_open(mob/living/user=null) if(screen_on) to_chat(user, span_notice("You close \the [src].")) slowdown = initial(slowdown) - w_class = initial(w_class) + update_weight_class(initial(w_class)) drag_slowdown = initial(drag_slowdown) else to_chat(user, span_notice("You open \the [src].")) slowdown = slowdown_open - w_class = w_class_open + update_weight_class(w_class_open) drag_slowdown = slowdown_open if(isliving(loc)) var/mob/living/localmob = loc diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm index 674520f1fb211..cbed5bef57f45 100644 --- a/code/modules/modular_computers/computers/item/pda.dm +++ b/code/modules/modular_computers/computers/item/pda.dm @@ -157,12 +157,6 @@ inserted_item = attacking_item playsound(src, 'sound/machines/pda_button1.ogg', 50, TRUE) -/obj/item/modular_computer/pda/AltClick(mob/user) - . = ..() - if(.) - return - - remove_pen(user) /obj/item/modular_computer/pda/CtrlClick(mob/user) . = ..() diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index 38989d45d2d51..ee6c9ee68f0af 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -230,15 +230,6 @@ /datum/computer_file/program/radar/lifeline, ) -/obj/item/modular_computer/pda/viro - name = "virology PDA" - greyscale_config = /datum/greyscale_config/tablet/stripe_double - greyscale_colors = "#FAFAFA#355FAC#57C451" - starting_programs = list( - /datum/computer_file/program/records/medical, - /datum/computer_file/program/robocontrol, - ) - /obj/item/modular_computer/pda/chemist name = "chemist PDA" greyscale_config = /datum/greyscale_config/tablet/stripe_thick diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm index 18f394d6ee0b2..0ec80da4bbb29 100644 --- a/code/modules/modular_computers/computers/machinery/console_presets.dm +++ b/code/modules/modular_computers/computers/machinery/console_presets.dm @@ -94,7 +94,7 @@ setup_starting_software() REGISTER_REQUIRED_MAP_ITEM(1, 1) if(department_type) - name = "[lowertext(initial(department_type.department_name))] [name]" + name = "[LOWER_TEXT(initial(department_type.department_name))] [name]" cpu.name = name /obj/machinery/modular_computer/preset/cargochat/proc/add_starting_software() @@ -105,7 +105,7 @@ return var/datum/computer_file/program/chatclient/chatprogram = cpu.find_file_by_name("ntnrc_client") - chatprogram.username = "[lowertext(initial(department_type.department_name))]_department" + chatprogram.username = "[LOWER_TEXT(initial(department_type.department_name))]_department" cpu.idle_threads += chatprogram var/datum/computer_file/program/department_order/orderprogram = cpu.find_file_by_name("dept_order") @@ -144,7 +144,7 @@ update_appearance(UPDATE_ICON) // Rest of the chat program setup is done in LateInit -/obj/machinery/modular_computer/preset/cargochat/cargo/LateInitialize() +/obj/machinery/modular_computer/preset/cargochat/cargo/post_machine_initialize() . = ..() var/datum/computer_file/program/chatclient/chatprogram = cpu.find_file_by_name("ntnrc_client") chatprogram.username = "cargo_requests_operator" diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm index 0e17f012453ab..6f0050534cce7 100644 --- a/code/modules/modular_computers/computers/machinery/modular_computer.dm +++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm @@ -116,11 +116,11 @@ SIGNAL_HANDLER return update_icon(updates) -/obj/machinery/modular_computer/AltClick(mob/user) - . = ..() +/obj/machinery/modular_computer/click_alt(mob/user) if(CPU_INTERACTABLE(user) || !can_interact(user)) - return - cpu.AltClick(user) + return NONE + cpu.click_alt(user) + return CLICK_ACTION_SUCCESS //ATTACK HAND IGNORING PARENT RETURN VALUE // On-click handling. Turns on the computer if it's off and opens the GUI. diff --git a/code/modules/modular_computers/file_system/programs/atmosscan.dm b/code/modules/modular_computers/file_system/programs/atmosscan.dm index 8f29af435108b..7e26087285971 100644 --- a/code/modules/modular_computers/file_system/programs/atmosscan.dm +++ b/code/modules/modular_computers/file_system/programs/atmosscan.dm @@ -44,7 +44,7 @@ var/list/airs = islist(mixture) ? mixture : list(mixture) var/list/new_gasmix_data = list() for(var/datum/gas_mixture/air as anything in airs) - var/mix_name = capitalize(lowertext(target.name)) + var/mix_name = capitalize(LOWER_TEXT(target.name)) if(airs.len != 1) //not a unary gas mixture mix_name += " - Node [airs.Find(air)]" new_gasmix_data += list(gas_mixture_parser(air, mix_name)) diff --git a/code/modules/modular_computers/file_system/programs/emojipedia.dm b/code/modules/modular_computers/file_system/programs/emojipedia.dm index 6e9bf56a381c8..10be69cc34976 100644 --- a/code/modules/modular_computers/file_system/programs/emojipedia.dm +++ b/code/modules/modular_computers/file_system/programs/emojipedia.dm @@ -14,7 +14,7 @@ /datum/computer_file/program/emojipedia/New() . = ..() // Sort the emoji list so it's easier to find things and we don't have to keep sorting on ui_data since the number of emojis can not change in-game. - emoji_list = sortTim(emoji_list, /proc/cmp_text_asc) + sortTim(emoji_list, /proc/cmp_text_asc) /datum/computer_file/program/emojipedia/ui_static_data(mob_user) var/list/data = list() diff --git a/code/modules/modular_computers/file_system/programs/secureye.dm b/code/modules/modular_computers/file_system/programs/secureye.dm index eee170e7c2cd9..aa3ed0e5828ce 100644 --- a/code/modules/modular_computers/file_system/programs/secureye.dm +++ b/code/modules/modular_computers/file_system/programs/secureye.dm @@ -70,7 +70,7 @@ // Convert networks to lowercase for(var/i in network) network -= i - network += lowertext(i) + network += LOWER_TEXT(i) // Initialize map objects cam_screen = new cam_screen.generate_view(map_name) diff --git a/code/modules/modular_computers/file_system/programs/techweb.dm b/code/modules/modular_computers/file_system/programs/techweb.dm index a72eef1bc9a7d..1394b9556a698 100644 --- a/code/modules/modular_computers/file_system/programs/techweb.dm +++ b/code/modules/modular_computers/file_system/programs/techweb.dm @@ -197,7 +197,7 @@ if(stored_research.can_afford(price)) user.investigate_log("researched [id]([json_encode(price)]) on techweb id [stored_research.id] via [computer].", INVESTIGATE_RESEARCH) if(istype(stored_research, /datum/techweb/science)) - SSblackbox.record_feedback("associative", "science_techweb_unlock", 1, list("id" = "[id]", "name" = tech_node.display_name, "price" = "[json_encode(price)]", "time" = SQLtime())) + SSblackbox.record_feedback("associative", "science_techweb_unlock", 1, list("id" = "[id]", "name" = tech_node.display_name, "price" = "[json_encode(price)]", "time" = ISOtime())) if(stored_research.research_node_id(id)) computer.say("Successfully researched [tech_node.display_name].") var/logname = "Unknown" @@ -218,7 +218,7 @@ logname = "[id_card_of_human_user.registered_name]" stored_research.research_logs += list(list( "node_name" = tech_node.display_name, - "node_cost" = price["General Research"], + "node_cost" = price[TECHWEB_POINT_TYPE_GENERIC], "node_researcher" = logname, "node_research_location" = "[get_area(computer)] ([user.x],[user.y],[user.z])", )) diff --git a/code/modules/movespeed/modifiers/innate.dm b/code/modules/movespeed/modifiers/innate.dm index 2a55b9db4d79d..94a3f7a2e791c 100644 --- a/code/modules/movespeed/modifiers/innate.dm +++ b/code/modules/movespeed/modifiers/innate.dm @@ -6,6 +6,10 @@ multiplicative_slowdown = 2 flags = IGNORE_NOSLOW +/datum/movespeed_modifier/snail + movetypes = ~FLYING + variable = TRUE + /datum/movespeed_modifier/bodypart movetypes = ~FLYING variable = TRUE diff --git a/code/modules/pai/card.dm b/code/modules/pai/card.dm index 77ca42aeebcee..ccf0bae5f042b 100644 --- a/code/modules/pai/card.dm +++ b/code/modules/pai/card.dm @@ -248,7 +248,7 @@ ignore_key = POLL_IGNORE_PAI, ) - addtimer(VARSET_CALLBACK(src, request_spam, FALSE), PAI_SPAM_TIME, TIMER_UNIQUE | TIMER_STOPPABLE | TIMER_CLIENT_TIME | TIMER_DELETE_ME) + addtimer(VARSET_CALLBACK(src, request_spam, FALSE), PAI_SPAM_TIME, TIMER_UNIQUE|TIMER_DELETE_ME) return TRUE /** diff --git a/code/modules/pai/door_jack.dm b/code/modules/pai/door_jack.dm index 182cdc1002718..36220ecfaced8 100644 --- a/code/modules/pai/door_jack.dm +++ b/code/modules/pai/door_jack.dm @@ -104,17 +104,17 @@ /mob/living/silicon/pai/proc/hack_door() if(!hacking_cable) return FALSE - if(!hacking_cable.machine) + if(!hacking_cable.hacking_machine) balloon_alert(src, "nothing connected") return FALSE playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, TRUE) balloon_alert(src, "overriding...") // Now begin hacking - if(!do_after(src, 15 SECONDS, hacking_cable.machine, timed_action_flags = NONE, progress = TRUE)) + if(!do_after(src, 15 SECONDS, hacking_cable.hacking_machine, timed_action_flags = NONE, progress = TRUE)) balloon_alert(src, "failed! retracting...") QDEL_NULL(hacking_cable) return FALSE - var/obj/machinery/door/door = hacking_cable.machine + var/obj/machinery/door/door = hacking_cable.hacking_machine balloon_alert(src, "success") door.open() QDEL_NULL(hacking_cable) diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm index 428bfd33fce41..2f050f11a5fb0 100644 --- a/code/modules/pai/pai.dm +++ b/code/modules/pai/pai.dm @@ -119,6 +119,9 @@ "mouse" = TRUE, "rabbit" = TRUE, "repairbot" = TRUE, + "kitten" = TRUE, + "puppy" = TRUE, + "spider" = TRUE, ) /// List of all available card overlays. var/static/list/possible_overlays = list( diff --git a/code/modules/paperwork/carbonpaper.dm b/code/modules/paperwork/carbonpaper.dm index 1dfe4ea782160..9c8ec0b8640f7 100644 --- a/code/modules/paperwork/carbonpaper.dm +++ b/code/modules/paperwork/carbonpaper.dm @@ -20,11 +20,11 @@ return . += span_notice("Right-click to tear off the carbon-copy (you must use both hands).") -/obj/item/paper/carbon/AltClick(mob/living/user) +/obj/item/paper/carbon/click_alt(mob/living/user) if(!copied) to_chat(user, span_notice("Take off the carbon copy first.")) - return - return ..() + return CLICK_ACTION_BLOCKING + return CLICK_ACTION_SUCCESS /obj/item/paper/carbon/proc/removecopy(mob/living/user) if(copied) diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index ffcaba5a02d6f..f4e6c7122468d 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -71,13 +71,16 @@ pen = null update_icon() -/obj/item/clipboard/AltClick(mob/user) - ..() - if(pen) - if(integrated_pen) - to_chat(user, span_warning("You can't seem to find a way to remove [src]'s [pen].")) - else - remove_pen(user) +/obj/item/clipboard/click_alt(mob/user) + if(isnull(pen)) + return CLICK_ACTION_BLOCKING + + if(integrated_pen) + to_chat(user, span_warning("You can't seem to find a way to remove [src]'s [pen].")) + return CLICK_ACTION_BLOCKING + + remove_pen(user) + return CLICK_ACTION_SUCCESS /obj/item/clipboard/update_overlays() . = ..() diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 140bdffcf8767..70e930ca31e3e 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -37,12 +37,10 @@ if(I.w_class < WEIGHT_CLASS_NORMAL) //there probably shouldn't be anything placed ontop of filing cabinets in a map that isn't meant to go in them I.forceMove(src) -/obj/structure/filingcabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 2) - for(var/obj/item/I in src) - I.forceMove(loc) - qdel(src) +/obj/structure/filingcabinet/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 2) + for(var/obj/item/obj in src) + obj.forceMove(loc) /obj/structure/filingcabinet/attackby(obj/item/P, mob/living/user, params) var/list/modifiers = params2list(params) @@ -97,7 +95,7 @@ if(istype(content) && in_range(src, usr)) usr.put_in_hands(content) icon_state = "[initial(icon_state)]-open" - addtimer(VARSET_CALLBACK(src, icon_state, initial(icon_state)), 5) + addtimer(VARSET_CALLBACK(src, icon_state, initial(icon_state)), 0.5 SECONDS) return TRUE /obj/structure/filingcabinet/attack_tk(mob/user) diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm index 033d7e67342de..88fc176801a7f 100644 --- a/code/modules/paperwork/handlabeler.dm +++ b/code/modules/paperwork/handlabeler.dm @@ -107,12 +107,9 @@ to_chat(user, span_notice("You turn off [src].")) return TRUE -/obj/item/hand_labeler/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . +/obj/item/hand_labeler/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(!istype(tool, /obj/item/hand_labeler_refill)) - return . + return NONE balloon_alert(user, "refilled") qdel(tool) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 5aac6d93bc3a3..5dd5515c47c4c 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -30,6 +30,7 @@ grind_results = list(/datum/reagent/cellulose = 3) color = COLOR_WHITE item_flags = SKIP_FANTASY_ON_SPAWN + interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING /// Lazylist of raw, unsanitised, unparsed text inputs that have been made to the paper. var/list/datum/paper_input/raw_text_inputs @@ -359,13 +360,13 @@ return TRUE return ..() -/obj/item/paper/AltClick(mob/living/user) - . = ..() - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) - return +/obj/item/paper/click_alt(mob/living/user) if(HAS_TRAIT(user, TRAIT_PAPER_MASTER)) - return make_plane(user, /obj/item/paperplane/syndicate) - return make_plane(user, /obj/item/paperplane) + make_plane(user, /obj/item/paperplane/syndicate) + return CLICK_ACTION_SUCCESS + make_plane(user, /obj/item/paperplane) + return CLICK_ACTION_SUCCESS + /** @@ -374,9 +375,9 @@ * * Arguments: * * mob/living/user - who's folding - * * obj/item/paperplane/plane_type - what it will be folded into (path) + * * plane_type - what it will be folded into (path) */ -/obj/item/paper/proc/make_plane(mob/living/user, obj/item/paperplane/plane_type = /obj/item/paperplane) +/obj/item/paper/proc/make_plane(mob/living/user, plane_type = /obj/item/paperplane) balloon_alert(user, "folded into a plane") user.temporarilyRemoveItemFromInventory(src) var/obj/item/paperplane/new_plane = new plane_type(loc, src) @@ -440,8 +441,8 @@ // Handle stamping items. if(writing_stats["interaction_mode"] == MODE_STAMPING) if(!user.can_read(src) || user.is_blind()) - //The paper's stampable window area is assumed approx 400x500 - add_stamp(writing_stats["stamp_class"], rand(0, 400), rand(0, 500), rand(0, 360), writing_stats["stamp_icon_state"]) + //The paper's stampable window area is assumed approx 300x400 + add_stamp(writing_stats["stamp_class"], rand(0, 300), rand(0, 400), rand(0, 360), writing_stats["stamp_icon_state"]) user.visible_message(span_notice("[user] blindly stamps [src] with \the [attacking_item]!")) to_chat(user, span_notice("You stamp [src] with \the [attacking_item] the best you can!")) playsound(src, 'sound/items/handling/standard_stamp.ogg', 50, vary = TRUE) @@ -453,6 +454,25 @@ ui_interact(user) return ..() +/// Secondary right click interaction to quickly stamp things +/obj/item/paper/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers) + var/list/writing_stats = tool.get_writing_implement_details() + + if(!length(writing_stats)) + return NONE + if(writing_stats["interaction_mode"] != MODE_STAMPING) + return NONE + if(!user.can_read(src) || user.is_blind()) // Just leftclick instead + return NONE + + add_stamp(writing_stats["stamp_class"], rand(1, 300), rand(1, 400), stamp_icon_state = writing_stats["stamp_icon_state"]) + user.visible_message( + span_notice("[user] quickly stamps [src] with [tool] without looking."), + span_notice("You quickly stamp [src] with [tool] without looking."), + ) + playsound(src, 'sound/items/handling/standard_stamp.ogg', 50, vary = TRUE) + + return ITEM_INTERACT_BLOCKING // Stop the UI from opening. /** * Attempts to ui_interact the paper to the given user, with some sanity checking * to make sure the camera still exists via the weakref and that this paper is still diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 9878249a6d12d..8e4fedf2fdad6 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -61,8 +61,7 @@ return CONTEXTUAL_SCREENTIP_SET -/obj/item/papercutter/deconstruct(disassembled) - ..() +/obj/item/papercutter/atom_deconstruct(disassembled) if(!disassembled) return @@ -142,16 +141,14 @@ return ..() -/obj/item/papercutter/AltClick(mob/user) - if(!user.Adjacent(src)) - return ..() - +/obj/item/papercutter/click_alt(mob/user) // can only remove one at a time; paper goes first, as its most likely what players will want to be taking out if(!isnull(stored_paper)) user.put_in_hands(stored_paper) else if(!isnull(stored_blade) && !blade_secured) user.put_in_hands(stored_blade) update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/papercutter/attack_hand_secondary(mob/user, list/modifiers) if(!stored_blade) diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 86db803322f05..3d7177dcb3e01 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -240,7 +240,7 @@ if(total_paper == 0) deconstruct(FALSE) -/obj/item/paper_bin/bundlenatural/deconstruct(disassembled) +/obj/item/paper_bin/bundlenatural/atom_deconstruct(disassembled) dump_contents(drop_location()) return ..() diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 2a9e78e248966..ec71eda2e46f4 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -44,6 +44,7 @@ dart_insert_projectile_icon_state, \ CALLBACK(src, PROC_REF(get_dart_var_modifiers))\ ) + AddElement(/datum/element/tool_renaming) RegisterSignal(src, COMSIG_DART_INSERT_ADDED, PROC_REF(on_inserted_into_dart)) RegisterSignal(src, COMSIG_DART_INSERT_REMOVED, PROC_REF(on_removed_from_dart)) @@ -179,6 +180,7 @@ if(current_skin) desc = "It's an expensive [current_skin] fountain pen. The nib is quite sharp." + /obj/item/pen/fountain/captain/proc/reskin_dart_insert(datum/component/dart_insert/insert_comp) if(!istype(insert_comp)) //You really shouldn't be sending this signal from anything other than a dart_insert component return @@ -209,54 +211,6 @@ log_combat(user, M, "stabbed", src) return TRUE -/obj/item/pen/afterattack(obj/O, mob/living/user, proximity) - . = ..() - - if (!proximity) - return . - - . |= AFTERATTACK_PROCESSED_ITEM - - //Changing name/description of items. Only works if they have the UNIQUE_RENAME object flag set - if(isobj(O) && (O.obj_flags & UNIQUE_RENAME)) - var/penchoice = tgui_input_list(user, "What would you like to edit?", "Pen Setting", list("Rename", "Description", "Reset")) - if(QDELETED(O) || !user.can_perform_action(O)) - return - if(penchoice == "Rename") - var/input = tgui_input_text(user, "What do you want to name [O]?", "Object Name", "[O.name]", MAX_NAME_LEN) - var/oldname = O.name - if(QDELETED(O) || !user.can_perform_action(O)) - return - if(input == oldname || !input) - to_chat(user, span_notice("You changed [O] to... well... [O].")) - else - O.AddComponent(/datum/component/rename, input, O.desc) - to_chat(user, span_notice("You have successfully renamed \the [oldname] to [O].")) - ADD_TRAIT(O, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) - O.update_appearance(UPDATE_ICON) - - if(penchoice == "Description") - var/input = tgui_input_text(user, "Describe [O]", "Description", "[O.desc]", 280) - var/olddesc = O.desc - if(QDELETED(O) || !user.can_perform_action(O)) - return - if(input == olddesc || !input) - to_chat(user, span_notice("You decide against changing [O]'s description.")) - else - O.AddComponent(/datum/component/rename, O.name, input) - to_chat(user, span_notice("You have successfully changed [O]'s description.")) - ADD_TRAIT(O, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) - O.update_appearance(UPDATE_ICON) - - if(penchoice == "Reset") - if(QDELETED(O) || !user.can_perform_action(O)) - return - - qdel(O.GetComponent(/datum/component/rename)) - to_chat(user, span_notice("You have successfully reset [O]'s name and description.")) - REMOVE_TRAIT(O, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) - O.update_appearance(UPDATE_ICON) - /obj/item/pen/get_writing_implement_details() return list( interaction_mode = MODE_WRITING, diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index e55225b1ca00a..0712e516de451 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -547,7 +547,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) toner_cartridge = object balloon_alert(user, "cartridge inserted") - else if(istype(object, /obj/item/areaeditor/blueprints)) + else if(istype(object, /obj/item/blueprints)) to_chat(user, span_warning("\The [object] is too large to put into the copier. You need to find something else to record the document.")) else if(istype(object, /obj/item/paperwork)) @@ -595,7 +595,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) else user.visible_message(span_warning("[user] starts putting [target] onto the photocopier!"), span_notice("You start putting [target] onto the photocopier...")) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(!target || QDELETED(target) || QDELETED(src) || !Adjacent(target)) //check if the photocopier/target still exists. return diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm index 56b7343995a2c..5c849f4a530cd 100644 --- a/code/modules/paperwork/ticketmachine.dm +++ b/code/modules/paperwork/ticketmachine.dm @@ -156,7 +156,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/ticket_machine, 32) machine.increment() if(isnull(machine.current_ticket)) to_chat(activator, span_notice("The button light indicates that there are no more tickets to be processed.")) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 1 SECONDS) /obj/machinery/ticket_machine/update_icon() . = ..() @@ -187,7 +187,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/ticket_machine, 32) to_chat(user, span_notice("[src] refuses [I]! There [max_number - ticket_number == 1 ? "is" : "are"] still [max_number - ticket_number] ticket\s left!")) return to_chat(user, span_notice("You start to refill [src]'s ticket holder (doing this will reset its ticket count!).")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) to_chat(user, span_notice("You insert [I] into [src] as it whirs nondescriptly.")) qdel(I) ticket_number = 0 diff --git a/code/modules/photography/_pictures.dm b/code/modules/photography/_pictures.dm index 45fa5654ad922..3d430439b908c 100644 --- a/code/modules/photography/_pictures.dm +++ b/code/modules/photography/_pictures.dm @@ -72,7 +72,6 @@ .["caption"] = caption .["pixel_size_x"] = psize_x .["pixel_size_y"] = psize_y - .["blueprints"] = has_blueprints .["logpath"] = logpath SET_SERIALIZATION_SEMVER(semvers, "1.0.0") @@ -93,8 +92,6 @@ id = input["id"] psize_x = input["pixel_size_x"] psize_y = input["pixel_size_y"] - if(input["blueprints"]) - has_blueprints = input["blueprints"] if(input["caption"]) caption = input["caption"] if(input["desc"]) diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index 0d5f37cb86737..35462a24d86db 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -72,10 +72,9 @@ picture_size_y = min(clamp(desired_y, picture_size_y_min, picture_size_y_max), CAMERA_PICTURE_SIZE_HARD_LIMIT) return TRUE -/obj/item/camera/AltClick(mob/user) - if(!user.can_perform_action(src)) - return +/obj/item/camera/click_alt(mob/user) adjust_zoom(user) + return CLICK_ACTION_SUCCESS /obj/item/camera/attack(mob/living/carbon/human/M, mob/user) return @@ -206,7 +205,7 @@ turfs += placeholder for(var/mob/M in placeholder) mobs += M - if(locate(/obj/item/areaeditor/blueprints) in placeholder) + if(locate(/obj/item/blueprints) in placeholder) blueprints = TRUE // do this before picture is taken so we can reveal revenants for the photo @@ -251,11 +250,11 @@ to_chat(user, span_notice("[pictures_left] photos left.")) if(can_customise) - var/customise = tgui_alert(user, "Do you want to customize the photo?", "Customization", list("Yes", "No")) + var/customise = user.is_holding(new_photo) && tgui_alert(user, "Do you want to customize the photo?", "Customization", list("Yes", "No")) if(customise == "Yes") - var/name1 = tgui_input_text(user, "Set a name for this photo, or leave blank.", "Name", max_length = 32) - var/desc1 = tgui_input_text(user, "Set a description to add to photo, or leave blank.", "Description", max_length = 128) - var/caption = tgui_input_text(user, "Set a caption for this photo, or leave blank.", "Caption", max_length = 256) + var/name1 = user.is_holding(new_photo) && tgui_input_text(user, "Set a name for this photo, or leave blank.", "Name", max_length = 32) + var/desc1 = user.is_holding(new_photo) && tgui_input_text(user, "Set a description to add to photo, or leave blank.", "Description", max_length = 128) + var/caption = user.is_holding(new_photo) && tgui_input_text(user, "Set a caption for this photo, or leave blank.", "Caption", max_length = 256) if(name1) picture.picture_name = name1 if(desc1) diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm index 4fbe3e034d88c..9efde283e0767 100644 --- a/code/modules/photography/photos/frame.dm +++ b/code/modules/photography/photos/frame.dm @@ -173,18 +173,15 @@ if(framed) . += framed -/obj/structure/sign/picture_frame/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/wallframe/picture/F = new /obj/item/wallframe/picture(loc) - if(framed) - F.displayed = framed - set_and_save_framed(null) - if(contents.len) - var/obj/item/I = pick(contents) - I.forceMove(F) - F.update_appearance() - qdel(src) - +/obj/structure/sign/picture_frame/atom_deconstruct(disassembled = TRUE) + var/obj/item/wallframe/picture/showcase = new /obj/item/wallframe/picture(loc) + if(framed) + showcase.displayed = framed + set_and_save_framed(null) + if(contents.len) + var/obj/item/I = pick(contents) + I.forceMove(showcase) + showcase.update_appearance() /obj/structure/sign/picture_frame/showroom name = "distinguished crew display" diff --git a/code/modules/plumbing/ducts.dm b/code/modules/plumbing/ducts.dm index 33073ae910f1f..a7990f65ce5b9 100644 --- a/code/modules/plumbing/ducts.dm +++ b/code/modules/plumbing/ducts.dm @@ -343,9 +343,13 @@ All the important duct code: /obj/item/stack/ducts/attack_self(mob/user) var/new_layer = tgui_input_list(user, "Select a layer", "Layer", GLOB.plumbing_layers, duct_layer) + if(!user.is_holding(src)) + return if(new_layer) duct_layer = new_layer var/new_color = tgui_input_list(user, "Select a color", "Color", GLOB.pipe_paint_colors, duct_color) + if(!user.is_holding(src)) + return if(new_color) duct_color = new_color add_atom_colour(GLOB.pipe_paint_colors[new_color], FIXED_COLOUR_PRIORITY) diff --git a/code/modules/plumbing/plumbers/_plumb_machinery.dm b/code/modules/plumbing/plumbers/_plumb_machinery.dm index dcfa5faac5cbb..e3f9486bee999 100644 --- a/code/modules/plumbing/plumbers/_plumb_machinery.dm +++ b/code/modules/plumbing/plumbers/_plumb_machinery.dm @@ -8,7 +8,8 @@ icon = 'icons/obj/pipes_n_cables/hydrochem/plumbers.dmi' icon_state = "pump" density = TRUE - idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 7.5 + processing_flags = START_PROCESSING_MANUALLY + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2.75 resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF ///Plumbing machinery is always gonna need reagents, so we might aswell put it here var/buffer = 50 @@ -26,18 +27,22 @@ . = ..() . += span_notice("The maximum volume display reads: [reagents.maximum_volume] units.") -/obj/machinery/plumbing/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation - /obj/machinery/plumbing/wrench_act(mob/living/user, obj/item/tool) - . = ..() - default_unfasten_wrench(user, tool) - return ITEM_INTERACT_SUCCESS + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) + if(anchored) + begin_processing() + else + end_processing() + return ITEM_INTERACT_SUCCESS /obj/machinery/plumbing/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) - to_chat(user, span_notice("You start furiously plunging [name].")) - if(do_after(user, 30, target = src)) - to_chat(user, span_notice("You finish plunging the [name].")) + user.balloon_alert_to_viewers("furiously plunging...") + if(do_after(user, 3 SECONDS, target = src)) + user.balloon_alert_to_viewers("finished plunging") reagents.expose(get_turf(src), TOUCH) //splash on the floor reagents.clear_reagents() diff --git a/code/modules/plumbing/plumbers/acclimator.dm b/code/modules/plumbing/plumbers/acclimator.dm index 79b525d3504da..014ff8499018d 100644 --- a/code/modules/plumbing/plumbers/acclimator.dm +++ b/code/modules/plumbing/plumbers/acclimator.dm @@ -14,7 +14,6 @@ icon_state = "acclimator" base_icon_state = "acclimator" buffer = 200 - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 ///towards wich temperature do we build? var/target_temperature = 300 @@ -32,7 +31,7 @@ AddComponent(/datum/component/plumbing/acclimator, bolt, layer) /obj/machinery/plumbing/acclimator/process(seconds_per_tick) - if(machine_stat & NOPOWER || !enabled || !reagents.total_volume || reagents.chem_temp == target_temperature) + if(!is_operational || !enabled || !reagents.total_volume || reagents.chem_temp == target_temperature) if(acclimate_state != NEUTRAL) acclimate_state = NEUTRAL update_appearance() diff --git a/code/modules/plumbing/plumbers/bottler.dm b/code/modules/plumbing/plumbers/bottler.dm index 1acbed37a74e0..5f63a3070bd2a 100644 --- a/code/modules/plumbing/plumbers/bottler.dm +++ b/code/modules/plumbing/plumbers/bottler.dm @@ -4,10 +4,8 @@ icon_state = "bottler" layer = ABOVE_ALL_MOB_LAYER plane = ABOVE_GAME_PLANE - reagent_flags = TRANSPARENT | DRAINABLE buffer = 100 - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 ///how much do we fill var/wanted_amount = 10 @@ -71,7 +69,7 @@ to_chat(user, span_notice(" The [src] will now fill for [wanted_amount]u.")) /obj/machinery/plumbing/bottler/process(seconds_per_tick) - if(machine_stat & NOPOWER) + if(!is_operational) return // Sanity check the result locations and stop processing if they don't exist if(goodspot == null || badspot == null || inputspot == null) diff --git a/code/modules/plumbing/plumbers/destroyer.dm b/code/modules/plumbing/plumbers/destroyer.dm index 5f81e24eaf24c..503b3e76223fd 100644 --- a/code/modules/plumbing/plumbers/destroyer.dm +++ b/code/modules/plumbing/plumbers/destroyer.dm @@ -3,7 +3,6 @@ desc = "Breaks down chemicals and annihilates them." icon_state = "disposal" pass_flags_self = PASSMACHINE | LETPASSTHROW // Small - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 ///we remove 5 reagents per second var/disposal_rate = 5 @@ -13,7 +12,7 @@ AddComponent(/datum/component/plumbing/simple_demand, bolt, layer) /obj/machinery/plumbing/disposer/process(seconds_per_tick) - if(machine_stat & NOPOWER) + if(!is_operational) return if(reagents.total_volume) if(icon_state != initial(icon_state) + "_working") //threw it here instead of update icon since it only has two states diff --git a/code/modules/plumbing/plumbers/fermenter.dm b/code/modules/plumbing/plumbers/fermenter.dm index 8800029779db3..ac421bce74002 100644 --- a/code/modules/plumbing/plumbers/fermenter.dm +++ b/code/modules/plumbing/plumbers/fermenter.dm @@ -6,7 +6,6 @@ plane = ABOVE_GAME_PLANE reagent_flags = TRANSPARENT | DRAINABLE buffer = 400 - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 ///input dir var/eat_dir = SOUTH @@ -36,7 +35,7 @@ /// uses fermentation proc similar to fermentation barrels /obj/machinery/plumbing/fermenter/proc/ferment(atom/AM) - if(machine_stat & NOPOWER) + if(!is_operational) return if(reagents.holder_full()) return diff --git a/code/modules/plumbing/plumbers/filter.dm b/code/modules/plumbing/plumbers/filter.dm index 633f70830f016..c4df35164f02c 100644 --- a/code/modules/plumbing/plumbers/filter.dm +++ b/code/modules/plumbing/plumbers/filter.dm @@ -30,7 +30,7 @@ data["right"] = english_right return data -/obj/machinery/plumbing/filter/ui_act(action, params) +/obj/machinery/plumbing/filter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -42,6 +42,8 @@ var/selected_reagent = tgui_input_list(usr, "Select [which] reagent", "Reagent", GLOB.name2reagent) if(!selected_reagent) return TRUE + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return FALSE var/datum/reagent/chem_id = GLOB.name2reagent[selected_reagent] if(!chem_id) @@ -69,5 +71,3 @@ if(english_right.Find(chem_name)) english_right -= chem_name right -= chem_id - - diff --git a/code/modules/plumbing/plumbers/grinder_chemical.dm b/code/modules/plumbing/plumbers/grinder_chemical.dm index ae356fef089ce..f75ec94f21c22 100644 --- a/code/modules/plumbing/plumbers/grinder_chemical.dm +++ b/code/modules/plumbing/plumbers/grinder_chemical.dm @@ -4,10 +4,8 @@ icon_state = "grinder_chemical" layer = ABOVE_ALL_MOB_LAYER plane = ABOVE_GAME_PLANE - reagent_flags = TRANSPARENT | DRAINABLE buffer = 400 - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 /obj/machinery/plumbing/grinder_chemical/Initialize(mapload, bolt, layer) . = ..() @@ -47,7 +45,7 @@ * * [AM][atom] - the atom to grind or juice */ /obj/machinery/plumbing/grinder_chemical/proc/grind(atom/AM) - if(machine_stat & NOPOWER) + if(!is_operational) return if(reagents.holder_full()) return @@ -56,11 +54,10 @@ var/obj/item/I = AM var/result - if(I.grind_results || I.juice_typepath) + if(I.grind_results) + result = I.grind(reagents, usr) + else + result = I.juice(reagents, usr) + if(result) use_energy(active_power_usage) - if(I.grind_results) - result = I.grind(reagents, usr) - else if (I.juice_typepath) - result = I.juice(reagents, usr) - if(result) - qdel(I) + qdel(I) diff --git a/code/modules/plumbing/plumbers/iv_drip.dm b/code/modules/plumbing/plumbers/iv_drip.dm index bbdb80f57b16d..6e2585553849c 100644 --- a/code/modules/plumbing/plumbers/iv_drip.dm +++ b/code/modules/plumbing/plumbers/iv_drip.dm @@ -6,6 +6,7 @@ base_icon_state = "plumb" density = TRUE use_internal_storage = TRUE + processing_flags = START_PROCESSING_MANUALLY /obj/machinery/iv_drip/plumbing/Initialize(mapload, bolt, layer) . = ..() @@ -23,18 +24,20 @@ return CONTEXTUAL_SCREENTIP_SET /obj/machinery/iv_drip/plumbing/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) - to_chat(user, span_notice("You start furiously plunging [name].")) - if(do_after(user, 30, target = src)) - to_chat(user, span_notice("You finish plunging the [name].")) + user.balloon_alert_to_viewers("furiously plunging...", "plunging iv drip...") + if(do_after(user, 3 SECONDS, target = src)) + user.balloon_alert_to_viewers("finished plunging") reagents.expose(get_turf(src), TOUCH) //splash on the floor reagents.clear_reagents() -/obj/machinery/iv_drip/plumbing/can_use_alt_click(mob/user) - return FALSE //Alt click is used for rotation - /obj/machinery/iv_drip/plumbing/wrench_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) + if(anchored) + begin_processing() + else + end_processing() return ITEM_INTERACT_SUCCESS - -/obj/machinery/iv_drip/plumbing/on_deconstruction(disassembled) - qdel(src) diff --git a/code/modules/plumbing/plumbers/pill_press.dm b/code/modules/plumbing/plumbers/pill_press.dm index 2db9222e7c7f6..945908342a6a6 100644 --- a/code/modules/plumbing/plumbers/pill_press.dm +++ b/code/modules/plumbing/plumbers/pill_press.dm @@ -10,7 +10,6 @@ name = "chemical press" desc = "A press that makes pills, patches and bottles." icon_state = "pill_press" - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 /// current operating product (pills or patches) var/product = "pill" @@ -74,7 +73,7 @@ return container /obj/machinery/plumbing/pill_press/process(seconds_per_tick) - if(machine_stat & NOPOWER) + if(!is_operational) return //shift & check to account for floating point inaccuracies diff --git a/code/modules/plumbing/plumbers/plumbing_buffer.dm b/code/modules/plumbing/plumbers/plumbing_buffer.dm index 7b3ef306d0419..06aad506ff035 100644 --- a/code/modules/plumbing/plumbers/plumbing_buffer.dm +++ b/code/modules/plumbing/plumbers/plumbing_buffer.dm @@ -68,7 +68,7 @@ neighbour.attempt_connect() //technically this would runtime if you made about 200~ buffers add_overlay(icon_state + "_alert") - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, cut_overlay), icon_state + "_alert"), 20) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, cut_overlay), icon_state + "_alert"), 2 SECONDS) /obj/machinery/plumbing/buffer/attack_hand_secondary(mob/user, modifiers) . = ..() diff --git a/code/modules/plumbing/plumbers/reaction_chamber.dm b/code/modules/plumbing/plumbers/reaction_chamber.dm index 72caa60376745..59fcfaf7caf91 100644 --- a/code/modules/plumbing/plumbers/reaction_chamber.dm +++ b/code/modules/plumbing/plumbers/reaction_chamber.dm @@ -9,7 +9,6 @@ icon_state = "reaction_chamber" buffer = 200 reagent_flags = TRANSPARENT | NO_REACT - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 /** * list of set reagents that the reaction_chamber allows in, and must all be present before mixing is enabled. @@ -49,23 +48,18 @@ return NONE /obj/machinery/plumbing/reaction_chamber/process(seconds_per_tick) - //half the power for getting reagents in - var/power_usage = active_power_usage * 0.5 + if(!is_operational || !reagents.total_volume) + return if(!emptying || reagents.is_reacting) //adjust temperature of final solution - var/temp_diff = target_temperature - reagents.chem_temp - if(abs(temp_diff) > 0.01) //if we are not close enough keep going - reagents.adjust_thermal_energy(temp_diff * HEATER_COEFFICIENT * seconds_per_tick * SPECIFIC_HEAT_DEFAULT * reagents.total_volume) //keep constant with chem heater + var/energy = (target_temperature - reagents.chem_temp) * HEATER_COEFFICIENT * seconds_per_tick * reagents.heat_capacity() + reagents.adjust_thermal_energy(energy) + use_energy(active_power_usage + abs(ROUND_UP(energy) / 120)) //do other stuff with final solution handle_reagents(seconds_per_tick) - //full power for doing reactions - power_usage *= 2 - - use_energy(power_usage * seconds_per_tick) - ///For subtypes that want to do additional reagent handling /obj/machinery/plumbing/reaction_chamber/proc/handle_reagents(seconds_per_tick) return @@ -107,6 +101,8 @@ var/selected_reagent = tgui_input_list(ui.user, "Select reagent", "Reagent", GLOB.name2reagent) if(!selected_reagent) return FALSE + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return FALSE var/datum/reagent/input_reagent = GLOB.name2reagent[selected_reagent] if(!input_reagent) diff --git a/code/modules/plumbing/plumbers/splitters.dm b/code/modules/plumbing/plumbers/splitters.dm index de27922700971..b87a07d694cc4 100644 --- a/code/modules/plumbing/plumbers/splitters.dm +++ b/code/modules/plumbing/plumbers/splitters.dm @@ -3,7 +3,6 @@ name = "chemical splitter" desc = "A chemical splitter for smart chemical factorization. Waits till a set of conditions is met and then stops all input and splits the buffer evenly or other in two ducts." icon_state = "splitter" - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 buffer = 100 density = FALSE diff --git a/code/modules/plumbing/plumbers/synthesizer.dm b/code/modules/plumbing/plumbers/synthesizer.dm index d7a5d83a2518e..0399ad85f3c04 100644 --- a/code/modules/plumbing/plumbers/synthesizer.dm +++ b/code/modules/plumbing/plumbers/synthesizer.dm @@ -4,7 +4,6 @@ desc = "Produces a single chemical at a given volume. Must be plumbed. Most effective when working in unison with other chemical synthesizers, heaters and filters." icon_state = "synthesizer" icon = 'icons/obj/pipes_n_cables/hydrochem/plumbers.dmi' - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 ///Amount we produce for every process. Ideally keep under 5 since thats currently the standard duct capacity var/amount = 1 @@ -49,7 +48,7 @@ dispensable_reagents = default_reagents /obj/machinery/plumbing/synthesizer/process(seconds_per_tick) - if(machine_stat & NOPOWER || !reagent_id || !amount) + if(!is_operational || !reagent_id || !amount) return //otherwise we get leftovers, and we need this to be precise @@ -57,7 +56,7 @@ return reagents.add_reagent(reagent_id, amount) - use_energy(active_power_usage) + use_energy(active_power_usage * seconds_per_tick) /obj/machinery/plumbing/synthesizer/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) diff --git a/code/modules/plumbing/plumbers/teleporter.dm b/code/modules/plumbing/plumbers/teleporter.dm index e1aa26532dce8..df79220d15a8c 100644 --- a/code/modules/plumbing/plumbers/teleporter.dm +++ b/code/modules/plumbing/plumbers/teleporter.dm @@ -77,7 +77,7 @@ return TRUE /obj/machinery/plumbing/receiver/process(seconds_per_tick) - if(machine_stat & NOPOWER || panel_open) + if(!is_operational || panel_open) return if(senders.len) diff --git a/code/modules/plumbing/plumbers/vatgrower.dm b/code/modules/plumbing/plumbers/vatgrower.dm index ab2a732c9c523..7327a648dadce 100644 --- a/code/modules/plumbing/plumbers/vatgrower.dm +++ b/code/modules/plumbing/plumbers/vatgrower.dm @@ -27,7 +27,7 @@ return NONE ///When we process, we make use of our reagents to try and feed the samples we have. -/obj/machinery/plumbing/growing_vat/process() +/obj/machinery/plumbing/growing_vat/process(seconds_per_tick) if(!is_operational) return if(!biological_sample) @@ -37,6 +37,7 @@ return playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) audible_message(pick(list(span_notice("[src] grumbles!"), span_notice("[src] makes a splashing noise!"), span_notice("[src] sloshes!")))) + use_energy(active_power_usage * seconds_per_tick) ///Handles the petri dish depositing into the vat. /obj/machinery/plumbing/growing_vat/attacked_by(obj/item/I, mob/living/user) diff --git a/code/modules/power/apc/apc_attack.dm b/code/modules/power/apc/apc_attack.dm index c9f04adea862a..acaaac1bd3eec 100644 --- a/code/modules/power/apc/apc_attack.dm +++ b/code/modules/power/apc/apc_attack.dm @@ -11,7 +11,7 @@ if(!istype(maybe_ethereal_stomach)) togglelock(user) else - if(maybe_ethereal_stomach.crystal_charge >= ETHEREAL_CHARGE_NORMAL) + if(maybe_ethereal_stomach.cell.charge() >= ETHEREAL_CHARGE_NORMAL) togglelock(user) ethereal_interact(user, modifiers) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN @@ -29,19 +29,20 @@ return var/charge_limit = ETHEREAL_CHARGE_DANGEROUS - APC_POWER_GAIN var/obj/item/organ/internal/stomach/ethereal/stomach = maybe_stomach + var/obj/item/stock_parts/cell/stomach_cell = stomach.cell if(!((stomach?.drain_time < world.time) && LAZYACCESS(modifiers, RIGHT_CLICK))) return if(ethereal.combat_mode) if(cell.charge <= (cell.maxcharge / 2)) // ethereals can't drain APCs under half charge, this is so that they are forced to look to alternative power sources if the station is running low addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "safeties prevent draining!"), alert_timer_duration) return - if(stomach.crystal_charge > charge_limit) + if(stomach_cell.charge() > charge_limit) addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "charge is full!"), alert_timer_duration) return stomach.drain_time = world.time + APC_DRAIN_TIME addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "draining power"), alert_timer_duration) while(do_after(user, APC_DRAIN_TIME, target = src)) - if(cell.charge <= (cell.maxcharge / 2) || (stomach.crystal_charge > charge_limit)) + if(cell.charge <= (cell.maxcharge / 2) || (stomach_cell.charge() > charge_limit)) return balloon_alert(ethereal, "received charge") stomach.adjust_charge(APC_POWER_GAIN) @@ -51,20 +52,19 @@ if(cell.charge >= cell.maxcharge - APC_POWER_GAIN) addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "APC can't receive more power!"), alert_timer_duration) return - if(stomach.crystal_charge < APC_POWER_GAIN) + if(stomach_cell.charge() < APC_POWER_GAIN) addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "charge is too low!"), alert_timer_duration) return stomach.drain_time = world.time + APC_DRAIN_TIME addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "transfering power"), alert_timer_duration) if(!do_after(user, APC_DRAIN_TIME, target = src)) return - if((cell.charge >= (cell.maxcharge - APC_POWER_GAIN)) || (stomach.crystal_charge < APC_POWER_GAIN)) + if((cell.charge >= (cell.maxcharge - APC_POWER_GAIN)) || (stomach_cell.charge() < APC_POWER_GAIN)) balloon_alert(ethereal, "can't transfer power!") return if(istype(stomach)) while(do_after(user, APC_DRAIN_TIME, target = src)) balloon_alert(ethereal, "transferred power") - stomach.adjust_charge(-APC_POWER_GAIN) cell.give(-stomach.adjust_charge(-APC_POWER_GAIN)) else balloon_alert(ethereal, "can't transfer power!") @@ -110,13 +110,17 @@ return TRUE if(!HAS_SILICON_ACCESS(user)) return TRUE + . = TRUE var/mob/living/silicon/ai/AI = user var/mob/living/silicon/robot/robot = user - if(aidisabled || malfhack && istype(malfai) && ((istype(AI) && (malfai != AI && malfai != AI.parent)) || (istype(robot) && (robot in malfai.connected_robots)))) - if(!loud) - balloon_alert(user, "it's disabled!") - return FALSE - return TRUE + if(istype(AI) || istype(robot)) + if(aidisabled) + . = FALSE + else if(istype(malfai) && (malfai != AI || !(robot in malfai.connected_robots))) + . = FALSE + if (!. && !loud) + balloon_alert(user, "it's disabled!") + return . /obj/machinery/power/apc/proc/set_broken() if(machine_stat & BROKEN) diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index a90d1cd388a5a..7e63aff7cbe1b 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -5,6 +5,9 @@ // may be opened to change power cell // three different channels (lighting/equipment/environ) - may each be set to on, off, or auto +///Cap for how fast cells charge, as a percentage per second (.01 means cellcharge is capped to 1% per second) +#define CHARGELEVEL 0.01 + /obj/machinery/power/apc name = "area power controller" desc = "A control terminal for the area's electrical systems." @@ -17,6 +20,7 @@ damage_deflection = 10 resistance_flags = FIRE_PROOF interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON + interaction_flags_click = ALLOW_SILICON_REACH processing_flags = START_PROCESSING_MANUALLY ///Range of the light emitted when on @@ -208,7 +212,7 @@ //Make the apc visually interactive register_context() - addtimer(CALLBACK(src, PROC_REF(update)), 5) + addtimer(CALLBACK(src, PROC_REF(update)), 0.5 SECONDS) RegisterSignal(SSdcs, COMSIG_GLOB_GREY_TIDE, PROC_REF(grey_tide)) RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) update_appearance() @@ -227,8 +231,11 @@ find_and_hang_on_wall() /obj/machinery/power/apc/Destroy() - if(malfai && operating) - malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10, 0, 1000) + if(malfai) + if(operating) + malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10, 0, 1000) + malfai.hacked_apcs -= src + malfai = null disconnect_from_area() QDEL_NULL(alarm_manager) if(occupier) @@ -243,6 +250,7 @@ /obj/machinery/power/apc/proc/on_saboteur(datum/source, disrupt_duration) SIGNAL_HANDLER + disrupt_duration *= 0.1 // so, turns out, failure timer is in seconds, not deciseconds; without this, disruptions last 10 times as long as they probably should energy_fail(disrupt_duration) return COMSIG_SABOTEUR_SUCCESS @@ -582,7 +590,7 @@ // now trickle-charge the cell if(chargemode && operating && excess && cell.used_charge()) // Max charge is capped to % per second constant. - lastused_total += charge_cell(min(cell.chargerate, cell.maxcharge * GLOB.CHARGELEVEL) * seconds_per_tick, cell = cell, grid_only = TRUE, channel = AREA_USAGE_APC_CHARGE) + lastused_total += charge_cell(min(cell.chargerate, cell.maxcharge * CHARGELEVEL) * seconds_per_tick, cell = cell, grid_only = TRUE, channel = AREA_USAGE_APC_CHARGE) charging = APC_CHARGING // show cell as fully charged if so @@ -626,7 +634,7 @@ /obj/machinery/power/apc/proc/overload_lighting() if(!operating || shorted) return - if(cell && cell.use(20 KILO JOULES)) + if(cell && cell.use(0.02 * STANDARD_CELL_CHARGE)) INVOKE_ASYNC(src, PROC_REF(break_lights)) /obj/machinery/power/apc/proc/break_lights() @@ -697,6 +705,8 @@ /obj/machinery/power/apc/proc/draw_energy(amount) var/grid_used = min(terminal?.surplus(), amount) terminal?.add_load(grid_used) + if(QDELETED(cell)) + return grid_used var/cell_used = 0 if(amount > grid_used) cell_used += cell.use(amount - grid_used, force = TRUE) @@ -720,3 +730,5 @@ return round(energy_to_power(required_joules / trickle_charge_power) * SSmachines.wait + SSmachines.wait, SSmachines.wait) return null + +#undef CHARGELEVEL diff --git a/code/modules/power/apc/apc_malf.dm b/code/modules/power/apc/apc_malf.dm index 62134de146e82..f4c27e15a4067 100644 --- a/code/modules/power/apc/apc_malf.dm +++ b/code/modules/power/apc/apc_malf.dm @@ -1,7 +1,7 @@ /obj/machinery/power/apc/proc/get_malf_status(mob/living/silicon/ai/malf) if(!istype(malf) || !malf.malf_picker) return APC_AI_NO_MALF - if(malfai != (malf.parent || malf)) + if(malfai != malf) return APC_AI_NO_HACK if(occupier == malf) return APC_AI_HACK_SHUNT_HERE @@ -12,7 +12,7 @@ /obj/machinery/power/apc/proc/malfhack(mob/living/silicon/ai/malf) if(!istype(malf)) return - if(get_malf_status(malf) != 1) + if(get_malf_status(malf) != APC_AI_NO_HACK) return if(malf.malfhacking) to_chat(malf, span_warning("You are already hacking an APC!")) @@ -37,18 +37,16 @@ if(!is_station_level(z)) return malf.ShutOffDoomsdayDevice() - occupier = new /mob/living/silicon/ai(src, malf.laws.copy_lawset(), malf) //DEAR GOD WHY? //IKR???? - occupier.adjustOxyLoss(malf.getOxyLoss()) + occupier = malf + if (isturf(malf.loc)) // create a deactivated AI core if the AI isn't coming from an emergency mech shunt + malf.linked_core = new /obj/structure/ai_core/deactivated + malf.linked_core.remote_ai = malf // note that we do not set the deactivated core's core_mmi.brainmob + malf.forceMove(src) // move INTO the APC, not to its tile if(!findtext(occupier.name, "APC Copy")) occupier.name = "[malf.name] APC Copy" - if(malf.parent) - occupier.parent = malf.parent - else - occupier.parent = malf malf.shunted = TRUE occupier.eyeobj.name = "[occupier.name] (AI Eye)" - if(malf.parent) - qdel(malf) + occupier.eyeobj.forceMove(src.loc) for(var/obj/item/pinpointer/nuke/disk_pinpointers in GLOB.pinpointer_list) disk_pinpointers.switch_mode_to(TRACK_MALF_AI) //Pinpointer will track the shunted AI var/datum/action/innate/core_return/return_action = new @@ -58,12 +56,11 @@ /obj/machinery/power/apc/proc/malfvacate(forced) if(!occupier) return - if(occupier.parent && occupier.parent.stat != DEAD) - occupier.mind.transfer_to(occupier.parent) - occupier.parent.shunted = FALSE - occupier.parent.setOxyLoss(occupier.getOxyLoss()) - occupier.parent.cancel_camera() - qdel(occupier) + if(occupier.linked_core) + occupier.shunted = FALSE + occupier.forceMove(occupier.linked_core.loc) + qdel(occupier.linked_core) + occupier.cancel_camera() return to_chat(occupier, span_danger("Primary core damaged, unable to return core processes.")) if(forced) @@ -89,7 +86,7 @@ if(!occupier.mind || !occupier.client) to_chat(user, span_warning("[occupier] is either inactive or destroyed!")) return FALSE - if(!occupier.parent.stat) + if(occupier.linked_core) //if they have an active linked_core, they can't be transferred from an APC to_chat(user, span_warning("[occupier] is refusing all attempts at transfer!") ) return FALSE if(transfer_in_progress) @@ -116,7 +113,7 @@ return FALSE to_chat(user, span_notice("AI accepted request. Transferring stored intelligence to [card]...")) to_chat(occupier, span_notice("Transfer starting. You will be moved to [card] shortly.")) - if(!do_after(user, 50, target = src)) + if(!do_after(user, 5 SECONDS, target = src)) to_chat(occupier, span_warning("[user] was interrupted! Transfer canceled.")) transfer_in_progress = FALSE return FALSE @@ -127,7 +124,7 @@ to_chat(occupier, span_notice("Transfer complete! You've been stored in [user]'s [card.name].")) occupier.forceMove(card) card.AI = occupier - occupier.parent.shunted = FALSE + occupier.shunted = FALSE occupier.cancel_camera() occupier = null transfer_in_progress = FALSE diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index 8ae76fe01549b..0116205fdd4ca 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -1,10 +1,7 @@ //attack with an item - open/close cover, insert cell, or (un)lock interface -/obj/machinery/power/apc/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - . = ..() - if(.) - return . - +/obj/machinery/power/apc/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = NONE if(HAS_TRAIT(tool, TRAIT_APC_SHOCKING)) . = fork_outlet_act(user, tool) if(.) @@ -17,7 +14,7 @@ if(istype(tool, /obj/item/stock_parts/cell)) . = cell_act(user, tool) else if(istype(tool, /obj/item/stack/cable_coil)) - . = cable_act(user, tool, is_right_clicking) + . = cable_act(user, tool, LAZYACCESS(modifiers, RIGHT_CLICK)) else if(istype(tool, /obj/item/electronics/apc)) . = electronics_act(user, tool) else if(istype(tool, /obj/item/electroadaptive_pseudocircuit)) @@ -26,7 +23,7 @@ . = wallframe_act(user, tool) if(.) return . - + if(panel_open && !opened && is_wire_tool(tool)) wires.interact(user) return ITEM_INTERACT_SUCCESS @@ -73,44 +70,59 @@ update_appearance() return ITEM_INTERACT_SUCCESS -/// Called when we interact with the APC with a cable, attempts to wire the APC and create a terminal -/obj/machinery/power/apc/proc/cable_act(mob/living/user, obj/item/stack/cable_coil/installing_cable, is_right_clicking) +/// Checks if we can place a terminal on the APC +/obj/machinery/power/apc/proc/can_place_terminal(mob/living/user, obj/item/stack/cable_coil/installing_cable, silent = TRUE) if(!opened) - return NONE - + return FALSE var/turf/host_turf = get_turf(src) - if(!host_turf) - CRASH("cable_act on APC when it's not on a turf") if(host_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) - balloon_alert(user, "remove the floor plating!") - return ITEM_INTERACT_BLOCKING - if(terminal) - balloon_alert(user, "already wired!") - return ITEM_INTERACT_BLOCKING + if(!silent && user) + balloon_alert(user, "remove the floor plating!") + return FALSE + if(!isnull(terminal)) + if(!silent && user) + balloon_alert(user, "already wired!") + return FALSE if(!has_electronics) - balloon_alert(user, "no board to wire!") - return ITEM_INTERACT_BLOCKING - + if(!silent && user) + balloon_alert(user, "no board to wire!") + return FALSE + if(panel_open) + if(!silent && user) + balloon_alert(user, "wires prevent placing a terminal!") + return FALSE if(installing_cable.get_amount() < 10) - balloon_alert(user, "need ten lengths of cable!") + if(!silent && user) + balloon_alert(user, "need ten lengths of cable!") + return FALSE + return TRUE + +/// Called when we interact with the APC with a cable, attempts to wire the APC and create a terminal +/obj/machinery/power/apc/proc/cable_act(mob/living/user, obj/item/stack/cable_coil/installing_cable, is_right_clicking) + if(!opened) + return NONE + if(!can_place_terminal(user, installing_cable, silent = FALSE)) return ITEM_INTERACT_BLOCKING var/terminal_cable_layer = cable_layer // Default to machine's cable layer if(is_right_clicking) var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer) - if(isnull(choice)) + if(isnull(choice) \ + || !user.is_holding(installing_cable) \ + || !user.Adjacent(src) \ + || user.incapacitated() \ + || !can_place_terminal(user, installing_cable, silent = TRUE) \ + ) return ITEM_INTERACT_BLOCKING terminal_cable_layer = GLOB.cable_name_to_layer[choice] - user.visible_message(span_notice("[user.name] adds cables to the APC frame.")) - balloon_alert(user, "adding cables to the frame...") - playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + user.visible_message(span_notice("[user.name] starts addding cables to the APC frame.")) + balloon_alert(user, "adding cables...") + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) - if(!do_after(user, 20, target = src)) - return ITEM_INTERACT_BLOCKING - if(installing_cable.get_amount() < 10 || !installing_cable) + if(!do_after(user, 2 SECONDS, target = src)) return ITEM_INTERACT_BLOCKING - if(terminal || !opened || !has_electronics) + if(!can_place_terminal(user, installing_cable, silent = TRUE)) return ITEM_INTERACT_BLOCKING var/turf/our_turf = get_turf(src) var/obj/structure/cable/cable_node = our_turf.get_cable_node(terminal_cable_layer) @@ -118,7 +130,8 @@ do_sparks(5, TRUE, src) return ITEM_INTERACT_BLOCKING installing_cable.use(10) - balloon_alert(user, "cables added to the frame") + user.visible_message(span_notice("[user.name] adds cables to the APC frame.")) + balloon_alert(user, "cables added") make_terminal(terminal_cable_layer) terminal.connect_to_network() return ITEM_INTERACT_SUCCESS @@ -127,7 +140,7 @@ /obj/machinery/power/apc/proc/electronics_act(mob/living/user, obj/item/electronics/apc/installing_board) if(!opened) return NONE - + if(has_electronics) balloon_alert(user, "there is already a board!") return ITEM_INTERACT_BLOCKING @@ -140,7 +153,7 @@ balloon_alert(user, "inserting the board...") playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) - if(!do_after(user, 10, target = src) || has_electronics) + if(!do_after(user, 1 SECONDS, target = src) || has_electronics) return ITEM_INTERACT_BLOCKING has_electronics = APC_ELECTRONICS_INSTALLED @@ -155,7 +168,7 @@ if(machine_stat & BROKEN) balloon_alert(user, "frame is too damaged!") return ITEM_INTERACT_BLOCKING - if(!pseudocircuit.adapt_circuit(user, circuit_cost = 50 KILO JOULES)) + if(!pseudocircuit.adapt_circuit(user, circuit_cost = 0.05 * STANDARD_CELL_CHARGE)) return ITEM_INTERACT_BLOCKING user.visible_message( span_notice("[user] fabricates a circuit and places it into [src]."), @@ -169,7 +182,7 @@ if(machine_stat & MAINT) balloon_alert(user, "no board for a cell!") return ITEM_INTERACT_BLOCKING - if(!pseudocircuit.adapt_circuit(user, circuit_cost = 500 KILO JOULES)) + if(!pseudocircuit.adapt_circuit(user, circuit_cost = 0.5 * STANDARD_CELL_CHARGE)) return ITEM_INTERACT_BLOCKING var/obj/item/stock_parts/cell/crap/empty/bad_cell = new(src) bad_cell.forceMove(src) @@ -195,7 +208,7 @@ if((machine_stat & BROKEN) && opened == APC_COVER_REMOVED && has_electronics && terminal) // Cover is the only thing broken, we do not need to remove elctronicks to replace cover user.visible_message(span_notice("[user.name] replaces missing APC's cover.")) balloon_alert(user, "replacing APC's cover...") - if(!do_after(user, 20, target = src)) // replacing cover is quicker than replacing whole frame + if(!do_after(user, 2 SECONDS, target = src)) // replacing cover is quicker than replacing whole frame return ITEM_INTERACT_BLOCKING balloon_alert(user, "cover replaced") qdel(wallframe) @@ -209,7 +222,7 @@ return ITEM_INTERACT_BLOCKING user.visible_message(span_notice("[user.name] replaces the damaged APC frame with a new one.")) balloon_alert(user, "replacing damaged frame...") - if(!do_after(user, 50, target = src)) + if(!do_after(user, 5 SECONDS, target = src)) return ITEM_INTERACT_BLOCKING balloon_alert(user, "replaced frame") qdel(wallframe) @@ -459,7 +472,7 @@ environ = APC_CHANNEL_OFF update_appearance() update() - addtimer(CALLBACK(src, PROC_REF(reset), APC_RESET_EMP), 600) + addtimer(CALLBACK(src, PROC_REF(reset), APC_RESET_EMP), 60 SECONDS) /obj/machinery/power/apc/proc/togglelock(mob/living/user) if(obj_flags & EMAGGED) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 4480dc981efc3..2e95b12914650 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -141,11 +141,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri return ..() // then go ahead and delete the cable -/obj/structure/cable/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/stack/cable_coil/cable = new(drop_location(), 1) - cable.set_cable_color(cable_color) - qdel(src) +/obj/structure/cable/atom_deconstruct(disassembled = TRUE) + var/obj/item/stack/cable_coil/cable = new(drop_location(), 1) + cable.set_cable_color(cable_color) /////////////////////////////////// // General procedures @@ -575,7 +573,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri if(affecting && IS_ROBOTIC_LIMB(affecting)) if(user == H) user.visible_message(span_notice("[user] starts to fix some of the wires in [H]'s [affecting.name]."), span_notice("You start fixing some of the wires in [H == user ? "your" : "[H]'s"] [affecting.name].")) - if(!do_after(user, 50, H)) + if(!do_after(user, 5 SECONDS, H)) return if(item_heal_robotic(H, user, 0, 15)) use(1) @@ -631,6 +629,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri /obj/item/stack/cable_coil/five amount = 5 +/obj/item/stack/cable_coil/thirty + amount = 30 + /obj/item/stack/cable_coil/cut amount = null icon_state = "coil2" diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 6a2dd0737142c..db5791da43526 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -1,6 +1,6 @@ #define CELL_DRAIN_TIME 35 -#define CELL_POWER_GAIN 60 -#define CELL_POWER_DRAIN 750 +#define CELL_POWER_GAIN (0.06 * STANDARD_CELL_CHARGE) +#define CELL_POWER_DRAIN (0.75 * STANDARD_CELL_CHARGE) /** * # Power cell @@ -31,7 +31,7 @@ ///If the power cell was damaged by an explosion, chance for it to become corrupted and function the same as rigged. var/corrupted = FALSE ///How much power is given per second in a recharger. - var/chargerate = STANDARD_CELL_CHARGE * 0.05 + var/chargerate = STANDARD_CELL_RATE * 0.05 ///If true, the cell will state it's maximum charge in it's description var/ratingdesc = TRUE ///If it's a grown that acts as a battery, add a wire overlay to it. @@ -186,6 +186,19 @@ explode() return power_used +/** + * Changes the charge of the cell. + * Args: + * - amount: The energy to give to the cell (can be negative). + * Returns: The energy that was given to the cell (can be negative). + */ +/obj/item/stock_parts/cell/proc/change(amount) + var/energy_used = clamp(amount, -charge, maxcharge - charge) + charge += energy_used + if(rigged && energy_used) + explode() + return energy_used + /obj/item/stock_parts/cell/examine(mob/user) . = ..() if(rigged) @@ -259,18 +272,19 @@ var/charge_limit = ETHEREAL_CHARGE_DANGEROUS - CELL_POWER_GAIN var/obj/item/organ/internal/stomach/ethereal/stomach = maybe_stomach + var/obj/item/stock_parts/cell/stomach_cell = stomach.cell if((stomach.drain_time > world.time) || !stomach) return if(charge < CELL_POWER_DRAIN) to_chat(H, span_warning("[src] doesn't have enough power!")) return - if(stomach.crystal_charge > charge_limit) + if(stomach_cell.charge() > charge_limit) to_chat(H, span_warning("Your charge is full!")) return to_chat(H, span_notice("You begin clumsily channeling power from [src] into your body.")) stomach.drain_time = world.time + CELL_DRAIN_TIME while(do_after(user, CELL_DRAIN_TIME, target = src)) - if((charge < CELL_POWER_DRAIN) || (stomach.crystal_charge > charge_limit)) + if((charge < CELL_POWER_DRAIN) || (stomach_cell.charge() > charge_limit)) return if(istype(stomach)) to_chat(H, span_notice("You receive some charge from [src], wasting some in the process.")) @@ -285,7 +299,7 @@ SSexplosions.high_mov_atom += src /obj/item/stock_parts/cell/proc/get_electrocute_damage() - return ELECTROCUTE_DAMAGE(charge) + return ELECTROCUTE_DAMAGE(charge / max(0.001 * STANDARD_CELL_CHARGE, 1)) // Wouldn't want it to consider more energy than whatever is actually in the cell if for some strange reason someone set the STANDARD_CELL_CHARGE to below 1kJ. /obj/item/stock_parts/cell/get_part_rating() return maxcharge * 10 + charge @@ -312,7 +326,7 @@ desc = "A power cell with a slightly higher capacity than normal!" maxcharge = STANDARD_CELL_CHARGE * 2.5 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*0.5) - chargerate = STANDARD_CELL_CHARGE * 0.5 + chargerate = STANDARD_CELL_RATE * 0.5 /obj/item/stock_parts/cell/upgraded/plus name = "upgraded power cell+" @@ -338,7 +352,7 @@ /obj/item/stock_parts/cell/pulse //200 pulse shots name = "pulse rifle power cell" maxcharge = STANDARD_CELL_CHARGE * 40 - chargerate = STANDARD_CELL_CHARGE * 0.75 + chargerate = STANDARD_CELL_RATE * 0.75 /obj/item/stock_parts/cell/pulse/carbine //25 pulse shots name = "pulse carbine power cell" @@ -353,14 +367,14 @@ icon_state = "bscell" maxcharge = STANDARD_CELL_CHARGE * 10 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*0.6) - chargerate = STANDARD_CELL_CHARGE + chargerate = STANDARD_CELL_RATE /obj/item/stock_parts/cell/high name = "high-capacity power cell" icon_state = "hcell" maxcharge = STANDARD_CELL_CHARGE * 10 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*0.6) - chargerate = STANDARD_CELL_CHARGE * 0.75 + chargerate = STANDARD_CELL_RATE * 0.75 /obj/item/stock_parts/cell/high/empty empty = TRUE @@ -370,7 +384,7 @@ icon_state = "scell" maxcharge = STANDARD_CELL_CHARGE * 20 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT * 3) - chargerate = STANDARD_CELL_CHARGE + chargerate = STANDARD_CELL_RATE /obj/item/stock_parts/cell/super/empty empty = TRUE @@ -380,7 +394,7 @@ icon_state = "hpcell" maxcharge = STANDARD_CELL_CHARGE * 30 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT * 4) - chargerate = STANDARD_CELL_CHARGE * 1.5 + chargerate = STANDARD_CELL_RATE * 1.5 /obj/item/stock_parts/cell/hyper/empty empty = TRUE @@ -391,7 +405,7 @@ icon_state = "bscell" maxcharge = STANDARD_CELL_CHARGE * 40 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*6) - chargerate = STANDARD_CELL_CHARGE * 2 + chargerate = STANDARD_CELL_RATE * 2 /obj/item/stock_parts/cell/bluespace/empty empty = TRUE @@ -464,7 +478,7 @@ name = "beam rifle capacitor" desc = "A high powered capacitor that can provide huge amounts of energy in an instant." maxcharge = STANDARD_CELL_CHARGE * 50 - chargerate = STANDARD_CELL_CHARGE * 2.5 //Extremely energy intensive + chargerate = STANDARD_CELL_RATE * 2.5 //Extremely energy intensive /obj/item/stock_parts/cell/beam_rifle/corrupt() return @@ -503,6 +517,21 @@ /obj/item/stock_parts/cell/inducer_supply maxcharge = STANDARD_CELL_CHARGE * 5 +/obj/item/stock_parts/cell/ethereal + name = "ahelp it" + desc = "you sohuldn't see this" + maxcharge = ETHEREAL_CHARGE_DANGEROUS + charge = ETHEREAL_CHARGE_FULL + icon_state = null + charge_light_type = null + connector_type = null + custom_materials = null + grind_results = null + +/obj/item/stock_parts/cell/ethereal/examine(mob/user) + . = ..() + CRASH("[src.type] got examined by [user]") + #undef CELL_DRAIN_TIME #undef CELL_POWER_GAIN #undef CELL_POWER_DRAIN diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index c5db0fc05bdb9..2d552dbbe9edb 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -118,9 +118,8 @@ RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) AddElement(/datum/element/atmos_sensitive, mapload) find_and_hang_on_wall(custom_drop_callback = CALLBACK(src, PROC_REF(knock_down))) - return INITIALIZE_HINT_LATELOAD -/obj/machinery/light/LateInitialize() +/obj/machinery/light/post_machine_initialize() . = ..() #ifndef MAP_TEST switch(fitting) @@ -380,6 +379,10 @@ span_notice("You open [src]'s casing."), span_hear("You hear a noise.")) deconstruct() return + + if(tool.item_flags & ABSTRACT) + return + to_chat(user, span_userdanger("You stick \the [tool] into the light socket!")) if(has_power() && (tool.obj_flags & CONDUCTS_ELECTRICITY)) do_sparks(3, TRUE, src) diff --git a/code/modules/power/lighting/light_construct.dm b/code/modules/power/lighting/light_construct.dm index 905ae72c2e38b..8b79c33d69bcb 100644 --- a/code/modules/power/lighting/light_construct.dm +++ b/code/modules/power/lighting/light_construct.dm @@ -162,10 +162,8 @@ if(attacking_blob && attacking_blob.loc == loc) qdel(src) -/obj/structure/light_construct/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, sheets_refunded) - qdel(src) +/obj/structure/light_construct/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, sheets_refunded) /obj/structure/light_construct/small name = "small light fixture frame" diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm index 2f18bab660a1c..7f1ef8fc2e3a8 100644 --- a/code/modules/power/pipecleaners.dm +++ b/code/modules/power/pipecleaners.dm @@ -106,15 +106,13 @@ By design, d1 is the smallest direction and d2 is the highest QDEL_NULL(stored) return ..() // then go ahead and delete the pipe_cleaner -/obj/structure/pipe_cleaner/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(loc) - if(T) - stored.forceMove(T) - stored = null - else - qdel(stored) - qdel(src) +/obj/structure/pipe_cleaner/atom_deconstruct(disassembled = TRUE) + var/turf/location = get_turf(loc) + if(location) + stored.forceMove(location) + stored = null + else + qdel(stored) /////////////////////////////////// // General procedures @@ -165,10 +163,9 @@ By design, d1 is the smallest direction and d2 is the highest stored.color = colorC stored.update_appearance() -/obj/structure/pipe_cleaner/AltClick(mob/living/user) - if(!user.can_perform_action(src)) - return +/obj/structure/pipe_cleaner/click_alt(mob/living/user) cut_pipe_cleaner(user) + return CLICK_ACTION_SUCCESS /////////////////////////////////////////////// // The pipe cleaner coil object, used for laying pipe cleaner diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 84542805d484d..e4c1617c0f0b8 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -98,7 +98,7 @@ var/obj/S = sheet_path sheet_name = initial(S.name) -/obj/machinery/power/port_gen/pacman/Destroy() +/obj/machinery/power/port_gen/pacman/on_deconstruction(disassembled) DropFuel() return ..() diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index f5b4a8ca66b6a..71daf214019c7 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -30,7 +30,7 @@ /obj/machinery/power/Destroy() disconnect_from_network() - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(update_cable_icons_on_turf), get_turf(src)), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(update_cable_icons_on_turf), get_turf(src)), 0.3 SECONDS) return ..() /////////////////////////////// @@ -50,9 +50,9 @@ . = ..() if(can_change_cable_layer) if(!QDELETED(powernet)) - . += span_notice("It's operating on the [lowertext(GLOB.cable_layer_to_name["[cable_layer]"])].") + . += span_notice("It's operating on the [LOWER_TEXT(GLOB.cable_layer_to_name["[cable_layer]"])].") else - . += span_warning("It's disconnected from the [lowertext(GLOB.cable_layer_to_name["[cable_layer]"])].") + . += span_warning("It's disconnected from the [LOWER_TEXT(GLOB.cable_layer_to_name["[cable_layer]"])].") . += span_notice("It's power line can be changed with a [EXAMINE_HINT("multitool")].") /obj/machinery/power/multitool_act(mob/living/user, obj/item/tool) @@ -62,7 +62,7 @@ /obj/machinery/power/multitool_act_secondary(mob/living/user, obj/item/tool) return multitool_act(user, tool) -/// Called on multitool_act when we can change cable layers, override to add more conditions +/// Called on multitool_act when we can change cable layers, override to add more conditions /obj/machinery/power/proc/cable_layer_act(mob/living/user, obj/item/tool) var/choice = tgui_input_list(user, "Select Power Line For Operation", "Select Cable Layer", GLOB.cable_name_to_layer) if(isnull(choice) || QDELETED(src) || QDELETED(user) || QDELETED(tool) || !user.Adjacent(src) || !user.is_holding(tool)) @@ -176,7 +176,7 @@ var/surplus = local_apc.surplus() var/grid_used = min(surplus, amount) var/apc_used = 0 - if((amount > grid_used) && !ignore_apc) // Use from the APC's cell if there isn't enough energy from the grid. + if((amount > grid_used) && !ignore_apc && !QDELETED(local_apc.cell)) // Use from the APC's cell if there isn't enough energy from the grid. apc_used = local_apc.cell.use(amount - grid_used, force = force) if(!force && (amount < grid_used + apc_used)) // If we aren't forcing it and there isn't enough energy to supply demand, return nothing. @@ -204,7 +204,7 @@ return amount var/obj/machinery/power/apc/my_apc = my_area.apc - if(isnull(my_apc)) + if(isnull(my_apc) || QDELETED(my_apc.cell)) return FALSE return my_apc.cell.use(amount, force = force) diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index d9fc0671e31d7..22682471d1359 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -29,6 +29,7 @@ COMSIG_ATOM_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) /obj/machinery/field/containment/Destroy() if(field_gen_1) @@ -164,4 +165,4 @@ to_chat(considered_atom, span_userdanger("The field repels you with tremendous force!")) playsound(src, 'sound/effects/gravhit.ogg', 50, TRUE) considered_atom.throw_at(target, 200, 4) - addtimer(CALLBACK(src, PROC_REF(clear_shock)), 5) + addtimer(CALLBACK(src, PROC_REF(clear_shock)), 0.5 SECONDS) diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 084f74d50ec1f..c4be44ed36785 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -346,8 +346,6 @@ return return ..() -/obj/machinery/power/emitter/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/machinery/power/emitter/proc/integrate(obj/item/gun/energy/energy_gun, mob/user) if(!istype(energy_gun, /obj/item/gun/energy)) diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm index c83db17c586d8..b46b29538c608 100644 --- a/code/modules/power/singularity/field_generator.dm +++ b/code/modules/power/singularity/field_generator.dm @@ -208,6 +208,7 @@ no power level overlay is currently in the overlays list. air_update_turf(TRUE, FALSE) INVOKE_ASYNC(src, PROC_REF(cleanup)) addtimer(CALLBACK(src, PROC_REF(cool_down)), 5 SECONDS) + RemoveElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) /obj/machinery/field/generator/proc/cool_down() if(active || warming_up <= 0) @@ -220,6 +221,7 @@ no power level overlay is currently in the overlays list. /obj/machinery/field/generator/proc/turn_on() active = FG_CHARGING addtimer(CALLBACK(src, PROC_REF(warm_up)), 5 SECONDS) + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) /obj/machinery/field/generator/proc/warm_up() if(!active) @@ -283,11 +285,11 @@ no power level overlay is currently in the overlays list. set_explosion_block(INFINITY) can_atmos_pass = ATMOS_PASS_NO air_update_turf(TRUE, TRUE) - addtimer(CALLBACK(src, PROC_REF(setup_field), 1), 1) - addtimer(CALLBACK(src, PROC_REF(setup_field), 2), 2) - addtimer(CALLBACK(src, PROC_REF(setup_field), 4), 3) - addtimer(CALLBACK(src, PROC_REF(setup_field), 8), 4) - addtimer(VARSET_CALLBACK(src, active, FG_ONLINE), 5) + addtimer(CALLBACK(src, PROC_REF(setup_field), 1), 0.1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(setup_field), 2), 0.2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(setup_field), 4), 0.3 SECONDS) + addtimer(CALLBACK(src, PROC_REF(setup_field), 8), 0.4 SECONDS) + addtimer(VARSET_CALLBACK(src, active, FG_ONLINE), 0.5 SECONDS) /obj/machinery/field/generator/proc/setup_field(NSEW) var/turf/current_turf = loc diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 5b712d52da2ff..74b7bfdbcdcb4 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -340,7 +340,7 @@ if(STAGE_ONE) steps = 1 if(STAGE_TWO) - steps = 3//Yes this is right + steps = 2 if(STAGE_THREE) steps = 3 if(STAGE_FOUR) @@ -386,16 +386,8 @@ /obj/singularity/proc/can_move(turf/considered_turf) if(!considered_turf) return FALSE - if((locate(/obj/machinery/field/containment) in considered_turf) || (locate(/obj/machinery/shieldwall) in considered_turf)) + if (HAS_TRAIT(considered_turf, TRAIT_CONTAINMENT_FIELD)) return FALSE - else if(locate(/obj/machinery/field/generator) in considered_turf) - var/obj/machinery/field/generator/check_generator = locate(/obj/machinery/field/generator) in considered_turf - if(check_generator?.active) - return FALSE - else if(locate(/obj/machinery/power/shieldwallgen) in considered_turf) - var/obj/machinery/power/shieldwallgen/check_shield = locate(/obj/machinery/power/shieldwallgen) in considered_turf - if(check_shield?.active) - return FALSE return TRUE /obj/singularity/proc/event() @@ -482,3 +474,16 @@ /// Special singularity that spawns for shuttle events only /obj/singularity/shuttle_event anchored = FALSE + +/// Special singularity spawned by being sucked into a black hole during emagged orion trail. +/obj/singularity/orion + move_self = FALSE + +/obj/singularity/orion/Initialize(mapload) + . = ..() + var/datum/component/singularity/singularity = singularity_component.resolve() + singularity?.grav_pull = 1 + +/obj/singularity/orion/process(seconds_per_tick) + if(SPT_PROB(0.5, seconds_per_tick)) + mezzer() diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index a9a512bceafd7..0cad7bdcef557 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -112,55 +112,42 @@ //building and linking a terminal if(istype(item, /obj/item/stack/cable_coil)) - var/dir = get_dir(user,src) - if(dir & (dir-1))//we don't want diagonal click - return - - if(terminal) //is there already a terminal ? - to_chat(user, span_warning("This SMES already has a power terminal!")) - return - - if(!panel_open) //is the panel open ? - to_chat(user, span_warning("You must open the maintenance panel first!")) - return - - var/turf/turf = get_turf(user) - if (turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) //can we get to the underfloor? - to_chat(user, span_warning("You must first remove the floor plating!")) - return - - - var/obj/item/stack/cable_coil/cable = item - if(cable.get_amount() < 10) - to_chat(user, span_warning("You need more wires!")) + if(!can_place_terminal(user, item, silent = FALSE)) return var/terminal_cable_layer if(LAZYACCESS(params2list(params), RIGHT_CLICK)) var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer) - if(isnull(choice)) + if(isnull(choice) \ + || !user.is_holding(item) \ + || !user.Adjacent(src) \ + || user.incapacitated() \ + || !can_place_terminal(user, item, silent = TRUE) \ + ) return terminal_cable_layer = GLOB.cable_name_to_layer[choice] - to_chat(user, span_notice("You start building the power terminal...")) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) + user.visible_message(span_notice("[user.name] starts adding cables to [src].")) + balloon_alert(user, "adding cables...") + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) - if(do_after(user, 20, target = src)) - if(cable.get_amount() < 10 || !cable) - return - var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one - if (prob(50) && electrocute_mob(user, connected_cable, connected_cable, 1, TRUE)) //animate the electrocution if uncautious and unlucky - do_sparks(5, TRUE, src) - return - if(!terminal) - cable.use(10) - user.visible_message(span_notice("[user.name] builds a power terminal."),\ - span_notice("You build the power terminal.")) - - //build the terminal and link it to the network - make_terminal(turf, terminal_cable_layer) - terminal.connect_to_network() - connect_to_network() + if(!do_after(user, 2 SECONDS, target = src)) + return + if(!can_place_terminal(user, item, silent = TRUE)) + return + var/obj/item/stack/cable_coil/cable = item + var/turf/turf = get_turf(user) + var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one + if (prob(50) && electrocute_mob(user, connected_cable, connected_cable, 1, TRUE)) //animate the electrocution if uncautious and unlucky + do_sparks(5, TRUE, src) + return + cable.use(10) + user.visible_message(span_notice("[user.name] adds cables to [src]")) + balloon_alert(user, "cables added") + //build the terminal and link it to the network + make_terminal(turf, terminal_cable_layer) + terminal.connect_to_network() + connect_to_network() return //crowbarring it ! @@ -175,6 +162,31 @@ return ..() +/// Checks if we're in a valid state to place a terminal +/obj/machinery/power/smes/proc/can_place_terminal(mob/living/user, obj/item/stack/cable_coil/installing_cable, silent = TRUE) + var/set_dir = get_dir(user, src) + if(set_dir & (set_dir - 1))//we don't want diagonal click + return FALSE + + var/turf/terminal_turf = get_turf(user) + if(!panel_open) + if(!silent && user) + balloon_alert(user, "open the maintenance panel!") + return FALSE + if(terminal_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) + if(!silent && user) + balloon_alert(user, "remove the floor plating!") + return FALSE + if(terminal) + if(!silent && user) + balloon_alert(user, "already wired!") + return FALSE + if(installing_cable.get_amount() < 10) + if(!silent && user) + balloon_alert(user, "need ten lengths of cable!") + return FALSE + return TRUE + /obj/machinery/power/smes/wirecutter_act(mob/living/user, obj/item/item) //disassembling the terminal . = ..() @@ -425,6 +437,16 @@ update_appearance() log_smes() +// Variant of SMES that starts with super power cells for higher longevity +/obj/machinery/power/smes/super + name = "super capacity power storage unit" + desc = "A super-capacity superconducting magnetic energy storage (SMES) unit. Relatively rare, and typically installed in long-range outposts where minimal maintenance is expected." + circuit = /obj/item/circuitboard/machine/smes/super + capacity = 100 * STANDARD_CELL_CHARGE + +/obj/machinery/power/smes/super/full + charge = 100 * STANDARD_CELL_CHARGE + /obj/machinery/power/smes/full charge = 50 * STANDARD_CELL_CHARGE diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 9b47c133705f2..370140a4f74cd 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -42,6 +42,8 @@ /obj/machinery/power/solar/Destroy() unset_control() //remove from control computer + QDEL_NULL(panel) + QDEL_NULL(panel_edge) return ..() /obj/machinery/power/solar/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) diff --git a/code/modules/power/supermatter/supermatter_variants.dm b/code/modules/power/supermatter/supermatter_variants.dm index 9d69066a5353b..ebc21b2b5b09f 100644 --- a/code/modules/power/supermatter/supermatter_variants.dm +++ b/code/modules/power/supermatter/supermatter_variants.dm @@ -21,6 +21,21 @@ layer = ABOVE_MOB_LAYER moveable = TRUE + +/obj/machinery/power/supermatter_crystal/shard/Initialize(mapload) + . = ..() + + register_context() + + +/obj/machinery/power/supermatter_crystal/shard/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + + if(held_item?.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = anchored ? "Unanchor" : "Anchor" + return CONTEXTUAL_SCREENTIP_SET + + /// Shard SM with it's processing disabled. /obj/machinery/power/supermatter_crystal/shard/hugbox name = "anchored supermatter shard" diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm index 4c861a4bb4b57..04b9ab8798b73 100644 --- a/code/modules/power/terminal.dm +++ b/code/modules/power/terminal.dm @@ -26,9 +26,9 @@ /obj/machinery/power/terminal/examine(mob/user) . = ..() if(!QDELETED(powernet)) - . += span_notice("It's operating on the [lowertext(GLOB.cable_layer_to_name["[cable_layer]"])].") + . += span_notice("It's operating on the [LOWER_TEXT(GLOB.cable_layer_to_name["[cable_layer]"])].") else - . += span_warning("It's disconnected from the [lowertext(GLOB.cable_layer_to_name["[cable_layer]"])].") + . += span_warning("It's disconnected from the [LOWER_TEXT(GLOB.cable_layer_to_name["[cable_layer]"])].") /obj/machinery/power/terminal/should_have_node() return TRUE diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 376cebb7dcd9e..0e7957b65fb2f 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -127,7 +127,7 @@ energy_to_raise = energy_to_raise * 1.25 playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, TRUE, extrarange = 30) - addtimer(CALLBACK(src, PROC_REF(new_mini_ball)), 100) + addtimer(CALLBACK(src, PROC_REF(new_mini_ball)), 10 SECONDS) else if(energy < energy_to_lower && orbiting_balls.len) energy_to_raise = energy_to_raise / 1.25 energy_to_lower = (energy_to_raise / 1.25) - 20 diff --git a/code/modules/power/turbine/turbine.dm b/code/modules/power/turbine/turbine.dm index 21269c90d37c8..590b135ad9a31 100644 --- a/code/modules/power/turbine/turbine.dm +++ b/code/modules/power/turbine/turbine.dm @@ -43,7 +43,7 @@ register_context() -/obj/machinery/power/turbine/LateInitialize() +/obj/machinery/power/turbine/post_machine_initialize() . = ..() activate_parts() diff --git a/code/modules/power/turbine/turbine_computer.dm b/code/modules/power/turbine/turbine_computer.dm index 9e0f5bdaa469e..f983e11c1f128 100644 --- a/code/modules/power/turbine/turbine_computer.dm +++ b/code/modules/power/turbine/turbine_computer.dm @@ -9,11 +9,7 @@ ///Easy way to connect a computer and a turbine roundstart by setting an id on both this and the core_rotor var/mapping_id -/obj/machinery/computer/turbine_computer/Initialize(mapload) - . = ..() - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/computer/turbine_computer/LateInitialize() +/obj/machinery/computer/turbine_computer/post_machine_initialize() . = ..() locate_machinery() diff --git a/code/modules/procedural_mapping/mapGenerator.dm b/code/modules/procedural_mapping/mapGenerator.dm index 420ac9c8d7976..58ff564190702 100644 --- a/code/modules/procedural_mapping/mapGenerator.dm +++ b/code/modules/procedural_mapping/mapGenerator.dm @@ -136,40 +136,36 @@ // HERE BE DEBUG DRAGONS // /////////////////////////// -/client/proc/debugNatureMapGenerator() - set name = "Test Nature Map Generator" - set category = "Debug" - +ADMIN_VERB(debug_nature_map_generator, R_DEBUG, "Test Nature Map Generator", "Test the nature map generator", ADMIN_CATEGORY_DEBUG) var/datum/map_generator/nature/N = new() - var/startInput = input(usr, "Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null + var/startInput = input(user, "Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null if (isnull(startInput)) return - var/endInput = input(usr, "End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text|null - + var/endInput = input(user, "End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[user.mob.z]") as text|null if (isnull(endInput)) return //maxx maxy and current z so that if you fuck up, you only fuck up one entire z level instead of the entire universe if(!startInput || !endInput) - to_chat(src, "Missing Input") + to_chat(user, "Missing Input") return var/list/startCoords = splittext(startInput, ";") var/list/endCoords = splittext(endInput, ";") if(!startCoords || !endCoords) - to_chat(src, "Invalid Coords") - to_chat(src, "Start Input: [startInput]") - to_chat(src, "End Input: [endInput]") + to_chat(user, "Invalid Coords") + to_chat(user, "Start Input: [startInput]") + to_chat(user, "End Input: [endInput]") return var/turf/Start = locate(text2num(startCoords[1]),text2num(startCoords[2]),text2num(startCoords[3])) var/turf/End = locate(text2num(endCoords[1]),text2num(endCoords[2]),text2num(endCoords[3])) if(!Start || !End) - to_chat(src, "Invalid Turfs") - to_chat(src, "Start Coords: [startCoords[1]] - [startCoords[2]] - [startCoords[3]]") - to_chat(src, "End Coords: [endCoords[1]] - [endCoords[2]] - [endCoords[3]]") + to_chat(user, "Invalid Turfs") + to_chat(user, "Start Coords: [startCoords[1]] - [startCoords[2]] - [startCoords[3]]") + to_chat(user, "End Coords: [endCoords[1]] - [endCoords[2]] - [endCoords[3]]") return var/static/list/clusters = list( @@ -191,7 +187,7 @@ var/theCluster = 0 if(moduleClusters != "None") if(!clusters[moduleClusters]) - to_chat(src, "Invalid Cluster Flags") + to_chat(user, "Invalid Cluster Flags") return theCluster = clusters[moduleClusters] else @@ -202,9 +198,9 @@ M.clusterCheckFlags = theCluster - to_chat(src, "Defining Region") + to_chat(user, "Defining Region") N.defineRegion(Start, End) - to_chat(src, "Region Defined") - to_chat(src, "Generating Region") + to_chat(user, "Region Defined") + to_chat(user, "Generating Region") N.generate() - to_chat(src, "Generated Region") + to_chat(user, "Generated Region") diff --git a/code/modules/projectiles/ammunition/ballistic/junk.dm b/code/modules/projectiles/ammunition/ballistic/junk.dm new file mode 100644 index 0000000000000..99a9b637923f5 --- /dev/null +++ b/code/modules/projectiles/ammunition/ballistic/junk.dm @@ -0,0 +1,43 @@ +// Junk + +/obj/item/ammo_casing/junk + name = "improvised junk round" + desc = "What is in the shell? Shoot it to find out." + icon_state = "improvshell" + caliber = CALIBER_JUNK + projectile_type = /obj/projectile/bullet/junk + custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*2, /datum/material/glass=SMALL_MATERIAL_AMOUNT*1) + +// Junk Shell Spawner; used to spawn in our random shells upon crafting + +/obj/effect/spawner/random/junk_shell + name = "junk shell spawner" + desc = "Bullet. Bullet Bullet." + icon_state = "junkround" + loot = list( + /obj/item/ammo_casing/junk = 50, + /obj/item/ammo_casing/junk/incendiary = 20, + /obj/item/ammo_casing/junk/shock = 20, + /obj/item/ammo_casing/junk/hunter = 20, + /obj/item/ammo_casing/junk/phasic = 5, + /obj/item/ammo_casing/junk/ripper = 5, + /obj/item/ammo_casing/junk/reaper = 1, + ) + +/obj/item/ammo_casing/junk/incendiary + projectile_type = /obj/projectile/bullet/incendiary/fire/junk + +/obj/item/ammo_casing/junk/phasic + projectile_type = /obj/projectile/bullet/junk/phasic + +/obj/item/ammo_casing/junk/shock + projectile_type = /obj/projectile/bullet/junk/shock + +/obj/item/ammo_casing/junk/hunter + projectile_type = /obj/projectile/bullet/junk/hunter + +/obj/item/ammo_casing/junk/ripper + projectile_type = /obj/projectile/bullet/junk/ripper + +/obj/item/ammo_casing/junk/reaper + projectile_type = /obj/projectile/bullet/junk/reaper diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm index 078f4bba1c4fd..b545500420bc1 100644 --- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm +++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm @@ -103,15 +103,6 @@ variance = 25 custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*2) -/obj/item/ammo_casing/shotgun/improvised - name = "improvised shell" - desc = "A homemade shotgun casing filled with crushed glass, used to commmit vandalism and property damage." - icon_state = "improvshell" - projectile_type = /obj/projectile/bullet/pellet/shotgun_improvised - custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*2, /datum/material/glass=SMALL_MATERIAL_AMOUNT*1) - pellets = 6 - variance = 30 - /obj/item/ammo_casing/shotgun/ion name = "ion shell" desc = "An advanced shotgun shell which uses a subspace ansible crystal to produce an effect similar to a standard ion rifle. \ diff --git a/code/modules/projectiles/ammunition/energy/special.dm b/code/modules/projectiles/ammunition/energy/special.dm index e5de3df5d50d4..f9d5ca5d61250 100644 --- a/code/modules/projectiles/ammunition/energy/special.dm +++ b/code/modules/projectiles/ammunition/energy/special.dm @@ -69,7 +69,7 @@ firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect/blue /obj/item/ammo_casing/energy/shrink - projectile_type = /obj/projectile/beam/shrink + projectile_type = /obj/projectile/magic/shrink/alien select_name = "shrink ray" e_cost = LASER_SHOTS(5, STANDARD_CELL_CHARGE) diff --git a/code/modules/projectiles/ammunition/special/magic.dm b/code/modules/projectiles/ammunition/special/magic.dm index 9135e3ec5b947..0ae053005c4d7 100644 --- a/code/modules/projectiles/ammunition/special/magic.dm +++ b/code/modules/projectiles/ammunition/special/magic.dm @@ -82,3 +82,9 @@ /obj/item/ammo_casing/magic/nothing projectile_type = /obj/projectile/magic/nothing harmful = FALSE + +/obj/item/ammo_casing/magic/shrink + projectile_type = /obj/projectile/magic/shrink + +/obj/item/ammo_casing/magic/shrink/wand + projectile_type = /obj/projectile/magic/shrink/wand diff --git a/code/modules/projectiles/boxes_magazines/internal/rifle.dm b/code/modules/projectiles/boxes_magazines/internal/rifle.dm index 5fdc182ccff98..52d395725a100 100644 --- a/code/modules/projectiles/boxes_magazines/internal/rifle.dm +++ b/code/modules/projectiles/boxes_magazines/internal/rifle.dm @@ -11,13 +11,23 @@ /obj/item/ammo_box/magazine/internal/boltaction/pipegun name = "pipegun internal magazine" - caliber = CALIBER_SHOTGUN - ammo_type = /obj/item/ammo_casing/shotgun/improvised + caliber = CALIBER_JUNK + ammo_type = /obj/item/ammo_casing/junk max_ammo = 1 +/obj/item/ammo_box/magazine/internal/boltaction/pipegun/pistol + name = "pipe pistol internal magazine" + max_ammo = 3 + /obj/item/ammo_box/magazine/internal/boltaction/pipegun/prime name = "regal pipegun internal magazine" - max_ammo = 3 + max_ammo = 4 + ammo_type = /obj/item/ammo_casing/junk/reaper + +/obj/item/ammo_box/magazine/internal/boltaction/pipegun/pistol/prime + name = "regal pipe pistol internal magazine" + max_ammo = 6 + ammo_type = /obj/item/ammo_casing/junk/reaper /obj/item/ammo_box/magazine/internal/enchanted max_ammo = 1 diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 322ee737c9b09..912f162b922a4 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -32,7 +32,7 @@ var/can_suppress = FALSE var/suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg' var/suppressed_volume = 60 - var/can_unsuppress = TRUE + var/can_unsuppress = TRUE /// whether a gun can be unsuppressed. for ballistics, also determines if it generates a suppressor overlay var/recoil = 0 //boom boom shake the room var/clumsy_check = TRUE var/obj/item/ammo_casing/chambered = null @@ -592,7 +592,7 @@ semicd = TRUE - if(!bypass_timer && (!do_after(user, 120, target) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) + if(!bypass_timer && (!do_after(user, 12 SECONDS, target) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) if(user) if(user == target) user.visible_message(span_notice("[user] decided not to shoot.")) diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 8c069ae8c4be0..6f798eb8908e1 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -220,7 +220,7 @@ if (bolt_type == BOLT_TYPE_OPEN && bolt_locked) . += "[icon_state]_bolt" - if(suppressed) + if(suppressed && can_unsuppress) // if it can't be unsuppressed, we assume the suppressor is integrated into the gun itself and don't generate an overlay var/mutable_appearance/MA = mutable_appearance(icon, "[icon_state]_suppressor") if(suppressor_x_offset) MA.pixel_x = suppressor_x_offset @@ -479,7 +479,7 @@ ///Installs a new suppressor, assumes that the suppressor is already in the contents of src /obj/item/gun/ballistic/proc/install_suppressor(obj/item/suppressor/S) suppressed = S - w_class += S.w_class //so pistols do not fit in pockets when suppressed + update_weight_class(w_class + S.w_class) //so pistols do not fit in pockets when suppressed update_appearance() /obj/item/gun/ballistic/clear_suppressor() @@ -487,21 +487,19 @@ return if(isitem(suppressed)) var/obj/item/I = suppressed - w_class -= I.w_class + update_weight_class(w_class - I.w_class) return ..() -/obj/item/gun/ballistic/AltClick(mob/user) - if (unique_reskin && !current_skin && user.can_perform_action(src, NEED_DEXTERITY)) - reskin_obj(user) - return - if(loc == user) - if(suppressed && can_unsuppress) - var/obj/item/suppressor/S = suppressed - if(!user.is_holding(src)) - return ..() - balloon_alert(user, "[S.name] removed") - user.put_in_hands(S) - clear_suppressor() +/obj/item/gun/ballistic/click_alt(mob/user) + if(!suppressed || !can_unsuppress) + return CLICK_ACTION_BLOCKING + var/obj/item/suppressor/S = suppressed + if(!user.is_holding(src)) + return CLICK_ACTION_BLOCKING + balloon_alert(user, "[S.name] removed") + user.put_in_hands(S) + clear_suppressor() + return CLICK_ACTION_SUCCESS ///Prefire empty checks for the bolt drop /obj/item/gun/ballistic/proc/prefire_empty_checks() @@ -574,9 +572,9 @@ if (bolt_locked) . += "The [bolt_wording] is locked back and needs to be released before firing or de-fouling." if (suppressed) - . += "It has a suppressor attached that can be removed with alt+click." + . += "It has a suppressor [can_unsuppress ? "attached that can be removed with alt+click." : "that is integral or can't otherwise be removed."]" if(can_misfire) - . += span_danger("You get the feeling this might explode if you fire it....") + . += span_danger("You get the feeling this might explode if you fire it...") if(misfire_probability > 0) . += span_danger("Given the state of the gun, there is a [misfire_probability]% chance it'll misfire.") @@ -651,7 +649,7 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( user.visible_message(span_danger("[src] goes off!"), span_danger("[src] goes off in your face!")) return - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) if(sawn_off) return user.visible_message(span_notice("[user] shortens [src]!"), span_notice("You shorten [src].")) @@ -659,7 +657,7 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( if(handle_modifications) name = "sawn-off [src.name]" desc = sawn_desc - w_class = WEIGHT_CLASS_NORMAL + update_weight_class(WEIGHT_CLASS_NORMAL) //The file might not have a "gun" icon, let's prepare for this lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' @@ -681,7 +679,7 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( user.changeNext_move(CLICK_CD_MELEE) balloon_alert(user, "cleaning...") - if(do_after(user, 100, target = src)) + if(do_after(user, 10 SECONDS, target = src)) misfire_probability = initial(misfire_probability) balloon_alert(user, "fouling cleaned out") return TRUE diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index 3d6940692d890..8c6e2ae7cbde3 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -260,13 +260,12 @@ . += span_notice("It seems like you could use an empty hand to remove the magazine.") -/obj/item/gun/ballistic/automatic/l6_saw/AltClick(mob/user) - if(!user.can_perform_action(src)) - return +/obj/item/gun/ballistic/automatic/l6_saw/click_alt(mob/user) cover_open = !cover_open balloon_alert(user, "cover [cover_open ? "opened" : "closed"]") playsound(src, 'sound/weapons/gun/l6/l6_door.ogg', 60, TRUE) update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/gun/ballistic/automatic/l6_saw/update_icon_state() . = ..() diff --git a/code/modules/projectiles/guns/ballistic/bows/_bow.dm b/code/modules/projectiles/guns/ballistic/bows/_bow.dm index c356d5b266c42..86094d0fe17ad 100644 --- a/code/modules/projectiles/guns/ballistic/bows/_bow.dm +++ b/code/modules/projectiles/guns/ballistic/bows/_bow.dm @@ -29,13 +29,14 @@ . = ..() icon_state = chambered ? "[base_icon_state]_[drawn ? "drawn" : "nocked"]" : "[base_icon_state]" -/obj/item/gun/ballistic/bow/AltClick(mob/user) +/obj/item/gun/ballistic/bow/click_alt(mob/user) if(isnull(chambered)) - return ..() + return CLICK_ACTION_BLOCKING user.put_in_hands(chambered) chambered = magazine.get_round() update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/gun/ballistic/bow/proc/drop_arrow() chambered.forceMove(drop_location()) diff --git a/code/modules/projectiles/guns/ballistic/pistol.dm b/code/modules/projectiles/guns/ballistic/pistol.dm index 270e7edd93078..53af6c45dd1e7 100644 --- a/code/modules/projectiles/guns/ballistic/pistol.dm +++ b/code/modules/projectiles/guns/ballistic/pistol.dm @@ -30,6 +30,20 @@ /obj/item/gun/ballistic/automatic/pistol/fire_mag spawn_magazine_type = /obj/item/ammo_box/magazine/m9mm/fire +/obj/item/gun/ballistic/automatic/pistol/contraband + +/obj/item/gun/ballistic/automatic/pistol/contraband/Initialize(mapload) + if(prob(10)) + pin = pick( + list( + /obj/item/firing_pin/clown, + /obj/item/firing_pin/clown/ultra, + /obj/item/firing_pin/clown/ultra/selfdestruct, + )) + . = ..() + pin.pin_removable = FALSE + + /obj/item/gun/ballistic/automatic/pistol/suppressed/Initialize(mapload) . = ..() var/obj/item/suppressor/S = new(src) @@ -43,6 +57,53 @@ empty_indicator = TRUE suppressor_x_offset = 12 +/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher + name = "\improper Ansem/SC pistol" + desc = "A modified variant of the Ansem, spiritual successor to the Makarov, featuring an integral suppressor and push-button trigger on the grip \ + for an underbarrel-mounted disruptor, similar in operation to the standalone SC/FISHER. Chambered in 10mm." + desc_controls = "Right-click to use the underbarrel disruptor. Two shots maximum between self-charges." + icon_state = "pistol_evil_fisher" + suppressed = TRUE + can_suppress = FALSE + can_unsuppress = FALSE + var/obj/item/gun/energy/recharge/fisher/underbarrel + +/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/examine_more(mob/user) + . = ..() + . += span_notice("The Ansem/SC is a Scarborough Arms-manufactured overhaul suite for the also Scarborough Arms-manufactured Ansem handgun, designed for special \ + operators who like to operate operationally, and/or people who really, really hate lightbulbs, and tend to fight people who really like lightbulbs. \ + The slide is lengthened and has an integrated suppressor, while a compact kinetic light disruptor was mounted underneath the barrel. \ + Scarborough Arms has never actually officially responded to allegations that they're involved with the modification and/or manufacture \ + of the SC/FISHER or similar disruptor weapons. Operators are reminded that kinetic light disruptors do not actually physically harm targets.
    \ + Caveat emptor.") + +/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/Initialize(mapload) + . = ..() + underbarrel = new /obj/item/gun/energy/recharge/fisher(src) + +/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/Destroy() + QDEL_NULL(underbarrel) + return ..() + +/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/afterattack_secondary(atom/target, mob/living/user, proximity_flag, click_parameters) + underbarrel.afterattack(target, user, proximity_flag, click_parameters) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/afterattack(atom/target, mob/living/user, flag, params) + // mirrors what the standalone fisher does when you hit people with it + . = ..() + if(user.Adjacent(target)) + var/obj/projectile/energy/fisher/melee/simulated_hit = new + simulated_hit.firer = user + simulated_hit.on_hit(target) + +/obj/item/gun/ballistic/automatic/pistol/clandestine/fisher/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + // as above comment, mirrors what the standalone fisher does when you hit people with it + . = ..() + var/obj/projectile/energy/fisher/melee/simulated_hit = new + simulated_hit.firer = throwingdatum.get_thrower() + simulated_hit.on_hit(hit_atom) + /obj/item/gun/ballistic/automatic/pistol/m1911 name = "\improper M1911" desc = "A classic .45 handgun with a small magazine capacity." @@ -83,6 +144,19 @@ lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg' bolt_drop_sound = 'sound/weapons/gun/pistol/slide_drop.ogg' +/obj/item/gun/ballistic/automatic/pistol/deagle/contraband + +/obj/item/gun/ballistic/automatic/pistol/deagle/contraband/Initialize(mapload) + if(prob(10)) + pin = pick( + list( + /obj/item/firing_pin/clown, + /obj/item/firing_pin/clown/ultra, + /obj/item/firing_pin/clown/ultra/selfdestruct, + )) + . = ..() + pin.pin_removable = FALSE + /obj/item/gun/ballistic/automatic/pistol/deagle/gold desc = "A gold plated Desert Eagle folded over a million times by superior martian gunsmiths. Uses .50 AE ammo." icon_state = "deagleg" diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index 373607e53dd63..f7d9ed19cbea5 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -37,9 +37,9 @@ ..() chamber_round() -/obj/item/gun/ballistic/revolver/AltClick(mob/user) - ..() +/obj/item/gun/ballistic/revolver/click_alt(mob/user) spin() + return CLICK_ACTION_SUCCESS /obj/item/gun/ballistic/revolver/fire_sounds() var/frequency_to_use = sin((90/magazine?.max_ammo) * get_ammo(TRUE, FALSE)) // fucking REVOLVERS @@ -311,3 +311,10 @@ user.emote("scream") user.drop_all_held_items() user.Paralyze(80) + +/obj/item/gun/ballistic/revolver/reverse/mateba + name = /obj/item/gun/ballistic/revolver/mateba::name + desc = /obj/item/gun/ballistic/revolver/mateba::desc + clumsy_check = FALSE + icon_state = "mateba" + diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index 966dd2caf32a3..e50d5ce464c89 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -219,6 +219,10 @@ bolt_locked = FALSE update_appearance() +/obj/item/gun/ballistic/rifle/rebarxbow/shoot_live_shot(mob/living/user) + ..() + rack() + /obj/item/gun/ballistic/rifle/rebarxbow/can_shoot() if (bolt_locked) return FALSE @@ -255,46 +259,79 @@ . = ..() AddComponent(/datum/component/scope, range_modifier = 2) //enough range to at least be useful for stealth +/// PIPE GUNS /// + /obj/item/gun/ballistic/rifle/boltaction/pipegun name = "pipegun" - desc = "An excellent weapon for flushing out tunnel rats and enemy assistants, but its rifling leaves much to be desired." - icon = 'icons/obj/weapons/guns/ballistic.dmi' - icon_state = "musket" - inhand_icon_state = "musket" - worn_icon_state = "musket" - lefthand_file = 'icons/mob/inhands/weapons/64x_guns_left.dmi' - righthand_file = 'icons/mob/inhands/weapons/64x_guns_right.dmi' - inhand_x_dimension = 64 - inhand_y_dimension = 64 + desc = "A symbol that the true masters of this place are not those who merely inhabit it, but the one willing to twist it towards a killing intent." + icon_state = "pipegun" + inhand_icon_state = "pipegun" + worn_icon_state = "pipegun" fire_sound = 'sound/weapons/gun/sniper/shot.ogg' accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/pipegun - initial_caliber = CALIBER_SHOTGUN - alternative_caliber = CALIBER_STRILKA310 - initial_fire_sound = 'sound/weapons/gun/sniper/shot.ogg' - alternative_fire_sound = 'sound/weapons/gun/shotgun/shot.ogg' - can_modify_ammo = TRUE + + projectile_damage_multiplier = 1.35 + obj_flags = UNIQUE_RENAME can_bayonet = TRUE - knife_x_offset = 25 - knife_y_offset = 11 + knife_x_offset = 35 + knife_y_offset = 10 can_be_sawn_off = FALSE - projectile_damage_multiplier = 0.75 + trigger_guard = TRIGGER_GUARD_ALLOW_ALL - SET_BASE_PIXEL(0, 0) + SET_BASE_PIXEL(-8, 0) /obj/item/gun/ballistic/rifle/boltaction/pipegun/handle_chamber() . = ..() do_sparks(1, TRUE, src) +/obj/item/gun/ballistic/rifle/boltaction/pipegun/examine_more(mob/user) + . = ..() + . += span_notice("Looking down at the [name], you recall a tale told to you in some distant memory...") + + . += span_info("It's said that the first slaying committed on a Nanotrasen space station was by an assistant.") + . += span_info("That this act, done by toolbox, maybe spear, was what consigned their kind to a life of destitution, rejection and violence.") + . += span_info("They carry the weight of this act visibly; the grey jumpsuit. Breathing deeply filtered air. And with bloodsoaked yellow hands clenched into fists. Eyes, sharp and waiting. Hunters in the dark.") + . += span_info("Eventually, these killing spirits sought to stake a claim on the metal tombs they were trapped within. Rejecting their status. Determined to be something more.") + . += span_info("This weapon is one such tool. And it is a grim one indeed. Wrought from scrap, pulled from the station's walls and floors and the very nails holding it together.") + . += span_info("It is a symbol that the true masters of this place are not those who merely inhabit it. But the one willing to twist it towards a killing intent.") + +/obj/item/gun/ballistic/rifle/boltaction/pipegun/pistol + name = "pipe pistol" + desc = "It is foolish to think that anyone wearing the grey is incapable of hurting you, simply because they are not baring their teeth." + icon_state = "pipepistol" + inhand_icon_state = "pipepistol" + worn_icon_state = "gun" + accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/pipegun/pistol + projectile_damage_multiplier = 0.50 + spread = 15 //kinda inaccurate + slot_flags = ITEM_SLOT_BELT + w_class = WEIGHT_CLASS_NORMAL + can_bayonet = FALSE + weapon_weight = WEAPON_MEDIUM + + SET_BASE_PIXEL(0, 0) + /obj/item/gun/ballistic/rifle/boltaction/pipegun/prime name = "regal pipegun" - desc = "Older, territorial assistants typically possess more valuable loot." - icon_state = "musket_prime" - inhand_icon_state = "musket_prime" - worn_icon_state = "musket_prime" + desc = "To call this 'regal' is a cruel irony. For the only noteworthy quality of nobility is in how it is wielded to kill. \ + All monarchs deserve to be crowned. But none will remember the dead tyrant for the red stain they left on the carpet." + icon_state = "regal_pipegun" + inhand_icon_state = "regal_pipegun" + worn_icon_state = "regal_pipegun" accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/pipegun/prime + projectile_damage_multiplier = 2 + +/obj/item/gun/ballistic/rifle/boltaction/pipegun/pistol/prime + name = "regal pipe pistol" + desc = "What value is there in honesty towards the dishonest? So that they might twist the arm and slit the wrist? \ + The open palm is no sign of weakness; it is to draw the eyes away from the other hand, lying in wait." + icon_state = "regal_pipepistol" + inhand_icon_state = "regal_pipepistol" + accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/pipegun/pistol/prime projectile_damage_multiplier = 1 + spread = 0 -/// MAGICAL BOLT ACTIONS + ARCANE BARRAGE? /// +/// MAGICAL BOLT ACTIONS /// /obj/item/gun/ballistic/rifle/enchanted name = "enchanted bolt action rifle" diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index a45511193b767..85f3283ca43d1 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -85,6 +85,7 @@ w_class = WEIGHT_CLASS_HUGE semi_auto = TRUE accepted_magazine_type = /obj/item/ammo_box/magazine/internal/shot/tube + interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING /// If defined, the secondary tube is this type, if you want different shell loads var/alt_mag_type /// If TRUE, we're drawing from the alternate_magazine @@ -131,10 +132,9 @@ else balloon_alert(user, "switched to tube A") -/obj/item/gun/ballistic/shotgun/automatic/dual_tube/AltClick(mob/living/user) - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) - return +/obj/item/gun/ballistic/shotgun/automatic/dual_tube/click_alt(mob/living/user) rack() + return CLICK_ACTION_SUCCESS // Bulldog shotgun // @@ -288,10 +288,6 @@ can_be_sawn_off = TRUE pb_knockback = 3 // it's a super shotgun! -/obj/item/gun/ballistic/shotgun/doublebarrel/AltClick(mob/user) - . = ..() - if(unique_reskin && !current_skin && user.can_perform_action(src, NEED_DEXTERITY)) - reskin_obj(user) /obj/item/gun/ballistic/shotgun/doublebarrel/sawoff(mob/user) . = ..() diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index dfcb59f1e9c1c..4c00e83b0bbc6 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -36,23 +36,26 @@ /obj/item/gun/energy/fire_sounds() // What frequency the energy gun's sound will make - var/frequency_to_use + var/pitch_to_use = 1 var/obj/item/ammo_casing/energy/shot = ammo_type[select] // What percentage of the full battery a shot will expend var/shot_cost_percent = round(clamp(shot.e_cost / cell.maxcharge, 0, 1) * 100) // Ignore this on oversized/infinite cells or ammo without cost - if(shot_cost_percent > 0) + if(shot_cost_percent > 0 && shot_cost_percent < 100) // The total amount of shots the fully charged energy gun can fire before running out - var/max_shots = round(100/shot_cost_percent) + var/max_shots = round(100/shot_cost_percent) - 1 // How many shots left before the energy gun's current battery runs out of energy - var/shots_left = round((round(clamp(cell.charge / cell.maxcharge, 0, 1) * 100))/shot_cost_percent) - frequency_to_use = sin((90/max_shots) * shots_left) + var/shots_left = round((round(clamp(cell.charge / cell.maxcharge, 0, 1) * 100))/shot_cost_percent) - 1 + pitch_to_use = LERP(1, 0.3, (1 - (shots_left/max_shots)) ** 2) + + var/sound/playing_sound = sound(suppressed ? suppressed_sound : fire_sound) + playing_sound.pitch = pitch_to_use if(suppressed) - playsound(src, suppressed_sound, suppressed_volume, vary_fire_sound, ignore_walls = FALSE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0, frequency = frequency_to_use) + playsound(src, playing_sound, suppressed_volume, vary_fire_sound, ignore_walls = FALSE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0) else - playsound(src, fire_sound, fire_sound_volume, vary_fire_sound, frequency = frequency_to_use) + playsound(src, playing_sound, fire_sound_volume, vary_fire_sound) /obj/item/gun/energy/emp_act(severity) . = ..() diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 5037d26d144bb..65b2b72c7d256 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -129,12 +129,17 @@ MK.uninstall(src) return ..() +/obj/item/gun/energy/recharge/kinetic_accelerator/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + . = ..() + if(istype(arrived, /obj/item/borg/upgrade/modkit)) + modkits |= arrived + /obj/item/gun/energy/recharge/kinetic_accelerator/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/borg/upgrade/modkit)) var/obj/item/borg/upgrade/modkit/MK = I MK.install(src, user) else - ..() + return ..() /obj/item/gun/energy/recharge/kinetic_accelerator/proc/get_remaining_mod_capacity() var/current_capacity_used = 0 @@ -263,7 +268,7 @@ if(istype(A, /obj/item/gun/energy/recharge/kinetic_accelerator) && !issilicon(user)) install(A, user) else - ..() + return ..() /obj/item/borg/upgrade/modkit/action(mob/living/silicon/robot/R) . = ..() @@ -294,7 +299,7 @@ return to_chat(user, span_notice("You install the modkit.")) playsound(loc, 'sound/items/screwdriver.ogg', 100, TRUE) - KA.modkits += src + KA.modkits |= src else to_chat(user, span_notice("The modkit you're trying to install would conflict with an already installed modkit. Remove existing modkits first.")) else diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 6cb50018c7926..95baca98db80f 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -143,7 +143,8 @@ /obj/projectile/beam/laser/accelerator/Range() ..() damage += 7 - transform *= 1 + ((damage/7) * 0.2)//20% larger per tile + transform = 0 + transform *= 1 + (((damage - 6)/7) * 0.2)//20% larger per tile ///X-ray gun diff --git a/code/modules/projectiles/guns/energy/recharge.dm b/code/modules/projectiles/guns/energy/recharge.dm index 3d94193a53199..71d14348608fe 100644 --- a/code/modules/projectiles/guns/energy/recharge.dm +++ b/code/modules/projectiles/guns/energy/recharge.dm @@ -150,19 +150,23 @@ /obj/item/gun/energy/recharge/fisher/examine_more(mob/user) . = ..() - . += span_notice("The SC/FISHER is an illegally-modified kinetic accelerator cut down and refit into a disassembled miniature energy gun chassis, with its pressure chamber \ - attenuated to launch kinetic bolts that disrupt flashlights and cameras, if only temporarily. This effect also works on cyborg headlamps, and works longer in melee.

    \ - While some would argue that this is a really terrible design choice, others argue that it is very funny to be able to shoot at light sources. Caveat emptor.") + . += span_notice("The SC/FISHER is an illegally-modified kinetic accelerator cut down and refit into a disassembled miniature energy gun chassis, \ + with its pressure chamber attenuated to launch kinetic bolts that temporarily disrupt flashlights, cameras, and certain other electronics. \ + This effect also works on cyborg headlamps, and works longer in melee.

    \ + While some would argue that this is a really terrible design choice, others argue that it is very funny to be able to shoot at light sources.
    \ + Caveat emptor.") /obj/item/gun/energy/recharge/fisher/afterattack(atom/target, mob/living/user, flag, params) // you should just shoot them, but in case you can't/wont . = ..() if(user.Adjacent(target)) var/obj/projectile/energy/fisher/melee/simulated_hit = new + simulated_hit.firer = user simulated_hit.on_hit(target) /obj/item/gun/energy/recharge/fisher/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) // ...you reeeeeally just shoot them, but in case you can't/won't . = ..() var/obj/projectile/energy/fisher/melee/simulated_hit = new + simulated_hit.firer = throwingdatum.get_thrower() simulated_hit.on_hit(hit_atom) diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 8ad40a06c8936..50d7c5385d50d 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -78,6 +78,9 @@ ammo_type = list(/obj/item/ammo_casing/energy/mindflayer) ammo_x_offset = 2 +/// amount of charge used up to start action (multiplied by amount) and per progress_flash_divisor ticks of welding +#define PLASMA_CUTTER_CHARGE_WELD (0.025 * STANDARD_CELL_CHARGE) + /obj/item/gun/energy/plasmacutter name = "plasma cutter" desc = "A mining tool capable of expelling concentrated plasma bursts. You could use it to cut limbs off xenos! Or, you know, mine stuff." @@ -91,13 +94,10 @@ sharpness = SHARP_EDGED can_charge = FALSE gun_flags = NOT_A_REAL_GUN - heat = 3800 usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg') tool_behaviour = TOOL_WELDER toolspeed = 0.7 //plasmacutters can be used as welders, and are faster than standard welders - /// amount of charge used up to start action (multiplied by amount) and per progress_flash_divisor ticks of welding - var/charge_weld = 25 KILO JOULES /obj/item/gun/energy/plasmacutter/Initialize(mapload) AddElement(/datum/element/update_icon_blocker) @@ -126,7 +126,7 @@ balloon_alert(user, "already fully charged!") return I.use(1) - cell.give(500 KILO JOULES * charge_multiplier) + cell.give(0.5 * STANDARD_CELL_CHARGE * charge_multiplier) balloon_alert(user, "cell recharged") else ..() @@ -148,14 +148,14 @@ // Amount cannot be used if drain is made continuous, e.g. amount = 5, charge_weld = 25 // Then it'll drain 125 at first and 25 periodically, but fail if charge dips below 125 even though it still can finish action // Alternately it'll need to drain amount*charge_weld every period, which is either obscene or makes it free for other uses - if(amount ? cell.charge < charge_weld * amount : cell.charge < charge_weld) + if(amount ? cell.charge < PLASMA_CUTTER_CHARGE_WELD * amount : cell.charge < PLASMA_CUTTER_CHARGE_WELD) balloon_alert(user, "not enough charge!") return FALSE return TRUE /obj/item/gun/energy/plasmacutter/use(used) - return (!QDELETED(cell) && cell.use(used ? used * charge_weld : charge_weld)) + return (!QDELETED(cell) && cell.use(used ? used * PLASMA_CUTTER_CHARGE_WELD : PLASMA_CUTTER_CHARGE_WELD)) /obj/item/gun/energy/plasmacutter/use_tool(atom/target, mob/living/user, delay, amount=1, volume=0, datum/callback/extra_checks) @@ -169,6 +169,8 @@ else . = ..(amount=1) +#undef PLASMA_CUTTER_CHARGE_WELD + /obj/item/gun/energy/plasmacutter/adv name = "advanced plasma cutter" icon_state = "adv_plasmacutter" @@ -407,7 +409,7 @@ COOLDOWN_START(src, coin_regen_cd, coin_regen_rate) /obj/item/gun/energy/marksman_revolver/afterattack_secondary(atom/target, mob/living/user, params) - if(!can_see(user, get_turf(target), length = 9)) + if(!CAN_THEY_SEE(target, user)) return ..() if(max_coins && coin_count <= 0) diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index c4e719e781724..5ca2e3052518d 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -150,6 +150,7 @@ /obj/projectile/magic/teleport, /obj/projectile/magic/wipe, /obj/projectile/temp/chill, + /obj/projectile/magic/shrink ) /obj/item/gun/magic/staff/chaos/unrestricted @@ -319,3 +320,17 @@ inhand_icon_state = "pharoah_sceptre" worn_icon_state = "wipestaff" school = SCHOOL_FORBIDDEN //arguably the worst staff in the entire game effect wise + +/obj/item/gun/magic/staff/shrink + name = "staff of shrinking" + desc = "An artefact that spits bolts of tiny magic that makes things small. It's easily mistaken for a wand." + fire_sound = 'sound/magic/staff_shrink.ogg' + ammo_type = /obj/item/ammo_casing/magic/shrink + icon_state = "shrinkstaff" + inhand_icon_state = "staff" + max_charges = 10 // slightly more/faster charges since this will be used on walls and such + recharge_rate = 5 + no_den_usage = TRUE + school = SCHOOL_TRANSMUTATION + slot_flags = NONE //too small to wear on your back + w_class = WEIGHT_CLASS_NORMAL //but small enough for a bag diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index a078c4ae00b0e..82b78a4859ed0 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -256,3 +256,25 @@ name = "wand of nothing" desc = "It's not just a stick, it's a MAGIC stick?" ammo_type = /obj/item/ammo_casing/magic/nothing + + +///////////////////////////////////// +//WAND OF SHRINKING +///////////////////////////////////// + +/obj/item/gun/magic/wand/shrink + name = "wand of shrinking" + desc = "Feel the tiny eldritch terror of an itty... bitty... head!" + ammo_type = /obj/item/ammo_casing/magic/shrink/wand + icon_state = "shrinkwand" + base_icon_state = "shrinkwand" + fire_sound = 'sound/magic/staff_shrink.ogg' + max_charges = 10 //10, 5, 5, 4 + no_den_usage = TRUE + w_class = WEIGHT_CLASS_TINY + +/obj/item/gun/magic/wand/shrink/zap_self(mob/living/user) + to_chat(user, span_notice("The world grows large...")) + charges-- + user.AddComponent(/datum/component/shrink, -1) // small forever + return ..() diff --git a/code/modules/projectiles/guns/special/grenade_launcher.dm b/code/modules/projectiles/guns/special/grenade_launcher.dm index e5ce8c51316a9..830952dd769e6 100644 --- a/code/modules/projectiles/guns/special/grenade_launcher.dm +++ b/code/modules/projectiles/guns/special/grenade_launcher.dm @@ -53,4 +53,4 @@ F.active = 1 F.icon_state = initial(F.icon_state) + "_active" playsound(user.loc, 'sound/weapons/armbomb.ogg', 75, TRUE, -3) - addtimer(CALLBACK(F, TYPE_PROC_REF(/obj/item/grenade, detonate)), 15) + addtimer(CALLBACK(F, TYPE_PROC_REF(/obj/item/grenade, detonate)), 1.5 SECONDS) diff --git a/code/modules/projectiles/guns/special/medbeam.dm b/code/modules/projectiles/guns/special/medbeam.dm index 267470f17013c..0ad5caf2fec82 100644 --- a/code/modules/projectiles/guns/special/medbeam.dm +++ b/code/modules/projectiles/guns/special/medbeam.dm @@ -16,12 +16,7 @@ weapon_weight = WEAPON_MEDIUM -/obj/item/gun/medbeam/Initialize(mapload) - . = ..() - START_PROCESSING(SSobj, src) - /obj/item/gun/medbeam/Destroy(mob/user) - STOP_PROCESSING(SSobj, src) LoseTarget() return ..() @@ -41,6 +36,7 @@ QDEL_NULL(current_beam) active = FALSE on_beam_release(current_target) + STOP_PROCESSING(SSobj, src) current_target = null /** @@ -69,6 +65,7 @@ active = TRUE current_beam = user.Beam(current_target, icon_state="medbeam", time = 10 MINUTES, maxdistance = max_range, beam_type = /obj/effect/ebeam/medical) RegisterSignal(current_beam, COMSIG_QDELETING, PROC_REF(beam_died))//this is a WAY better rangecheck than what was done before (process check) + START_PROCESSING(SSobj, src) SSblackbox.record_feedback("tally", "gun_fired", 1, type) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 602bbcc8c4ce6..8bc358b43874c 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -342,7 +342,7 @@ var/organ_hit_text = "" if(hit_limb_zone) - organ_hit_text = " in \the [parse_zone(hit_limb_zone)]" + organ_hit_text = " in \the [living_target.parse_zone_with_bodypart(hit_limb_zone)]" if(suppressed == SUPPRESSED_VERY) playsound(loc, hitsound, 5, TRUE, -1) else if(suppressed) @@ -457,7 +457,7 @@ if(!trajectory) qdel(src) return FALSE - if(impacted[A]) // NEVER doublehit + if(impacted[A.weak_reference]) // NEVER doublehit return FALSE var/datum/point/point_cache = trajectory.copy_to() var/turf/T = get_turf(A) @@ -510,7 +510,7 @@ if(QDELETED(src) || !T || !target) return // 2. - impacted[target] = TRUE //hash lookup > in for performance in hit-checking + impacted[WEAKREF(target)] = TRUE //hash lookup > in for performance in hit-checking // 3. var/mode = prehit_pierce(target) if(mode == PROJECTILE_DELETE_WITHOUT_HITTING) @@ -587,7 +587,7 @@ //Returns true if the target atom is on our current turf and above the right layer //If direct target is true it's the originally clicked target. /obj/projectile/proc/can_hit_target(atom/target, direct_target = FALSE, ignore_loc = FALSE, cross_failed = FALSE) - if(QDELETED(target) || impacted[target]) + if(QDELETED(target) || impacted[target.weak_reference]) return FALSE if(!ignore_loc && (loc != target.loc) && !(can_hit_turfs && direct_target && loc == target)) return FALSE @@ -675,7 +675,7 @@ * Used to not even attempt to Bump() or fail to Cross() anything we already hit. */ /obj/projectile/CanPassThrough(atom/blocker, movement_dir, blocker_opinion) - return impacted[blocker] ? TRUE : ..() + return ..() || impacted[blocker.weak_reference] /** * Projectile moved: @@ -1186,10 +1186,8 @@ var/turf/startloc = get_turf(src) var/obj/projectile/bullet = new projectile_type(startloc) bullet.starting = startloc - var/list/ignore = list() for (var/atom/thing as anything in ignore_targets) - ignore[thing] = TRUE - bullet.impacted += ignore + bullet.impacted[WEAKREF(thing)] = TRUE bullet.firer = firer || src bullet.fired_from = src bullet.yo = target.y - startloc.y diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index e75bbda4d8c5c..a8946379f8c52 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -249,23 +249,6 @@ /obj/projectile/beam/lasertag/bluetag/hitscan hitscan = TRUE -//a shrink ray that shrinks stuff, which grows back after a short while. -/obj/projectile/beam/shrink - name = "shrink ray" - icon_state = "blue_laser" - hitsound = 'sound/weapons/shrink_hit.ogg' - damage = 0 - damage_type = STAMINA - armor_flag = ENERGY - impact_effect_type = /obj/effect/temp_visual/impact_effect/shrink - light_color = LIGHT_COLOR_BLUE - var/shrink_time = 90 - -/obj/projectile/beam/shrink/on_hit(atom/target, blocked = 0, pierce_hit) - . = ..() - if(isopenturf(target) || isindestructiblewall(target))//shrunk floors wouldnt do anything except look weird, i-walls shouldn't be bypassable - return - target.AddComponent(/datum/component/shrink, shrink_time) - -/obj/projectile/beam/shrink/is_hostile_projectile() - return TRUE +/obj/projectile/magic/shrink/alien + antimagic_flags = NONE + shrink_time = 9 SECONDS diff --git a/code/modules/projectiles/projectile/bullets/junk.dm b/code/modules/projectiles/projectile/bullets/junk.dm new file mode 100644 index 0000000000000..344a732911347 --- /dev/null +++ b/code/modules/projectiles/projectile/bullets/junk.dm @@ -0,0 +1,71 @@ +// Junk (Pipe Pistols and Pipeguns) + +/obj/projectile/bullet/junk + name = "junk bullet" + icon_state = "trashball" + damage = 30 + embedding = list(embed_chance=15, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10) + var/bane_mob_biotypes = MOB_ROBOTIC + var/bane_multiplier = 1.5 + var/bane_added_damage = 0 + +/obj/projectile/bullet/junk/Initialize(mapload) + . = ..() + AddElement(/datum/element/bane, mob_biotypes = bane_mob_biotypes, target_type = /mob/living, damage_multiplier = bane_multiplier, added_damage = bane_added_damage, requires_combat_mode = FALSE) + +/obj/projectile/bullet/incendiary/fire/junk + name = "burning oil" + damage = 30 + fire_stacks = 5 + suppressed = SUPPRESSED_NONE + +/obj/projectile/bullet/junk/phasic + name = "junk phasic bullet" + icon_state = "gaussphase" + projectile_phasing = PASSTABLE | PASSGLASS | PASSGRILLE | PASSCLOSEDTURF | PASSMACHINE | PASSSTRUCTURE | PASSDOORS + +/obj/projectile/bullet/junk/shock + name = "bundle of live electrical parts" + icon_state = "tesla_projectile" + damage = 15 + embedding = null + shrapnel_type = null + bane_multiplier = 3 + +/obj/projectile/bullet/junk/shock/on_hit(atom/target, blocked = 0, pierce_hit) + . = ..() + if(isliving(target)) + var/mob/living/victim = target + victim.electrocute_act(damage, src, siemens_coeff = 1, flags = SHOCK_NOSTUN) + +/obj/projectile/bullet/junk/hunter + name = "junk hunter bullet" + icon_state = "gauss" + bane_mob_biotypes = MOB_ROBOTIC | MOB_BEAST | MOB_SPECIAL + bane_multiplier = 0 + bane_added_damage = 50 + +/obj/projectile/bullet/junk/ripper + name = "junk ripper bullet" + icon_state = "redtrac" + damage = 10 + embedding = list(embed_chance=100, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10) + wound_bonus = 10 + bare_wound_bonus = 30 + +/obj/projectile/bullet/junk/reaper + name = "junk reaper bullet" + tracer_type = /obj/effect/projectile/tracer/sniper + impact_type = /obj/effect/projectile/impact/sniper + muzzle_type = /obj/effect/projectile/muzzle/sniper + hitscan = TRUE + impact_effect_type = null + hitscan_light_intensity = 3 + hitscan_light_range = 0.75 + hitscan_light_color_override = LIGHT_COLOR_DIM_YELLOW + muzzle_flash_intensity = 5 + muzzle_flash_range = 1 + muzzle_flash_color_override = LIGHT_COLOR_DIM_YELLOW + impact_light_intensity = 5 + impact_light_range = 1 + impact_light_color_override = LIGHT_COLOR_DIM_YELLOW diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm index 7eb0945b18b48..1bb7988e4bae4 100644 --- a/code/modules/projectiles/projectile/energy/net_snare.dm +++ b/code/modules/projectiles/projectile/energy/net_snare.dm @@ -40,7 +40,7 @@ else com.target_ref = null - addtimer(CALLBACK(src, PROC_REF(pop), teletarget), 30) + addtimer(CALLBACK(src, PROC_REF(pop), teletarget), 3 SECONDS) /obj/effect/nettingportal/proc/pop(teletarget) if(teletarget) diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm index 5172a9984dae0..66ea4d2c86593 100644 --- a/code/modules/projectiles/projectile/energy/stun.dm +++ b/code/modules/projectiles/projectile/energy/stun.dm @@ -22,7 +22,7 @@ if(C.dna && C.dna.check_mutation(/datum/mutation/human/hulk)) C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") else if(!C.check_stun_immunity(CANKNOCKDOWN)) - addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 20), 5) + addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 20), 0.5 SECONDS) /obj/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet do_sparks(1, TRUE, src) diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index e52d38b3da111..1a25f8e23703a 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -580,3 +580,31 @@ damage_type = BURN damage = 2 antimagic_charge_cost = 0 // since the cards gets spammed like a shotgun + +//a shrink ray that shrinks stuff, which grows back after a short while. +/obj/projectile/magic/shrink + name = "shrink ray" + icon_state = "blue_laser" + hitsound = 'sound/weapons/shrink_hit.ogg' + damage = 0 + damage_type = STAMINA + armor_flag = ENERGY + impact_effect_type = /obj/effect/temp_visual/impact_effect/shrink + light_color = LIGHT_COLOR_BLUE + var/shrink_time = -1 + +/obj/projectile/magic/shrink/on_hit(atom/target, blocked = 0, pierce_hit) + . = ..() + if(isopenturf(target) || isindestructiblewall(target))//shrunk floors wouldnt do anything except look weird, i-walls shouldn't be bypassable + return + target.AddComponent(/datum/component/shrink, shrink_time) + +/obj/projectile/magic/shrink/is_hostile_projectile() + return TRUE + +/obj/projectile/magic/shrink/wand + shrink_time = 90 SECONDS + +/obj/projectile/magic/shrink/wand/on_hit(atom/target, blocked = 0, pierce_hit) + shrink_time = rand(60 SECONDS, 90 SECONDS) + return ..() diff --git a/code/modules/projectiles/projectile/special/saboteur.dm b/code/modules/projectiles/projectile/special/saboteur.dm index 4ef6b9ffcbe6d..46fcc136c0927 100644 --- a/code/modules/projectiles/projectile/special/saboteur.dm +++ b/code/modules/projectiles/projectile/special/saboteur.dm @@ -7,6 +7,7 @@ range = 21 projectile_phasing = PASSTABLE | PASSMOB | PASSMACHINE | PASSSTRUCTURE hitscan = TRUE + hit_threshhold = LOW_OBJ_LAYER // required to be able to hit floor lights var/disrupt_duration = 15 SECONDS /obj/projectile/energy/fisher/on_hit(atom/target, blocked, pierce_hit) diff --git a/code/modules/projectiles/projectile/special/wormhole.dm b/code/modules/projectiles/projectile/special/wormhole.dm index dbcb6f4cf8b30..c3a5159f8aa78 100644 --- a/code/modules/projectiles/projectile/special/wormhole.dm +++ b/code/modules/projectiles/projectile/special/wormhole.dm @@ -29,4 +29,5 @@ return BULLET_ACT_BLOCK . = ..() + playsound(loc, pick("sound/effects/portal_open1.ogg" , "sound/effects/portal_open2.ogg" , "sound/effects/portal_open3.ogg"), 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) projector.create_portal(src, get_turf(src)) diff --git a/code/modules/reagents/chemistry/chem_wiki_render.dm b/code/modules/reagents/chemistry/chem_wiki_render.dm index a2ac0af8ffb57..99116adc84b08 100644 --- a/code/modules/reagents/chemistry/chem_wiki_render.dm +++ b/code/modules/reagents/chemistry/chem_wiki_render.dm @@ -1,10 +1,6 @@ -//Generates a wikitable txt file for use with the wiki - does not support productless reactions at the moment -/client/proc/generate_wikichem_list() - set category = "Debug" - set name = "Parse Wikichems" - +ADMIN_VERB(generate_wikichem_list, R_DEBUG, "Parse Wikichems", "Parse and generate a text file for wikichem.", ADMIN_CATEGORY_DEBUG) //If we're a reaction product - var/prefix_reaction = {"{| class=\"wikitable sortable\" style=\"width:100%; text-align:left; border: 3px solid #FFDD66; cellspacing=0; cellpadding=2; background-color:white;\" + var/static/prefix_reaction = {"{| class=\"wikitable sortable\" style=\"width:100%; text-align:left; border: 3px solid #FFDD66; cellspacing=0; cellpadding=2; background-color:white;\" ! scope=\"col\" style='width:150px; background-color:#FFDD66;'|Name ! scope=\"col\" class=\"unsortable\" style='background-color:#FFDD66;'|Formula ! scope=\"col\" class=\"unsortable\" style='background-color:#FFDD66; width:170px;'|Reaction conditions @@ -13,9 +9,9 @@ |- "} - var/input_text = tgui_input_text(usr, "Input a name of a reagent, or a series of reagents split with a comma (no spaces) to get it's wiki table entry", "Recipe") //95% of the time, the reagent type is a lowercase, no spaces / underscored version of the name + var/input_text = tgui_input_text(user, "Input a name of a reagent, or a series of reagents split with a comma (no spaces) to get it's wiki table entry", "Recipe") //95% of the time, the reagent type is a lowercase, no spaces / underscored version of the name if(!input_text) - to_chat(usr, "Input was blank!") + to_chat(user, "Input was blank!") return text2file(prefix_reaction, "[GLOB.log_directory]/chem_parse.txt") var/list/names = splittext("[input_text]", ",") @@ -23,13 +19,13 @@ for(var/name in names) var/datum/reagent/reagent = find_reagent_object_from_type(get_chem_id(name)) if(!reagent) - to_chat(usr, "Could not find [name]. Skipping.") + to_chat(user, "Could not find [name]. Skipping.") continue //Get reaction var/list/reactions = GLOB.chemical_reactions_list_product_index[reagent.type] if(!length(reactions)) - to_chat(usr, "Could not find [name] reaction! Continuing anyways.") + to_chat(user, "Could not find [name] reaction! Continuing anyways.") var/single_parse = generate_chemwiki_line(reagent, null) text2file(single_parse, "[GLOB.log_directory]/chem_parse.txt") continue @@ -38,8 +34,7 @@ var/single_parse = generate_chemwiki_line(reagent, reaction) text2file(single_parse, "[GLOB.log_directory]/chem_parse.txt") text2file("|}", "[GLOB.log_directory]/chem_parse.txt") //Cap off the table - to_chat(usr, "Done! Saved file to (wherever your root folder is, i.e. where the DME is)/[GLOB.log_directory]/chem_parse.txt OR use the Get Current Logs verb under the Admin tab. (if you click Open, and it does nothing, that's because you've not set a .txt default program! Try downloading it instead, and use that file to set a default program! Have a nice day!") - + to_chat(user, "Done! Saved file to (wherever your root folder is, i.e. where the DME is)/[GLOB.log_directory]/chem_parse.txt OR use the Get Current Logs verb under the Admin tab. (if you click Open, and it does nothing, that's because you've not set a .txt default program! Try downloading it instead, and use that file to set a default program! Have a nice day!") /// Generate the big list of reagent based reactions. /proc/generate_chemwiki_line(datum/reagent/reagent, datum/chemical_reaction/reaction) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index bacef74180b02..68c4c2abff059 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -394,15 +394,15 @@ return ITEM_INTERACT_SUCCESS return ITEM_INTERACT_BLOCKING -/obj/machinery/chem_dispenser/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/machinery/chem_dispenser/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(is_reagent_container(tool) && !(tool.item_flags & ABSTRACT) && tool.is_open_container()) if(!user.transferItemToLoc(tool, src)) - return ..() + return ITEM_INTERACT_BLOCKING replace_beaker(user, tool) ui_interact(user) return ITEM_INTERACT_SUCCESS - return ..() + return NONE /obj/machinery/chem_dispenser/get_cell() return cell @@ -481,8 +481,6 @@ /obj/machinery/chem_dispenser/attack_ai_secondary(mob/user, list/modifiers) return attack_hand_secondary(user, modifiers) -/obj/machinery/chem_dispenser/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/machinery/chem_dispenser/drinks name = "soda dispenser" @@ -570,8 +568,7 @@ /obj/machinery/chem_dispenser/drinks/fullupgrade //fully ugpraded stock parts, emagged desc = "Contains a large reservoir of soft drinks. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION - circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/fullupgrade + obj_flags = CAN_BE_HIT | EMAGGED /obj/machinery/chem_dispenser/drinks/fullupgrade/Initialize(mapload) . = ..() @@ -630,7 +627,7 @@ /obj/machinery/chem_dispenser/drinks/beer/fullupgrade //fully ugpraded stock parts, emagged desc = "Contains a large reservoir of the good stuff. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION + obj_flags = CAN_BE_HIT | EMAGGED circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/beer/fullupgrade /obj/machinery/chem_dispenser/drinks/beer/fullupgrade/Initialize(mapload) @@ -654,7 +651,6 @@ /obj/machinery/chem_dispenser/mutagensaltpeter name = "botanical chemical dispenser" desc = "Creates and dispenses chemicals useful for botany." - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION circuit = /obj/item/circuitboard/machine/chem_dispenser/mutagensaltpeter /// The default list of dispensable reagents available in the mutagensaltpeter chem dispenser @@ -680,7 +676,7 @@ /obj/machinery/chem_dispenser/fullupgrade //fully ugpraded stock parts, emagged desc = "Creates and dispenses chemicals. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION + obj_flags = CAN_BE_HIT | EMAGGED circuit = /obj/item/circuitboard/machine/chem_dispenser/fullupgrade /obj/machinery/chem_dispenser/fullupgrade/Initialize(mapload) diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm index 857cd5bd22124..3cf5b75240065 100644 --- a/code/modules/reagents/chemistry/machinery/chem_heater.dm +++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm @@ -31,8 +31,12 @@ QDEL_NULL(beaker) return ..() -/obj/machinery/chem_heater/on_deconstruction(disassembled) - beaker?.forceMove(drop_location()) +/obj/machinery/chem_heater/Exited(atom/movable/gone, direction) + . = ..() + if(gone == beaker) + UnregisterSignal(beaker.reagents, COMSIG_REAGENTS_REACTION_STEP) + beaker = null + update_appearance() /obj/machinery/chem_heater/add_context(atom/source, list/context, obj/item/held_item, mob/user) if(isnull(held_item) || (held_item.item_flags & ABSTRACT) || (held_item.flags_1 & HOLOGRAM_1)) @@ -58,7 +62,6 @@ return NONE - /obj/machinery/chem_heater/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) @@ -80,25 +83,17 @@ icon_state = "[base_icon_state][beaker ? 1 : 0]b" return ..() -/obj/machinery/chem_heater/Exited(atom/movable/gone, direction) - . = ..() - if(gone == beaker) - UnregisterSignal(beaker.reagents, COMSIG_REAGENTS_REACTION_STEP) - beaker = null - update_appearance() - /obj/machinery/chem_heater/RefreshParts() . = ..() heater_coefficient = 0.1 for(var/datum/stock_part/micro_laser/micro_laser in component_parts) heater_coefficient *= micro_laser.tier +/obj/machinery/chem_heater/item_interaction(mob/living/user, obj/item/held_item, list/modifiers) + if(user.combat_mode || (held_item.item_flags & ABSTRACT) || (held_item.flags_1 & HOLOGRAM_1) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) + return NONE -/obj/machinery/chem_heater/item_interaction(mob/living/user, obj/item/held_item, list/modifiers, is_right_clicking) - if((held_item.item_flags & ABSTRACT) || (held_item.flags_1 & HOLOGRAM_1)) - return ..() - - if(QDELETED(beaker)) + if(!QDELETED(beaker)) if(istype(held_item, /obj/item/reagent_containers/dropper) || istype(held_item, /obj/item/reagent_containers/syringe)) var/obj/item/reagent_containers/injector = held_item injector.afterattack(beaker, user, proximity_flag = TRUE) @@ -110,19 +105,28 @@ balloon_alert(user, "beaker added") return ITEM_INTERACT_SUCCESS - return ..() + return NONE /obj/machinery/chem_heater/wrench_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + . = ITEM_INTERACT_BLOCKING if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS /obj/machinery/chem_heater/screwdriver_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + . = ITEM_INTERACT_BLOCKING if(default_deconstruction_screwdriver(user, "mixer0b", "[base_icon_state][beaker ? 1 : 0]b", tool)) return ITEM_INTERACT_SUCCESS /obj/machinery/chem_heater/crowbar_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + . = ITEM_INTERACT_BLOCKING if(default_deconstruction_crowbar(tool)) return ITEM_INTERACT_SUCCESS @@ -174,12 +178,13 @@ PRIVATE_PROC(TRUE) //must be on and beaker must have something inside to heat - if(!on || (machine_stat & NOPOWER) || QDELETED(beaker) || !beaker.reagents.total_volume) + if(!on || !is_operational || QDELETED(beaker) || !beaker.reagents.total_volume) return FALSE //heat the beaker and use some power. we want to use only a small amount of power since this proc gets called frequently - beaker.reagents.adjust_thermal_energy((target_temperature - beaker.reagents.chem_temp) * heater_coefficient * seconds_per_tick * SPECIFIC_HEAT_DEFAULT * beaker.reagents.total_volume) - use_energy(active_power_usage * seconds_per_tick * 0.3) + var/energy = (target_temperature - beaker.reagents.chem_temp) * heater_coefficient * seconds_per_tick * beaker.reagents.heat_capacity() + beaker.reagents.adjust_thermal_energy(energy) + use_energy(active_power_usage + abs(ROUND_UP(energy) / 120)) return TRUE /obj/machinery/chem_heater/proc/on_reaction_step(datum/reagents/holder, num_reactions, seconds_per_tick) diff --git a/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm b/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm index 298fe25981445..e11910a13afce 100644 --- a/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm +++ b/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm @@ -147,9 +147,9 @@ for(var/datum/stock_part/micro_laser/laser in component_parts) cms_coefficient /= laser.tier -/obj/machinery/chem_mass_spec/item_interaction(mob/living/user, obj/item/item, list/modifiers, is_right_clicking) +/obj/machinery/chem_mass_spec/item_interaction(mob/living/user, obj/item/item, list/modifiers) if((item.item_flags & ABSTRACT) || (item.flags_1 & HOLOGRAM_1) || !can_interact(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return ..() + return NONE if(is_reagent_container(item) && item.is_open_container()) if(processing_reagents) @@ -160,13 +160,14 @@ if(!user.transferItemToLoc(beaker, src)) return ITEM_INTERACT_BLOCKING + var/is_right_clicking = LAZYACCESS(modifiers, RIGHT_CLICK) replace_beaker(user, !is_right_clicking, beaker) to_chat(user, span_notice("You add [beaker] to [is_right_clicking ? "output" : "input"] slot.")) update_appearance() ui_interact(user) return ITEM_INTERACT_SUCCESS - return ..() + return NONE /obj/machinery/chem_mass_spec/wrench_act(mob/living/user, obj/item/tool) . = ITEM_INTERACT_BLOCKING @@ -240,11 +241,11 @@ lower_mass_range = calculate_mass(smallest = TRUE) upper_mass_range = calculate_mass(smallest = FALSE) estimate_time() - else //replace output beaker if(!QDELETED(beaker2)) try_put_in_hand(beaker2, user) beaker2 = new_beaker + log.Cut() update_appearance() @@ -257,8 +258,8 @@ return for(var/datum/reagent/reagent as anything in beaker1.reagents.reagent_list) - //we don't bother about impure chems - if(istype(reagent, /datum/reagent/inverse) || (reagent.inverse_chem_val > reagent.purity && reagent.inverse_chem)) + //we don't deal chems that are so impure that they are about to become inverted + if(reagent.inverse_chem_val > reagent.purity && reagent.inverse_chem) continue //out of our selected range if(reagent.mass < lower_mass_range || reagent.mass > upper_mass_range) @@ -299,10 +300,7 @@ var/purity = target.purity var/is_inverse = FALSE - if(istype(reagent, /datum/reagent/inverse)) - log = "Too impure to use" //we don't bother about impure chems - is_inverse = TRUE - else if(reagent.inverse_chem_val > reagent.purity && reagent.inverse_chem) + if(reagent.inverse_chem_val > reagent.purity && reagent.inverse_chem) purity = target.get_inverse_purity() target = GLOB.chemical_reagents_list[reagent.inverse_chem] log = "Too impure to use" //we don't bother about impure chems @@ -351,13 +349,9 @@ /obj/machinery/chem_mass_spec/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() - if(.) + if(. || processing_reagents) return - if(processing_reagents) - balloon_alert(ui.user, "still processing") - return ..() - switch(action) if("activate") if(QDELETED(beaker1)) @@ -433,14 +427,12 @@ replace_beaker(ui.user, FALSE) return TRUE -/obj/machinery/chem_mass_spec/AltClick(mob/living/user) - . = ..() - if(!can_interact(user)) - return +/obj/machinery/chem_mass_spec/click_alt(mob/living/user) if(processing_reagents) balloon_alert(user, "still processing!") - return ..() + return CLICK_ACTION_BLOCKING replace_beaker(user, TRUE) + return CLICK_ACTION_SUCCESS /obj/machinery/chem_mass_spec/alt_click_secondary(mob/living/user) . = ..() @@ -455,10 +447,7 @@ if(!processing_reagents) return PROCESS_KILL - if(!is_operational || panel_open || !anchored || (machine_stat & (BROKEN | NOPOWER))) - return - - if(!use_energy(active_power_usage * seconds_per_tick)) + if(!is_operational || panel_open || !anchored) return progress_time += seconds_per_tick @@ -468,8 +457,8 @@ log.Cut() for(var/datum/reagent/reagent as anything in beaker1.reagents.reagent_list) - //we don't bother about impure chems - if(istype(reagent, /datum/reagent/inverse) || (reagent.inverse_chem_val > reagent.purity && reagent.inverse_chem)) + //we don't deal chems that are so impure that they are about to become inverted + if(reagent.inverse_chem_val > reagent.purity && reagent.inverse_chem) continue //out of our selected range if(reagent.mass < lower_mass_range || reagent.mass > upper_mass_range) @@ -490,3 +479,5 @@ estimate_time() update_appearance() return PROCESS_KILL + + use_energy(active_power_usage * seconds_per_tick) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index afd81d7fb9544..4524b3f0567ad 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -1,84 +1,96 @@ -#define TRANSFER_MODE_DESTROY 0 -#define TRANSFER_MODE_MOVE 1 -#define TARGET_BEAKER "beaker" -#define TARGET_BUFFER "buffer" +#define MAX_CONTAINER_PRINT_AMOUNT 50 /obj/machinery/chem_master name = "ChemMaster 3000" desc = "Used to separate chemicals and distribute them in a variety of forms." - density = TRUE - layer = BELOW_OBJ_LAYER icon = 'icons/obj/medical/chemical.dmi' icon_state = "chemmaster" base_icon_state = "chemmaster" + density = TRUE idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.2 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.2 resistance_flags = FIRE_PROOF | ACID_PROOF circuit = /obj/item/circuitboard/machine/chem_master - /// Icons for different percentages of buffer reagents - var/fill_icon = 'icons/obj/medical/reagent_fillings.dmi' - var/fill_icon_state = "chemmaster" - var/static/list/fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) + /// Inserted reagent container var/obj/item/reagent_containers/beaker /// Whether separated reagents should be moved back to container or destroyed. - var/transfer_mode = TRANSFER_MODE_MOVE - /// Whether reagent analysis screen is active - var/reagent_analysis_mode = FALSE - /// Reagent being analyzed - var/datum/reagent/analyzed_reagent + var/is_transfering = TRUE /// List of printable container types - var/list/printable_containers = list() - /// Container used by default to reset to (REF) - var/default_container - /// Selected printable container type (REF) - var/selected_container - /// Whether the machine has an option to suggest container - var/has_container_suggestion = FALSE - /// Whether to suggest container or not - var/do_suggest_container = FALSE - /// The container suggested by main reagent in the buffer - var/suggested_container + var/list/printable_containers + /// Container used by default to reset to + var/obj/item/reagent_containers/default_container + /// Selected printable container type + var/obj/item/reagent_containers/selected_container /// Whether the machine is busy with printing containers var/is_printing = FALSE - /// Number of printed containers in the current printing cycle for UI progress bar + /// Number of containers printed so far var/printing_progress + /// Number of containers to be printed var/printing_total - /// Default duration of printing cycle - var/printing_speed = 0.75 SECONDS // Duration of animation - /// The amount of containers printed in one cycle - var/printing_amount = 1 + /// The time it takes to print a container + var/printing_speed = 0.75 SECONDS /obj/machinery/chem_master/Initialize(mapload) create_reagents(100) - load_printable_containers() - default_container = REF(printable_containers[printable_containers[1]][1]) + + printable_containers = load_printable_containers() + default_container = printable_containers[printable_containers[1]][1] selected_container = default_container - return ..() + + register_context() + + . = ..() + + var/obj/item/circuitboard/machine/chem_master/board = circuit + board.build_path = type + board.name = name /obj/machinery/chem_master/Destroy() QDEL_NULL(beaker) return ..() -/obj/machinery/chem_master/on_deconstruction(disassembled) - replace_beaker() - return ..() +/obj/machinery/chem_master/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + if(isnull(held_item) || (held_item.item_flags & ABSTRACT) || (held_item.flags_1 & HOLOGRAM_1)) + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_RMB] = "Remove beaker" + . = CONTEXTUAL_SCREENTIP_SET + return . -/obj/machinery/chem_master/Exited(atom/movable/gone, direction) - . = ..() - if(gone == beaker) - beaker = null - update_appearance(UPDATE_ICON) + if(is_reagent_container(held_item) && held_item.is_open_container()) + if(!QDELETED(beaker)) + context[SCREENTIP_CONTEXT_LMB] = "Replace beaker" + else + context[SCREENTIP_CONTEXT_LMB] = "Insert beaker" + return CONTEXTUAL_SCREENTIP_SET + + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] panel" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""] anchor" + return CONTEXTUAL_SCREENTIP_SET + else if(panel_open && held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET -/obj/machinery/chem_master/RefreshParts() +/obj/machinery/chem_master/examine(mob/user) . = ..() - reagents.maximum_volume = 0 - for(var/obj/item/reagent_containers/cup/beaker/beaker in component_parts) - reagents.maximum_volume += beaker.reagents.maximum_volume - printing_amount = 0 - for(var/datum/stock_part/servo/servo in component_parts) - printing_amount += servo.tier - -/obj/machinery/chem_master/update_appearance(updates=ALL) + if(in_range(user, src) || isobserver(user)) + . += span_notice("The status display reads:
    Reagent buffer capacity: [reagents.maximum_volume] units.
    Printing speed: [0.75 SECONDS / printing_speed * 100]%.") + if(!QDELETED(beaker)) + . += span_notice("[beaker] of [beaker.reagents.maximum_volume]u capacity inserted") + . += span_notice("Right click with empty hand to remove beaker") + else + . += span_warning("Missing input beaker") + + . += span_notice("It can be [EXAMINE_HINT("wrenched")] [anchored ? "loose" : "in place"]") + . += span_notice("Its maintainence panel can be [EXAMINE_HINT("screwed")] [panel_open ? "close" : "open"]") + if(panel_open) + . += span_notice("The machine can be [EXAMINE_HINT("pried")] apart.") + +/obj/machinery/chem_master/update_appearance(updates) . = ..() if(panel_open || (machine_stat & (NOPOWER|BROKEN))) set_light(0) @@ -102,9 +114,7 @@ // Screen overlay if(!panel_open && !(machine_stat & (NOPOWER | BROKEN))) var/screen_overlay = base_icon_state + "_overlay_screen" - if(reagent_analysis_mode) - screen_overlay += "_analysis" - else if(is_printing) + if(is_printing) screen_overlay += "_active" else if(reagents.total_volume > 0) screen_overlay += "_main" @@ -114,45 +124,125 @@ // Buffer reagents overlay if(reagents.total_volume) var/threshold = null + var/static/list/fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) for(var/i in 1 to fill_icon_thresholds.len) - if(ROUND_UP(100 * reagents.total_volume / reagents.maximum_volume) >= fill_icon_thresholds[i]) + if(ROUND_UP(100 * (reagents.total_volume / reagents.maximum_volume)) >= fill_icon_thresholds[i]) threshold = i if(threshold) - var/fill_name = "[fill_icon_state][fill_icon_thresholds[threshold]]" - var/mutable_appearance/filling = mutable_appearance(fill_icon, fill_name) + var/fill_name = "chemmaster[fill_icon_thresholds[threshold]]" + var/mutable_appearance/filling = mutable_appearance('icons/obj/medical/reagent_fillings.dmi', fill_name) filling.color = mix_color_from_reagents(reagents.reagent_list) . += filling +/obj/machinery/chem_master/Exited(atom/movable/gone, direction) + . = ..() + if(gone == beaker) + beaker = null + update_appearance(UPDATE_OVERLAYS) + +/obj/machinery/chem_master/on_set_is_operational(old_value) + if(!is_operational) + is_printing = FALSE + update_appearance(UPDATE_OVERLAYS) + +/obj/machinery/chem_master/RefreshParts() + . = ..() + reagents.maximum_volume = 0 + for(var/obj/item/reagent_containers/cup/beaker/beaker in component_parts) + reagents.maximum_volume += beaker.reagents.maximum_volume + + //Servo tier determines printing speed + printing_speed = 1 SECONDS + for(var/datum/stock_part/servo/servo in component_parts) + printing_speed -= servo.tier * 0.25 SECONDS + printing_speed = max(printing_speed, 0.25 SECONDS) + +///Return a map of category->list of containers this machine can print +/obj/machinery/chem_master/proc/load_printable_containers() + PROTECTED_PROC(TRUE) + SHOULD_BE_PURE(TRUE) + + var/static/list/containers + if(!length(containers)) + containers = list( + CAT_TUBES = GLOB.reagent_containers[CAT_TUBES], + CAT_PILLS = GLOB.reagent_containers[CAT_PILLS], + CAT_PATCHES = GLOB.reagent_containers[CAT_PATCHES], + ) + return containers + +/obj/machinery/chem_master/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(user.combat_mode || (tool.item_flags & ABSTRACT) || (tool.flags_1 & HOLOGRAM_1) || !can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) + return NONE + + if(is_reagent_container(tool) && tool.is_open_container()) + replace_beaker(user, tool) + if(!panel_open) + ui_interact(user) + return ITEM_INTERACT_SUCCESS + else + return ITEM_INTERACT_BLOCKING + + return NONE + /obj/machinery/chem_master/wrench_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(is_printing) + balloon_alert(user, "still printing!") + return . + if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS - return ITEM_INTERACT_BLOCKING /obj/machinery/chem_master/screwdriver_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(is_printing) + balloon_alert(user, "still printing!") + return . + if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool)) - update_appearance(UPDATE_ICON) + update_appearance(UPDATE_OVERLAYS) return ITEM_INTERACT_SUCCESS - return ITEM_INTERACT_BLOCKING /obj/machinery/chem_master/crowbar_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(is_printing) + balloon_alert(user, "still printing!") + return . + if(default_deconstruction_crowbar(tool)) return ITEM_INTERACT_SUCCESS - return ITEM_INTERACT_BLOCKING -/obj/machinery/chem_master/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - if(is_reagent_container(tool) && !(tool.item_flags & ABSTRACT) && tool.is_open_container()) - replace_beaker(user, tool) - if(!panel_open) - ui_interact(user) - return ITEM_INTERACT_SUCCESS +/** + * Insert, remove, replace the existig beaker + * Arguments + * + * * mob/living/user - the player trying to replace the beaker + * * obj/item/reagent_containers/new_beaker - the beaker we are trying to insert, swap with existing or remove if null + */ +/obj/machinery/chem_master/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) + PRIVATE_PROC(TRUE) - return ..() + if(!QDELETED(beaker)) + try_put_in_hand(beaker, user) + if(!QDELETED(new_beaker) && user.transferItemToLoc(new_beaker, src)) + beaker = new_beaker + update_appearance(UPDATE_OVERLAYS) /obj/machinery/chem_master/attack_hand_secondary(mob/user, list/modifiers) . = ..() if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return . - if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH)) + if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) return . replace_beaker(user) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN @@ -163,25 +253,6 @@ /obj/machinery/chem_master/attack_ai_secondary(mob/user, list/modifiers) return attack_hand_secondary(user, modifiers) -/// Insert new beaker and/or eject the inserted one -/obj/machinery/chem_master/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) - if(new_beaker && user && !user.transferItemToLoc(new_beaker, src)) - return FALSE - if(beaker) - try_put_in_hand(beaker, user) - beaker = null - if(new_beaker) - beaker = new_beaker - update_appearance(UPDATE_ICON) - return TRUE - -/obj/machinery/chem_master/proc/load_printable_containers() - printable_containers = list( - CAT_TUBES = GLOB.reagent_containers[CAT_TUBES], - CAT_PILLS = GLOB.reagent_containers[CAT_PILLS], - CAT_PATCHES = GLOB.reagent_containers[CAT_PATCHES], - ) - /obj/machinery/chem_master/ui_assets(mob/user) return list( get_asset_datum(/datum/asset/spritesheet/chemmaster) @@ -195,269 +266,286 @@ /obj/machinery/chem_master/ui_static_data(mob/user) var/list/data = list() + + data["maxPrintable"] = MAX_CONTAINER_PRINT_AMOUNT data["categories"] = list() for(var/category in printable_containers) - var/container_data = list() + //make the category + var/list/category_list = list( + "name" = category, + "containers" = list(), + ) + + //add containers to this category for(var/obj/item/reagent_containers/container as anything in printable_containers[category]) - container_data += list(list( + category_list["containers"] += list(list( "icon" = sanitize_css_class_name("[container]"), "ref" = REF(container), "name" = initial(container.name), "volume" = initial(container.volume), )) - data["categories"]+= list(list( - "name" = category, - "containers" = container_data, - )) + + //add the category + data["categories"] += list(category_list) return data /obj/machinery/chem_master/ui_data(mob/user) - var/list/data = list() + . = list() + + //printing statictics + .["isPrinting"] = is_printing + .["printingProgress"] = printing_progress + .["printingTotal"] = printing_total + + //contents of source beaker + var/list/beaker_data = null + if(!QDELETED(beaker)) + beaker_data = list() + beaker_data["maxVolume"] = beaker.volume + beaker_data["currentVolume"] = round(beaker.reagents.total_volume, CHEMICAL_VOLUME_ROUNDING) + var/list/beakerContents = list() + if(length(beaker.reagents.reagent_list)) + for(var/datum/reagent/reagent as anything in beaker.reagents.reagent_list) + beakerContents += list(list( + "ref" = "[reagent.type]", + "name" = reagent.name, + "volume" = round(reagent.volume, CHEMICAL_VOLUME_ROUNDING), + "pH" = reagent.ph, + "color" = reagent.color, + "description" = reagent.description, + "purity" = reagent.purity, + "metaRate" = reagent.metabolization_rate, + "overdose" = reagent.overdose_threshold, + "addictionTypes" = reagents.parse_addictions(reagent), + )) + beaker_data["contents"] = beakerContents + .["beaker"] = beaker_data + + //contents of buffer + beaker_data = list() + beaker_data["maxVolume"] = reagents.maximum_volume + beaker_data["currentVolume"] = round(reagents.total_volume, CHEMICAL_VOLUME_ROUNDING) + var/list/beakerContents = list() + if(length(reagents.reagent_list)) + for(var/datum/reagent/reagent as anything in reagents.reagent_list) + beakerContents += list(list( + "ref" = "[reagent.type]", + "name" = reagent.name, + "volume" = round(reagent.volume, CHEMICAL_VOLUME_ROUNDING), + "pH" = reagent.ph, + "color" = reagent.color, + "description" = reagent.description, + "purity" = reagent.purity, + "metaRate" = reagent.metabolization_rate, + "overdose" = reagent.overdose_threshold, + "addictionTypes" = reagents.parse_addictions(reagent), + )) + beaker_data["contents"] = beakerContents + .["buffer"] = beaker_data + + //is transfering or destroying reagents. applied only for buffer + .["isTransfering"] = is_transfering + + //container along with the suggested type + var/obj/item/reagent_containers/suggested_container = default_container + if(reagents.total_volume > 0) + var/datum/reagent/master_reagent = reagents.get_master_reagent() + var/container_found = FALSE + suggested_container = master_reagent.default_container + for(var/category in printable_containers) + for(var/obj/item/reagent_containers/container as anything in printable_containers[category]) + if(container == suggested_container) + suggested_container = REF(container) + container_found = TRUE + break + if(!container_found) + suggested_container = REF(default_container) + .["suggestedContainerRef"] = suggested_container + + //selected container + .["selectedContainerRef"] = REF(selected_container) + .["selectedContainerVolume"] = initial(selected_container.volume) + +/** + * Transfers a single reagent between buffer & beaker + * Arguments + * + * * mob/user - the player who is attempting the transfer + * * datum/reagents/source - the holder we are transferring from + * * datum/reagents/target - the holder we are transferring to + * * datum/reagent/path - the reagent typepath we are transfering + * * amount - volume to transfer -1 means custom amount + * * do_transfer - transfer the reagents else destroy them + */ +/obj/machinery/chem_master/proc/transfer_reagent(mob/user, datum/reagents/source, datum/reagents/target, datum/reagent/path, amount, do_transfer) + PRIVATE_PROC(TRUE) + + //sanity checks for transfer amount + if(isnull(amount)) + return FALSE + amount = text2num(amount) + if(isnull(amount)) + return FALSE + if(amount == -1) + var/target_amount = tgui_input_number(user, "Enter amount to transfer", "Transfer amount") + if(!target_amount) + return FALSE + amount = text2num(target_amount) + if(isnull(amount)) + return FALSE + if(amount <= 0) + return FALSE - data["reagentAnalysisMode"] = reagent_analysis_mode - if(reagent_analysis_mode && analyzed_reagent) - var/state - switch(analyzed_reagent.reagent_state) - if(SOLID) - state = "Solid" - if(LIQUID) - state = "Liquid" - if(GAS) - state = "Gas" - else - state = "Unknown" - data["analysisData"] = list( - "name" = analyzed_reagent.name, - "state" = state, - "pH" = analyzed_reagent.ph, - "color" = analyzed_reagent.color, - "description" = analyzed_reagent.description, - "purity" = analyzed_reagent.purity, - "metaRate" = analyzed_reagent.metabolization_rate, - "overdose" = analyzed_reagent.overdose_threshold, - "addictionTypes" = reagents.parse_addictions(analyzed_reagent), - ) - else - data["isPrinting"] = is_printing - data["printingProgress"] = printing_progress - data["printingTotal"] = printing_total - data["hasBeaker"] = beaker ? TRUE : FALSE - data["beakerCurrentVolume"] = beaker ? round(beaker.reagents.total_volume, 0.01) : null - data["beakerMaxVolume"] = beaker ? beaker.volume : null - var/list/beaker_contents = list() - if(beaker) - for(var/datum/reagent/reagent in beaker.reagents.reagent_list) - beaker_contents.Add(list(list("name" = reagent.name, "ref" = REF(reagent), "volume" = round(reagent.volume, 0.01)))) - data["beakerContents"] = beaker_contents - - var/list/buffer_contents = list() - if(reagents.total_volume) - for(var/datum/reagent/reagent in reagents.reagent_list) - buffer_contents.Add(list(list("name" = reagent.name, "ref" = REF(reagent), "volume" = round(reagent.volume, 0.01)))) - data["bufferContents"] = buffer_contents - data["bufferCurrentVolume"] = round(reagents.total_volume, 0.01) - data["bufferMaxVolume"] = reagents.maximum_volume - - data["transferMode"] = transfer_mode - - data["hasContainerSuggestion"] = !!has_container_suggestion - if(has_container_suggestion) - data["doSuggestContainer"] = !!do_suggest_container - if(do_suggest_container) - if(reagents.total_volume > 0) - var/master_reagent = reagents.get_master_reagent() - suggested_container = get_suggested_container(master_reagent) - else - suggested_container = default_container - data["suggestedContainer"] = suggested_container - selected_container = suggested_container - else if (isnull(selected_container)) - selected_container = default_container - - data["selectedContainerRef"] = selected_container - var/obj/item/reagent_containers/container = locate(selected_container) - data["selectedContainerVolume"] = initial(container.volume) + //sanity checks for reagent path + var/datum/reagent/reagent = text2path(path) + if (!reagent) + return FALSE - return data + //use energy + if(!use_energy(active_power_usage, force = FALSE)) + return FALSE -/obj/machinery/chem_master/ui_act(action, params) + //do the operation + . = FALSE + if(do_transfer) + if(target.is_reacting) + return FALSE + if(source.trans_to(target, amount, target_id = reagent)) + . = TRUE + else if(source.remove_reagent(reagent, amount)) + . = TRUE + if(. && !QDELETED(src)) //transferring volatile reagents can cause a explosion & destory us + update_appearance(UPDATE_OVERLAYS) + return . + +/obj/machinery/chem_master/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return - if(action == "eject") - replace_beaker(usr) - return TRUE - - if(action == "transfer") - var/reagent_ref = params["reagentRef"] - var/amount = text2num(params["amount"]) - var/target = params["target"] - return transfer_reagent(reagent_ref, amount, target) - - if(action == "toggleTransferMode") - transfer_mode = !transfer_mode - return TRUE - - if(action == "analyze") - analyzed_reagent = locate(params["reagentRef"]) - if(analyzed_reagent) - reagent_analysis_mode = TRUE - update_appearance(UPDATE_ICON) + switch(action) + if("eject") + replace_beaker(ui.user) return TRUE - if(action == "stopAnalysis") - reagent_analysis_mode = FALSE - analyzed_reagent = null - update_appearance(UPDATE_ICON) - return TRUE + if("transfer") + if(is_printing) + say("buffer locked while printing!") + return - if(action == "stopPrinting") - is_printing = FALSE - return TRUE + var/reagent_ref = params["reagentRef"] + var/amount = params["amount"] + var/target = params["target"] - if(action == "toggleContainerSuggestion") - do_suggest_container = !do_suggest_container - return TRUE + if(target == "buffer") + return transfer_reagent(ui.user, beaker.reagents, reagents, reagent_ref, amount, TRUE) + else if(target == "beaker") + return transfer_reagent(ui.user, reagents, beaker.reagents, reagent_ref, amount, is_transfering) + return FALSE - if(action == "selectContainer") - selected_container = params["ref"] - return TRUE + if("toggleTransferMode") + is_transfering = !is_transfering + return TRUE - if(action == "create") - if(reagents.total_volume == 0) - return FALSE - var/item_count = text2num(params["itemCount"]) - if(item_count <= 0) - return FALSE - create_containers(item_count) - return TRUE - -/// Create N selected containers with reagents from buffer split between them -/obj/machinery/chem_master/proc/create_containers(item_count = 1) - var/obj/item/reagent_containers/container_style = locate(selected_container) - var/is_pill_subtype = ispath(container_style, /obj/item/reagent_containers/pill) - var/volume_in_each = reagents.total_volume / item_count - var/printing_amount_current = is_pill_subtype ? printing_amount * 2 : printing_amount - - // Generate item name - var/item_name_default = initial(container_style.name) - var/datum/reagent/master_reagent = reagents.get_master_reagent() - if(selected_container == default_container) // Tubes and bottles gain reagent name - item_name_default = "[master_reagent.name] [item_name_default]" - if(!(initial(container_style.reagent_flags) & OPENCONTAINER)) // Closed containers get both reagent name and units in the name - item_name_default = "[master_reagent.name] [item_name_default] ([volume_in_each]u)" - var/item_name = tgui_input_text(usr, - "Container name", - "Name", - item_name_default, - MAX_NAME_LEN) - - if(!item_name || !reagents.total_volume || QDELETED(src) || !usr.can_perform_action(src, ALLOW_SILICON_REACH)) - return FALSE + if("stopPrinting") + is_printing = FALSE + update_appearance(UPDATE_OVERLAYS) + return TRUE - // Print and fill containers - is_printing = TRUE - update_appearance(UPDATE_ICON) - printing_progress = 0 - printing_total = item_count - while(item_count > 0) - if(!is_printing) - break - use_energy(active_power_usage) - stoplag(printing_speed) - for(var/i in 1 to printing_amount_current) - if(!item_count) - continue - var/obj/item/reagent_containers/item = new container_style(drop_location()) - adjust_item_drop_location(item) - item.name = item_name - item.reagents.clear_reagents() - reagents.trans_to(item, volume_in_each, transferred_by = src) - printing_progress++ - item_count-- - update_appearance(UPDATE_ICON) - is_printing = FALSE - update_appearance(UPDATE_ICON) - return TRUE - -/// Transfer reagents to specified target from the opposite source -/obj/machinery/chem_master/proc/transfer_reagent(reagent_ref, amount, target) - if (amount == -1) - amount = text2num(input("Enter the amount you want to transfer:", name, "")) - if (amount == null || amount <= 0) - return FALSE - if (!beaker && target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_MOVE) - return FALSE - var/datum/reagent/reagent = locate(reagent_ref) - if (!reagent) - return FALSE + if("selectContainer") + var/obj/item/reagent_containers/target = locate(params["ref"]) + if(!ispath(target)) + return FALSE - use_energy(active_power_usage) + selected_container = target + return TRUE - if (target == TARGET_BUFFER) - if(!check_reactions(reagent, beaker.reagents)) - return FALSE - beaker.reagents.trans_to(src, amount, target_id = reagent.type) - update_appearance(UPDATE_ICON) - return TRUE - - if (target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_DESTROY) - reagents.remove_reagent(reagent.type, amount) - update_appearance(UPDATE_ICON) - return TRUE - if (target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_MOVE) - if(!check_reactions(reagent, reagents)) - return FALSE - reagents.trans_to(beaker, amount, target_id = reagent.type) - update_appearance(UPDATE_ICON) - return TRUE + if("create") + if(!reagents.total_volume || is_printing) + return FALSE + + //validate print count + var/item_count = params["itemCount"] + if(isnull(item_count)) + return FALSE + item_count = text2num(item_count) + if(isnull(item_count) || item_count <= 0) + return FALSE + item_count = min(item_count, MAX_CONTAINER_PRINT_AMOUNT) + var/volume_in_each = round(reagents.total_volume / item_count, CHEMICAL_VOLUME_ROUNDING) + + // Generate item name + var/item_name_default = initial(selected_container.name) + var/datum/reagent/master_reagent = reagents.get_master_reagent() + if(selected_container == default_container) // Tubes and bottles gain reagent name + item_name_default = "[master_reagent.name] [item_name_default]" + if(!(initial(selected_container.reagent_flags) & OPENCONTAINER)) // Closed containers get both reagent name and units in the name + item_name_default = "[master_reagent.name] [item_name_default] ([volume_in_each]u)" + var/item_name = tgui_input_text(usr, + "Container name", + "Name", + item_name_default, + MAX_NAME_LEN) + if(!item_name) + return FALSE + + //start printing + is_printing = TRUE + printing_progress = 0 + printing_total = item_count + update_appearance(UPDATE_OVERLAYS) + create_containers(ui.user, item_count, item_name, volume_in_each) + return TRUE - return FALSE +/** + * Create N selected containers with reagents from buffer split between them + * Arguments + * + * * mob/user - the player printing these containers + * * item_count - number of containers to print + * * item_name - the name for each container printed + * * volume_in_each - volume in each container created + */ +/obj/machinery/chem_master/proc/create_containers(mob/user, item_count, item_name, volume_in_each) + PRIVATE_PROC(TRUE) + + //lost power or manually stopped + if(!is_printing) + return -/// Checks to see if the target reagent is being created (reacting) and if so prevents transfer -/// Only prevents reactant from being moved so that people can still manlipulate input reagents -/obj/machinery/chem_master/proc/check_reactions(datum/reagent/reagent, datum/reagents/holder) - if(!reagent) - return FALSE - var/canMove = TRUE - for(var/datum/equilibrium/equilibrium as anything in holder.reaction_list) - if(equilibrium.reaction.reaction_flags & REACTION_COMPETITIVE) - continue - for(var/datum/reagent/result as anything in equilibrium.reaction.required_reagents) - if(result == reagent.type) - canMove = FALSE - if(!canMove) - say("Cannot move reagent during reaction!") - return canMove - -/// Retrieve REF to the best container for provided reagent -/obj/machinery/chem_master/proc/get_suggested_container(datum/reagent/reagent) - var/preferred_container = reagent.default_container - for(var/category in printable_containers) - for(var/container in printable_containers[category]) - if(container == preferred_container) - return REF(container) - return default_container + //use power + if(!use_energy(active_power_usage, force = FALSE)) + is_printing = FALSE + update_appearance(UPDATE_OVERLAYS) + return -/obj/machinery/chem_master/examine(mob/user) - . = ..() - if(in_range(user, src) || isobserver(user)) - . += span_notice("The status display reads:
    Reagent buffer capacity: [reagents.maximum_volume] units.
    Number of containers printed at once increased by [100 * (printing_amount / initial(printing_amount)) - 100]%.") + //print the stuff + var/obj/item/reagent_containers/item = new selected_container(drop_location()) + adjust_item_drop_location(item) + item.name = item_name + item.reagents.clear_reagents() + reagents.trans_to(item, volume_in_each, transferred_by = user) + printing_progress++ + update_appearance(UPDATE_OVERLAYS) + + //print more items + item_count -- + if(item_count > 0) + addtimer(CALLBACK(src, PROC_REF(create_containers), user, item_count, item_name, volume_in_each), printing_speed) + else + is_printing = FALSE + update_appearance(UPDATE_OVERLAYS) /obj/machinery/chem_master/condimaster name = "CondiMaster 3000" desc = "Used to create condiments and other cooking supplies." icon_state = "condimaster" - has_container_suggestion = TRUE /obj/machinery/chem_master/condimaster/load_printable_containers() - printable_containers = list( - CAT_CONDIMENTS = GLOB.reagent_containers[CAT_CONDIMENTS], - ) + var/static/list/containers + if(!length(containers)) + containers = list(CAT_CONDIMENTS = GLOB.reagent_containers[CAT_CONDIMENTS]) + return containers -#undef TRANSFER_MODE_DESTROY -#undef TRANSFER_MODE_MOVE -#undef TARGET_BEAKER -#undef TARGET_BUFFER +#undef MAX_CONTAINER_PRINT_AMOUNT diff --git a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm index c0cb45dda2aa2..552bfe48650ca 100644 --- a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm +++ b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm @@ -6,14 +6,16 @@ base_icon_state = "dispenser" amount = 10 resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION use_power = NO_POWER_USE - var/static/list/shortcuts = list( - "meth" = /datum/reagent/drug/methamphetamine - ) ///The purity of the created reagent in % (purity uses 0-1 values) var/purity = 100 +/obj/machinery/chem_dispenser/chem_synthesizer/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/machinery/chem_dispenser/chem_synthesizer/crowbar_act(mob/living/user, obj/item/tool) + return NONE + /obj/machinery/chem_dispenser/chem_synthesizer/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) diff --git a/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm b/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm index a6113d2f0c6e4..25a7eecbd374f 100644 --- a/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm +++ b/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm @@ -9,6 +9,7 @@ slot_flags = ITEM_SLOT_BELT custom_price = PAYCHECK_CREW * 10 custom_premium_price = PAYCHECK_CREW * 14 + interaction_flags_click = FORBID_TELEKINESIS_REACH ///Creating an empty slot for a beaker that can be added to dispense into var/obj/item/reagent_containers/beaker @@ -105,14 +106,14 @@ /obj/item/storage/portable_chem_mixer/ex_act(severity, target) return severity > EXPLODE_LIGHT ? ..() : FALSE -/obj/item/storage/portable_chem_mixer/item_interaction(mob/living/user, obj/item/weapon, list/modifiers, is_right_clicking) +/obj/item/storage/portable_chem_mixer/item_interaction(mob/living/user, obj/item/weapon, list/modifiers) if (!atom_storage.locked || \ (weapon.item_flags & ABSTRACT) || \ (weapon.flags_1 & HOLOGRAM_1) || \ !is_reagent_container(weapon) || \ !weapon.is_open_container() \ ) - return ..() + return NONE replace_beaker(user, weapon) update_appearance() @@ -250,15 +251,14 @@ var/atom/movable/screen/inventory/hand/H = over_object M.putItemFromInventoryInHandIfPossible(src, H.held_index) -/obj/item/storage/portable_chem_mixer/AltClick(mob/living/user) +/obj/item/storage/portable_chem_mixer/click_alt(mob/living/user) if(!atom_storage.locked) balloon_alert(user, "lock first to use alt eject!") - return ..() - if(!can_interact(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return + return CLICK_ACTION_BLOCKING replace_beaker(user) update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/storage/portable_chem_mixer/CtrlClick(mob/living/user) if(atom_storage.locked == STORAGE_FULLY_LOCKED) diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index bdd4f12507567..e206ffebbc9f8 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -99,7 +99,12 @@ . += span_notice("Filled to [round((total_weight / maximum_weight) * 100)]% capacity.") if(!QDELETED(beaker)) - . += span_notice("A beaker of [beaker.reagents.maximum_volume]u capacity is present.") + . += span_notice("A beaker of [beaker.reagents.maximum_volume]u capacity is present. Contains:") + if(beaker.reagents.total_volume) + for(var/datum/reagent/reg as anything in beaker.reagents.reagent_list) + . += span_notice("[round(reg.volume, CHEMICAL_VOLUME_ROUNDING)]u of [reg.name]") + else + . += span_notice("Nothing.") . += span_notice("[EXAMINE_HINT("Right click")] with empty hand to remove beaker.") else . += span_warning("It's missing a beaker.") @@ -206,9 +211,9 @@ return items_transfered -/obj/machinery/reagentgrinder/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/machinery/reagentgrinder/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(user.combat_mode || (tool.item_flags & ABSTRACT) || (tool.flags_1 & HOLOGRAM_1) || !can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH)) - return ..() + return NONE //add the beaker if (is_reagent_container(tool) && tool.is_open_container()) @@ -257,7 +262,7 @@ to_chat(user, span_warning("You must drag & dump contents of [tool] into [src].")) return ITEM_INTERACT_BLOCKING - return ..() + return NONE /obj/machinery/reagentgrinder/wrench_act(mob/living/user, obj/item/tool) if(user.combat_mode) diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm index c103457025def..6f58fb9019307 100644 --- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm +++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm @@ -1,4 +1,5 @@ -#define REAGENTS_BASE_VOLUME 100 // actual volume is REAGENTS_BASE_VOLUME plus REAGENTS_BASE_VOLUME * rating for each matterbin +/// Actual volume is REAGENTS_BASE_VOLUME plus REAGENTS_BASE_VOLUME * rating for each matterbin +#define REAGENTS_BASE_VOLUME 100 /obj/machinery/smoke_machine name = "smoke machine" @@ -8,21 +9,17 @@ base_icon_state = "smoke" density = TRUE circuit = /obj/item/circuitboard/machine/smoke_machine - processing_flags = NONE + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_REQUIRES_ANCHORED + processing_flags = START_PROCESSING_MANUALLY + ///Divided against the amount of smoke to produce. Higher values equals lesser amount of reagents consumed to create smoke var/efficiency = 20 + ///Is this machine on or off var/on = FALSE - var/cooldown = 0 - var/useramount = 30 // Last used amount - var/setting = 1 // displayed range is 3 * setting - var/max_range = 3 // displayed max range is 3 * max range - -/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location = null, datum/reagents/carry = null, efficiency = 10, silent=FALSE) - src.holder = holder - src.location = get_turf(location) - src.amount = amount - carry?.copy_to(chemholder, 20) - carry?.remove_all(amount / efficiency) + ///Higher values mean larger smoke pufs but also more power & reagents consumed + var/setting = 1 + ///Max setting acheived from upgraded capacitors + var/max_range = 3 /// A factory which produces clouds of smoke for the smoke machine. /datum/effect_system/fluid_spread/smoke/chem/smoke_machine @@ -33,88 +30,145 @@ opacity = FALSE alpha = 100 +/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location, datum/reagents/carry, efficiency = 10, silent = FALSE) + src.holder = holder + src.location = get_turf(location) + src.amount = amount + if(carry) + carry.copy_to(chemholder, 20) + carry.remove_all(amount / efficiency) + /obj/machinery/smoke_machine/Initialize(mapload) - . = ..() create_reagents(REAGENTS_BASE_VOLUME, INJECTABLE) + + . = ..() + AddComponent(/datum/component/plumbing/simple_demand) AddComponent(/datum/component/simple_rotation) - for(var/datum/stock_part/matter_bin/B in component_parts) - reagents.maximum_volume += REAGENTS_BASE_VOLUME * B.tier - if(is_operational) - begin_processing() + register_context() + +/obj/machinery/smoke_machine/on_deconstruction(disassembled) + reagents.expose(loc, TOUCH) + reagents.clear_reagents() + +/obj/machinery/smoke_machine/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + if(isnull(held_item)) + return + + if(is_reagent_container(held_item) && held_item.is_open_container()) + context[SCREENTIP_CONTEXT_LMB] = "Inject reagents" + return CONTEXTUAL_SCREENTIP_SET + + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] panel" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Una" : "A"]nchor" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_CROWBAR && panel_open) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/smoke_machine/examine(mob/user) + . = ..() + + . += span_notice("Reagent capacity [reagents.total_volume]/[reagents.maximum_volume].") + . += span_notice("Operating at [round((efficiency / 26) * 100)]% efficiency.") + + . += span_notice("Its maintainence panel can be [EXAMINE_HINT("screwed")] [panel_open ? "closed" : "open"].") + if(panel_open) + . += span_notice("It can be [EXAMINE_HINT("pried")] apart.") + + if(anchored) + . += span_notice("It can be [EXAMINE_HINT("wrenched")] loose.") + else + . += span_warning("It needs to be [EXAMINE_HINT("anchored")] in place to work.") /obj/machinery/smoke_machine/update_icon_state() - if((!is_operational) || (!on) || (reagents.total_volume == 0)) - icon_state = "[base_icon_state]0[panel_open ? "-o" : null]" + if(!is_operational || !on || !reagents.total_volume) + icon_state = "[base_icon_state]0[panel_open ? "-o" : ""]" return ..() + icon_state = "[base_icon_state]1" return ..() /obj/machinery/smoke_machine/RefreshParts() . = ..() + + //new capacity to store reagents from matter bins var/new_volume = REAGENTS_BASE_VOLUME for(var/datum/stock_part/matter_bin/matter_bin in component_parts) new_volume += REAGENTS_BASE_VOLUME * matter_bin.tier - if(!reagents) - create_reagents(new_volume, INJECTABLE) reagents.maximum_volume = new_volume - if(new_volume < reagents.total_volume) - reagents.expose(loc, TOUCH) // if someone manages to downgrade it without deconstructing - reagents.clear_reagents() + + //new efficiency from capacitors efficiency = 18 for(var/datum/stock_part/capacitor/capacitor in component_parts) efficiency += 2 * capacitor.tier + + //new maximum range from servos max_range = 1 for(var/datum/stock_part/servo/servo in component_parts) max_range += servo.tier max_range = max(3, max_range) -/obj/machinery/smoke_machine/on_set_is_operational(old_value) - if(old_value) //Turned off - end_processing() - else //Turned on - begin_processing() +/obj/machinery/smoke_machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = NONE + if(user.combat_mode || tool.item_flags & ABSTRACT || tool.flags_1 & HOLOGRAM_1 || !user.can_perform_action(src, ALLOW_SILICON_REACH)) + return ITEM_INTERACT_SKIP_TO_ATTACK + //transfer reagents from an open container into machine + if(is_reagent_container(tool) && tool.is_open_container()) + var/obj/item/reagent_containers/RC = tool + var/units = RC.reagents.trans_to(src, RC.amount_per_transfer_from_this, transferred_by = user) + if(units) + to_chat(user, span_notice("You transfer [units] units of the solution to [src].")) + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING -/obj/machinery/smoke_machine/process() - if(reagents.total_volume == 0) - on = FALSE - update_appearance() +/obj/machinery/smoke_machine/wrench_act(mob/living/user, obj/item/tool) + . = ITEM_INTERACT_BLOCKING + if(on) + balloon_alert(user, "turn off first!") return - var/turf/location = get_turf(src) - var/smoke_test = locate(/obj/effect/particle_effect/fluid/smoke) in location - if(on && !smoke_test) - update_appearance() - var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/smoke = new() - smoke.set_up(setting * 3, holder = src, location = location, carry = reagents, efficiency = efficiency) - smoke.start() - use_energy(active_power_usage) -/obj/machinery/smoke_machine/wrench_act(mob/living/user, obj/item/tool) - . = ..() - if(default_unfasten_wrench(user, tool, time = 4 SECONDS)) - on = FALSE + if(default_unfasten_wrench(user, tool, time = 4 SECONDS) == SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS - return FALSE -/obj/machinery/smoke_machine/attackby(obj/item/I, mob/user, params) - add_fingerprint(user) - if(is_reagent_container(I) && I.is_open_container()) - var/obj/item/reagent_containers/RC = I - var/units = RC.reagents.trans_to(src, RC.amount_per_transfer_from_this, transferred_by = user) - if(units) - to_chat(user, span_notice("You transfer [units] units of the solution to [src].")) - return - if(default_deconstruction_screwdriver(user, "smoke0-o", "smoke0", I)) +/obj/machinery/smoke_machine/screwdriver_act(mob/living/user, obj/item/tool) + . = ITEM_INTERACT_BLOCKING + if(on) + balloon_alert(user, "turn off first!") return - if(default_deconstruction_crowbar(I)) + + if(default_deconstruction_screwdriver(user, "smoke0-o", "smoke0", tool)) + update_appearance(UPDATE_ICON_STATE) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/smoke_machine/crowbar_act(mob/living/user, obj/item/tool) + . = ITEM_INTERACT_BLOCKING + if(on) + balloon_alert(user, "turn off first!") return - return ..() -/obj/machinery/smoke_machine/on_deconstruction(disassembled) - reagents.expose(loc, TOUCH) - reagents.clear_reagents() + if(default_deconstruction_crowbar(tool)) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/smoke_machine/process() + if(!reagents.total_volume || !anchored || !on || !is_operational) + on = FALSE + update_appearance(UPDATE_ICON_STATE) + return PROCESS_KILL + + var/turf/location = get_turf(src) + if(!(locate(/obj/effect/particle_effect/fluid/smoke) in location)) + var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/smoke = new() + smoke.set_up(setting * 3, holder = src, location = location, carry = reagents, efficiency = efficiency) + smoke.start() + use_energy(active_power_usage * (setting / max_range)) + update_appearance(UPDATE_ICON_STATE) /obj/machinery/smoke_machine/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -123,41 +177,58 @@ ui.open() /obj/machinery/smoke_machine/ui_data(mob/user) - var/data = list() - var/tank_contents = list() - var/tank_current_volume = 0 - for(var/datum/reagent/R in reagents.reagent_list) - tank_contents += list(list("name" = R.name, "volume" = R.volume)) // list in a list because Byond merges the first list... - tank_current_volume += R.volume - data["tankContents"] = tank_contents - data["tankCurrentVolume"] = reagents.total_volume ? reagents.total_volume : null - data["tankMaxVolume"] = reagents.maximum_volume - data["active"] = on - data["setting"] = setting - data["maxSetting"] = max_range - return data - -/obj/machinery/smoke_machine/ui_act(action, params) + . = list() + + var/list/tank_data = list() + tank_data["maxVolume"] = reagents.maximum_volume + tank_data["currentVolume"] = round(reagents.total_volume, CHEMICAL_VOLUME_ROUNDING) + var/list/tankContents = list() + for(var/datum/reagent/reagent in reagents.reagent_list) + tankContents += list(list("name" = reagent.name, "volume" = round(reagent.volume, CHEMICAL_VOLUME_ROUNDING))) + tank_data["contents"] = tankContents + .["tank"] = tank_data + + .["active"] = on + .["setting"] = setting + .["maxSetting"] = max_range + +/obj/machinery/smoke_machine/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() - - if(. || !anchored) + if(.) return + switch(action) if("purge") reagents.clear_reagents() - update_appearance() - . = TRUE + update_appearance(UPDATE_ICON_STATE) + return TRUE + if("setting") - var/amount = text2num(params["amount"]) + var/amount = params["amount"] + if(isnull(amount)) + return FALSE + + amount = text2num(amount) + if(isnull(amount)) + return FALSE + if(amount in 1 to max_range) setting = amount - . = TRUE + return TRUE + if("power") on = !on - update_appearance() - if(on) - message_admins("[ADMIN_LOOKUPFLW(usr)] activated a smoke machine that contains [english_list(reagents.reagent_list)] at [ADMIN_VERBOSEJMP(src)].") - usr.log_message("activated a smoke machine that contains [english_list(reagents.reagent_list)]", LOG_GAME) - log_combat(usr, src, "has activated [src] which contains [english_list(reagents.reagent_list)] at [AREACOORD(src)].") + if(on && reagents.total_volume) + var/mob/user = ui.user + var/list/english_list = english_list(reagents.reagent_list) + message_admins("[ADMIN_LOOKUPFLW(user)] activated a smoke machine that contains [english_list] at [ADMIN_VERBOSEJMP(src)].") + user.log_message("activated a smoke machine that contains [english_list]", LOG_GAME) + log_combat(user, src, "has activated [src] which contains [english_list] at [AREACOORD(src)].") + begin_processing() + else + on = FALSE + end_processing() + update_appearance(UPDATE_ICON_STATE) + return TRUE #undef REAGENTS_BASE_VOLUME diff --git a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm index 0262c48d546ae..3fd769ddba9bb 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm @@ -1658,7 +1658,7 @@ need_mob_update += drinker.adjustStaminaLoss(-heal_amt, updating_stamina = FALSE, required_biotype = affected_biotype) if(need_mob_update) drinker.updatehealth() - drinker.visible_message(span_warning("[drinker] shivers with renewed vigor!"), span_notice("One taste of [lowertext(name)] fills you with energy!")) + drinker.visible_message(span_warning("[drinker] shivers with renewed vigor!"), span_notice("One taste of [LOWER_TEXT(name)] fills you with energy!")) if(!drinker.stat && heal_points == 20) //brought us out of softcrit drinker.visible_message(span_danger("[drinker] lurches to [drinker.p_their()] feet!"), span_boldnotice("Up and at 'em, kid.")) @@ -2632,7 +2632,7 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 3) + stomach.adjust_charge(reac_volume * 0.003 * STANDARD_CELL_CHARGE) /datum/reagent/consumable/ethanol/telepole name = "Telepole" @@ -2652,7 +2652,7 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 2) + stomach.adjust_charge(reac_volume * 0.002 * STANDARD_CELL_CHARGE) /datum/reagent/consumable/ethanol/pod_tesla name = "Pod Tesla" @@ -2679,7 +2679,7 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 5) + stomach.adjust_charge(reac_volume * 0.005 * STANDARD_CELL_CHARGE) // Welcome to the Blue Room Bar and Grill, home to Mars' finest cocktails /datum/reagent/consumable/ethanol/rice_beer diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index f733bc686f0b6..f753f2f1c325c 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -1258,4 +1258,4 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 3) + stomach.adjust_charge(reac_volume * 0.003 * STANDARD_CELL_CHARGE) diff --git a/code/modules/reagents/chemistry/reagents/drinks/glass_styles/alcohol.dm b/code/modules/reagents/chemistry/reagents/drinks/glass_styles/alcohol.dm index bb9e5869ca804..5811f49da8f21 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/glass_styles/alcohol.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/glass_styles/alcohol.dm @@ -107,8 +107,8 @@ desc = "It's as strong as it smells." icon_state = "absinthe" -/datum/glass_style/drinking_glass/hooch - required_drink_type = /datum/reagent/consumable/ethanol/hooch +/datum/glass_style/drinking_glass/ale + required_drink_type = /datum/reagent/consumable/ethanol/ale name = "glass of ale" desc = "A freezing pint of delicious Ale." icon_state = "aleglass" diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 7cb3943b28623..cb05757bdc548 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -685,7 +685,7 @@ . = ..() playsound(invisible_man, 'sound/chemistry/saturnx_fade.ogg', 40) to_chat(invisible_man, span_nicegreen("You feel pins and needles all over your skin as your body suddenly becomes transparent!")) - addtimer(CALLBACK(src, PROC_REF(turn_man_invisible), invisible_man), 10) //just a quick delay to synch up the sound. + addtimer(CALLBACK(src, PROC_REF(turn_man_invisible), invisible_man), 1 SECONDS) //just a quick delay to synch up the sound. if(!invisible_man.hud_used) return diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index f1bf67348fb16..2e45ecf641bc1 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -185,7 +185,7 @@ exposed_mob.emote("scream") playsound(exposed_mob, 'sound/machines/fryer/deep_fryer_emerge.ogg', 25, TRUE) ADD_TRAIT(exposed_mob, TRAIT_OIL_FRIED, "cooking_oil_react") - addtimer(CALLBACK(exposed_mob, TYPE_PROC_REF(/mob/living, unfry_mob)), 3) + addtimer(CALLBACK(exposed_mob, TYPE_PROC_REF(/mob/living, unfry_mob)), 0.3 SECONDS) if(FryLoss) exposed_mob.adjustFireLoss(FryLoss) @@ -484,13 +484,13 @@ adjust_blood_flow(-0.06 * reac_volume, initial_flow * 0.6) // 20u of a salt shacker * 0.1 = -1.6~ blood flow, but is always clamped to, at best, third blood loss from that wound. // Crystal irritation worsening recovery. gauzed_clot_rate *= 0.65 - to_chat(carbies, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin but soaking up most of the blood.")) + to_chat(carbies, span_notice("The salt bits seep in and stick to [LOWER_TEXT(src)], painfully irritating the skin but soaking up most of the blood.")) /datum/wound/slash/flesh/on_salt(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.1 * reac_volume, initial_flow * 0.5) // 20u of a salt shacker * 0.1 = -2~ blood flow, but is always clamped to, at best, halve blood loss from that wound. // Crystal irritation worsening recovery. clot_rate *= 0.75 - to_chat(carbies, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin but soaking up most of the blood.")) + to_chat(carbies, span_notice("The salt bits seep in and stick to [LOWER_TEXT(src)], painfully irritating the skin but soaking up most of the blood.")) /datum/wound/burn/flesh/on_salt(reac_volume) // Slightly sanitizes and disinfects, but also increases infestation rate (some bacteria are aided by salt), and decreases flesh healing (can damage the skin from moisture absorption) @@ -498,7 +498,7 @@ infestation -= max(VALUE_PER(0.3, 30) * reac_volume, 0) infestation_rate += VALUE_PER(0.12, 30) * reac_volume flesh_healing -= max(VALUE_PER(5, 30) * reac_volume, 0) - to_chat(victim, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin! After a few moments, it feels marginally better.")) + to_chat(victim, span_notice("The salt bits seep in and stick to [LOWER_TEXT(src)], painfully irritating the skin! After a few moments, it feels marginally better.")) /datum/reagent/consumable/blackpepper name = "Black Pepper" @@ -531,7 +531,10 @@ . = ..() if(isvampire(affected_mob)) //incapacitating but not lethal. Unfortunately, vampires cannot vomit. if(SPT_PROB(min((current_cycle-1)/2, 12.5), seconds_per_tick)) - to_chat(affected_mob, span_danger("You can't get the scent of garlic out of your nose! You can barely think...")) + if(HAS_TRAIT(affected_mob, TRAIT_ANOSMIA)) + to_chat(affected_mob, span_danger("You feel that something is wrong, your strength is leaving you! You can barely think...")) + else + to_chat(affected_mob, span_danger("You can't get the scent of garlic out of your nose! You can barely think...")) affected_mob.Paralyze(10) affected_mob.set_jitter_if_lower(20 SECONDS) else @@ -649,18 +652,18 @@ /datum/wound/pierce/bleed/on_flour(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.015 * reac_volume) // 30u of a flour sack * 0.015 = -0.45~ blood flow, prettay good - to_chat(carbies, span_notice("The flour seeps into [lowertext(src)], painfully drying it up and absorbing some of the blood.")) + to_chat(carbies, span_notice("The flour seeps into [LOWER_TEXT(src)], painfully drying it up and absorbing some of the blood.")) // When some nerd adds infection for wounds, make this increase the infection /datum/wound/slash/flesh/on_flour(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.04 * reac_volume) // 30u of a flour sack * 0.04 = -1.25~ blood flow, pretty good! - to_chat(carbies, span_notice("The flour seeps into [lowertext(src)], painfully drying some of it up and absorbing a little blood.")) + to_chat(carbies, span_notice("The flour seeps into [LOWER_TEXT(src)], painfully drying some of it up and absorbing a little blood.")) // When some nerd adds infection for wounds, make this increase the infection // Don't pour flour onto burn wounds, it increases infection risk! Very unwise. Backed up by REAL info from REAL professionals. // https://www.reuters.com/article/uk-factcheck-flour-burn-idUSKCN26F2N3 /datum/wound/burn/flesh/on_flour(reac_volume) - to_chat(victim, span_notice("The flour seeps into [lowertext(src)], spiking you with intense pain! That probably wasn't a good idea...")) + to_chat(victim, span_notice("The flour seeps into [LOWER_TEXT(src)], spiking you with intense pain! That probably wasn't a good idea...")) sanitization -= min(0, 1) infestation += 0.2 return @@ -755,18 +758,18 @@ /datum/wound/pierce/bleed/on_starch(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.03 * reac_volume) - to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], painfully drying some of it up and absorbing a little blood.")) + to_chat(carbies, span_notice("The slimey starch seeps into [LOWER_TEXT(src)], painfully drying some of it up and absorbing a little blood.")) // When some nerd adds infection for wounds, make this increase the infection return /datum/wound/slash/flesh/on_starch(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.06 * reac_volume) - to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], painfully drying it up and absorbing some of the blood.")) + to_chat(carbies, span_notice("The slimey starch seeps into [LOWER_TEXT(src)], painfully drying it up and absorbing some of the blood.")) // When some nerd adds infection for wounds, make this increase the infection return /datum/wound/burn/flesh/on_starch(reac_volume, mob/living/carbon/carbies) - to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], spiking you with intense pain! That probably wasn't a good idea...")) + to_chat(carbies, span_notice("The slimey starch seeps into [LOWER_TEXT(src)], spiking you with intense pain! That probably wasn't a good idea...")) sanitization -= min(0, 0.5) infestation += 0.1 return @@ -946,7 +949,7 @@ var/mob/living/carbon/exposed_carbon = exposed_mob var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) - stomach.adjust_charge(reac_volume * 30) + stomach.adjust_charge(reac_volume * 0.03 * STANDARD_CELL_CHARGE) /datum/reagent/consumable/liquidelectricity/enriched/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents.dm index 59baceab5579f..20cd80d9c5b0e 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents.dm @@ -104,6 +104,9 @@ /datum/reagent/inverse/cryostylane/on_mob_add(mob/living/carbon/affected_mob, amount) . = ..() + if(HAS_TRAIT(affected_mob, TRAIT_RESISTCOLD)) + holder.remove_reagent(type, volume) + return cube = new /obj/structure/ice_stasis(get_turf(affected_mob)) cube.color = COLOR_CYAN cube.set_anchored(TRUE) diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm index 3c677e43d1c07..3ae946d4fab46 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm @@ -100,18 +100,7 @@ Basically, we fill the time between now and 2s from now with hands based off the /datum/reagent/inverse/helgrasp/proc/spawn_hands(mob/living/carbon/affected_mob) if(!affected_mob && iscarbon(holder.my_atom))//Catch timer affected_mob = holder.my_atom - //Adapted from the end of the curse - but lasts a short time - var/grab_dir = turn(affected_mob.dir, pick(-90, 90, 180, 180)) //grab them from a random direction other than the one faced, favoring grabbing from behind - var/turf/spawn_turf = get_ranged_target_turf(affected_mob, grab_dir, 8)//Larger range so you have more time to dodge - if(!spawn_turf) - return - new/obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, affected_mob.dir) - playsound(spawn_turf, 'sound/effects/curse2.ogg', 80, TRUE, -1) - var/obj/projectile/curse_hand/hel/hand = new (spawn_turf) - hand.preparePixelProjectile(affected_mob, spawn_turf) - if(QDELETED(hand)) //safety check if above fails - above has a stack trace if it does fail - return - hand.fire() + fire_curse_hand(affected_mob) //At the end, we clear up any loose hanging timers just in case and spawn any remaining lag_remaining hands all at once. /datum/reagent/inverse/helgrasp/on_mob_delete(mob/living/affected_mob) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 049d1b87337df..d4f26367a5a54 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -1330,6 +1330,9 @@ if (affected_mob.get_timed_status_effect_duration(/datum/status_effect/hallucination) >= 10 SECONDS) affected_mob.adjust_hallucinations(-10 SECONDS * REM * seconds_per_tick) + if(affected_mob.getStaminaLoss() >= 100) + affected_mob.reagents.remove_reagent(type, 2 * REM * seconds_per_tick) + var/need_mob_update = FALSE if(SPT_PROB(10, seconds_per_tick)) need_mob_update += affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1, 50, affected_organ_flags) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index ce8cbc3275870..9859617ce4271 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -325,18 +325,18 @@ /datum/wound/pierce/bleed/on_saltwater(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.06 * reac_volume, initial_flow * 0.6) - to_chat(carbies, span_notice("The salt water splashes over [lowertext(src)], soaking up the blood.")) + to_chat(carbies, span_notice("The salt water splashes over [LOWER_TEXT(src)], soaking up the blood.")) /datum/wound/slash/flesh/on_saltwater(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.1 * reac_volume, initial_flow * 0.5) - to_chat(carbies, span_notice("The salt water splashes over [lowertext(src)], soaking up the blood.")) + to_chat(carbies, span_notice("The salt water splashes over [LOWER_TEXT(src)], soaking up the blood.")) /datum/wound/burn/flesh/on_saltwater(reac_volume) // Similar but better stats from normal salt. sanitization += VALUE_PER(0.6, 30) * reac_volume infestation -= max(VALUE_PER(0.5, 30) * reac_volume, 0) infestation_rate += VALUE_PER(0.07, 30) * reac_volume - to_chat(victim, span_notice("The salt water splashes over [lowertext(src)], soaking up the... miscellaneous fluids. It feels somewhat better afterwards.")) + to_chat(victim, span_notice("The salt water splashes over [LOWER_TEXT(src)], soaking up the... miscellaneous fluids. It feels somewhat better afterwards.")) return /datum/reagent/water/holywater @@ -711,7 +711,7 @@ var/datum/species/species_type = race affected_mob.set_species(species_type) holder.del_reagent(type) - to_chat(affected_mob, span_warning("You've become \a [lowertext(initial(species_type.name))]!")) + to_chat(affected_mob, span_warning("You've become \a [LOWER_TEXT(initial(species_type.name))]!")) return /datum/reagent/mutationtoxin/classic //The one from plasma on green slimes @@ -1228,7 +1228,7 @@ to_chat(affected_mob, span_warning("You feel unstable...")) affected_mob.set_jitter_if_lower(2 SECONDS) current_cycle = 1 - addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/living, bluespace_shuffle)), 30) + addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/living, bluespace_shuffle)), 3 SECONDS) /mob/living/proc/bluespace_shuffle() do_teleport(src, get_turf(src), 5, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) @@ -2201,10 +2201,10 @@ var/mob/living/carbon/human/exposed_human = exposed_mob if(!HAS_TRAIT(exposed_human, TRAIT_SHAVED)) - var/datum/sprite_accessory/facial_hair/picked_beard = pick(GLOB.facial_hairstyles_list) + var/datum/sprite_accessory/facial_hair/picked_beard = pick(SSaccessories.facial_hairstyles_list) exposed_human.set_facial_hairstyle(picked_beard, update = FALSE) if(!HAS_TRAIT(exposed_human, TRAIT_BALD)) - var/datum/sprite_accessory/hair/picked_hair = pick(GLOB.hairstyles_list) + var/datum/sprite_accessory/hair/picked_hair = pick(SSaccessories.hairstyles_list) exposed_human.set_hairstyle(picked_hair, update = TRUE) to_chat(exposed_human, span_notice("Hair starts sprouting from your [HAS_TRAIT(exposed_human, TRAIT_BALD) ? "face" : "scalp"].")) diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 7f316a05f79c8..bcdee284bd78b 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -753,19 +753,20 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/toxin/itching_powder/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - var/need_mob_update = FALSE - if(SPT_PROB(8, seconds_per_tick)) - to_chat(affected_mob, span_danger("You scratch at your head.")) - need_mob_update += affected_mob.adjustBruteLoss(0.2*REM, FALSE, required_bodytype = affected_bodytype) - if(SPT_PROB(8, seconds_per_tick)) - to_chat(affected_mob, span_danger("You scratch at your leg.")) - need_mob_update += affected_mob.adjustBruteLoss(0.2*REM, FALSE, required_bodytype = affected_bodytype) - if(SPT_PROB(8, seconds_per_tick)) - to_chat(affected_mob, span_danger("You scratch at your arm.")) - need_mob_update += affected_mob.adjustBruteLoss(0.2*REM, FALSE, required_bodytype = affected_bodytype) + var/scratched = FALSE + var/scratch_damage = 0.2 * REM - if(need_mob_update) - . = UPDATE_MOB_HEALTH + var/obj/item/bodypart/head = affected_mob.get_bodypart(BODY_ZONE_HEAD) + if(!isnull(head) && SPT_PROB(8, seconds_per_tick)) + scratched = affected_mob.itch(damage = scratch_damage, target_part = head) + + var/obj/item/bodypart/leg = affected_mob.get_bodypart(pick(BODY_ZONE_L_LEG,BODY_ZONE_R_LEG)) + if(!isnull(leg) && SPT_PROB(8, seconds_per_tick)) + scratched = affected_mob.itch(damage = scratch_damage, target_part = leg, silent = scratched) || scratched + + var/obj/item/bodypart/arm = affected_mob.get_bodypart(pick(BODY_ZONE_L_ARM,BODY_ZONE_R_ARM)) + if(!isnull(arm) && SPT_PROB(8, seconds_per_tick)) + scratched = affected_mob.itch(damage = scratch_damage, target_part = arm, silent = scratched) || scratched if(SPT_PROB(1.5, seconds_per_tick)) holder.add_reagent(/datum/reagent/toxin/histamine,rand(1,3)) diff --git a/code/modules/reagents/chemistry/reagents/unique/eigenstasium.dm b/code/modules/reagents/chemistry/reagents/unique/eigenstasium.dm index 7c18c7e201466..8c093888028e9 100644 --- a/code/modules/reagents/chemistry/reagents/unique/eigenstasium.dm +++ b/code/modules/reagents/chemistry/reagents/unique/eigenstasium.dm @@ -116,6 +116,6 @@ var/list/lockers = list() for(var/obj/structure/closet/closet in exposed_turf.contents) lockers += closet - if(!length(lockers)) + if(!lockers.len) return - GLOB.eigenstate_manager.create_new_link(lockers) + GLOB.eigenstate_manager.create_new_link(lockers, subtle = FALSE) diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index c7732e0908a0d..f7fc1b04ac8de 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -261,10 +261,10 @@ else if(setting_type) if(step_away(X, T) && moving_power > 1) //Can happen twice at most. So this is fine. - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), X, T), 2) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), X, T), 0.2 SECONDS) else if(step_towards(X, T) && moving_power > 1) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_towards), X, T), 2) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_towards), X, T), 0.2 SECONDS) //////////////////Generic explosions/failures//////////////////// // It is HIGHLY, HIGHLY recomended that you consume all/a good volume of the reagents/products in an explosion - because it will just keep going forever until the reaction stops diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 505b46ebc850b..dee575cf06363 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -945,7 +945,7 @@ optimal_ph_min = 3 optimal_ph_max = 12 required_temp = 50 - reaction_flags = REACTION_INSTANT + reaction_flags = REACTION_INSTANT | REAGENT_SPLITRETAINVOL reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE /datum/chemical_reaction/ant_slurry // We're basically gluing ants together with synthflesh & maint sludge to make a bigger ant. diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index edb11633e91bc..d190a44aea063 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -157,7 +157,7 @@ mix_message = "Sparks start flying around the gunpowder!" /datum/chemical_reaction/reagent_explosion/gunpowder_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - addtimer(CALLBACK(src, PROC_REF(default_explode), holder, created_volume, modifier, strengthdiv), rand(5,10) SECONDS) + addtimer(CALLBACK(src, PROC_REF(default_explode), holder, created_volume, modifier, strengthdiv), rand(5 SECONDS, 10 SECONDS)) /datum/chemical_reaction/thermite results = list(/datum/reagent/thermite = 3) diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index ecd46a44db01e..6407ff0fb8b2b 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -103,21 +103,21 @@ /datum/chemical_reaction/slime/slimemobspawn/proc/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate violently!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 5, "Gold Slime", HOSTILE_SPAWN), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 5, "Gold Slime", HOSTILE_SPAWN), 5 SECONDS) /datum/chemical_reaction/slime/slimemobspawn/lesser required_reagents = list(/datum/reagent/blood = 1) /datum/chemical_reaction/slime/slimemobspawn/lesser/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate violently!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Lesser Gold Slime", HOSTILE_SPAWN, FACTION_NEUTRAL), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Lesser Gold Slime", HOSTILE_SPAWN, FACTION_NEUTRAL), 5 SECONDS) /datum/chemical_reaction/slime/slimemobspawn/friendly required_reagents = list(/datum/reagent/water = 1) /datum/chemical_reaction/slime/slimemobspawn/friendly/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate adorably!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 1, "Friendly Gold Slime", FRIENDLY_SPAWN, FACTION_NEUTRAL), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 1, "Friendly Gold Slime", FRIENDLY_SPAWN, FACTION_NEUTRAL), 5 SECONDS) /datum/chemical_reaction/slime/slimemobspawn/spider required_reagents = list(/datum/reagent/spider_extract = 1) @@ -125,7 +125,7 @@ /datum/chemical_reaction/slime/slimemobspawn/spider/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate crikey-ingly!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Traitor Spider Slime", /mob/living/basic/spider/giant/midwife, FACTION_NEUTRAL, FALSE), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Traitor Spider Slime", /mob/living/basic/spider/giant/midwife, FACTION_NEUTRAL, FALSE), 5 SECONDS) //Silver @@ -194,7 +194,7 @@ /datum/chemical_reaction/slime/slimefreeze/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/turf/T = get_turf(holder.my_atom) T.visible_message(span_danger("The slime extract starts to feel extremely cold!")) - addtimer(CALLBACK(src, PROC_REF(freeze), holder), 50) + addtimer(CALLBACK(src, PROC_REF(freeze), holder), 5 SECONDS) var/obj/item/slime_extract/M = holder.my_atom deltimer(M.qdel_timer) ..() @@ -229,7 +229,7 @@ /datum/chemical_reaction/slime/slimefire/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/turf/T = get_turf(holder.my_atom) T.visible_message(span_danger("The slime extract begins to vibrate adorably!")) - addtimer(CALLBACK(src, PROC_REF(slime_burn), holder), 50) + addtimer(CALLBACK(src, PROC_REF(slime_burn), holder), 5 SECONDS) var/obj/item/slime_extract/M = holder.my_atom deltimer(M.qdel_timer) ..() @@ -372,7 +372,7 @@ message_admins("Slime Explosion reaction started at [ADMIN_VERBOSEJMP(T)]. Last Fingerprint: [touch_msg]") log_game("Slime Explosion reaction started at [AREACOORD(T)]. Last Fingerprint: [lastkey ? lastkey : "N/A"].") T.visible_message(span_danger("The slime extract begins to vibrate violently !")) - addtimer(CALLBACK(src, PROC_REF(boom), holder), 50) + addtimer(CALLBACK(src, PROC_REF(boom), holder), 5 SECONDS) var/obj/item/slime_extract/M = holder.my_atom deltimer(M.qdel_timer) ..() @@ -456,7 +456,7 @@ required_container = /obj/item/slime_extract/cerulean /datum/chemical_reaction/slime/slime_territory/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - new /obj/item/areaeditor/blueprints/slime(get_turf(holder.my_atom)) + new /obj/item/blueprints/slime(get_turf(holder.my_atom)) ..() //Sepia @@ -525,7 +525,7 @@ S.visible_message(span_danger("Infused with plasma, the core begins to expand uncontrollably!")) S.icon_state = "[S.base_state]_active" S.active = TRUE - addtimer(CALLBACK(S, TYPE_PROC_REF(/obj/item/grenade, detonate)), rand(15,60)) + addtimer(CALLBACK(S, TYPE_PROC_REF(/obj/item/grenade, detonate)), rand(1.5 SECONDS, 6 SECONDS)) else var/mob/living/basic/slime/random/random_slime = new (get_turf(holder.my_atom)) random_slime.visible_message(span_danger("Infused with plasma, the core begins to quiver and grow, and a new baby slime emerges from it!")) @@ -541,7 +541,7 @@ S.visible_message(span_danger("Infused with slime jelly, the core begins to expand uncontrollably!")) S.icon_state = "[S.base_state]_active" S.active = TRUE - addtimer(CALLBACK(S, TYPE_PROC_REF(/obj/item/grenade, detonate)), rand(15,60)) + addtimer(CALLBACK(S, TYPE_PROC_REF(/obj/item/grenade, detonate)), rand(1.5 SECONDS, 6 SECONDS)) var/lastkey = holder.my_atom.fingerprintslast var/touch_msg = "N/A" if(lastkey) diff --git a/code/modules/reagents/reagent_containers/chem_pack.dm b/code/modules/reagents/reagent_containers/chem_pack.dm index 3345f1e99ef76..98ffa2e596e4e 100644 --- a/code/modules/reagents/reagent_containers/chem_pack.dm +++ b/code/modules/reagents/reagent_containers/chem_pack.dm @@ -8,23 +8,29 @@ spillable = TRUE obj_flags = UNIQUE_RENAME resistance_flags = ACID_PROOF - var/sealed = FALSE fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) has_variable_transfer_amount = FALSE + interaction_flags_click = NEED_DEXTERITY + /// Whether this has been sealed shut + var/sealed = FALSE + +/obj/item/reagent_containers/chem_pack/click_alt(mob/living/user) + if(sealed) + balloon_alert(user, "sealed!") + return CLICK_ACTION_BLOCKING -/obj/item/reagent_containers/chem_pack/AltClick(mob/living/user) - if(user.can_perform_action(src, NEED_DEXTERITY) && !sealed) - if(iscarbon(user) && (HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))) - to_chat(user, span_warning("Uh... whoops! You accidentally spill the content of the bag onto yourself.")) - SplashReagents(user) - return + if(iscarbon(user) && (HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))) + to_chat(user, span_warning("Uh... whoops! You accidentally spill the content of the bag onto yourself.")) + SplashReagents(user) + return CLICK_ACTION_BLOCKING - reagents.flags = NONE - reagent_flags = DRAWABLE | INJECTABLE //To allow for sabotage or ghetto use. - reagents.flags = reagent_flags - spillable = FALSE - sealed = TRUE - to_chat(user, span_notice("You seal the bag.")) + reagents.flags = NONE + reagent_flags = DRAWABLE | INJECTABLE //To allow for sabotage or ghetto use. + reagents.flags = reagent_flags + spillable = FALSE + sealed = TRUE + balloon_alert(user, "sealed") + return CLICK_ACTION_SUCCESS /obj/item/reagent_containers/chem_pack/examine() . = ..() diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 6134731cafd9d..41542ea105e7a 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -23,7 +23,7 @@ . = ..() if(drink_type) var/list/types = bitfield_to_list(drink_type, FOOD_FLAGS) - . += span_notice("It is [lowertext(english_list(types))].") + . += span_notice("It is [LOWER_TEXT(english_list(types))].") /** * Checks if the mob actually liked drinking this cup. @@ -453,11 +453,13 @@ spillable = TRUE var/obj/item/grinded -/obj/item/reagent_containers/cup/mortar/AltClick(mob/user) - if(grinded) - grinded.forceMove(drop_location()) - grinded = null - to_chat(user, span_notice("You eject the item inside.")) +/obj/item/reagent_containers/cup/mortar/click_alt(mob/user) + if(!grinded) + return CLICK_ACTION_BLOCKING + grinded.forceMove(drop_location()) + grinded = null + balloon_alert(user, "ejected") + return CLICK_ACTION_SUCCESS /obj/item/reagent_containers/cup/mortar/attackby(obj/item/I, mob/living/carbon/human/user) ..() @@ -473,7 +475,7 @@ var/picked_option = show_radial_menu(user, src, choose_options, radius = 38, require_near = TRUE) if(grinded && in_range(src, user) && user.is_holding(I) && picked_option) to_chat(user, span_notice("You start grinding...")) - if(do_after(user, 25, target = src)) + if(do_after(user, 2.5 SECONDS, target = src)) user.adjustStaminaLoss(40) switch(picked_option) if("Juice") diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm index 1e4466da8c331..75bc79c5a6aaa 100644 --- a/code/modules/reagents/reagent_containers/cups/bottle.dm +++ b/code/modules/reagents/reagent_containers/cups/bottle.dm @@ -513,7 +513,7 @@ return TRUE -/obj/item/reagent_containers/cup/bottle/syrup_bottle/AltClick(mob/user) +/obj/item/reagent_containers/cup/bottle/syrup_bottle/click_alt(mob/user) cap_on = !cap_on if(!cap_on) icon_state = "syrup_open" @@ -522,7 +522,7 @@ icon_state = "syrup" balloon_alert(user, "put pump cap on") update_icon_state() - return ..() + return CLICK_ACTION_SUCCESS /obj/item/reagent_containers/cup/bottle/syrup_bottle/proc/rename(mob/user, obj/item/writing_instrument) if(!user.can_write(writing_instrument)) diff --git a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm index adcd2ff79fab9..7441614682c06 100644 --- a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm @@ -35,7 +35,7 @@ /obj/item/reagent_containers/cup/glass/drinkingglass/on_reagent_change(datum/reagents/holder, ...) . = ..() if(!length(reagents.reagent_list)) - REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) //so new drinks can rename the glass + REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) //so new drinks can rename the glass // Having our icon state change removes fill thresholds /obj/item/reagent_containers/cup/glass/drinkingglass/on_cup_change(datum/glass_style/style) @@ -58,7 +58,7 @@ return REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, SHAKER_LABEL_TRAIT) - REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) + REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) name = initial(name) desc = initial(desc) update_appearance(UPDATE_NAME | UPDATE_DESC) diff --git a/code/modules/reagents/reagent_containers/cups/drinks.dm b/code/modules/reagents/reagent_containers/cups/drinks.dm index cba2f937da49f..5a3ed446f607c 100644 --- a/code/modules/reagents/reagent_containers/cups/drinks.dm +++ b/code/modules/reagents/reagent_containers/cups/drinks.dm @@ -122,10 +122,10 @@ . += span_notice("Alt-click to toggle cup lid.") return -/obj/item/reagent_containers/cup/glass/coffee/AltClick(mob/user) +/obj/item/reagent_containers/cup/glass/coffee/click_alt(mob/user) lid_open = !lid_open update_icon_state() - return ..() + return CLICK_ACTION_SUCCESS /obj/item/reagent_containers/cup/glass/coffee/update_icon_state() if(lid_open) @@ -248,11 +248,10 @@ else . += span_notice("The cap has been taken off. Alt-click to put a cap on.") -/obj/item/reagent_containers/cup/glass/waterbottle/AltClick(mob/user) - . = ..() +/obj/item/reagent_containers/cup/glass/waterbottle/click_alt(mob/user) if(cap_lost) to_chat(user, span_warning("The cap seems to be missing! Where did it go?")) - return + return CLICK_ACTION_BLOCKING var/fumbled = HAS_TRAIT(user, TRAIT_CLUMSY) && prob(5) if(cap_on || fumbled) @@ -270,6 +269,7 @@ spillable = FALSE to_chat(user, span_notice("You put the cap on [src].")) update_appearance() + return CLICK_ACTION_SUCCESS /obj/item/reagent_containers/cup/glass/waterbottle/is_refillable() if(cap_on) @@ -436,6 +436,7 @@ amount_per_transfer_from_this = 10 volume = 100 isGlass = FALSE + interaction_flags_click = NEED_HANDS|FORBID_TELEKINESIS_REACH /// Whether or not poured drinks should use custom names and descriptions var/using_custom_drinks = FALSE /// Name custom drinks will have @@ -463,34 +464,30 @@ . += span_notice("Drinks poured from this shaker will have the following name: [custom_drink_name]") . += span_notice("Drinks poured from this shaker will have the following description: [custom_drink_desc]") -/obj/item/reagent_containers/cup/glass/shaker/AltClick(mob/user) - . = ..() - if(!user.can_perform_action(src, NEED_HANDS|FORBID_TELEKINESIS_REACH)) - return - +/obj/item/reagent_containers/cup/glass/shaker/click_alt(mob/user) if(using_custom_drinks) using_custom_drinks = FALSE disable_custom_drinks() balloon_alert(user, "custom drinks disabled") - return + return CLICK_ACTION_BLOCKING var/new_name = reject_bad_text(tgui_input_text(user, "Drink name", "Set drink name", custom_drink_name, 45, FALSE), 64) if(!new_name) balloon_alert(user, "invalid drink name!") using_custom_drinks = FALSE - return + return CLICK_ACTION_BLOCKING if(!user.can_perform_action(src, NEED_HANDS|FORBID_TELEKINESIS_REACH)) - return + return CLICK_ACTION_BLOCKING var/new_desc = reject_bad_text(tgui_input_text(user, "Drink description", "Set drink description", custom_drink_desc, 64, TRUE), 128) if(!new_desc) balloon_alert(user, "invalid drink description!") using_custom_drinks = FALSE - return + return CLICK_ACTION_BLOCKING if(!user.can_perform_action(src, NEED_HANDS|FORBID_TELEKINESIS_REACH)) - return + return CLICK_ACTION_BLOCKING using_custom_drinks = TRUE custom_drink_name = new_name @@ -498,6 +495,7 @@ enable_custom_drinks() balloon_alert(user, "now pouring custom drinks") + return CLICK_ACTION_SUCCESS /obj/item/reagent_containers/cup/glass/shaker/proc/enable_custom_drinks() RegisterSignal(src, COMSIG_REAGENTS_CUP_TRANSFER_TO, PROC_REF(handle_transfer)) diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index a69810ca95447..a293aac7aa1b1 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -406,7 +406,7 @@ return "[year] [origin] [type]" /obj/item/reagent_containers/cup/glass/bottle/absinthe - name = "extra-strong absinthe" + name = "Extra-strong absinthe" desc = "A strong alcoholic drink brewed and distributed by" icon_state = "absinthebottle" list_reagents = list(/datum/reagent/consumable/ethanol/absinthe = 100) @@ -894,7 +894,8 @@ desc = "Fermented prison wine made from fruit, sugar, and despair. You probably shouldn't drink this around Security." icon_state = "trashbag1" // pruno releases air as it ferments, we don't want to simulate this in atmos, but we can make it look like it did for (var/mob/living/M in view(2, get_turf(src))) // letting people and/or narcs know when the pruno is done - to_chat(M, span_info("A pungent smell emanates from [src], like fruit puking out its guts.")) + if(HAS_TRAIT(M, TRAIT_ANOSMIA)) + to_chat(M, span_info("A pungent smell emanates from [src], like fruit puking out its guts.")) playsound(get_turf(src), 'sound/effects/bubbles2.ogg', 25, TRUE) /** diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 4cbb4839416c3..c4cd57b15680e 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -122,7 +122,7 @@ has_variable_transfer_amount = FALSE volume = 15 ignore_flags = 1 //so you can medipen through spacesuits - reagent_flags = DRAWABLE + reagent_flags = NONE flags_1 = null list_reagents = list(/datum/reagent/medicine/epinephrine = 10, /datum/reagent/toxin/formaldehyde = 3, /datum/reagent/medicine/coagulant = 2) custom_price = PAYCHECK_CREW @@ -312,7 +312,6 @@ base_icon_state = "gorillapen" volume = 5 ignore_flags = 0 - reagent_flags = NONE list_reagents = list(/datum/reagent/magillitis = 5) /obj/item/reagent_containers/hypospray/medipen/pumpup diff --git a/code/modules/reagents/reagent_containers/medigel.dm b/code/modules/reagents/reagent_containers/medigel.dm index e6836c7a4c296..f6d7b116eff2e 100644 --- a/code/modules/reagents/reagent_containers/medigel.dm +++ b/code/modules/reagents/reagent_containers/medigel.dm @@ -32,6 +32,7 @@ "Purple" = "medigel_purple" ) + /obj/item/reagent_containers/medigel/mode_change_message(mob/user) var/squirt_mode = amount_per_transfer_from_this == initial(amount_per_transfer_from_this) to_chat(user, span_notice("You will now apply the medigel's contents in [squirt_mode ? "extended sprays":"short bursts"]. You'll now use [amount_per_transfer_from_this] units per use.")) diff --git a/code/modules/reagents/reagent_containers/misc.dm b/code/modules/reagents/reagent_containers/misc.dm index fa8d8cd36281f..f631e8e28a0e0 100644 --- a/code/modules/reagents/reagent_containers/misc.dm +++ b/code/modules/reagents/reagent_containers/misc.dm @@ -32,7 +32,7 @@ if(on && (!cell || cell.charge <= 0)) //Check if we ran out of power change_power_status(FALSE) return FALSE - cell.use(5 KILO WATTS * seconds_per_tick) //Basic cell goes for like 200 seconds, bluespace for 8000 + cell.use(0.005 * STANDARD_CELL_RATE * seconds_per_tick) //Basic cell goes for like 200 seconds, bluespace for 8000 if(!reagents.total_volume) return FALSE var/max_temp = min(500 + (500 * (0.2 * cell.rating)), 1000) // 373 to 1000 diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index fd2ab0eb4931a..98ba3a13ed2eb 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -49,7 +49,7 @@ ///Runs the consumption code, can be overriden for special effects /obj/item/reagent_containers/pill/proc/on_consumption(mob/consumer, mob/giver) if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), consumer, span_notice("[pick(strings(REDPILL_FILE, "redpill_questions"))]")), 50) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), consumer, span_notice("[pick(strings(REDPILL_FILE, "redpill_questions"))]")), 5 SECONDS) if(apply_type == INGEST) SEND_SIGNAL(consumer, COMSIG_LIVING_PILL_CONSUMED, src, giver) SEND_SIGNAL(src, COMSIG_PILL_CONSUMED, eater = consumer, feeder = giver) @@ -314,6 +314,12 @@ list_reagents = list(/datum/reagent/gravitum = 5) rename_with_volume = TRUE +/obj/item/reagent_containers/pill/ondansetron + name = "ondansetron pill" + desc = "Alleviates nausea. May cause drowsiness." + icon_state = "pill11" + list_reagents = list(/datum/reagent/medicine/ondansetron = 10) + // Pill styles for chem master /obj/item/reagent_containers/pill/style diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 52968cac22fe1..be40215039de4 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -100,7 +100,7 @@ reagent_puff.end_life() return - var/datum/move_loop/our_loop = SSmove_manager.move_towards_legacy(reagent_puff, target, wait_step, timeout = range * wait_step, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + var/datum/move_loop/our_loop = GLOB.move_manager.move_towards_legacy(reagent_puff, target, wait_step, timeout = range * wait_step, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) reagent_puff.RegisterSignal(our_loop, COMSIG_QDELETING, TYPE_PROC_REF(/obj/effect/decal/chempuff, loop_ended)) reagent_puff.RegisterSignal(our_loop, COMSIG_MOVELOOP_POSTPROCESS, TYPE_PROC_REF(/obj/effect/decal/chempuff, check_move)) @@ -438,10 +438,6 @@ "Yellow" = "sprayer_med_yellow", "Blue" = "sprayer_med_blue") -/obj/item/reagent_containers/spray/medical/AltClick(mob/user) - if(unique_reskin && !current_skin && user.can_perform_action(src, NEED_DEXTERITY)) - reskin_obj(user) - /obj/item/reagent_containers/spray/medical/reskin_obj(mob/M) ..() switch(icon_state) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 5dd5e8b93dd22..b8b3576aa4b1b 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -196,12 +196,9 @@ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 6, flame_range = 8) qdel(src) -/obj/structure/reagent_dispensers/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - boom() - else - qdel(src) +/obj/structure/reagent_dispensers/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + boom() /obj/structure/reagent_dispensers/proc/tank_leak() if(leaking && reagents && reagents.total_volume >= amount_to_leak) @@ -438,8 +435,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/virusfood, 30 . = ..() AddComponent(/datum/component/simple_rotation) -/obj/structure/reagent_dispensers/plumbed/storage/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/structure/reagent_dispensers/plumbed/storage/update_overlays() . = ..() diff --git a/code/modules/reagents/withdrawal/generic_addictions.dm b/code/modules/reagents/withdrawal/generic_addictions.dm index de7cf968ae15c..844c62956e555 100644 --- a/code/modules/reagents/withdrawal/generic_addictions.dm +++ b/code/modules/reagents/withdrawal/generic_addictions.dm @@ -183,7 +183,7 @@ /datum/addiction/medicine/withdrawal_stage_1_process(mob/living/carbon/affected_carbon, seconds_per_tick) . = ..() - if(SPT_PROB(10, seconds_per_tick)) + if(SPT_PROB(1, seconds_per_tick)) affected_carbon.emote("cough") /datum/addiction/medicine/withdrawal_enters_stage_2(mob/living/carbon/affected_carbon) @@ -216,6 +216,9 @@ /datum/addiction/medicine/withdrawal_stage_2_process(mob/living/carbon/affected_carbon, seconds_per_tick) . = ..() + if(SPT_PROB(2, seconds_per_tick)) + affected_carbon.emote("cough") + var/datum/hallucination/fake_health_doll/hallucination = health_doll_ref?.resolve() if(QDELETED(hallucination)) health_doll_ref = null @@ -235,15 +238,14 @@ /datum/addiction/medicine/withdrawal_stage_3_process(mob/living/carbon/affected_carbon, seconds_per_tick) . = ..() + if(SPT_PROB(5, seconds_per_tick)) + affected_carbon.emote("cough") + var/datum/hallucination/fake_health_doll/hallucination = health_doll_ref?.resolve() if(!QDELETED(hallucination) && SPT_PROB(5, seconds_per_tick)) hallucination.increment_fake_damage() return - if(SPT_PROB(15, seconds_per_tick)) - affected_carbon.emote("cough") - return - if(SPT_PROB(65, seconds_per_tick)) return @@ -283,11 +285,11 @@ /datum/addiction/nicotine/withdrawal_stage_2_process(mob/living/carbon/affected_carbon, seconds_per_tick) . = ..() affected_carbon.set_jitter_if_lower(20 SECONDS * seconds_per_tick) - if(SPT_PROB(10, seconds_per_tick)) + if(SPT_PROB(2, seconds_per_tick)) affected_carbon.emote("cough") /datum/addiction/nicotine/withdrawal_stage_3_process(mob/living/carbon/affected_carbon, seconds_per_tick) . = ..() affected_carbon.set_jitter_if_lower(30 SECONDS * seconds_per_tick) - if(SPT_PROB(15, seconds_per_tick)) + if(SPT_PROB(5, seconds_per_tick)) affected_carbon.emote("cough") diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm index cb008252037a1..c440926388709 100644 --- a/code/modules/recycling/conveyor.dm +++ b/code/modules/recycling/conveyor.dm @@ -37,13 +37,28 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) //Direction -> if we have a conveyor belt in that direction var/list/neighbors -/obj/machinery/conveyor/Initialize(mapload) +/obj/machinery/conveyor/Initialize(mapload, new_dir, new_id) . = ..() AddElement(/datum/element/footstep_override, priority = STEP_SOUND_CONVEYOR_PRIORITY) - var/static/list/give_turf_traits = list(TRAIT_TURF_IGNORE_SLOWDOWN) - AddElement(/datum/element/give_turf_traits, give_turf_traits) + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_TURF_IGNORE_SLOWDOWN))) register_context() + if(new_dir) + setDir(new_dir) + if(new_id) + id = new_id + neighbors = list() + ///Leaving onto conveyor detection won't work at this point, but that's alright since it's an optimization anyway + ///Should be fine without it + var/static/list/loc_connections = list( + COMSIG_ATOM_EXITED = PROC_REF(conveyable_exit), + COMSIG_ATOM_ENTERED = PROC_REF(conveyable_enter), + COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(conveyable_enter) + ) + AddElement(/datum/element/connect_loc, loc_connections) + update_move_direction() + LAZYADD(GLOB.conveyors_by_id[id], src) + /obj/machinery/conveyor/examine(mob/user) . = ..() if(inverted) @@ -96,27 +111,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) icon_state = "conveyor_map_inverted" flipped = TRUE -// create a conveyor -/obj/machinery/conveyor/Initialize(mapload, new_dir, new_id) - ..() - if(new_dir) - setDir(new_dir) - if(new_id) - id = new_id - neighbors = list() - ///Leaving onto conveyor detection won't work at this point, but that's alright since it's an optimization anyway - ///Should be fine without it - var/static/list/loc_connections = list( - COMSIG_ATOM_EXITED = PROC_REF(conveyable_exit), - COMSIG_ATOM_ENTERED = PROC_REF(conveyable_enter), - COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(conveyable_enter) - ) - AddElement(/datum/element/connect_loc, loc_connections) - update_move_direction() - LAZYADD(GLOB.conveyors_by_id[id], src) - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/conveyor/LateInitialize() +/obj/machinery/conveyor/post_machine_initialize() . = ..() build_neighbors() @@ -245,7 +240,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) /obj/machinery/conveyor/proc/conveyable_enter(datum/source, atom/convayable) SIGNAL_HANDLER if(operating == CONVEYOR_OFF) - SSmove_manager.stop_looping(convayable, SSconveyors) + GLOB.move_manager.stop_looping(convayable, SSconveyors) return start_conveying(convayable) @@ -253,12 +248,12 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) SIGNAL_HANDLER var/has_conveyor = neighbors["[direction]"] if(convayable.z != z || !has_conveyor || !isturf(convayable.loc)) //If you've entered something on us, stop moving - SSmove_manager.stop_looping(convayable, SSconveyors) + GLOB.move_manager.stop_looping(convayable, SSconveyors) /obj/machinery/conveyor/proc/start_conveying(atom/movable/moving) if(QDELETED(moving)) return - var/datum/move_loop/move/moving_loop = SSmove_manager.processing_on(moving, SSconveyors) + var/datum/move_loop/move/moving_loop = GLOB.move_manager.processing_on(moving, SSconveyors) if(moving_loop) moving_loop.direction = movedir moving_loop.delay = speed * 1 SECONDS @@ -272,7 +267,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) /obj/machinery/conveyor/proc/stop_conveying(atom/movable/thing) if(!ismovable(thing)) return - SSmove_manager.stop_looping(thing, SSconveyors) + GLOB.move_manager.stop_looping(thing, SSconveyors) // attack with item, place item on conveyor /obj/machinery/conveyor/attackby(obj/item/attacking_item, mob/living/user, params) @@ -354,8 +349,6 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) /// The current state of the switch. var/position = CONVEYOR_OFF - /// Last direction setting. - var/last_pos = CONVEYOR_BACKWARDS /// If the switch only operates the conveyor belts in a single direction. var/oneway = FALSE /// If the level points the opposite direction when it's turned on. @@ -376,6 +369,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) AddComponent(/datum/component/usb_port, list( /obj/item/circuit_component/conveyor_switch, )) + register_context() /obj/machinery/conveyor_switch/Destroy() LAZYREMOVE(GLOB.conveyors_by_id[id], src) @@ -401,6 +395,27 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) icon_state = "[base_icon_state]-[invert_icon ? "rev" : "fwd"]" return ..() +/obj/machinery/conveyor_switch/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(!held_item) + context[SCREENTIP_CONTEXT_LMB] = "Toggle forwards" + if(!oneway) + context[SCREENTIP_CONTEXT_RMB] = "Toggle backwards" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_MULTITOOL) + context[SCREENTIP_CONTEXT_LMB] = "Set speed" + context[SCREENTIP_CONTEXT_RMB] = "View wires" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Toggle oneway" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Detach" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "Invert" + return CONTEXTUAL_SCREENTIP_SET + /// Updates all conveyor belts that are linked to this switch, and tells them to start processing. /obj/machinery/conveyor_switch/proc/update_linked_conveyors() for(var/obj/machinery/conveyor/belt in GLOB.conveyors_by_id[id]) @@ -418,29 +433,46 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) CHECK_TICK /// Updates the switch's `position` and `last_pos` variable. Useful so that the switch can properly cycle between the forwards, backwards and neutral positions. -/obj/machinery/conveyor_switch/proc/update_position() +/obj/machinery/conveyor_switch/proc/update_position(direction) if(position == CONVEYOR_OFF) if(oneway) //is it a oneway switch position = oneway else - if(last_pos < CONVEYOR_OFF) + if(direction == CONVEYOR_FORWARD) position = CONVEYOR_FORWARD - last_pos = CONVEYOR_OFF else position = CONVEYOR_BACKWARDS - last_pos = CONVEYOR_OFF else - last_pos = position position = CONVEYOR_OFF -/// Called when a user clicks on this switch with an open hand. -/obj/machinery/conveyor_switch/interact(mob/user) +/obj/machinery/conveyor_switch/proc/on_user_activation(mob/user, direction) add_fingerprint(user) - update_position() + update_position(direction) update_appearance() update_linked_conveyors() update_linked_switches() +/// Called when a user clicks on this switch with an open hand. +/obj/machinery/conveyor_switch/attack_hand(mob/user, list/modifiers) + . = ..() + on_user_activation(user, CONVEYOR_FORWARD) + +/obj/machinery/conveyor_switch/attack_hand_secondary(mob/user, list/modifiers) + on_user_activation(user, CONVEYOR_BACKWARDS) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/conveyor_switch/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/conveyor_switch/attack_ai_secondary(mob/user, list/modifiers) + return attack_hand_secondary(user, modifiers) + +/obj/machinery/conveyor_switch/attack_robot(mob/user) + return attack_hand(user) + +/obj/machinery/conveyor_switch/attack_robot_secondary(mob/user, list/modifiers) + return attack_hand_secondary(user, modifiers) + /obj/machinery/conveyor_switch/attackby(obj/item/attacking_item, mob/user, params) if(is_wire_tool(attacking_item)) wires.interact(user) @@ -592,14 +624,19 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) /obj/item/circuit_component/conveyor_switch display_name = "Conveyor Switch" desc = "Allows to control connected conveyor belts." - circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL + /// Direction input ports. + var/datum/port/input/stop + var/datum/port/input/active + var/datum/port/input/reverse /// The current direction of the conveyor attached to the component. var/datum/port/output/direction /// The switch this conveyor switch component is attached to. var/obj/machinery/conveyor_switch/attached_switch /obj/item/circuit_component/conveyor_switch/populate_ports() + active = add_input_port("Activate", PORT_TYPE_SIGNAL, trigger = PROC_REF(activate)) + stop = add_input_port("Stop", PORT_TYPE_SIGNAL, trigger = PROC_REF(stop)) direction = add_output_port("Conveyor Direction", PORT_TYPE_NUMBER) /obj/item/circuit_component/conveyor_switch/get_ui_notices() @@ -610,27 +647,34 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) . = ..() if(istype(shell, /obj/machinery/conveyor_switch)) attached_switch = shell + if(!attached_switch.oneway) + reverse = add_input_port("Reverse", PORT_TYPE_SIGNAL, trigger = PROC_REF(reverse)) /obj/item/circuit_component/conveyor_switch/unregister_usb_parent(atom/movable/shell) attached_switch = null return ..() -/obj/item/circuit_component/conveyor_switch/input_received(datum/port/input/port) - if(!attached_switch) - return - - INVOKE_ASYNC(src, PROC_REF(update_conveyers), port) - -/obj/item/circuit_component/conveyor_switch/proc/update_conveyers(datum/port/input/port) - if(!attached_switch) - return - - attached_switch.update_position() +/obj/item/circuit_component/conveyor_switch/proc/on_switch_changed() attached_switch.update_appearance() attached_switch.update_linked_conveyors() attached_switch.update_linked_switches() direction.set_output(attached_switch.position) +/obj/item/circuit_component/conveyor_switch/proc/activate() + SIGNAL_HANDLER + attached_switch.position = CONVEYOR_FORWARD + INVOKE_ASYNC(src, PROC_REF(on_switch_changed)) + +/obj/item/circuit_component/conveyor_switch/proc/stop() + SIGNAL_HANDLER + attached_switch.position = CONVEYOR_OFF + INVOKE_ASYNC(src, PROC_REF(on_switch_changed)) + +/obj/item/circuit_component/conveyor_switch/proc/reverse() + SIGNAL_HANDLER + attached_switch.position = CONVEYOR_BACKWARDS + INVOKE_ASYNC(src, PROC_REF(on_switch_changed)) + #undef CONVEYOR_BACKWARDS #undef CONVEYOR_OFF #undef CONVEYOR_FORWARD diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 84e43fd0dec90..4acb1aa0a33c6 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -10,6 +10,7 @@ resistance_flags = FIRE_PROOF interaction_flags_machine = INTERACT_MACHINE_OPEN | INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON obj_flags = CAN_BE_HIT + use_power = NO_POWER_USE /// The internal air reservoir of the disposal var/datum/gas_mixture/air_contents @@ -99,7 +100,8 @@ if(current_size >= STAGE_FIVE) deconstruct() -/obj/machinery/disposal/LateInitialize() +/obj/machinery/disposal/post_machine_initialize() + . = ..() //this will get a copy of the air turf and take a SEND PRESSURE amount of air from it var/atom/L = loc var/datum/gas_mixture/env = new diff --git a/code/modules/recycling/disposal/construction.dm b/code/modules/recycling/disposal/construction.dm index 4b8fef129244e..903a59a930557 100644 --- a/code/modules/recycling/disposal/construction.dm +++ b/code/modules/recycling/disposal/construction.dm @@ -95,8 +95,6 @@ pipe_type = initial(temp.flip_type) update_appearance() -/obj/structure/disposalconstruct/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation // construction/deconstruction // wrench: (un)anchor diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm index 2d964d0f8fb3f..b842a69413d7d 100644 --- a/code/modules/recycling/disposal/holder.dm +++ b/code/modules/recycling/disposal/holder.dm @@ -78,7 +78,7 @@ /// Starts the movement process, persists while the holder is moving through pipes /obj/structure/disposalholder/proc/start_moving() var/delay = world.tick_lag - var/datum/move_loop/our_loop = SSmove_manager.move_disposals(src, delay = delay, timeout = delay * count) + var/datum/move_loop/our_loop = GLOB.move_manager.move_disposals(src, delay = delay, timeout = delay * count) if(our_loop) RegisterSignal(our_loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move)) RegisterSignal(our_loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(try_expel)) @@ -172,7 +172,7 @@ for(var/obj/structure/disposalpipe/P in T) if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir if(QDELING(P)) - to_chat(world, "DEBUG -- [src] here, new pipe is being thanos'd") + CRASH("Pipe is being deleted while being used by a disposal holder at ([P.x], [P.y], [P.z]") return P // if no matching pipe, return null return null diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm index 69519874cd2ca..9a1ad786e7220 100644 --- a/code/modules/recycling/disposal/pipe.dm +++ b/code/modules/recycling/disposal/pipe.dm @@ -170,27 +170,24 @@ return TRUE // called when pipe is cut with welder -/obj/structure/disposalpipe/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - if(spawn_pipe) - var/obj/structure/disposalconstruct/construct = stored - if(!construct) // Don't have something? Make one now - construct = new /obj/structure/disposalconstruct(src, null, SOUTH, FALSE, src) - stored = null - construct.forceMove(loc) - transfer_fingerprints_to(construct) - construct.setDir(dir) - spawn_pipe = FALSE - else - var/turf/T = get_turf(src) - for(var/D in GLOB.cardinals) - if(D & dpdir) - var/obj/structure/disposalpipe/broken/P = new(T) - P.setDir(D) +/obj/structure/disposalpipe/atom_deconstruct(disassembled = TRUE) + if(disassembled) + if(spawn_pipe) + var/obj/structure/disposalconstruct/construct = stored + if(!construct) // Don't have something? Make one now + construct = new /obj/structure/disposalconstruct(src, null, SOUTH, FALSE, src) + stored = null + construct.forceMove(loc) + transfer_fingerprints_to(construct) + construct.setDir(dir) + spawn_pipe = FALSE + else + var/turf/location = get_turf(src) + for(var/dir in GLOB.cardinals) + if(dir & dpdir) + var/obj/structure/disposalpipe/broken/pipe = new(location) + pipe.setDir(dir) spew_forth() - qdel(src) - /obj/structure/disposalpipe/singularity_pull(S, current_size) ..() @@ -323,9 +320,6 @@ spawn_pipe = FALSE anchored = FALSE -/obj/structure/disposalpipe/broken/deconstruct() - qdel(src) - /obj/structure/disposalpipe/rotator icon_state = "pipe-r1" initialize_dirs = DISP_DIR_LEFT | DISP_DIR_RIGHT | DISP_DIR_FLIP diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index a178bcd6ad5ff..8c46de58a98b2 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -51,10 +51,9 @@ if(EXPLODE_LIGHT) SSexplosions.low_mov_atom += contents -/obj/item/delivery/deconstruct() +/obj/item/delivery/atom_deconstruct(dissambled = TRUE) unwrap_contents() post_unwrap_contents() - return ..() /obj/item/delivery/examine(mob/user) . = ..() @@ -80,7 +79,7 @@ movable_loc.relay_container_resist_act(user, object) return to_chat(user, span_notice("You lean on the back of [object] and start pushing to rip the wrapping around it.")) - if(do_after(user, 50, target = object)) + if(do_after(user, 5 SECONDS, target = object)) if(!user || user.stat != CONSCIOUS || user.loc != object || object.loc != src) return to_chat(user, span_notice("You successfully removed [object]'s wrapping!")) @@ -401,10 +400,10 @@ payments_acc = null to_chat(user, span_notice("You clear the registered account.")) -/obj/item/sales_tagger/AltClick(mob/user) - . = ..() +/obj/item/sales_tagger/click_alt(mob/user) var/potential_cut = input("How much would you like to pay out to the registered card?","Percentage Profit ([round(cut_min*100)]% - [round(cut_max*100)]%)") as num|null if(!potential_cut) cut_multiplier = initial(cut_multiplier) cut_multiplier = clamp(round(potential_cut/100, cut_min), cut_min, cut_max) to_chat(user, span_notice("[round(cut_multiplier*100)]% profit will be received if a package with a barcode is sold.")) + return CLICK_ACTION_SUCCESS diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm index d67919cd38031..c370424fa7d2c 100644 --- a/code/modules/religion/burdened/psyker.dm +++ b/code/modules/religion/burdened/psyker.dm @@ -341,7 +341,7 @@ else times_dry_fired = 0 var/turf/target_turf = get_offset_target_turf(get_ranged_target_turf(owner, owner.dir, 7), dx = rand(-1, 1), dy = rand(-1, 1)) - held_gun.process_fire(target_turf, owner, TRUE, null, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)) + held_gun.process_fire(target_turf, owner, TRUE, null, pick(GLOB.all_body_zones)) held_gun.semicd = FALSE /datum/action/cooldown/spell/charged/psychic_booster diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index ee5865b835a52..a8f23225a8ba8 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -154,10 +154,10 @@ /datum/religion_sect/mechanical/sect_bless(mob/living/target, mob/living/chap) if(iscyborg(target)) var/mob/living/silicon/robot/R = target - var/charge_amt = 50 + var/charge_amount = 0.05 * STANDARD_CELL_CHARGE if(target.mind?.holy_role == HOLY_ROLE_HIGHPRIEST) - charge_amt *= 2 - R.cell?.charge += charge_amt + charge_amount *= 2 + R.cell?.charge += charge_amount R.visible_message(span_notice("[chap] charges [R] with the power of [GLOB.deity]!")) to_chat(R, span_boldnotice("You are charged by the power of [GLOB.deity]!")) R.add_mood_event("blessing", /datum/mood_event/blessing) @@ -171,7 +171,7 @@ var/did_we_charge = FALSE var/obj/item/organ/internal/stomach/ethereal/eth_stomach = blessed.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(eth_stomach)) - eth_stomach.adjust_charge(60) + eth_stomach.adjust_charge(0.06 * STANDARD_CELL_CHARGE) did_we_charge = TRUE //if we're not targeting a robot part we stop early @@ -200,11 +200,11 @@ if(!istype(power_cell)) return - if(power_cell.charge < 0.3 * STANDARD_CELL_CHARGE) + if(power_cell.charge() < 0.3 * STANDARD_CELL_CHARGE) to_chat(chap, span_notice("[GLOB.deity] does not accept pity amounts of power.")) return - adjust_favor(round(power_cell.charge/300), chap) + adjust_favor(round(power_cell.charge() / (0.3 * STANDARD_CELL_CHARGE)), chap) to_chat(chap, span_notice("You offer [power_cell]'s power to [GLOB.deity], pleasing them.")) qdel(power_cell) return TRUE @@ -238,7 +238,7 @@ to_chat(user, span_notice("The candle needs to be lit to be offered!")) return to_chat(user, span_notice("[GLOB.deity] is pleased with your sacrifice.")) - adjust_favor(50, user) //it's not a lot but hey there's a pacifist favor option at least + adjust_favor(40, user) //it's not a lot but hey there's a pacifist favor option at least qdel(offering) return TRUE diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index d907191c33ddd..d7d0fa818441c 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -128,13 +128,36 @@ /datum/religion_rites/machine_blessing/invoke_effect(mob/living/user, atom/movable/religious_tool) ..() var/altar_turf = get_turf(religious_tool) - var/blessing = pick( - /obj/item/organ/internal/cyberimp/arm/surgery, - /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic, - /obj/item/organ/internal/cyberimp/eyes/hud/medical, - /obj/item/organ/internal/cyberimp/mouth/breathing_tube, - /obj/item/organ/internal/cyberimp/chest/thrusters, - /obj/item/organ/internal/eyes/robotic/glow, + var/blessing = pick_weight_recursive( + list( + // Arms + list( + /obj/item/organ/internal/cyberimp/arm/combat = 1, + /obj/item/organ/internal/cyberimp/arm/surgery = 1000000, + /obj/item/organ/internal/cyberimp/arm/toolset = 1500000, + ) = 15, + // Eyes + list( + /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic = 1, + /obj/item/organ/internal/cyberimp/eyes/hud/medical = 1, + /obj/item/organ/internal/eyes/robotic/glow = 1, + /obj/item/organ/internal/eyes/robotic/shield = 2, + ) = 15, + // Chest + list( + /obj/item/organ/internal/cyberimp/chest/reviver = 1, + /obj/item/organ/internal/cyberimp/chest/thrusters = 2, + ) = 9, + // Brain / Head + list( + /obj/item/organ/internal/cyberimp/brain/anti_drop = 100, + /obj/item/organ/internal/cyberimp/brain/anti_stun = 10, + ) = 10, + // Misc + list( + /obj/item/organ/internal/cyberimp/mouth/breathing_tube = 1, + ) = 5, + ) ) new blessing(altar_turf) return TRUE diff --git a/code/modules/requests/request_manager.dm b/code/modules/requests/request_manager.dm index dd6d8d42a480e..74a40304f7aed 100644 --- a/code/modules/requests/request_manager.dm +++ b/code/modules/requests/request_manager.dm @@ -163,17 +163,18 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) switch(action) if ("pp") - var/mob/M = request.owner?.mob - usr.client.holder.show_player_panel(M) + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/show_player_panel, request.owner?.mob) return TRUE + if ("vv") var/mob/M = request.owner?.mob usr.client.debug_variables(M) return TRUE + if ("sm") - var/mob/M = request.owner?.mob - usr.client.cmd_admin_subtle_message(M) + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/cmd_admin_subtle_message, request.owner?.mob) return TRUE + if ("flw") var/mob/M = request.owner?.mob usr.client.admin_follow(M) @@ -192,8 +193,9 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) D.traitor_panel() return TRUE else - usr.client.holder.show_traitor_panel(M) + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_traitor_panel, M) return TRUE + if ("logs") var/mob/M = request.owner?.mob if(!ismob(M)) @@ -201,16 +203,11 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) return TRUE show_individual_logging_panel(M, null, null) return TRUE + if ("smite") - if(!check_rights(R_FUN)) - to_chat(usr, "Insufficient permissions to smite, you require +FUN", confidential = TRUE) - return TRUE - var/mob/living/carbon/human/H = request.owner?.mob - if (!H || !istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human", confidential = TRUE) - return TRUE - usr.client.smite(H) + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/admin_smite, request.owner?.mob) return TRUE + if ("rply") if (request.req_type == REQUEST_PRAYER) to_chat(usr, "Cannot reply to a prayer", confidential = TRUE) diff --git a/code/modules/research/designs/AI_module_designs.dm b/code/modules/research/designs/AI_module_designs.dm index f45ca0e314879..715bd96472545 100644 --- a/code/modules/research/designs/AI_module_designs.dm +++ b/code/modules/research/designs/AI_module_designs.dm @@ -210,6 +210,17 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SCIENCE +/datum/design/board/yesman_module + name = "Y.E.S.M.A.N. Module" + desc = "Allows for the construction of a Y.E.S.M.A.N. AI Core Module." + id = "yesman_module" + materials = list(/datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/diamond = SHEET_MATERIAL_AMOUNT, /datum/material/bluespace = HALF_SHEET_MATERIAL_AMOUNT) + build_path = /obj/item/ai_module/core/full/yesman + category = list( + RND_CATEGORY_AI + RND_SUBCATEGORY_AI_CORE_MODULES + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + /datum/design/board/nutimov_module name = "Nutimov Module" desc = "Allows for the construction of a Nutimov AI Core Module." diff --git a/code/modules/research/designs/autolathe/service_designs.dm b/code/modules/research/designs/autolathe/service_designs.dm index 6b8d7f474fca4..e34fc5166c89c 100644 --- a/code/modules/research/designs/autolathe/service_designs.dm +++ b/code/modules/research/designs/autolathe/service_designs.dm @@ -190,6 +190,19 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE +/datum/design/soup_pot + name = "Soup Pot" + id = "souppot" + build_type = AUTOLATHE | PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT*5, /datum/material/bluespace =SMALL_MATERIAL_AMOUNT*4) + category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_EQUIPMENT) + build_path = /obj/item/reagent_containers/cup/soup_pot + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_KITCHEN, + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE + /datum/design/bowl name = "Bowl" id = "bowl" diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 0081fe052eca7..819c17662af76 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -1408,6 +1408,36 @@ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_MEDICAL ) +/datum/design/borg_upgrade_surgicalomnitool + name = "Advanced Surgical Omnitool Upgrade" + id = "borg_upgrade_surgicalomnitool" + build_type = MECHFAB + build_path = /obj/item/borg/upgrade/surgery_omnitool + materials = list( + /datum/material/iron=SHEET_MATERIAL_AMOUNT*5, + /datum/material/titanium=SHEET_MATERIAL_AMOUNT*3, + /datum/material/silver=SHEET_MATERIAL_AMOUNT*2, + ) + construction_time = 4 SECONDS + category = list( + RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_MEDICAL + ) + +/datum/design/borg_upgrade_engineeringomnitool + name = "Advanced Engineering Omnitool Upgrade" + id = "borg_upgrade_engineeringomnitool" + build_type = MECHFAB + build_path = /obj/item/borg/upgrade/engineering_omnitool + materials = list( + /datum/material/iron=SHEET_MATERIAL_AMOUNT*5, + /datum/material/titanium=SHEET_MATERIAL_AMOUNT*3, + /datum/material/gold=SHEET_MATERIAL_AMOUNT*2, + ) + construction_time = 4 SECONDS + category = list( + RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_ENGINEERING, + ) + /datum/design/borg_upgrade_trashofholding name = "Trash Bag of Holding" id = "borg_upgrade_trashofholding" diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index e17b53da692fe..84dcb67233d52 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -189,6 +189,17 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE +/datum/design/water_balloon + name = "Water Balloon" + id = "water_balloon" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/plastic =SMALL_MATERIAL_AMOUNT*5) + build_path = /obj/item/toy/waterballoon + category = list( + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SERVICE + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE + /datum/design/mesons name = "Optical Meson Scanners" desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting condition." diff --git a/code/modules/research/designs/tool_designs.dm b/code/modules/research/designs/tool_designs.dm index 304ed53790a68..649d0c5c09dfc 100644 --- a/code/modules/research/designs/tool_designs.dm +++ b/code/modules/research/designs/tool_designs.dm @@ -137,7 +137,7 @@ name = "RCD anti disruption designs upgrade" desc = "Prevents interruption of RCD construction and deconstruction." id = "rcd_upgrade_anti_interrupt" - build_type = PROTOLATHE + build_type = PROTOLATHE | AWAY_LATHE materials = list( /datum/material/iron = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 1.25, @@ -154,7 +154,7 @@ name = "RCD cooling upgrade" desc = "Allows the RCD to more quickly perform multiple actions at once." id = "rcd_upgrade_cooling" - build_type = PROTOLATHE + build_type = PROTOLATHE | AWAY_LATHE materials = list( /datum/material/iron = SHEET_MATERIAL_AMOUNT * 2, /datum/material/glass = SHEET_MATERIAL_AMOUNT, diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm index 3606dd67e2e60..204ecaa289bcf 100644 --- a/code/modules/research/designs/wiremod_designs.dm +++ b/code/modules/research/designs/wiremod_designs.dm @@ -81,6 +81,11 @@ id = "comp_logic" build_path = /obj/item/circuit_component/compare/logic +/datum/design/component/toggle + name = "Toggle Component" + id = "comp_toggle" + build_path = /obj/item/circuit_component/compare/toggle + /datum/design/component/delay name = "Delay Component" id = "comp_delay" @@ -221,6 +226,11 @@ id = "comp_health" build_path = /obj/item/circuit_component/health +/datum/design/component/compare/health_state + name = "Compare Health State Component" + id = "comp_health_state" + build_path = /obj/item/circuit_component/compare/health_state + /datum/design/component/matscanner name = "Material Scanner" id = "comp_matscanner" @@ -337,6 +347,11 @@ id = "comp_ntnet_send" build_path = /obj/item/circuit_component/ntnet_send +/datum/design/component/list_literal/ntnet_send + name = "NTNet Transmitter List Literal" + id = "comp_ntnet_send_list_literal" + build_path = /obj/item/circuit_component/list_literal/ntnet_send + /datum/design/component/list_literal name = "List Literal Component" id = "comp_list_literal" diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm index 03fffcec8ca6f..021c282958d89 100644 --- a/code/modules/research/destructive_analyzer.dm +++ b/code/modules/research/destructive_analyzer.dm @@ -53,9 +53,9 @@ addtimer(CALLBACK(src, PROC_REF(finish_loading)), 1 SECONDS) return TRUE -/obj/machinery/rnd/destructive_analyzer/AltClick(mob/user) - . = ..() +/obj/machinery/rnd/destructive_analyzer/click_alt(mob/user) unload_item() + return CLICK_ACTION_SUCCESS /obj/machinery/rnd/destructive_analyzer/update_icon_state() icon_state = "[base_icon_state][loaded_item ? "_l" : null]" @@ -115,11 +115,11 @@ say("Destructive analysis failed!") return TRUE -//Let emags in on a right click -/obj/machinery/rnd/destructive_analyzer/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - if(is_right_clicking && istype(tool, /obj/item/card/emag)) - return NONE - return ..() +/obj/machinery/rnd/destructive_analyzer/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers) + // Cringe way to let emags insert on RMB because we still use attackby to insert + if(istype(tool, /obj/item/card/emag)) + return ITEM_INTERACT_SKIP_TO_ATTACK + return NONE //This allows people to put syndicate screwdrivers in the machine. Secondary act still passes. /obj/machinery/rnd/destructive_analyzer/screwdriver_act(mob/living/user, obj/item/tool) diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index 11d87bdd66780..89c69b7334e40 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -509,10 +509,10 @@ investigate_log("Experimentor has drained power from its APC", INVESTIGATE_EXPERIMENTOR) if(globalMalf == 99) visible_message(span_warning("[src] begins to glow and vibrate. It's going to blow!")) - addtimer(CALLBACK(src, PROC_REF(boom)), 50) + addtimer(CALLBACK(src, PROC_REF(boom)), 5 SECONDS) if(globalMalf == 100) visible_message(span_warning("[src] begins to glow and vibrate. It's going to blow!")) - addtimer(CALLBACK(src, PROC_REF(honk)), 50) + addtimer(CALLBACK(src, PROC_REF(honk)), 5 SECONDS) addtimer(CALLBACK(src, PROC_REF(reset_exp)), resetTime) @@ -663,7 +663,7 @@ /obj/item/relic/proc/explode(mob/user) to_chat(user, span_danger("[src] begins to heat up!")) - addtimer(CALLBACK(src, PROC_REF(do_explode), user), rand(35, 100)) + addtimer(CALLBACK(src, PROC_REF(do_explode), user), rand(3.5 SECONDS, 10 SECONDS)) /obj/item/relic/proc/do_explode(mob/user) if(loc == user) @@ -674,7 +674,7 @@ /obj/item/relic/proc/teleport(mob/user) to_chat(user, span_notice("[src] begins to vibrate!")) - addtimer(CALLBACK(src, PROC_REF(do_the_teleport), user), rand(10, 30)) + addtimer(CALLBACK(src, PROC_REF(do_the_teleport), user), rand(1 SECONDS, 3 SECONDS)) /obj/item/relic/proc/do_the_teleport(mob/user) var/turf/userturf = get_turf(user) diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index d0c2473f449a4..bdd31f4e9a04c 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -1,8 +1,8 @@ /obj/machinery/rnd/production name = "technology fabricator" desc = "Makes researched and prototype items with materials and energy." - // Energy cost per full stack of materials spent. Material insertion is 40% of this. - active_power_usage = 50 * BASE_MACHINE_ACTIVE_CONSUMPTION + /// Energy cost per full stack of materials spent. Material insertion is 40% of this. + active_power_usage = 0.05 * STANDARD_CELL_RATE /// The efficiency coefficient. Material costs and print times are multiplied by this number; var/efficiency_coeff = 1 @@ -22,10 +22,6 @@ var/drop_direction = 0 /obj/machinery/rnd/production/Initialize(mapload) - . = ..() - - cached_designs = list() - materials = AddComponent( /datum/component/remote_materials, \ mapload, \ @@ -34,6 +30,10 @@ ) \ ) + . = ..() + + cached_designs = list() + RegisterSignal(src, COMSIG_SILO_ITEM_CONSUMED, TYPE_PROC_REF(/obj/machinery/rnd/production, silo_material_insert)) AddComponent( @@ -182,11 +182,10 @@ /obj/machinery/rnd/production/RefreshParts() . = ..() - if(materials) - var/total_storage = 0 - for(var/datum/stock_part/matter_bin/bin in component_parts) - total_storage += bin.tier * 37.5 * SHEET_MATERIAL_AMOUNT - materials.set_local_size(total_storage) + var/total_storage = 0 + for(var/datum/stock_part/matter_bin/bin in component_parts) + total_storage += bin.tier * 37.5 * SHEET_MATERIAL_AMOUNT + materials.set_local_size(total_storage) efficiency_coeff = compute_efficiency() @@ -448,12 +447,12 @@ drop_direction = direction balloon_alert(usr, "dropping [dir2text(drop_direction)]") -/obj/machinery/rnd/production/AltClick(mob/user) - . = ..() - if(!drop_direction || !can_interact(user)) - return +/obj/machinery/rnd/production/click_alt(mob/user) + if(drop_direction == 0) + return CLICK_ACTION_BLOCKING if(busy) balloon_alert(user, "busy printing!") - return + return CLICK_ACTION_BLOCKING balloon_alert(user, "drop direction reset") drop_direction = 0 + return CLICK_ACTION_SUCCESS diff --git a/code/modules/research/ordnance/doppler_array.dm b/code/modules/research/ordnance/doppler_array.dm index 7afe201f36007..5e44c2dc703e4 100644 --- a/code/modules/research/ordnance/doppler_array.dm +++ b/code/modules/research/ordnance/doppler_array.dm @@ -250,8 +250,6 @@ SIGNAL_HANDLER set_light_on(!(machine_stat & NOPOWER)) -/obj/machinery/doppler_array/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/machinery/doppler_array/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index e529f97eb0c82..cc8e842f18e9a 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -45,7 +45,7 @@ Nothing else in the console has ID requirements. return reagent.name return ID -/obj/machinery/computer/rdconsole/LateInitialize() +/obj/machinery/computer/rdconsole/post_machine_initialize() . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research) CONNECT_TO_RND_SERVER_ROUNDSTART(stored_research, src) @@ -108,7 +108,7 @@ Nothing else in the console has ID requirements. if(stored_research.can_afford(price)) user.investigate_log("researched [id]([json_encode(price)]) on techweb id [stored_research.id].", INVESTIGATE_RESEARCH) if(istype(stored_research, /datum/techweb/science)) - SSblackbox.record_feedback("associative", "science_techweb_unlock", 1, list("id" = "[id]", "name" = TN.display_name, "price" = "[json_encode(price)]", "time" = SQLtime())) + SSblackbox.record_feedback("associative", "science_techweb_unlock", 1, list("id" = "[id]", "name" = TN.display_name, "price" = "[json_encode(price)]", "time" = ISOtime())) if(stored_research.research_node_id(id)) say("Successfully researched [TN.display_name].") var/logname = "Unknown" @@ -129,7 +129,7 @@ Nothing else in the console has ID requirements. logname = "[ID.registered_name]" stored_research.research_logs += list(list( "node_name" = TN.display_name, - "node_cost" = price["General Research"], + "node_cost" = price[TECHWEB_POINT_TYPE_GENERIC], "node_researcher" = logname, "node_research_location" = "[get_area(src)] ([src.x],[src.y],[src.z])", )) diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm index 58d7f1f29cf3d..60dcc8716cc10 100644 --- a/code/modules/research/rdmachines.dm +++ b/code/modules/research/rdmachines.dm @@ -24,7 +24,7 @@ set_wires(new /datum/wires/rnd(src)) register_context() -/obj/machinery/rnd/LateInitialize() +/obj/machinery/rnd/post_machine_initialize() . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research) CONNECT_TO_RND_SERVER_ROUNDSTART(stored_research, src) diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm index e446672bc33a9..1bd0d3560beed 100644 --- a/code/modules/research/server.dm +++ b/code/modules/research/server.dm @@ -154,17 +154,16 @@ if(HDD_OVERLOADED) . += "The front panel is dangling open. The hdd inside is destroyed and the wires are all burned." -/obj/machinery/rnd/server/master/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) +/obj/machinery/rnd/server/master/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(!tool.tool_behaviour) - return ..() - // Only antags are given the training and knowledge to disassemble this thing. - if(is_special_character(user)) - return ..() - if(user.combat_mode) return NONE - - balloon_alert(user, "you can't find an obvious maintenance hatch!") - return ITEM_INTERACT_BLOCKING + // Only antags are given the training and knowledge to disassemble this thing. + if(!is_special_character(user)) + if(user.combat_mode) + return ITEM_INTERACT_SKIP_TO_ATTACK + balloon_alert(user, "you can't find an obvious maintenance hatch!") + return ITEM_INTERACT_BLOCKING + return NONE /obj/machinery/rnd/server/master/attackby(obj/item/attacking_item, mob/user, params) if(istype(attacking_item, /obj/item/computer_disk/hdd_theft)) diff --git a/code/modules/research/server_control.dm b/code/modules/research/server_control.dm index 94a429dc6d717..24327a731a64e 100644 --- a/code/modules/research/server_control.dm +++ b/code/modules/research/server_control.dm @@ -9,7 +9,7 @@ ///Connected techweb node the server is connected to. var/datum/techweb/stored_research -/obj/machinery/computer/rdservercontrol/LateInitialize() +/obj/machinery/computer/rdservercontrol/post_machine_initialize() . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research) CONNECT_TO_RND_SERVER_ROUNDSTART(stored_research, src) diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 79d24b9c55ab9..d4cb4afefdaf0 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -207,7 +207,7 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good continue part_list += component_part //Sort the parts. This ensures that higher tier items are applied first. - part_list = sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort)) + sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort)) return part_list /proc/cmp_rped_sort(obj/item/first_item, obj/item/second_item) diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 8e0fdc95a746c..69552a4923ca3 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -106,6 +106,7 @@ "slime_scanner", "solar_panel", "solar_tracker", + "souppot", "space_heater", "spoon", "status_display_frame", @@ -343,6 +344,7 @@ "comp_get_column", "comp_gps", "comp_health", + "comp_health_state", "comp_hear", "comp_id_access_reader", "comp_id_getter", @@ -367,6 +369,7 @@ "comp_not", "comp_ntnet_receive", "comp_ntnet_send", + "comp_ntnet_send_list_literal", "comp_pinpointer", "comp_pressuresensor", "comp_radio", @@ -385,6 +388,7 @@ "comp_tempsensor", "comp_textcase", "comp_timepiece", + "comp_toggle", "comp_tonumber", "comp_tostring", "comp_trigonometry", @@ -1020,6 +1024,7 @@ "borg_upgrade_rped", "borg_upgrade_hypermod", "borg_upgrade_inducer", + "borg_upgrade_engineeringomnitool", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) @@ -1035,6 +1040,7 @@ "borg_upgrade_piercinghypospray", "borg_upgrade_pinpointer", "borg_upgrade_surgicalprocessor", + "borg_upgrade_surgicalomnitool", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) @@ -1094,6 +1100,7 @@ "maintain_module", "liveandletlive_module", "reporter_module", + "yesman_module", "hulkamania_module", "peacekeeper_module", "overlord_module", diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm index 7b85a878ec39b..0e6a37ce3d0ba 100644 --- a/code/modules/research/xenobiology/crossbreeding/_misc.dm +++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm @@ -93,8 +93,8 @@ Slimecrossing Items icon_state = "yellow slime extract" rating = 7 custom_materials = null - maxcharge = 50000 - chargerate = 2500 + maxcharge = 50 * STANDARD_CELL_CHARGE + chargerate = 2.5 * STANDARD_CELL_RATE charge_light_type = null connector_type = "slimecore" diff --git a/code/modules/research/xenobiology/crossbreeding/_potions.dm b/code/modules/research/xenobiology/crossbreeding/_potions.dm index 7b37ce3ae6b55..ecf76357e2010 100644 --- a/code/modules/research/xenobiology/crossbreeding/_potions.dm +++ b/code/modules/research/xenobiology/crossbreeding/_potions.dm @@ -54,7 +54,7 @@ Slimecrossing Potions peace_target.visible_message(span_danger("[user] starts to drink [src]!"), span_danger("You start to drink [src]!")) - if(!do_after(user, 100, target = peace_target)) + if(!do_after(user, 10 SECONDS, target = peace_target)) return if(peace_target != user) to_chat(user, span_notice("You feed [peace_target] [src]!")) @@ -91,7 +91,7 @@ Slimecrossing Potions love_target.visible_message(span_danger("[user] starts to feed [love_target] a love potion!"), span_userdanger("[user] starts to feed you a love potion!")) - if(!do_after(user, 50, target = love_target)) + if(!do_after(user, 5 SECONDS, target = love_target)) return to_chat(user, span_notice("You feed [love_target] the love potion!")) to_chat(love_target, span_notice("You develop feelings for [user], and anyone [user.p_they()] like[user.p_s()].")) diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index 667ffe24191c4..03b178e3f57f7 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -7,6 +7,7 @@ id = "rainbow_protection" duration = 100 alert_type = /atom/movable/screen/alert/status_effect/rainbow_protection + show_duration = TRUE var/originalcolor /datum/status_effect/rainbow_protection/on_apply() @@ -37,6 +38,7 @@ id = "slimeskin" duration = 300 alert_type = /atom/movable/screen/alert/status_effect/slimeskin + show_duration = TRUE var/originalcolor /datum/status_effect/slimeskin/on_apply() diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm index c21645ede96e1..72ee9d98516eb 100644 --- a/code/modules/research/xenobiology/crossbreeding/burning.dm +++ b/code/modules/research/xenobiology/crossbreeding/burning.dm @@ -258,7 +258,7 @@ Burning extracts: /obj/item/slimecross/burning/oil/do_effect(mob/user) user.visible_message(span_warning("[user] activates [src]. It's going to explode!"), span_danger("You activate [src]. It crackles in anticipation")) - addtimer(CALLBACK(src, PROC_REF(boom)), 50) + addtimer(CALLBACK(src, PROC_REF(boom)), 5 SECONDS) /// Inflicts a blastwave upon every mob within a small radius. /obj/item/slimecross/burning/oil/proc/boom() diff --git a/code/modules/research/xenobiology/crossbreeding/charged.dm b/code/modules/research/xenobiology/crossbreeding/charged.dm index 0440c7e9205ac..76c4d3eaa1437 100644 --- a/code/modules/research/xenobiology/crossbreeding/charged.dm +++ b/code/modules/research/xenobiology/crossbreeding/charged.dm @@ -199,7 +199,7 @@ Charged extracts: /obj/item/slimecross/charged/gold/do_effect(mob/user) user.visible_message(span_warning("[src] starts shuddering violently!")) - addtimer(CALLBACK(src, PROC_REF(startTimer)), 50) + addtimer(CALLBACK(src, PROC_REF(startTimer)), 5 SECONDS) /obj/item/slimecross/charged/gold/proc/startTimer() START_PROCESSING(SSobj, src) @@ -224,7 +224,7 @@ Charged extracts: /obj/item/slimecross/charged/oil/do_effect(mob/user) user.visible_message(span_danger("[src] begins to shake with rapidly increasing force!")) - addtimer(CALLBACK(src, PROC_REF(boom)), 50) + addtimer(CALLBACK(src, PROC_REF(boom)), 5 SECONDS) /obj/item/slimecross/charged/oil/proc/boom() explosion(src, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4, explosion_cause = src) //Much smaller effect than normal oils, but devastatingly strong where it does hit. diff --git a/code/modules/research/xenobiology/crossbreeding/chilling.dm b/code/modules/research/xenobiology/crossbreeding/chilling.dm index 2a23e34cb171b..d8cf3456ed221 100644 --- a/code/modules/research/xenobiology/crossbreeding/chilling.dm +++ b/code/modules/research/xenobiology/crossbreeding/chilling.dm @@ -174,7 +174,7 @@ Chilling extracts: for(var/mob/living/M in allies) var/datum/status_effect/slimerecall/S = M.apply_status_effect(/datum/status_effect/slimerecall) S.target = user - if(do_after(user, 100, target=src)) + if(do_after(user, 10 SECONDS, target=src)) to_chat(user, span_notice("[src] shatters as it tears a hole in reality, snatching the linked individuals from the void!")) for(var/mob/living/M in allies) var/datum/status_effect/slimerecall/S = M.has_status_effect(/datum/status_effect/slimerecall) @@ -292,7 +292,7 @@ Chilling extracts: /obj/item/slimecross/chilling/oil/do_effect(mob/user) user.visible_message(span_danger("[src] begins to shake with muted intensity!")) - addtimer(CALLBACK(src, PROC_REF(boom)), 50) + addtimer(CALLBACK(src, PROC_REF(boom)), 5 SECONDS) /obj/item/slimecross/chilling/oil/proc/boom() explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 10, explosion_cause = src) //Large radius, but mostly light damage, and no flash. diff --git a/code/modules/research/xenobiology/crossbreeding/consuming.dm b/code/modules/research/xenobiology/crossbreeding/consuming.dm index bffc15256943d..5a23d30671f54 100644 --- a/code/modules/research/xenobiology/crossbreeding/consuming.dm +++ b/code/modules/research/xenobiology/crossbreeding/consuming.dm @@ -66,7 +66,7 @@ Consuming extracts: fed = TRUE else M.visible_message(span_danger("[user] tries to force [M] to eat [src]!"), span_userdanger("[user] tries to force you to eat [src]!")) - if(do_after(user, 20, target = M)) + if(do_after(user, 2 SECONDS, target = M)) fed = TRUE M.visible_message(span_danger("[user] forces [M] to eat [src]!"), span_warning("[user] forces you to eat [src].")) if(fed) diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index de97ea7bf6990..9724bd776d87e 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -58,7 +58,7 @@ stored_slimes = list() -/obj/machinery/computer/camera_advanced/xenobio/LateInitialize(mapload) +/obj/machinery/computer/camera_advanced/xenobio/post_machine_initialize() . = ..() for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers) if(get_area(recycler.loc) == get_area(loc)) @@ -360,9 +360,9 @@ Due to keyboard shortcuts, the second one is not necessarily the remote eye's lo // Alternate clicks for slime, monkey and open turf if using a xenobio console -/mob/living/basic/slime/AltClick(mob/user) +/mob/living/basic/slime/click_alt(mob/user) SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_ALT, src) - ..() + return CLICK_ACTION_SUCCESS /mob/living/basic/slime/ShiftClick(mob/user) SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_SHIFT, src) diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index 866b2902b3389..7f87a08b85b3f 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -108,7 +108,7 @@ return 120 if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_notice("Your [name] starts pulsing...")) - if(do_after(user, 40, target = user)) + if(do_after(user, 4 SECONDS, target = user)) var/mob/living/basic/slime/new_slime = new(get_turf(user), /datum/slime_type/grey) playsound(user, 'sound/effects/splat.ogg', 50, TRUE) to_chat(user, span_notice("You spit out [new_slime].")) @@ -128,7 +128,7 @@ switch(activation_type) if(SLIME_ACTIVATE_MINOR) user.visible_message(span_warning("[user] starts shaking!"),span_notice("Your [name] starts pulsing gently...")) - if(do_after(user, 40, target = user)) + if(do_after(user, 4 SECONDS, target = user)) var/mob/living/spawned_mob = create_random_mob(user.drop_location(), FRIENDLY_SPAWN) spawned_mob.faction |= FACTION_NEUTRAL playsound(user, 'sound/effects/splat.ogg', 50, TRUE) @@ -137,7 +137,7 @@ if(SLIME_ACTIVATE_MAJOR) user.visible_message(span_warning("[user] starts shaking violently!"),span_warning("Your [name] starts pulsing violently...")) - if(do_after(user, 50, target = user)) + if(do_after(user, 5 SECONDS, target = user)) var/mob/living/spawned_mob = create_random_mob(user.drop_location(), HOSTILE_SPAWN) if(!user.combat_mode) spawned_mob.faction |= FACTION_NEUTRAL @@ -274,12 +274,12 @@ to_chat(user, span_warning("Your glow is already enhanced!")) return species.update_glow(user, 5) - addtimer(CALLBACK(species, TYPE_PROC_REF(/datum/species/jelly/luminescent, update_glow), user, LUMINESCENT_DEFAULT_GLOW), 600) + addtimer(CALLBACK(species, TYPE_PROC_REF(/datum/species/jelly/luminescent, update_glow), user, LUMINESCENT_DEFAULT_GLOW), 1 MINUTES) to_chat(user, span_notice("You start glowing brighter.")) if(SLIME_ACTIVATE_MAJOR) user.visible_message(span_warning("[user]'s skin starts flashing intermittently..."), span_warning("Your skin starts flashing intermittently...")) - if(do_after(user, 25, target = user)) + if(do_after(user, 2.5 SECONDS, target = user)) empulse(user, 1, 2) user.visible_message(span_warning("[user]'s skin flashes!"), span_warning("Your skin flashes as you emit an electromagnetic pulse!")) return 600 @@ -384,7 +384,7 @@ switch(activation_type) if(SLIME_ACTIVATE_MINOR) to_chat(user, span_warning("You feel yourself reverting to human form...")) - if(do_after(user, 120, target = user)) + if(do_after(user, 12 SECONDS, target = user)) to_chat(user, span_warning("You feel human again!")) user.set_species(/datum/species/human) return @@ -392,7 +392,7 @@ if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_warning("You feel yourself radically changing your slime type...")) - if(do_after(user, 120, target = user)) + if(do_after(user, 12 SECONDS, target = user)) to_chat(user, span_warning("You feel different!")) user.set_species(pick(/datum/species/jelly/slime, /datum/species/jelly/stargazer)) return @@ -437,7 +437,7 @@ if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_warning("You feel your own light turning dark...")) - if(do_after(user, 120, target = user)) + if(do_after(user, 12 SECONDS, target = user)) to_chat(user, span_warning("You feel a longing for darkness.")) user.set_species(pick(/datum/species/shadow)) return @@ -459,7 +459,7 @@ if(SLIME_ACTIVATE_MAJOR) user.visible_message(span_warning("[user]'s skin starts pulsing and glowing ominously..."), span_userdanger("You feel unstable...")) - if(do_after(user, 60, target = user)) + if(do_after(user, 6 SECONDS, target = user)) to_chat(user, span_userdanger("You explode!")) explosion(user, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 6, explosion_cause = src) user.investigate_log("has been gibbed by an oil slime extract explosion.", INVESTIGATE_DEATHS) @@ -487,7 +487,7 @@ if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_warning("You feel your body rapidly hardening...")) - if(do_after(user, 120, target = user)) + if(do_after(user, 12 SECONDS, target = user)) to_chat(user, span_warning("You feel solid.")) user.set_species(/datum/species/golem) return @@ -511,7 +511,7 @@ switch(activation_type) if(SLIME_ACTIVATE_MINOR) to_chat(user, span_warning("You feel your body vibrating...")) - if(do_after(user, 25, target = user)) + if(do_after(user, 2.5 SECONDS, target = user)) to_chat(user, span_warning("You teleport!")) do_teleport(user, get_turf(user), 6, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) return 300 @@ -598,7 +598,7 @@ if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_warning("You feel time slow down...")) - if(do_after(user, 30, target = user)) + if(do_after(user, 3 SECONDS, target = user)) new /obj/effect/timestop(get_turf(user), 2, 50, list(user)) return 900 @@ -705,10 +705,9 @@ context[SCREENTIP_CONTEXT_ALT_LMB] = "Set potion offer reason" return CONTEXTUAL_SCREENTIP_SET -/obj/item/slimepotion/slime/sentience/AltClick(mob/living/user) - if(!can_interact(user)) - return +/obj/item/slimepotion/slime/sentience/click_alt(mob/living/user) potion_reason = tgui_input_text(user, "Enter reason for offering potion", "Intelligence Potion", potion_reason, multiline = TRUE) + return CLICK_ACTION_SUCCESS /obj/item/slimepotion/slime/sentience/attack(mob/living/dumb_mob, mob/user) if(being_used || !isliving(dumb_mob)) @@ -1082,17 +1081,3 @@ turf_type = /turf/open/floor/sepia merge_type = /obj/item/stack/tile/sepia -/obj/item/areaeditor/blueprints/slime - name = "cerulean prints" - desc = "A one use yet of blueprints made of jelly like organic material. Extends the reach of the management console." - color = "#2956B2" - -/obj/item/areaeditor/blueprints/slime/edit_area() - ..() - var/area/area = get_area(src) - for (var/list/zlevel_turfs as anything in area.get_zlevel_turf_lists()) - for(var/turf/area_turf as anything in zlevel_turfs) - area_turf.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) - area_turf.add_atom_colour("#2956B2", FIXED_COLOUR_PRIORITY) - area.area_flags |= XENOBIOLOGY_COMPATIBLE - qdel(src) diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index e4b2eaa6c2829..dc046d6fa6fb5 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -125,7 +125,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) event = event_type waiting = TRUE GLOB.keycard_events.fireEvent("triggerEvent", src) - addtimer(CALLBACK(src, PROC_REF(eventSent)), 20) + addtimer(CALLBACK(src, PROC_REF(eventSent)), 2 SECONDS) /obj/machinery/keycard_auth/proc/eventSent() triggerer = null @@ -135,7 +135,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) /obj/machinery/keycard_auth/proc/triggerEvent(source) event_source = source update_appearance() - addtimer(CALLBACK(src, PROC_REF(eventTriggered)), 20) + addtimer(CALLBACK(src, PROC_REF(eventTriggered)), 2 SECONDS) /obj/machinery/keycard_auth/proc/eventTriggered() event_source = null diff --git a/code/modules/shuttle/assault_pod.dm b/code/modules/shuttle/assault_pod.dm index b628d7c5d8481..d9a21cf5e2363 100644 --- a/code/modules/shuttle/assault_pod.dm +++ b/code/modules/shuttle/assault_pod.dm @@ -28,6 +28,7 @@ var/width = 7 var/height = 7 var/lz_dir = 1 + var/lzname = "assault_pod" /obj/item/assault_pod/attack_self(mob/living/user) @@ -45,8 +46,8 @@ return var/turf/T = pick(turfs) var/obj/docking_port/stationary/landing_zone = new /obj/docking_port/stationary(T) - landing_zone.shuttle_id = "assault_pod([REF(src)])" - landing_zone.port_destinations = "assault_pod([REF(src)])" + landing_zone.shuttle_id = "[lzname]([REF(src)])" + landing_zone.port_destinations = "[lzname]([REF(src)])" landing_zone.name = "Landing Zone" landing_zone.dwidth = dwidth landing_zone.dheight = dheight @@ -61,3 +62,23 @@ to_chat(user, span_notice("Landing zone set.")) qdel(src) + +/obj/item/assault_pod/medieval //for the medieval pirates + name = "Shuttle placement designator" + icon = 'icons/obj/scrolls.dmi' + icon_state = "blueprints" + inhand_icon_state = null + desc = "A map of the station used to select where you want to land your shuttle." + shuttle_id = "pirate" + dwidth = 1 + dheight = 1 + width = 15 + height = 9 + lzname = "pirate" + +/obj/item/assault_pod/medieval/Initialize(mapload) + . = ..() + var/counter = length(SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/shuttle/pirate)) + if(counter != 1) + shuttle_id = "[shuttle_id]_[counter]" + lzname = "[lzname] [counter]" diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index c93bd5e8c14e0..6ac45f9424d99 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -201,9 +201,11 @@ shuttle.setTimer(shuttle.timeLeft(1) + hijack_flight_time_increase) //give the guy more time to hijack if it's already in flight. return shuttle.hijack_status -/obj/machinery/computer/emergency_shuttle/AltClick(user) - if(isliving(user)) - attempt_hijack_stage(user) +/obj/machinery/computer/emergency_shuttle/click_alt(mob/living/user) + if(!isliving(user)) + return NONE + attempt_hijack_stage(user) + return CLICK_ACTION_SUCCESS /obj/machinery/computer/emergency_shuttle/proc/attempt_hijack_stage(mob/living/user) if(!user.CanReach(src)) @@ -291,13 +293,12 @@ obj_flags |= EMAGGED SSshuttle.emergency.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL - var/datum/species/S = new for(var/i in 1 to 10) // the shuttle system doesn't know who these people are, but they // must be important, surely var/obj/item/card/id/ID = new(src) var/datum/job/J = pick(SSjob.joinable_occupations) - ID.registered_name = S.random_name(pick(MALE, FEMALE)) + ID.registered_name = generate_random_name_species_based(species_type = /datum/species/human) ID.assignment = J.title authorized += ID @@ -819,10 +820,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/pod, 32) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN return ..() -/obj/item/storage/pod/AltClick(mob/user) - if(!can_interact(user)) - return - return ..() +/obj/item/storage/pod/click_alt(mob/user) + return CLICK_ACTION_SUCCESS /obj/item/storage/pod/can_interact(mob/user) if(!..()) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 9b267489100ee..56f99e270a49d 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -115,8 +115,6 @@ All ShuttleMove procs go here if(rotation) shuttleRotate(rotation) - update_parallax_contents() - return TRUE /atom/movable/proc/lateShuttleMove(turf/oldT, list/movement_force, move_dir) diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 2088e8f3234c8..fbe3e52e5030f 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -6,8 +6,8 @@ //NORTH default dir /obj/docking_port invisibility = INVISIBILITY_ABSTRACT - icon = 'icons/obj/devices/tracker.dmi' - icon_state = "pinonfar" + icon = 'icons/effects/docking_ports.dmi' + icon_state = "static" resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF anchored = TRUE @@ -436,7 +436,7 @@ /obj/docking_port/mobile name = "shuttle" - icon_state = "pinonclose" + icon_state = "mobile" area_type = SHUTTLE_DEFAULT_SHUTTLE_AREA_TYPE diff --git a/code/modules/shuttle/spaceship_navigation_beacon.dm b/code/modules/shuttle/spaceship_navigation_beacon.dm index eb613be54def9..41b3f5e39ed9a 100644 --- a/code/modules/shuttle/spaceship_navigation_beacon.dm +++ b/code/modules/shuttle/spaceship_navigation_beacon.dm @@ -5,7 +5,6 @@ icon_state = "beacon_active" base_icon_state = "beacon" density = TRUE - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /// Locked beacons cannot be jumped to by ships. var/locked = FALSE diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index 0617b9696a708..e5b4b0eb02439 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -79,7 +79,6 @@ var/obj/machinery/power/emitter/energycannon/magical/our_statue var/list/mob/living/sleepers = list() var/never_spoken = TRUE - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /obj/structure/table/abductor/wabbajack/Initialize(mapload) . = ..() @@ -89,6 +88,12 @@ STOP_PROCESSING(SSobj, src) . = ..() +/obj/structure/table/abductor/wabbajack/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/table/abductor/wabbajack/wrench_act(mob/living/user, obj/item/tool) + return NONE + /obj/structure/table/abductor/wabbajack/process() if(isnull(our_statue)) our_statue = locate() in orange(4, src) @@ -112,7 +117,7 @@ L.visible_message(span_revennotice("A strange purple glow wraps itself around [L] as [L.p_they()] suddenly fall[L.p_s()] unconscious."), span_revendanger("[desc]")) // Don't let them sit suround unconscious forever - addtimer(CALLBACK(src, PROC_REF(sleeper_dreams), L), 100) + addtimer(CALLBACK(src, PROC_REF(sleeper_dreams), L), 10 SECONDS) // Existing sleepers for(var/i in found) @@ -173,7 +178,6 @@ /obj/structure/table/wood/shuttle_bar resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION max_integrity = 1000 var/boot_dir = 1 @@ -184,6 +188,12 @@ ) AddElement(/datum/element/connect_loc, loc_connections) +/obj/structure/table/wood/shuttle_bar/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/table/wood/shuttle_bar/wrench_act(mob/living/user, obj/item/tool) + return NONE + /obj/structure/table/wood/shuttle_bar/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER var/mob/living/M = AM diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm index f08446b650da3..08e0b0d269950 100644 --- a/code/modules/shuttle/syndicate.dm +++ b/code/modules/shuttle/syndicate.dm @@ -11,7 +11,9 @@ shuttleId = "syndicate" possible_destinations = "syndicate_away;syndicate_z5;syndicate_ne;syndicate_nw;syndicate_n;syndicate_se;syndicate_sw;syndicate_s;syndicate_custom" resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/machinery/computer/shuttle/syndicate/screwdriver_act(mob/living/user, obj/item/I) + return NONE /obj/machinery/computer/shuttle/syndicate/launch_check(mob/user) . = ..() @@ -64,5 +66,6 @@ y_offset = -1 whitelist_turfs = list(/turf/open/space, /turf/open/floor/plating, /turf/open/lava, /turf/closed/mineral, /turf/open/openspace, /turf/open/misc) see_hidden = TRUE + circuit = /obj/item/circuitboard/computer/syndicate_shuttle_docker #undef SYNDICATE_CHALLENGE_TIMER diff --git a/code/modules/spells/spell_types/cone/cone_of_cold.dm b/code/modules/spells/spell_types/cone/cone_of_cold.dm index c60c8613e4e23..9327e2c2fad4f 100644 --- a/code/modules/spells/spell_types/cone/cone_of_cold.dm +++ b/code/modules/spells/spell_types/cone/cone_of_cold.dm @@ -44,7 +44,7 @@ frozen_floor.MakeSlippery(turf_freeze_type, unfreeze_turf_duration, permanent = (unfreeze_turf_duration == INFINITY)) /datum/action/cooldown/spell/cone/staggered/cone_of_cold/do_mob_cone_effect(mob/living/target_mob, atom/caster, level) - if(target_mob.can_block_magic(antimagic_flags) || target_mob == caster) + if(target_mob.can_block_magic(antimagic_flags) || target_mob == caster || HAS_TRAIT(target_mob, TRAIT_RESISTCOLD)) return if(ispath(frozen_status_effect_path) && unfreeze_mob_duration > 0 SECONDS) // 0 duration = don't apply the status effect diff --git a/code/modules/spells/spell_types/jaunt/bloodcrawl.dm b/code/modules/spells/spell_types/jaunt/bloodcrawl.dm index 836bfd98dca43..00327111e8915 100644 --- a/code/modules/spells/spell_types/jaunt/bloodcrawl.dm +++ b/code/modules/spells/spell_types/jaunt/bloodcrawl.dm @@ -162,6 +162,8 @@ they will be consumed by you, fully healing you." /// The sound played when someone's consumed. var/consume_sound = 'sound/magic/demon_consume.ogg' + /// consume count (statistics and stuff) + var/consume_count = 0 /datum/action/cooldown/spell/jaunt/bloodcrawl/slaughter_demon/try_enter_jaunt(obj/effect/decal/cleanable/blood, mob/living/jaunter) // Save this before the actual jaunt @@ -228,6 +230,7 @@ victim.investigate_log("has been killed by being consumed by a slaugter demon.", INVESTIGATE_DEATHS) victim.death() on_victim_consumed(victim, jaunter) + consume_count++ /** * Called when a victim starts to be consumed. diff --git a/code/modules/spells/spell_types/jaunt/shadow_walk.dm b/code/modules/spells/spell_types/jaunt/shadow_walk.dm index c5a47cd1740c4..c869fb19913e8 100644 --- a/code/modules/spells/spell_types/jaunt/shadow_walk.dm +++ b/code/modules/spells/spell_types/jaunt/shadow_walk.dm @@ -45,7 +45,7 @@ exit_jaunt(cast_on) return - playsound(get_turf(owner), 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1) + playsound(get_turf(owner), 'sound/effects/nightmare_poof.ogg', 50, TRUE, -1, ignore_walls = FALSE) cast_on.visible_message(span_boldwarning("[cast_on] melts into the shadows!")) cast_on.SetAllImmobility(0) cast_on.setStaminaLoss(0, FALSE) @@ -107,7 +107,7 @@ reveal_turf.visible_message(span_boldwarning("[jaunter] is revealed by the light!")) else reveal_turf.visible_message(span_boldwarning("[jaunter] emerges from the darkness!")) - playsound(reveal_turf, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1) + playsound(reveal_turf, 'sound/effects/nightmare_reappear.ogg', 50, TRUE, -1, ignore_walls = FALSE) return ..() diff --git a/code/modules/spells/spell_types/right_and_wrong.dm b/code/modules/spells/spell_types/right_and_wrong.dm index 27662943af03a..306770c074f43 100644 --- a/code/modules/spells/spell_types/right_and_wrong.dm +++ b/code/modules/spells/spell_types/right_and_wrong.dm @@ -230,9 +230,12 @@ GLOBAL_LIST_INIT(summoned_magic_objectives, list( SSevents.reschedule() if(user) - to_chat(user, span_warning("You have intensified summon events, causing them to occur more often!")) - message_admins("[ADMIN_LOOKUPFLW(user)] intensified summon events!") - user.log_message("intensified events!", LOG_GAME) + message_admins("[ADMIN_LOOKUPFLW(user)] [ismob(user) ? "":"admin triggered "]intensified summon events!") + if(ismob(user)) + to_chat(user, span_warning("You have intensified summon events, causing them to occur more often!")) + user.log_message("intensified events!", LOG_GAME) + else //admin triggered + log_admin("[key_name(user)] intensified summon events.") else log_game("Summon Events was intensified!") @@ -245,9 +248,12 @@ GLOBAL_LIST_INIT(summoned_magic_objectives, list( SSevents.toggleWizardmode() SSevents.reschedule() if(user) - to_chat(user, span_warning("You have cast summon events!")) - message_admins("[ADMIN_LOOKUPFLW(user)] summoned events!") - user.log_message("summoned events!", LOG_GAME) + message_admins("[ADMIN_LOOKUPFLW(user)] [ismob(user) ? "summoned":"admin triggered summon"] events!") + if(ismob(user)) + to_chat(user, span_warning("You have cast summon events!")) + user.log_message("summoned events!", LOG_GAME) + else //admin triggered + log_admin("[key_name(user)] summoned events.") else message_admins("Summon Events was triggered!") log_game("Summon Events was triggered!") diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index db5a5e09761b9..c83f710d1df1d 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -258,7 +258,7 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE) /obj/machinery/bsa/full/proc/reload() ready = FALSE use_energy(power_used_per_shot) - addtimer(CALLBACK(src,"ready_cannon"),600) + addtimer(CALLBACK(src,"ready_cannon"), 1 MINUTES) /obj/machinery/bsa/full/proc/ready_cannon() ready = TRUE diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm index 8c8924cdcab50..c4dc91810c14f 100644 --- a/code/modules/surgery/amputation.dm +++ b/code/modules/surgery/amputation.dm @@ -43,9 +43,9 @@ display_results( user, target, - span_notice("You begin to sever [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to sever [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] begins to sever [target]'s [parse_zone(target_zone)]!"), + span_notice("You begin to sever [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to sever [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_notice("[user] begins to sever [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) display_pain(target, "You feel a gruesome pain in your [parse_zone(target_zone)]'s joint!") @@ -54,11 +54,11 @@ display_results( user, target, - span_notice("You sever [target]'s [parse_zone(target_zone)]."), - span_notice("[user] severs [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] severs [target]'s [parse_zone(target_zone)]!"), + span_notice("You sever [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] severs [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_notice("[user] severs [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) - display_pain(target, "You can no longer feel your severed [parse_zone(target_zone)]!") + display_pain(target, "You can no longer feel your severed [target.parse_zone_with_bodypart(target_zone)]!") if(HAS_MIND_TRAIT(user, TRAIT_MORBID) && ishuman(user)) var/mob/living/carbon/human/morbid_weirdo = user diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 58e91646c0fee..07cb1fdd752c0 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -165,8 +165,8 @@ /// Type of an attack from this limb does. Arms will do punches, Legs for kicks, and head for bites. (TO ADD: tactical chestbumps) var/attack_type = BRUTE - /// the verb used for an unarmed attack when using this limb, such as arm.unarmed_attack_verb = punch - var/unarmed_attack_verb = "bump" + /// the verbs used for an unarmed attack when using this limb, such as arm.unarmed_attack_verbs = list("punch") + var/list/unarmed_attack_verbs = list("bump") /// if we have a special attack verb for hitting someone who is grappled by us, it goes here. var/grappled_attack_verb /// what visual effect is used when this limb is used to strike someone. @@ -180,8 +180,6 @@ var/unarmed_damage_high = 1 ///Determines the accuracy bonus, armor penetration and knockdown probability. var/unarmed_effectiveness = 10 - /// How many pixels this bodypart will offset the top half of the mob, used for abnormally sized torsos and legs - var/top_offset = 0 /// Traits that are given to the holder of the part. If you want an effect that changes this, don't add directly to this. Use the add_bodypart_trait() proc var/list/bodypart_traits = list() @@ -344,13 +342,13 @@ for(var/datum/wound/wound as anything in wounds) switch(wound.severity) if(WOUND_SEVERITY_TRIVIAL) - check_list += "\t [span_danger("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)].")]" + check_list += "\t [span_danger("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)].")]" if(WOUND_SEVERITY_MODERATE) - check_list += "\t [span_warning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!")]" + check_list += "\t [span_warning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!")]" if(WOUND_SEVERITY_SEVERE) - check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!!")]" + check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!!")]" if(WOUND_SEVERITY_CRITICAL) - check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!!!")]" + check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!!!")]" for(var/obj/item/embedded_thing in embedded_objects) var/stuck_word = embedded_thing.isEmbedHarmless() ? "stuck" : "embedded" @@ -393,7 +391,7 @@ playsound(loc, 'sound/weapons/slice.ogg', 50, TRUE, -1) user.visible_message(span_warning("[user] begins to cut open [src]."),\ span_notice("You begin to cut open [src]...")) - if(do_after(user, 54, target = src)) + if(do_after(user, 5.4 SECONDS, target = src)) drop_organs(user, TRUE) else return ..() @@ -748,14 +746,14 @@ if(owner == new_owner) return FALSE //`null` is a valid option, so we need to use a num var to make it clear no change was made. - SEND_SIGNAL(src, COMSIG_BODYPART_CHANGED_OWNER, new_owner, owner) - if(owner) . = owner //return value is old owner clear_ownership(owner) if(new_owner) apply_ownership(new_owner) + SEND_SIGNAL(src, COMSIG_BODYPART_CHANGED_OWNER, new_owner, owner) + refresh_bleed_rate() return . @@ -1085,10 +1083,11 @@ bodypart_overlays -= overlay overlay.removed_from_limb(src) -/obj/item/bodypart/deconstruct(disassembled = TRUE) +/obj/item/bodypart/atom_deconstruct(disassembled = TRUE) SHOULD_CALL_PARENT(TRUE) drop_organs() + return ..() /// INTERNAL PROC, DO NOT USE diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 03f4cc98e1401..e0d74a7169451 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -373,7 +373,7 @@ /mob/living/carbon/proc/regenerate_limbs(list/excluded_zones = list()) SEND_SIGNAL(src, COMSIG_CARBON_REGENERATE_LIMBS, excluded_zones) - var/list/zone_list = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + var/list/zone_list = GLOB.all_body_zones.Copy() var/list/dismembered_by_copy = body_zone_dismembered_by?.Copy() diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 2a1c0cdc9d408..1cc06471f2832 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -17,7 +17,7 @@ scars_covered_by_clothes = FALSE grind_results = null is_dimorphic = TRUE - unarmed_attack_verb = "bite" + unarmed_attack_verbs = list("bite", "chomp") unarmed_attack_effect = ATTACK_EFFECT_BITE unarmed_attack_sound = 'sound/weapons/bite.ogg' unarmed_miss_sound = 'sound/weapons/bite.ogg' diff --git a/code/modules/surgery/bodyparts/head_hair_and_lips.dm b/code/modules/surgery/bodyparts/head_hair_and_lips.dm index 7b3ec6ff18821..453bd79ee22e9 100644 --- a/code/modules/surgery/bodyparts/head_hair_and_lips.dm +++ b/code/modules/surgery/bodyparts/head_hair_and_lips.dm @@ -9,25 +9,10 @@ hair_hidden = FALSE facial_hair_hidden = FALSE if(human_head_owner) - if(human_head_owner.head) - var/obj/item/hat = human_head_owner.head - if(hat.flags_inv & HIDEHAIR) + for(var/obj/item/worn_item in human_head_owner.get_equipped_items()) + if(worn_item.flags_inv & HIDEHAIR) hair_hidden = TRUE - if(hat.flags_inv & HIDEFACIALHAIR) - facial_hair_hidden = TRUE - - if(human_head_owner.wear_mask) - var/obj/item/mask = human_head_owner.wear_mask - if(mask.flags_inv & HIDEHAIR) - hair_hidden = TRUE - if(mask.flags_inv & HIDEFACIALHAIR) - facial_hair_hidden = TRUE - - if(human_head_owner.w_uniform) - var/obj/item/item_uniform = human_head_owner.w_uniform - if(item_uniform.flags_inv & HIDEHAIR) - hair_hidden = TRUE - if(item_uniform.flags_inv & HIDEFACIALHAIR) + if(worn_item.flags_inv & HIDEFACIALHAIR) facial_hair_hidden = TRUE //invisibility and husk stuff if(HAS_TRAIT(human_head_owner, TRAIT_INVISIBLE_MAN) || HAS_TRAIT(human_head_owner, TRAIT_HUSK)) @@ -99,7 +84,7 @@ var/image/facial_hair_overlay if(!facial_hair_hidden && facial_hairstyle && (head_flags & HEAD_FACIAL_HAIR)) - sprite_accessory = GLOB.facial_hairstyles_list[facial_hairstyle] + sprite_accessory = SSaccessories.facial_hairstyles_list[facial_hairstyle] if(sprite_accessory) //Overlay facial_hair_overlay = image(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER, image_dir) @@ -114,12 +99,12 @@ var/facial_hair_gradient_style = LAZYACCESS(gradient_styles, GRADIENT_FACIAL_HAIR_KEY) if(facial_hair_gradient_style) var/facial_hair_gradient_color = LAZYACCESS(gradient_colors, GRADIENT_FACIAL_HAIR_KEY) - var/image/facial_hair_gradient_overlay = get_gradient_overlay(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER, GLOB.facial_hair_gradients_list[facial_hair_gradient_style], facial_hair_gradient_color, image_dir) + var/image/facial_hair_gradient_overlay = get_gradient_overlay(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER, SSaccessories.facial_hair_gradients_list[facial_hair_gradient_style], facial_hair_gradient_color, image_dir) . += facial_hair_gradient_overlay var/image/hair_overlay if(!(show_debrained && (head_flags & HEAD_DEBRAIN)) && !hair_hidden && hairstyle && (head_flags & HEAD_HAIR)) - var/datum/sprite_accessory/hair/hair_sprite_accessory = GLOB.hairstyles_list[hairstyle] + var/datum/sprite_accessory/hair/hair_sprite_accessory = SSaccessories.hairstyles_list[hairstyle] if(hair_sprite_accessory) //Overlay hair_overlay = image(hair_sprite_accessory.icon, hair_sprite_accessory.icon_state, -HAIR_LAYER, image_dir) @@ -135,7 +120,7 @@ var/hair_gradient_style = LAZYACCESS(gradient_styles, GRADIENT_HAIR_KEY) if(hair_gradient_style) var/hair_gradient_color = LAZYACCESS(gradient_colors, GRADIENT_HAIR_KEY) - var/image/hair_gradient_overlay = get_gradient_overlay(hair_sprite_accessory.icon, hair_sprite_accessory.icon_state, -HAIR_LAYER, GLOB.hair_gradients_list[hair_gradient_style], hair_gradient_color, image_dir) + var/image/hair_gradient_overlay = get_gradient_overlay(hair_sprite_accessory.icon, hair_sprite_accessory.icon_state, -HAIR_LAYER, SSaccessories.hair_gradients_list[hair_gradient_style], hair_gradient_color, image_dir) hair_gradient_overlay.pixel_y = hair_sprite_accessory.y_offset . += hair_gradient_overlay diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 126bd3db33a4f..fb0647d0fb504 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -83,7 +83,7 @@ /mob/living/carbon/proc/get_missing_limbs() RETURN_TYPE(/list) - var/list/full = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + var/list/full = GLOB.all_body_zones.Copy() for(var/zone in full) if(get_bodypart(zone)) full -= zone @@ -100,7 +100,7 @@ return list() /mob/living/carbon/get_disabled_limbs() - var/list/full = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + var/list/full = GLOB.all_body_zones.Copy() var/list/disabled = list() for(var/zone in full) var/obj/item/bodypart/affecting = get_bodypart(zone) diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 22450ca793d7b..03f53c962d59f 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -83,7 +83,6 @@ icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi' icon_husk = 'icons/mob/human/species/monkey/bodyparts.dmi' husk_type = "monkey" - top_offset = -5 icon_state = "default_monkey_chest" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE @@ -130,7 +129,7 @@ aux_layer = BODYPARTS_HIGH_LAYER body_damage_coeff = LIMB_BODY_DAMAGE_COEFFICIENT_DEFAULT can_be_disabled = TRUE - unarmed_attack_verb = "punch" /// The classic punch, wonderfully classic and completely random + unarmed_attack_verbs = list("punch") /// The classic punch, wonderfully classic and completely random grappled_attack_verb = "pummel" unarmed_damage_low = 5 unarmed_damage_high = 10 @@ -391,7 +390,7 @@ can_be_disabled = TRUE unarmed_attack_effect = ATTACK_EFFECT_KICK body_zone = BODY_ZONE_L_LEG - unarmed_attack_verb = "kick" // The lovely kick, typically only accessable by attacking a grouded foe. 1.5 times better than the punch. + unarmed_attack_verbs = list("kick") // The lovely kick, typically only accessable by attacking a grouded foe. 1.5 times better than the punch. unarmed_damage_low = 7 unarmed_damage_high = 15 unarmed_effectiveness = 15 @@ -467,7 +466,6 @@ icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi' icon_husk = 'icons/mob/human/species/monkey/bodyparts.dmi' husk_type = "monkey" - top_offset = -3 icon_state = "default_monkey_l_leg" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE @@ -558,7 +556,6 @@ icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi' icon_husk = 'icons/mob/human/species/monkey/bodyparts.dmi' husk_type = "monkey" - top_offset = -3 icon_state = "default_monkey_r_leg" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE @@ -584,15 +581,3 @@ can_be_disabled = FALSE max_damage = LIMB_MAX_HP_ALIEN_LIMBS should_draw_greyscale = FALSE - -/obj/item/bodypart/leg/right/tallboy - limb_id = SPECIES_TALLBOY - top_offset = 23 - unarmed_damage_low = 30 - unarmed_damage_low = 50 - -/obj/item/bodypart/leg/left/tallboy - limb_id = SPECIES_TALLBOY - top_offset = 23 - unarmed_damage_low = 30 - unarmed_damage_low = 50 diff --git a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm index 3eeafa6f4e1a8..20e4b58660795 100644 --- a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm @@ -36,7 +36,7 @@ limb_id = SPECIES_ETHEREAL dmg_overlay_type = null attack_type = BURN //burn bish - unarmed_attack_verb = "burn" + unarmed_attack_verbs = list("burn", "sear") grappled_attack_verb = "scorch" unarmed_attack_sound = 'sound/weapons/etherealhit.ogg' unarmed_miss_sound = 'sound/weapons/etherealmiss.ogg' @@ -54,7 +54,7 @@ limb_id = SPECIES_ETHEREAL dmg_overlay_type = null attack_type = BURN // bish buzz - unarmed_attack_verb = "burn" + unarmed_attack_verbs = list("burn", "sear") grappled_attack_verb = "scorch" unarmed_attack_sound = 'sound/weapons/etherealhit.ogg' unarmed_miss_sound = 'sound/weapons/etherealmiss.ogg' diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index e6fffe1e6f91b..30e91db21373a 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -16,7 +16,7 @@ /obj/item/bodypart/arm/left/lizard icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = SPECIES_LIZARD - unarmed_attack_verb = "slash" + unarmed_attack_verbs = list("slash", "scratch", "claw") grappled_attack_verb = "lacerate" unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slash.ogg' @@ -25,7 +25,7 @@ /obj/item/bodypart/arm/right/lizard icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = SPECIES_LIZARD - unarmed_attack_verb = "slash" + unarmed_attack_verbs = list("slash", "scratch", "claw") grappled_attack_verb = "lacerate" unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slash.ogg' diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index cc61393193ae8..2730bc362c72c 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -15,7 +15,7 @@ /obj/item/bodypart/arm/left/snail limb_id = SPECIES_SNAIL - unarmed_attack_verb = "slap" + unarmed_attack_verbs = list("slap") unarmed_attack_effect = ATTACK_EFFECT_DISARM unarmed_damage_low = 1 unarmed_damage_high = 2 //snails are soft and squishy @@ -24,7 +24,7 @@ /obj/item/bodypart/arm/right/snail limb_id = SPECIES_SNAIL - unarmed_attack_verb = "slap" + unarmed_attack_verbs = list("slap") unarmed_attack_effect = ATTACK_EFFECT_DISARM unarmed_damage_low = 1 unarmed_damage_high = 2 //snails are soft and squishy @@ -36,7 +36,6 @@ unarmed_damage_low = 1 unarmed_damage_high = 2 //snails are soft and squishy burn_modifier = 2 - speed_modifier = 3 //disgustingly slow biological_state = (BIO_FLESH|BIO_BLOODED) /obj/item/bodypart/leg/right/snail @@ -44,7 +43,6 @@ unarmed_damage_low = 1 unarmed_damage_high = 2 //snails are soft and squishy burn_modifier = 2 - speed_modifier = 3 //disgustingly slow biological_state = (BIO_FLESH|BIO_BLOODED) ///ABDUCTOR @@ -222,7 +220,7 @@ /obj/item/bodypart/arm/left/pod limb_id = SPECIES_PODPERSON - unarmed_attack_verb = "slash" + unarmed_attack_verbs = list("slash", "lash") grappled_attack_verb = "lacerate" unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slice.ogg' @@ -231,7 +229,7 @@ /obj/item/bodypart/arm/right/pod limb_id = SPECIES_PODPERSON - unarmed_attack_verb = "slash" + unarmed_attack_verbs = list("slash", "lash") grappled_attack_verb = "lacerate" unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slice.ogg' @@ -584,38 +582,34 @@ limb_id = BODYPART_ID_MEAT should_draw_greyscale = FALSE -/obj/item/bodypart/arm/left/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) +/obj/item/bodypart/arm/left/flesh/Initialize(mapload) . = ..() - if(!dont_spawn_flesh) - new /mob/living/basic/living_limb_flesh(src, src) ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + AddElement(/datum/element/living_limb_initialiser) /obj/item/bodypart/arm/right/flesh limb_id = BODYPART_ID_MEAT should_draw_greyscale = FALSE -/obj/item/bodypart/arm/right/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) +/obj/item/bodypart/arm/right/flesh/Initialize(mapload) . = ..() - if(!dont_spawn_flesh) - new /mob/living/basic/living_limb_flesh(src, src) ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + AddElement(/datum/element/living_limb_initialiser) /obj/item/bodypart/leg/left/flesh limb_id = BODYPART_ID_MEAT should_draw_greyscale = FALSE -/obj/item/bodypart/leg/left/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) +/obj/item/bodypart/leg/left/flesh/Initialize(mapload) . = ..() - if(!dont_spawn_flesh) - new /mob/living/basic/living_limb_flesh(src, src) ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + AddElement(/datum/element/living_limb_initialiser) /obj/item/bodypart/leg/right/flesh limb_id = BODYPART_ID_MEAT should_draw_greyscale = FALSE -/obj/item/bodypart/leg/right/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) +/obj/item/bodypart/leg/right/flesh/Initialize(mapload) . = ..() - if(!dont_spawn_flesh) - new /mob/living/basic/living_limb_flesh(src, src) ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + AddElement(/datum/element/living_limb_initialiser) diff --git a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm index be8d601b1fb58..011ee83368a63 100644 --- a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm @@ -25,7 +25,7 @@ icon_static = 'icons/mob/human/species/moth/bodyparts.dmi' limb_id = SPECIES_MOTH should_draw_greyscale = FALSE - unarmed_attack_verb = "slash" + unarmed_attack_verbs = list("slash") grappled_attack_verb = "lacerate" unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slash.ogg' @@ -37,7 +37,7 @@ icon_static = 'icons/mob/human/species/moth/bodyparts.dmi' limb_id = SPECIES_MOTH should_draw_greyscale = FALSE - unarmed_attack_verb = "slash" + unarmed_attack_verbs = list("slash") grappled_attack_verb = "lacerate" unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slash.ogg' diff --git a/code/modules/surgery/bodyparts/wounds.dm b/code/modules/surgery/bodyparts/wounds.dm index 1fc16c7ca8f8d..93d61b091d9c0 100644 --- a/code/modules/surgery/bodyparts/wounds.dm +++ b/code/modules/surgery/bodyparts/wounds.dm @@ -317,7 +317,7 @@ dam_mul *= iter_wound.damage_multiplier_penalty if(!LAZYLEN(wounds) && current_gauze && !replaced) // no more wounds = no need for the gauze anymore - owner.visible_message(span_notice("\The [current_gauze.name] on [owner]'s [name] falls away."), span_notice("The [current_gauze.name] on your [parse_zone(body_zone)] falls away.")) + owner.visible_message(span_notice("\The [current_gauze.name] on [owner]'s [name] falls away."), span_notice("The [current_gauze.name] on your [plaintext_zone] falls away.")) QDEL_NULL(current_gauze) wound_damage_multiplier = dam_mul diff --git a/code/modules/surgery/bone_mending.dm b/code/modules/surgery/bone_mending.dm index 87fc3db0af2c4..73fdcba3fce6b 100644 --- a/code/modules/surgery/bone_mending.dm +++ b/code/modules/surgery/bone_mending.dm @@ -48,7 +48,7 @@ /datum/surgery_step/repair_bone_hairline name = "repair hairline fracture (bonesetter/bone gel/tape)" implements = list( - /obj/item/bonesetter = 100, + TOOL_BONESET = 100, /obj/item/stack/medical/bone_gel = 100, /obj/item/stack/sticky_tape/surgical = 100, /obj/item/stack/sticky_tape/super = 50, @@ -60,13 +60,13 @@ display_results( user, target, - span_notice("You begin to repair the fracture in [target]'s [parse_zone(user.zone_selected)]..."), - span_notice("[user] begins to repair the fracture in [target]'s [parse_zone(user.zone_selected)] with [tool]."), - span_notice("[user] begins to repair the fracture in [target]'s [parse_zone(user.zone_selected)]."), + span_notice("You begin to repair the fracture in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."), + span_notice("[user] begins to repair the fracture in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."), + span_notice("[user] begins to repair the fracture in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), ) - display_pain(target, "Your [parse_zone(user.zone_selected)] aches with pain!") + display_pain(target, "Your [target.parse_zone_with_bodypart(user.zone_selected)] aches with pain!") else - user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]...")) + user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]...")) /datum/surgery_step/repair_bone_hairline/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) if(surgery.operated_wound) @@ -76,9 +76,9 @@ display_results( user, target, - span_notice("You successfully repair the fracture in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] successfully repairs the fracture in [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully repairs the fracture in [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully repair the fracture in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] successfully repairs the fracture in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully repairs the fracture in [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) log_combat(user, target, "repaired a hairline fracture in", addition="COMBAT_MODE: [uppertext(user.combat_mode)]") qdel(surgery.operated_wound) @@ -98,7 +98,7 @@ /datum/surgery_step/reset_compound_fracture name = "reset bone (bonesetter)" implements = list( - /obj/item/bonesetter = 100, + TOOL_BONESET = 100, /obj/item/stack/sticky_tape/surgical = 60, /obj/item/stack/sticky_tape/super = 40, /obj/item/stack/sticky_tape = 20) @@ -109,13 +109,13 @@ display_results( user, target, - span_notice("You begin to reset the bone in [target]'s [parse_zone(user.zone_selected)]..."), - span_notice("[user] begins to reset the bone in [target]'s [parse_zone(user.zone_selected)] with [tool]."), - span_notice("[user] begins to reset the bone in [target]'s [parse_zone(user.zone_selected)]."), + span_notice("You begin to reset the bone in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."), + span_notice("[user] begins to reset the bone in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."), + span_notice("[user] begins to reset the bone in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), ) - display_pain(target, "The aching pain in your [parse_zone(user.zone_selected)] is overwhelming!") + display_pain(target, "The aching pain in your [target.parse_zone_with_bodypart(user.zone_selected)] is overwhelming!") else - user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]...")) + user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]...")) /datum/surgery_step/reset_compound_fracture/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) if(surgery.operated_wound) @@ -125,9 +125,9 @@ display_results( user, target, - span_notice("You successfully reset the bone in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] successfully resets the bone in [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully resets the bone in [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully reset the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] successfully resets the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully resets the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) log_combat(user, target, "reset a compound fracture in", addition="COMBAT MODE: [uppertext(user.combat_mode)]") else @@ -159,13 +159,13 @@ display_results( user, target, - span_notice("You begin to repair the fracture in [target]'s [parse_zone(user.zone_selected)]..."), - span_notice("[user] begins to repair the fracture in [target]'s [parse_zone(user.zone_selected)] with [tool]."), - span_notice("[user] begins to repair the fracture in [target]'s [parse_zone(user.zone_selected)]."), + span_notice("You begin to repair the fracture in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."), + span_notice("[user] begins to repair the fracture in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."), + span_notice("[user] begins to repair the fracture in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), ) - display_pain(target, "The aching pain in your [parse_zone(user.zone_selected)] is overwhelming!") + display_pain(target, "The aching pain in your [target.parse_zone_with_bodypart(user.zone_selected)] is overwhelming!") else - user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]...")) + user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]...")) /datum/surgery_step/repair_bone_compound/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) if(surgery.operated_wound) @@ -175,9 +175,9 @@ display_results( user, target, - span_notice("You successfully repair the fracture in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] successfully repairs the fracture in [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully repairs the fracture in [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully repair the fracture in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] successfully repairs the fracture in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully repairs the fracture in [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) log_combat(user, target, "repaired a compound fracture in", addition="COMBAT MODE: [uppertext(user.combat_mode)]") qdel(surgery.operated_wound) @@ -218,9 +218,9 @@ display_results( user, target, - span_notice("You begin to discard the smaller skull debris in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to discard the smaller skull debris in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to poke around in [target]'s [parse_zone(target_zone)]..."), + span_notice("You begin to discard the smaller skull debris in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to discard the smaller skull debris in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to poke around in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), ) display_pain(target, "Your brain feels like it's getting stabbed by little shards of glass!") diff --git a/code/modules/surgery/burn_dressing.dm b/code/modules/surgery/burn_dressing.dm index 61be9056f6c18..cde9b7b29807c 100644 --- a/code/modules/surgery/burn_dressing.dm +++ b/code/modules/surgery/burn_dressing.dm @@ -72,20 +72,20 @@ if(surgery.operated_wound) var/datum/wound/burn/flesh/burn_wound = surgery.operated_wound if(burn_wound.infestation <= 0) - to_chat(user, span_notice("[target]'s [parse_zone(user.zone_selected)] has no infected flesh to remove!")) + to_chat(user, span_notice("[target]'s [target.parse_zone_with_bodypart(user.zone_selected)] has no infected flesh to remove!")) surgery.status++ repeatable = FALSE return display_results( user, target, - span_notice("You begin to excise infected flesh from [target]'s [parse_zone(user.zone_selected)]..."), - span_notice("[user] begins to excise infected flesh from [target]'s [parse_zone(user.zone_selected)] with [tool]."), - span_notice("[user] begins to excise infected flesh from [target]'s [parse_zone(user.zone_selected)]."), + span_notice("You begin to excise infected flesh from [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."), + span_notice("[user] begins to excise infected flesh from [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."), + span_notice("[user] begins to excise infected flesh from [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), ) - display_pain(target, "The infection in your [parse_zone(user.zone_selected)] stings like hell! It feels like you're being stabbed!") + display_pain(target, "The infection in your [target.parse_zone_with_bodypart(user.zone_selected)] stings like hell! It feels like you're being stabbed!") else - user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]...")) + user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]...")) /datum/surgery_step/debride/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) var/datum/wound/burn/flesh/burn_wound = surgery.operated_wound @@ -94,9 +94,9 @@ display_results( user, target, - span_notice("You successfully excise some of the infected flesh from [target]'s [parse_zone(target_zone)][progress_text]."), - span_notice("[user] successfully excises some of the infected flesh from [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully excises some of the infected flesh from [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully excise some of the infected flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)][progress_text]."), + span_notice("[user] successfully excises some of the infected flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully excises some of the infected flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) log_combat(user, target, "excised infected flesh in", addition="COMBAT MODE: [uppertext(user.combat_mode)]") surgery.operated_bodypart.receive_damage(brute=3, wound_bonus=CANT_WOUND) @@ -113,9 +113,9 @@ display_results( user, target, - span_notice("You carve away some of the healthy flesh from [target]'s [parse_zone(target_zone)]."), - span_notice("[user] carves away some of the healthy flesh from [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] carves away some of the healthy flesh from [target]'s [parse_zone(target_zone)]!"), + span_notice("You carve away some of the healthy flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] carves away some of the healthy flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] carves away some of the healthy flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) surgery.operated_bodypart.receive_damage(brute=rand(4,8), sharpness=TRUE) @@ -146,13 +146,13 @@ display_results( user, target, - span_notice("You begin to dress the burns on [target]'s [parse_zone(user.zone_selected)]..."), - span_notice("[user] begins to dress the burns on [target]'s [parse_zone(user.zone_selected)] with [tool]."), - span_notice("[user] begins to dress the burns on [target]'s [parse_zone(user.zone_selected)]."), + span_notice("You begin to dress the burns on [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."), + span_notice("[user] begins to dress the burns on [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."), + span_notice("[user] begins to dress the burns on [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), ) - display_pain(target, "The burns on your [parse_zone(user.zone_selected)] sting like hell!") + display_pain(target, "The burns on your [target.parse_zone_with_bodypart(user.zone_selected)] sting like hell!") else - user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]...")) + user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]...")) /datum/surgery_step/dress/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) var/datum/wound/burn/flesh/burn_wound = surgery.operated_wound @@ -160,9 +160,9 @@ display_results( user, target, - span_notice("You successfully wrap [target]'s [parse_zone(target_zone)] with [tool]."), - span_notice("[user] successfully wraps [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully wraps [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully wrap [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]."), + span_notice("[user] successfully wraps [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully wraps [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) log_combat(user, target, "dressed burns in", addition="COMBAT MODE: [uppertext(user.combat_mode)]") burn_wound.sanitization += sanitization_added diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index dc28e5da5769b..0d583d09a11b0 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -15,11 +15,11 @@ display_results( user, target, - span_notice("You begin to wedge [tool] in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to wedge \the [tool] in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to wedge something in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to wedge [tool] in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to wedge \the [tool] in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to wedge something in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "Something's being jammed into your [parse_zone(target_zone)]!") + display_pain(target, "Something's being jammed into your [target.parse_zone_with_bodypart(target_zone)]!") /datum/surgery_step/insert_pill/success(mob/user, mob/living/carbon/target, target_zone, obj/item/reagent_containers/pill/tool, datum/surgery/surgery, default_display_results = FALSE) if(!istype(tool)) @@ -36,9 +36,9 @@ display_results( user, target, - span_notice("You wedge [tool] into [target]'s [parse_zone(target_zone)]."), - span_notice("[user] wedges \the [tool] into [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] wedges something into [target]'s [parse_zone(target_zone)]!"), + span_notice("You wedge [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] wedges \the [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_notice("[user] wedges something into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) return ..() diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm index a2b9eb33cbf06..66eaf6faf737f 100644 --- a/code/modules/surgery/implant_removal.dm +++ b/code/modules/surgery/implant_removal.dm @@ -56,6 +56,9 @@ display_pain(target, "You can feel your [implant.name] pulled out of you!") implant.removed(target) + if (QDELETED(implant)) + return ..() + var/obj/item/implantcase/case for(var/obj/item/implantcase/implant_case in user.held_items) case = implant_case diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 28a2443600bbe..5276111e56727 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -24,20 +24,20 @@ to_chat(user, span_warning("That's not an augment, silly!")) return SURGERY_STEP_FAIL if(aug.body_zone != target_zone) - to_chat(user, span_warning("[tool] isn't the right type for [parse_zone(target_zone)].")) + to_chat(user, span_warning("[tool] isn't the right type for [target.parse_zone_with_bodypart(target_zone)].")) return SURGERY_STEP_FAIL target_limb = surgery.operated_bodypart if(target_limb) display_results( user, target, - span_notice("You begin to augment [target]'s [parse_zone(user.zone_selected)]..."), - span_notice("[user] begins to augment [target]'s [parse_zone(user.zone_selected)] with [aug]."), - span_notice("[user] begins to augment [target]'s [parse_zone(user.zone_selected)]."), + span_notice("You begin to augment [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."), + span_notice("[user] begins to augment [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [aug]."), + span_notice("[user] begins to augment [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), ) - display_pain(target, "You feel a horrible pain in your [parse_zone(user.zone_selected)]!") + display_pain(target, "You feel a horrible pain in your [target.parse_zone_with_bodypart(user.zone_selected)]!") else - user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]...")) + user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]...")) //ACTUAL SURGERIES @@ -74,9 +74,9 @@ display_results( user, target, - span_warning("You fail in replacing [target]'s [parse_zone(target_zone)]! Their body has rejected [tool]!"), - span_warning("[user] fails to replace [target]'s [parse_zone(target_zone)]!"), - span_warning("[user] fails to replaces [target]'s [parse_zone(target_zone)]!"), + span_warning("You fail in replacing [target]'s [target.parse_zone_with_bodypart(target_zone)]! Their body has rejected [tool]!"), + span_warning("[user] fails to replace [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_warning("[user] fails to replaces [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) tool.forceMove(target.loc) return @@ -85,12 +85,12 @@ display_results( user, target, - span_notice("You successfully augment [target]'s [parse_zone(target_zone)]."), - span_notice("[user] successfully augments [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully augments [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully augment [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] successfully augments [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully augments [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) - display_pain(target, "Your [parse_zone(target_zone)] comes awash with synthetic sensation!", mechanical_surgery = TRUE) - log_combat(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] COMBAT MODE: [uppertext(user.combat_mode)]") + display_pain(target, "Your [target.parse_zone_with_bodypart(target_zone)] comes awash with synthetic sensation!", mechanical_surgery = TRUE) + log_combat(user, target, "augmented", addition="by giving him new [target.parse_zone_with_bodypart(target_zone)] COMBAT MODE: [uppertext(user.combat_mode)]") else - to_chat(user, span_warning("[target] has no organic [parse_zone(target_zone)] there!")) + to_chat(user, span_warning("[target] has no organic [target.parse_zone_with_bodypart(target_zone)] there!")) return ..() diff --git a/code/modules/surgery/mechanic_steps.dm b/code/modules/surgery/mechanic_steps.dm index bb07fb72dedf5..309090a03cae0 100644 --- a/code/modules/surgery/mechanic_steps.dm +++ b/code/modules/surgery/mechanic_steps.dm @@ -14,11 +14,11 @@ display_results( user, target, - span_notice("You begin to unscrew the shell of [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to unscrew the shell of [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to unscrew the shell of [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to unscrew the shell of [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You can feel your [parse_zone(target_zone)] grow numb as the sensory panel is unscrewed.", TRUE) + display_pain(target, "You can feel your [target.parse_zone_with_bodypart(target_zone)] grow numb as the sensory panel is unscrewed.", TRUE) /datum/surgery_step/mechanic_open/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.get_sharpness()) @@ -44,11 +44,11 @@ display_results( user, target, - span_notice("You begin to screw the shell of [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to screw the shell of [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to screw the shell of [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to screw the shell of [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to screw the shell of [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to screw the shell of [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel the faint pricks of sensation return as your [parse_zone(target_zone)]'s panel is screwed in.", TRUE) + display_pain(target, "You feel the faint pricks of sensation return as your [target.parse_zone_with_bodypart(target_zone)]'s panel is screwed in.", TRUE) /datum/surgery_step/mechanic_close/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.get_sharpness()) @@ -72,11 +72,11 @@ display_results( user, target, - span_notice("You begin to prepare electronics in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to prepare electronics in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to prepare electronics in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to prepare electronics in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You can feel a faint buzz in your [parse_zone(target_zone)] as the electronics reboot.", TRUE) + display_pain(target, "You can feel a faint buzz in your [target.parse_zone_with_bodypart(target_zone)] as the electronics reboot.", TRUE) //unwrench /datum/surgery_step/mechanic_unwrench @@ -91,11 +91,11 @@ display_results( user, target, - span_notice("You begin to unwrench some bolts in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to unwrench some bolts in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to unwrench some bolts in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to unwrench some bolts in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel a jostle in your [parse_zone(target_zone)] as the bolts begin to loosen.", TRUE) + display_pain(target, "You feel a jostle in your [target.parse_zone_with_bodypart(target_zone)] as the bolts begin to loosen.", TRUE) /datum/surgery_step/mechanic_unwrench/tool_check(mob/user, obj/item/tool) if(tool.usesound) @@ -116,11 +116,11 @@ display_results( user, target, - span_notice("You begin to wrench some bolts in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to wrench some bolts in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to wrench some bolts in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to wrench some bolts in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel a jostle in your [parse_zone(target_zone)] as the bolts begin to tighten.", TRUE) + display_pain(target, "You feel a jostle in your [target.parse_zone_with_bodypart(target_zone)] as the bolts begin to tighten.", TRUE) /datum/surgery_step/mechanic_wrench/tool_check(mob/user, obj/item/tool) if(tool.usesound) @@ -140,11 +140,11 @@ display_results( user, target, - span_notice("You begin to open the hatch holders in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to open the hatch holders in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to open the hatch holders in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to open the hatch holders in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "The last faint pricks of tactile sensation fade from your [parse_zone(target_zone)] as the hatch is opened.", TRUE) + display_pain(target, "The last faint pricks of tactile sensation fade from your [target.parse_zone_with_bodypart(target_zone)] as the hatch is opened.", TRUE) /datum/surgery_step/open_hatch/tool_check(mob/user, obj/item/tool) if(tool.usesound) diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index aaa0bc765e1cb..6f5ab21c82815 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -158,7 +158,7 @@ if(!isorgan(target_organ)) if (target_zone == BODY_ZONE_PRECISE_EYES) target_zone = check_zone(target_zone) - to_chat(user, span_warning("You cannot put [target_organ] into [target]'s [parse_zone(target_zone)]!")) + to_chat(user, span_warning("You cannot put [target_organ] into [target]'s [target.parse_zone_with_bodypart(target_zone)]!")) return SURGERY_STEP_FAIL tool = target_organ if(isorgan(tool)) @@ -167,7 +167,7 @@ success_sound = 'sound/surgery/organ2.ogg' target_organ = tool if(target_zone != target_organ.zone || target.get_organ_slot(target_organ.slot)) - to_chat(user, span_warning("There is no room for [target_organ] in [target]'s [parse_zone(target_zone)]!")) + to_chat(user, span_warning("There is no room for [target_organ] in [target]'s [target.parse_zone_with_bodypart(target_zone)]!")) return SURGERY_STEP_FAIL var/obj/item/organ/meatslab = tool if(!meatslab.useable) @@ -182,11 +182,11 @@ display_results( user, target, - span_notice("You begin to insert [tool] into [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to insert [tool] into [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to insert something into [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to insert [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to insert [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to insert something into [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You can feel something being placed in your [parse_zone(target_zone)]!") + display_pain(target, "You can feel something being placed in your [target.parse_zone_with_bodypart(target_zone)]!") else if(implement_type in implements_extract) @@ -199,7 +199,7 @@ if (target_zone == BODY_ZONE_PRECISE_EYES) target_zone = check_zone(target_zone) if(!length(organs)) - to_chat(user, span_warning("There are no removable organs in [target]'s [parse_zone(target_zone)]!")) + to_chat(user, span_warning("There are no removable organs in [target]'s [target.parse_zone_with_bodypart(target_zone)]!")) return SURGERY_STEP_FAIL else for(var/obj/item/organ/organ in organs) @@ -221,11 +221,11 @@ display_results( user, target, - span_notice("You begin to extract [target_organ] from [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to extract [target_organ] from [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to extract something from [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to extract [target_organ] from [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to extract [target_organ] from [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to extract something from [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You can feel your [target_organ.name] being removed from your [parse_zone(target_zone)]!") + display_pain(target, "You can feel your [target_organ.name] being removed from your [target.parse_zone_with_bodypart(target_zone)]!") else return SURGERY_STEP_FAIL @@ -247,11 +247,12 @@ display_results( user, target, - span_notice("You insert [tool] into [target]'s [parse_zone(target_zone)]."), - span_notice("[user] inserts [tool] into [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] inserts something into [target]'s [parse_zone(target_zone)]!"), + span_notice("You insert [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] inserts [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_notice("[user] inserts something into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) - display_pain(target, "Your [parse_zone(target_zone)] throbs with pain as your new [tool.name] comes to life!") + display_pain(target, "Your [target.parse_zone_with_bodypart(target_zone)] throbs with pain as your new [tool.name] comes to life!") + target_organ.on_surgical_insertion(user, target, target_zone, tool) else target_organ.forceMove(target.loc) @@ -260,11 +261,11 @@ display_results( user, target, - span_notice("You successfully extract [target_organ] from [target]'s [parse_zone(target_zone)]."), - span_notice("[user] successfully extracts [target_organ] from [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] successfully extracts something from [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully extract [target_organ] from [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] successfully extracts [target_organ] from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_notice("[user] successfully extracts something from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) - display_pain(target, "Your [parse_zone(target_zone)] throbs with pain, you can't feel your [target_organ.name] anymore!") + display_pain(target, "Your [target.parse_zone_with_bodypart(target_zone)] throbs with pain, you can't feel your [target_organ.name] anymore!") log_combat(user, target, "surgically removed [target_organ.name] from", addition="COMBAT MODE: [uppertext(user.combat_mode)]") target_organ.Remove(target) target_organ.forceMove(get_turf(target)) @@ -273,9 +274,9 @@ display_results( user, target, - span_warning("You can't extract anything from [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!"), + span_warning("You can't extract anything from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_notice("[user] can't seem to extract anything from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_notice("[user] can't seem to extract anything from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) if(HAS_MIND_TRAIT(user, TRAIT_MORBID) && ishuman(user)) var/mob/living/carbon/human/morbid_weirdo = user diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm index aa697cb107271..a307d00dbba65 100644 --- a/code/modules/surgery/organic_steps.dm +++ b/code/modules/surgery/organic_steps.dm @@ -16,11 +16,11 @@ display_results( user, target, - span_notice("You begin to make an incision in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to make an incision in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to make an incision in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel a stabbing in your [parse_zone(target_zone)].") + display_pain(target, "You feel a stabbing in your [target.parse_zone_with_bodypart(target_zone)].") /datum/surgery_step/incise/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.get_sharpness()) @@ -35,9 +35,9 @@ display_results( user, target, - span_notice("Blood pools around the incision in [human_target]'s [parse_zone(target_zone)]."), - span_notice("Blood pools around the incision in [human_target]'s [parse_zone(target_zone)]."), - span_notice("Blood pools around the incision in [human_target]'s [parse_zone(target_zone)]."), + span_notice("Blood pools around the incision in [human_target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("Blood pools around the incision in [human_target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("Blood pools around the incision in [human_target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) var/obj/item/bodypart/target_bodypart = target.get_bodypart(target_zone) if(target_bodypart) @@ -48,11 +48,11 @@ display_results( user, target, - span_notice("You begin to carefully make an incision in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to carefully make an incision in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to carefully make an incision in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to carefully make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to carefully make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to carefully make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel a careful stabbing in your [parse_zone(target_zone)].") + display_pain(target, "You feel a careful stabbing in your [target.parse_zone_with_bodypart(target_zone)].") //clamp bleeders /datum/surgery_step/clamp_bleeders @@ -69,11 +69,11 @@ display_results( user, target, - span_notice("You begin to clamp bleeders in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to clamp bleeders in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to clamp bleeders in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to clamp bleeders in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel a pinch as the bleeding in your [parse_zone(target_zone)] is slowed.") + display_pain(target, "You feel a pinch as the bleeding in your [target.parse_zone_with_bodypart(target_zone)] is slowed.") /datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) if(locate(/datum/surgery_step/saw) in surgery.steps) @@ -101,11 +101,11 @@ display_results( user, target, - span_notice("You begin to retract the skin in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to retract the skin in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to retract the skin in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to retract the skin in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to retract the skin in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to retract the skin in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel a severe stinging pain spreading across your [parse_zone(target_zone)] as the skin is pulled back!") + display_pain(target, "You feel a severe stinging pain spreading across your [target.parse_zone_with_bodypart(target_zone)] as the skin is pulled back!") //close incision /datum/surgery_step/close @@ -123,11 +123,11 @@ display_results( user, target, - span_notice("You begin to mend the incision in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to mend the incision in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to mend the incision in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to mend the incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to mend the incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to mend the incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "Your [parse_zone(target_zone)] is being burned!") + display_pain(target, "Your [target.parse_zone_with_bodypart(target_zone)] is being burned!") /datum/surgery_step/close/tool_check(mob/user, obj/item/tool) if(implement_type == TOOL_WELDER || implement_type == /obj/item) @@ -173,11 +173,11 @@ display_results( user, target, - span_notice("You begin to saw through the bone in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to saw through the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to saw through the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to saw through the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel a horrid ache spread through the inside of your [parse_zone(target_zone)]!") + display_pain(target, "You feel a horrid ache spread through the inside of your [target.parse_zone_with_bodypart(target_zone)]!") /datum/surgery_step/saw/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !(tool.get_sharpness() && (tool.force >= 10))) @@ -189,11 +189,11 @@ display_results( user, target, - span_notice("You saw [target]'s [parse_zone(target_zone)] open."), - span_notice("[user] saws [target]'s [parse_zone(target_zone)] open!"), - span_notice("[user] saws [target]'s [parse_zone(target_zone)] open!"), + span_notice("You saw [target]'s [target.parse_zone_with_bodypart(target_zone)] open."), + span_notice("[user] saws [target]'s [target.parse_zone_with_bodypart(target_zone)] open!"), + span_notice("[user] saws [target]'s [target.parse_zone_with_bodypart(target_zone)] open!"), ) - display_pain(target, "It feels like something just broke in your [parse_zone(target_zone)]!") + display_pain(target, "It feels like something just broke in your [target.parse_zone_with_bodypart(target_zone)]!") return ..() //drill bone @@ -211,18 +211,18 @@ display_results( user, target, - span_notice("You begin to drill into the bone in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to drill into the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to drill into the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to drill into the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel a horrible piercing pain in your [parse_zone(target_zone)]!") + display_pain(target, "You feel a horrible piercing pain in your [target.parse_zone_with_bodypart(target_zone)]!") /datum/surgery_step/drill/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) display_results( user, target, - span_notice("You drill into [target]'s [parse_zone(target_zone)]."), - span_notice("[user] drills into [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] drills into [target]'s [parse_zone(target_zone)]!"), + span_notice("You drill into [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] drills into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), + span_notice("[user] drills into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) return ..() diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index d7f08a7be35b6..a3cda722a358d 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -82,10 +82,11 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) /obj/item/organ/Destroy() if(bodypart_owner && !owner && !QDELETED(bodypart_owner)) bodypart_remove(bodypart_owner) - else if(owner) - // The special flag is important, because otherwise mobs can die - // while undergoing transformation into different mobs. + else if(owner && QDESTROYING(owner)) + // The mob is being deleted, don't update the mob Remove(owner, special=TRUE) + else if(owner) + Remove(owner) else STOP_PROCESSING(SSobj, src) return ..() @@ -239,6 +240,11 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) for(var/obj/item/organ/organ as anything in organs) organ.set_organ_damage(0) set_heartattack(FALSE) + + // Ears have aditional vаr "deaf", need to update it too + var/obj/item/organ/internal/ears/ears = get_organ_slot(ORGAN_SLOT_EARS) + ears?.adjustEarDamage(0, -INFINITY) // full heal ears deafness + return // Default organ fixing handling @@ -273,7 +279,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) if(!ears) ears = new() ears.Insert(src) - ears.set_organ_damage(0) + ears.adjustEarDamage(-INFINITY, -INFINITY) // actually do: set_organ_damage(0) and deaf = 0 /obj/item/organ/proc/handle_failing_organs(seconds_per_tick) return diff --git a/code/modules/surgery/organs/external/_external_organ.dm b/code/modules/surgery/organs/external/_external_organ.dm index b58f08fe97d7e..a054bc741e632 100644 --- a/code/modules/surgery/organs/external/_external_organ.dm +++ b/code/modules/surgery/organs/external/_external_organ.dm @@ -182,7 +182,7 @@ return TRUE /datum/bodypart_overlay/mutant/horns/get_global_feature_list() - return GLOB.horns_list + return SSaccessories.horns_list ///The frills of a lizard (like weird fin ears) /obj/item/organ/external/frills @@ -209,7 +209,7 @@ return FALSE /datum/bodypart_overlay/mutant/frills/get_global_feature_list() - return GLOB.frills_list + return SSaccessories.frills_list ///Guess what part of the lizard this is? /obj/item/organ/external/snout @@ -238,7 +238,7 @@ return FALSE /datum/bodypart_overlay/mutant/snout/get_global_feature_list() - return GLOB.snouts_list + return SSaccessories.snouts_list ///A moth's antennae /obj/item/organ/external/antennae @@ -315,7 +315,7 @@ burn_datum = fetch_sprite_datum(burn_datum) //turn the path into the singleton instance /datum/bodypart_overlay/mutant/antennae/get_global_feature_list() - return GLOB.moth_antennae_list + return SSaccessories.moth_antennae_list /datum/bodypart_overlay/mutant/antennae/get_base_icon_state() return burnt ? burn_datum.icon_state : sprite_datum.icon_state @@ -347,7 +347,7 @@ var/color_inverse_base = 255 /datum/bodypart_overlay/mutant/pod_hair/get_global_feature_list() - return GLOB.pod_hair_list + return SSaccessories.pod_hair_list /datum/bodypart_overlay/mutant/pod_hair/color_image(image/overlay, draw_layer, obj/item/bodypart/limb) if(draw_layer != bitflag_to_layer(color_swapped_layer)) diff --git a/code/modules/surgery/organs/external/spines.dm b/code/modules/surgery/organs/external/spines.dm index 743b7fa8d47f2..86bff9a768939 100644 --- a/code/modules/surgery/organs/external/spines.dm +++ b/code/modules/surgery/organs/external/spines.dm @@ -32,7 +32,7 @@ feature_key = "spines" /datum/bodypart_overlay/mutant/spines/get_global_feature_list() - return GLOB.spines_list + return SSaccessories.spines_list /datum/bodypart_overlay/mutant/spines/can_draw_on_bodypart(mob/living/carbon/human/human) . = ..() diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index 4234ca9b5aed4..38b35bce45cb3 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -135,7 +135,7 @@ var/wagging = FALSE /datum/bodypart_overlay/mutant/tail/get_base_icon_state() - return (wagging ? "wagging_" : "") + sprite_datum.icon_state //add the wagging tag if we be wagging + return "[wagging ? "wagging_" : ""][sprite_datum.icon_state]" //add the wagging tag if we be wagging /datum/bodypart_overlay/mutant/tail/can_draw_on_bodypart(mob/living/carbon/human/human) if(human.wear_suit && (human.wear_suit.flags_inv & HIDEJUMPSUIT)) @@ -150,6 +150,9 @@ wag_flags = WAG_ABLE +/datum/bodypart_overlay/mutant/tail/get_global_feature_list() + return SSaccessories.tails_list_human + /obj/item/organ/external/tail/cat/get_butt_sprite() return BUTT_SPRITE_CAT @@ -158,19 +161,21 @@ feature_key = "tail_cat" color_source = ORGAN_COLOR_HAIR -/datum/bodypart_overlay/mutant/tail/cat/get_global_feature_list() - return GLOB.tails_list_human - /obj/item/organ/external/tail/monkey + name = "monkey tail" + preference = "feature_monkey_tail" + bodypart_overlay = /datum/bodypart_overlay/mutant/tail/monkey + dna_block = DNA_MONKEY_TAIL_BLOCK + ///Monkey tail bodypart overlay /datum/bodypart_overlay/mutant/tail/monkey color_source = NONE feature_key = "tail_monkey" /datum/bodypart_overlay/mutant/tail/monkey/get_global_feature_list() - return GLOB.tails_list_monkey + return SSaccessories.tails_list_monkey /obj/item/organ/external/tail/lizard name = "lizard tail" @@ -187,7 +192,7 @@ feature_key = "tail_lizard" /datum/bodypart_overlay/mutant/tail/lizard/get_global_feature_list() - return GLOB.tails_list_lizard + return SSaccessories.tails_list_lizard /obj/item/organ/external/tail/lizard/fake name = "fabricated lizard tail" @@ -203,7 +208,7 @@ var/tail_spine_key = NONE /datum/bodypart_overlay/mutant/tail_spines/get_global_feature_list() - return GLOB.tail_spines_list + return SSaccessories.tail_spines_list /datum/bodypart_overlay/mutant/tail_spines/get_base_icon_state() return (!isnull(tail_spine_key) ? "[tail_spine_key]_" : "") + (wagging ? "wagging_" : "") + sprite_datum.icon_state // Select the wagging state if appropriate diff --git a/code/modules/surgery/organs/external/wings/functional_wings.dm b/code/modules/surgery/organs/external/wings/functional_wings.dm index aacf6f08f6a5c..da3fe3353035c 100644 --- a/code/modules/surgery/organs/external/wings/functional_wings.dm +++ b/code/modules/surgery/organs/external/wings/functional_wings.dm @@ -50,7 +50,7 @@ ///Called on_life(). Handle flight code and check if we're still flying /obj/item/organ/external/wings/functional/proc/handle_flight(mob/living/carbon/human/human) - if(human.movement_type & ~FLYING) + if(!(human.movement_type & FLYING)) return FALSE if(!can_fly(human)) toggle_flight(human) @@ -112,19 +112,22 @@ human.remove_traits(list(TRAIT_NO_FLOATING_ANIM, TRAIT_MOVE_FLYING), SPECIES_FLIGHT_TRAIT) passtable_off(human, SPECIES_FLIGHT_TRAIT) close_wings() - human.update_body_parts() + + human.refresh_gravity() ///SPREAD OUR WINGS AND FLLLLLYYYYYY /obj/item/organ/external/wings/functional/proc/open_wings() var/datum/bodypart_overlay/mutant/wings/functional/overlay = bodypart_overlay overlay.open_wings() wings_open = TRUE + owner.update_body_parts() ///close our wings /obj/item/organ/external/wings/functional/proc/close_wings() var/datum/bodypart_overlay/mutant/wings/functional/overlay = bodypart_overlay wings_open = FALSE overlay.close_wings() + owner.update_body_parts() if(isturf(owner?.loc)) var/turf/location = loc @@ -139,9 +142,9 @@ /datum/bodypart_overlay/mutant/wings/functional/get_global_feature_list() if(wings_open) - return GLOB.wings_open_list + return SSaccessories.wings_open_list else - return GLOB.wings_list + return SSaccessories.wings_list ///Update our wingsprite to the open wings variant /datum/bodypart_overlay/mutant/wings/functional/proc/open_wings() @@ -186,6 +189,9 @@ desc = "Powered by pure edgy-teenager-notebook-scribblings. Just kidding. But seriously, how do these keep you flying?!" sprite_accessory_override = /datum/sprite_accessory/wings/skeleton +/obj/item/organ/external/wings/functional/moth/make_flap_sound(mob/living/carbon/wing_owner) + playsound(wing_owner, 'sound/voice/moth/moth_flutter.ogg', 50, TRUE) + ///mothra wings, which relate to moths. /obj/item/organ/external/wings/functional/moth/mothra name = "mothra wings" diff --git a/code/modules/surgery/organs/external/wings/moth_wings.dm b/code/modules/surgery/organs/external/wings/moth_wings.dm index f4e0f156e703e..87b944622aa09 100644 --- a/code/modules/surgery/organs/external/wings/moth_wings.dm +++ b/code/modules/surgery/organs/external/wings/moth_wings.dm @@ -25,6 +25,9 @@ UnregisterSignal(organ_owner, list(COMSIG_HUMAN_BURNING, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_MOVABLE_PRE_MOVE)) REMOVE_TRAIT(organ_owner, TRAIT_FREE_FLOAT_MOVEMENT, REF(src)) +/obj/item/organ/external/wings/moth/make_flap_sound(mob/living/carbon/wing_owner) + playsound(wing_owner, 'sound/voice/moth/moth_flutter.ogg', 50, TRUE) + /obj/item/organ/external/wings/moth/can_soften_fall() return !burnt @@ -84,7 +87,7 @@ burn_datum = fetch_sprite_datum(burn_datum) /datum/bodypart_overlay/mutant/wings/moth/get_global_feature_list() - return GLOB.moth_wings_list + return SSaccessories.moth_wings_list /datum/bodypart_overlay/mutant/wings/moth/can_draw_on_bodypart(mob/living/carbon/human/human) if(!(human.wear_suit?.flags_inv & HIDEMUTWINGS)) diff --git a/code/modules/surgery/organs/external/wings/wings.dm b/code/modules/surgery/organs/external/wings/wings.dm index 189c03e0277dd..775ffebf54cdf 100644 --- a/code/modules/surgery/organs/external/wings/wings.dm +++ b/code/modules/surgery/organs/external/wings/wings.dm @@ -13,6 +13,10 @@ /obj/item/organ/external/wings/proc/can_soften_fall() return TRUE +///Implement as needed to play a sound effect on *flap emote +/obj/item/organ/external/wings/proc/make_flap_sound(mob/living/carbon/wing_owner) + return + ///Bodypart overlay of default wings. Does not have any wing functionality /datum/bodypart_overlay/mutant/wings layers = ALL_EXTERNAL_OVERLAYS diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm index df194bbed0f42..24aadfeca14f6 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm @@ -23,7 +23,7 @@ synthesizing = TRUE to_chat(owner, span_notice("You feel less hungry...")) owner.adjust_nutrition(25 * seconds_per_tick) - addtimer(CALLBACK(src, PROC_REF(synth_cool)), 50) + addtimer(CALLBACK(src, PROC_REF(synth_cool)), 5 SECONDS) /obj/item/organ/internal/cyberimp/chest/nutriment/proc/synth_cool() synthesizing = FALSE diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm index 0e004ab3c5cb5..89c6f9c96a411 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm @@ -106,32 +106,62 @@ var/static/list/signalCache = list( COMSIG_LIVING_STATUS_STUN, - COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_LIVING_STATUS_IMMOBILIZE, COMSIG_LIVING_STATUS_PARALYZE, ) - var/stun_cap_amount = 40 + ///timer before the implant activates + var/stun_cap_amount = 1 SECONDS + ///amount of time you are resistant to stuns and knockdowns + var/stun_resistance_time = 6 SECONDS + COOLDOWN_DECLARE(implant_cooldown) /obj/item/organ/internal/cyberimp/brain/anti_stun/on_mob_remove(mob/living/carbon/implant_owner) . = ..() UnregisterSignal(implant_owner, signalCache) + UnregisterSignal(implant_owner, COMSIG_CARBON_ENTER_STAMCRIT) /obj/item/organ/internal/cyberimp/brain/anti_stun/on_mob_insert(mob/living/carbon/receiver) . = ..() RegisterSignals(receiver, signalCache, PROC_REF(on_signal)) + RegisterSignal(receiver, COMSIG_CARBON_ENTER_STAMCRIT, PROC_REF(on_stamcrit)) /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/on_signal(datum/source, amount) SIGNAL_HANDLER if(!(organ_flags & ORGAN_FAILING) && amount > 0) addtimer(CALLBACK(src, PROC_REF(clear_stuns)), stun_cap_amount, TIMER_UNIQUE|TIMER_OVERRIDE) +/obj/item/organ/internal/cyberimp/brain/anti_stun/proc/on_stamcrit(datum/source) + SIGNAL_HANDLER + if(!(organ_flags & ORGAN_FAILING)) + addtimer(CALLBACK(src, PROC_REF(clear_stuns)), stun_cap_amount, TIMER_UNIQUE|TIMER_OVERRIDE) + /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/clear_stuns() - if(owner || !(organ_flags & ORGAN_FAILING)) - owner.SetStun(0) - owner.SetKnockdown(0) - owner.SetImmobilized(0) - owner.SetParalyzed(0) + if(isnull(owner) || (organ_flags & ORGAN_FAILING) || !COOLDOWN_FINISHED(src, implant_cooldown)) + return + + owner.SetStun(0) + owner.SetKnockdown(0) + owner.SetImmobilized(0) + owner.SetParalyzed(0) + owner.setStaminaLoss(0) + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living, setStaminaLoss), 0), stun_resistance_time) + + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(5, 1, src) + sparks.start() + + owner.add_traits(list(TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_BATON_RESISTANCE, TRAIT_STUNIMMUNE), REF(src)) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_IGNOREDAMAGESLOWDOWN, REF(src)), stun_resistance_time) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_BATON_RESISTANCE, REF(src)), stun_resistance_time) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_STUNIMMUNE, REF(src)), stun_resistance_time) + + COOLDOWN_START(src, implant_cooldown, 60 SECONDS) + addtimer(CALLBACK(src, PROC_REF(implant_ready)),60 SECONDS) + +/obj/item/organ/internal/cyberimp/brain/anti_stun/proc/implant_ready() + if(owner) + to_chat(owner, span_purple("Your rebooter implant is ready.")) /obj/item/organ/internal/cyberimp/brain/anti_stun/emp_act(severity) . = ..() @@ -141,7 +171,8 @@ addtimer(CALLBACK(src, PROC_REF(reboot)), 90 / severity) /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/reboot() - organ_flags &= ~ORGAN_FAILING + organ_flags &= ~ORGAN_FAILING + implant_ready() //[[[[MOUTH]]]] /obj/item/organ/internal/cyberimp/mouth diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm index 7fd5c85675fd3..eba24086cca2b 100644 --- a/code/modules/surgery/organs/internal/ears/_ears.dm +++ b/code/modules/surgery/organs/internal/ears/_ears.dm @@ -15,17 +15,16 @@ now_fixed = "Noise slowly begins filling your ears once more." low_threshold_cleared = "The ringing in your ears has died down." - // `deaf` measures "ticks" of deafness. While > 0, the person is unable - // to hear anything. + /// `deaf` measures "ticks" of deafness. While > 0, the person is unable to hear anything. var/deaf = 0 // `damage` in this case measures long term damage to the ears, if too high, // the person will not have either `deaf` or `ear_damage` decrease // without external aid (earmuffs, drugs) - //Resistance against loud noises + /// Resistance against loud noises var/bang_protect = 0 - // Multiplier for both long term and short term ear damage + /// Multiplier for both long term and short term ear damage var/damage_multiplier = 1 /obj/item/organ/internal/ears/on_life(seconds_per_tick, times_fired) @@ -34,28 +33,98 @@ to_chat(owner, span_warning("The ringing in your ears grows louder, blocking out any external noises for a moment.")) . = ..() - // if we have non-damage related deafness like mutations, quirks or clothing (earmuffs), don't bother processing here. Ear healing from earmuffs or chems happen elsewhere + // if we have non-damage related deafness like mutations, quirks or clothing (earmuffs), don't bother processing here. + // Ear healing from earmuffs or chems happen elsewhere if(HAS_TRAIT_NOT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE)) return + // no healing if failing + if(organ_flags & ORGAN_FAILING) + return + adjustEarDamage(0, -0.5 * seconds_per_tick) + if((damage > low_threshold) && SPT_PROB(damage / 60, seconds_per_tick)) + adjustEarDamage(0, 4) + SEND_SOUND(owner, sound('sound/weapons/flash_ring.ogg')) + +/obj/item/organ/internal/ears/apply_organ_damage(damage_amount, maximum, required_organ_flag) + . = ..() + update_temp_deafness() + +/obj/item/organ/internal/ears/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags) + . = ..() + update_temp_deafness() + +/obj/item/organ/internal/ears/on_mob_remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_MOB_SAY) + REMOVE_TRAIT(organ_owner, TRAIT_DEAF, EAR_DAMAGE) + +/** + * Snowflake proc to handle temporary deafness + * + * * ddmg: Handles normal organ damage + * * ddeaf: Handles temporary deafness, 1 ddeaf = 2 seconds of deafness, by default (with no multiplier) + */ +/obj/item/organ/internal/ears/proc/adjustEarDamage(ddmg = 0, ddeaf = 0) + if(owner.status_flags & GODMODE) + update_temp_deafness() + return + + var/mod_damage = ddmg > 0 ? (ddmg * damage_multiplier) : ddmg + if(mod_damage) + apply_organ_damage(mod_damage) + var/mod_deaf = ddeaf > 0 ? (ddeaf * damage_multiplier) : ddeaf + if(mod_deaf) + deaf = max(deaf + mod_deaf, 0) + update_temp_deafness() + +/// Updates status of deafness +/obj/item/organ/internal/ears/proc/update_temp_deafness() + // if we're failing we always have at least some deaf stacks (and thus deafness) + if(organ_flags & ORGAN_FAILING) + deaf = max(deaf, 1 * damage_multiplier) + + if(isnull(owner)) + return - if((organ_flags & ORGAN_FAILING)) - deaf = max(deaf, 1) // if we're failing we always have at least 1 deaf stack (and thus deafness) - else // only clear deaf stacks if we're not failing - deaf = max(deaf - (0.5 * seconds_per_tick), 0) - if((damage > low_threshold) && SPT_PROB(damage / 60, seconds_per_tick)) - adjustEarDamage(0, 4) - SEND_SOUND(owner, sound('sound/weapons/flash_ring.ogg')) + if(owner.status_flags & GODMODE) + deaf = 0 - if(deaf) - ADD_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE) + if(deaf > 0) + if(!HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE)) + RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(adjust_speech)) + ADD_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE) else REMOVE_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE) + UnregisterSignal(owner, COMSIG_MOB_SAY) -/obj/item/organ/internal/ears/proc/adjustEarDamage(ddmg, ddeaf) - if(owner.status_flags & GODMODE) +/// Being deafened by loud noises makes you shout +/obj/item/organ/internal/ears/proc/adjust_speech(datum/source, list/speech_args) + SIGNAL_HANDLER + + if(HAS_TRAIT_NOT_FROM(source, TRAIT_DEAF, EAR_DAMAGE)) return - set_organ_damage(clamp(damage + (ddmg * damage_multiplier), 0, maxHealth)) - deaf = max(deaf + (ddeaf * damage_multiplier), 0) + if(HAS_TRAIT(source, TRAIT_SIGN_LANG)) + return + + var/message = speech_args[SPEECH_MESSAGE] + // Replace only end-of-sentence punctuation with exclamation marks (hence the empty space) + // We don't wanna mess with things like ellipses + message = replacetext(message, ". ", "! ") + message = replacetext(message, "? ", "?! ") + // Special case for the last character + switch(copytext_char(message, -1)) + if(".") + if(copytext_char(message, -2) != "..") // Once again ignoring ellipses, let people trail off + message = copytext_char(message, 1, -1) + "!" + if("?") + message = copytext_char(message, 1, -1) + "?!" + if("!") + pass() + else + message += "!" + + speech_args[SPEECH_MESSAGE] = message + return COMPONENT_UPPERCASE_SPEECH /obj/item/organ/internal/ears/invincible damage_multiplier = 0 diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm index aaf79ba755369..bffdf1ae44d08 100644 --- a/code/modules/surgery/organs/internal/eyes/_eyes.dm +++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm @@ -501,7 +501,7 @@ set_beam_color(new_color, to_update) return TRUE if("enter_color") - var/new_color = lowertext(params["new_color"]) + var/new_color = LOWER_TEXT(params["new_color"]) var/to_update = params["to_update"] set_beam_color(new_color, to_update, sanitize = TRUE) return TRUE diff --git a/code/modules/surgery/organs/internal/lungs/_lungs.dm b/code/modules/surgery/organs/internal/lungs/_lungs.dm index 1db1963e8d665..a60cc24375617 100644 --- a/code/modules/surgery/organs/internal/lungs/_lungs.dm +++ b/code/modules/surgery/organs/internal/lungs/_lungs.dm @@ -266,7 +266,8 @@ var/ratio = (breath.gases[/datum/gas/oxygen][MOLES] / safe_oxygen_max) * 10 breather.apply_damage(clamp(ratio, oxy_breath_dam_min, oxy_breath_dam_max), oxy_damage_type, spread_damage = TRUE) - breather.throw_alert(ALERT_TOO_MUCH_OXYGEN, /atom/movable/screen/alert/too_much_oxy) + if(!HAS_TRAIT(breather, TRAIT_ANOSMIA)) + breather.throw_alert(ALERT_TOO_MUCH_OXYGEN, /atom/movable/screen/alert/too_much_oxy) /// Handles NOT having too much o2. only relevant if safe_oxygen_max has a value /obj/item/organ/internal/lungs/proc/safe_oxygen(mob/living/carbon/breather, datum/gas_mixture/breath, old_o2_pp) @@ -285,7 +286,8 @@ if(nitro_pp < safe_nitro_min && !HAS_TRAIT(src, TRAIT_SPACEBREATHING)) // Suffocation side-effects. // Not safe to check the old pp because of can_breath_vacuum - breather.throw_alert(ALERT_NOT_ENOUGH_NITRO, /atom/movable/screen/alert/not_enough_nitro) + if(!HAS_TRAIT(breather, TRAIT_ANOSMIA)) + breather.throw_alert(ALERT_NOT_ENOUGH_NITRO, /atom/movable/screen/alert/not_enough_nitro) var/gas_breathed = handle_suffocation(breather, nitro_pp, safe_nitro_min, breath.gases[/datum/gas/nitrogen][MOLES]) if(nitro_pp) breathe_gas_volume(breath, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, volume = gas_breathed) @@ -318,7 +320,8 @@ breather.emote("cough") if((world.time - breather.co2overloadtime) > 12 SECONDS) - breather.throw_alert(ALERT_TOO_MUCH_CO2, /atom/movable/screen/alert/too_much_co2) + if(!HAS_TRAIT(breather, TRAIT_ANOSMIA)) + breather.throw_alert(ALERT_TOO_MUCH_CO2, /atom/movable/screen/alert/too_much_co2) breather.Unconscious(6 SECONDS) // Lets hurt em a little, let them know we mean business. breather.apply_damage(3, co2_damage_type, spread_damage = TRUE) @@ -337,7 +340,8 @@ // Suffocation side-effects. if(plasma_pp < safe_plasma_min && !HAS_TRAIT(src, TRAIT_SPACEBREATHING)) // Could check old_plasma_pp but vacuum breathing hates me - breather.throw_alert(ALERT_NOT_ENOUGH_PLASMA, /atom/movable/screen/alert/not_enough_plas) + if(!HAS_TRAIT(breather, TRAIT_ANOSMIA)) + breather.throw_alert(ALERT_NOT_ENOUGH_PLASMA, /atom/movable/screen/alert/not_enough_plas) // Breathe insufficient amount of Plasma, exhale CO2. var/gas_breathed = handle_suffocation(breather, plasma_pp, safe_plasma_min, breath.gases[/datum/gas/plasma][MOLES]) if(plasma_pp) @@ -362,7 +366,8 @@ // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so. if(old_plasma_pp < safe_plasma_max) - breather.throw_alert(ALERT_TOO_MUCH_PLASMA, /atom/movable/screen/alert/too_much_plas) + if(!HAS_TRAIT(breather, TRAIT_ANOSMIA)) + breather.throw_alert(ALERT_TOO_MUCH_PLASMA, /atom/movable/screen/alert/too_much_plas) var/ratio = (breath.gases[/datum/gas/plasma][MOLES] / safe_plasma_max) * 10 breather.apply_damage(clamp(ratio, plas_breath_dam_min, plas_breath_dam_max), plas_damage_type, spread_damage = TRUE) @@ -466,6 +471,8 @@ miasma_disease.name = "Unknown" breather.AirborneContractDisease(miasma_disease, TRUE) // Miasma side effects + if (HAS_TRAIT(breather, TRAIT_ANOSMIA)) //Anosmia quirk holder cannot smell miasma, but can get diseases from it. + return switch(miasma_pp) if(0.25 to 5) // At lower pp, give out a little warning @@ -522,7 +529,8 @@ // More N2O, more severe side-effects. Causes stun/sleep. if(old_n2o_pp < n2o_para_min) - breather.throw_alert(ALERT_TOO_MUCH_N2O, /atom/movable/screen/alert/too_much_n2o) + if(!HAS_TRAIT(breather, TRAIT_ANOSMIA)) + breather.throw_alert(ALERT_TOO_MUCH_N2O, /atom/movable/screen/alert/too_much_n2o) n2o_euphoria = EUPHORIA_ACTIVE // give them one second of grace to wake up and run away a bit! @@ -754,31 +762,85 @@ if(!HAS_TRAIT(breather, TRAIT_RESISTCOLD)) // COLD DAMAGE var/cold_modifier = breather.dna.species.coldmod + var/breath_effect_prob = 0 if(breath_temperature < cold_level_3_threshold) - breather.apply_damage(cold_level_3_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_3_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 100 if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold) - breather.apply_damage(cold_level_2_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_2_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 50 if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold) - breather.apply_damage(cold_level_1_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_1_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 25 if(breath_temperature < cold_level_1_threshold) - if(prob(20)) + if(prob(sqrt(breath_effect_prob) * 4)) to_chat(breather, span_warning("You feel [cold_message] in your [name]!")) + if(prob(50)) + breather.emote("shiver") + if(prob(breath_effect_prob)) + // Breathing into your mask, no particle. We can add fogged up glasses later + if(breather.is_mouth_covered()) + return + // Even though breathing via internals TECHNICALLY exhales into the environment, we'll still block it + if(breather.internal || breather.external) + return + emit_breath_particle(breather, /particles/fog/breath) if(!HAS_TRAIT(breather, TRAIT_RESISTHEAT)) // HEAT DAMAGE var/heat_modifier = breather.dna.species.heatmod + var/heat_message_prob = 0 if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold) - breather.apply_damage(heat_level_1_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_1_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 100 if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold) - breather.apply_damage(heat_level_2_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_2_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 50 if(breath_temperature > heat_level_3_threshold) - breather.apply_damage(heat_level_3_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_3_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 25 if(breath_temperature > heat_level_1_threshold) - if(prob(20)) + if(prob(sqrt(heat_message_prob) * 4)) to_chat(breather, span_warning("You feel [hot_message] in your [name]!")) // The air you breathe out should match your body temperature breath.temperature = breather.bodytemperature +/// Creates a particle effect off the mouth of the passed mob. +/obj/item/organ/internal/lungs/proc/emit_breath_particle(mob/living/carbon/human/breather, particle_type) + ASSERT(ispath(particle_type, /particles)) + + var/obj/effect/abstract/particle_holder/holder = new(breather, particle_type) + var/particles/breath_particle = holder.particles + var/breath_dir = breather.dir + + var/list/particle_grav = list(0, 0.1, 0) + var/list/particle_pos = list(0, breather.get_mob_height() + 2, 0) + if(breath_dir & NORTH) + particle_grav[2] = 0.2 + breath_particle.rotation = pick(-45, 45) + // Layer it behind the mob since we're facing away from the camera + holder.pixel_w -= 4 + holder.pixel_y += 4 + if(breath_dir & WEST) + particle_grav[1] = -0.2 + particle_pos[1] = -5 + breath_particle.rotation = -45 + if(breath_dir & EAST) + particle_grav[1] = 0.2 + particle_pos[1] = 5 + breath_particle.rotation = 45 + if(breath_dir & SOUTH) + particle_grav[2] = 0.2 + breath_particle.rotation = pick(-45, 45) + // Shouldn't be necessary but just for parity + holder.pixel_w += 4 + holder.pixel_y -= 4 + + breath_particle.gravity = particle_grav + breath_particle.position = particle_pos + + QDEL_IN(holder, breath_particle.lifespan) + /obj/item/organ/internal/lungs/on_life(seconds_per_tick, times_fired) . = ..() if(failed && !(organ_flags & ORGAN_FAILING)) diff --git a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm index c31260cca719e..2675f46d13d6e 100644 --- a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm +++ b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm @@ -3,11 +3,19 @@ icon_state = "stomach-p" //Welp. At least it's more unique in functionaliy. desc = "A crystal-like organ that stores the electric charge of ethereals." organ_traits = list(TRAIT_NOHUNGER) // We have our own hunger mechanic. - ///basically satiety but electrical - var/crystal_charge = ETHEREAL_CHARGE_FULL + /// Where the energy of the stomach is stored. + var/obj/item/stock_parts/cell/cell ///used to keep ethereals from spam draining power sources var/drain_time = 0 +/obj/item/organ/internal/stomach/ethereal/Initialize(mapload) + . = ..() + cell = new /obj/item/stock_parts/cell/ethereal(null) + +/obj/item/organ/internal/stomach/ethereal/Destroy() + QDEL_NULL(cell) + return ..() + /obj/item/organ/internal/stomach/ethereal/on_life(seconds_per_tick, times_fired) . = ..() adjust_charge(-ETHEREAL_DISCHARGE_RATE * seconds_per_tick) @@ -27,11 +35,12 @@ stomach_owner.clear_alert(ALERT_ETHEREAL_OVERCHARGE) /obj/item/organ/internal/stomach/ethereal/handle_hunger_slowdown(mob/living/carbon/human/human) - human.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (1.5 * (1 - crystal_charge / 100))) + human.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (1.5 * (1 - cell.charge() / 100))) -/obj/item/organ/internal/stomach/ethereal/proc/charge(datum/source, amount, repairs) +/obj/item/organ/internal/stomach/ethereal/proc/charge(datum/source, datum/callback/charge_cell, seconds_per_tick) SIGNAL_HANDLER - adjust_charge(amount / 3.5) + + charge_cell.Invoke(cell, seconds_per_tick / 3.5) // Ethereals don't have NT designed charging ports, so they charge slower. /obj/item/organ/internal/stomach/ethereal/proc/on_electrocute(datum/source, shock_damage, shock_source, siemens_coeff = 1, flags = NONE) SIGNAL_HANDLER @@ -46,12 +55,11 @@ * Returns: The amount of energy that actually got changed in joules. **/ /obj/item/organ/internal/stomach/ethereal/proc/adjust_charge(amount) - var/amount_changed = clamp(amount, ETHEREAL_CHARGE_NONE - crystal_charge, ETHEREAL_CHARGE_DANGEROUS - crystal_charge) - crystal_charge = crystal_charge + amount - return amount_changed + var/amount_changed = clamp(amount, ETHEREAL_CHARGE_NONE - cell.charge(), ETHEREAL_CHARGE_DANGEROUS - cell.charge()) + return cell.change(amount_changed) /obj/item/organ/internal/stomach/ethereal/proc/handle_charge(mob/living/carbon/carbon, seconds_per_tick, times_fired) - switch(crystal_charge) + switch(cell.charge()) if(-INFINITY to ETHEREAL_CHARGE_NONE) carbon.add_mood_event("charge", /datum/mood_event/decharged) carbon.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/emptycell/ethereal) @@ -99,8 +107,9 @@ playsound(carbon, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) carbon.cut_overlay(overcharge) - tesla_zap(source = carbon, zap_range = 2, power = crystal_charge * 2.5, cutoff = 1 KILO JOULES, zap_flags = ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) - adjust_charge(ETHEREAL_CHARGE_FULL - crystal_charge) + // Only a small amount of the energy gets discharged as the zap. The rest dissipates as heat. Keeps the damage and energy from the zap the same regardless of what STANDARD_CELL_CHARGE is. + var/discharged_energy = -adjust_charge(ETHEREAL_CHARGE_FULL - cell.charge()) * min(7500 / STANDARD_CELL_CHARGE, 1) + tesla_zap(source = carbon, zap_range = 2, power = discharged_energy, cutoff = 1 KILO JOULES, zap_flags = ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) carbon.visible_message(span_danger("[carbon] violently discharges energy!"), span_warning("You violently discharge energy!")) if(prob(10)) //chance of developing heart disease to dissuade overcharging oneself diff --git a/code/modules/surgery/organs/internal/tongue/_tongue.dm b/code/modules/surgery/organs/internal/tongue/_tongue.dm index 5098d738d305b..469879263cc85 100644 --- a/code/modules/surgery/organs/internal/tongue/_tongue.dm +++ b/code/modules/surgery/organs/internal/tongue/_tongue.dm @@ -444,7 +444,7 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) var/list/message_word_list = splittext(message, " ") var/list/translated_word_list = list() for(var/word in message_word_list) - word = GLOB.english_to_zombie[lowertext(word)] + word = GLOB.english_to_zombie[LOWER_TEXT(word)] translated_word_list += word ? word : FALSE // all occurrences of characters "eiou" (case-insensitive) are replaced with "r" diff --git a/code/modules/surgery/organs/organ_movement.dm b/code/modules/surgery/organs/organ_movement.dm index 7c6907da86334..2889cbe07081b 100644 --- a/code/modules/surgery/organs/organ_movement.dm +++ b/code/modules/surgery/organs/organ_movement.dm @@ -193,7 +193,6 @@ // The true movement is here moveToNullspace() - bodypart_owner.contents -= src bodypart_owner = null on_bodypart_remove(limb) @@ -224,9 +223,14 @@ /** * Proc that gets called when the organ is surgically removed by someone, can be used for special effects - * Currently only used so surplus organs can explode when surgically removed. */ /obj/item/organ/proc/on_surgical_removal(mob/living/user, mob/living/carbon/old_owner, target_zone, obj/item/tool) SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_ORGAN_SURGICALLY_REMOVED, user, old_owner, target_zone, tool) RemoveElement(/datum/element/decal/blood) +/** + * Proc that gets called when the organ is surgically inserted by someone. Seem familiar? + */ +/obj/item/organ/proc/on_surgical_insertion(mob/living/user, mob/living/carbon/new_owner, target_zone, obj/item/tool) + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ORGAN_SURGICALLY_INSERTED, user, new_owner, target_zone, tool) diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm index 9224c29b2db63..90357f7b2e497 100644 --- a/code/modules/surgery/plastic_surgery.dm +++ b/code/modules/surgery/plastic_surgery.dm @@ -42,11 +42,11 @@ display_results( user, target, - span_notice("You begin to insert [tool] into the incision in [target]'s [parse_zone(target_zone)]..."), - span_notice("[user] begins to insert [tool] into the incision in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to insert [tool] into the incision in [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to insert [tool] into the incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]..."), + span_notice("[user] begins to insert [tool] into the incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to insert [tool] into the incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) - display_pain(target, "You feel something inserting just below the skin in your [parse_zone(target_zone)].") + display_pain(target, "You feel something inserting just below the skin in your [target.parse_zone_with_bodypart(target_zone)].") /datum/surgery_step/insert_plastic/success(mob/user, mob/living/target, target_zone, obj/item/stack/tool, datum/surgery/surgery, default_display_results) . = ..() @@ -94,11 +94,11 @@ else user.visible_message(span_warning("You have no picture to base the appearance on, reverting to random appearances.")) for(var/i in 1 to 10) - names += target.dna.species.random_name(target.gender, TRUE) + names += target.generate_random_mob_name(TRUE) else - for(var/_i in 1 to 9) + for(var/j in 1 to 9) names += "Subject [target.gender == MALE ? "i" : "o"]-[pick("a", "b", "c", "d", "e")]-[rand(10000, 99999)]" - names += target.dna.species.random_name(target.gender, TRUE) //give one normal name in case they want to do regular plastic surgery + names += target.generate_random_mob_name(TRUE) //give one normal name in case they want to do regular plastic surgery var/chosen_name = tgui_input_list(user, "New name to assign", "Plastic Surgery", names) if(isnull(chosen_name)) return diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm index 818c7a788d953..fcfc01f3a9b9a 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/prosthetic_replacement.dm @@ -62,27 +62,27 @@ organ_rejection_dam = 30 if(!bodypart_to_attach.can_attach_limb(target)) - target.balloon_alert(user, "that doesn't go on the [parse_zone(target_zone)]!") + target.balloon_alert(user, "that doesn't go on the [target.parse_zone_with_bodypart(target_zone)]!") return SURGERY_STEP_FAIL if(target_zone == bodypart_to_attach.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm. display_results( user, target, - span_notice("You begin to replace [target]'s [parse_zone(target_zone)] with [tool]..."), - span_notice("[user] begins to replace [target]'s [parse_zone(target_zone)] with [tool]."), - span_notice("[user] begins to replace [target]'s [parse_zone(target_zone)]."), + span_notice("You begin to replace [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]..."), + span_notice("[user] begins to replace [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]."), + span_notice("[user] begins to replace [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) else - to_chat(user, span_warning("[tool] isn't the right type for [parse_zone(target_zone)].")) + to_chat(user, span_warning("[tool] isn't the right type for [target.parse_zone_with_bodypart(target_zone)].")) return SURGERY_STEP_FAIL else if(target_zone == BODY_ZONE_L_ARM || target_zone == BODY_ZONE_R_ARM) display_results( user, target, span_notice("You begin to attach [tool] onto [target]..."), - span_notice("[user] begins to attach [tool] onto [target]'s [parse_zone(target_zone)]."), - span_notice("[user] begins to attach something onto [target]'s [parse_zone(target_zone)]."), + span_notice("[user] begins to attach [tool] onto [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] begins to attach something onto [target]'s [target.parse_zone_with_bodypart(target_zone)]."), ) else to_chat(user, span_warning("[tool] must be installed onto an arm.")) @@ -105,11 +105,11 @@ display_results( user, target, - span_notice("You succeed in replacing [target]'s [parse_zone(target_zone)]."), - span_notice("[user] successfully replaces [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully replaces [target]'s [parse_zone(target_zone)]!"), + span_notice("You succeed in replacing [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] successfully replaces [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully replaces [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) - display_pain(target, "You feel synthetic sensation wash from your [parse_zone(target_zone)], which you can feel again!", TRUE) + display_pain(target, "You feel synthetic sensation wash from your [target.parse_zone_with_bodypart(target_zone)], which you can feel again!", TRUE) return else var/obj/item/bodypart/bodypart_to_attach = target.newBodyPart(target_zone, FALSE, FALSE) @@ -123,7 +123,7 @@ span_notice("[user] finishes attaching [tool]!"), span_notice("[user] finishes the attachment procedure!"), ) - display_pain(target, "You feel a strange sensation from your new [parse_zone(target_zone)].", TRUE) + display_pain(target, "You feel a strange sensation from your new [target.parse_zone_with_bodypart(target_zone)].", TRUE) if(istype(tool, /obj/item/chainsaw)) qdel(tool) var/obj/item/chainsaw/mounted_chainsaw/new_arm = new(target) diff --git a/code/modules/surgery/repair_puncture.dm b/code/modules/surgery/repair_puncture.dm index 9b9071cff89c5..31a61a8827986 100644 --- a/code/modules/surgery/repair_puncture.dm +++ b/code/modules/surgery/repair_puncture.dm @@ -50,22 +50,22 @@ /datum/surgery_step/repair_innards/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound if(!pierce_wound) - user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]...")) + user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]...")) return if(pierce_wound.blood_flow <= 0) - to_chat(user, span_notice("[target]'s [parse_zone(user.zone_selected)] has no puncture to repair!")) + to_chat(user, span_notice("[target]'s [target.parse_zone_with_bodypart(user.zone_selected)] has no puncture to repair!")) surgery.status++ return display_results( user, target, - span_notice("You begin to realign the torn blood vessels in [target]'s [parse_zone(user.zone_selected)]..."), - span_notice("[user] begins to realign the torn blood vessels in [target]'s [parse_zone(user.zone_selected)] with [tool]."), - span_notice("[user] begins to realign the torn blood vessels in [target]'s [parse_zone(user.zone_selected)]."), + span_notice("You begin to realign the torn blood vessels in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."), + span_notice("[user] begins to realign the torn blood vessels in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."), + span_notice("[user] begins to realign the torn blood vessels in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), ) - display_pain(target, "You feel a horrible stabbing pain in your [parse_zone(user.zone_selected)]!") + display_pain(target, "You feel a horrible stabbing pain in your [target.parse_zone_with_bodypart(user.zone_selected)]!") /datum/surgery_step/repair_innards/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound @@ -76,9 +76,9 @@ display_results( user, target, - span_notice("You successfully realign some of the blood vessels in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] successfully realigns some of the blood vessels in [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully realigns some of the blood vessels in [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully realign some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] successfully realigns some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully realigns some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) log_combat(user, target, "excised infected flesh in", addition="COMBAT MODE: [uppertext(user.combat_mode)]") surgery.operated_bodypart.receive_damage(brute=3, wound_bonus=CANT_WOUND) @@ -90,9 +90,9 @@ display_results( user, target, - span_notice("You jerk apart some of the blood vessels in [target]'s [parse_zone(target_zone)]."), - span_notice("[user] jerks apart some of the blood vessels in [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] jerk apart some of the blood vessels in [target]'s [parse_zone(target_zone)]!"), + span_notice("You jerk apart some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)]."), + span_notice("[user] jerks apart some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] jerk apart some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) surgery.operated_bodypart.receive_damage(brute=rand(4,8), sharpness=SHARP_EDGED, wound_bonus = 10) @@ -117,16 +117,16 @@ /datum/surgery_step/seal_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound if(!pierce_wound) - user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]...")) + user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]...")) return display_results( user, target, - span_notice("You begin to meld some of the split blood vessels in [target]'s [parse_zone(user.zone_selected)]..."), - span_notice("[user] begins to meld some of the split blood vessels in [target]'s [parse_zone(user.zone_selected)] with [tool]."), - span_notice("[user] begins to meld some of the split blood vessels in [target]'s [parse_zone(user.zone_selected)]."), + span_notice("You begin to meld some of the split blood vessels in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."), + span_notice("[user] begins to meld some of the split blood vessels in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."), + span_notice("[user] begins to meld some of the split blood vessels in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), ) - display_pain(target, "You're being burned inside your [parse_zone(user.zone_selected)]!") + display_pain(target, "You're being burned inside your [target.parse_zone_with_bodypart(user.zone_selected)]!") /datum/surgery_step/seal_veins/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound @@ -137,9 +137,9 @@ display_results( user, target, - span_notice("You successfully meld some of the split blood vessels in [target]'s [parse_zone(target_zone)] with [tool]."), - span_notice("[user] successfully melds some of the split blood vessels in [target]'s [parse_zone(target_zone)] with [tool]!"), - span_notice("[user] successfully melds some of the split blood vessels in [target]'s [parse_zone(target_zone)]!"), + span_notice("You successfully meld some of the split blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]."), + span_notice("[user] successfully melds some of the split blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"), + span_notice("[user] successfully melds some of the split blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)]!"), ) log_combat(user, target, "dressed burns in", addition="COMBAT MODE: [uppertext(user.combat_mode)]") pierce_wound.adjust_blood_flow(-0.5) @@ -147,7 +147,7 @@ surgery.status = REALIGN_INNARDS to_chat(user, span_notice("There still seems to be misaligned blood vessels to finish...")) else - to_chat(user, span_green("You've repaired all the internal damage in [target]'s [parse_zone(target_zone)]!")) + to_chat(user, span_green("You've repaired all the internal damage in [target]'s [target.parse_zone_with_bodypart(target_zone)]!")) return ..() #undef REALIGN_INNARDS diff --git a/code/modules/antagonists/traitor/objectives/sleeper_protocol.dm b/code/modules/surgery/sleeper_protocol.dm similarity index 50% rename from code/modules/antagonists/traitor/objectives/sleeper_protocol.dm rename to code/modules/surgery/sleeper_protocol.dm index f28a79d692669..693b0fbfb5c4a 100644 --- a/code/modules/antagonists/traitor/objectives/sleeper_protocol.dm +++ b/code/modules/surgery/sleeper_protocol.dm @@ -1,71 +1,3 @@ -/datum/traitor_objective_category/sleeper_protocol - name = "Sleeper Protocol" - objectives = list( - /datum/traitor_objective/sleeper_protocol = 1, - /datum/traitor_objective/sleeper_protocol/everybody = 1, - ) - -/datum/traitor_objective/sleeper_protocol - name = "Perform the sleeper protocol on a crewmember" - description = "Use the button below to materialize a surgery disk in your hand, where you'll then be able to perform the sleeper protocol on a crewmember. If the disk gets destroyed, the objective will fail. This will only work on living and sentient crewmembers." - - progression_minimum = 0 MINUTES - - progression_reward = list(8 MINUTES, 15 MINUTES) - telecrystal_reward = 1 - - var/list/limited_to = list( - JOB_CHIEF_MEDICAL_OFFICER, - JOB_MEDICAL_DOCTOR, - JOB_PARAMEDIC, - JOB_VIROLOGIST, - JOB_ROBOTICIST, - ) - - var/obj/item/disk/surgery/sleeper_protocol/disk - - var/mob/living/current_registered_mob - - var/inverted_limitation = FALSE - -/datum/traitor_objective/sleeper_protocol/generate_ui_buttons(mob/user) - var/list/buttons = list() - if(!disk) - buttons += add_ui_button("", "Clicking this will materialize the sleeper protocol surgery in your hand", "save", "summon_disk") - return buttons - -/datum/traitor_objective/sleeper_protocol/ui_perform_action(mob/living/user, action) - switch(action) - if("summon_disk") - if(disk) - return - disk = new(user.drop_location()) - user.put_in_hands(disk) - AddComponent(/datum/component/traitor_objective_register, disk, \ - fail_signals = list(COMSIG_QDELETING)) - -/datum/traitor_objective/sleeper_protocol/proc/on_surgery_success(datum/source, datum/surgery_step/step, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) - SIGNAL_HANDLER - if(istype(step, /datum/surgery_step/brainwash/sleeper_agent)) - succeed_objective() - -/datum/traitor_objective/sleeper_protocol/can_generate_objective(datum/mind/generating_for, list/possible_duplicates) - var/datum/job/job = generating_for.assigned_role - if(!(job.title in limited_to) && !inverted_limitation) - return FALSE - if((job.title in limited_to) && inverted_limitation) - return FALSE - if(length(possible_duplicates) > 0) - return FALSE - return TRUE - -/datum/traitor_objective/sleeper_protocol/generate_objective(datum/mind/generating_for, list/possible_duplicates) - AddComponent(/datum/component/traitor_objective_mind_tracker, generating_for, \ - signals = list(COMSIG_MOB_SURGERY_STEP_SUCCESS = PROC_REF(on_surgery_success))) - return TRUE - -/datum/traitor_objective/sleeper_protocol/ungenerate_objective() - disk = null /obj/item/disk/surgery/sleeper_protocol name = "Suspicious Surgery Disk" desc = "The disk provides instructions on how to turn someone into a sleeper agent for the Syndicate." @@ -129,10 +61,3 @@ if(!.) return target.gain_trauma(new /datum/brain_trauma/mild/phobia/conspiracies(), TRAUMA_RESILIENCE_LOBOTOMY) - -/datum/traitor_objective/sleeper_protocol/everybody //Much harder for non-med and non-robo - progression_minimum = 30 MINUTES - progression_reward = list(8 MINUTES, 15 MINUTES) - telecrystal_reward = 1 - - inverted_limitation = TRUE diff --git a/code/modules/surgery/stomachpump.dm b/code/modules/surgery/stomachpump.dm index 0c9a0ce564f68..25f067aef6505 100644 --- a/code/modules/surgery/stomachpump.dm +++ b/code/modules/surgery/stomachpump.dm @@ -46,7 +46,7 @@ span_notice("[user] forces [target_human] to vomit, cleansing their stomach of some chemicals!"), span_notice("[user] forces [target_human] to vomit!"), ) - target_human.vomit(20, FALSE, TRUE, 1, TRUE, FALSE, purge_ratio = 0.67) //higher purge ratio than regular vomiting + target_human.vomit((MOB_VOMIT_MESSAGE | MOB_VOMIT_STUN), lost_nutrition = 20, purge_ratio = 0.67) //higher purge ratio than regular vomiting return ..() /datum/surgery_step/stomach_pump/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) @@ -55,7 +55,7 @@ display_results( user, target, - span_warning("You screw up, brusing [target_human]'s chest!"), + span_warning("You screw up, bruising [target_human]'s chest!"), span_warning("[user] screws up, brusing [target_human]'s chest!"), span_warning("[user] screws up!"), ) diff --git a/code/modules/surgery/surgery_helpers.dm b/code/modules/surgery/surgery_helpers.dm index 922ef836dbb4c..ec33b47dca2f0 100644 --- a/code/modules/surgery/surgery_helpers.dm +++ b/code/modules/surgery/surgery_helpers.dm @@ -34,10 +34,10 @@ if(covered_locations & HEAD) return FALSE if(BODY_ZONE_PRECISE_EYES) - if(covered_locations & HEAD || face_covered & HIDEEYES || eyesmouth_covered & GLASSESCOVERSEYES) + if((face_covered & HIDEEYES) || (eyesmouth_covered & (MASKCOVERSEYES|HEADCOVERSEYES|GLASSESCOVERSEYES))) return FALSE if(BODY_ZONE_PRECISE_MOUTH) - if(covered_locations & HEAD || face_covered & HIDEFACE || eyesmouth_covered & MASKCOVERSMOUTH || eyesmouth_covered & HEADCOVERSMOUTH) + if((face_covered & HIDEFACE) || (eyesmouth_covered & (MASKCOVERSMOUTH|HEADCOVERSMOUTH))) return FALSE if(BODY_ZONE_CHEST) if(covered_locations & CHEST) diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index 342f984042fec..8c9782163bd00 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -51,7 +51,7 @@ if(get_location_accessible(target, target_zone) || (surgery.surgery_flags & SURGERY_IGNORE_CLOTHES)) initiate(user, target, target_zone, tool, surgery, try_to_fail) else - to_chat(user, span_warning("You need to expose [target]'s [parse_zone(target_zone)] to perform surgery on it!")) + to_chat(user, span_warning("You need to expose [target]'s [target.parse_zone_with_bodypart(target_zone)] to perform surgery on it!")) return TRUE //returns TRUE so we don't stab the guy in the dick or wherever. if(repeatable) @@ -112,7 +112,7 @@ modded_time = min(modded_time, time * SURGERY_SLOWDOWN_CAP_MULTIPLIER)//also if that, then cap modded_time at time*modifier if(iscyborg(user))//any immunities to surgery slowdown should go in this check. - modded_time = time + modded_time = time * tool.toolspeed var/was_sleeping = (target.stat != DEAD && target.IsSleeping()) diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index d24b1a5927157..85c1beab0a357 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -170,7 +170,7 @@ /obj/item/surgicaldrill/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] rams [src] into [user.p_their()] chest! It looks like [user.p_theyre()] trying to commit suicide!")) - addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living/carbon, gib), null, null, TRUE, TRUE), 25) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living/carbon, gib), null, null, TRUE, TRUE), 2.5 SECONDS) user.SpinAnimation(3, 10) playsound(user, 'sound/machines/juicer.ogg', 20, TRUE) return MANUAL_SUICIDE diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index 64bd496f2bbb3..754335494f98f 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -118,6 +118,8 @@ /datum/asset/simple/namespaced/fontawesome)) flush_queue |= window.send_asset(get_asset_datum( /datum/asset/simple/namespaced/tgfont)) + flush_queue |= window.send_asset(get_asset_datum( + /datum/asset/json/icon_ref_map)) for(var/datum/asset/asset in src_object.ui_assets(user)) flush_queue |= window.send_asset(asset) if (flush_queue) diff --git a/code/modules/tgui_input/list.dm b/code/modules/tgui_input/list.dm index 174f16fc7b57c..22c6d48edfc5a 100644 --- a/code/modules/tgui_input/list.dm +++ b/code/modules/tgui_input/list.dm @@ -111,7 +111,7 @@ /datum/tgui_list_input/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "ListInputModal") + ui = new(user, src, "ListInputWindow") ui.open() /datum/tgui_list_input/ui_close(mob/user) diff --git a/code/modules/tgui_input/say_modal/speech.dm b/code/modules/tgui_input/say_modal/speech.dm index 27e5776b3f1fe..0d95b855a15ff 100644 --- a/code/modules/tgui_input/say_modal/speech.dm +++ b/code/modules/tgui_input/say_modal/speech.dm @@ -45,7 +45,7 @@ client.ooc(entry) return TRUE if(ADMIN_CHANNEL) - client.cmd_admin_say(entry) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, entry) return TRUE return FALSE diff --git a/code/modules/tgui_input/say_modal/typing.dm b/code/modules/tgui_input/say_modal/typing.dm index a6367c088d694..7fc6a93f29425 100644 --- a/code/modules/tgui_input/say_modal/typing.dm +++ b/code/modules/tgui_input/say_modal/typing.dm @@ -38,42 +38,31 @@ /** Sets the mob as "thinking" - with indicator and the TRAIT_THINKING_IN_CHARACTER trait */ /datum/tgui_say/proc/start_thinking() - if(!window_open || !client.typing_indicators) + if(!window_open) return FALSE - /// Special exemptions - if(isabductor(client.mob)) - return FALSE - ADD_TRAIT(client.mob, TRAIT_THINKING_IN_CHARACTER, CURRENTLY_TYPING_TRAIT) - client.mob.create_thinking_indicator() + return client.start_thinking() /** Removes typing/thinking indicators and flags the mob as not thinking */ /datum/tgui_say/proc/stop_thinking() - client.mob?.remove_all_indicators() + return client.stop_thinking() /** * Handles the user typing. After a brief period of inactivity, * signals the client mob to revert to the "thinking" icon. */ /datum/tgui_say/proc/start_typing() - var/mob/client_mob = client.mob - client_mob.remove_thinking_indicator() - if(!window_open || !client.typing_indicators || !HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER)) + if(!window_open) return FALSE - client_mob.create_typing_indicator() - addtimer(CALLBACK(src, PROC_REF(stop_typing)), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE) + return client.start_typing() /** - * Callback to remove the typing indicator after a brief period of inactivity. + * Remove the typing indicator after a brief period of inactivity or during say events. * If the user was typing IC, the thinking indicator is shown. */ /datum/tgui_say/proc/stop_typing() - if(isnull(client?.mob)) - return FALSE - var/mob/client_mob = client.mob - client_mob.remove_typing_indicator() - if(!window_open || !client.typing_indicators || !HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER)) + if(!window_open) return FALSE - client_mob.create_thinking_indicator() + client.stop_typing() /// Overrides for overlay creation /mob/living/create_thinking_indicator() diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm index 22027a3cf8e13..9956305db26e0 100644 --- a/code/modules/tooltip/tooltip.dm +++ b/code/modules/tooltip/tooltip.dm @@ -85,7 +85,7 @@ Notes: queueHide = showing ? TRUE : FALSE if (queueHide) - addtimer(CALLBACK(src, PROC_REF(do_hide)), 1) + addtimer(CALLBACK(src, PROC_REF(do_hide)), 0.1 SECONDS) else do_hide() @@ -112,7 +112,7 @@ Notes: return var/ui_style = user.client?.prefs?.read_preference(/datum/preference/choiced/ui_style) if(!theme && ui_style) - theme = lowertext(ui_style) + theme = LOWER_TEXT(ui_style) if(!theme) theme = "default" user.client.tooltips.show(tip_src, params, title, content, theme) diff --git a/code/modules/transport/_transport_machinery.dm b/code/modules/transport/_transport_machinery.dm index 1cbbbdeb24b57..a51d6d840d372 100644 --- a/code/modules/transport/_transport_machinery.dm +++ b/code/modules/transport/_transport_machinery.dm @@ -95,7 +95,7 @@ /obj/machinery/transport/proc/clear_repair_signals() UnregisterSignal(src, repair_signals) - QDEL_LAZYLIST(repair_signals) + LAZYNULL(repair_signals) /obj/machinery/transport/examine(mob/user) . = ..() @@ -128,8 +128,8 @@ playsound(src, 'sound/machines/synth_yes.ogg', 75, use_reverb = TRUE) machine.balloon_alert(user, "success!") UnregisterSignal(src, repair_signals) - QDEL_LAZYLIST(repair_signals) - QDEL_LAZYLIST(methods_to_fix) + LAZYNULL(repair_signals) + methods_to_fix = list() malfunctioning = FALSE set_machine_stat(machine_stat & ~EMAGGED) set_is_operational(TRUE) diff --git a/code/modules/transport/admin.dm b/code/modules/transport/admin.dm index 9d68d967e60ae..63f1fbfd55a3b 100644 --- a/code/modules/transport/admin.dm +++ b/code/modules/transport/admin.dm @@ -1,23 +1,14 @@ -/** - * Helper tool to try and resolve tram controller errors, or reset the contents if someone put a million chickens on the tram - * and now it's slow as hell and lagging things. - */ -/datum/admins/proc/reset_tram() - set name = "Reset Tram" - set category = "Debug" +ADMIN_VERB(reset_tram, R_DEBUG|R_ADMIN, "Reset Tram", "Reset a tram controller or its contents.", ADMIN_CATEGORY_DEBUG) var/static/list/debug_tram_list = list( - TRAMSTATION_LINE_1, - BIRDSHOT_LINE_1, - BIRDSHOT_LINE_2, - HILBERT_LINE_1, + TRAMSTATION_LINE_1, + BIRDSHOT_LINE_1, + BIRDSHOT_LINE_2, + HILBERT_LINE_1, ) - if(!check_rights(R_DEBUG)) - return - var/datum/transport_controller/linear/tram/broken_controller - var/selected_transport_id = tgui_input_list(usr, "Which tram?", "Off the rails", debug_tram_list) - var/reset_type = tgui_input_list(usr, "How hard of a reset?", "How bad is it screwed up", list("Clear Tram Contents", "Controller", "Controller and Contents", "Delete Datum", "Cancel")) + var/selected_transport_id = tgui_input_list(user, "Which tram?", "Off the rails", debug_tram_list) + var/reset_type = tgui_input_list(user, "How hard of a reset?", "How bad is it screwed up", list("Clear Tram Contents", "Controller", "Controller and Contents", "Delete Datum", "Cancel")) if(isnull(reset_type) || reset_type == "Cancel") return @@ -28,40 +19,40 @@ break if(isnull(broken_controller)) - to_chat(usr, span_warning("Couldn't find a transport controller datum with ID [selected_transport_id]!")) + to_chat(user, span_warning("Couldn't find a transport controller datum with ID [selected_transport_id]!")) return switch(reset_type) if("Clear Tram Contents") - var/selection = tgui_alert(usr, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) + var/selection = tgui_alert(user, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) switch(selection) if("Contents") broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) - message_admins("[key_name_admin(usr)] performed a contents reset of tram ID [selected_transport_id].") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents reset.") + message_admins("[key_name_admin(user)] performed a contents reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a contents reset.") if("Contents and Players") broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = TRUE) - message_admins("[key_name_admin(usr)] performed a contents and player mob reset of tram ID [selected_transport_id].") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents and player mob reset.") + message_admins("[key_name_admin(user)] performed a contents and player mob reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a contents and player mob reset.") else return if("Controller") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a controller reset, force operational.") - message_admins("[key_name_admin(usr)] performed a controller reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a controller reset, force operational.") + message_admins("[key_name_admin(user)] performed a controller reset of tram ID [selected_transport_id].") broken_controller.set_operational(TRUE) broken_controller.reset_position() if("Controller and Contents") - var/selection = tgui_alert(usr, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) + var/selection = tgui_alert(user, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) switch(selection) if("Contents") - message_admins("[key_name_admin(usr)] performed a contents and controller reset of tram ID [selected_transport_id].") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents reset. Controller reset, force operational.") + message_admins("[key_name_admin(user)] performed a contents and controller reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a contents reset. Controller reset, force operational.") broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) if("Contents and Players") - message_admins("[key_name_admin(usr)] performed a contents/player/controller reset of tram ID [selected_transport_id].") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents and player mob reset. Controller reset, force operational.") + message_admins("[key_name_admin(user)] performed a contents/player/controller reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a contents and player mob reset. Controller reset, force operational.") broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = TRUE) else return @@ -70,7 +61,7 @@ broken_controller.reset_position() if("Delete Datum") - var/confirm = tgui_alert(usr, "Deleting [selected_transport_id] will make it unrecoverable this round. Are you sure?", "Delete tram ID [selected_transport_id]", list("Yes", "Cancel")) + var/confirm = tgui_alert(user, "Deleting [selected_transport_id] will make it unrecoverable this round. Are you sure?", "Delete tram ID [selected_transport_id]", list("Yes", "Cancel")) if(confirm != "Yes") return @@ -82,4 +73,4 @@ broken_controller.cycle_doors(CYCLE_OPEN, BYPASS_DOOR_CHECKS) broken_controller.estop() qdel(broken_controller) - message_admins("[key_name_admin(usr)] performed a datum delete of tram ID [selected_transport_id].") + message_admins("[key_name_admin(user)] performed a datum delete of tram ID [selected_transport_id].") diff --git a/code/modules/transport/elevator/elev_indicator.dm b/code/modules/transport/elevator/elev_indicator.dm index 7b34f2d610556..22b9334be5a39 100644 --- a/code/modules/transport/elevator/elev_indicator.dm +++ b/code/modules/transport/elevator/elev_indicator.dm @@ -36,11 +36,7 @@ /// The elevator's current floor relative to its lowest floor being 1 var/current_lift_floor = 1 -/obj/machinery/lift_indicator/Initialize(mapload) - . = ..() - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/lift_indicator/LateInitialize() +/obj/machinery/lift_indicator/post_machine_initialize() . = ..() for(var/datum/transport_controller/linear/possible_match as anything in SStransport.transports_by_type[TRANSPORT_TYPE_ELEVATOR]) diff --git a/code/modules/transport/elevator/elev_music_zone.dm b/code/modules/transport/elevator/elev_music_zone.dm index 1f09a00a68be6..045407fe7819a 100644 --- a/code/modules/transport/elevator/elev_music_zone.dm +++ b/code/modules/transport/elevator/elev_music_zone.dm @@ -67,7 +67,7 @@ GLOBAL_LIST_EMPTY(elevator_music) QDEL_LIST_ASSOC_VAL(tracked_mobs) return ..() -/datum/proximity_monitor/advanced/elevator_music_area/field_turf_crossed(mob/entered, turf/location) +/datum/proximity_monitor/advanced/elevator_music_area/field_turf_crossed(mob/entered, turf/old_location, turf/new_location) if (!istype(entered) || !entered.mind) return @@ -80,7 +80,7 @@ GLOBAL_LIST_EMPTY(elevator_music) tracked_mobs[entered] = null // Still add it to the list so we don't keep making this check RegisterSignal(entered, COMSIG_QDELETING, PROC_REF(mob_destroyed)) -/datum/proximity_monitor/advanced/elevator_music_area/field_turf_uncrossed(mob/exited, turf/location) +/datum/proximity_monitor/advanced/elevator_music_area/field_turf_uncrossed(mob/exited, turf/old_location, turf/new_location) if (!(exited in tracked_mobs)) return if (exited.z == host.z && get_dist(exited, host) <= current_range) diff --git a/code/modules/transport/elevator/elev_panel.dm b/code/modules/transport/elevator/elev_panel.dm index 24b6e0fa3175c..76b95922dfe66 100644 --- a/code/modules/transport/elevator/elev_panel.dm +++ b/code/modules/transport/elevator/elev_panel.dm @@ -60,19 +60,15 @@ AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) AddElement(/datum/element/contextual_screentip_bare_hands, lmb_text = "Send Elevator") - // Machinery returns lateload by default via parent, - // this is just here for redundancy's sake. - . = INITIALIZE_HINT_LATELOAD - maploaded = mapload - // Maploaded panels link in LateInitialize... + // Maploaded panels link in post_machine_initialize... if(mapload) return // And non-mapload panels link in Initialize link_with_lift(log_error = FALSE) -/obj/machinery/elevator_control_panel/LateInitialize() +/obj/machinery/elevator_control_panel/post_machine_initialize() . = ..() // If we weren't maploaded, we probably already linked (or tried to link) in Initialize(). if(!maploaded) diff --git a/code/modules/transport/tram/tram_controller.dm b/code/modules/transport/tram/tram_controller.dm index 8f5fae1deea95..51b8a32acafac 100644 --- a/code/modules/transport/tram/tram_controller.dm +++ b/code/modules/transport/tram/tram_controller.dm @@ -708,19 +708,20 @@ /obj/machinery/transport/tram_controller/hilbert configured_transport_id = HILBERT_LINE_1 - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/machinery/transport/tram_controller/wrench_act_secondary(mob/living/user, obj/item/tool) + return NONE /obj/machinery/transport/tram_controller/Initialize(mapload) . = ..() register_context() if(!id_tag) id_tag = assign_random_name() - return INITIALIZE_HINT_LATELOAD /** * Mapped or built tram cabinet isn't located on a transport module. */ -/obj/machinery/transport/tram_controller/LateInitialize(mapload) +/obj/machinery/transport/tram_controller/post_machine_initialize() . = ..() SStransport.hello(src, name, id_tag) find_controller() @@ -848,7 +849,7 @@ return playsound(loc, 'sound/items/deconstruct.ogg', 50, vary = TRUE) balloon_alert(user, "unsecured") - deconstruct() + deconstruct(TRUE) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/machinery/transport/tram_controller/screwdriver_act_secondary(mob/living/user, obj/item/tool) diff --git a/code/modules/transport/tram/tram_controls.dm b/code/modules/transport/tram/tram_controls.dm index 435b47f9d1bfd..0bfce56aa5c96 100644 --- a/code/modules/transport/tram/tram_controls.dm +++ b/code/modules/transport/tram/tram_controls.dm @@ -54,7 +54,7 @@ var/obj/item/circuitboard/computer/tram_controls/my_circuit = circuit split_mode = my_circuit.split_mode -/obj/machinery/computer/tram_controls/LateInitialize() +/obj/machinery/computer/tram_controls/post_machine_initialize() . = ..() if(!id_tag) id_tag = assign_random_name() diff --git a/code/modules/transport/tram/tram_displays.dm b/code/modules/transport/tram/tram_displays.dm index 47fe21f2ff19e..b228bb38e9bd3 100644 --- a/code/modules/transport/tram/tram_displays.dm +++ b/code/modules/transport/tram/tram_displays.dm @@ -51,7 +51,6 @@ TRAMSTATION_LINE_1, ) set_light(l_dir = REVERSE_DIR(dir)) - return INITIALIZE_HINT_LATELOAD /obj/machinery/transport/destination_sign/Destroy() SStransport.displays -= src @@ -61,7 +60,7 @@ . = ..() set_light(l_dir = REVERSE_DIR(dir)) -/obj/machinery/transport/destination_sign/indicator/LateInitialize(mapload) +/obj/machinery/transport/destination_sign/indicator/post_machine_initialize() . = ..() link_tram() diff --git a/code/modules/transport/tram/tram_doors.dm b/code/modules/transport/tram/tram_doors.dm index 7e21b93679119..644f45def4aa5 100644 --- a/code/modules/transport/tram/tram_doors.dm +++ b/code/modules/transport/tram/tram_doors.dm @@ -136,7 +136,7 @@ for(var/mob/living/future_pancake in checked_turf) future_pancake.visible_message(span_warning("[src] beeps angrily and closes on [future_pancake]!"), span_userdanger("[src] beeps angrily and closes on you!")) SEND_SIGNAL(future_pancake, COMSIG_LIVING_DOORCRUSHED, src) - if(ishuman(future_pancake) || ismonkey(future_pancake)) + if(ishuman(future_pancake)) future_pancake.emote("scream") future_pancake.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 2) future_pancake.Paralyze(2 SECONDS) @@ -184,7 +184,7 @@ RemoveElement(/datum/element/atmos_sensitive, mapload) return INITIALIZE_HINT_LATELOAD -/obj/machinery/door/airlock/tram/LateInitialize(mapload) +/obj/machinery/door/airlock/tram/post_machine_initialize() . = ..() INVOKE_ASYNC(src, PROC_REF(open)) SStransport.doors += src diff --git a/code/modules/transport/tram/tram_machinery.dm b/code/modules/transport/tram/tram_machinery.dm index 7371447d08244..99375bfbaf578 100644 --- a/code/modules/transport/tram/tram_machinery.dm +++ b/code/modules/transport/tram/tram_machinery.dm @@ -37,8 +37,7 @@ . = ..() return INITIALIZE_HINT_LATELOAD -/obj/item/assembly/control/transport/call_button/LateInitialize(mapload) - . = ..() +/obj/item/assembly/control/transport/call_button/LateInitialize() if(!id_tag) id_tag = assign_random_name() SStransport.hello(src, name, id_tag) diff --git a/code/modules/transport/tram/tram_power.dm b/code/modules/transport/tram/tram_power.dm index ff0251e909052..45c48766db81d 100644 --- a/code/modules/transport/tram/tram_power.dm +++ b/code/modules/transport/tram/tram_power.dm @@ -15,11 +15,7 @@ /// The tram platform we're connected to and providing power var/obj/effect/landmark/transport/nav_beacon/tram/platform/connected_platform -/obj/machinery/transport/power_rectifier/Initialize(mapload) - . = ..() - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/transport/power_rectifier/LateInitialize(mapload) +/obj/machinery/transport/power_rectifier/post_machine_initialize() . = ..() RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(power_tram)) find_platform() diff --git a/code/modules/transport/tram/tram_remote.dm b/code/modules/transport/tram/tram_remote.dm index 4176117d8b2f8..3a45ec4e6650e 100644 --- a/code/modules/transport/tram/tram_remote.dm +++ b/code/modules/transport/tram/tram_remote.dm @@ -107,12 +107,9 @@ SEND_SIGNAL(src, COMSIG_TRANSPORT_REQUEST, specific_transport_id, destination, options) -/obj/item/assembly/control/transport/remote/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return - +/obj/item/assembly/control/transport/remote/click_alt(mob/user) link_tram(user) + return CLICK_ACTION_SUCCESS /obj/item/assembly/control/transport/remote/proc/link_tram(mob/user) specific_transport_id = null diff --git a/code/modules/transport/tram/tram_signals.dm b/code/modules/transport/tram/tram_signals.dm index 101ae1027a306..eb64866603043 100644 --- a/code/modules/transport/tram/tram_signals.dm +++ b/code/modules/transport/tram/tram_signals.dm @@ -107,9 +107,8 @@ RegisterSignal(SStransport, COMSIG_COMMS_STATUS, PROC_REF(comms_change)) SStransport.crossing_signals += src register_context() - return INITIALIZE_HINT_LATELOAD -/obj/machinery/transport/crossing_signal/LateInitialize(mapload) +/obj/machinery/transport/crossing_signal/post_machine_initialize() . = ..() link_tram() link_sensor() @@ -170,20 +169,16 @@ obj_flags |= EMAGGED return TRUE -/obj/machinery/transport/crossing_signal/AltClick(mob/living/user) - . = ..() - if(!can_interact(user)) - return - +/obj/machinery/transport/crossing_signal/click_alt(mob/living/user) var/obj/item/tool = user.get_active_held_item() if(!panel_open || tool?.tool_behaviour != TOOL_WRENCH) - return FALSE + return CLICK_ACTION_BLOCKING tool.play_tool_sound(src, 50) setDir(turn(dir,-90)) - to_chat(user, span_notice("You rotate [src].")) + balloon_alert(user, "rotated") find_uplink() - return TRUE + return CLICK_ACTION_SUCCESS /obj/machinery/transport/crossing_signal/attackby_secondary(obj/item/weapon, mob/user, params) . = ..() @@ -510,9 +505,8 @@ /obj/machinery/transport/guideway_sensor/Initialize(mapload) . = ..() SStransport.sensors += src - return INITIALIZE_HINT_LATELOAD -/obj/machinery/transport/guideway_sensor/LateInitialize(mapload) +/obj/machinery/transport/guideway_sensor/post_machine_initialize() . = ..() pair_sensor() RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(wake_up)) diff --git a/code/modules/transport/tram/tram_structures.dm b/code/modules/transport/tram/tram_structures.dm index 74532d87be76d..368223d11653b 100644 --- a/code/modules/transport/tram/tram_structures.dm +++ b/code/modules/transport/tram/tram_structures.dm @@ -212,14 +212,12 @@ return ..() -/obj/structure/tram/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - if(mineral_amount) - for(var/i in 1 to mineral_amount) - new mineral(loc) - qdel(src) +/obj/structure/tram/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + if(mineral_amount) + for(var/i in 1 to mineral_amount) + new mineral(loc) /obj/structure/tram/attackby(obj/item/item, mob/user, params) . = ..() @@ -488,7 +486,6 @@ return INITIALIZE_HINT_LATELOAD /obj/structure/tram/spoiler/LateInitialize() - . = ..() RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(set_spoiler)) /obj/structure/tram/spoiler/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/modules/transport/transport_module.dm b/code/modules/transport/transport_module.dm index baa6d9d0fc82d..a2ba6f5167b47 100644 --- a/code/modules/transport/transport_module.dm +++ b/code/modules/transport/transport_module.dm @@ -96,7 +96,6 @@ return INITIALIZE_HINT_LATELOAD /obj/structure/transport/linear/LateInitialize() - . = ..() //after everything is initialized the transport controller can order everything transport_controller_datum.order_platforms_by_z_level() @@ -908,7 +907,7 @@ new overlay(our_turf) turfs += our_turf - addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 1) + addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 0.1 SECONDS) /obj/structure/transport/linear/tram/proc/clear_turfs(list/turfs_to_clear, iterations) for(var/turf/our_old_turf as anything in turfs_to_clear) @@ -928,7 +927,7 @@ turfs += our_turf if(iterations) - addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 1) + addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 0.1 SECONDS) /obj/structure/transport/linear/tram/proc/estop_throw(throw_direction) for(var/mob/living/passenger in transport_contents) diff --git a/code/modules/tutorials/_tutorial.dm b/code/modules/tutorials/_tutorial.dm index 7819a9e2b85ac..aecdcb7f23b88 100644 --- a/code/modules/tutorials/_tutorial.dm +++ b/code/modules/tutorials/_tutorial.dm @@ -13,8 +13,7 @@ /datum/tutorial/New(mob/user) src.user = user - RegisterSignal(user, COMSIG_QDELETING, PROC_REF(destroy_self)) - RegisterSignal(user.client, COMSIG_QDELETING, PROC_REF(destroy_self)) + RegisterSignals(user, list(COMSIG_QDELETING, COMSIG_MOB_LOGOUT), PROC_REF(destroy_self)) /datum/tutorial/Destroy(force) user.client?.screen -= instruction_screen @@ -242,7 +241,13 @@ /// Dismisses the tutorial, not marking it as completed in the database. /// Call `/datum/tutorial/proc/dismiss()` instead. /datum/tutorial_manager/proc/dismiss(mob/user) - performing_ckeys -= user.ckey + // this can be null in some disconnect/mob logout cases so we use some fallbacks + var/user_ckey = user.ckey + if(!user_ckey && user.canon_client) + user_ckey = user.canon_client.ckey + if(!user_ckey && user.mind?.key) + user_ckey = ckey(user.mind.key) + performing_ckeys -= user_ckey /// Given a ckey, will mark them as being completed without affecting the database. /// Call `/datum/tutorial/proc/complete()` instead. diff --git a/code/modules/tutorials/tutorial_instruction.dm b/code/modules/tutorials/tutorial_instruction.dm index 05c95e2f7540d..0ad9ce6f2e0fe 100644 --- a/code/modules/tutorials/tutorial_instruction.dm +++ b/code/modules/tutorials/tutorial_instruction.dm @@ -7,7 +7,6 @@ layer = TUTORIAL_INSTRUCTIONS_LAYER mouse_opacity = MOUSE_OPACITY_TRANSPARENT - var/client/client var/atom/movable/screen/tutorial_instruction_text/instruction_text /atom/movable/screen/tutorial_instruction/Initialize(mapload, datum/hud/hud_owner, message, client/client) @@ -15,14 +14,12 @@ transform = transform.Scale(36, 2.5) - src.client = client animate(src, alpha = 245, time = 0.8 SECONDS, easing = SINE_EASING) instruction_text = new(src, null, message, client) vis_contents += instruction_text /atom/movable/screen/tutorial_instruction/Destroy() - client = null QDEL_NULL(instruction_text) return ..() diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 44739168ce10e..e6275bc02e1e0 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -101,6 +101,7 @@ #include "bespoke_id.dm" #include "binary_insert.dm" #include "bitrunning.dm" +#include "blackmarket.dm" #include "blindness.dm" #include "bloody_footprints.dm" #include "breath.dm" @@ -108,6 +109,7 @@ #include "cable_powernets.dm" #include "card_mismatch.dm" #include "cardboard_cutouts.dm" +#include "cargo_dep_order_locations.dm" #include "cargo_selling.dm" #include "chain_pull_through_space.dm" #include "changeling.dm" @@ -117,6 +119,7 @@ #include "closets.dm" #include "clothing_under_armor_subtype_check.dm" #include "combat.dm" +#include "combat_welder.dm" #include "component_tests.dm" #include "confusion.dm" #include "connect_loc.dm" @@ -168,6 +171,7 @@ #include "ling_decap.dm" #include "liver.dm" #include "load_map_security.dm" +#include "lootpanel.dm" #include "lungs.dm" #include "machine_disassembly.dm" #include "mafia.dm" @@ -255,6 +259,7 @@ #include "station_trait_tests.dm" #include "status_effect_ticks.dm" #include "stomach.dm" +#include "storage.dm" #include "strange_reagent.dm" #include "strippable.dm" #include "stuns.dm" diff --git a/code/modules/unit_tests/blackmarket.dm b/code/modules/unit_tests/blackmarket.dm new file mode 100644 index 0000000000000..984e2ea815503 --- /dev/null +++ b/code/modules/unit_tests/blackmarket.dm @@ -0,0 +1,23 @@ +/// Ensures black market items have acceptable variable values. +/datum/unit_test/blackmarket + +/datum/unit_test/blackmarket/Run() + for(var/datum/market_item/prototype as anything in subtypesof(/datum/market_item)) + if(prototype::abstract_path == prototype) //skip abstract paths + continue + if(!prototype::category) + TEST_FAIL("[prototype] doesn't have a set category (or the abstract path var isn't correctly set)") + continue + if(!prototype::item) + TEST_FAIL("[prototype] doesn't have a set item (or the abstract path var isn't correctly set)") + continue + if(isnull(prototype::price) && prototype::price_max <= prototype::price_min) + TEST_FAIL("[prototype] doesn't have a correctly set random price (price_max should be higher than price_min)") + if(isnull(prototype::stock) && prototype::stock_max < prototype::stock_min) + TEST_FAIL("[prototype] doesn't have a correctly set random stock (stock_max shouldn't be lower than stock_min)") + if(!isnum(prototype::availability_prob)) + TEST_FAIL("[prototype] doesn't have a set availability_prob (must be a number)") + if(!prototype::name) + TEST_FAIL("[prototype] doesn't have a set name") + if(!prototype::desc) + TEST_FAIL("[prototype] doesn't have a set desc") diff --git a/code/modules/unit_tests/cargo_dep_order_locations.dm b/code/modules/unit_tests/cargo_dep_order_locations.dm new file mode 100644 index 0000000000000..106a0eb19a76b --- /dev/null +++ b/code/modules/unit_tests/cargo_dep_order_locations.dm @@ -0,0 +1,18 @@ +/datum/unit_test/cargo_dep_order_locations + +/datum/unit_test/cargo_dep_order_locations/Run() + for(var/datum/job_department/department as anything in SSjob.joinable_departments) + var/delivery_areas = department.department_delivery_areas + if(!length(delivery_areas)) + continue + if(check_valid_delivery_location(delivery_areas)) + continue + TEST_FAIL("[department.type] failed to find a valid delivery location on this map.") + + +/datum/unit_test/cargo_dep_order_locations/proc/check_valid_delivery_location(list/delivery_areas) + for(var/delivery_area_type in delivery_areas) + + if(GLOB.areas_by_type[delivery_area_type]) + return TRUE + return FALSE diff --git a/code/modules/unit_tests/combat_welder.dm b/code/modules/unit_tests/combat_welder.dm new file mode 100644 index 0000000000000..2fa9052d6fba0 --- /dev/null +++ b/code/modules/unit_tests/combat_welder.dm @@ -0,0 +1,26 @@ +/datum/unit_test/welder_combat + +/datum/unit_test/welder_combat/Run() + var/mob/living/carbon/human/tider = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + var/mob/living/carbon/human/victim = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + var/obj/item/weldingtool/weapon = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + + tider.put_in_active_hand(weapon, forced = TRUE) + tider.set_combat_mode(TRUE) + weapon.attack_self(tider) + weapon.melee_attack_chain(tider, victim) + + TEST_ASSERT_NOTEQUAL(victim.getFireLoss(), 0, "Victim did not get burned by welder.") + TEST_ASSERT_EQUAL(weapon.get_fuel(), weapon.max_fuel - 1, "Welder did not consume fuel on attacking a mob") + + var/obj/structure/blob/blobby = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + weapon.melee_attack_chain(tider, blobby) + + TEST_ASSERT_NOTEQUAL(blobby.get_integrity(), blobby.max_integrity, "Blob did not get burned by welder.") + TEST_ASSERT_EQUAL(weapon.get_fuel(), weapon.max_fuel - 2, "Welder did not consume fuel on attacking a blob") + + weapon.force = 999 + weapon.melee_attack_chain(tider, blobby) + + TEST_ASSERT(QDELETED(blobby), "Blob was not destroyed by welder.") + TEST_ASSERT_EQUAL(weapon.get_fuel(), weapon.max_fuel - 3, "Welder did not consume fuel on deleting a blob") diff --git a/code/modules/unit_tests/limbsanity.dm b/code/modules/unit_tests/limbsanity.dm index 9988c7471e297..6efec37ab76d5 100644 --- a/code/modules/unit_tests/limbsanity.dm +++ b/code/modules/unit_tests/limbsanity.dm @@ -2,37 +2,11 @@ /datum/unit_test/limbsanity/Run() for(var/path in subtypesof(/obj/item/bodypart) - list(/obj/item/bodypart/arm, /obj/item/bodypart/leg)) /// removes the abstract items. - var/obj/item/bodypart/part = new path(null) - if(part.is_dimorphic) - if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]_m")) + var/obj/item/bodypart/part = path + if(part::is_dimorphic) + if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]_m")) TEST_FAIL("[path] does not have a valid icon for male variants") - if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]_f")) + if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]_f")) TEST_FAIL("[path] does not have a valid icon for female variants") - else if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]")) + else if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]")) TEST_FAIL("[path] does not have a valid icon") - -/// Tests the height adjustment system which dynamically changes how much the chest, head, and arms of a carbon are adjusted upwards or downwards based on the length of their legs and chest. -/datum/unit_test/limb_height_adjustment - -/datum/unit_test/limb_height_adjustment/Run() - var/mob/living/carbon/human/john_doe = allocate(/mob/living/carbon/human/consistent) - var/mob/living/carbon/human/species/monkey/monkey = allocate(/mob/living/carbon/human/species/monkey) - var/mob/living/carbon/human/tallboy = allocate(/mob/living/carbon/human/consistent) - - tallboy.set_species(/datum/species/human/tallboy) - TEST_ASSERT_EQUAL(john_doe.get_top_offset(), 0, "John Doe found to have a top offset other than zero.") - TEST_ASSERT_EQUAL(monkey.get_top_offset(), -8, "Monkey found to have a top offset other than -8.") - TEST_ASSERT_EQUAL(tallboy.get_top_offset(), 23, "Tallboy human varient found to have a top offset other than 23.") - - - var/obj/item/bodypart/leg/left/monkey/left_monky_leg = allocate(/obj/item/bodypart/leg/left/monkey) - var/obj/item/bodypart/leg/right/monkey/right_monky_leg = allocate(/obj/item/bodypart/leg/right/monkey) - - left_monky_leg.replace_limb(john_doe, TRUE) - - TEST_ASSERT_EQUAL(john_doe.get_top_offset(), 0, "John Doe has a top offset other than 0 with one human leg and one monkey leg.") - - right_monky_leg.replace_limb(john_doe, TRUE) - - TEST_ASSERT_EQUAL(john_doe.get_top_offset(), -3, "John Doe has a top offset other than -3 with two monkey legs.") - diff --git a/code/modules/unit_tests/lootpanel.dm b/code/modules/unit_tests/lootpanel.dm new file mode 100644 index 0000000000000..1903c22d54652 --- /dev/null +++ b/code/modules/unit_tests/lootpanel.dm @@ -0,0 +1,35 @@ +/datum/unit_test/lootpanel + abstract_type = /datum/unit_test/lootpanel + +/datum/unit_test/lootpanel/contents/Run() + var/datum/client_interface/mock_client = new() + var/datum/lootpanel/panel = new(mock_client) + var/mob/living/carbon/human/labrat = allocate(/mob/living/carbon/human/consistent) + mock_client.mob = labrat + var/turf/one_over = locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z) + var/obj/item/storage/toolbox/box = allocate(/obj/item/storage/toolbox, one_over) + + panel.open(one_over) + TEST_ASSERT_EQUAL(length(panel.contents), 2, "Contents should populate on open") + TEST_ASSERT_EQUAL(length(panel.to_image), 2, "to_image should've populated (unit testing)") + TEST_ASSERT_EQUAL(panel.contents[1].item, one_over, "First item should be the source turf") + + var/datum/search_object/searchable = panel.contents[2] + TEST_ASSERT_EQUAL(searchable.item, box, "Second item should be the box") + + qdel(box) + TEST_ASSERT_EQUAL(length(panel.contents), 1, "Contents should update on searchobj deleted") + TEST_ASSERT_EQUAL(length(panel.to_image), 1, "to_image should update on searchobj deleted") + + allocate(/obj/item/storage/toolbox, one_over) + TEST_ASSERT_EQUAL(length(panel.contents), 1, "Contents shouldn't update, we're dumb") + TEST_ASSERT_EQUAL(length(panel.to_image), 1, "to_image shouldn't update, we're dumb") + + panel.populate_contents() // this also calls reset_contents bc length(contents) + TEST_ASSERT_EQUAL(length(panel.contents), 2, "Contents should repopulate with the new toolbox") + + panel.populate_contents() + TEST_ASSERT_EQUAL(length(panel.contents), 2, "Panel shouldnt dupe searchables if reopened") + + mock_client.mob = null + diff --git a/code/modules/unit_tests/mouse_bite_cable.dm b/code/modules/unit_tests/mouse_bite_cable.dm index 6d3150d279d6a..df77976ce47ce 100644 --- a/code/modules/unit_tests/mouse_bite_cable.dm +++ b/code/modules/unit_tests/mouse_bite_cable.dm @@ -19,6 +19,9 @@ // Ai controlling processes expect a seconds_per_tick, supply a real-fake dt var/fake_dt = SSai_controllers.wait * 0.1 + // Set AI - AIs by default are off in z-levels with no client, we have to force it on. + biter.ai_controller.set_ai_status(AI_STATUS_ON) + biter.ai_controller.can_idle = FALSE // Select behavior - this will queue finding the cable biter.ai_controller.SelectBehaviors(fake_dt) // Process behavior - this will execute the "locate the cable" behavior diff --git a/code/modules/unit_tests/organ_set_bonus.dm b/code/modules/unit_tests/organ_set_bonus.dm index a9e9a8805f9c4..967803e223f17 100644 --- a/code/modules/unit_tests/organ_set_bonus.dm +++ b/code/modules/unit_tests/organ_set_bonus.dm @@ -22,7 +22,7 @@ /datum/infuser_entry/fly, )) // Fetch the globally instantiated DNA Infuser entries. - for(var/datum/infuser_entry/infuser_entry as anything in GLOB.infuser_entries) + for(var/datum/infuser_entry/infuser_entry as anything in flatten_list(GLOB.infuser_entries)) var/output_organs = infuser_entry.output_organs var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent) var/list/obj/item/organ/inserted_organs = list() diff --git a/code/modules/unit_tests/preference_species.dm b/code/modules/unit_tests/preference_species.dm index 8e49f49cdd6a4..8d913cc8fb64d 100644 --- a/code/modules/unit_tests/preference_species.dm +++ b/code/modules/unit_tests/preference_species.dm @@ -12,7 +12,7 @@ for(var/species_id in get_selectable_species()) var/species_type = GLOB.species_list[species_id] - var/datum/species/species = new species_type() + var/datum/species/species = GLOB.species_prototypes[species_type] // Check the species decription. // If it's not overridden, a stack trace will be thrown (and fail the test). @@ -29,5 +29,3 @@ TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore().") else if(!islist(species_lore)) TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore() (Did not return a list).") - - qdel(species) diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png index 1d5f88bd8407f..558916cdd4550 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_tallboy.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_tallboy.png deleted file mode 100644 index 262353dc0a95a..0000000000000 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_tallboy.png and /dev/null differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png index e0d02f4302f43..5fd259a0ed4fa 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_human_legged.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_human_legged.png deleted file mode 100644 index 285c0a660ca89..0000000000000 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_human_legged.png and /dev/null differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_monkey_freak.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_monkey_freak.png deleted file mode 100644 index dc13acaeffcc7..0000000000000 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_monkey_freak.png and /dev/null differ diff --git a/code/modules/unit_tests/storage.dm b/code/modules/unit_tests/storage.dm new file mode 100644 index 0000000000000..82ac035ed7ea6 --- /dev/null +++ b/code/modules/unit_tests/storage.dm @@ -0,0 +1,22 @@ +/// Test storage datums +/datum/unit_test/storage + +/datum/unit_test/storage/Run() + var/obj/item/big_thing = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + big_thing.w_class = WEIGHT_CLASS_BULKY + var/obj/item/small_thing = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + small_thing.w_class = WEIGHT_CLASS_SMALL + + var/obj/item/storage/backpack/storage_item = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + + storage_item.atom_storage.attempt_insert(big_thing) + TEST_ASSERT_NOTEQUAL(big_thing.loc, storage_item, "A bulky item should have failed to insert into a backpack") + + storage_item.atom_storage.attempt_insert(small_thing) + TEST_ASSERT_EQUAL(small_thing.loc, storage_item, "A small item should have successfully inserted into a backpack") + + small_thing.update_weight_class(WEIGHT_CLASS_NORMAL) + TEST_ASSERT_EQUAL(small_thing.loc, storage_item, "A small item changed into normal size should not have ejected from the backpack") + + small_thing.update_weight_class(WEIGHT_CLASS_BULKY) + TEST_ASSERT_NOTEQUAL(small_thing.loc, storage_item, "A small item changed back into bulky size should have ejected from the backpack") diff --git a/code/modules/unit_tests/suit_storage_icons.dm b/code/modules/unit_tests/suit_storage_icons.dm index 8c77b0524112b..12305e7abfc0b 100644 --- a/code/modules/unit_tests/suit_storage_icons.dm +++ b/code/modules/unit_tests/suit_storage_icons.dm @@ -10,18 +10,13 @@ continue wearable_item_paths |= item_path - for(var/clothing_path in (subtypesof(/obj/item/clothing) - typesof(/obj/item/clothing/head/mob_holder) - typesof(/obj/item/clothing/suit/space/santa))) //mob_holder is a psuedo abstract item. santa suit is a VERY SNOWFLAKE admin spawn suit that can hold /every/ possible item. - var/obj/item/clothing/spawned_item = new clothing_path - for(var/path in spawned_item.allowed) //find all usable suit storage stuff. + for(var/obj/item/clothing/clothing_path in (subtypesof(/obj/item/clothing) - typesof(/obj/item/clothing/head/mob_holder) - typesof(/obj/item/clothing/suit/space/santa))) //mob_holder is a psuedo abstract item. santa suit is a VERY SNOWFLAKE admin spawn suit that can hold /every/ possible item. + for(var/path in clothing_path::allowed) //find all usable suit storage stuff. wearable_item_paths |= path - qdel(spawned_item) - for(var/mod_path in subtypesof(/obj/item/mod/control)) - var/obj/item/mod/control/control_mod = new - for(var/path in control_mod.chestplate.allowed) + for(var/obj/item/mod/control/mod_path in subtypesof(/obj/item/mod/control)) + for(var/path in mod_path::chestplate::allowed) wearable_item_paths |= path - qdel(control_mod) - var/list/already_warned_icons = list() var/count = 1 //to be removed once the test goes live / into CI failure mode. diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 332005070d5b6..9a6f89fddc353 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -340,7 +340,7 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) if(length(focused_tests)) tests_to_run = focused_tests - tests_to_run = sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority)) + sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority)) var/list/test_results = list() diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index f0f7b0accaf5e..e17488bc96a6d 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -71,7 +71,7 @@ /// If this uplink item is only available to certain roles. Roles are dependent on the frequency chip or stored ID. var/list/restricted_roles = list() /// The species able to purchase this uplink item. - var/restricted_species = list() + var/list/restricted_species = list() /// The minimum amount of progression needed for this item to be added to uplinks. var/progression_minimum = 0 /// Whether this purchase is visible in the purchase log. diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm index f18cc9a565eb1..c8486f4b5d008 100644 --- a/code/modules/uplink/uplink_items/nukeops.dm +++ b/code/modules/uplink/uplink_items/nukeops.dm @@ -475,6 +475,14 @@ Its chameleon projector lets it disguise itself as a Nanotrasen cyborg, on top it has thermal vision and a pinpointer." item = /obj/item/antag_spawner/nuke_ops/borg_tele/saboteur +/datum/uplink_item/reinforcements/overwatch_agent + name = "Overwatch Intelligence Agent" + desc = "An Overwatch Intelligence Agent is assigned to your operation. They can view your progress and help coordinate using your \ + operative team's body-cams. They can also pilot the shuttle remotely and view the station's camera net. \ + If you're a meathead who's just here to kill people and don't care about strategising or intel, you'll still have someone to bear witness to your murder-spree!" + item = /obj/item/antag_spawner/nuke_ops/overwatch + cost = 12 + // ~~ Disposable Sentry Gun ~~ // Technically not a spawn but it is a kind of reinforcement...I guess. diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index a64bd4d1c370b..ca1728f3fc043 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -36,11 +36,11 @@ hud_possible = list(DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD, DIAG_CAMERA_HUD) mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse.dmi' ///How much energy the mech will consume each time it moves. this is the current active energy consumed - var/step_energy_drain = 8 KILO JOULES + var/step_energy_drain = 0.008 * STANDARD_CELL_CHARGE ///How much energy we drain each time we mechpunch someone - var/melee_energy_drain = 15 KILO JOULES + var/melee_energy_drain = 0.015 * STANDARD_CELL_CHARGE ///Power we use to have the lights on - var/light_power_drain = 2 KILO WATTS + var/light_power_drain = 0.002 * STANDARD_CELL_RATE ///Modifiers for directional damage reduction var/list/facing_modifiers = list(MECHA_FRONT_ARMOUR = 0.5, MECHA_SIDE_ARMOUR = 1, MECHA_BACK_ARMOUR = 1.5) ///if we cant use our equipment(such as due to EMP) @@ -269,8 +269,12 @@ AddElement(/datum/element/hostile_machine) /obj/vehicle/sealed/mecha/Destroy() - for(var/ejectee in occupants) - mob_exit(ejectee, silent = TRUE) + /// If the former occupants get polymorphed, mutated, chestburstered, + /// or otherwise replaced by another mob, that mob is no longer in .occupants + /// and gets deleted with the mech. However, they do remain in .contents + var/list/potential_occupants = contents | occupants + for(var/mob/buggy_ejectee in potential_occupants) + mob_exit(buggy_ejectee, silent = TRUE, forced = TRUE) if(LAZYLEN(flat_equipment)) for(var/obj/item/mecha_parts/mecha_equipment/equip as anything in flat_equipment) @@ -324,7 +328,7 @@ for(var/mob/living/occupant as anything in occupants) if(isAI(occupant)) var/mob/living/silicon/ai/ai = occupant - if(!ai.linked_core) // we probably shouldnt gib AIs with a core + if(!ai.linked_core && !ai.can_shunt) // we probably shouldnt gib AIs with a core or shunting abilities unlucky_ai = occupant ai.investigate_log("has been gibbed by having their mech destroyed.", INVESTIGATE_DEATHS) ai.gib(DROP_ALL_REMAINS) //No wreck, no AI to recover @@ -703,6 +707,26 @@ target.mech_melee_attack(src, user) TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MELEE_ATTACK, melee_cooldown) + +/// Driver alt clicks anything while in mech +/obj/vehicle/sealed/mecha/proc/on_click_alt(mob/user, atom/target, params) + SIGNAL_HANDLER + + . = COMSIG_MOB_CANCEL_CLICKON // Cancel base_click_alt + + if(target != src) + return + + if(!(user in occupants)) + return + + if(!(user in return_controllers_with_flag(VEHICLE_CONTROL_DRIVE))) + to_chat(user, span_warning("You're in the wrong seat to control movement.")) + return + + toggle_strafe() + + /// middle mouse click signal wrapper for AI users /obj/vehicle/sealed/mecha/proc/on_middlemouseclick(mob/user, atom/target, params) SIGNAL_HANDLER diff --git a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm index 83167bf29e219..b1e0d84f14ebe 100644 --- a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm @@ -17,12 +17,12 @@ /obj/item/mecha_parts/mecha_equipment/medical/sleeper name = "mounted sleeper" - desc = "Equipment for medical exosuits. A mounted sleeper that stabilizes patients and can inject reagents in the exosuit's reserves." + desc = "Equipment for medical exosuits. A mounted sleeper that stabilizes patients and can inject reagents from a equipped exosuit syringe gun." icon_state = "mecha_sleeper" energy_drain = 20 range = MECHA_MELEE equip_cooldown = 20 - ///ref to the patient loaded in the sleeper + /// ref to the patient loaded in the sleeper var/mob/living/carbon/patient /// amount of chems to inject into patient from other hands syringe gun var/inject_amount = 10 @@ -32,15 +32,47 @@ content.forceMove(get_turf(src)) return ..() +/obj/item/mecha_parts/mecha_equipment/medical/proc/get_reagent_data(list/datum/reagent/reagent_list) + var/list/contained_reagents = list() + if(length(reagent_list)) + for(var/datum/reagent/reagent as anything in reagent_list) + contained_reagents += list(list("name" = reagent.name, "volume" = round(reagent.volume, 0.01))) // list in a list because Byond merges the first list... + return contained_reagents + /obj/item/mecha_parts/mecha_equipment/medical/sleeper/get_snowflake_data() var/list/data = list("snowflake_id" = MECHA_SNOWFLAKE_ID_SLEEPER) - if(!patient) + if(isnull(patient)) return data + var/patient_state + switch(patient.stat) + if(0) + patient_state = "Conscious" + if(1) + patient_state = "Unconscious" + if(2) + patient_state = "*dead*" + else + patient_state = "Unknown" + var/core_temp = "" + if(ishuman(patient)) + var/mob/living/carbon/human/humi = patient + core_temp = humi.bodytemperature-T0C data["patient"] = list( - "patientname" = patient.name, - "is_dead" = patient.stat == DEAD, + "patient_name" = patient.name, "patient_health" = patient.health/patient.maxHealth, + "patient_state" = patient_state, + "core_temp" = core_temp, + "brute_loss" = patient.getBruteLoss(), + "burn_loss" = patient.getFireLoss(), + "toxin_loss" = patient.getToxLoss(), + "oxygen_loss" = patient.getOxyLoss(), ) + data["has_brain_damage"] = patient.get_organ_loss(ORGAN_SLOT_BRAIN) != 0 + data["has_traumas"] = length(patient.get_traumas()) != 0 + data["contained_reagents"] = get_reagent_data(patient.reagents.reagent_list) + + var/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/shooter = locate(/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun) in chassis + data["injectible_reagents"] = get_reagent_data(shooter.reagents.reagent_list) return data /obj/item/mecha_parts/mecha_equipment/medical/sleeper/handle_ui_act(action, list/params) @@ -48,10 +80,13 @@ if("eject") go_out() return TRUE - if("view_stats") - usr << browse(get_patient_stats(),"window=msleeper") - onclose(usr, "msleeper") - return FALSE + var/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/shooter = locate() in chassis + for(var/datum/reagent/medication in shooter.reagents.reagent_list) + if(action == ("inject_reagent_" + medication.name)) + inject_reagent(medication, shooter) + break // or maybe return TRUE? i'm not certain + + return FALSE /obj/item/mecha_parts/mecha_equipment/medical/sleeper/action(mob/source, atom/atomtarget, list/modifiers) if(!action_checks(atomtarget)) @@ -59,7 +94,7 @@ if(!iscarbon(atomtarget)) return var/mob/living/carbon/target = atomtarget - if(!patient_insertion_check(target)) + if(!patient_insertion_check(target, source)) return to_chat(source, "[icon2html(src, source)][span_notice("You start putting [target] into [src]...")]") chassis.visible_message(span_warning("[chassis] starts putting [target] into \the [src].")) @@ -76,7 +111,7 @@ return ..() /obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/patient_insertion_check(mob/living/carbon/target, mob/user) - if(target.buckled) + if(!isnull(target.buckled)) to_chat(user, "[icon2html(src, user)][span_warning("[target] will not fit into the sleeper because [target.p_theyre()] buckled to [target.buckled]!")]") return FALSE if(target.has_buckled_mobs()) @@ -103,92 +138,7 @@ STOP_PROCESSING(SSobj, src) return ..() -/obj/item/mecha_parts/mecha_equipment/medical/sleeper/Topic(href,href_list) - . = ..() - if(.) - return - if(!(usr in chassis.occupants)) - return - if(href_list["inject"]) - var/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG = locate() in chassis - var/datum/reagent/R = locate(href_list["inject"]) in SG.reagents.reagent_list - if(istype(R)) - inject_reagent(R, SG) - -/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_patient_stats() - if(!patient) - return - return {" - - - [patient] statistics - - - - -

    Health statistics

    -
    - [get_patient_dam()] -
    -

    Reagents in bloodstream

    -
    - [get_patient_reagents()] -
    -
    - [get_available_reagents()] -
    - - "} - -/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_patient_dam() - var/t1 - switch(patient.stat) - if(0) - t1 = "Conscious" - if(1) - t1 = "Unconscious" - if(2) - t1 = "*dead*" - else - t1 = "Unknown" - var/core_temp = "" - if(ishuman(patient)) - var/mob/living/carbon/human/humi = patient - core_temp = {"Body Temperature: [humi.bodytemperature-T0C]°C ([humi.bodytemperature*1.8-459.67]°F)
    "} - return {"Health: [patient.stat > 1 ? "[t1]" : "[patient.health]% ([t1])"]
    - [core_temp] - Body Temperature: [patient.bodytemperature-T0C]°C ([patient.bodytemperature*1.8-459.67]°F)
    - Brute Damage: [patient.getBruteLoss()]%
    - Respiratory Damage: [patient.getOxyLoss()]%
    - Toxin Content: [patient.getToxLoss()]%
    - Burn Severity: [patient.getFireLoss()]%
    - [span_danger("[patient.get_organ_loss(ORGAN_SLOT_BRAIN) ? "Significant brain damage detected." : ""]")]
    - [span_danger("[length(patient.get_traumas()) ? "Brain Traumas detected." : ""]")]
    - "} - -/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_patient_reagents() - if(patient.reagents) - for(var/datum/reagent/R in patient.reagents.reagent_list) - if(R.volume > 0) - . += "[R]: [round(R.volume,0.01)]
    " - return . || "None" - -/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/get_available_reagents() - var/output - var/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun) in chassis - if(SG && SG.reagents && islist(SG.reagents.reagent_list)) - for(var/datum/reagent/R in SG.reagents.reagent_list) - if(R.volume > 0) - output += "Inject [R.name]
    " - return output - - -/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/inject_reagent(datum/reagent/R,obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG) +/obj/item/mecha_parts/mecha_equipment/medical/sleeper/proc/inject_reagent(datum/reagent/R, obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/SG) if(!R || !patient || !SG || !(SG in chassis.flat_equipment)) return var/to_inject = min(R.volume, inject_amount) @@ -294,11 +244,7 @@ "total_reagents" = reagents.maximum_volume, "analyzed_reagents" = analyzed_reagents, ) - var/list/contained_reagents = list() - if(length(reagents.reagent_list)) - for(var/datum/reagent/reagent as anything in reagents.reagent_list) - contained_reagents += list(list("name" = reagent.name, "volume" = round(reagent.volume, 0.01))) // list in a list because Byond merges the first list... - data["contained_reagents"] = contained_reagents + data["contained_reagents"] = get_reagent_data(reagents.reagent_list) return data /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/handle_ui_act(action, list/params) diff --git a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm index 25fd2879a6b90..f7a866bdffe90 100644 --- a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm @@ -10,7 +10,7 @@ desc = "Equipment for engineering and combat exosuits. This is the drill that'll pierce the heavens!" icon_state = "mecha_drill" equip_cooldown = 15 - energy_drain = 10 KILO JOULES + energy_drain = 0.01 * STANDARD_CELL_CHARGE force = 15 harmful = TRUE range = MECHA_MELEE @@ -32,6 +32,29 @@ ADD_TRAIT(src, TRAIT_INSTANTLY_PROCESSES_BOULDERS, INNATE_TRAIT) ADD_TRAIT(src, TRAIT_BOULDER_BREAKER, INNATE_TRAIT) +/obj/item/mecha_parts/mecha_equipment/drill/attach(obj/vehicle/sealed/mecha/new_mecha, attach_right) + . = ..() + RegisterSignal(chassis, COMSIG_MOVABLE_BUMP, PROC_REF(bump_mine)) + +/obj/item/mecha_parts/mecha_equipment/drill/detach(atom/moveto) + UnregisterSignal(chassis, COMSIG_MOVABLE_BUMP) + return ..() + +/obj/item/mecha_parts/mecha_equipment/drill/Destroy() + if(chassis) + UnregisterSignal(chassis, COMSIG_MOVABLE_BUMP) + return ..() + +///Called whenever the mech bumps into something; action() handles checking if it is a mineable turf +/obj/item/mecha_parts/mecha_equipment/drill/proc/bump_mine(obj/vehicle/sealed/mecha/bumper, atom/bumped_into) + SIGNAL_HANDLER + var/list/drivers = chassis.return_drivers() + if(!LAZYLEN(drivers)) //I don't know if this is possible but just in case + return + + //Just use the first one /shrug + INVOKE_ASYNC(src, PROC_REF(action), drivers[1], bumped_into, null, TRUE) + /obj/item/mecha_parts/mecha_equipment/drill/do_after_checks(atom/target) // Gotta be close to the target if(!loc.Adjacent(target)) @@ -41,55 +64,71 @@ return FALSE return ..() -/obj/item/mecha_parts/mecha_equipment/drill/action(mob/source, atom/target, list/modifiers) - // We can only drill non-space turfs, living mobs and objects. - if(isspaceturf(target) || !(isliving(target) || isobj(target) || isturf(target))) - return +/obj/item/mecha_parts/mecha_equipment/drill/action(mob/source, atom/target, list/modifiers, bumped) + //If bumped, only bother drilling mineral turfs + if(bumped) + if(!ismineralturf(target)) + return + + //Prevent drilling into gibtonite more than once; code mostly from MODsuit drill + if(istype(target, /turf/closed/mineral/gibtonite)) + var/turf/closed/mineral/gibtonite/giberal_turf = target + if(giberal_turf.stage != GIBTONITE_UNSTRUCK) + playsound(chassis, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + to_chat(source, span_warning("[icon2html(src, source)] Active gibtonite ore deposit detected! Safety protocols preventing continued drilling.")) + return - // For whatever reason we can't drill things that acid won't even stick too, and probably - // shouldn't waste our time drilling indestructible things. - if(isobj(target)) - var/obj/target_obj = target - if(target_obj.resistance_flags & (UNACIDABLE | INDESTRUCTIBLE)) + else + // We can only drill non-space turfs, living mobs and objects. + if(isspaceturf(target) || !(isliving(target) || isobj(target) || isturf(target))) return + // For whatever reason we can't drill things that acid won't even stick too, and probably + // shouldn't waste our time drilling indestructible things. + if(isobj(target)) + var/obj/target_obj = target + if(target_obj.resistance_flags & (UNACIDABLE | INDESTRUCTIBLE)) + return + // You can't drill harder by clicking more. - if(!DOING_INTERACTION_WITH_TARGET(source, target) && do_after_cooldown(target, source, DOAFTER_SOURCE_MECHADRILL)) - target.visible_message(span_warning("[chassis] starts to drill [target]."), \ - span_userdanger("[chassis] starts to drill [target]..."), \ - span_hear("You hear drilling.")) + if(DOING_INTERACTION_WITH_TARGET(source, target) && do_after_cooldown(target, source, DOAFTER_SOURCE_MECHADRILL)) + return - log_message("Started drilling [target]", LOG_MECHA) + target.visible_message(span_warning("[chassis] starts to drill [target]."), \ + span_userdanger("[chassis] starts to drill [target]..."), \ + span_hear("You hear drilling.")) - // Drilling a turf is a one-and-done procedure. - if(isturf(target)) - // Check if we can even use the equipment to begin with. - if(!action_checks(target)) - return + log_message("Started drilling [target]", LOG_MECHA) + + // Drilling a turf is a one-and-done procedure. + if(isturf(target)) + // Check if we can even use the equipment to begin with. + if(!action_checks(target)) + return - var/turf/T = target - T.drill_act(src, source) - - return ..() - - // Drilling objects and mobs is a repeating procedure. - while(do_after_mecha(target, source, drill_delay)) - if(isliving(target)) - drill_mob(target, source) - playsound(src,'sound/weapons/drill.ogg',40,TRUE) - else if(isobj(target)) - var/obj/O = target - if(istype(O, /obj/item/boulder)) - var/obj/item/boulder/nu_boulder = O - nu_boulder.manual_process(src, source) - else - O.take_damage(15, BRUTE, 0, FALSE, get_dir(chassis, target)) - playsound(src,'sound/weapons/drill.ogg', 40, TRUE) - - // If we caused a qdel drilling the target, we can stop drilling them. - // Prevents starting a do_after on a qdeleted target. - if(QDELETED(target)) - break + var/turf/T = target + T.drill_act(src, source) + + return ..() + + // Drilling objects and mobs is a repeating procedure. + while(do_after_mecha(target, source, drill_delay)) + if(isliving(target)) + drill_mob(target, source) + playsound(src,'sound/weapons/drill.ogg',40,TRUE) + else if(isobj(target)) + var/obj/O = target + if(istype(O, /obj/item/boulder)) + var/obj/item/boulder/nu_boulder = O + nu_boulder.manual_process(src, source) + else + O.take_damage(15, BRUTE, 0, FALSE, get_dir(chassis, target)) + playsound(src,'sound/weapons/drill.ogg', 40, TRUE) + + // If we caused a qdel drilling the target, we can stop drilling them. + // Prevents starting a do_after on a qdeleted target. + if(QDELETED(target)) + break return ..() diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm index 067ad2250f06b..6a70d4db9f043 100644 --- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm @@ -9,7 +9,7 @@ desc = "An exosuit module that allows exosuits to teleport to any position in view." icon_state = "mecha_teleport" equip_cooldown = 150 - energy_drain = 1 MEGA JOULES + energy_drain = STANDARD_CELL_CHARGE range = MECHA_RANGED var/teleport_range = 7 @@ -129,7 +129,7 @@ /obj/item/mecha_parts/mecha_equipment/gravcatapult/proc/do_scatter(atom/movable/scatter, atom/movable/target) var/dist = 5 - get_dist(scatter, target) var/delay = 2 - SSmove_manager.move_away(scatter, target, delay = delay, timeout = delay * dist, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) + GLOB.move_manager.move_away(scatter, target, delay = delay, timeout = delay * dist, flags = MOVEMENT_LOOP_START_FAST, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) /obj/item/mecha_parts/mecha_equipment/gravcatapult/get_snowflake_data() return list( @@ -285,7 +285,7 @@ ///Maximum fuel capacity of the generator, in units var/max_fuel = 75 * SHEET_MATERIAL_AMOUNT ///Energy recharged per second - var/rechargerate = 5 KILO WATTS + var/rechargerate = 0.005 * STANDARD_CELL_RATE /obj/item/mecha_parts/mecha_equipment/generator/Initialize(mapload) . = ..() diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm index 5497113017e87..276afc0f3d6c7 100644 --- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -7,7 +7,7 @@ desc = "Equipment for engineering exosuits. Lifts objects and loads them into cargo." icon_state = "mecha_clamp" equip_cooldown = 15 - energy_drain = 10 KILO JOULES + energy_drain = 0.01 * STANDARD_CELL_CHARGE tool_behaviour = TOOL_RETRACTOR range = MECHA_MELEE toolspeed = 0.8 diff --git a/code/modules/vehicles/mecha/mech_bay.dm b/code/modules/vehicles/mecha/mech_bay.dm index 1f46856562575..5166b9c5fdfc5 100644 --- a/code/modules/vehicles/mecha/mech_bay.dm +++ b/code/modules/vehicles/mecha/mech_bay.dm @@ -12,7 +12,7 @@ ///Ref to charge console for seeing charge for this port, cyclical reference var/obj/machinery/computer/mech_bay_power_console/recharge_console ///Power unit per second to charge by - var/recharge_power = 25 KILO WATTS + var/recharge_power = 0.025 * STANDARD_CELL_RATE ///turf that will be checked when a mech wants to charge. directly one turf in the direction it is facing var/turf/recharging_turf @@ -46,7 +46,7 @@ var/total_rating = 0 for(var/datum/stock_part/capacitor/capacitor in component_parts) total_rating += capacitor.tier - recharge_power = total_rating * 12.5 KILO WATTS + recharge_power = total_rating * 0.0125 * STANDARD_CELL_RATE /obj/machinery/mech_bay_recharge_port/examine(mob/user) . = ..() @@ -64,10 +64,11 @@ recharge_console.update_appearance() if(!recharging_mech?.cell) return - if(recharging_mech.cell.charge < recharging_mech.cell.maxcharge) - if(!use_energy(active_power_usage * seconds_per_tick)) - return - charge_cell(recharge_power * seconds_per_tick, recharging_mech.cell, grid_only = TRUE) + if(recharging_mech.cell.used_charge()) + //charge cell, account for heat loss given from work done + var/charge_given = charge_cell(recharge_power * seconds_per_tick, recharging_mech.cell, grid_only = TRUE) + if(charge_given) + use_energy((charge_given + active_power_usage) * 0.01) else recharge_console.update_appearance() if(recharging_mech.loc != recharging_turf) diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index c4acded799446..2dce26624ad25 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -55,7 +55,7 @@ RefreshParts() //Recalculating local material sizes if the fab isn't linked return ..() -/obj/machinery/mecha_part_fabricator/LateInitialize() +/obj/machinery/mecha_part_fabricator/post_machine_initialize() . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research) CONNECT_TO_RND_SERVER_ROUNDSTART(stored_research, src) @@ -127,14 +127,12 @@ if(panel_open) . += span_notice("Alt-click to rotate the output direction.") -/obj/machinery/mecha_part_fabricator/AltClick(mob/user) - . = ..() - if(!user.can_perform_action(src)) - return - if(panel_open) - dir = turn(dir, -90) - balloon_alert(user, "rotated to [dir2text(dir)].") - return TRUE +/obj/machinery/mecha_part_fabricator/click_alt(mob/user) + if(!panel_open) + return CLICK_ACTION_BLOCKING + dir = turn(dir, -90) + balloon_alert(user, "rotated to [dir2text(dir)].") + return CLICK_ACTION_SUCCESS /** * Updates the `final_sets` and `buildable_parts` for the current mecha fabricator. @@ -474,7 +472,7 @@ /obj/machinery/mecha_part_fabricator/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted) var/datum/material/M = id_inserted add_overlay("fab-load-[M.name]") - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, cut_overlay), "fab-load-[M.name]"), 10) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, cut_overlay), "fab-load-[M.name]"), 1 SECONDS) /obj/machinery/mecha_part_fabricator/screwdriver_act(mob/living/user, obj/item/I) if(..()) diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm index 2b410bd60c775..322a1189053b8 100644 --- a/code/modules/vehicles/mecha/mecha_actions.dm +++ b/code/modules/vehicles/mecha/mecha_actions.dm @@ -91,14 +91,6 @@ chassis.toggle_strafe() -/obj/vehicle/sealed/mecha/AltClick(mob/living/user) - if(!(user in occupants) || !user.can_perform_action(src)) - return - if(!(user in return_controllers_with_flag(VEHICLE_CONTROL_DRIVE))) - to_chat(user, span_warning("You're in the wrong seat to control movement.")) - return - - toggle_strafe() /obj/vehicle/sealed/mecha/proc/toggle_strafe() if(!(mecha_flags & CAN_STRAFE)) @@ -107,7 +99,9 @@ strafe = !strafe - to_chat(occupants, "strafing mode [strafe?"on":"off"].") + for(var/mob/occupant in occupants) + balloon_alert(occupant, "strafing [strafe?"on":"off"]") + occupant.playsound_local(src, 'sound/machines/terminal_eject.ogg', 50, TRUE) log_message("Toggled strafing mode [strafe?"on":"off"].", LOG_MECHA) for(var/occupant in occupants) diff --git a/code/modules/vehicles/mecha/mecha_ai_interaction.dm b/code/modules/vehicles/mecha/mecha_ai_interaction.dm index 9ae35d8ff4ba4..3a681cac97db5 100644 --- a/code/modules/vehicles/mecha/mecha_ai_interaction.dm +++ b/code/modules/vehicles/mecha/mecha_ai_interaction.dm @@ -67,6 +67,7 @@ if(AI_MECH_HACK) //Called by AIs on the mech AI.linked_core = new /obj/structure/ai_core/deactivated(AI.loc) + AI.linked_core.remote_ai = AI if(AI.can_dominate_mechs && LAZYLEN(occupants)) //Oh, I am sorry, were you using that? to_chat(AI, span_warning("Occupants detected! Forced ejection initiated!")) to_chat(occupants, span_danger("You have been forcibly ejected!")) @@ -101,6 +102,7 @@ AI.eyeobj?.RegisterSignal(src, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/mob/camera/ai_eye, update_visibility)) AI.controlled_equipment = src AI.remote_control = src + AI.ShutOffDoomsdayDevice() to_chat(AI, AI.can_dominate_mechs ? span_greenannounce("Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!") :\ span_notice("You have been uploaded to a mech's onboard computer.")) to_chat(AI, "Use Middle-Mouse or the action button in your HUD to toggle equipment safety. Clicks with safety enabled will pass AI commands.") diff --git a/code/modules/vehicles/mecha/mecha_mob_interaction.dm b/code/modules/vehicles/mecha/mecha_mob_interaction.dm index e9d7f5a1e1fe8..e72d5505cb6fc 100644 --- a/code/modules/vehicles/mecha/mecha_mob_interaction.dm +++ b/code/modules/vehicles/mecha/mecha_mob_interaction.dm @@ -119,19 +119,29 @@ //stop listening to this signal, as the static update is now handled by the eyeobj's setLoc AI.eyeobj?.UnregisterSignal(src, COMSIG_MOVABLE_MOVED) AI.eyeobj?.forceMove(newloc) //kick the eye out as well - if(forced)//This should only happen if there are multiple AIs in a round, and at least one is Malf. + if(forced) + AI.controlled_equipment = null + AI.remote_control = null if(!AI.linked_core) //if the victim AI has no core - AI.investigate_log("has been gibbed by being forced out of their mech by another AI.", INVESTIGATE_DEATHS) - AI.gib(DROP_ALL_REMAINS) //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced. - AI = null - mecha_flags &= ~SILICON_PILOT - return + if (!AI.can_shunt || !length(AI.hacked_apcs)) + AI.investigate_log("has been gibbed by being forced out of their mech.", INVESTIGATE_DEATHS) + /// If an AI with no core (and no shunting abilities) gets forced out of their mech + /// (in a way that isn't handled by the normal handling of their mech being destroyed) + /// we gib 'em here, too. + AI.gib(DROP_ALL_REMAINS) + AI = null + mecha_flags &= ~SILICON_PILOT + return + else + var/obj/machinery/power/apc/emergency_shunt_apc = pick(AI.hacked_apcs) + emergency_shunt_apc.malfoccupy(AI) //get shunted into a random APC (you don't get to choose which) + AI = null + mecha_flags &= ~SILICON_PILOT + return + newloc = get_turf(AI.linked_core) + qdel(AI.linked_core) + AI.forceMove(newloc) else - if(!AI.linked_core) - if(!silent) - to_chat(AI, span_userdanger("Inactive core destroyed. Unable to return.")) - AI.linked_core = null - return if(!silent) to_chat(AI, span_notice("Returning to core...")) AI.controlled_equipment = null @@ -139,6 +149,9 @@ mob_container = AI newloc = get_turf(AI.linked_core) qdel(AI.linked_core) + AI.forceMove(newloc) + else if(isliving(M)) + mob_container = M else return ..() var/mob/living/ejector = M @@ -157,24 +170,26 @@ setDir(SOUTH) return ..() -/obj/vehicle/sealed/mecha/add_occupant(mob/M, control_flags) - RegisterSignal(M, COMSIG_MOB_CLICKON, PROC_REF(on_mouseclick), TRUE) - RegisterSignal(M, COMSIG_MOB_SAY, PROC_REF(display_speech_bubble), TRUE) - RegisterSignal(M, COMSIG_MOVABLE_KEYBIND_FACE_DIR, PROC_REF(on_turn), TRUE) +/obj/vehicle/sealed/mecha/add_occupant(mob/driver, control_flags) + RegisterSignal(driver, COMSIG_MOB_CLICKON, PROC_REF(on_mouseclick), TRUE) + RegisterSignal(driver, COMSIG_MOB_SAY, PROC_REF(display_speech_bubble), TRUE) + RegisterSignal(driver, COMSIG_MOVABLE_KEYBIND_FACE_DIR, PROC_REF(on_turn), TRUE) + RegisterSignal(driver, COMSIG_MOB_ALTCLICKON, PROC_REF(on_click_alt)) . = ..() update_appearance() -/obj/vehicle/sealed/mecha/remove_occupant(mob/M) - UnregisterSignal(M, list( +/obj/vehicle/sealed/mecha/remove_occupant(mob/driver) + UnregisterSignal(driver, list( COMSIG_MOB_CLICKON, COMSIG_MOB_SAY, COMSIG_MOVABLE_KEYBIND_FACE_DIR, + COMSIG_MOB_ALTCLICKON, )) - M.clear_alert(ALERT_CHARGE) - M.clear_alert(ALERT_MECH_DAMAGE) - if(M.client) - M.update_mouse_pointer() - M.client.view_size.resetToDefault() + driver.clear_alert(ALERT_CHARGE) + driver.clear_alert(ALERT_MECH_DAMAGE) + if(driver.client) + driver.update_mouse_pointer() + driver.client.view_size.resetToDefault() zoom_mode = FALSE . = ..() update_appearance() @@ -182,9 +197,20 @@ /obj/vehicle/sealed/mecha/container_resist_act(mob/living/user) if(isAI(user)) var/mob/living/silicon/ai/AI = user - if(!AI.can_shunt) - to_chat(AI, span_notice("You can't leave a mech after dominating it!.")) - return FALSE + if(!AI.linked_core) + to_chat(AI, span_userdanger("Inactive core destroyed. Unable to return.")) + if(!AI.can_shunt || !AI.hacked_apcs.len) + to_chat(AI, span_warning("[AI.can_shunt ? "No hacked APCs available." : "No shunting capabilities."]")) + return + var/confirm = tgui_alert(AI, "Shunt to a random APC? You won't have anywhere else to go!", "Confirm Emergency Shunt", list("Yes", "No")) + if(confirm == "Yes") + /// Mechs with open cockpits can have the pilot shot by projectiles, or EMPs may destroy the AI inside + /// Alternatively, destroying the mech will shunt the AI if they can shunt, or a deadeye wizard can hit + /// them with a teleportation bolt + if (AI.stat == DEAD || AI.loc != src) + return + mob_exit(AI, forced = TRUE) + return to_chat(user, span_notice("You begin the ejection procedure. Equipment is disabled during this process. Hold still to finish ejecting.")) is_currently_ejecting = TRUE if(do_after(user, has_gravity() ? exit_delay : 0 , target = src)) diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index 711da429cca2f..a4872289e962c 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -318,7 +318,7 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo) /obj/item/mecha_parts/mecha_equipment/ejector/relay_container_resist_act(mob/living/user, obj/container) to_chat(user, span_notice("You lean on the back of [container] and start pushing so it falls out of [src].")) - if(do_after(user, 300, target = container)) + if(do_after(user, 30 SECONDS, target = container)) if(!user || user.stat != CONSCIOUS || user.loc != src || container.loc != src ) return to_chat(user, span_notice("You successfully pushed [container] out of [src]!")) diff --git a/code/modules/vehicles/motorized_wheelchair.dm b/code/modules/vehicles/motorized_wheelchair.dm index 128530968e243..8dbdfd93e8f69 100644 --- a/code/modules/vehicles/motorized_wheelchair.dm +++ b/code/modules/vehicles/motorized_wheelchair.dm @@ -10,7 +10,7 @@ ///Self explanatory, ratio of how much power we use var/power_efficiency = 1 ///How much energy we use - var/energy_usage = 100 KILO JOULES + var/energy_usage = 0.1 * STANDARD_CELL_CHARGE ///whether the panel is open so a user can take out the cell var/panel_open = FALSE ///Parts used in building the wheelchair diff --git a/code/modules/vehicles/ridden.dm b/code/modules/vehicles/ridden.dm index 33f81184e9a34..52c7924d72f22 100644 --- a/code/modules/vehicles/ridden.dm +++ b/code/modules/vehicles/ridden.dm @@ -5,6 +5,7 @@ buckle_lying = 0 pass_flags_self = PASSTABLE COOLDOWN_DECLARE(message_cooldown) + interaction_flags_click = NEED_DEXTERITY /obj/vehicle/ridden/examine(mob/user) . = ..() @@ -39,16 +40,17 @@ inserted_key.forceMove(drop_location()) inserted_key = I -/obj/vehicle/ridden/AltClick(mob/user) - if(!inserted_key || !user.can_perform_action(src, NEED_DEXTERITY)) - return ..() +/obj/vehicle/ridden/click_alt(mob/user) + if(!inserted_key) + return CLICK_ACTION_BLOCKING if(!is_occupant(user)) to_chat(user, span_warning("You must be riding the [src] to remove [src]'s key!")) - return + return CLICK_ACTION_BLOCKING to_chat(user, span_notice("You remove \the [inserted_key] from \the [src].")) inserted_key.forceMove(drop_location()) user.put_in_hands(inserted_key) inserted_key = null + return CLICK_ACTION_SUCCESS /obj/vehicle/ridden/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) if(!in_range(user, src) || !in_range(M, src)) diff --git a/code/modules/vehicles/scooter.dm b/code/modules/vehicles/scooter.dm index 9e320c2f8deb6..a4f3652448342 100644 --- a/code/modules/vehicles/scooter.dm +++ b/code/modules/vehicles/scooter.dm @@ -159,7 +159,7 @@ victim.Paralyze(1.5 SECONDS) skater.adjustStaminaLoss(instability) victim.visible_message(span_danger("[victim] straight up gets grinded into the ground by [skater]'s [src]! Radical!")) - addtimer(CALLBACK(src, PROC_REF(grind)), 1) + addtimer(CALLBACK(src, PROC_REF(grind)), 0.1 SECONDS) /obj/vehicle/ridden/scooter/skateboard/MouseDrop(atom/over_object) . = ..() diff --git a/code/modules/vehicles/secway.dm b/code/modules/vehicles/secway.dm index fb23739333888..c8cab1a7dc1cd 100644 --- a/code/modules/vehicles/secway.dm +++ b/code/modules/vehicles/secway.dm @@ -77,7 +77,7 @@ if(!eddie_murphy) return ..() user.visible_message(span_warning("[user] begins cleaning [eddie_murphy] out of [src]."), span_warning("You begin cleaning [eddie_murphy] out of [src]...")) - if(!do_after(user, 60, target = src)) + if(!do_after(user, 6 SECONDS, target = src)) return ..() user.visible_message(span_warning("[user] cleans [eddie_murphy] out of [src]."), span_warning("You manage to get [eddie_murphy] out of [src].")) eddie_murphy.forceMove(drop_location()) diff --git a/code/modules/vehicles/vehicle_actions.dm b/code/modules/vehicles/vehicle_actions.dm index ed9884a9ea3cb..c378009996618 100644 --- a/code/modules/vehicles/vehicle_actions.dm +++ b/code/modules/vehicles/vehicle_actions.dm @@ -353,7 +353,7 @@ rider.client.give_award(/datum/award/achievement/misc/tram_surfer, rider) vehicle.grinding = TRUE vehicle.icon_state = "[initial(vehicle.icon_state)]-grind" - addtimer(CALLBACK(vehicle, TYPE_PROC_REF(/obj/vehicle/ridden/scooter/skateboard/, grind)), 2) + addtimer(CALLBACK(vehicle, TYPE_PROC_REF(/obj/vehicle/ridden/scooter/skateboard/, grind)), 0.2 SECONDS) else vehicle.obj_flags &= ~BLOCK_Z_OUT_DOWN rider.spin(spintime = 4, speed = 1) diff --git a/code/modules/vehicles/vehicle_key.dm b/code/modules/vehicles/vehicle_key.dm index f6e5f7c4e2882..08cb75df2d440 100644 --- a/code/modules/vehicles/vehicle_key.dm +++ b/code/modules/vehicles/vehicle_key.dm @@ -20,7 +20,7 @@ return SHAME user.visible_message(span_suicide("[user] is putting \the [src] in [user.p_their()] ear and starts [user.p_their()] motor! It looks like [user.p_theyre()] trying to commit suicide!")) user.say("Vroom vroom!!", forced="secway key suicide") //Not doing a shamestate here, because even if they fail to speak they're spinning. - addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living/, gib)), 20) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living/, gib)), 2 SECONDS) return MANUAL_SUICIDE /obj/item/key/janitor @@ -46,7 +46,7 @@ if(SKILL_LEVEL_APPRENTICE to SKILL_LEVEL_JOURNEYMAN) //At least they tried user.visible_message(span_suicide("[user] is putting \the [src] in [user.p_their()] mouth and has inefficiently become one with the janicart! It looks like [user.p_theyre()] trying to commit suicide!")) user.AddElement(/datum/element/cleaning) - addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 51) + addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 5.1 SECONDS) return MANUAL_SUICIDE if(SKILL_LEVEL_EXPERT to SKILL_LEVEL_MASTER) //They are worthy enough, but can it go even further beyond? user.visible_message(span_suicide("[user] is putting \the [src] in [user.p_their()] mouth and has skillfully become one with the janicart! It looks like [user.p_theyre()] trying to commit suicide!")) diff --git a/code/modules/vehicles/wheelchair.dm b/code/modules/vehicles/wheelchair.dm index e7b3d9b3a56af..d40b57276c0e4 100644 --- a/code/modules/vehicles/wheelchair.dm +++ b/code/modules/vehicles/wheelchair.dm @@ -63,8 +63,6 @@ qdel(src) return ITEM_INTERACT_SUCCESS -/obj/vehicle/ridden/wheelchair/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation /obj/vehicle/ridden/wheelchair/update_overlays() . = ..() @@ -128,7 +126,7 @@ . = ..() if(over_object != usr || !Adjacent(usr) || !foldabletype) return FALSE - if(!ishuman(usr) || !usr.can_perform_action(src)) + if(!ishuman(usr) || !usr.can_perform_action(src, ALLOW_RESTING)) return FALSE if(has_buckled_mobs()) return FALSE @@ -140,6 +138,12 @@ /obj/item/wheelchair/attack_self(mob/user) //Deploys wheelchair on in-hand use deploy_wheelchair(user, user.loc) +/obj/item/wheelchair/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(isopenturf(interacting_with)) + deploy_wheelchair(user, interacting_with) + return ITEM_INTERACT_SUCCESS + return NONE + /obj/item/wheelchair/proc/deploy_wheelchair(mob/user, atom/location) var/obj/vehicle/ridden/wheelchair/wheelchair_unfolded = new unfolded_type(location) wheelchair_unfolded.add_fingerprint(user) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index cf966727abb74..096cd735bd483 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -548,6 +548,28 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) return . +/** + * After-effects of refilling a vending machine from a refill canister + * + * This takes the amount of products restocked and gives the user our contained credits if needed, + * sending the user a fitting message. + * + * Arguments: + * * user - the user restocking us + * * restocked - the amount of items we've been refilled with + */ +/obj/machinery/vending/proc/post_restock(mob/living/user, restocked) + if(!restocked) + to_chat(user, span_warning("There's nothing to restock!")) + return + + to_chat(user, span_notice("You loaded [restocked] items in [src][credits_contained > 0 ? ", and are rewarded [credits_contained] credits." : "."]")) + var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR) + cargo_account.adjust_money(round(credits_contained * 0.5), "Vending: Restock") + var/obj/item/holochip/payday = new(src, credits_contained) + try_put_in_hand(payday, user) + credits_contained = 0 + /** * Refill our inventory from the passed in product list into the record list * @@ -704,15 +726,8 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) to_chat(user, span_warning("[canister] is empty!")) else // instantiate canister if needed - var/transferred = restock(canister) - if(transferred) - to_chat(user, span_notice("You loaded [transferred] items in [src][credits_contained > 0 ? ", and are rewarded [credits_contained] credits." : "."]")) - var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR) - cargo_account.adjust_money(round(credits_contained * 0.5), "Vending: Restock") - var/obj/item/holochip/payday = new(src, credits_contained) - try_put_in_hand(payday, user) - else - to_chat(user, span_warning("There's nothing to restock!")) + var/restocked = restock(canister) + post_restock(user, restocked) return if(compartmentLoadAccessCheck(user) && !user.combat_mode) @@ -1142,22 +1157,21 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) /obj/machinery/vending/exchange_parts(mob/user, obj/item/storage/part_replacer/replacer) if(!istype(replacer)) return FALSE - if((obj_flags & NO_DECONSTRUCTION) && !replacer.works_from_distance) - return FALSE if(!component_parts || !refill_canister) return FALSE - var/moved = 0 - if(panel_open || replacer.works_from_distance) - if(replacer.works_from_distance) - display_parts(user) - for(var/replacer_item in replacer) - if(istype(replacer, refill_canister)) - moved += restock(replacer_item) - else - display_parts(user) - if(moved) - to_chat(user, span_notice("[moved] items restocked.")) + if(!panel_open || replacer.works_from_distance) + to_chat(user, display_parts(user)) + + if(!panel_open && !replacer.works_from_distance) + return FALSE + + var/restocked = 0 + for(var/replacer_item in replacer) + if(istype(replacer_item, refill_canister)) + restocked += restock(replacer_item) + post_restock(user, restocked) + if(restocked > 0) replacer.play_rped_sound() return TRUE @@ -1180,7 +1194,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) if(tilted && !user.buckled && !isAdminGhostAI(user)) to_chat(user, span_notice("You begin righting [src].")) - if(do_after(user, 50, target=src)) + if(do_after(user, 5 SECONDS, target=src)) untilt(user) return diff --git a/code/modules/vending/runic_vendor.dm b/code/modules/vending/runic_vendor.dm index 3edb5b2726403..f338340c8b1d8 100644 --- a/code/modules/vending/runic_vendor.dm +++ b/code/modules/vending/runic_vendor.dm @@ -9,6 +9,7 @@ vend_reply = "Please, stand still near the vending machine for your special package!" resistance_flags = FIRE_PROOF light_mask = "RunicVendor-light-mask" + obj_flags = parent_type::obj_flags | NO_DEBRIS_AFTER_DECONSTRUCTION /// How long the vendor stays up before it decays. var/time_to_decay = 30 SECONDS /// Area around the vendor that will pushback nearby mobs. @@ -60,15 +61,16 @@ return . +/obj/machinery/vending/runic_vendor/handle_deconstruct(disassembled) + SHOULD_NOT_OVERRIDE(TRUE) -/obj/machinery/vending/runic_vendor/Destroy() visible_message(span_warning("[src] flickers and disappears!")) playsound(src,'sound/weapons/resonator_blast.ogg',25,TRUE) return ..() /obj/machinery/vending/runic_vendor/proc/runic_explosion() explosion(src, light_impact_range = 2) - qdel(src) + deconstruct(FALSE) /obj/machinery/vending/runic_vendor/proc/runic_pulse() var/pulse_locs = spiral_range_turfs(pulse_distance, get_turf(src)) @@ -82,10 +84,9 @@ mob_to_be_pulsed_back.throw_at(target, 4, 4) /obj/machinery/vending/runic_vendor/screwdriver_act(mob/living/user, obj/item/I) - explosion(src, light_impact_range = 2) - qdel(src) + runic_explosion() /obj/machinery/vending/runic_vendor/proc/decay() - qdel(src) + deconstruct(FALSE) #undef PULSE_DISTANCE_RANGE diff --git a/code/modules/wiremod/components/action/equpiment_action.dm b/code/modules/wiremod/components/action/equpiment_action.dm index 54150ca44d60b..641722c595b60 100644 --- a/code/modules/wiremod/components/action/equpiment_action.dm +++ b/code/modules/wiremod/components/action/equpiment_action.dm @@ -89,4 +89,4 @@ for(var/ref in granted_to) var/datum/action/granted_action = granted_to[ref] granted_action.name = button_name.value || "Action" - granted_action.button_icon_state = "bci_[replacetextEx(lowertext(icon_options.value), " ", "_")]" + granted_action.button_icon_state = "bci_[replacetextEx(LOWER_TEXT(icon_options.value), " ", "_")]" diff --git a/code/modules/wiremod/components/action/speech.dm b/code/modules/wiremod/components/action/speech.dm index 0e2936bcfbfdb..f149cba9122bc 100644 --- a/code/modules/wiremod/components/action/speech.dm +++ b/code/modules/wiremod/components/action/speech.dm @@ -11,6 +11,8 @@ /// The message to send var/datum/port/input/message + /// The quiet mode flag + var/datum/port/input/quietmode /// The cooldown for this component of how often it can send speech messages. var/speech_cooldown = 1 SECONDS @@ -21,6 +23,7 @@ /obj/item/circuit_component/speech/populate_ports() message = add_input_port("Message", PORT_TYPE_STRING, trigger = null) + quietmode = add_input_port("Quiet Mode", PORT_TYPE_NUMBER, default = 0) /obj/item/circuit_component/speech/input_received(datum/port/input/port) if(!parent.shell) @@ -31,5 +34,5 @@ if(message.value) var/atom/movable/shell = parent.shell - shell.say(message.value, forced = "circuit speech | [parent.get_creator()]") + shell.say(message.value, forced = "circuit speech | [parent.get_creator()]", message_range = quietmode.value > 0 ? WHISPER_RANGE : MESSAGE_RANGE) TIMER_COOLDOWN_START(shell, COOLDOWN_CIRCUIT_SPEECH, speech_cooldown) diff --git a/code/modules/wiremod/components/atom/health_state.dm b/code/modules/wiremod/components/atom/health_state.dm new file mode 100644 index 0000000000000..dc83a41fdfd8d --- /dev/null +++ b/code/modules/wiremod/components/atom/health_state.dm @@ -0,0 +1,56 @@ +/** + * # Compare Health State Component + * + * Returns true when state matches entity. + */ + +/obj/item/circuit_component/compare/health_state + display_name = "Compare Health State" + desc = "A component that compares the health state of an organism, and returns true or false." + category = "Entity" + + /// The input port + var/datum/port/input/input_port + + /// Compare state option + var/datum/port/input/option/state_option + + var/max_range = 5 + +/obj/item/circuit_component/compare/health_state/get_ui_notices() + . = ..() + . += create_ui_notice("Maximum Range: [max_range] tiles", "orange", "info") + +/obj/item/circuit_component/compare/health_state/populate_options() + input_port = add_input_port("Organism", PORT_TYPE_ATOM) + + var/static/component_options = list( + "Alive", + "Asleep", + "Critical", + "Unconscious", + "Deceased", + ) + state_option = add_option_port("Comparison Option", component_options) + +/obj/item/circuit_component/compare/health_state/do_comparisons() + var/mob/living/organism = input_port.value + var/turf/current_turf = get_location() + if(!istype(organism) || current_turf.z != organism.z || get_dist(current_turf, organism) > max_range) + return FALSE + + var/current_option = state_option.value + var/state = organism.stat + switch(current_option) + if("Alive") + return state != DEAD + if("Asleep") + return !!organism.IsSleeping() && !organism.IsUnconscious() + if("Critical") + return state == SOFT_CRIT || state == HARD_CRIT + if("Unconscious") + return state == UNCONSCIOUS || state == HARD_CRIT || !!organism.IsUnconscious() + if("Deceased") + return state == DEAD + //Unknown state, something fucked up really bad - just return false + return FALSE diff --git a/code/modules/wiremod/components/atom/hear.dm b/code/modules/wiremod/components/atom/hear.dm index 3c3f05691b2d6..98c45a77f6fc2 100644 --- a/code/modules/wiremod/components/atom/hear.dm +++ b/code/modules/wiremod/components/atom/hear.dm @@ -8,6 +8,9 @@ desc = "A component that listens for messages. Requires a shell." category = "Entity" + /// The on/off port + var/datum/port/input/on + /// The message heard var/datum/port/output/message_port /// The language heard @@ -20,6 +23,7 @@ var/datum/port/output/trigger_port /obj/item/circuit_component/hear/populate_ports() + on = add_input_port("On", PORT_TYPE_NUMBER, default = 1) message_port = add_output_port("Message", PORT_TYPE_STRING) language_port = add_output_port("Language", PORT_TYPE_STRING) speaker_port = add_output_port("Speaker", PORT_TYPE_ATOM) @@ -40,6 +44,8 @@ return Hear(arglist(arguments)) /obj/item/circuit_component/hear/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range) + if(!on.value) + return FALSE if(speaker == parent?.shell) return FALSE diff --git a/code/modules/wiremod/components/math/toggle.dm b/code/modules/wiremod/components/math/toggle.dm new file mode 100644 index 0000000000000..9f51c974cb31f --- /dev/null +++ b/code/modules/wiremod/components/math/toggle.dm @@ -0,0 +1,36 @@ +/** + * # Toggle Component + * + * Does a toggle between true and false on trigger + */ +/obj/item/circuit_component/compare/toggle + display_name = "Toggle" + desc = "A component that toggles between on and off when triggered. All input ports (except for set toggle) will trigger the component." + category = "Math" + + /// A signal to reset the toggle back to 0 + var/datum/port/input/toggle_set + /// A signal to toggle and return the current state + var/datum/port/input/toggle_and_compare + + var/toggle_state = FALSE + +/obj/item/circuit_component/compare/toggle/populate_custom_ports() + toggle_set = add_input_port("Set Toggle State", PORT_TYPE_NUMBER) + toggle_and_compare = add_input_port("Toggle And Compare", PORT_TYPE_SIGNAL) + toggle_state = FALSE + +/obj/item/circuit_component/compare/toggle/input_received(datum/port/input/port) + if(port == toggle_set) + toggle_state = !!port.value + return + if(COMPONENT_TRIGGERED_BY(toggle_and_compare, port)) + toggle_state = !toggle_state + if(toggle_state) + true.set_output(COMPONENT_SIGNAL) + else + false.set_output(COMPONENT_SIGNAL) + return ..() + +/obj/item/circuit_component/compare/toggle/do_comparisons() + return toggle_state diff --git a/code/modules/wiremod/components/ntnet/ntnet_send.dm b/code/modules/wiremod/components/ntnet/ntnet_send.dm index 105af11760bc1..7ff4372927f3f 100644 --- a/code/modules/wiremod/components/ntnet/ntnet_send.dm +++ b/code/modules/wiremod/components/ntnet/ntnet_send.dm @@ -27,12 +27,17 @@ data_package = add_input_port("Data Package", PORT_TYPE_LIST(PORT_TYPE_ANY)) enc_key = add_input_port("Encryption Key", PORT_TYPE_STRING) +/obj/item/circuit_component/ntnet_send/should_receive_input(datum/port/input/port) + . = ..() + if(!.) + return FALSE + /// If the server is down, don't use power or attempt to send data + return find_functional_ntnet_relay() + /obj/item/circuit_component/ntnet_send/pre_input_received(datum/port/input/port) if(port == list_options) var/new_datatype = list_options.value data_package.set_datatype(PORT_TYPE_LIST(new_datatype)) /obj/item/circuit_component/ntnet_send/input_received(datum/port/input/port) - if(!find_functional_ntnet_relay()) - return - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CIRCUIT_NTNET_DATA_SENT, list("data" = data_package.value, "enc_key" = enc_key.value, "port" = WEAKREF(data_package))) + send_ntnet_data(data_package, enc_key.value) diff --git a/code/modules/wiremod/components/ntnet/ntnet_send_literal.dm b/code/modules/wiremod/components/ntnet/ntnet_send_literal.dm new file mode 100644 index 0000000000000..49e1c2b00abe5 --- /dev/null +++ b/code/modules/wiremod/components/ntnet/ntnet_send_literal.dm @@ -0,0 +1,30 @@ +/** + * # NTNet Transmitter List Literal Component + * + * Create a list literal and send a data package through NTNet + * + * This file is based off of ntnet_send.dm + * Any changes made to those files should be copied over with discretion + */ +/obj/item/circuit_component/list_literal/ntnet_send + display_name = "NTNet Transmitter List Literal" + desc = "Creates a list literal data package and sends it through NTNet. If Encryption Key is set then transmitted data will be only picked up by receivers with the same Encryption Key." + category = "NTNet" + + /// Encryption key + var/datum/port/input/enc_key + +/obj/item/circuit_component/list_literal/ntnet_send/populate_ports() + . = ..() + enc_key = add_input_port("Encryption Key", PORT_TYPE_STRING) + +/obj/item/circuit_component/list_literal/ntnet_send/should_receive_input(datum/port/input/port) + . = ..() + if(!.) + return FALSE + /// If the server is down, don't use power or attempt to send data + return find_functional_ntnet_relay() + +/obj/item/circuit_component/list_literal/ntnet_send/input_received(datum/port/input/port) + . = ..() + send_ntnet_data(list_output, enc_key.value) diff --git a/code/modules/wiremod/components/string/textcase.dm b/code/modules/wiremod/components/string/textcase.dm index ac28965423632..70b67740b416f 100644 --- a/code/modules/wiremod/components/string/textcase.dm +++ b/code/modules/wiremod/components/string/textcase.dm @@ -41,7 +41,7 @@ var/result switch(textcase_options.value) if(COMP_TEXT_LOWER) - result = lowertext(value) + result = LOWER_TEXT(value) if(COMP_TEXT_UPPER) result = uppertext(value) diff --git a/code/modules/wiremod/core/admin_panel.dm b/code/modules/wiremod/core/admin_panel.dm index 74e72ad5efe0c..9a262cb5e4c9f 100644 --- a/code/modules/wiremod/core/admin_panel.dm +++ b/code/modules/wiremod/core/admin_panel.dm @@ -1,10 +1,7 @@ -/// An admin verb to view all circuits, plus useful information -/datum/admins/proc/view_all_circuits() - set category = "Admin.Game" - set name = "View All Circuits" +ADMIN_VERB(view_all_circuits, R_ADMIN, "View All Circuits", "List all circuits in the game.", ADMIN_CATEGORY_GAME) var/static/datum/circuit_admin_panel/circuit_admin_panel = new - circuit_admin_panel.ui_interact(usr) + circuit_admin_panel.ui_interact(user.mob) /datum/circuit_admin_panel @@ -66,9 +63,10 @@ usr.client?.debug_variables(circuit) if ("open_circuit") circuit.ui_interact(usr) + if ("open_player_panel") var/datum/mind/inserter = circuit.inserter_mind?.resolve() - usr.client?.holder?.show_player_panel(inserter?.current) + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_player_panel, inserter?.current) return TRUE diff --git a/code/modules/wiremod/core/component.dm b/code/modules/wiremod/core/component.dm index 530f73ded8cd6..cf142d1e36520 100644 --- a/code/modules/wiremod/core/component.dm +++ b/code/modules/wiremod/core/component.dm @@ -77,7 +77,7 @@ /obj/item/circuit_component/Initialize(mapload) . = ..() if(name == COMPONENT_DEFAULT_NAME) - name = "[lowertext(display_name)] [COMPONENT_DEFAULT_NAME]" + name = "[LOWER_TEXT(display_name)] [COMPONENT_DEFAULT_NAME]" populate_options() populate_ports() if((circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL) && !trigger_input) @@ -405,3 +405,14 @@ */ /obj/item/circuit_component/proc/unregister_usb_parent(atom/movable/shell) return + +/** + * Called when a circuit component requests to send Ntnet data signal. + * + * Arguments: + * * port - The required list port needed by the Ntnet recieve + * * key - The encryption key + * * signal_type - The signal type used for sending this global signal (optional, default is COMSIG_GLOB_CIRCUIT_NTNET_DATA_SENT) + */ +/obj/item/circuit_component/proc/send_ntnet_data(datum/port/input/port, key, signal_type = COMSIG_GLOB_CIRCUIT_NTNET_DATA_SENT) + SEND_GLOBAL_SIGNAL(signal_type, list("data" = port.value, "enc_key" = key, "port" = WEAKREF(port))) diff --git a/code/modules/wiremod/core/component_printer.dm b/code/modules/wiremod/core/component_printer.dm index 7c691e3a4c47b..370a6cfea5244 100644 --- a/code/modules/wiremod/core/component_printer.dm +++ b/code/modules/wiremod/core/component_printer.dm @@ -24,7 +24,7 @@ . = ..() materials = AddComponent(/datum/component/remote_materials, mapload) -/obj/machinery/component_printer/LateInitialize() +/obj/machinery/component_printer/post_machine_initialize() . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !techweb) CONNECT_TO_RND_SERVER_ROUNDSTART(techweb, src) diff --git a/code/modules/wiremod/core/duplicator.dm b/code/modules/wiremod/core/duplicator.dm index 2f248d11a8938..25e8332680432 100644 --- a/code/modules/wiremod/core/duplicator.dm +++ b/code/modules/wiremod/core/duplicator.dm @@ -220,30 +220,24 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list( rel_x = component_data["rel_x"] rel_y = component_data["rel_y"] -/client/proc/load_circuit() - set name = "Load Circuit" - set category = "Admin.Fun" - - if(!check_rights(R_VAREDIT)) - return - +ADMIN_VERB(load_circuit, R_VAREDIT, "Load Circuit", "Loads a circuit from a file or direct input.", ADMIN_CATEGORY_FUN) var/list/errors = list() - var/option = alert(usr, "Load by file or direct input?", "Load by file or string", "File", "Direct Input") + var/option = alert(user, "Load by file or direct input?", "Load by file or string", "File", "Direct Input") var/txt switch(option) if("File") - txt = file2text(input(usr, "Input File") as null|file) + txt = file2text(input(user, "Input File") as null|file) if("Direct Input") - txt = input(usr, "Input JSON", "Input JSON") as text|null + txt = input(user, "Input JSON", "Input JSON") as text|null if(!txt) return - var/obj/item/integrated_circuit/loaded/circuit = new(mob.drop_location()) + var/obj/item/integrated_circuit/loaded/circuit = new(user.mob.drop_location()) circuit.load_circuit_data(txt, errors) if(length(errors)) - to_chat(src, span_warning("The following errors were found whilst compiling the circuit data:")) + to_chat(user, span_warning("The following errors were found whilst compiling the circuit data:")) for(var/error in errors) - to_chat(src, span_warning(error)) + to_chat(user, span_warning(error)) diff --git a/code/modules/wiremod/core/integrated_circuit.dm b/code/modules/wiremod/core/integrated_circuit.dm index 7dde89e511612..5a825b81482e8 100644 --- a/code/modules/wiremod/core/integrated_circuit.dm +++ b/code/modules/wiremod/core/integrated_circuit.dm @@ -80,6 +80,9 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) /// The Y position of the screen. Used for adding components. var/screen_y = 0 + /// The grid mode state for the circuit. + var/grid_mode = TRUE + /// The current size of the circuit. var/current_size = 0 @@ -400,6 +403,7 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) .["examined_notices"] = examined?.get_ui_notices() .["examined_rel_x"] = examined_rel_x .["examined_rel_y"] = examined_rel_y + .["grid_mode"] = grid_mode .["is_admin"] = (admin_only || isAdminGhostAI(user)) && check_rights_for(user.client, R_VAREDIT) @@ -577,6 +581,9 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) else set_display_name("") . = TRUE + if("toggle_grid_mode") + toggle_grid_mode() + . = TRUE if("set_examined_component") var/component_id = text2num(params["component_id"]) if(!WITHIN_RANGE(component_id, attached_components)) @@ -709,6 +716,10 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) else shell.name = initial(shell.name) +/// Toggles the grid mode property for this circuit. +/obj/item/integrated_circuit/proc/toggle_grid_mode() + grid_mode = !grid_mode + /** * Returns the creator of the integrated circuit. Used in admin messages and other related things. */ diff --git a/code/modules/wiremod/shell/controller.dm b/code/modules/wiremod/shell/controller.dm index ad03867b89be4..b46dad3673f58 100644 --- a/code/modules/wiremod/shell/controller.dm +++ b/code/modules/wiremod/shell/controller.dm @@ -71,9 +71,9 @@ */ /obj/item/circuit_component/controller/proc/send_alternate_signal(atom/source, mob/user) SIGNAL_HANDLER - if(!user.Adjacent(source)) - return + handle_trigger(source, user, "alternate", alt) + return CLICK_ACTION_SUCCESS /** diff --git a/code/modules/wiremod/shell/dispenser.dm b/code/modules/wiremod/shell/dispenser.dm index 4ea2d03c9d706..4a00f7fed88d0 100644 --- a/code/modules/wiremod/shell/dispenser.dm +++ b/code/modules/wiremod/shell/dispenser.dm @@ -18,10 +18,9 @@ var/list/obj/item/stored_items = list() var/locked = FALSE -/obj/structure/dispenser_bot/deconstruct(disassembled) +/obj/structure/dispenser_bot/atom_deconstruct(disassembled = TRUE) for(var/obj/item/stored_item as anything in stored_items) remove_item(stored_item) - return ..() /obj/structure/dispenser_bot/Destroy() QDEL_LIST(stored_items) diff --git a/code/modules/wiremod/shell/gun.dm b/code/modules/wiremod/shell/gun.dm index ff5815367139b..283815fb3346b 100644 --- a/code/modules/wiremod/shell/gun.dm +++ b/code/modules/wiremod/shell/gun.dm @@ -30,7 +30,7 @@ range = 7 /obj/item/stock_parts/cell/emproof/wiremod_gun - maxcharge = 100 + maxcharge = 0.1 * STANDARD_CELL_CHARGE /obj/item/gun/energy/wiremod_gun/Initialize(mapload) . = ..() @@ -82,6 +82,6 @@ if(!parent?.cell) return var/obj/item/gun/energy/fired_gun = source - var/totransfer = min(100 KILO JOULES, parent.cell.charge) - var/transferred = fired_gun.cell.give(totransfer) - parent.cell.use(transferred) + var/transferred = fired_gun.cell.give(min(0.1 * STANDARD_CELL_CHARGE, parent.cell.charge)) + if(transferred) + parent.cell.use(transferred, force = TRUE) diff --git a/code/modules/wiremod/shell/module.dm b/code/modules/wiremod/shell/module.dm index 6f9a3dda93b7e..9061bac3e300e 100644 --- a/code/modules/wiremod/shell/module.dm +++ b/code/modules/wiremod/shell/module.dm @@ -106,7 +106,7 @@ action_comp.granted_to[REF(user)] = src circuit_component = action_comp name = action_comp.button_name.value - button_icon_state = "bci_[replacetextEx(lowertext(action_comp.icon_options.value), " ", "_")]" + button_icon_state = "bci_[replacetextEx(LOWER_TEXT(action_comp.icon_options.value), " ", "_")]" /datum/action/item_action/mod/pinnable/circuit/Destroy() circuit_component.granted_to -= REF(pinner) diff --git a/code/modules/wiremod/shell/moneybot.dm b/code/modules/wiremod/shell/moneybot.dm index cacb457149dc7..f3c2dfe93dab4 100644 --- a/code/modules/wiremod/shell/moneybot.dm +++ b/code/modules/wiremod/shell/moneybot.dm @@ -15,9 +15,8 @@ var/stored_money = 0 var/locked = FALSE -/obj/structure/money_bot/deconstruct(disassembled) +/obj/structure/money_bot/atom_deconstruct(disassembled = TRUE) new /obj/item/holochip(drop_location(), stored_money) - return ..() /obj/structure/money_bot/proc/add_money(to_add) stored_money += to_add diff --git a/config/config.txt b/config/config.txt index 1c87fc110ae9a..09824fed555e8 100644 --- a/config/config.txt +++ b/config/config.txt @@ -143,16 +143,26 @@ GUEST_BAN ## IPINTEL: ## This allows you to detect likely proxies by checking ips against getipintel.net -## Rating to warn at: (0.9 is good, 1 is 100% likely to be a spammer/proxy, 0.8 is 80%, etc) anything equal to or higher then this number triggers an admin warning -#IPINTEL_RATING_BAD 0.9 +## Rating to warn at: (0.8 is good, 1 is 100% likely to be a spammer/proxy, 0.8 is 80%, etc) anything equal to or higher then this number triggers an admin warning +#IPINTEL_RATING_BAD 0.8 ## Contact email, (required to use the service, leaving blank or default disables IPINTEL) #IPINTEL_EMAIL ch@nge.me -## How long to save good matches (ipintel rate limits to 15 per minute and 500 per day. so this shouldn't be too low, getipintel.net suggests 6 hours, time is in hours) (Your ip will get banned if you go over 500 a day too many times) -#IPINTEL_SAVE_GOOD 12 -## How long to save bad matches (these numbers can change as ips change hands, best not to save these for too long in case somebody gets a new ip used by a spammer/proxy before.) -#IPINTEL_SAVE_BAD 3 -## Domain name to query (leave commented out for the default, only needed if you pay getipintel.net for more querys) -#IPINTEL_DOMAIN check.getipintel.net +## Query base, if you pay for more queries this is what you want to change. +#IPINTEL_BASE check.getipintel.net +## Maximum number of queries in a minute +#IPINTEL_MAX_QUERY_MINUTE 15 +## Maximum number of queries in a day +#IPINTEL_MAX_QUERY_DAY 500 +## Whether clients which cannot be checked due to a rate limit will be denied +#IPINTEL_REJECT_RATE_LIMITED +## Whether clients which are flagged as a VPN will be denied +IPINTEL_REJECT_BAD +## Whether clients which cannot be checked due to an error of some form will be denied +#IPINTEL_REJECT_UNKNOWN +## How long to store results in the cache before they must be retrieved again. IN DAYS. +#IPINTEL_CACHE_LENGTH 7 +## How many minutes of living playtime to be automatically exempt from IPIntel. 0 for never. +#IPINTEL_EXEMPT_PLAYTIME_LIVING 0 ## Uncomment to allow web client connections #ALLOW_WEBCLIENT @@ -368,14 +378,14 @@ AUTOADMIN_RANK Game Master ## These trigger for any version below (non-inclusive) the given version, so 510 triggers on 509 or lower. ## These messages will be followed by one stating the clients current version and the required version for clarity. ## If CLIENT_WARN_POPUP is uncommented a popup window with the message will be displayed instead -#CLIENT_WARN_VERSION 511 -#CLIENT_WARN_BUILD 1421 +#CLIENT_WARN_VERSION 515 +#CLIENT_WARN_BUILD 1635 #CLIENT_WARN_POPUP -#CLIENT_WARN_MESSAGE Byond released 511 as the stable release. You can set the framerate your client runs at, which makes the game feel very different and cool. Shortly after its release we will end up using 511 client features and you will be forced to update. -CLIENT_ERROR_VERSION 511 +#CLIENT_WARN_MESSAGE Byond released 515 as the stable release. This comes bundled with a host of niceties, including image generation for UIs and :: operators. +CLIENT_ERROR_VERSION 515 CLIENT_ERROR_MESSAGE Your version of byond is not supported. Please upgrade. -## The minimum build needed for joining the server, if using 512, a good minimum build would be 1421 as that disables the Middle Mouse Button exploit. -CLIENT_ERROR_BUILD 1421 +## The minimum build needed for joining the server. +CLIENT_ERROR_BUILD 1590 ## TOPIC RATE LIMITING ## This allows you to limit how many topic calls (clicking on an interface window) the client can do in any given game second and/or game minute. diff --git a/config/game_options.txt b/config/game_options.txt index f6d321c1b8e13..2979648126dde 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -147,6 +147,13 @@ EVENTS_MIN_TIME_MUL 1 ## Set to 0 to make dangerous events avaliable for all populations. EVENTS_MIN_PLAYERS_MUL 1 +## The lower bound, in deciseconds, for how soon another random event can be scheduled. +## Defaults to 1500 deciseconds or 2.5 minutes +EVENTS_FREQUENCY_LOWER 1500 + +## The upper bound, in deciseconds, for how soon another random event can be scheduled. +## Defaults to 4200 deciseconds or 7 minutes +EVENTS_FREQUENCY_UPPER 4200 ## AI ### @@ -265,6 +272,7 @@ RANDOM_LAWS corporate #RANDOM_LAWS reporter #RANDOM_LAWS hulkamania #RANDOM_LAWS ten_commandments +#RANDOM_LAWS yesman ## Bad idea laws. Probably shouldn't enable these #RANDOM_LAWS syndie diff --git a/config/jobconfig.toml b/config/jobconfig.toml index 7106d2f2a4ef5..294868e28bb5e 100644 --- a/config/jobconfig.toml +++ b/config/jobconfig.toml @@ -183,8 +183,8 @@ "# Playtime Requirements" = 0 "# Required Account Age" = 0 "# Required Character Age" = 0 -"# Spawn Positions" = 3 -"# Total Positions" = 5 +"# Spawn Positions" = 4 +"# Total Positions" = 6 [MIME] "# Playtime Requirements" = 0 @@ -270,13 +270,6 @@ "# Spawn Positions" = 0 "# Total Positions" = 0 -[VIROLOGIST] -"# Playtime Requirements" = 60 -"# Required Account Age" = 0 -"# Required Character Age" = 0 -"# Spawn Positions" = 1 -"# Total Positions" = 1 - [WARDEN] "# Playtime Requirements" = 300 "# Required Account Age" = 7 diff --git a/cutter_templates/bitmask/restore.toml b/cutter_templates/bitmask/restore.toml new file mode 100644 index 0000000000000..066354eedc606 --- /dev/null +++ b/cutter_templates/bitmask/restore.toml @@ -0,0 +1,20 @@ +# Bitmask restoration! +# Allows for easy mass extraction of template pngs and their configs from a dmi +# Use this if you have a dmi and you want a cutter config you can edit easily +# Of note, while it tries its best it is nowhere near perfect. We don't parity check against the existing dmi +# And we also do not account for overrided states very well +# Always double check (and be aware that dmi is weird so you may get diffs of 1 rgb value when doin this) +mode = "BitmaskSliceReconstruct" +# List of icon states to pull out (by default) +extract = ["0", "3", "12", "15", "255"] + +# Map of name -> state that will be encoded into a positions list later +# Lets you extract particular states and use them to fill in for states later +# Useful to carry over odd snowflake states +#[bespoke] + +# Map of key -> value to set on the created config +# Lets you set arbitrary values on the created config, mostly useful for batch processing +# IMPORTANT NOTE: We sort of assume you'll setup a default template here (since this is for batch processing), +# so if things work odd that's likely why +#[set] diff --git a/dependencies.sh b/dependencies.sh index 087c337a0461f..d5c22948358b6 100644 --- a/dependencies.sh +++ b/dependencies.sh @@ -5,14 +5,15 @@ # byond version export BYOND_MAJOR=515 -export BYOND_MINOR=1633 +export BYOND_MINOR=1637 #rust_g git tag export RUST_G_VERSION=3.1.0 #node version -export NODE_VERSION=20 -export NODE_VERSION_LTS=20.12.0 +export NODE_VERSION_LTS=20.13.0 +# compatiblility mode MUST work with windows 7 +export NODE_VERSION_COMPAT=20.2.0 # SpacemanDMM git tag export SPACEMAN_DMM_VERSION=suite-1.8 @@ -27,7 +28,7 @@ export AUXLUA_REPO=tgstation/auxlua export AUXLUA_VERSION=1.4.4 #hypnagogic repo -export CUTTER_REPO=actioninja/hypnagogic +export CUTTER_REPO=spacestation13/hypnagogic #hypnagogic git tag -export CUTTER_VERSION=v3.0.1 +export CUTTER_VERSION=v3.1.0 diff --git a/html/changelogs/AutoChangeLog-pr-82402.yml b/html/changelogs/AutoChangeLog-pr-82402.yml deleted file mode 100644 index 1c0eedc6f5af1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82402.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Momo8289" -delete-after: True -changes: - - bugfix: "Holographic energy swords have undergone some more rigorous safety inspections, and should no longer be a danger to clumsy crew members." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82537.yml b/html/changelogs/AutoChangeLog-pr-82537.yml new file mode 100644 index 0000000000000..05eb79c52e55e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82537.yml @@ -0,0 +1,4 @@ +author: "sheets, spacemenart, ben10omintrix, goofball, infrared baron, aofie" +delete-after: True +changes: + - rscadd: "adds lavaland raptors and the raptor ranch" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83163.yml b/html/changelogs/AutoChangeLog-pr-83163.yml new file mode 100644 index 0000000000000..596a19c31cdd5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83163.yml @@ -0,0 +1,6 @@ +author: "Melbert" +delete-after: True +changes: + - rscadd: "Icebox: The bar returns to its home." + - rscadd: "Icebox: Standardizes some decal styles in the main hallway." + - bugfix: "Icebox: The lower brig's missing air alarm has been found." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83175.yml b/html/changelogs/AutoChangeLog-pr-83175.yml new file mode 100644 index 0000000000000..74e6d3adc8fae --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83175.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - rscadd: "Adds Minecarts, (possibly admin only depending on when this PR is merged in relation to the Icebox Bar PR)" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83226.yml b/html/changelogs/AutoChangeLog-pr-83226.yml new file mode 100644 index 0000000000000..4b238c2c09934 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83226.yml @@ -0,0 +1,4 @@ +author: "Sadboysuss" +delete-after: True +changes: + - bugfix: "fixed malf AI being able to overload shuttle consoles and the gateway control console" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83228.yml b/html/changelogs/AutoChangeLog-pr-83228.yml new file mode 100644 index 0000000000000..4b54488895c0f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83228.yml @@ -0,0 +1,5 @@ +author: "Hatterhat" +delete-after: True +changes: + - qol: "The Ansem, suppressor, and SC/FISHER included in the Fisher gimmick bundle now come together as one whole gun, the Ansem/SC. It's integrally suppressed, and fires the disruptor on right-click." + - bugfix: "The SC/FISHER disrupts APCs for an appropriate amount of time, not ten times the intended disruption length." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83233.yml b/html/changelogs/AutoChangeLog-pr-83233.yml new file mode 100644 index 0000000000000..e9af66c53c507 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83233.yml @@ -0,0 +1,4 @@ +author: "improvedname" +delete-after: True +changes: + - balance: "Nukies ordnance now include more gasses and stock parts" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83241.yml b/html/changelogs/AutoChangeLog-pr-83241.yml new file mode 100644 index 0000000000000..e96d12b9a0fab --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83241.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "You will now be ejected from Space Phase if you lose your focus or lose consciousness somehow during the jaunt." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83250.yml b/html/changelogs/AutoChangeLog-pr-83250.yml new file mode 100644 index 0000000000000..96dc09bab0959 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83250.yml @@ -0,0 +1,4 @@ +author: "DaCoolBoss" +delete-after: True +changes: + - bugfix: "adds missing prefix to name of The Lizard's Gas Lava land ruin." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83252.yml b/html/changelogs/AutoChangeLog-pr-83252.yml new file mode 100644 index 0000000000000..3df9ade7e6f48 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83252.yml @@ -0,0 +1,5 @@ +author: "ShizCalev" +delete-after: True +changes: + - bugfix: "Malf AI can now override/overload closed turrets." + - bugfix: "Fixed a scenario in which a turret would have its covers closed while still firing." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83259.yml b/html/changelogs/AutoChangeLog-pr-83259.yml new file mode 100644 index 0000000000000..e439ae7128516 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83259.yml @@ -0,0 +1,4 @@ +author: "Echriser" +delete-after: True +changes: + - bugfix: "Fixes a bunch of hearts turning into errors when you try to eat them" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83265.yml b/html/changelogs/AutoChangeLog-pr-83265.yml new file mode 100644 index 0000000000000..2bca25f700506 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83265.yml @@ -0,0 +1,4 @@ +author: "grungussuss" +delete-after: True +changes: + - qol: "suit sensors can now be maxed by ctrl clicking your jumpsuit" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83266.yml b/html/changelogs/AutoChangeLog-pr-83266.yml new file mode 100644 index 0000000000000..b68ca89b10840 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83266.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - bugfix: "Mob spawners (such as lavaland tendrils) won't spawn more mobs than they are supposed to, faster than they should." \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 2475630906b24..9677f61ec718a 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -152,3 +152,760 @@ - qol: Makes the clown anomalous crystal actually useful for once rather than an open griefing tool. It now revives the dead...as clowns! - admin: Adds logging for the anomalous crystal activation, including fingerprints. +2024-04-05: + 00-Steven: + - bugfix: 'All Nighter: fixed a runtime from not having a head, whether from hars/deletion/somesuch.' + - bugfix: 'All Nighter: losing and regaining your head while you had eyebags no + longer removes your eyebags until you''ve slept.' + Bilbo367: + - bugfix: material experiments not scanning + DATA-xPUNGED: + - bugfix: Fixes Alcoholic quirk selection + - bugfix: Fixes Junkie, Smoker, and Alcoholic not giving you more addiction when + you come clean. + KingkumaArt: + - bugfix: Moves that one wall on NorthStar to not block the maints passage + Majkl-J: + - bugfix: Observers can now see people's quirks again + Melbert: + - qol: Breathing cold air now has a particle effect associated, careful not to let + your glasses fog up. + - qol: Breathing cold air will now occasionally make your spaceman shiver. Brrr. + - bugfix: Heretic sac restarts your heart + Momo8289: + - bugfix: Holographic energy swords have undergone some more rigorous safety inspections, + and should no longer be a danger to clumsy crew members. + Zergspower: + - bugfix: borg panel access now requires robotics access again + nikothedude: + - bugfix: Root beer no longer causes laser carbines and disabler smgs to fire infinitely + fast. +2024-04-06: + 00-Steven: + - admin: Refresh button on the View Round Logs menu actually works, instead of just + adding a runtime to the logs (and not updating them). + Archie700: + - bugfix: changed value of cell charge from 5000 to 5 megajoules + Artemchik542: + - bugfix: aheal now properly heals ears deafness + Blacklist897: + - balance: suit and cell chargers should draw from grid preventing instant apc blackouts + in most cases. + EnterTheJake: + - balance: CNS Rebooter Implant will now pull you out of stamcrit and grant you + a few seconds of stun immunity + JohnFulpWillard: + - admin: Removing components button now lists components to remove + Rhials: + - rscadd: Nuclear Operatives now purchase an Intelligence Agent, who can watch cameras + and bodycams, move the shuttle, and provide radio support. Only 12 Telecrystals! + SyncIt21: + - refactor: refactors how objects are deconstructed in relation to the `NO_DECONSTRUCTION` + flag. Certain objects & machinery may display different tool interactions & + behaviours when destroyed/deconstructed. Report these changes if you feel like + they are bugs + Zergspower: + - bugfix: fixes Borg and Syndicate inducers not working + jlsnow301, infraredbaron: + - rscadd: Added a new UI element over players that are interacting, building, etc. +2024-04-07: + Bilbo367: + - bugfix: Narcolepsy is no longer activated while neutered. + JohnFulpWillard: + - bugfix: You can no longer take chemicals out of medipens with a syringe. + - balance: Basic mob AIs with no mobs on the Z level now stop. + Melbert: + - bugfix: Fix fancy anomaly theme being broken + - bugfix: Skill rewards should properly be dropped out of unworthy player's hands + - bugfix: Items will properly pass through slime on occasion + - bugfix: Captive Xeno end round report should make a tad more sense + Skeleton-In-Disguise: + - rscadd: Transhumanist now allows you to select your augmentation + - rscadd: Transhumanist can now provide a robotic voice box, or flashlight eyes + - spellcheck: Transhumanist's roundstart text has been re-written to not be wrong + Vishenka0704: + - qol: Added search bar to character prefs catalogs + mc-oofert: + - balance: punches no longer knock down or deal stamina damage + necromanceranne: + - rscadd: Watcher wreaths. Made from the mangled remains of a watcher, now a handsome + accessory for you to wear a few inches behind your head. Comes in Normal and + Icewing variants. + - rscadd: Some bounties for the two variants of watcher wreaths. +2024-04-08: + Fluffles: + - bugfix: Hats/glasses/masks should hopefully behave more predictably for the purposes + of eye/mouth surgery. + Jacquerel: + - rscadd: Adds a new Final Objective where you force your fellow crew to fight to + the death on pain of... death. + LemonInTheDark: + - bugfix: The color matrix editor now works properly again + Metekillot: + - bugfix: Broken chameleon kits can't be unbroken by an EMP. + Rhials: + - bugfix: Sweeps a tile of dust off of the Maint Mania deathmatch map, which was + causing errors. +2024-04-09: + JohnFulpWillard, Zeek the Rat: + - rscadd: Battle Arcade has been completely overhauled in a new progression system, + this time using TGUI. + - rscadd: The Curator's keys can now reset arcade cabinets. + - balance: You now need to be literate to play arcade games, except for Mediborg's + Amputation Adventure. + - bugfix: You can no longer screwdriver emagged arcade consoles. Accept your fate. + - bugfix: Silicons can no longer play Mediborg's Amputation Adventure. + Melbert: + - spellcheck: Shoes and Gloves are now referred to as "a pair of" rather than "some". + - spellcheck: Reinforced Window's description is less out of place. + - spellcheck: Fixed an empty space in examining a human's bloody hands. + - code_imp: It's a tad easier to exit an atom's examine text now. + mc-oofert: + - qol: slaughter/laughter demons have a cooler round end report + - qol: you may not bodyslam yourself as a demon + - code_imp: slaughter and laughter demons are given their antag datum when their + mind initializes +2024-04-10: + 00-Steven: + - bugfix: Lead acid batteries have had their power values fixed. + 00-Steven, SyncIt21: + - bugfix: Wrench table deconstruction gives the right materials again. + - bugfix: Screwdriver table deconstruction only deconstructs the top again. + ArcaneMusic: + - bugfix: Vorpal Scythe execute messages now read correctly. + Bisar: + - bugfix: Mechs will no longer delete their living non-occupant contents when destroyed. + Higgin: + - balance: 'Spies can now get five additional types of objective: Protect Human, + Protect Nonhuman, Detain, Jailbreak, and Escape (Exile).' + - balance: Spy objectives now feature a much wider array of targets and treatments. + - refactor: added no_failure var to objectives. Objectives with no_failure = TRUE + do not print a success at roundend. Custom objectives use this now instead of + a separate string. + IndieanaJones: + - qol: Basic dexterous mobs now have a health doll and screen damage indication + like other basic mobs. + JohnFulpWillard: + - rscadd: A bunch of new medipens you can refill with the medipen refiller (survival/luxury/mutadone/saturnx/meth) + - bugfix: Mech pads, door buttons, message monitors, tram machines, abductor consoles + & holodeck computers now use power. + JohnFulpWillard, Tattax: + - rscadd: Monkeys can now wear all jumpsuits. + - rscadd: Bioscrambler anomalies can now give monkey legs. + - bugfix: Monkeys can have their tails removed, and tails are no longer invisible + when implanted into another species. + Melbert: + - bugfix: You can't fit items which are normally too large for a storage by fitting + it in the storage when it is small, then growing it to a larger size. + NeonNik2245: + - rscadd: Adds anosmia quirk + Pickle-Coding: + - bugfix: Fixes many instances of energy sources for ethereals supplying a thousand + times less energy than intended. + - bugfix: Fixes recharging stations not being able to charge ethereals. + - bugfix: Fixes recharge stations charging too fast. + - qol: Recharge stations display their recharging speed in formatted power, rather + than unformatted energy per cycle. + - balance: Cells will only consider 0.1% of their charge for calculating shock damage. + Rhials: + - bugfix: The tide of post-round blob zombies when a blob wins will no longer break + the speakers in your headset. + SyncIt21: + - bugfix: Reagent grinders display reagents of its beaker on examination + Thunder12345: + - rscadd: Added support for directional explosions. + - rscadd: Rocket launcher backblast is now 271% more explosive, check your six for + friendlies! + - rscadd: X4 charges now explode in a cone away from the user when placed on a sufficiently + solid object. + - bugfix: 'X4 charges will now behave correctly when placed on dense atoms (note: + don''t try to read a variable from an atom you just blew up)' + mc-oofert: + - bugfix: deathmatch can no longer occassionally send people to nullspace + necromanceranne: + - image: Updates the colors of various material datum to bring them closer in-line + with their actual material stacks + - image: Improves the sprites for the material knight armor and helmet. +2024-04-11: + Absolucy: + - qol: Added balloon alerts whenever you start plunging something (i.e ) + Bilbo367: + - bugfix: fixes ody sleeper UI not updating to new chems to inject. + - bugfix: fixes ody sleeper not telling user why they can't pick up a person. + - code_imp: gives a common method for giving reagent list data to .tsx + Boviro: + - qol: Atmospherics Overalls now can store fire extinguishers in the suit storage + slot + - balance: Increased Advanced Extinguisher capacity to 100u + Jacquerel: + - bugfix: Medbots can no longer be used as especially large golden ID cards + JohnFulpWillard: + - refactor: Blueprints now use TGUI. + - qol: Blueprints can now be used while lying down. + SethLafuente: + - bugfix: Fixes Radiation Hood not having FOV blockage + SyncIt21: + - qol: Adds screen tips & examines for screwdriver, wrench, crowbar & beaker insertion, + removal & replacing actions + - qol: Analyzing reagents no longer blocks other players from doing other operations. + Multiple players can analyze different reagents on the same machine + - qol: You cannot do any tool acts on the machine while printing to prevent any + side effects. + - qol: The preferred container for the master reagent in the beaker is now showed + in both condiment & chem master. The feature can be enabled/disabled via a check + box + - code_imp: removed defines for reagent transfer, vars for reagent analyzis to save + memory. Autodoc for other vars & procs + - bugfix: You can hit the chem master with tools like screwdriver, crowbar, wrench + & beaker in combat mode + - bugfix: You cannot insert hologram items into the chem master + - bugfix: Deconstructing a condiment master will give you the circuit board already + pre-programmed with that option + - bugfix: You now print the exact amount of containers requested even with upgraded + parts without creating empty containers. Max printable containers is 13 with + tier 4 parts able to print 50 containers. + - refactor: Optimized client side UI code & chem master as a whole. + - bugfix: Autolathe correctly computes the print amount of custom material items + like toolboxes and doesn't grey out its print button + Watermelon914: + - admin: LUA - Adds a new library called handler_group. Include it in your files + by doing require('handler_group') + YesterdaysPromise: + - rscadd: Added long balloon box to the clown's starting inventory, and a skill-chip + of long lost honk-motherian knowledge to their brain. + - rscadd: Added long balloons. Consequently, added balloon animals to make from + such balloons. Also, balloon top hat, vest, helmet, and a mallet. Don't ask + about the mallet. + - rscadd: A long balloons box harvested fresh from the farms on the clown planet + will be able to be shipped in a crate to the cargo department near you! + - rscadd: As per requests; water balloons can now be printed at service lathe, and + entertainment modsuit can now blow long balloons! + - image: Balloons will now have an unique sprite when in the inventory, compared + when to on the ground. +2024-04-12: + 00-Steven: + - bugfix: Standard RPEDs work on machines again. + Jacquerel: + - spellcheck: Effectively hitting furniture and machines with objects will no longer + be double punctuated. + - bugfix: Goliaths can't grab their own riders with tentacles + Melbert: + - qol: Basic Bots will use their "salute" emotes less often. + - rscdel: Basic bot fists. + Pickle-Coding: + - balance: Atmos resin can directly cool the floor. + SyncIt21: + - code_imp: renamed `NO_DECONSTRUCTION` to `NO_DEBRIS_AFTER_DECONSTRUCTION` so its + name matches its intended purpose + - bugfix: fixes some items that incorrectly used `NO_DECONSTRUCTION` prior to its + refactor, meaning makes some objects non deconstructable again + disappointedButNotSuprised: + - rscadd: Coffee machines can now carry over reagents from the beans to the coffee + (surely no one will inject poison into them) +2024-04-13: + 00-Steven: + - refactor: Instead of being hardcoded to the pen, renaming items is now an element. + Currently only pens have this, and functionality should be the same, but please + report it if you find any items that were renamable but now aren't. + DaCoolBoss: + - spellcheck: Fixes a typo in the cargo console. + Horatio22: + - spellcheck: grammar fixes in the roundstart advisory warnings + Iamgoofball: + - bugfix: Fixes AI lag by re-adding idle mode to all AI that was lost with the simple + mob to basic mob conversion. + - bugfix: AI controllers with no clients around for 14 tiles will move into idle + mode and stop planning or acting. + - bugfix: AI controllers will now record how much time was spent on planning or + un-idling AI controllers. + Jacquerel: + - balance: The Bioscrambler will now actively attempt to get closer to living targets + rather than chilling in a closet nobody goes into (unless you trap it in a containment + field). + - balance: Because it can now travel through walls, the Bioscrambler will no longer + transform you THROUGH walls. + JohnFulpWillard: + - bugfix: Advanced camera consoles now boots you off when you're moved out of reach. + Ketrai: + - qol: chef equipment can now deposit and withdraw to/from trays! + - qol: chef now has access to griddle and oven sized trays! + - qol: service can now print soup pots + Melbert: + - bugfix: You can't change the GPS tag of something unless you can actually use + the GPS + - bugfix: You can't set the teleporter to a location unless you can actually use + the teleporter + - bugfix: You can't reply to request console requests unless you can actually use + the console + - bugfix: You can't update AI lawboards unless you're actually holding them + - bugfix: You can't update a borg rename board unless you're actually holding it + - bugfix: You can't mess with plumbing machines unless you can actually use them + - bugfix: You can't recolor / relayer ducts unless you're actually holding them + - bugfix: You can't magically wire APCs and SMESs unless you're right by them + - bugfix: You can't use Stargazer Telepathy on people who you can't see + - bugfix: You can't configure the Inspector Hat unless you can actually use it + StrangeWeirdKitten: + - balance: The upload and communication boards directly have trackers installed, + activated only when authenticated. + SyncIt21: + - bugfix: chem master properly shuts down if it loses power mid printing and won't + transfer reagents for the same + Watermelon914: + - bugfix: 'LUA: Registering a signal on a deleted datum will throw a more descriptive + error message.' + ZephyrTFA: + - admin: Something changed, but you shouldn't be able to notice. If verbs are funky + report this to <@946283057915232337> on discord. + hyperjll: + - balance: Haloperidol now purges 2 units per second of itself, should the victim + have zero stamina. (Stamcrit) + jlsnow301: + - bugfix: 'Deviants buffed: Rogue shoelacing, pickpocketing and restraint resisting + no longer give cogbar icons.' + - bugfix: Airlock electronics and other access-config type UIs should look much + better. + wesoda25: + - bugfix: blood rites - will no longer delete after running out of charges + - bugfix: blood rites - now heal shades as well + - bugfix: blood rites - now charge 1.65x for self healing as opposed to the ~2x + they were before + - code_imp: blood rites code hurts my eyes a bit less now +2024-04-14: + 00-Steven: + - bugfix: Clicking the buckled alert unbuckles you again. + Bisar: + - qol: Cyborgs now understand door and APC wires at a glance, among others + Jacquerel: + - bugfix: Living Limbs created by Bioscrambler will be alive. + - bugfix: Living Limbs can once more attach themselves to your body. + - balance: Living Limbs will prioritise attacking your limbs. + - bugfix: Basic Mobs will once again spread their damage across body zones instead + of only attacking your chest. + JohnFulpWillard: + - bugfix: The HoP's photobooth button is now consistently connected to the HoP's + photobooth. + Metekillot: + - bugfix: Being in critical condition no longer damages zombies. + - code_imp: TRAIT_NODEATH will actually stop you dying in (most) cases. + SyncIt21: + - bugfix: Operating computers clears its ui display procedures if patient is moved + out of the operating table in any way + - bugfix: you can put back the oven tray after you take it out + - bugfix: only oven trays are allowed in ovens preventing baked food runtimes + - bugfix: advanced camera consoles correctly deactivate when something happens(no + proximity, no power etc) to its user + kaylexis: + - image: Updates old belt sprites. Mostly the bags, but some misc. ones as well + like the chainsword and RPED +2024-04-15: + AMyriad: + - image: Updated the ability icons used by AIs and station bots + AyIong: + - qol: General settings tab into TGchat, looks better now, and is more convenient + to use. Also, each button has a font written on it. + Ben10Omintrix: + - bugfix: minebots no longer bomb each other (and other miners) through landmines + - bugfix: minebot shields will no longer lose color in lower z levels + JohnFulpWillard: + - bugfix: Battle arcade's higher levels no longer gives you a "Gear" gear, and counterattacks + can now properly kill enemies. + - qol: Crayons can now draw up to 4 letters at a time per tile. + Thunder12345: + - spellcheck: Pre-Approved Cyborg Candidates are no longer "Cantidates" + jlsnow301: + - rscadd: Added a loot window for alt-clicking tiles. + - rscdel: Removed the item browser from the stat panel. +2024-04-16: + Iajret: + - bugfix: wiring newly built SMESes should place new teminal under the player and + not under the SMES itself. + TheRyeGuyWhoWillNowDie: + - bugfix: strip menu sensors change respects locked sensors +2024-04-17: + 00-Steven: + - bugfix: RPEDs can be used on vendors again. Note that only bluespace RPEDs can + carry vendor refills as of writing. + - bugfix: RPEDs can display vendor parts again. + - bugfix: Restocking vendors gives credits whether done manually or by RPEDs. + - bugfix: Vendors reset their contained credits when restocked. + AMyriad: + - bugfix: Probably fixed directional tinted windows looking like directional frosted + windows + - image: Deleted a bunch of unused structure sprites + - image: Fixed the lobby menu's collapse button being offset by a pixel + Ben10Omintrix: + - bugfix: basic bots no longer start with all access + Jacquerel: + - bugfix: Anomalous Research ruin Bioscrambler anomalies won't home in on targets + - bugfix: Bioscrambler won't randomly drop its target for no reason + - admin: Reactivating an anomaly core via the anomaly releaser is now logged. + - bugfix: Fixes various bugs related to dimensional/spectral anomalies moving when + they should not. + JohnFulpWillard: + - bugfix: Medipens can no longer be deepfried, closing an exploit that allowed people + to drain/inject chems into it with saltshakers and IV drips. + Melbert: + - refactor: Staff of Healing should perform slightly better. + - bugfix: Blobs may rejoice, welding torches now consume fuel when attacking objects + again after two years. + Rhials: + - sound: Nightmare has a new sound effect for entering/exiting shadow jaunt. It + also no longer can be heard through walls. + SyncIt21: + - bugfix: Ordinance lab igniter in Icebox works again + - bugfix: facescarf ui toggle button works again + - bugfix: closets & crates will dump all contents out first before deleting itself + regardless of `NO_DEBRIS_AFTER_DECONSTRUCTION` thus not for e.g. hard deleting + mobs inside it + Vect0r: + - bugfix: 'BIRDSHOT: the clown now has a megaphone. Go honk!' + Xackii: + - bugfix: Birdshot now have engi wardrope + Zytolg: + - bugfix: Cleans up some rocks on Birdshot + jlsnow301: + - rscadd: The lootpanel now works at range. + - rscadd: Screentips for reskinnable items. + - bugfix: Alt click interactions have been refactored, which may lead to unintentional + changes to gameplay. Report any issues, please. + - bugfix: CentCom dispatched a team of interns to fix the loot panel's loading message. + It should now load properly. It did before too, but now the message is fixed. + mc-oofert: + - bugfix: tramstation AI sat starts full +2024-04-18: + Ben10Omintrix: + - code_imp: The way mobs idle has been refactored, please report any issues with + non-reactive mobs + - rscadd: miners can now purchase grapple guns + Melbert: + - rscadd: Adds the Strong Stomach quirk, which allows you to eat grimy food without + worry about disease, and makes you a bit more resilient to the effects of vomiting. + - rscdel: Deviant Tastes no longer prevents you from getting a negative moodlet + from eating dirty food. Strong Stomach does that now. + - bugfix: Height now applies less weird to certain worn items, bare-handed bloody + hands, and damage overlays. + jlsnow301: + - bugfix: Bit avatars no longer have access to free binary comms with the AI outfit + - bugfix: Netpods have had their security against exploits increased. + mc-oofert: + - bugfix: you no longer need to put your sleeping carp gloves off and on in Deathmatch + to get the martial art + san7890: + - rscadd: Regal Rats are now able to tear down those colorful posters those weird + grey creatures keep spackling up on the walls of their rightful domain. +2024-04-19: + Iajret: + - bugfix: cooling and anti-disruption RCD upgrades can now be printed in ancient + protolathes + Jacquerel: + - balance: Gulag mining has been rebalanced so that every boulder is worth the same + amount of points to mine for a prisoner regardless of what it contains, and + should be more consistent. + - rscadd: A vent which boulders can be hauled out of by hand has been added to the + gulag which you can use if there's nothing left to mine. It is very slow, but + at least it gives you a workout... + Melbert: + - refactor: Atom-Item interactions have been refactored once more. Report any oddities. + - rscadd: Being deafnened from a loud sound (flashbang, explosions) will now force + people not naturally deaf to shout + - rscadd: Ear damage multiplier now only applies to taking damage, not healing damage, + meaning Felinids (who take 2x the ear damage) will no longer heal ear damage + 2x faster. + - refactor: Ears have been refactored slightly, ear deafness should now update more + snappily + Rhials: + - qol: Water tiles now extinguish fires on items and people. + SyncIt21: + - code_imp: most cell power usages are scaled with defined constants to help adapt + to future changes + - bugfix: smart pipes release their gases into the air when unwrenched + - bugfix: cryo pipe connector component has no side effects of gas reallocation + when deleted + TheRyeGuyWhoWillNowDie: + - bugfix: being revived with a cyber-heart now properly restarts the cyber heart + Watermelon914: + - bugfix: Fixed RnD consoles not being able to be opened. + jlsnow301: + - rscdel: Due to a need for company restructuring, virologists have been laid off + by CentCom and doctors can optionally take their place. + - bugfix: TGUI Alerts shouldn't have such wonky buttons any more + - bugfix: Fixed a bluescreen in cargo console + - bugfix: 'Lootpanel additions: Condensed item names for the quick of draw' + san7890: + - qol: There's a bit more user feedback when it comes to attempting to handcuff + someone. + starrm4nn: + - qol: Replaced the surgical tools in the Primary Surgery Theatre with 2 Surgery + Trays. +2024-04-20: + Ben10Omintrix: + - qol: slimes will stay active without needing any one to watch over + Bmon: + - bugfix: Fixed on-mob sprite alightment for the NT SWAT helmet. + Iamgoofball: + - bugfix: Carps migrating through the station no longer idle so they don't get stuck + after spawning until someone walks by. + Melbert: + - bugfix: Primal Instincts and Living Flesh should be a tad more reactive + - bugfix: You can handcuff people with 2 arms and you can no longer handcuff people + with 0 arms + Motho: + - rscadd: Added wizard-themed deathmatch map. + - rscadd: Added mystery wand box. + Sightld2: + - bugfix: Ants are no longer picky eaters. Low Purity sugar will no longer result + in less Ants than you started with. + SyncIt21: + - bugfix: plumbing machinery begins processing only when wrenched & ends when unwrenched + - bugfix: plumbing machinery uses energy only when wrenched & doing work, will stop/use + less energy when idle + - bugfix: plumbing grinder chemical will grinds & juice stuff correctly i.e. prefer + grinding over juicing for most stuff + Vishenka0704: + - qol: added mass craft for personal crafting + ZephyrTFA: + - admin: Controller Overview UI. Check the Server Tab. + grungussuss: + - sound: cyborgs now have sounds to indicate they are moving + iliyaxox: + - spellcheck: '''inisimin'' verb corrected to ''invisimin''' + jlsnow301: + - bugfix: Mecha pilots are no longer bothered by incessant loot panels while holding + ALT for strafe disable. + - bugfix: Dropdowns received some much-needed QoL, like having the scrollbar follow + your selection. + - bugfix: AI voice changer now shows its current voice selection. + - bugfix: Deathmatch screen has been touched up. + - bugfix: Prefs menu has their dropdowns simplified, hopefully fixing issues +2024-04-21: + ZephyrTFA: + - admin: New dropdown to force change a mob's name and the attached client's preferences. + - admin: Player Panel is back + jlsnow301: + - bugfix: Fixed the targeting capability of mobs with full auto + - bugfix: You can now fire the marksman revolver at things you can see +2024-04-22: + FlufflesTheDog: + - bugfix: loading oven trays from serving trays and other containers works again + Iajret: + - rscadd: added ventpointer that points toward nearby ore vents and can be bought + with mining points + - balance: scanned ore vents can now be found with GPS + - bugfix: fixed ore vents missing overlay icon for uranium + Melbert: + - bugfix: You can open bags with alt click while resting again + - qol: Many items which previously required you to stand to alt-click now don't, + such as bedsheets and spray cans + Rhials: + - qol: Lava and plasma rivers now immerse you in them. + Singul0: + - rscadd: Adds an omnitoolset for both engineering and medical cyborgs, containing + various basic tools + - qol: Engineer and Medical module inventory space is now significantly decluttered + SyncIt21: + - bugfix: HPLC can purify inverted chems and are now coloured green(clean) in the + UI + - bugfix: pseudo circuit adapter computes recharge delay durations correctly & won't + use power when on cooldown + - code_imp: uses standard cell defines for N-spect scanner + - bugfix: off station & round start lathes with local storage don't have infinite + storage size. + jlsnow301: + - bugfix: Fixes the sight range on lootpanel. + vinylspiders: + - bugfix: dropdowns that use display_names as an alias for numeric values will no + longer cause tgui bluescreens +2024-04-23: + EvilDragonfiend: + - code_imp: /appearance type references are now investigatable in vv editor. + - code_imp: '/image references display a summarised name with its dmi file name + and icon_state when it''s investigated from a datum where it uses. Format is: + "mob_hud_image = /image (hud.dmi:medical) [0x00000]"' + - code_imp: /image types no longer show first image incorrectly when its icon_state + is null + FlufflesTheDog: + - bugfix: Stone tiles (and things on them) no longer get immersed in lava + Melbert: + - qol: Getting up from prone, moving up or down a z-level (not via ladders, naturally. + Like flight), and de/activating your modsuit no longer shows cogwheel effect + Pickle-Coding: + - bugfix: Fixes mechanical sect gaining 1,000 times the favor from a cell sacrifice. + SyncIt21: + - bugfix: Fixes runtime in advanced camera console when power is turned off + jlsnow301: + - bugfix: Cargo's supply console has been upgraded visually. + necromanceranne: + - rscadd: Replaces Fitness with Athletics; same skill, but now more specifically + applicable to boxing. + - rscadd: Athletics does not increase sprite size. + - balance: Overhauls Boxing to add a lot more depth to the interactions. Only applicable + to other boxers, however. You can still punch the snot out of non-boxers though. + But only up to stamcrit or unconsciousness. No hitting someone who can't fight + back! + - balance: Adds Evil Boxing, which is the evil and fucked up version of boxing that + you kill people with and are allowed to flout the sacred rules of boxing as + you please. Everyone is a victim! + san7890: + - bugfix: Evolved aliens should no longer have two numbers in their name. +2024-04-24: + Ben10Omintrix: + - bugfix: brimdemons (and other mobs) will act normally + Jacquerel and Melbert: + - rscadd: A new achievement for moving a boulder from one place to another, at great + effort. + - balance: Hauling a boulder around makes you move slower, as it does when dragging + it. + Melbert: + - qol: Tuberculosis makes you cough more + - qol: Nicotine Addiciton makes you cough less + - qol: Medicine Addiction maybe makes you cough more, maybe makes you cough less + - bugfix: Only brute damage causes brain damage when applied to the forehead, rather + than all damage types + - bugfix: Playing Cards memory now reads better + - qol: Coughing will now no longer print to chat, IE, it is runechat only. If you + have runechat emotes disabled, however, it will still print to chat. + - qol: Snapping now has a visual component. + - bugfix: All emotes are no longer considered audible, meaning blind people go back + to not being able to see people do flips and jumps + - bugfix: However, blind people are now told when they do a visible emote like flipping + (because they can, obviously, feel themselves flipping). Likewise, deaf people + are told when they do some audible emotes, like coughing or screaming. + Rhials: + - bugfix: Fake handcuffs/Zipties no longer block clicks for a few seconds after + being resisted out of. + SyncIt21: + - bugfix: plumbing & chem reaction chamber heating effects accurately reflect the + beakers heat capacity & power usage + - bugfix: plumbing reaction will not use power when emptying or when there are no + reagents to heat + - bugfix: you can hit the chem reaction chamber with items like beakers, screwdrivers, + crowbars and what not + jlsnow301: + - rscadd: Admin tools buffed, check the Controller Overview + - rscadd: Controller Overview moved to debug tab + - bugfix: 'Cargo express console fixed: No more bluescreen' + necromanceranne: + - rscadd: Adds a higher capacity SMES unit to lower maintenance areas and maps. + - bugfix: Miners can actually access and fix their engineering issues on the lavaland + base via the engineering section of the base. + - bugfix: The gulag SMES unit is no longer needlessly draining the entire power + grid of the main mining base. + uaioy: + - rscadd: New heavy weight pirates, medieval warmongers + - rscadd: Adds military spear, shortsword, boarding axe, kite shields + - rscadd: Adds warlord and crude armor + - rscadd: Adds medieval shuttle (made by striders18) +2024-04-25: + Fikou: + - bugfix: brimbeams no longer make a cog appear above the mob + - bugfix: you can no longer take off someones glasses or mask through atmos hardhat + - bugfix: once you adjust a welding helmet or something it no longer makes your + cigarette or sunglasses invisible + - bugfix: welding gas mask works once again + - bugfix: quick equips dont drop the item if you cant equip it + Momo8289: + - rscadd: The crew monitor now has sorting options and a search bar. + grungussuss: + - rscadd: whistle emote + - refactor: Refactored how laugh, sneeze, cough and cry sound is called in the code, + report strange behavior with these emotes. + - sound: added sounds for whistle, cry, cough, sneeze, laugh for moths and lizards + emotes + necromanceranne: + - balance: Longfall modules no logner stun you when they activate. + - balance: Falling from a height greater than one z-level while using the longfall + module will still stagger you. +2024-04-26: + Ben10Omintrix: + - bugfix: all bots have their normal accesses restored + Bisar: + - bugfix: AI controlled monkeys are no longer catatonic, and they have primal eyes + again when turned into humans. + - spellcheck: Noticable organs now have more modular grammar, and their current + grammar is fixed. + - refactor: Refactored the code for displaying the messages for noticable organs. + - config: Added a documented define of all our pronouns + KingkumaArt: + - bugfix: The rebar crossbows now properly loosen their bowstring upon firing. + LT3: + - balance: ChemMaster can again print a maximum of 50 pills/patches per run + - balance: Higher tier servos increase ChemMaster printing speed + Singul0: + - bugfix: fixed cyborg bonesetter not working for compound fractures + - bugfix: butchering not disabling in cyborg omnitool + - bugfix: fixes a bug where if you select the omnitool it would be stuck in surgery + initiator mode + - bugfix: cautery in off hand for cyborg omnitools not working + jlsnow301: + - bugfix: Restored silicon alt-clicking capability + necromanceranne: + - bugfix: The plasma flower modsuit core now actually contains a reasonable quantity + of power. +2024-04-27: + Maurukas: + - bugfix: Removed a power loop on icebox + - bugfix: Disconnected aux power smes from icebox grid at roundstart + - bugfix: Removed some power cables connecting Deltastation's aux power + - bugfix: Fixed tramstation's gravity generator SMES, now functions and charged + at roundstart. + - bugfix: NorthStar's gravity generator SMES is now properly charged at roundstart + ZephyrTFA: + - admin: The return of IPIntel + grungussuss: + - bugfix: fixed being able to install multiple of the same upgrade to medical cyborgs +2024-04-28: + Ben10Omintrix: + - bugfix: fixes mobs getting stuck trying to reach something unreachable + EnterTheJake: + - bugfix: Spraycan no longer spams your chat when you mouse over it. + Melbert: + - bugfix: Midround malf can roll again + Rhials: + - bugfix: Overwatch Intelligence Agents no longer get their own uplinks, leading + to a self-replicating grey goo scenario. + jlsnow301: + - bugfix: Fixes clipping in the ESC menu between buttons and long station names. +2024-04-29: + 13spacemen: + - bugfix: All alert polls ignore option works + - code_imp: Unarmed attacks (punches, etc.) now support multiple attack verbs instead + of only one + EnterTheJake: + - image: The Infiltrator Suit has received a new model, sleeker than ever! + FlufflesTheDog: + - bugfix: minebot shields are now actually orderable + - bugfix: vinegar may once again be crafted with wine, water, and sugar + JohnFulpWillard: + - bugfix: Examining someone with Med/Sec HUDs will no longer filter the message + under Radio. + - bugfix: pAI requests should no longer randomly permanently break in a round. + Melbert: + - bugfix: Plasma cutters work again + Metekillot: + - bugfix: Mech domination now properly integrates with shunting. + - bugfix: Combat upgraded AIs no longer get two buggy malf ability pickers if they + also become malfunctioning + - refactor: Refactored most of the functionality around malf AI shunting, mech control + Rhials: + - admin: Lazy loading map templates now gives you the option to not ghost/teleport + to the loaded area upon completion. + Sadboysuss: + - admin: spy can now be rolebanned + VexingRaven: + - bugfix: The debug box no longer spills its contents everywhere + improvedname: + - qol: Arrivals shuttle is now more player friendly + san7890: + - admin: Possess Object is now back in the right-click context menu. +2024-04-30: + Jacquerel: + - balance: Netguardian Prime can see in the dark. + - image: You can see Netguardian Prime in the dark. + SyncIt21: + - bugfix: Eigenstasium exposed & Anomaly station trait affected closets work again. + Eigenstasium closets are tainted blue + YesterdaysPromise: + - bugfix: The start-of-the-round tips will no longer feature virologists, but will, + however, start featuring heretics and coroners. + intercepti0n: + - rscadd: Added a short scene when getting an Ordeal of Sisyphus achievement. diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml new file mode 100644 index 0000000000000..388a7eef52835 --- /dev/null +++ b/html/changelogs/archive/2024-05.yml @@ -0,0 +1,471 @@ +2024-05-01: + 13spacemen: + - bugfix: Ethereal unarmed attacks "sear" instead of "singe", which was buggy + Constellado: + - qol: Made birdshot atmos easier to use. + - bugfix: The Birdshot engineering department is no longer using a second hand broken + microwave. + Fikou: + - rscadd: you can use a photo with blueprints on it to read wires + Flleeppyy, Absolucy: + - sound: Added unique announcement jingles to each heretic path's ascension, replacing + the old "space-time anomalies detected" announcement. + JohnFulpWillard: + - bugfix: Genetic sequence scanners now show the sequence to mutated genes from + scanned individuals. + - bugfix: QM is now excluded from getting tasked with stealing telescopic batons + and the captain's spare ID, like all other command personnel are. + - qol: The Human AI's advanced security console can be repackaged with a screwdriver + if you wish to move it. + LT3: + - qol: The various RCD upgrade disks no longer look identical + Maurukas: + - bugfix: On examine PDAs will now inform players that the power cell can be removed + for recharging or replacement, and how to do so. + SyncIt21: + - bugfix: computers don't deconstruct themselves twice so machines like slotmachine + don't spawn excess chips upon deconstruction + improvedname: + - bugfix: Fixes tramstation gravgen wiring + - bugfix: Fixes tramstation turbine wiring + - bugfix: Fixes northstar cmo button name + jlsnow301: + - bugfix: Fixes a bluescreen in the deathmatch lobby UI. + larentoun: + - bugfix: Infinite-range laser pointer (for "AI" Big Brother) now has a correct + diode. If you accidentaly remove it then you can put it back! + mc-oofert: + - rscadd: trainship hijack deathmatch map + necromanceranne: + - bugfix: If you are a freerunner, you don't end up faceplanting despite having + catlike grace. +2024-05-02: + Echriser: + - qol: conveyor switches now have direction-specific input signals + Fluffles: + - qol: you can pick up wheelchairs while on the ground + - qol: you can place wheelchairs a tile away from you, like roller beds + JohnFulpWillard: + - bugfix: Monkey changelings that are disguised as someone can now take off their + flesh clothes. + - bugfix: You can now re-construct pod doors that had deconstruction started. + - qol: You can now make pod door assemblies using plasteel in-hand. + - bugfix: Monkeys can no longer be knocked over by walking into a windoor on combat + mode while they're behind it. + - admin: Debug uplinks now shows all categories and won't lock upon buying items + like his grace and the syndicate balloon. + - bugfix: Constantly fleeing in Battle Arcade will no longer give you a very large + amount of decimals due to halving your gold every time. + - bugfix: AIs can now track Silicon as long as their built-in camera is online. + Melbert: + - admin: Custom Single and Custom Multi votes are now combined into one vote + - admin: Admins can now end votes instantly, rather than cancelling them + - admin: Admins can now reset the vote cooldown + - bugfix: Vote cooldown actually applies now + Pickle-Coding: + - bugfix: Fixes hypercharged slime core cells and circuit guns having 1,000 times + less energy than intended. + Watermelon914: + - bugfix: Fixed the ipintel subsystem not working. + kawoppi: + - bugfix: the civilian bounty control terminal displays the payout of new bounty + options again + - qol: the civilian bounty control terminal displays the description of new bounty + options + nikothedude: + - bugfix: Jousting no longer bypasses pacifism +2024-05-03: + Echriser: + - qol: conveyors now use left and right click controls + - qol: add screentips for conveyor switches + - rscdel: removes circuit conveyor circuit default trigger behavior in favor in + favor of the three state triggers + Gaxeer: + - bugfix: fix runtime when no events were drafted to be picked from + - config: make events frequency configurable + StrangeWeirdKitten: + - qol: You can now quickly stamp papers with a right click + Zenog400: + - rscadd: increased the size of the pool that Machine Blessing draws from + - balance: weighted some of the implants that Machine Blessing can give + mc-oofert: + - image: added directional sprites for radiation shutters +2024-05-04: + Ben10Omintrix: + - bugfix: mobs in the same faction will no longer be at odds against one another + - bugfix: mobs can now perform behaviors alongside searching for targets + - bugfix: mobs will no longer be starting and stopping when chasing targets + Ghommie: + - rscadd: Adds an Icebox-specific station trait that brightens outdoors areas on + the surface level. + Ikalpo: + - bugfix: Stage 2 singularities should no longer escape containment + Melbert: + - bugfix: New machine god blessings now actually works probably + Profakos: + - balance: Bitrunners can now earn Bepis disks, once per medium domain or above, + if they scored at least an A. + - rscdel: Bitrunners can not buy Bepis disks from their vendors. + Ryll/Shaps: + - bugfix: Pacifists can no longer endlessly spam the backblast functionality of + loaded rocket launchers that they cannot actually fire + Watermelon914: + - bugfix: Fixed lua scripts breaking when turfs with registered signals get deleted. + Xander3359: + - bugfix: You can no longer bypass construction restrictions via the crafting menu + cnleth: + - bugfix: Fire ant colonies created by burning regular ants will now contain fire + ants as their reagent + jlsnow301: + - bugfix: Candy corn is once again available to detective fedoras + mogeoko: + - bugfix: Ventcrawling mobs can change Z-level using multiz-decks again. +2024-05-05: + Isratosh: + - bugfix: If kidnapped and ransomed by pirates, you will now properly return to + the station automatically after 6 minutes. + - bugfix: You can no longer be kidnapped and held for ransom by cargo technicians + posing as pirates. + Jacquerel: + - bugfix: Blood Brothers should spawn knowing what their objectives are. + - bugfix: Teams of 3 Blood Brothers will once more have an additional objective. + Melbert: + - refactor: Random Name Generation has been refactored. Report any instances of + people having weird (or "Unknown") names. + - qol: Felinids, Slimepeople, Podpeople, and some other species without defined + namelists now automatically generate names based on their primary language(s). + - qol: More non-human names can be generated in codewords (and other misc. areas) + than just lizard names. + larentoun: + - bugfix: Materials are now correctly applied to crafted items (chairs, toilets, + etc) +2024-05-06: + improvedname: + - bugfix: fixes traditional equipment crate name + paganiy: + - qol: Admin modsuit now has a radiation protect module +2024-05-07: + CandleJaxx: + - rscadd: '''puppy'' ''kitten'' and ''spider'' pai skins' +2024-05-08: + '@MrEmre12, @Majkl-J': + - rscadd: Fishing pool introduced to metastation garden + - refactor: All water tiles now handle fishing through a unified fishing_datum variable + BurgerBB: + - qol: The inspector's Fedora now uses regex. When saying commands, it is much more + generous on picking up trigger word. + Derpguy3: + - bugfix: A meter attached to distribution pipes in Birdshot's atmospherics has + been moved to the matching pipe layer. + Fikou: + - rscdel: You can no longer use another station's blueprint photo to look at wires + or do the traitor objective with. + Iamgoofball: + - balance: Spies can now use other spies' uplinks. + Melbert: + - balance: To see wires in photos of blueprints, you first must squint at the photo. + ReturnToZender (hitting delete on a power cable): + - rscdel: Single loose power cable in icebox maintenance + Rhials: + - balance: Virtual domain ghost roles can no longer enter the safehouse/"equipment" + areas of a domain. + - bugfix: Pirate virtual domain ghost roles will no longer make a pirate team antag + datum. + ShizCalev: + - bugfix: Inducers no longer break completely after trying to charge a PDA with + them. + delingar: + - rscadd: RD's skillchip adds cyborg wires knowledge + jlsnow301: + - bugfix: Lootpanel now requires 515.1635 to generate most icons. TG support for + 514 ended May 1. Update your client to fix the icons. + mc-oofert: + - qol: temporarily soulless (deathmatch, etc) bodies dont appear as soulless on + medhud +2024-05-09: + 00-Steven: + - bugfix: Pride pins can be reskinned again with alt-click. + AMyriad: + - bugfix: Removed stray pixels appearing on certain parts of railing + Bisar: + - balance: Knockdown effects will know consistently disarm, instead of failing to + disarm if you're already lying down. + Ghommie: + - bugfix: Added the missing bulwark MOD module and the jawed fishing hook to the + black market. + GoldenAlpharex: + - bugfix: Removed another rogue cable from underneath a disconnected SMES. + Jane: + - qol: The Coroner's Ritual Knife can now sit upon Med Belts! + Melbert: + - bugfix: DNA infusing tiers works again + - bugfix: Cult can build again + - qol: There is now a slight animation to entering a portal or teleporter. + - qol: Spies may spawn in less numbers, but rarely may also spawn in more numbers. + XElectricX: + - qol: Mech drills can auto-mine by walking into rock. + jlsnow301: + - bugfix: Silicons can set the teleporter destinations again. + - bugfix: The quick equip 'E' hotkey shouldn't warn if one of your bags is full + anymore +2024-05-10: + 00-Steven: + - qol: Added alt-click usage context to toggle_icon component + - bugfix: The stomach pump surgery actually works again. + - spellcheck: '"brusing" to "bruising" in the message you get when failing the stomach + pump surgery.' + Echriser: + - bugfix: conveyor switches work for cyborgs again + GoldenAlpharex for the code, Thlumyn for the sprites: + - bugfix: Fixed smoothing turfs displaying some incorrect damaged overlays because + of a non-smoothing damage overlay of different dimensions than the smoothing + sprite used as the base. Less black void, let's go! + - image: Added smooth broken/burnt overlays for grass, meaning that it's going to + look a lot less broken when the grass tile is at the edge of a smoothing group. + Jacquerel: + - rscdel: Being sacrified by a Heretic no longer gives you an incurable phobia. + - rscadd: Being sacrificed by a Heretic will drop 2-4 of your organs on the ground + and replace them with "corrupt organs" with negative effects which can be suppressed + with Holy Water. + - rscadd: Players who have been sacrificed by Heretics will experience additional + and rapidly lethal consequences for attempting to fight someone who previously + sacrificed them, as long as that person is wearing a focus. + - sound: Lasers adjust their pitch as they run out of charge, rather than frequency + Melbert: + - qol: Morgue trays (and the contents inside) are now animated on open and close + MrStonedOne & Lilah Novi: + - rscadd: Say commands typed in the command bar now trigger typing indicators + Pickle-Coding: + - qol: The labor camp shuttle properly sets people to parole after they complete + their work. + - qol: The labor camp shuttle specifies which person returned to the station. + ShizCalev: + - bugfix: Cursed Items wizard event actually works again. + TiviPlus: + - bugfix: fixed clients being seen as stuck doing tutorials in some cases when changing + mobs + jlsnow301: + - bugfix: Supermatter shards now have screentips with a wrench in hand + malton33: + - bugfix: space heaters now display the correct mode when the maintenance panel + is closed + paganiy: + - bugfix: The shuttle will no longer delete you while you are in jaunt + vinylspiders: + - bugfix: moths with functional/flight potion wings get an animation when they *flap + once again, and it makes a sound +2024-05-11: + carlarctg: + - rscadd: Chance to become crab on nonlethal DNA meltdown + norsvenska: + - bugfix: The Coroner and Bitrunner can now be selected as a target for kidnapping + and heirloom destruction objectives. + - bugfix: The Chief Engineer is now a valid target for heirloom destruction objectives. +2024-05-12: + Higgin: + - bugfix: Spies no longer get the 'nothing' / 'free objective' due to trying to + make Protect objectives without targets. + Xander3359: + - bugfix: Ale now has a drinking_glass style +2024-05-13: + Bisar: + - qol: Most of the alternate click modes (right click, control clicking, shift clicking, + etc) have been enabled in the alt-click item menu. + - bugfix: You will no longer point at things you right-click in the alt-click item + menu. + Melbert: + - rscadd: Cigarette smoke is now more smokey. + - rscadd: Taking a cigarette out of your mouth will let out a big puff of smoke. + PapaMichael: + - bugfix: Rat Kings can no longer trap mice inside of pipes by creating them while + ventcrawling. + - balance: Rat Kings can no longer create grime and miasma while ventcrawling. + Rhials: + - rscadd: Bitrunners now have their own job figurine. Cool! + nikothedude: + - spellcheck: Added a period to the end of the wendigo deathrattle + paganiy: + - qol: Now you can put a cigarette in your mouth just by hitting the pack of cigarettes + on yourself. + - bugfix: The cigarette pack no longer moves under the spaceman when they interacts + with it with the RMB +2024-05-14: + Jacquerel: + - rscadd: People who spend time improving their bodies are able to evaluate the + relative physical strength of those they examine as a kind of "power level". + - rscadd: Changeling transformation copies the target's athletics skill level. + Time-Green: + - bugfix: Deleting someones brain kills them again + jlsnow301: + - bugfix: Alt click will draw the captain's sabre again + paganiy: + - bugfix: Accelerator laser gun no longer shoots sun size projectiles. + starrm4nn: + - qol: Gives Health sensor assemblies a UI so its easier to use. +2024-05-15: + DaCoolBoss: + - bugfix: The random arcade machines in the 'Interdyne Spinward Research Base's + now function. + Melbert: + - qol: Some alerts, such as Fleshmend's, show their remaining duration on their + icon. + Seven: + - bugfix: Fixed a runtime when using the cultist blood rites on yourself. + Webcomicartist: + - bugfix: The lavaland mining shuttle doors no longer trap cargo security on lavaland + due to access weirdness. + iwishforducks: + - bugfix: Fixes random decal in space on Tramstation + necromanceranne: + - bugfix: Fixes an accidental reversion to greyscale plate armor. +2024-05-16: + Ben10Omintrix: + - rscadd: parrots will now try to immitate the speaker's voice + DaxDupont: + - bugfix: Fixes error when running docker compose on apt upgrade + Derpguy3: + - qol: Additional box types can be crafted from cardboard. Happy organizing. + - spellcheck: A typo in box crafting for prescription glasses has been fixed. + Hatterhat: + - bugfix: The SC/FISHER can now shoot floor lights. + Jacquerel: + - admin: Admins can now more easily modify whether a Blood Brother can convert someone + Jane: + - qol: Shovels, Serrated Bone Shovels, and Entrenching Tools can now be hung upon + Miner and Coroner Winter Coats, as well as the Coroner's Labcoat! + - image: Mirrored the mirrored sprites to display Shovels in the suit slot properly. + Melbert: + - qol: When you are offered something, you can shift-click the alert to examine + the item rather than take it. + - qol: Examine blocks for screen alert examining. + - qol: Screentips for offer alerts. + PKPenguin321: + - rscadd: New funny wizard staff/wand that shrinks stuff. + - rscadd: Being shrunken now leaves you vulnerable to being crushed to death. + Pickle-Coding: + - balance: There are reports of malfunctioning guns being confiscated. + Seven: + - bugfix: Destroyed solar panels no longer drop their overlays + Shadow-Quill: + - qol: The "Confirm Order" button on Cargo consoles is now active when the cargo + shuttle is at Central Command instead of at the station. + ShizCalev: + - bugfix: Spam clicking a modkit with a kinetic accelerator can no longer lead to + ghosted versions of the modkits appearing in the modkit list, breaking the gun. + SyncIt21: + - bugfix: cell chargers, mechbay port chargers & recharge stations heat lost is + directly proportional to energy drawn from the grid to charge their respective + cells + - bugfix: cyborgs should charge more frequently & to their max capacity at recharge + stations + - qol: adds examines & screentips for tool & container actions on the smoke machine + - qol: smoke machine no longer requires a power cell for construction + - code_imp: autodocs & removes vars for some machine, Updated attack chain to latest + standards for smoke machine + - bugfix: You no longer hit the smoke machine with the beaker + - bugfix: You can hit the smoke machine with tools & beakers when in combat mode + - bugfix: no abstract & hologram item interactions allowed with smoke machine + Time-Green: + - bugfix: Space Ninja and other space spawned antags get a 1 minute radiation shield + in the radioactive nebula + grungussuss and Virgilcore: + - sound: portals now have a unique sound to them + jlsnow301: + - bugfix: Bitrunning antagonists no longer gib on teleport + - bugfix: Cyber tac now have a visible name / ID + - bugfix: 'Renamed the bitrunning malfunction event to just "Malfunction: x"' + - bugfix: You can adjust your uniform while lying down again + necromanceranne: + - bugfix: Fixes the knife offset for pipeguns + tmyqlfpir: + - qol: Add tooltips to circuit editor buttons + - qol: Add grid alignment mode to circuit editor + - rscadd: Added new compare health state component + - rscadd: Added new NTNet send list literal component + - rscadd: Added new toggle component + - qol: Added activity toggle to voice activator component + - qol: Added quiet mode to speech component + - qol: NTNet send component will not use power/trigger if NTNet is offline +2024-05-17: + 00-Steven: + - bugfix: Emotion masks no longer use a janky workaround for infinite reskinning. + - bugfix: Mech pilot suit shows reskinning usage context correctly. + - bugfix: Accessories show "wear above/below suit" usage context appropriately. + - bugfix: Accessories don't block reskinning usage context when they shouldn't. + - bugfix: Showing reskinning usage context cares about the infinite reskinning flag, + rather than whether it's in storage or not. + - rscdel: Removed redundant reskinning usage context code from medical sprays, now + shows reskinning usage context like other reskinnables. + EnterTheJake: + - balance: Rust Heretics rusting is now consistent and tied to knowledge progression. + - balance: Walking on rust applies disgust and chem purge to non-heretics and brute + damage to silicons. + - balance: Toxic damage on heretic skills is replaced with disgust. + - balance: Aggressive Spread radius is now a bit shorter in exchange for losing + its RNG elements, cooldown is halved on ascension. + - balance: Pulse of Entropy had its radius doubled and the recipe simplified. + - balance: Leeching walk has had its healing increased and a minor temp regulation + effect added. + - balance: Rust Walker's knowledge has been moved up in tree(close to aggressive + spread) they are now easier to summon and have more health. + - balance: You cannot place floor tiles on rusted turfs anymore, (use a welder to + scrape off the rust first). + - balance: Rustbringer's oath has been reworked to propagate around in a circular + fashion and not just on the bridge z level. + - balance: Resist cold trait now gives immunity to freeze effects, and has now been + added to Rustbringer's oath along with slowdown immunity. + - bugfix: Fixed glowing runes being invisible. + JohnFulpWillard: + - bugfix: Snails no longer move at normal speed while resting. + - bugfix: Snails can no longer get insane speed from getting their legs replaced. + - bugfix: Humans don't become immensely slow when getting a Snail leg. + - admin: lube walking element is now much easier to mess with to fit however you + want to use it for. + Melbert: + - bugfix: After 3 years, radiation now causes you to go bald and mutate again + Pickle-Coding: + - bugfix: Fixes engineering cyborg screwdriver not being pointy. Fixes engineering + cyborg crowbar from being pointy. + - bugfix: Fixes cyborg omnitools not using the correct wound bonus and armour penetration + values. + Rengan: + - bugfix: Officers sabre and grilles now conducts electricity as it should. + Seven: + - bugfix: Wings no longer work in space if you activated them beforehand. + ShizCalev: + - bugfix: Atoms on the border of a tile will now only trigger landmines if they + ACTUALLY pass over said mine. + Thunder12345: + - bugfix: Pyre chaplains can no longer generate infinite favour for free by buying + and selling candles. Candles now offer for 40 favour, down from 50. + Xander3359: + - rscdel: Removes the sleeper protocol traitor objective + - balance: RND server/Telecomms sabotage can now show up even later in the round + improvedname: + - bugfix: fixes metastation science scrubber pipeline + jlsnow301: + - bugfix: Fixed an issue preventing space ninjas from having a hud icon + - rscadd: 'ORBIT UI CHANGES:' + - rscadd: AFK players are greyed out. + - rscadd: Living NPCs now display health. + - rscadd: Icons displayed are now based on hud icons, which includes icons for player-visible + antagonists + - rscadd: You can now sort by job department (click health icon) + - rscadd: Round ending "critical" items will be listed at the top. + - rscadd: Click the settings button to expand for more info + - rscadd: Your current orbit target is highlighted. + - bugfix: Simplebot UI won't display '0' anymore when locked + mc-oofert: + - rscadd: mobile defibrillator mount + nikothedude: + - code_imp: Most instances of parse_zone now refer to the limb's plaintext_zone + var + siliconOpossum: + - qol: Neckties are now worn underneath suit items and accessories, they can still + be optionally worn over them in case you want the "business space suit" look + - bugfix: Fixed a bug where accessories wouldn't correctly apply over suits if you + equipped the jumpsuit they're attached to after the suit + starrm4nn: + - spellcheck: Fixes some typos in the goodies section and makes it look a bit more + consistent. + - bugfix: Fixed the spess knife's cutter tool icon being invisible. diff --git a/html/typing_indicator.html b/html/typing_indicator.html new file mode 100644 index 0000000000000..2988edff55fa0 --- /dev/null +++ b/html/typing_indicator.html @@ -0,0 +1,46 @@ + + + + + + + + + diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index 12e3ce9f7d594..fd7bee8ed6075 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/effects/docking_ports.dmi b/icons/effects/docking_ports.dmi new file mode 100644 index 0000000000000..96909d7bd0f35 Binary files /dev/null and b/icons/effects/docking_ports.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index dab4f272d96ba..5c64474dc0aab 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/effects/eldritch.dmi b/icons/effects/eldritch.dmi index 91fa9ff4f538b..51d7854e9502b 100644 Binary files a/icons/effects/eldritch.dmi and b/icons/effects/eldritch.dmi differ diff --git a/icons/effects/particles/smoke.dmi b/icons/effects/particles/smoke.dmi index 4a3239499b965..99123beeb59a9 100644 Binary files a/icons/effects/particles/smoke.dmi and b/icons/effects/particles/smoke.dmi differ diff --git a/icons/effects/progressbar.dmi b/icons/effects/progressbar.dmi index f055a07ba1492..3eed14db704a7 100644 Binary files a/icons/effects/progressbar.dmi and b/icons/effects/progressbar.dmi differ diff --git a/icons/effects/random_spawners.dmi b/icons/effects/random_spawners.dmi index 08df14c0ffc99..ddd6fd6f608bd 100644 Binary files a/icons/effects/random_spawners.dmi and b/icons/effects/random_spawners.dmi differ diff --git a/icons/effects/vent_overlays.dmi b/icons/effects/vent_overlays.dmi index 54ac3d7a819bb..375117f4c79f7 100644 Binary files a/icons/effects/vent_overlays.dmi and b/icons/effects/vent_overlays.dmi differ diff --git a/icons/hud/lobby/background.dmi b/icons/hud/lobby/background.dmi index 554543ecf3f72..5fb9085da0943 100644 Binary files a/icons/hud/lobby/background.dmi and b/icons/hud/lobby/background.dmi differ diff --git a/icons/hud/radial.dmi b/icons/hud/radial.dmi index 90813b4d7d210..e4a1693fb573e 100644 Binary files a/icons/hud/radial.dmi and b/icons/hud/radial.dmi differ diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi index d66bd0b995dee..e56df0560531a 100644 Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ diff --git a/icons/mob/actions/actions_AI.dmi b/icons/mob/actions/actions_AI.dmi index 048793c607838..429a766585dd2 100644 Binary files a/icons/mob/actions/actions_AI.dmi and b/icons/mob/actions/actions_AI.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 1b597f0d33db8..4fc02eaa2c0fc 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index fbe6871c92e2d..f8673eedd9518 100644 Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ diff --git a/icons/mob/clothing/belt_mirror.dmi b/icons/mob/clothing/belt_mirror.dmi index 4f7f64db8c67b..69fd53612f01d 100644 Binary files a/icons/mob/clothing/belt_mirror.dmi and b/icons/mob/clothing/belt_mirror.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index d0e5093d459c5..a670c33b7dcf6 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/mob/clothing/head/hats.dmi b/icons/mob/clothing/head/hats.dmi index 4183d5fa6cb4c..5e76ab78608f2 100644 Binary files a/icons/mob/clothing/head/hats.dmi and b/icons/mob/clothing/head/hats.dmi differ diff --git a/icons/mob/clothing/head/helmet.dmi b/icons/mob/clothing/head/helmet.dmi index 49edcf8422f26..523a306749d3d 100644 Binary files a/icons/mob/clothing/head/helmet.dmi and b/icons/mob/clothing/head/helmet.dmi differ diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index 3a213d5275ccd..c877c2fcb8826 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/clothing/modsuit/mod_clothing.dmi b/icons/mob/clothing/modsuit/mod_clothing.dmi index 793c14ce115ff..613559b726a7d 100644 Binary files a/icons/mob/clothing/modsuit/mod_clothing.dmi and b/icons/mob/clothing/modsuit/mod_clothing.dmi differ diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index 7895a3ac7facf..a193fbd74a8e3 100644 Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ diff --git a/icons/mob/clothing/suits/armor.dmi b/icons/mob/clothing/suits/armor.dmi index be2ba8f3730c1..c96fb14268367 100644 Binary files a/icons/mob/clothing/suits/armor.dmi and b/icons/mob/clothing/suits/armor.dmi differ diff --git a/icons/mob/clothing/under/costume.dmi b/icons/mob/clothing/under/costume.dmi index a3b6c7e50507d..34703c070589d 100644 Binary files a/icons/mob/clothing/under/costume.dmi and b/icons/mob/clothing/under/costume.dmi differ diff --git a/icons/mob/human/species/monkey/bodyparts.dmi b/icons/mob/human/species/monkey/bodyparts.dmi index 59a3a10c26cf2..9e95cbd0c72fc 100644 Binary files a/icons/mob/human/species/monkey/bodyparts.dmi and b/icons/mob/human/species/monkey/bodyparts.dmi differ diff --git a/icons/mob/human/species/monkey/monkey_tail.dmi b/icons/mob/human/species/monkey/monkey_tail.dmi index 2a06af25b797d..ffebf714f9aa9 100644 Binary files a/icons/mob/human/species/monkey/monkey_tail.dmi and b/icons/mob/human/species/monkey/monkey_tail.dmi differ diff --git a/icons/mob/human/species/monkey/uniform.dmi b/icons/mob/human/species/monkey/uniform.dmi deleted file mode 100644 index a835629528ae5..0000000000000 Binary files a/icons/mob/human/species/monkey/uniform.dmi and /dev/null differ diff --git a/icons/mob/inhands/clothing/hats_lefthand.dmi b/icons/mob/inhands/clothing/hats_lefthand.dmi index 191c85cf4825c..1d6461fb39dc9 100644 Binary files a/icons/mob/inhands/clothing/hats_lefthand.dmi and b/icons/mob/inhands/clothing/hats_lefthand.dmi differ diff --git a/icons/mob/inhands/clothing/hats_righthand.dmi b/icons/mob/inhands/clothing/hats_righthand.dmi index 8038e7474ee87..4d9710bf90159 100644 Binary files a/icons/mob/inhands/clothing/hats_righthand.dmi and b/icons/mob/inhands/clothing/hats_righthand.dmi differ diff --git a/icons/mob/inhands/clothing/suits_lefthand.dmi b/icons/mob/inhands/clothing/suits_lefthand.dmi index a43756d743a9b..02b1e2cbff266 100644 Binary files a/icons/mob/inhands/clothing/suits_lefthand.dmi and b/icons/mob/inhands/clothing/suits_lefthand.dmi differ diff --git a/icons/mob/inhands/clothing/suits_righthand.dmi b/icons/mob/inhands/clothing/suits_righthand.dmi index da837fdd8570e..7dd047b7345d7 100644 Binary files a/icons/mob/inhands/clothing/suits_righthand.dmi and b/icons/mob/inhands/clothing/suits_righthand.dmi differ diff --git a/icons/mob/inhands/equipment/shields_lefthand.dmi b/icons/mob/inhands/equipment/shields_lefthand.dmi index ce99a16d476c0..1aa27021b9ede 100644 Binary files a/icons/mob/inhands/equipment/shields_lefthand.dmi and b/icons/mob/inhands/equipment/shields_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/shields_righthand.dmi b/icons/mob/inhands/equipment/shields_righthand.dmi index 1c9c990b43dc9..4227ba00792b4 100644 Binary files a/icons/mob/inhands/equipment/shields_righthand.dmi and b/icons/mob/inhands/equipment/shields_righthand.dmi differ diff --git a/icons/mob/inhands/items/balloons_lefthand.dmi b/icons/mob/inhands/items/balloons_lefthand.dmi index cf51ac313e282..7fed45fc5909c 100644 Binary files a/icons/mob/inhands/items/balloons_lefthand.dmi and b/icons/mob/inhands/items/balloons_lefthand.dmi differ diff --git a/icons/mob/inhands/items/balloons_righthand.dmi b/icons/mob/inhands/items/balloons_righthand.dmi index 606f2007fd70d..c1856b2260b2a 100644 Binary files a/icons/mob/inhands/items/balloons_righthand.dmi and b/icons/mob/inhands/items/balloons_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/axes_lefthand.dmi b/icons/mob/inhands/weapons/axes_lefthand.dmi index 7a0f4fdd59218..8352626ce2755 100644 Binary files a/icons/mob/inhands/weapons/axes_lefthand.dmi and b/icons/mob/inhands/weapons/axes_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/axes_righthand.dmi b/icons/mob/inhands/weapons/axes_righthand.dmi index 42cb63507466a..7c026e12b66a5 100644 Binary files a/icons/mob/inhands/weapons/axes_righthand.dmi and b/icons/mob/inhands/weapons/axes_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi index 4c1acc9fa46f0..c1bcd197278b5 100644 Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi index f3a5f34e24723..98788d7371135 100644 Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/hammers_lefthand.dmi b/icons/mob/inhands/weapons/hammers_lefthand.dmi index 7f6985e1de5ec..5856bd8b0f834 100644 Binary files a/icons/mob/inhands/weapons/hammers_lefthand.dmi and b/icons/mob/inhands/weapons/hammers_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/hammers_righthand.dmi b/icons/mob/inhands/weapons/hammers_righthand.dmi index 2dd4f4b64c5cf..c6e8a0215ea3b 100644 Binary files a/icons/mob/inhands/weapons/hammers_righthand.dmi and b/icons/mob/inhands/weapons/hammers_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/polearms_lefthand.dmi b/icons/mob/inhands/weapons/polearms_lefthand.dmi index f9b43790df73f..a1355ed9c40a2 100644 Binary files a/icons/mob/inhands/weapons/polearms_lefthand.dmi and b/icons/mob/inhands/weapons/polearms_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/polearms_righthand.dmi b/icons/mob/inhands/weapons/polearms_righthand.dmi index 9f7e623989588..05665fbaf959d 100644 Binary files a/icons/mob/inhands/weapons/polearms_righthand.dmi and b/icons/mob/inhands/weapons/polearms_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi index e0a33fbcee351..6a0520ac9da69 100644 Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi index fcdac64bdca49..29db3057a2ab9 100644 Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ diff --git a/icons/mob/nonhuman-player/netguardian.dmi b/icons/mob/nonhuman-player/netguardian.dmi index 057e7a066c2be..c788c76772b81 100644 Binary files a/icons/mob/nonhuman-player/netguardian.dmi and b/icons/mob/nonhuman-player/netguardian.dmi differ diff --git a/icons/mob/silicon/pai.dmi b/icons/mob/silicon/pai.dmi index 2be986d411dbe..260b175f3ae3f 100644 Binary files a/icons/mob/silicon/pai.dmi and b/icons/mob/silicon/pai.dmi differ diff --git a/icons/mob/silicon/robot_items.dmi b/icons/mob/silicon/robot_items.dmi index e18a9d08f8691..5ad091d6c9f86 100644 Binary files a/icons/mob/silicon/robot_items.dmi and b/icons/mob/silicon/robot_items.dmi differ diff --git a/icons/mob/simple/lavaland/raptor_baby.dmi b/icons/mob/simple/lavaland/raptor_baby.dmi new file mode 100644 index 0000000000000..f892a3cb84fab Binary files /dev/null and b/icons/mob/simple/lavaland/raptor_baby.dmi differ diff --git a/icons/mob/simple/lavaland/raptor_big.dmi b/icons/mob/simple/lavaland/raptor_big.dmi new file mode 100644 index 0000000000000..2a89d84c85e3f Binary files /dev/null and b/icons/mob/simple/lavaland/raptor_big.dmi differ diff --git a/icons/mob/simple/lavaland/raptor_icebox.dmi b/icons/mob/simple/lavaland/raptor_icebox.dmi new file mode 100644 index 0000000000000..86b82e7142d8c Binary files /dev/null and b/icons/mob/simple/lavaland/raptor_icebox.dmi differ diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index 5bcd1df47d929..95453cb46edc8 100644 Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index d8a2fc0bd13cd..d5099c64e7f65 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/head/hats.dmi b/icons/obj/clothing/head/hats.dmi index b655dd1756708..da4a30e996740 100644 Binary files a/icons/obj/clothing/head/hats.dmi and b/icons/obj/clothing/head/hats.dmi differ diff --git a/icons/obj/clothing/head/helmet.dmi b/icons/obj/clothing/head/helmet.dmi index 94d11e6b82040..3cf561103a0a7 100644 Binary files a/icons/obj/clothing/head/helmet.dmi and b/icons/obj/clothing/head/helmet.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 568c059a54d78..5cb090978ae7c 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/modsuit/mod_clothing.dmi b/icons/obj/clothing/modsuit/mod_clothing.dmi index 5070dbb145c9c..3de713477b696 100644 Binary files a/icons/obj/clothing/modsuit/mod_clothing.dmi and b/icons/obj/clothing/modsuit/mod_clothing.dmi differ diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi index 986d9bd9158a9..e937d125ec2a4 100644 Binary files a/icons/obj/clothing/neck.dmi and b/icons/obj/clothing/neck.dmi differ diff --git a/icons/obj/clothing/suits/armor.dmi b/icons/obj/clothing/suits/armor.dmi index 5ff4e25df8636..f68ebc31a4763 100644 Binary files a/icons/obj/clothing/suits/armor.dmi and b/icons/obj/clothing/suits/armor.dmi differ diff --git a/icons/obj/clothing/under/costume.dmi b/icons/obj/clothing/under/costume.dmi index 90bdc205d52ed..85a49d1b3300c 100644 Binary files a/icons/obj/clothing/under/costume.dmi and b/icons/obj/clothing/under/costume.dmi differ diff --git a/icons/obj/devices/scanner.dmi b/icons/obj/devices/scanner.dmi index cea20f32f7f38..f02fa0e4ecdbf 100644 Binary files a/icons/obj/devices/scanner.dmi and b/icons/obj/devices/scanner.dmi differ diff --git a/icons/obj/devices/tracker.dmi b/icons/obj/devices/tracker.dmi index 0508fe816bc4a..59884c0aff881 100644 Binary files a/icons/obj/devices/tracker.dmi and b/icons/obj/devices/tracker.dmi differ diff --git a/icons/obj/doors/shutters_radiation.dmi b/icons/obj/doors/shutters_radiation.dmi index 657b613b0ccde..2e70b24a4aa2a 100644 Binary files a/icons/obj/doors/shutters_radiation.dmi and b/icons/obj/doors/shutters_radiation.dmi differ diff --git a/icons/obj/items_cyborg.dmi b/icons/obj/items_cyborg.dmi index f43d96153138c..39624fce676b8 100644 Binary files a/icons/obj/items_cyborg.dmi and b/icons/obj/items_cyborg.dmi differ diff --git a/icons/obj/machines/computer.dmi b/icons/obj/machines/computer.dmi index f8fb31c9ba080..9fcc46bf9b4e8 100644 Binary files a/icons/obj/machines/computer.dmi and b/icons/obj/machines/computer.dmi differ diff --git a/icons/obj/machines/defib_mount.dmi b/icons/obj/machines/defib_mount.dmi index 4518bb33783ae..846d634253887 100644 Binary files a/icons/obj/machines/defib_mount.dmi and b/icons/obj/machines/defib_mount.dmi differ diff --git a/icons/obj/medical/chemical.dmi b/icons/obj/medical/chemical.dmi index b4b26e4f848c6..84dfd01d2d455 100644 Binary files a/icons/obj/medical/chemical.dmi and b/icons/obj/medical/chemical.dmi differ diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi index d81a6d966c397..1f6393a8c51ba 100644 Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ diff --git a/icons/obj/railings.dmi b/icons/obj/railings.dmi index 7dcb4e7c6f7d7..49b560d2c8707 100644 Binary files a/icons/obj/railings.dmi and b/icons/obj/railings.dmi differ diff --git a/icons/obj/storage/box.dmi b/icons/obj/storage/box.dmi index 8b037860144cc..c0a327d7df669 100644 Binary files a/icons/obj/storage/box.dmi and b/icons/obj/storage/box.dmi differ diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi index 85367e1c47b57..96e803a52eea8 100644 Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi index 4e26f75aa99d1..2c2aae54de3c2 100644 Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi index 6bb1b8b41f67c..ec8216ccc3e7b 100644 Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ diff --git a/icons/obj/toys/balloons.dmi b/icons/obj/toys/balloons.dmi index 0ed6f471bfbe6..96afdaea2c0ed 100644 Binary files a/icons/obj/toys/balloons.dmi and b/icons/obj/toys/balloons.dmi differ diff --git a/icons/obj/toys/toy.dmi b/icons/obj/toys/toy.dmi index 9ac61738fadb1..ef3f6dc9370e5 100644 Binary files a/icons/obj/toys/toy.dmi and b/icons/obj/toys/toy.dmi differ diff --git a/icons/obj/track.dmi b/icons/obj/track.dmi new file mode 100644 index 0000000000000..7fd39e6e53949 Binary files /dev/null and b/icons/obj/track.dmi differ diff --git a/icons/obj/weapons/fireaxe.dmi b/icons/obj/weapons/fireaxe.dmi index c89ea533cbe2a..a4743f680ad52 100644 Binary files a/icons/obj/weapons/fireaxe.dmi and b/icons/obj/weapons/fireaxe.dmi differ diff --git a/icons/obj/weapons/guns/ballistic.dmi b/icons/obj/weapons/guns/ballistic.dmi index f6105e9c5ae10..abbb7743b0140 100644 Binary files a/icons/obj/weapons/guns/ballistic.dmi and b/icons/obj/weapons/guns/ballistic.dmi differ diff --git a/icons/obj/weapons/guns/magic.dmi b/icons/obj/weapons/guns/magic.dmi index 3d7238a72bb0b..34256a7106091 100644 Binary files a/icons/obj/weapons/guns/magic.dmi and b/icons/obj/weapons/guns/magic.dmi differ diff --git a/icons/obj/weapons/guns/projectiles.dmi b/icons/obj/weapons/guns/projectiles.dmi index 11b9af13a2c35..b4056f661b8d3 100644 Binary files a/icons/obj/weapons/guns/projectiles.dmi and b/icons/obj/weapons/guns/projectiles.dmi differ diff --git a/icons/obj/weapons/guns/wide_guns.dmi b/icons/obj/weapons/guns/wide_guns.dmi index c05453c3c25cf..568a3bc051f40 100644 Binary files a/icons/obj/weapons/guns/wide_guns.dmi and b/icons/obj/weapons/guns/wide_guns.dmi differ diff --git a/icons/obj/weapons/hammer.dmi b/icons/obj/weapons/hammer.dmi index 965fd0b37efc8..751e626779890 100644 Binary files a/icons/obj/weapons/hammer.dmi and b/icons/obj/weapons/hammer.dmi differ diff --git a/icons/obj/weapons/shields.dmi b/icons/obj/weapons/shields.dmi index 7c4be107566ec..99e9b06aa4000 100644 Binary files a/icons/obj/weapons/shields.dmi and b/icons/obj/weapons/shields.dmi differ diff --git a/icons/obj/weapons/spear.dmi b/icons/obj/weapons/spear.dmi index 7262da01c4551..7c044d362a765 100644 Binary files a/icons/obj/weapons/spear.dmi and b/icons/obj/weapons/spear.dmi differ diff --git a/icons/obj/weapons/sword.dmi b/icons/obj/weapons/sword.dmi index 255c3b0cffd0e..5dca921bd5bc4 100644 Binary files a/icons/obj/weapons/sword.dmi and b/icons/obj/weapons/sword.dmi differ diff --git a/icons/turf/composite.dmi b/icons/turf/composite.dmi index 7bb2d4717887c..a40c4121d252d 100644 Binary files a/icons/turf/composite.dmi and b/icons/turf/composite.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index 89b4876c0cec2..29eb7d3eaeccc 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/turf/floors/grass_damaged.dmi b/icons/turf/floors/grass_damaged.dmi new file mode 100644 index 0000000000000..73540b3ca6a4c Binary files /dev/null and b/icons/turf/floors/grass_damaged.dmi differ diff --git a/icons/turf/floors/grass_damaged.png b/icons/turf/floors/grass_damaged.png new file mode 100644 index 0000000000000..4123f91cabe7d Binary files /dev/null and b/icons/turf/floors/grass_damaged.png differ diff --git a/icons/turf/floors/grass_damaged.png.toml b/icons/turf/floors/grass_damaged.png.toml new file mode 100644 index 0000000000000..18341264515ee --- /dev/null +++ b/icons/turf/floors/grass_damaged.png.toml @@ -0,0 +1,14 @@ +output_name = "grass_damaged" +template = "bitmask/diagonal_32x32.toml" + +[icon_size] +x = 50 +y = 50 + +[output_icon_size] +x = 50 +y = 50 + +[cut_pos] +x = 25 +y = 25 \ No newline at end of file diff --git a/icons/ui_icons/achievements/achievements.dmi b/icons/ui_icons/achievements/achievements.dmi index ff62bd7e374ef..143d0dc0a03ae 100644 Binary files a/icons/ui_icons/achievements/achievements.dmi and b/icons/ui_icons/achievements/achievements.dmi differ diff --git a/icons/ui_icons/arcade/fireplace.png b/icons/ui_icons/arcade/fireplace.png new file mode 100644 index 0000000000000..080cadbebf022 Binary files /dev/null and b/icons/ui_icons/arcade/fireplace.png differ diff --git a/icons/ui_icons/arcade/shopkeeper.png b/icons/ui_icons/arcade/shopkeeper.png new file mode 100644 index 0000000000000..e5eca14d856df Binary files /dev/null and b/icons/ui_icons/arcade/shopkeeper.png differ diff --git a/interface/skin.dmf b/interface/skin.dmf index ede8e37684078..b8d1d82f17558 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -94,6 +94,15 @@ window "mainwindow" anchor2 = -1,-1 is-visible = false saved-params = "" + elem "commandbar_spy" + type = BROWSER + is-default = false + pos = 0,0 + size = 200x200 + anchor1 = -1,-1 + anchor2 = -1,-1 + is-visible = false + saved-params = "" window "mapwindow" elem "mapwindow" diff --git a/lua/SS13_base.lua b/lua/SS13_base.lua index ddacb345fd5c4..ea04c8c6503dd 100644 --- a/lua/SS13_base.lua +++ b/lua/SS13_base.lua @@ -1,3 +1,6 @@ +local timer = require("timer") +local state = require("state") + local SS13 = {} __SS13_signal_handlers = __SS13_signal_handlers or {} @@ -6,12 +9,7 @@ SS13.SSlua = dm.global_vars.vars.SSlua SS13.global_proc = "some_magic_bullshit" -for _, state in SS13.SSlua.vars.states do - if state.vars.internal_id == dm.state_id then - SS13.state = state - break - end -end +SS13.state = state.state function SS13.get_runner_ckey() return SS13.state:get_var("ckey_last_runner") @@ -25,12 +23,16 @@ function SS13.istype(thing, type) return dm.global_proc("_istype", thing, dm.global_proc("_text2path", type)) == 1 end +function SS13.start_tracking(datum) + local references = SS13.state.vars.references + references:add(datum) + SS13.state:call_proc("clear_on_delete", datum) +end + function SS13.new(type, ...) - local datum = SS13.new_untracked(type, table.unpack({...})) + local datum = SS13.new_untracked(type, ...) if datum then - local references = SS13.state.vars.references - references:add(datum) - SS13.state:call_proc("clear_on_delete", datum) + SS13.start_tracking(datum) return datum end end @@ -75,58 +77,45 @@ function SS13.await(thing_to_call, proc_to_call, ...) return return_value, runtime_message end -function SS13.register_signal(datum, signal, func, make_easy_clear_function) +function SS13.register_signal(datum, signal, func) if not SS13.istype(datum, "/datum") then return end - if not __SS13_signal_handlers[datum] then - __SS13_signal_handlers[datum] = {} + if not SS13.is_valid(datum) then + error("Tried to register a signal on a deleted datum!", 2) + return + end + local datumWeakRef = dm.global_proc("WEAKREF", datum) + if not __SS13_signal_handlers[datumWeakRef] then + __SS13_signal_handlers[datumWeakRef] = {} end if signal == "_cleanup" then return end - if not __SS13_signal_handlers[datum][signal] then - __SS13_signal_handlers[datum][signal] = {} + if not __SS13_signal_handlers[datumWeakRef][signal] then + __SS13_signal_handlers[datumWeakRef][signal] = {} end local callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first") + local callbackWeakRef = dm.global_proc("WEAKREF", callback) callback:call_proc("RegisterSignal", datum, signal, "Invoke") - local path = { "__SS13_signal_handlers", dm.global_proc("WEAKREF", datum), signal, dm.global_proc("WEAKREF", callback), "func" } + local path = { "__SS13_signal_handlers", datumWeakRef, signal, callbackWeakRef, "func" } callback.vars.arguments = { path } - if not __SS13_signal_handlers[datum]["_cleanup"] then - local cleanup_path = { "__SS13_signal_handlers", dm.global_proc("WEAKREF", datum), "_cleanup", "func" } - local cleanup_callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first", cleanup_path) - cleanup_callback:call_proc("RegisterSignal", datum, "parent_qdeleting", "Invoke") - __SS13_signal_handlers[datum]["_cleanup"] = { - func = function(datum) - SS13.signal_handler_cleanup(datum) - SS13.stop_tracking(cleanup_callback) - end, - callback = cleanup_callback, - } - end - if signal == "parent_qdeleting" then --We want to make sure that the cleanup function is the very last signal handler called. - local comp_lookup = datum.vars._listen_lookup - if comp_lookup then - local lookup_for_signal = comp_lookup.entries.parent_qdeleting - if lookup_for_signal and not SS13.istype(lookup_for_signal, "/datum") then - local cleanup_callback_index = - dm.global_proc("_list_find", lookup_for_signal, __SS13_signal_handlers[datum]["_cleanup"].callback) - if cleanup_callback_index ~= 0 and cleanup_callback_index ~= #comp_lookup then - dm.global_proc("_list_swap", lookup_for_signal, cleanup_callback_index, #lookup_for_signal) - end - end - end - end - __SS13_signal_handlers[datum][signal][callback] = { func = func, callback = callback } - if make_easy_clear_function then - local clear_function_name = "clear_signal_" .. tostring(datum) .. "_" .. signal .. "_" .. tostring(callback) - SS13[clear_function_name] = function() - if callback then - SS13.unregister_signal(datum, signal, callback) - end - SS13[clear_function_name] = nil + -- Turfs don't remove their signals on deletion. + if not __SS13_signal_handlers[datumWeakRef]._cleanup and not SS13.istype(datum, "/turf") then + local cleanupCallback = SS13.new("/datum/callback", SS13.state, "call_function_return_first") + local cleanupPath = { "__SS13_signal_handlers", datumWeakRef, "_cleanup"} + cleanupCallback.vars.arguments = { cleanupPath } + cleanupCallback:call_proc("RegisterSignal", datum, "parent_qdeleting", "Invoke") + __SS13_signal_handlers[datumWeakRef]._cleanup = function(datum) + SS13.start_tracking(datumWeakRef) + timer.set_timeout(0, function() + SS13.signal_handler_cleanup(datumWeakRef) + SS13.stop_tracking(cleanupCallback) + SS13.stop_tracking(datumWeakRef) + end) end end + __SS13_signal_handlers[datumWeakRef][signal][callbackWeakRef] = { func = func, callback = callback } return callback end @@ -143,51 +132,58 @@ function SS13.unregister_signal(datum, signal, callback) return end local handler_callback = handler_info.callback - handler_callback:call_proc("UnregisterSignal", datum, signal) + local callbackWeakRef = dm.global_proc("WEAKREF", handler_callback) + if not SS13.istype(datum, "/datum/weakref") then + handler_callback:call_proc("UnregisterSignal", datum, signal) + else + local actualDatum = datum:call_proc("hard_resolve") + if SS13.is_valid(actualDatum) then + handler_callback:call_proc("UnregisterSignal", actualDatum, signal) + end + end SS13.stop_tracking(handler_callback) end - local function clear_easy_clear_function(callback_to_clear) - local clear_function_name = "clear_signal_" .. tostring(datum) .. "_" .. signal .. "_" .. tostring(callback_to_clear) - SS13[clear_function_name] = nil + local datumWeakRef = datum + if not SS13.istype(datum, "/datum/weakref") then + datumWeakRef = dm.global_proc("WEAKREF", datum) end - - if not __SS13_signal_handlers[datum] then + if not __SS13_signal_handlers[datumWeakRef] then return end + if signal == "_cleanup" then return end - if not __SS13_signal_handlers[datum][signal] then + + if not __SS13_signal_handlers[datumWeakRef][signal] then return end if not callback then - for handler_key, handler_info in __SS13_signal_handlers[datum][signal] do - clear_easy_clear_function(handler_key) + for handler_key, handler_info in __SS13_signal_handlers[datumWeakRef][signal] do clear_handler(handler_info) end - __SS13_signal_handlers[datum][signal] = nil + __SS13_signal_handlers[datumWeakRef][signal] = nil else if not SS13.istype(callback, "/datum/callback") then return end - clear_easy_clear_function(callback) - clear_handler(__SS13_signal_handlers[datum][signal][callback]) - __SS13_signal_handlers[datum][signal][callback] = nil + local callbackWeakRef = dm.global_proc("WEAKREF", callback) + clear_handler(__SS13_signal_handlers[datumWeakRef][signal][callbackWeakRef]) + __SS13_signal_handlers[datumWeakRef][signal][callbackWeakRef] = nil end end -function SS13.signal_handler_cleanup(datum) - if not __SS13_signal_handlers[datum] then +function SS13.signal_handler_cleanup(datumWeakRef) + if not __SS13_signal_handlers[datumWeakRef] then return end - for signal, _ in __SS13_signal_handlers[datum] do - SS13.unregister_signal(datum, signal) + for signal, _ in __SS13_signal_handlers[datumWeakRef] do + SS13.unregister_signal(datumWeakRef, signal) end - - __SS13_signal_handlers[datum] = nil + __SS13_signal_handlers[datumWeakRef] = nil end return SS13 diff --git a/lua/docs/handler_group.md b/lua/docs/handler_group.md new file mode 100644 index 0000000000000..7856ff58b4859 --- /dev/null +++ b/lua/docs/handler_group.md @@ -0,0 +1,66 @@ +# Handler Group + +This module is for registering signals on a datum or several datums and being able to clear them all at once without having to unregister them manually. This is particularly useful if you register signals on a datum and need to clear them later without accidentally unregistering unrelated signals + +## Functions + +### HandlerGroup.new() +Creates a new handler group instance + +### HandlerGroup:register_signal(datum, signal, func) +Registers a signal on a datum, exactly the same as `SS13.register_signal` + +### HandlerGroup:clear() +Clears all registered signals that have been registered by this handler group. + +### HandlerGroup:clear_on(datum, signal, func) +Clears all registered signals that have been registered by this handler group when a signal is called on the specified datum. Additionally, a function can be ran before it is cleared + +### HandlerGroup.register_once(datum, signal func) +Identical to just creating a new HandlerGroup instance and calling `clear_on(datum, signal, func)`. + +The idea is to register a signal and clear it after it has been called once. + +## Examples + +The following examples showcase why using handler groups can make life easier in specific situations. + +### Explode when mob enters location +This function creates a 1 tile-wide explosion at the specified location if a specific mob walks over it. The explosion won't happen if the mob dies. This function should be callable on the same mob for different locations. The function should be self-contained, it should not affect other registered signals that the mob may have registered. + +#### Without Handler Groups +```lua +local function explodeAtLocation(mobVar, position) + local deathCallback + local moveCallback + local function unlinkFromMob() + SS13.unregister_signal(mobVar, "living_death", deathCallback) + SS13.unregister_signal(mobVar, "movable_moved", moveCallback) + end + deathCallback = SS13.register_signal(mobVar, "living_death", function(_, gibbed) + unlinkFromMob() + end) + moveCallback = SS13.register_signal(mobVar, "movable_moved", function(_, oldLoc) + if mobVar:get_var("loc") == position then + -- Creates a 1 tile-wide explosion at the specified position + dm.global_proc("explosion", position, 1, 0, 0) + unlinkFromMob() + end + end) +end +``` + +#### With Handler Groups +```lua +local function explodeAtLocation(mobVar, position) + local handler = handler_group.new() + handler:clear_on(mobVar, "living_death") + handler:register_signal(mobVar, "movable_moved", function(_, oldLoc) + if mobVar:get_var("loc") == position then + -- Creates a 1 tile-wide explosion at the specified position + dm.global_proc("explosion", position, 1, 0, 0) + handler:clear() + end + end) +end +``` diff --git a/lua/handler_group.lua b/lua/handler_group.lua new file mode 100644 index 0000000000000..0246d33c74488 --- /dev/null +++ b/lua/handler_group.lua @@ -0,0 +1,49 @@ +local SS13 = require('SS13') +local HandlerGroup = {} +HandlerGroup.__index = HandlerGroup + +function HandlerGroup.new() + return setmetatable({ + registered = {} + }, HandlerGroup) +end + +-- Registers a signal on a datum for this handler group instance. +function HandlerGroup:register_signal(datum, signal, func) + local callback = SS13.register_signal(datum, signal, func) + if not callback then + return + end + table.insert(self.registered, { datum = dm.global_proc("WEAKREF", datum), signal = signal, callback = callback }) +end + +-- Clears all the signals that have been registered on this HandlerGroup +function HandlerGroup:clear() + for _, data in self.registered do + if not data.callback or not data.datum then + continue + end + SS13.unregister_signal(data.datum, data.signal, data.callback) + end + table.clear(self.registered) +end + +-- Clears all the signals that have been registered on this HandlerGroup when a specific signal is sent on a datum. +function HandlerGroup:clear_on(datum, signal, func) + SS13.register_signal(datum, signal, function(...) + if func then + func(...) + end + self:clear() + end) +end + +-- Registers a signal on a datum and clears it after it is called once. +function HandlerGroup.register_once(datum, signal, func) + local callback = HandlerGroup.new() + callback:clear_on(datum, signal, func) + return callback +end + + +return HandlerGroup diff --git a/lua/state.lua b/lua/state.lua new file mode 100644 index 0000000000000..080ee9f7eb32c --- /dev/null +++ b/lua/state.lua @@ -0,0 +1,9 @@ +local SSlua = dm.global_vars:get_var("SSlua") + +for _, state in SSlua:get_var("states") do + if state:get_var("internal_id") == dm.state_id then + return { state = state } + end +end + +return { state = nil } diff --git a/lua/timer.lua b/lua/timer.lua index 605e5b98a2e5c..8619bbb54a29e 100644 --- a/lua/timer.lua +++ b/lua/timer.lua @@ -1,6 +1,8 @@ -local SS13 = require("SS13_base") +local state = require("state") + local Timer = {} +local SSlua = dm.global_vars:get_var("SSlua") __Timer_timers = __Timer_timers or {} __Timer_callbacks = __Timer_callbacks or {} @@ -35,7 +37,7 @@ function __stop_internal_timer(func) end __Timer_timer_processing = __Timer_timer_processing or false -SS13.state:set_var("timer_enabled", 1) +state.state:set_var("timer_enabled", 1) __Timer_timer_process = function(seconds_per_tick) if __Timer_timer_processing then return 0 @@ -50,7 +52,7 @@ __Timer_timer_process = function(seconds_per_tick) sleep() end if time >= timeData.executeTime then - SS13.state:get_var("functions_to_execute"):add(func) + state.state:get_var("functions_to_execute"):add(func) timeData.executing = true end end @@ -61,7 +63,7 @@ end function Timer.wait(time) local next_yield_index = __next_yield_index __add_internal_timer(function() - SS13.SSlua:call_proc("queue_resume", SS13.state, next_yield_index) + SSlua:call_proc("queue_resume", state.state, next_yield_index) end, time * 10, false) coroutine.yield() end diff --git a/sound/ambience/antag/heretic/ascend_ash.ogg b/sound/ambience/antag/heretic/ascend_ash.ogg new file mode 100644 index 0000000000000..a85aa0f6a9ccd Binary files /dev/null and b/sound/ambience/antag/heretic/ascend_ash.ogg differ diff --git a/sound/ambience/antag/heretic/ascend_blade.ogg b/sound/ambience/antag/heretic/ascend_blade.ogg new file mode 100644 index 0000000000000..da7c313ad8ad2 Binary files /dev/null and b/sound/ambience/antag/heretic/ascend_blade.ogg differ diff --git a/sound/ambience/antag/heretic/ascend_cosmic.ogg b/sound/ambience/antag/heretic/ascend_cosmic.ogg new file mode 100644 index 0000000000000..9ce740fa7e1e3 Binary files /dev/null and b/sound/ambience/antag/heretic/ascend_cosmic.ogg differ diff --git a/sound/ambience/antag/heretic/ascend_flesh.ogg b/sound/ambience/antag/heretic/ascend_flesh.ogg new file mode 100644 index 0000000000000..b488cafd0bf6c Binary files /dev/null and b/sound/ambience/antag/heretic/ascend_flesh.ogg differ diff --git a/sound/ambience/antag/heretic/ascend_knock.ogg b/sound/ambience/antag/heretic/ascend_knock.ogg new file mode 100644 index 0000000000000..73f0a7f0b3b5b Binary files /dev/null and b/sound/ambience/antag/heretic/ascend_knock.ogg differ diff --git a/sound/ambience/antag/heretic/ascend_moon.ogg b/sound/ambience/antag/heretic/ascend_moon.ogg new file mode 100644 index 0000000000000..b0d515686b20e Binary files /dev/null and b/sound/ambience/antag/heretic/ascend_moon.ogg differ diff --git a/sound/ambience/antag/heretic/ascend_rust.ogg b/sound/ambience/antag/heretic/ascend_rust.ogg new file mode 100644 index 0000000000000..5cfc73b2cf512 Binary files /dev/null and b/sound/ambience/antag/heretic/ascend_rust.ogg differ diff --git a/sound/ambience/antag/heretic/ascend_void.ogg b/sound/ambience/antag/heretic/ascend_void.ogg new file mode 100644 index 0000000000000..797784952d15c Binary files /dev/null and b/sound/ambience/antag/heretic/ascend_void.ogg differ diff --git a/sound/ambience/antag/ecult_op.ogg b/sound/ambience/antag/heretic/heretic_gain.ogg similarity index 100% rename from sound/ambience/antag/ecult_op.ogg rename to sound/ambience/antag/heretic/heretic_gain.ogg diff --git a/sound/ambience/music/sisyphus/sisyphus.ogg b/sound/ambience/music/sisyphus/sisyphus.ogg new file mode 100644 index 0000000000000..c69d0b608ebc5 Binary files /dev/null and b/sound/ambience/music/sisyphus/sisyphus.ogg differ diff --git a/sound/attributions.txt b/sound/attributions.txt index c81aa3e664b67..bade328eff9c9 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -140,3 +140,36 @@ https://freesound.org/people/steaq/sounds/560124/ refinery.ogg, smelter.ogg, and wooping_teleport.ogg are all original works by ArcaneMusic, with smelter.ogg using samples from rock_break alongside original sound effects from a warrior electric drill, where refinery and wooping_teleport are modifications of that same electric drill recording. + +paper_flip.ogg is made by gynation from Freesound.org, CC0 +https://freesound.org/people/gynation/sounds/82378/ + +nightmare_poof.ogg and nightmare_reappear.ogg are comprised of breath_01.wav by Nightflame (CC0) and slide-click.wav by Qat (CC0) +https://freesound.org/people/Qat/sounds/108332/ +https://freesound.org/people/Nightflame/sounds/368615/ + +modified by grungussuss: +male_sneeze1.ogg: https://freesound.org/people/InspectorJ/sounds/352177/ , license: CC BY 4.0 DEED +male_cry1.ogg: https://freesound.org/people/jacobmathiassen/sounds/254869/ , license: CC BY 4.0 DEED +male_cry2.ogg: https://freesound.org/people/scottemoil/sounds/263776/ , license: CC0 1.0 DEED +male_cry3.ogg: https://freesound.org/people/qubodup/sounds/200428/ , license: CC BY 4.0 DEED +female_cry1.ogg: https://freesound.org/people/Luzanne0/sounds/445299/ , license: CC BY-NC 3.0 DEED +female_cry2.ogg: https://freesound.org/people/Idalize/sounds/408211/ , license: CC BY-NC 4.0 DEED +female_cough1.ogg: https://freesound.org/people/OwlStorm/sounds/151213/ , license: CC0 1.0 DEED +female_cough2.ogg: https://freesound.org/people/thatkellytrna/sounds/425777/ , license: CC0 1.0 DEED +female_cough3.ogg: https://freesound.org/people/Luzanne0/sounds/445293/ , license: CC BY-NC 3.0 DEED +female_cough4.ogg: https://freesound.org/people/Luzanne0/sounds/445293/ , license: CC BY-NC 3.0 DEED +female_cough5.ogg: https://freesound.org/people/DarkNightPrincess/sounds/625322/ , license: CC0 1.0 DEED +female_cough6.ogg: https://freesound.org/people/drotzruhn/sounds/405206/ , license: CC BY 4.0 DEED +male_cough1.ogg: https://freesound.org/people/Harris85/sounds/208761/ , license: CC0 1.0 DEED +male_cough2.ogg: https://freesound.org/people/midwestdocumentary/sounds/722622/ , license: CC0 1.0 DEED +male_cough3.ogg: https://freesound.org/people/hadescolossus/sounds/701162/ , license: CC0 1.0 DEED +male_cough4.ogg: https://freesound.org/people/SoundDesignForYou/sounds/646652/ , license: CC0 1.0 DEED +male_cough5.ogg: https://freesound.org/people/SoundDesignForYou/sounds/646654/ , license: CC0 1.0 DEED +male_cough6.ogg: https://freesound.org/people/SoundDesignForYou/sounds/646656/ , license: CC0 1.0 DEED +lizard_laugh1.ogg: https://youtu.be/I7CX0AS8RNI , License: CC-BY-3.0 +moth_laugh1.ogg: https://github.com/BeeStation/BeeStation-Hornet/blob/11ba3fa04105c93dd96a63ad4afaef4b20c02d0d/sound/emotes/ , license: CC-BY-SA-3.0 +whistle1.ogg: https://freesound.org/people/taure/sounds/411638/ , license: CC0 1.0 DEED + +portal_close, portal_open_1 , portal_open_2 , portal_open_3 , portal_travel made by @virgilcore (discord IGN) + diff --git a/sound/creatures/raptor_1.ogg b/sound/creatures/raptor_1.ogg new file mode 100644 index 0000000000000..94d53073aa64f Binary files /dev/null and b/sound/creatures/raptor_1.ogg differ diff --git a/sound/creatures/raptor_2.ogg b/sound/creatures/raptor_2.ogg new file mode 100644 index 0000000000000..01c23ff03cedd Binary files /dev/null and b/sound/creatures/raptor_2.ogg differ diff --git a/sound/creatures/raptor_3.ogg b/sound/creatures/raptor_3.ogg new file mode 100644 index 0000000000000..dff3946ec0490 Binary files /dev/null and b/sound/creatures/raptor_3.ogg differ diff --git a/sound/creatures/raptor_4.ogg b/sound/creatures/raptor_4.ogg new file mode 100644 index 0000000000000..53c28c72ffdc9 Binary files /dev/null and b/sound/creatures/raptor_4.ogg differ diff --git a/sound/creatures/raptor_5.ogg b/sound/creatures/raptor_5.ogg new file mode 100644 index 0000000000000..dd424a1566fcb Binary files /dev/null and b/sound/creatures/raptor_5.ogg differ diff --git a/sound/effects/nightmare_poof.ogg b/sound/effects/nightmare_poof.ogg new file mode 100644 index 0000000000000..e8b44685ba438 Binary files /dev/null and b/sound/effects/nightmare_poof.ogg differ diff --git a/sound/effects/nightmare_reappear.ogg b/sound/effects/nightmare_reappear.ogg new file mode 100644 index 0000000000000..3dec20064602a Binary files /dev/null and b/sound/effects/nightmare_reappear.ogg differ diff --git a/sound/effects/portal_close.ogg b/sound/effects/portal_close.ogg new file mode 100644 index 0000000000000..b5910c460d54c Binary files /dev/null and b/sound/effects/portal_close.ogg differ diff --git a/sound/effects/portal_open_1.ogg b/sound/effects/portal_open_1.ogg new file mode 100644 index 0000000000000..02377a14e005e Binary files /dev/null and b/sound/effects/portal_open_1.ogg differ diff --git a/sound/effects/portal_open_2.ogg b/sound/effects/portal_open_2.ogg new file mode 100644 index 0000000000000..06309d8016028 Binary files /dev/null and b/sound/effects/portal_open_2.ogg differ diff --git a/sound/effects/portal_open_3.ogg b/sound/effects/portal_open_3.ogg new file mode 100644 index 0000000000000..b2d0e8a01b41f Binary files /dev/null and b/sound/effects/portal_open_3.ogg differ diff --git a/sound/effects/portal_travel.ogg b/sound/effects/portal_travel.ogg new file mode 100644 index 0000000000000..2c1e306b34ab4 Binary files /dev/null and b/sound/effects/portal_travel.ogg differ diff --git a/sound/items/paper_flip.ogg b/sound/items/paper_flip.ogg new file mode 100644 index 0000000000000..9e6aca596756c Binary files /dev/null and b/sound/items/paper_flip.ogg differ diff --git a/sound/magic/staff_shrink.ogg b/sound/magic/staff_shrink.ogg new file mode 100644 index 0000000000000..f2268130fd81c Binary files /dev/null and b/sound/magic/staff_shrink.ogg differ diff --git a/sound/voice/human/female_cough1.ogg b/sound/voice/human/female_cough1.ogg new file mode 100644 index 0000000000000..53af74368c3bf Binary files /dev/null and b/sound/voice/human/female_cough1.ogg differ diff --git a/sound/voice/human/female_cough2.ogg b/sound/voice/human/female_cough2.ogg new file mode 100644 index 0000000000000..eb3551a31fecb Binary files /dev/null and b/sound/voice/human/female_cough2.ogg differ diff --git a/sound/voice/human/female_cough3.ogg b/sound/voice/human/female_cough3.ogg new file mode 100644 index 0000000000000..a075963d3b46d Binary files /dev/null and b/sound/voice/human/female_cough3.ogg differ diff --git a/sound/voice/human/female_cough4.ogg b/sound/voice/human/female_cough4.ogg new file mode 100644 index 0000000000000..0136ea42ccff2 Binary files /dev/null and b/sound/voice/human/female_cough4.ogg differ diff --git a/sound/voice/human/female_cough5.ogg b/sound/voice/human/female_cough5.ogg new file mode 100644 index 0000000000000..7562661bd4853 Binary files /dev/null and b/sound/voice/human/female_cough5.ogg differ diff --git a/sound/voice/human/female_cough6.ogg b/sound/voice/human/female_cough6.ogg new file mode 100644 index 0000000000000..62938b7b761af Binary files /dev/null and b/sound/voice/human/female_cough6.ogg differ diff --git a/sound/voice/human/female_cry1.ogg b/sound/voice/human/female_cry1.ogg new file mode 100644 index 0000000000000..f4f7386417194 Binary files /dev/null and b/sound/voice/human/female_cry1.ogg differ diff --git a/sound/voice/human/female_cry2.ogg b/sound/voice/human/female_cry2.ogg new file mode 100644 index 0000000000000..e81e93b5c3f83 Binary files /dev/null and b/sound/voice/human/female_cry2.ogg differ diff --git a/sound/voice/human/female_sneeze1.ogg b/sound/voice/human/female_sneeze1.ogg new file mode 100644 index 0000000000000..8fe020a8c7e8a Binary files /dev/null and b/sound/voice/human/female_sneeze1.ogg differ diff --git a/sound/voice/human/male_cough1.ogg b/sound/voice/human/male_cough1.ogg new file mode 100644 index 0000000000000..f553bd855ae94 Binary files /dev/null and b/sound/voice/human/male_cough1.ogg differ diff --git a/sound/voice/human/male_cough2.ogg b/sound/voice/human/male_cough2.ogg new file mode 100644 index 0000000000000..3dcc880175fb5 Binary files /dev/null and b/sound/voice/human/male_cough2.ogg differ diff --git a/sound/voice/human/male_cough3.ogg b/sound/voice/human/male_cough3.ogg new file mode 100644 index 0000000000000..a87ba9cc4c730 Binary files /dev/null and b/sound/voice/human/male_cough3.ogg differ diff --git a/sound/voice/human/male_cough4.ogg b/sound/voice/human/male_cough4.ogg new file mode 100644 index 0000000000000..38052dc78711b Binary files /dev/null and b/sound/voice/human/male_cough4.ogg differ diff --git a/sound/voice/human/male_cough5.ogg b/sound/voice/human/male_cough5.ogg new file mode 100644 index 0000000000000..5a1b836775dbf Binary files /dev/null and b/sound/voice/human/male_cough5.ogg differ diff --git a/sound/voice/human/male_cough6.ogg b/sound/voice/human/male_cough6.ogg new file mode 100644 index 0000000000000..cfe4e08655b94 Binary files /dev/null and b/sound/voice/human/male_cough6.ogg differ diff --git a/sound/voice/human/male_cry1.ogg b/sound/voice/human/male_cry1.ogg new file mode 100644 index 0000000000000..50ffd0cf72a7d Binary files /dev/null and b/sound/voice/human/male_cry1.ogg differ diff --git a/sound/voice/human/male_cry2.ogg b/sound/voice/human/male_cry2.ogg new file mode 100644 index 0000000000000..8d35a4d527669 Binary files /dev/null and b/sound/voice/human/male_cry2.ogg differ diff --git a/sound/voice/human/male_cry3.ogg b/sound/voice/human/male_cry3.ogg new file mode 100644 index 0000000000000..58f39b5fff134 Binary files /dev/null and b/sound/voice/human/male_cry3.ogg differ diff --git a/sound/voice/human/male_sneeze1.ogg b/sound/voice/human/male_sneeze1.ogg new file mode 100644 index 0000000000000..1c7e8f42534d8 Binary files /dev/null and b/sound/voice/human/male_sneeze1.ogg differ diff --git a/sound/voice/human/whistle1.ogg b/sound/voice/human/whistle1.ogg new file mode 100644 index 0000000000000..4109260659723 Binary files /dev/null and b/sound/voice/human/whistle1.ogg differ diff --git a/sound/voice/lizard/lizard_laugh1.ogg b/sound/voice/lizard/lizard_laugh1.ogg new file mode 100644 index 0000000000000..b2c02e6d2fcb0 Binary files /dev/null and b/sound/voice/lizard/lizard_laugh1.ogg differ diff --git a/sound/voice/moth/moth_laugh1.ogg b/sound/voice/moth/moth_laugh1.ogg new file mode 100644 index 0000000000000..391d6c5aefe2c Binary files /dev/null and b/sound/voice/moth/moth_laugh1.ogg differ diff --git a/sound/weapons/zipline_fire.ogg b/sound/weapons/zipline_fire.ogg new file mode 100644 index 0000000000000..4ac133897b5d0 Binary files /dev/null and b/sound/weapons/zipline_fire.ogg differ diff --git a/sound/weapons/zipline_hit.ogg b/sound/weapons/zipline_hit.ogg new file mode 100644 index 0000000000000..cf17cbc84d15b Binary files /dev/null and b/sound/weapons/zipline_hit.ogg differ diff --git a/sound/weapons/zipline_mid.ogg b/sound/weapons/zipline_mid.ogg new file mode 100644 index 0000000000000..22148f1c594be Binary files /dev/null and b/sound/weapons/zipline_mid.ogg differ diff --git a/strings/antagonist_flavor/spy_objective.json b/strings/antagonist_flavor/spy_objective.json index aa696baad6fa0..908a8da2b82c0 100644 --- a/strings/antagonist_flavor/spy_objective.json +++ b/strings/antagonist_flavor/spy_objective.json @@ -8,73 +8,190 @@ "Ensure @pick(location) is @pick(affected) by the end of the shift.", "Ensure no heads of staff @pick(escape) the station.", "Ensure no members of @pick(department) @pick(escape) the station.", - "Ensure no rival @pick(rivals) @pick(escape) the station.", + "Ensure no @pick(rivals) @pick(escape) the station.", + "Ensure no @pick(rivals) succeed in their objectives.", + "Ensure all @pick(rivals) @pick(escape) the station.", + "Ensure all @pick(rivals) succeed in their objectives.", + "Ensure at least some @pick(rivals) leave the shift @pick(affected).", + "Ensure at least some @pick(rivals) do not leave the shift @pick(affected).", + "Ensure at least some @pick(rivals) @pick(escape) the station @pick(affected).", + "Ensure no @pick(rivals) @pick(escape) the station @pick(affected).", + "Ensure the station's @pick(happenings) turn out @pick(affected).", "Frame a crewmember for a crime.", "Free the station's AI from its laws.", "Halt the station's @pick(happenings).", + "Help the station succeed in its @pick(happenings).", "Invoke a mutiny against the heads of staff.", - "Make it difficult, but not impossible to @pick(escape) the station.", + "Invoke a mutiny in @pick(department).", + "Keep everyone out of @pick(location).", + "Make it difficult but not impossible to @pick(escape) the station.", + "Protect the station's @pick(happenings).", "Sabotage the station's power grid or engine.", + "Steal all the @pick(stealables) from @pick(department).", + "Steal all the @pick(stealables) from @pick(location).", "Steal as many @pick(stealables) as you can.", "Take control of the station as the new Captain.", - "Take hostages of high value crewmembers and demand a ransom." + "Take hostages of high value crewmembers and demand a ransom.", + "Terrorize @pick(department) enough to be attacked on sight.", + "Terrorize @pick(rivals) enough to be branded a hero." ], "department": [ - "Security", + "Command", "Engineering", "Medical", "Science", + "Security", + "Service", "Supply" ], "location": [ + "atmospherics", + "departures", "engineering", "genetics", "hydroponics", "medbay", + "the armory", "the bar", "the bridge", "the brig", "the cargo bay", + "the Central Primary hallway", + "the courtroom", "the chapel", + "the garden", + "the holodeck", "the kitchen", "the library", + "the mining outpost", + "the vault", + "virology", "xenobiology" ], "happenings": [ - "research", + "breakfasts", "cargo operations", "communications", + "efforts to figure something out", + "efforts to make an important decision", + "efforts to solve a crime", + "efforts to solve a murder", + "efforts to start a project", + "efforts to stop a disaster", + "lunches", + "dinners", "genetic research", - "mining operation" + "mech constructions", + "mining operations", + "optional surgeries", + "public gatherings", + "public services", + "research efforts", + "social events", + "xenobiological experiments" ], "affected": [ + "a disaster", "ablaze", + "alive", + "a failure", + "a success", + "better than expected", + "blasted", + "bored", + "boring", "burning", + "busy", + "clean", + "confused", + "confusing", "covered in blood", + "cursed", + "dead", + "dirty", + "disrupted", + "disabled", "demolished", "destroyed", + "devastated", "engulfed in flames", + "exploded", + "exploding", + "free", + "frustrated", + "functional", + "hazardous", + "horrified", + "horrifying", + "in chaos", + "inspired", + "inspiring", + "intact", + "locked down", + "non-functional", "obliterated", + "offended", "on fire", + "optimized", + "peaceful", + "powerful", + "quiet", "ruined", "sabotaged", + "safe", + "scary", + "scandalized", + "serene", + "shattered", + "terrible", + "tranquil", + "unrecognizable", + "vandalized", "wrecked" ], "rivals": [ "agents", + "aliens", + "cowards", + "criminals", + "entertainers", + "extradimensional horrors", + "fanatics", + "foreigners", + "hooligans", + "litterers", + "magic-users", "moles", "operatives", + "rude people", + "sentient non-humanoids", "spies", - "traitors" + "subversives", + "thieves", + "traitors", + "tyrants" ], "stealables": [ + "appliances", + "cargo orders", + "critical pieces of infrastructure", + "decorations", + "floor tiles", + "foods", "items", + "materials", + "medicines", "objects", + "pets", + "public supplies", + "quiet moments", "things", "tools", + "vending machines", "weapons" ], "escape": [ + "abscond from", "depart", "escape", "evacuate", diff --git a/strings/arcade.json b/strings/arcade.json index 584cbc6decd85..a97a3d7554961 100644 --- a/strings/arcade.json +++ b/strings/arcade.json @@ -79,64 +79,6 @@ "Yuletide" ], - "rpg_action": [ - "Annihilate", - "Ban", - "Defeat", - "Destroy", - "Mutilate", - "Nuke", - "Own", - "Perma", - "Pwn", - "Pulverize", - "Robust", - "Save", - "Stop", - "Strike", - "Valid", - "Yeet" - ], - - "rpg_action_valentines": [ - "Bewitch", - "Crush", - "Cuddle", - "Divorce", - "ERP", - "Romance", - "Seduce", - "Smooch", - "Titillate" - ], - - "rpg_action_halloween": [ - "Amputate", - "Behead", - "Beware", - "Butcher", - "Dismember", - "Exorcise", - "Frighten", - "Horrify", - "Scare", - "Scythe", - "Slay", - "Spook", - "Vanquish" - ], - - "rpg_action_xmas": [ - "Freeze", - "Jingle", - "Nutcrack", - "Re-gift", - "Snowplow", - "Stuff", - "Unwrap", - "Wassail" - ], - "rpg_enemy": [ "Administrator", "Bloopers", @@ -217,66 +159,6 @@ "Stalking Stocking", "Yeti", "Yuki-Onna" - ], - - "rpg_weapon": [ - "baseball bat", - "bike horn", - "broken bottle", - "chef's knife", - "circular saw", - "claymore", - "cleaver", - "crowbar", - "curator's whip", - "fire axe", - "fire extinguisher", - "full oxygen tank", - "glass shard", - "liz o' nine tails", - "null rod", - "potted plant", - "rolling pin", - "scalpel", - "screwdriver", - "stunprod", - "toolbox", - "welder" - ], - - "rpg_weapon_valentines": [ - "bouquet of deathnettles", - "candy-heart shotgun", - "cupid's arrow", - "declaration of anguished feelings", - "razor-sharp breakup letter", - "still-beating heart", - "thorny rose", - "toolbox of chocolates" - ], - - "rpg_weapon_halloween": [ - "chainsaw", - "heavy gravestone", - "lit jack-o-lantern", - "machete", - "silver dagger", - "skeleton femur", - "spectral blade", - "wooden stake" - ], - - "rpg_weapon_xmas": [ - "bike horn playing carols", - "blunt fruitcake", - "box cutter", - "Christmas-light garrotte", - "festivus polearm", - "rejected present", - "sharpened icicle", - "sprig of mistletoe", - "thrown snowball", - "whole Christmas tree" ] } diff --git a/strings/pirates.json b/strings/pirates.json index 62da040c6be2a..8eec25a3535f2 100644 --- a/strings/pirates.json +++ b/strings/pirates.json @@ -237,5 +237,22 @@ "Mass of Fermenting Dregs", "Bloody Valentine", "Wild Nothing" + ], + "medieval_names":[ + "Head Reaper", + "The Lords Judgement", + "The Judgement", + "Peasant Smiter", + "Wicked Ravager", + "Sheep Reaver", + "Never-ending Crusade", + "Locus Invicta", + "Memento Morieris", + "God Conqueror", + "Omnium Contra Omnes", + "Aries Duo", + "Dark Ages Bringer", + "Merciless Barricade", + "Murder Mcmurderface" ] } diff --git a/strings/tips.txt b/strings/tips.txt index 2f17afc84afb2..34075d12664a9 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -44,6 +44,14 @@ As a Geneticist, T goes to A, and G goes to C. As a Ghost, you can both start and join capture the flag games through the minigames menu, or by clicking on one of the team spawners, which can be found under the "Misc" section of the orbit menu. As a Ghost, you can double click on just about anything to follow it. Or just warp around! As a Ghost, you can see the inside of a container on the ground by clicking on it. +As a Heretic, the Path of Ash focuses on stealth and disorientation, but as you progress, sheds this playstyle in favor of a more aggressive, fiery finale. +As a Heretic, the Path of Moon will literally drive people around you crazy - perhaps crazy enough to become your allies should you succeed. +As a Heretic, the Path of Lock is an Assistant's best friend, and can open many pathways. Including ones beyond the veil... +As a Heretic, the Path of Flesh allows you to raise an army by summoning ghouls and monsters from beyond the veil. Through ascension, you become a one-man army yourself. +As a Heretic, the Path of Void makes people wish they could scream in the vast emptiness of space or have a chance at escaping from you. In the end, the storm takes all. +As a Heretic, the Path of Blade rewards your ability to fight, by making you better and better at it. Though ascension, you can become an ultimate dueling juggernaut. +As a Heretic, the Path of Rust is quite overt, but allows you to shrug of a lot of damage as everything around you slowly decays into nothing but rot and rust. +As a Heretic, the Path of Cosmos allows you to take rightful ownership of the very space the crew treads on. And if they don't respect your status, calling in a friend from beyond should show them. As a Janitor Cyborg, you are the bane of all slaughter demons and even Bubblegum himself. Cleaning up blood stains will severely gimp them. As a Janitor, if someone steals your janicart, you can instead use your space cleaner spray, grenades, water sprayer, exact bloody revenge or order another from Cargo. As a Janitor, mousetraps can be used to create bombs or booby-trap containers. @@ -60,6 +68,9 @@ As a Medical Doctor, you can extract implants by holding an empty implant case i As a Medical Doctor, you can point your penlight at people to create a medical hologram. This lets them know that you're coming to treat them. As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva. As a Medical Doctor, you must target the correct limb and not be in combat mode when trying to perform surgery on someone. Right clicking your patient will intentionally fail the surgery step. +As a Medical Doctor, when messing with viruses, remember that robotic organs can give immunity to disease effects and transmissibility. Make use of the inorganic biology symptom to bypass the protection. +As a Medical Doctor, while there's an pandemic, you only require small amounts of vaccine to heal a sick patient. Work with the Chemist to distribute your cures more efficiently. +As a Medical Doctor, try messing with the virology lab sometime! Viruses can range from healing powers so great that you can heal out of critical status, or diseases so dangerous they can kill the entire crew with airborne spontaneous combustion. Experiment! As a Monkey, you can crawl through air or scrubber vents by alt+left clicking them. You must drop everything you are wearing and holding to do this, however. As a Monkey, you can still wear a few human items, such as backpacks, gas masks and hats, and still have two free hands. As a Morph, you can talk while disguised, but your words have a chance of being slurred, giving you away! @@ -149,6 +160,7 @@ As the AI, you can take pictures with your camera and upload them to newscasters As the AI, you can use CTRL + 1-9 to set a location hotkey for your camera, allowing you to save the location and jump to it at will. Tilde and zero will return you to the last spot you jumped from, and the numpad numbers act as aliases to the regular number keys. As the Bartender, the drinks you start with only give you the basics. If you want more advanced mixtures, look into working with chemistry, hydroponics, or even mining for things to grind up and throw in! As the Bartender, you can use a circular saw on your shotgun to make it easier to store. +As the Bartender, remember to set up the bar sign by walking up to it and clicking it! As the Blob, don't neglect the creation of factories. These create spores that carry your reagent and can chase crew members far further than you. Spores can also be rallied to swarm the crew and cause panic, and can even take over corpses to create much more dangerous blob zombies! As the Blob, keep your core some distance from space, as it is both expensive to expand onto space, easy to be attacked from, and does not count towards your win condition. Emitter platforms built in space are especially dangerous. As the Blob, removing strong blobs, resource nodes, factories, and nodes will give you 4, 15, 25, and 25 resources back, respectively. @@ -175,10 +187,13 @@ As the Clown, eating bananas heals you slightly. Honk! As the Clown, if you lose your banana peel, you can still slip people with your PDA! Honk! As the Clown, if you're a Traitor and get an emag on sale (or convince another traitor), you can emag your Clown Car to unlock a variety of new functions, including the Siege Mode, which will allow you to launch your passengers, preferably directly into the Supermatter! Or into space. As the Clown, spice your gimmicks up! Nobody likes a one-trick pony. +As the Clown, click with one long balloon in hand onto another to create a balloon animal! Each combination of colours has its own unique result. As the Clown, you can use your stamp on a sheet of cardboard as the first step of making a honkbot. Fun for the whole crew! As the Clown, your Grail is the mineral bananium, which can be given to the Roboticist to build you a fun and robust mech beloved by everyone. As the Curator, be sure to keep the shelves stocked and the library clean for crew. As the Curator, you are not completely defenseless. Your whip easily disarms people, your laser pointer can blind humans and cyborgs, and you can hide items in wirecut books. +As the Coroner, you are more comfortable working on cadavers. You can perform autopsies or harvest organs from corpses a lot faster than your Medical Doctor counterparts. Work in tandem with them by helping prepare bodies for revival. +As the Coroner, you can perform autopsies on corpses recovered from strange circumstances with your handheld autopsy scanner to discover how they died. By teaming up with a Detective, you can solve several cases together! As the Detective, people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department. As the Detective, you can use your forensics scanner from a distance. Use this to scan boxes or other storage containers. As the Detective, your revolver can be loaded with .357 ammunition obtained from a hacked autolathe. Firing it has a decent chance to blow up your revolver. @@ -198,9 +213,6 @@ As the Quartermaster, be sure to check the manifests on crates you receive to ma As the Quartermaster, you can construct an express supply console that instantly delivers crates by drop pod. The impact will cause a small explosion as well. As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled. As the Research Director, you can take AIs out of their cores by loading them into an intelliCard, which lets you see their laws, even ion/syndicate ones. It can then be placed into an AI system integrity restorer computer to revive and/or repair them. -As the Virologist, robotic organs can give immunity to disease effects and transmissibility. Make use of the inorganic biology symptom to bypass the protection. -As the Virologist, you only require small amounts of vaccine to heal a sick patient. Work with the Chemist to distribute your cures more efficiently. -As the Virologist, your viruses can range from healing powers so great that you can heal out of critical status, or diseases so dangerous they can kill the entire crew with airborne spontaneous combustion. Experiment! As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while! As the Warden, keep a close eye on the armory at all times, as it is a favored strike point of nuclear operatives and cocky traitors. As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals. diff --git a/strings/traumas.json b/strings/traumas.json index db8a2e9c9c1d9..1fc4b95b1d857 100644 --- a/strings/traumas.json +++ b/strings/traumas.json @@ -67,7 +67,8 @@ "WHERES THE SLIP REWRITE WHERE THR FUCK ID IT?", "who the HELL do u thenk u r?!!!!", "without oxigen blob don't evoluate?", - "youed call her a toeugh bithc" + "youed call her a toeugh bithc", + "I AM ALPHA MAN!!" ], "mutations": [ diff --git a/tgstation.dme b/tgstation.dme index f7ec13785814b..2e7b8532db0ff 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -33,6 +33,7 @@ #include "code\__DEFINES\actions.dm" #include "code\__DEFINES\actionspeed_modification.dm" #include "code\__DEFINES\admin.dm" +#include "code\__DEFINES\admin_verb.dm" #include "code\__DEFINES\adventure.dm" #include "code\__DEFINES\airlock.dm" #include "code\__DEFINES\alarm.dm" @@ -42,7 +43,7 @@ #include "code\__DEFINES\antagonists.dm" #include "code\__DEFINES\apc_defines.dm" #include "code\__DEFINES\appearance.dm" -#include "code\__DEFINES\area_editor.dm" +#include "code\__DEFINES\arcades.dm" #include "code\__DEFINES\art.dm" #include "code\__DEFINES\assemblies.dm" #include "code\__DEFINES\assert.dm" @@ -62,6 +63,7 @@ #include "code\__DEFINES\chat.dm" #include "code\__DEFINES\chat_filter.dm" #include "code\__DEFINES\cleaning.dm" +#include "code\__DEFINES\click.dm" #include "code\__DEFINES\client.dm" #include "code\__DEFINES\clothing.dm" #include "code\__DEFINES\colors.dm" @@ -117,6 +119,7 @@ #include "code\__DEFINES\instruments.dm" #include "code\__DEFINES\interaction_flags.dm" #include "code\__DEFINES\inventory.dm" +#include "code\__DEFINES\ipintel.dm" #include "code\__DEFINES\is_helpers.dm" #include "code\__DEFINES\jobs.dm" #include "code\__DEFINES\keybinding.dm" @@ -180,6 +183,7 @@ #include "code\__DEFINES\procpath.dm" #include "code\__DEFINES\profile.dm" #include "code\__DEFINES\projectiles.dm" +#include "code\__DEFINES\pronouns.dm" #include "code\__DEFINES\qdel.dm" #include "code\__DEFINES\quirks.dm" #include "code\__DEFINES\radiation.dm" @@ -337,6 +341,7 @@ #include "code\__DEFINES\dcs\signals\signals_music.dm" #include "code\__DEFINES\dcs\signals\signals_object.dm" #include "code\__DEFINES\dcs\signals\signals_operating_computer.dm" +#include "code\__DEFINES\dcs\signals\signals_operatives.dm" #include "code\__DEFINES\dcs\signals\signals_painting.dm" #include "code\__DEFINES\dcs\signals\signals_proxmonitor.dm" #include "code\__DEFINES\dcs\signals\signals_radiation.dm" @@ -499,12 +504,11 @@ #include "code\__HELPERS\paths\jps.dm" #include "code\__HELPERS\paths\path.dm" #include "code\__HELPERS\paths\sssp.dm" -#include "code\__HELPERS\sorts\__main.dm" -#include "code\__HELPERS\sorts\InsertSort.dm" -#include "code\__HELPERS\sorts\MergeSort.dm" -#include "code\__HELPERS\sorts\TimSort.dm" +#include "code\__HELPERS\sorts\helpers.dm" +#include "code\__HELPERS\sorts\sort_instance.dm" #include "code\_globalvars\_regexes.dm" #include "code\_globalvars\admin.dm" +#include "code\_globalvars\arcade.dm" #include "code\_globalvars\bitfields.dm" #include "code\_globalvars\colorvars.dm" #include "code\_globalvars\configuration.dm" @@ -551,6 +555,7 @@ #include "code\_onclick\adjacent.dm" #include "code\_onclick\ai.dm" #include "code\_onclick\click.dm" +#include "code\_onclick\click_alt.dm" #include "code\_onclick\cyborg.dm" #include "code\_onclick\drag_drop.dm" #include "code\_onclick\item_attack.dm" @@ -612,6 +617,7 @@ #include "code\controllers\configuration\entries\resources.dm" #include "code\controllers\subsystem\achievements.dm" #include "code\controllers\subsystem\addiction.dm" +#include "code\controllers\subsystem\admin_verbs.dm" #include "code\controllers\subsystem\ai_controllers.dm" #include "code\controllers\subsystem\air.dm" #include "code\controllers\subsystem\ambience.dm" @@ -626,7 +632,6 @@ #include "code\controllers\subsystem\blackmarket.dm" #include "code\controllers\subsystem\chat.dm" #include "code\controllers\subsystem\circuit_component.dm" -#include "code\controllers\subsystem\communications.dm" #include "code\controllers\subsystem\dbcore.dm" #include "code\controllers\subsystem\dcs.dm" #include "code\controllers\subsystem\discord.dm" @@ -639,13 +644,11 @@ #include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\icon_smooth.dm" #include "code\controllers\subsystem\id_access.dm" -#include "code\controllers\subsystem\idlenpcpool.dm" #include "code\controllers\subsystem\init_profiler.dm" #include "code\controllers\subsystem\input.dm" #include "code\controllers\subsystem\ipintel.dm" #include "code\controllers\subsystem\job.dm" #include "code\controllers\subsystem\lag_switch.dm" -#include "code\controllers\subsystem\language.dm" #include "code\controllers\subsystem\library.dm" #include "code\controllers\subsystem\lighting.dm" #include "code\controllers\subsystem\lua.dm" @@ -684,6 +687,7 @@ #include "code\controllers\subsystem\sounds.dm" #include "code\controllers\subsystem\spatial_gridmap.dm" #include "code\controllers\subsystem\speech_controller.dm" +#include "code\controllers\subsystem\sprite_accessories.dm" #include "code\controllers\subsystem\statpanel.dm" #include "code\controllers\subsystem\stickyban.dm" #include "code\controllers\subsystem\stock_market.dm" @@ -718,7 +722,6 @@ #include "code\controllers\subsystem\movement\ai_movement.dm" #include "code\controllers\subsystem\movement\cliff_falling.dm" #include "code\controllers\subsystem\movement\hyperspace_drift.dm" -#include "code\controllers\subsystem\movement\move_handler.dm" #include "code\controllers\subsystem\movement\movement.dm" #include "code\controllers\subsystem\movement\movement_types.dm" #include "code\controllers\subsystem\movement\spacedrift.dm" @@ -737,7 +740,7 @@ #include "code\controllers\subsystem\processing\ai_basic_avoidance.dm" #include "code\controllers\subsystem\processing\ai_behaviors.dm" #include "code\controllers\subsystem\processing\antag_hud.dm" -#include "code\controllers\subsystem\processing\aura_healing.dm" +#include "code\controllers\subsystem\processing\aura.dm" #include "code\controllers\subsystem\processing\clock_component.dm" #include "code\controllers\subsystem\processing\conveyors.dm" #include "code\controllers\subsystem\processing\digital_clock.dm" @@ -747,7 +750,6 @@ #include "code\controllers\subsystem\processing\greyscale.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\obj.dm" -#include "code\controllers\subsystem\processing\obj_tab_items.dm" #include "code\controllers\subsystem\processing\plumbing.dm" #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" @@ -764,6 +766,8 @@ #include "code\datums\candidate_poll.dm" #include "code\datums\chat_payload.dm" #include "code\datums\chatmessage.dm" +#include "code\datums\cogbar.dm" +#include "code\datums\communications.dm" #include "code\datums\dash_weapon.dm" #include "code\datums\datum.dm" #include "code\datums\datumvars.dm" @@ -784,6 +788,7 @@ #include "code\datums\map_config.dm" #include "code\datums\minigames_menu.dm" #include "code\datums\mood.dm" +#include "code\datums\move_manager.dm" #include "code\datums\movement_detector.dm" #include "code\datums\mutable_appearance.dm" #include "code\datums\numbered_display.dm" @@ -894,6 +899,7 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\call_reinforcements.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\capricious_retaliate.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\climb_tree.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\express_happiness.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_food.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_paper_and_write.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_parent.dm" @@ -1090,6 +1096,7 @@ #include "code\datums\components\ground_sinking.dm" #include "code\datums\components\growth_and_differentiation.dm" #include "code\datums\components\gunpoint.dm" +#include "code\datums\components\happiness.dm" #include "code\datums\components\hazard_area.dm" #include "code\datums\components\healing_touch.dm" #include "code\datums\components\health_scaling_effects.dm" @@ -1120,6 +1127,7 @@ #include "code\datums\components\manual_breathing.dm" #include "code\datums\components\manual_heart.dm" #include "code\datums\components\marionette.dm" +#include "code\datums\components\martial_art_giver.dm" #include "code\datums\components\mind_linker.dm" #include "code\datums\components\mirv.dm" #include "code\datums\components\mob_chain.dm" @@ -1177,6 +1185,7 @@ #include "code\datums\components\simple_access.dm" #include "code\datums\components\simple_bodycam.dm" #include "code\datums\components\singularity.dm" +#include "code\datums\components\sisyphus_awarder.dm" #include "code\datums\components\sitcomlaughter.dm" #include "code\datums\components\sizzle.dm" #include "code\datums\components\slippery.dm" @@ -1360,6 +1369,7 @@ #include "code\datums\elements\atmos_requirements.dm" #include "code\datums\elements\atmos_sensitive.dm" #include "code\datums\elements\attack_equip.dm" +#include "code\datums\elements\attack_zone_randomiser.dm" #include "code\datums\elements\backblast.dm" #include "code\datums\elements\bane.dm" #include "code\datums\elements\basic_eating.dm" @@ -1385,6 +1395,7 @@ #include "code\datums\elements\connect_loc.dm" #include "code\datums\elements\consumable_mob.dm" #include "code\datums\elements\content_barfer.dm" +#include "code\datums\elements\corrupted_organ.dm" #include "code\datums\elements\crackable.dm" #include "code\datums\elements\crusher_loot.dm" #include "code\datums\elements\cuffsnapping.dm" @@ -1441,7 +1452,9 @@ #include "code\datums\elements\light_blocking.dm" #include "code\datums\elements\light_eaten.dm" #include "code\datums\elements\light_eater.dm" +#include "code\datums\elements\living_limb_initialiser.dm" #include "code\datums\elements\loomable.dm" +#include "code\datums\elements\lube_walking.dm" #include "code\datums\elements\mirage_border.dm" #include "code\datums\elements\mob_access.dm" #include "code\datums\elements\mob_grabber.dm" @@ -1460,7 +1473,9 @@ #include "code\datums\elements\pet_bonus.dm" #include "code\datums\elements\plant_backfire.dm" #include "code\datums\elements\point_of_interest.dm" +#include "code\datums\elements\poster_tearer.dm" #include "code\datums\elements\prevent_attacking_of_types.dm" +#include "code\datums\elements\proficient_miner.dm" #include "code\datums\elements\projectile_drop.dm" #include "code\datums\elements\projectile_shield.dm" #include "code\datums\elements\radiation_protected_clothing.dm" @@ -1475,7 +1490,6 @@ #include "code\datums\elements\simple_flying.dm" #include "code\datums\elements\skill_reward.dm" #include "code\datums\elements\skittish.dm" -#include "code\datums\elements\snail_crawl.dm" #include "code\datums\elements\soft_landing.dm" #include "code\datums\elements\spooky.dm" #include "code\datums\elements\squish.dm" @@ -1487,6 +1501,7 @@ #include "code\datums\elements\tenacious.dm" #include "code\datums\elements\tiny_mob_hunter.dm" #include "code\datums\elements\tool_flash.dm" +#include "code\datums\elements\tool_renaming.dm" #include "code\datums\elements\toy_talk.dm" #include "code\datums\elements\turf_transparency.dm" #include "code\datums\elements\undertile.dm" @@ -1501,6 +1516,7 @@ #include "code\datums\elements\wall_smasher.dm" #include "code\datums\elements\wall_tearer.dm" #include "code\datums\elements\wall_walker.dm" +#include "code\datums\elements\watery_tile.dm" #include "code\datums\elements\weapon_description.dm" #include "code\datums\elements\weather_listener.dm" #include "code\datums\elements\web_walker.dm" @@ -1638,6 +1654,7 @@ #include "code\datums\mutations\webbing.dm" #include "code\datums\proximity_monitor\field.dm" #include "code\datums\proximity_monitor\proximity_monitor.dm" +#include "code\datums\proximity_monitor\fields\ai_target_tracking.dm" #include "code\datums\proximity_monitor\fields\gravity.dm" #include "code\datums\proximity_monitor\fields\projectile_dampener.dm" #include "code\datums\proximity_monitor\fields\timestop.dm" @@ -1646,6 +1663,7 @@ #include "code\datums\quirks\negative_quirks\addict.dm" #include "code\datums\quirks\negative_quirks\all_nighter.dm" #include "code\datums\quirks\negative_quirks\allergic.dm" +#include "code\datums\quirks\negative_quirks\anosmia.dm" #include "code\datums\quirks\negative_quirks\bad_back.dm" #include "code\datums\quirks\negative_quirks\bad_touch.dm" #include "code\datums\quirks\negative_quirks\big_hands.dm" @@ -1727,6 +1745,7 @@ #include "code\datums\quirks\positive_quirks\skittish.dm" #include "code\datums\quirks\positive_quirks\spacer.dm" #include "code\datums\quirks\positive_quirks\spiritual.dm" +#include "code\datums\quirks\positive_quirks\strong_stomach.dm" #include "code\datums\quirks\positive_quirks\tagger.dm" #include "code\datums\quirks\positive_quirks\throwing_arm.dm" #include "code\datums\quirks\positive_quirks\voracious.dm" @@ -1759,9 +1778,9 @@ #include "code\datums\shuttles\starfury.dm" #include "code\datums\shuttles\whiteship.dm" #include "code\datums\skills\_skill.dm" +#include "code\datums\skills\athletics.dm" #include "code\datums\skills\cleaning.dm" #include "code\datums\skills\fishing.dm" -#include "code\datums\skills\fitness.dm" #include "code\datums\skills\gaming.dm" #include "code\datums\skills\mining.dm" #include "code\datums\station_traits\_station_trait.dm" @@ -1811,6 +1830,7 @@ #include "code\datums\status_effects\debuffs\hooked.dm" #include "code\datums\status_effects\debuffs\jitteriness.dm" #include "code\datums\status_effects\debuffs\pacifism.dm" +#include "code\datums\status_effects\debuffs\rust_corruption.dm" #include "code\datums\status_effects\debuffs\screen_blur.dm" #include "code\datums\status_effects\debuffs\screwy_hud.dm" #include "code\datums\status_effects\debuffs\silenced.dm" @@ -2035,7 +2055,10 @@ #include "code\game\machinery\computer\telescreen.dm" #include "code\game\machinery\computer\terminal.dm" #include "code\game\machinery\computer\warrant.dm" -#include "code\game\machinery\computer\arcade\arcade.dm" +#include "code\game\machinery\computer\arcade\_arcade.dm" +#include "code\game\machinery\computer\arcade\amputation.dm" +#include "code\game\machinery\computer\arcade\battle.dm" +#include "code\game\machinery\computer\arcade\battle_gear.dm" #include "code\game\machinery\computer\arcade\orion.dm" #include "code\game\machinery\computer\arcade\orion_event.dm" #include "code\game\machinery\computer\atmos_computers\__identifiers.dm" @@ -2066,6 +2089,7 @@ #include "code\game\machinery\computer\records\records.dm" #include "code\game\machinery\computer\records\security.dm" #include "code\game\machinery\dna_infuser\dna_infuser.dm" +#include "code\game\machinery\dna_infuser\dna_infusion.dm" #include "code\game\machinery\dna_infuser\infuser_book.dm" #include "code\game\machinery\dna_infuser\infuser_entry.dm" #include "code\game\machinery\dna_infuser\infuser_entries\infuser_tier_one_entries.dm" @@ -2118,6 +2142,7 @@ #include "code\game\objects\buckling.dm" #include "code\game\objects\empulse.dm" #include "code\game\objects\items.dm" +#include "code\game\objects\items_reskin.dm" #include "code\game\objects\obj_defense.dm" #include "code\game\objects\objs.dm" #include "code\game\objects\structures.dm" @@ -2344,6 +2369,7 @@ #include "code\game\objects\items\devices\aicard_evil.dm" #include "code\game\objects\items\devices\anomaly_neutralizer.dm" #include "code\game\objects\items\devices\anomaly_releaser.dm" +#include "code\game\objects\items\devices\battle_royale.dm" #include "code\game\objects\items\devices\beacon.dm" #include "code\game\objects\items\devices\chameleonproj.dm" #include "code\game\objects\items\devices\destabilizing_crystal.dm" @@ -2460,6 +2486,7 @@ #include "code\game\objects\items\grenades\syndieminibomb.dm" #include "code\game\objects\items\implants\implant.dm" #include "code\game\objects\items\implants\implant_abductor.dm" +#include "code\game\objects\items\implants\implant_battle_royale.dm" #include "code\game\objects\items\implants\implant_clown.dm" #include "code\game\objects\items\implants\implant_deathrattle.dm" #include "code\game\objects\items\implants\implant_explosive.dm" @@ -2690,6 +2717,7 @@ #include "code\game\objects\structures\gym\weight_machine_action.dm" #include "code\game\objects\structures\icemoon\cave_entrance.dm" #include "code\game\objects\structures\lavaland\geyser.dm" +#include "code\game\objects\structures\lavaland\gulag_vent.dm" #include "code\game\objects\structures\lavaland\necropolis_tendril.dm" #include "code\game\objects\structures\lavaland\ore_vent.dm" #include "code\game\objects\structures\plaques\_plaques.dm" @@ -2726,6 +2754,7 @@ #include "code\game\turfs\open\dirtystation.dm" #include "code\game\turfs\open\floor.dm" #include "code\game\turfs\open\grass.dm" +#include "code\game\turfs\open\hay.dm" #include "code\game\turfs\open\ice.dm" #include "code\game\turfs\open\lava.dm" #include "code\game\turfs\open\misc.dm" @@ -2762,7 +2791,6 @@ #include "code\modules\admin\admin_pda_message.dm" #include "code\modules\admin\admin_ranks.dm" #include "code\modules\admin\admin_verbs.dm" -#include "code\modules\admin\adminmenu.dm" #include "code\modules\admin\antag_panel.dm" #include "code\modules\admin\chat_commands.dm" #include "code\modules\admin\check_antagonists.dm" @@ -2773,7 +2801,6 @@ #include "code\modules\admin\fun_balloon.dm" #include "code\modules\admin\greyscale_modify_menu.dm" #include "code\modules\admin\holder2.dm" -#include "code\modules\admin\ipintel.dm" #include "code\modules\admin\IsBanned.dm" #include "code\modules\admin\known_alts.dm" #include "code\modules\admin\outfit_editor.dm" @@ -2822,6 +2849,8 @@ #include "code\modules\admin\smites\smite.dm" #include "code\modules\admin\smites\supply_pod.dm" #include "code\modules\admin\smites\supply_pod_quick.dm" +#include "code\modules\admin\verb_datums\_admin_verb_datum.dm" +#include "code\modules\admin\verb_datums\_admin_verb_holder.dm" #include "code\modules\admin\verbs\admin.dm" #include "code\modules\admin\verbs\admin_newscaster.dm" #include "code\modules\admin\verbs\adminevents.dm" @@ -2876,6 +2905,7 @@ #include "code\modules\admin\verbs\server.dm" #include "code\modules\admin\verbs\shuttlepanel.dm" #include "code\modules\admin\verbs\spawnobjasmob.dm" +#include "code\modules\admin\verbs\special_verbs.dm" #include "code\modules\admin\verbs\lua\_hooks.dm" #include "code\modules\admin\verbs\lua\_wrappers.dm" #include "code\modules\admin\verbs\lua\helpers.dm" @@ -2886,6 +2916,7 @@ #include "code\modules\admin\verbs\SDQL2\SDQL_2_wrappers.dm" #include "code\modules\admin\view_variables\admin_delete.dm" #include "code\modules\admin\view_variables\color_matrix_editor.dm" +#include "code\modules\admin\view_variables\debug_variable_appearance.dm" #include "code\modules\admin\view_variables\debug_variables.dm" #include "code\modules\admin\view_variables\filterrific.dm" #include "code\modules\admin\view_variables\get_variables.dm" @@ -3040,6 +3071,7 @@ #include "code\modules\antagonists\heretic\moon_lunatic.dm" #include "code\modules\antagonists\heretic\rust_effect.dm" #include "code\modules\antagonists\heretic\transmutation_rune.dm" +#include "code\modules\antagonists\heretic\items\corrupted_organs.dm" #include "code\modules\antagonists\heretic\items\eldritch_flask.dm" #include "code\modules\antagonists\heretic\items\eldritch_painting.dm" #include "code\modules\antagonists\heretic\items\forbidden_book.dm" @@ -3070,6 +3102,7 @@ #include "code\modules\antagonists\heretic\knowledge\starting_lore.dm" #include "code\modules\antagonists\heretic\knowledge\void_lore.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_buff.dm" +#include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_curse.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_knowledge.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_map.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_moodlets.dm" @@ -3145,10 +3178,12 @@ #include "code\modules\antagonists\nukeop\datums\operative_leader.dm" #include "code\modules\antagonists\nukeop\datums\operative_lone.dm" #include "code\modules\antagonists\nukeop\datums\operative_reinforcement.dm" +#include "code\modules\antagonists\nukeop\datums\operative_support.dm" #include "code\modules\antagonists\nukeop\datums\operative_team.dm" #include "code\modules\antagonists\nukeop\equipment\borgchameleon.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_authentication_disk.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_challenge.dm" +#include "code\modules\antagonists\nukeop\equipment\overwatch_tools.dm" #include "code\modules\antagonists\nukeop\equipment\pinpointer.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_bomb\_nuclear_bomb.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_bomb\beer_nuke.dm" @@ -3209,9 +3244,9 @@ #include "code\modules\antagonists\traitor\objectives\kill_pet.dm" #include "code\modules\antagonists\traitor\objectives\locate_weakpoint.dm" #include "code\modules\antagonists\traitor\objectives\sabotage_machinery.dm" -#include "code\modules\antagonists\traitor\objectives\sleeper_protocol.dm" #include "code\modules\antagonists\traitor\objectives\steal.dm" #include "code\modules\antagonists\traitor\objectives\abstract\target_player.dm" +#include "code\modules\antagonists\traitor\objectives\final_objective\battle_royale.dm" #include "code\modules\antagonists\traitor\objectives\final_objective\battlecruiser.dm" #include "code\modules\antagonists\traitor\objectives\final_objective\final_objective.dm" #include "code\modules\antagonists\traitor\objectives\final_objective\infect_ai.dm" @@ -3287,6 +3322,7 @@ #include "code\modules\asset_cache\assets\fontawesome.dm" #include "code\modules\asset_cache\assets\genetics.dm" #include "code\modules\asset_cache\assets\headers.dm" +#include "code\modules\asset_cache\assets\icon_ref_map.dm" #include "code\modules\asset_cache\assets\inventory.dm" #include "code\modules\asset_cache\assets\irv.dm" #include "code\modules\asset_cache\assets\jquery.dm" @@ -3431,16 +3467,19 @@ #include "code\modules\bitrunning\event.dm" #include "code\modules\bitrunning\job.dm" #include "code\modules\bitrunning\outfits.dm" +#include "code\modules\bitrunning\spawners.dm" #include "code\modules\bitrunning\turfs.dm" #include "code\modules\bitrunning\antagonists\_parent.dm" #include "code\modules\bitrunning\antagonists\cyber_police.dm" #include "code\modules\bitrunning\antagonists\cyber_tac.dm" +#include "code\modules\bitrunning\antagonists\ghost_role.dm" #include "code\modules\bitrunning\antagonists\netguardian.dm" #include "code\modules\bitrunning\components\avatar_connection.dm" #include "code\modules\bitrunning\components\bitrunning_points.dm" #include "code\modules\bitrunning\components\glitch.dm" #include "code\modules\bitrunning\components\netpod_healing.dm" #include "code\modules\bitrunning\components\npc_friendly.dm" +#include "code\modules\bitrunning\components\virtual_entity.dm" #include "code\modules\bitrunning\objects\byteforge.dm" #include "code\modules\bitrunning\objects\clothing.dm" #include "code\modules\bitrunning\objects\debug.dm" @@ -3608,6 +3647,7 @@ #include "code\modules\client\preferences_menu.dm" #include "code\modules\client\preferences_savefile.dm" #include "code\modules\client\preferences\_preference.dm" +#include "code\modules\client\preferences\addict.dm" #include "code\modules\client\preferences\admin.dm" #include "code\modules\client\preferences\age.dm" #include "code\modules\client\preferences\ai_core_display.dm" @@ -3631,7 +3671,6 @@ #include "code\modules\client\preferences\hotkeys.dm" #include "code\modules\client\preferences\item_outlines.dm" #include "code\modules\client\preferences\jobless_role.dm" -#include "code\modules\client\preferences\junkie.dm" #include "code\modules\client\preferences\language.dm" #include "code\modules\client\preferences\mod_select.dm" #include "code\modules\client\preferences\multiz_parallax.dm" @@ -3662,6 +3701,7 @@ #include "code\modules\client\preferences\statpanel.dm" #include "code\modules\client\preferences\tgui.dm" #include "code\modules\client\preferences\tooltips.dm" +#include "code\modules\client\preferences\trans_prosthetic.dm" #include "code\modules\client\preferences\ui_style.dm" #include "code\modules\client\preferences\underwear_color.dm" #include "code\modules\client\preferences\uplink_location.dm" @@ -3687,6 +3727,7 @@ #include "code\modules\client\preferences\species_features\ethereal.dm" #include "code\modules\client\preferences\species_features\felinid.dm" #include "code\modules\client\preferences\species_features\lizard.dm" +#include "code\modules\client\preferences\species_features\monkey.dm" #include "code\modules\client\preferences\species_features\moth.dm" #include "code\modules\client\preferences\species_features\mushperson.dm" #include "code\modules\client\preferences\species_features\mutants.dm" @@ -3695,6 +3736,7 @@ #include "code\modules\client\verbs\ooc.dm" #include "code\modules\client\verbs\ping.dm" #include "code\modules\client\verbs\suicide.dm" +#include "code\modules\client\verbs\typing.dm" #include "code\modules\client\verbs\who.dm" #include "code\modules\clothing\clothing.dm" #include "code\modules\clothing\belts\polymorph_belt.dm" @@ -4233,7 +4275,6 @@ #include "code\modules\jobs\job_types\shaft_miner.dm" #include "code\modules\jobs\job_types\station_engineer.dm" #include "code\modules\jobs\job_types\unassigned.dm" -#include "code\modules\jobs\job_types\virologist.dm" #include "code\modules\jobs\job_types\warden.dm" #include "code\modules\jobs\job_types\antagonists\abductor_agent.dm" #include "code\modules\jobs\job_types\antagonists\abductor_scientist.dm" @@ -4300,6 +4341,10 @@ #include "code\modules\keybindings\bindings_client.dm" #include "code\modules\keybindings\focus.dm" #include "code\modules\keybindings\setup.dm" +#include "code\modules\language\_language.dm" +#include "code\modules\language\_language_holder.dm" +#include "code\modules\language\_language_manuals.dm" +#include "code\modules\language\_language_menu.dm" #include "code\modules\language\aphasia.dm" #include "code\modules\language\beachbum.dm" #include "code\modules\language\buzzwords.dm" @@ -4308,10 +4353,6 @@ #include "code\modules\language\common.dm" #include "code\modules\language\draconic.dm" #include "code\modules\language\drone.dm" -#include "code\modules\language\language.dm" -#include "code\modules\language\language_holder.dm" -#include "code\modules\language\language_manuals.dm" -#include "code\modules\language\language_menu.dm" #include "code\modules\language\machine.dm" #include "code\modules\language\moffic.dm" #include "code\modules\language\monkey.dm" @@ -4337,12 +4378,13 @@ #include "code\modules\library\random_books.dm" #include "code\modules\library\skill_learning\skill_station.dm" #include "code\modules\library\skill_learning\skillchip.dm" +#include "code\modules\library\skill_learning\generic_skillchips\rod_suplex.dm" #include "code\modules\library\skill_learning\job_skillchips\_job.dm" #include "code\modules\library\skill_learning\job_skillchips\chef.dm" +#include "code\modules\library\skill_learning\job_skillchips\clown.dm" #include "code\modules\library\skill_learning\job_skillchips\janitor.dm" #include "code\modules\library\skill_learning\job_skillchips\miner.dm" #include "code\modules\library\skill_learning\job_skillchips\psychologist.dm" -#include "code\modules\library\skill_learning\job_skillchips\research_director.dm" #include "code\modules\library\skill_learning\job_skillchips\roboticist.dm" #include "code\modules\library\skill_learning\job_skillchips\station_engineer.dm" #include "code\modules\lighting\lighting_area.dm" @@ -4367,6 +4409,13 @@ #include "code\modules\logging\categories\log_category_silo.dm" #include "code\modules\logging\categories\log_category_target_zone_switch.dm" #include "code\modules\logging\categories\log_category_uplink.dm" +#include "code\modules\lootpanel\_lootpanel.dm" +#include "code\modules\lootpanel\contents.dm" +#include "code\modules\lootpanel\handlers.dm" +#include "code\modules\lootpanel\misc.dm" +#include "code\modules\lootpanel\search_object.dm" +#include "code\modules\lootpanel\ss_looting.dm" +#include "code\modules\lootpanel\ui.dm" #include "code\modules\mafia\_defines.dm" #include "code\modules\mafia\controller.dm" #include "code\modules\mafia\controller_ui.dm" @@ -4492,6 +4541,7 @@ #include "code\modules\mining\boulder_processing\brm.dm" #include "code\modules\mining\boulder_processing\refinery.dm" #include "code\modules\mining\equipment\explorer_gear.dm" +#include "code\modules\mining\equipment\grapple_gun.dm" #include "code\modules\mining\equipment\kheiral_cuffs.dm" #include "code\modules\mining\equipment\kinetic_crusher.dm" #include "code\modules\mining\equipment\lazarus_injector.dm" @@ -4501,6 +4551,7 @@ #include "code\modules\mining\equipment\miningradio.dm" #include "code\modules\mining\equipment\resonator.dm" #include "code\modules\mining\equipment\survival_pod.dm" +#include "code\modules\mining\equipment\vent_pointer.dm" #include "code\modules\mining\equipment\wormhole_jaunter.dm" #include "code\modules\mining\equipment\monster_organs\brimdust_sac.dm" #include "code\modules\mining\equipment\monster_organs\monster_organ.dm" @@ -4713,6 +4764,15 @@ #include "code\modules\mob\living\basic\lavaland\mook\mook_ai.dm" #include "code\modules\mob\living\basic\lavaland\mook\mook_village.dm" #include "code\modules\mob\living\basic\lavaland\node_drone\node_drone.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\_raptor.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\baby_raptor.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_behavior.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_controller.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_subtrees.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_dex.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_egg.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_food_trough.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_inheritance.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher_ai.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher_gaze.dm" @@ -4954,7 +5014,6 @@ #include "code\modules\mob\living\carbon\human\status_procs.dm" #include "code\modules\mob\living\carbon\human\suicides.dm" #include "code\modules\mob\living\carbon\human\species_types\abductors.dm" -#include "code\modules\mob\living\carbon\human\species_types\abominations.dm" #include "code\modules\mob\living\carbon\human\species_types\android.dm" #include "code\modules\mob\living\carbon\human\species_types\dullahan.dm" #include "code\modules\mob\living\carbon\human\species_types\ethereal.dm" @@ -5317,6 +5376,7 @@ #include "code\modules\projectiles\ammunition\_firing.dm" #include "code\modules\projectiles\ammunition\ballistic\foam.dm" #include "code\modules\projectiles\ammunition\ballistic\harpoon.dm" +#include "code\modules\projectiles\ammunition\ballistic\junk.dm" #include "code\modules\projectiles\ammunition\ballistic\lmg.dm" #include "code\modules\projectiles\ammunition\ballistic\pistol.dm" #include "code\modules\projectiles\ammunition\ballistic\revolver.dm" @@ -5400,6 +5460,7 @@ #include "code\modules\projectiles\projectile\bullets\dnainjector.dm" #include "code\modules\projectiles\projectile\bullets\foam_dart.dm" #include "code\modules\projectiles\projectile\bullets\grenade.dm" +#include "code\modules\projectiles\projectile\bullets\junk.dm" #include "code\modules\projectiles\projectile\bullets\lmg.dm" #include "code\modules\projectiles\projectile\bullets\pistol.dm" #include "code\modules\projectiles\projectile\bullets\revolver.dm" @@ -5768,6 +5829,7 @@ #include "code\modules\surgery\prosthetic_replacement.dm" #include "code\modules\surgery\repair_puncture.dm" #include "code\modules\surgery\revival.dm" +#include "code\modules\surgery\sleeper_protocol.dm" #include "code\modules\surgery\stomachpump.dm" #include "code\modules\surgery\surgery.dm" #include "code\modules\surgery\surgery_helpers.dm" @@ -6039,6 +6101,7 @@ #include "code\modules\wiremod\components\atom\direction.dm" #include "code\modules\wiremod\components\atom\gps.dm" #include "code\modules\wiremod\components\atom\health.dm" +#include "code\modules\wiremod\components\atom\health_state.dm" #include "code\modules\wiremod\components\atom\hear.dm" #include "code\modules\wiremod\components\atom\matscanner.dm" #include "code\modules\wiremod\components\atom\pinpointer.dm" @@ -6082,9 +6145,11 @@ #include "code\modules\wiremod\components\math\logic.dm" #include "code\modules\wiremod\components\math\not.dm" #include "code\modules\wiremod\components\math\random.dm" +#include "code\modules\wiremod\components\math\toggle.dm" #include "code\modules\wiremod\components\math\trigonometry.dm" #include "code\modules\wiremod\components\ntnet\ntnet_receive.dm" #include "code\modules\wiremod\components\ntnet\ntnet_send.dm" +#include "code\modules\wiremod\components\ntnet\ntnet_send_literal.dm" #include "code\modules\wiremod\components\sensors\pressuresensor.dm" #include "code\modules\wiremod\components\sensors\tempsensor.dm" #include "code\modules\wiremod\components\sensors\view_sensor.dm" diff --git a/tgui/.editorconfig b/tgui/.editorconfig new file mode 100644 index 0000000000000..d1d8a4176a416 --- /dev/null +++ b/tgui/.editorconfig @@ -0,0 +1,10 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/tgui/global.d.ts b/tgui/global.d.ts index 542788717ab64..9cb8e37c2e8c5 100644 --- a/tgui/global.d.ts +++ b/tgui/global.d.ts @@ -41,36 +41,6 @@ type ByondType = { */ windowId: string; - /** - * True if javascript is running in BYOND. - */ - IS_BYOND: boolean; - - /** - * Version of Trident engine of Internet Explorer. Null if N/A. - */ - TRIDENT: number | null; - - /** - * True if browser is IE8 or lower. - */ - IS_LTE_IE8: boolean; - - /** - * True if browser is IE9 or lower. - */ - IS_LTE_IE9: boolean; - - /** - * True if browser is IE10 or lower. - */ - IS_LTE_IE10: boolean; - - /** - * True if browser is IE11 or lower. - */ - IS_LTE_IE11: boolean; - /** * If `true`, unhandled errors and common mistakes result in a blue screen * of death, which stops this window from handling incoming messages and diff --git a/tgui/packages/common/collections.ts b/tgui/packages/common/collections.ts index 5bfcee8588441..9aed42557dc33 100644 --- a/tgui/packages/common/collections.ts +++ b/tgui/packages/common/collections.ts @@ -12,33 +12,36 @@ * If collection is 'null' or 'undefined', it will be returned "as is" * without emitting any errors (which can be useful in some cases). */ -export const filter = - (iterateeFn: (input: T, index: number, collection: T[]) => boolean) => - (collection: T[]): T[] => { - if (collection === null || collection === undefined) { - return collection; - } - if (Array.isArray(collection)) { - const result: T[] = []; - for (let i = 0; i < collection.length; i++) { - const item = collection[i]; - if (iterateeFn(item, i, collection)) { - result.push(item); - } +export const filter = ( + collection: T[], + iterateeFn: (input: T, index: number, collection: T[]) => boolean, +): T[] => { + if (collection === null || collection === undefined) { + return collection; + } + if (Array.isArray(collection)) { + const result: T[] = []; + for (let i = 0; i < collection.length; i++) { + const item = collection[i]; + if (iterateeFn(item, i, collection)) { + result.push(item); } - return result; } - throw new Error(`filter() can't iterate on type ${typeof collection}`); - }; + return result; + } + throw new Error(`filter() can't iterate on type ${typeof collection}`); +}; type MapFunction = { ( + collection: T[], iterateeFn: (value: T, index: number, collection: T[]) => U, - ): (collection: T[]) => U[]; + ): U[]; ( + collection: Record, iterateeFn: (value: T, index: K, collection: Record) => U, - ): (collection: Record) => U[]; + ): U[]; }; /** @@ -49,44 +52,30 @@ type MapFunction = { * If collection is 'null' or 'undefined', it will be returned "as is" * without emitting any errors (which can be useful in some cases). */ -export const map: MapFunction = - (iterateeFn) => - (collection: T[]): U[] => { - if (collection === null || collection === undefined) { - return collection; - } - - if (Array.isArray(collection)) { - return collection.map(iterateeFn); - } +export const map: MapFunction = (collection, iterateeFn) => { + if (collection === null || collection === undefined) { + return collection; + } - if (typeof collection === 'object') { - return Object.entries(collection).map(([key, value]) => { - return iterateeFn(value, key, collection); - }); + if (Array.isArray(collection)) { + const result: unknown[] = []; + for (let i = 0; i < collection.length; i++) { + result.push(iterateeFn(collection[i], i, collection)); } + return result; + } - throw new Error(`map() can't iterate on type ${typeof collection}`); - }; - -/** - * Given a collection, will run each element through an iteratee function. - * Will then filter out undefined values. - */ -export const filterMap = ( - collection: T[], - iterateeFn: (value: T) => U | undefined, -): U[] => { - const finalCollection: U[] = []; - - for (const value of collection) { - const output = iterateeFn(value); - if (output !== undefined) { - finalCollection.push(output); + if (typeof collection === 'object') { + const result: unknown[] = []; + for (let i in collection) { + if (Object.prototype.hasOwnProperty.call(collection, i)) { + result.push(iterateeFn(collection[i], i, collection)); + } } + return result; } - return finalCollection; + throw new Error(`map() can't iterate on type ${typeof collection}`); }; const COMPARATOR = (objA, objB) => { @@ -112,39 +101,38 @@ const COMPARATOR = (objA, objB) => { * * Iteratees are called with one argument (value). */ -export const sortBy = - (...iterateeFns: ((input: T) => unknown)[]) => - (array: T[]): T[] => { - if (!Array.isArray(array)) { - return array; - } - let length = array.length; - // Iterate over the array to collect criteria to sort it by - let mappedArray: { - criteria: unknown[]; - value: T; - }[] = []; - for (let i = 0; i < length; i++) { - const value = array[i]; - mappedArray.push({ - criteria: iterateeFns.map((fn) => fn(value)), - value, - }); - } - // Sort criteria using the base comparator - mappedArray.sort(COMPARATOR); - - // Unwrap values - const values: T[] = []; - while (length--) { - values[length] = mappedArray[length].value; - } - return values; - }; +export const sortBy = ( + array: T[], + ...iterateeFns: ((input: T) => unknown)[] +): T[] => { + if (!Array.isArray(array)) { + return array; + } + let length = array.length; + // Iterate over the array to collect criteria to sort it by + let mappedArray: { + criteria: unknown[]; + value: T; + }[] = []; + for (let i = 0; i < length; i++) { + const value = array[i]; + mappedArray.push({ + criteria: iterateeFns.map((fn) => fn(value)), + value, + }); + } + // Sort criteria using the base comparator + mappedArray.sort(COMPARATOR); -export const sort = sortBy(); + // Unwrap values + const values: T[] = []; + while (length--) { + values[length] = mappedArray[length].value; + } + return values; +}; -export const sortStrings = sortBy(); +export const sort = (array: T[]): T[] => sortBy(array); /** * Returns a range of numbers from start to end, exclusively. @@ -153,12 +141,34 @@ export const sortStrings = sortBy(); export const range = (start: number, end: number): number[] => new Array(end - start).fill(null).map((_, index) => index + start); +type ReduceFunction = { + ( + array: T[], + reducerFn: ( + accumulator: U, + currentValue: T, + currentIndex: number, + array: T[], + ) => U, + initialValue: U, + ): U; + ( + array: T[], + reducerFn: ( + accumulator: T, + currentValue: T, + currentIndex: number, + array: T[], + ) => T, + ): T; +}; + /** * A fast implementation of reduce. */ -export const reduce = (reducerFn, initialValue) => (array) => { +export const reduce: ReduceFunction = (array, reducerFn, initialValue?) => { const length = array.length; - let i; + let i: number; let result; if (initialValue === undefined) { i = 1; @@ -184,15 +194,16 @@ export const reduce = (reducerFn, initialValue) => (array) => { * is determined by the order they occur in the array. The iteratee is * invoked with one argument: value. */ -export const uniqBy = - (iterateeFn?: (value: T) => unknown) => - (array: T[]): T[] => { - const { length } = array; - const result: T[] = []; - const seen: unknown[] = iterateeFn ? [] : result; - let index = -1; - // prettier-ignore - outer: +export const uniqBy = ( + array: T[], + iterateeFn?: (value: T) => unknown, +): T[] => { + const { length } = array; + const result: T[] = []; + const seen: unknown[] = iterateeFn ? [] : result; + let index = -1; + // prettier-ignore + outer: while (++index < length) { let value: T | 0 = array[index]; const computed = iterateeFn ? iterateeFn(value) : value; @@ -214,10 +225,10 @@ export const uniqBy = result.push(value); } } - return result; - }; + return result; +}; -export const uniq = uniqBy(); +export const uniq = (array: T[]): T[] => uniqBy(array); type Zip = { [I in keyof T]: T[I] extends (infer U)[] ? U : never; @@ -247,17 +258,6 @@ export const zip = (...arrays: T): Zip => { return result; }; -/** - * This method is like "zip" except that it accepts iteratee to - * specify how grouped values should be combined. The iteratee is - * invoked with the elements of each group. - */ -export const zipWith = - (iterateeFn: (...values: T[]) => U) => - (...arrays: T[][]): U[] => { - return map((values: T[]) => iterateeFn(...values))(zip(...arrays)); - }; - const binarySearch = ( getKey: (value: T) => U, collection: readonly T[], @@ -293,13 +293,15 @@ const binarySearch = ( return compare > insertingKey ? middle : middle + 1; }; -export const binaryInsertWith = - (getKey: (value: T) => U) => - (collection: readonly T[], value: T) => { - const copy = [...collection]; - copy.splice(binarySearch(getKey, collection, value), 0, value); - return copy; - }; +export const binaryInsertWith = ( + collection: readonly T[], + value: T, + getKey: (value: T) => U, +): T[] => { + const copy = [...collection]; + copy.splice(binarySearch(getKey, collection, value), 0, value); + return copy; +}; /** * This method takes a collection of items and a number, returning a collection @@ -325,7 +327,8 @@ export const paginate = (collection: T[], maxPerPage: number): T[][] => { return pages; }; -const isObject = (obj: unknown) => typeof obj === 'object' && obj !== null; +const isObject = (obj: unknown): obj is object => + typeof obj === 'object' && obj !== null; // Does a deep merge of two objects. DO NOT FEED CIRCULAR OBJECTS!! export const deepMerge = (...objects: any[]): any => { diff --git a/tgui/packages/common/color.js b/tgui/packages/common/color.js deleted file mode 100644 index 59935931d82bf..0000000000000 --- a/tgui/packages/common/color.js +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -const EPSILON = 0.0001; - -export class Color { - constructor(r = 0, g = 0, b = 0, a = 1) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - - toString() { - // Alpha component needs to permit fractional values, so cannot use | - let alpha = parseFloat(this.a); - if (isNaN(alpha)) { - alpha = 1; - } - return `rgba(${this.r | 0}, ${this.g | 0}, ${this.b | 0}, ${alpha})`; - } - - // Darkens a color by a given percent. Returns a color, which can have toString called to get it's rgba() css value. - darken(percent) { - percent /= 100; - return new Color( - this.r - this.r * percent, - this.g - this.g * percent, - this.b - this.b * percent, - this.a, - ); - } - - // Brightens a color by a given percent. Returns a color, which can have toString called to get it's rgba() css value. - lighten(percent) { - // No point in rewriting code we already have. - return this.darken(-percent); - } -} - -/** - * Creates a color from the CSS hex color notation. - */ -Color.fromHex = (hex) => - new Color( - parseInt(hex.substr(1, 2), 16), - parseInt(hex.substr(3, 2), 16), - parseInt(hex.substr(5, 2), 16), - ); - -/** - * Linear interpolation of two colors. - */ -Color.lerp = (c1, c2, n) => - new Color( - (c2.r - c1.r) * n + c1.r, - (c2.g - c1.g) * n + c1.g, - (c2.b - c1.b) * n + c1.b, - (c2.a - c1.a) * n + c1.a, - ); - -/** - * Loops up the color in the provided list of colors - * with linear interpolation. - */ -Color.lookup = (value, colors = []) => { - const len = colors.length; - if (len < 2) { - throw new Error('Needs at least two colors!'); - } - const scaled = value * (len - 1); - if (value < EPSILON) { - return colors[0]; - } - if (value >= 1 - EPSILON) { - return colors[len - 1]; - } - const ratio = scaled % 1; - const index = scaled | 0; - return Color.lerp(colors[index], colors[index + 1], ratio); -}; diff --git a/tgui/packages/common/color.test.ts b/tgui/packages/common/color.test.ts new file mode 100644 index 0000000000000..93d90f05a23a7 --- /dev/null +++ b/tgui/packages/common/color.test.ts @@ -0,0 +1,49 @@ +import { Color } from './color'; + +describe('Color', () => { + it('should create a color with default values', () => { + const color = new Color(); + expect(color.r).toBe(0); + expect(color.g).toBe(0); + expect(color.b).toBe(0); + expect(color.a).toBe(1); + }); + + it('should create a color from hex', () => { + const color = Color.fromHex('#ff0000'); + expect(color.r).toBe(255); + expect(color.g).toBe(0); + expect(color.b).toBe(0); + }); + + it('should darken a color', () => { + const color = new Color(100, 100, 100).darken(50); + expect(color.r).toBe(50); + expect(color.g).toBe(50); + expect(color.b).toBe(50); + }); + + it('should lighten a color', () => { + const color = new Color(100, 100, 100).lighten(50); + expect(color.r).toBe(150); + expect(color.g).toBe(150); + expect(color.b).toBe(150); + }); + + it('should interpolate between two colors', () => { + const color1 = new Color(0, 0, 0); + const color2 = new Color(100, 100, 100); + const color = Color.lerp(color1, color2, 0.5); + expect(color.r).toBe(50); + expect(color.g).toBe(50); + expect(color.b).toBe(50); + }); + + it('should lookup a color in an array', () => { + const colors = [new Color(0, 0, 0), new Color(100, 100, 100)]; + const color = Color.lookup(0.5, colors); + expect(color.r).toBe(50); + expect(color.g).toBe(50); + expect(color.b).toBe(50); + }); +}); diff --git a/tgui/packages/common/color.ts b/tgui/packages/common/color.ts new file mode 100644 index 0000000000000..943b52a71fae9 --- /dev/null +++ b/tgui/packages/common/color.ts @@ -0,0 +1,94 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +const EPSILON = 0.0001; + +export class Color { + r: number; + g: number; + b: number; + a: number; + + constructor(r = 0, g = 0, b = 0, a = 1) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + toString(): string { + // Alpha component needs to permit fractional values, so cannot use | + let alpha = this.a; + if (typeof alpha === 'string') { + alpha = parseFloat(this.a as any); + } + if (isNaN(alpha)) { + alpha = 1; + } + return `rgba(${this.r | 0}, ${this.g | 0}, ${this.b | 0}, ${alpha})`; + } + + /** Darkens a color by a given percent. Returns a color, which can have toString called to get it's rgba() css value. */ + darken(percent: number): Color { + percent /= 100; + return new Color( + this.r - this.r * percent, + this.g - this.g * percent, + this.b - this.b * percent, + this.a, + ); + } + + /** Brightens a color by a given percent. Returns a color, which can have toString called to get it's rgba() css value. */ + lighten(percent: number): Color { + // No point in rewriting code we already have. + return this.darken(-percent); + } + + /** + * Creates a color from the CSS hex color notation. + */ + static fromHex(hex: string): Color { + return new Color( + parseInt(hex.slice(1, 3), 16), + parseInt(hex.slice(3, 5), 16), + parseInt(hex.slice(5, 7), 16), + ); + } + + /** + * Linear interpolation of two colors. + */ + static lerp(c1: Color, c2: Color, n: number): Color { + return new Color( + (c2.r - c1.r) * n + c1.r, + (c2.g - c1.g) * n + c1.g, + (c2.b - c1.b) * n + c1.b, + (c2.a - c1.a) * n + c1.a, + ); + } + + /** + * Loops up the color in the provided list of colors + * with linear interpolation. + */ + static lookup(value: number, colors: Color[]): Color { + const len = colors.length; + if (len < 2) { + throw new Error('Needs at least two colors!'); + } + const scaled = value * (len - 1); + if (value < EPSILON) { + return colors[0]; + } + if (value >= 1 - EPSILON) { + return colors[len - 1]; + } + const ratio = scaled % 1; + const index = scaled | 0; + return this.lerp(colors[index], colors[index + 1], ratio); + } +} diff --git a/tgui/packages/common/events.test.ts b/tgui/packages/common/events.test.ts new file mode 100644 index 0000000000000..b83ba467fd5fd --- /dev/null +++ b/tgui/packages/common/events.test.ts @@ -0,0 +1,34 @@ +import { EventEmitter } from './events'; + +describe('EventEmitter', () => { + it('should add and trigger an event listener', () => { + const emitter = new EventEmitter(); + const mockListener = jest.fn(); + emitter.on('test', mockListener); + emitter.emit('test', 'payload'); + expect(mockListener).toHaveBeenCalledWith('payload'); + }); + + it('should remove an event listener', () => { + const emitter = new EventEmitter(); + const mockListener = jest.fn(); + emitter.on('test', mockListener); + emitter.off('test', mockListener); + emitter.emit('test', 'payload'); + expect(mockListener).not.toHaveBeenCalled(); + }); + + it('should not fail when emitting an event with no listeners', () => { + const emitter = new EventEmitter(); + expect(() => emitter.emit('test', 'payload')).not.toThrow(); + }); + + it('should clear all event listeners', () => { + const emitter = new EventEmitter(); + const mockListener = jest.fn(); + emitter.on('test', mockListener); + emitter.clear(); + emitter.emit('test', 'payload'); + expect(mockListener).not.toHaveBeenCalled(); + }); +}); diff --git a/tgui/packages/common/events.js b/tgui/packages/common/events.ts similarity index 76% rename from tgui/packages/common/events.js rename to tgui/packages/common/events.ts index 7eeff511aa566..49223b29fb394 100644 --- a/tgui/packages/common/events.js +++ b/tgui/packages/common/events.ts @@ -4,17 +4,21 @@ * @license MIT */ +type Fn = (...args: any[]) => void; + export class EventEmitter { + private listeners: Record; + constructor() { this.listeners = {}; } - on(name, listener) { + on(name: string, listener: Fn): void { this.listeners[name] = this.listeners[name] || []; this.listeners[name].push(listener); } - off(name, listener) { + off(name: string, listener: Fn): void { const listeners = this.listeners[name]; if (!listeners) { throw new Error(`There is no listeners for "${name}"`); @@ -24,7 +28,7 @@ export class EventEmitter { }); } - emit(name, ...params) { + emit(name: string, ...params: any[]): void { const listeners = this.listeners[name]; if (!listeners) { return; @@ -35,7 +39,7 @@ export class EventEmitter { } } - clear() { + clear(): void { this.listeners = {}; } } diff --git a/tgui/packages/common/fp.js b/tgui/packages/common/fp.js deleted file mode 100644 index ba7df09d40701..0000000000000 --- a/tgui/packages/common/fp.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -/** - * Creates a function that returns the result of invoking the given - * functions, where each successive invocation is supplied the return - * value of the previous. - */ -// prettier-ignore -export const flow = (...funcs) => (input, ...rest) => { - let output = input; - for (let func of funcs) { - // Recurse into the array of functions - if (Array.isArray(func)) { - output = flow(...func)(output, ...rest); - } - else if (func) { - output = func(output, ...rest); - } - } - return output; -}; - -/** - * Composes single-argument functions from right to left. - * - * All functions might accept a context in form of additional arguments. - * If the resulting function is called with more than 1 argument, rest of - * the arguments are passed to all functions unchanged. - * - * @param {...Function} funcs The functions to compose - * @returns {Function} A function obtained by composing the argument functions - * from right to left. For example, compose(f, g, h) is identical to doing - * (input, ...rest) => f(g(h(input, ...rest), ...rest), ...rest) - */ -export const compose = (...funcs) => { - if (funcs.length === 0) { - return (arg) => arg; - } - if (funcs.length === 1) { - return funcs[0]; - } - // prettier-ignore - return funcs.reduce((a, b) => (value, ...rest) => - a(b(value, ...rest), ...rest)); -}; diff --git a/tgui/packages/common/fp.test.ts b/tgui/packages/common/fp.test.ts new file mode 100644 index 0000000000000..308a98d0f1227 --- /dev/null +++ b/tgui/packages/common/fp.test.ts @@ -0,0 +1,23 @@ +import { flow } from './fp'; + +describe('flow', () => { + it('composes multiple functions into one', () => { + const add2 = (x) => x + 2; + const multiplyBy3 = (x) => x * 3; + const subtract5 = (x) => x - 5; + + const composedFunction = flow(add2, multiplyBy3, subtract5); + + expect(composedFunction(4)).toBe(13); // ((4 + 2) * 3) - 5 = 13 + }); + + it('handles arrays of functions', () => { + const add2 = (x) => x + 2; + const multiplyBy3 = (x) => x * 3; + const subtract5 = (x) => x - 5; + + const composedFunction = flow([add2, multiplyBy3], subtract5); + + expect(composedFunction(4)).toBe(13); // ((4 + 2) * 3) - 5 = 13 + }); +}); diff --git a/tgui/packages/common/fp.ts b/tgui/packages/common/fp.ts new file mode 100644 index 0000000000000..62883a693a24a --- /dev/null +++ b/tgui/packages/common/fp.ts @@ -0,0 +1,38 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +type Func = (...args: any[]) => any; + +/** + * Creates a function that returns the result of invoking the given + * functions, where each successive invocation is supplied the return + * value of the previous. + * + * @example + * ```tsx + * const add2 = (x) => x + 2; + * const multiplyBy3 = (x) => x * 3; + * const subtract5 = (x) => x - 5; + * + * const composedFunction = flow(add2, multiplyBy3, subtract5); // ((4 + 2) * 3) - 5 = 13 + * const composedFunction2 = flow([add2, multiplyBy3], subtract5); // ((4 + 2) * 3) - 5 = 13 + * + */ +export const flow = + (...funcs: Array) => + (input: any, ...rest: any[]): any => { + let output = input; + + for (let func of funcs) { + // Recurse into the array of functions + if (Array.isArray(func)) { + output = flow(...func)(output, ...rest); + } else if (func) { + output = func(output, ...rest); + } + } + return output; + }; diff --git a/tgui/packages/common/perf.js b/tgui/packages/common/perf.ts similarity index 50% rename from tgui/packages/common/perf.js rename to tgui/packages/common/perf.ts index 591aa3537dee6..9266d88a896a1 100644 --- a/tgui/packages/common/perf.js +++ b/tgui/packages/common/perf.ts @@ -14,46 +14,57 @@ const FRAME_DURATION = 1000 / FPS; // True if Performance API is supported const supportsPerf = !!window.performance?.now; // High precision markers -let hpMarkersByName = {}; +let hpMarkersByName: Record = {}; // Low precision markers -let lpMarkersByName = {}; +let lpMarkersByName: Record = {}; /** * Marks a certain spot in the code for later measurements. */ -const mark = (name, timestamp) => { +function mark(name: string, timestamp?: number): void { if (process.env.NODE_ENV !== 'production') { if (supportsPerf && !timestamp) { hpMarkersByName[name] = performance.now(); } lpMarkersByName[name] = timestamp || Date.now(); } -}; +} /** * Calculates and returns the difference between two markers as a string. * * Use logger.log() to print the measurement. */ -const measure = (markerNameA, markerNameB) => { - if (process.env.NODE_ENV !== 'production') { - let markerA = hpMarkersByName[markerNameA]; - let markerB = hpMarkersByName[markerNameB]; - if (!markerA || !markerB) { - markerA = lpMarkersByName[markerNameA]; - markerB = lpMarkersByName[markerNameB]; - } - const duration = Math.abs(markerB - markerA); - return formatDuration(duration); +function measure(markerNameA: string, markerNameB: string): string | undefined { + if (process.env.NODE_ENV === 'production') return; + + let markerA = hpMarkersByName[markerNameA]; + let markerB = hpMarkersByName[markerNameB]; + + if (!markerA || !markerB) { + markerA = lpMarkersByName[markerNameA]; + markerB = lpMarkersByName[markerNameB]; } -}; -const formatDuration = (duration) => { + const duration = Math.abs(markerB - markerA); + + return formatDuration(duration); +} + +/** + * Formats a duration in milliseconds and frames. + */ +function formatDuration(duration: number): string { const durationInFrames = duration / FRAME_DURATION; - // prettier-ignore - return duration.toFixed(duration < 10 ? 1 : 0) + 'ms ' - + '(' + durationInFrames.toFixed(2) + ' frames)'; -}; + + return ( + duration.toFixed(duration < 10 ? 1 : 0) + + 'ms ' + + '(' + + durationInFrames.toFixed(2) + + ' frames)' + ); +} export const perf = { mark, diff --git a/tgui/packages/common/string.babel-plugin.cjs b/tgui/packages/common/string.babel-plugin.cjs deleted file mode 100644 index 97ca67c6ea4ca..0000000000000 --- a/tgui/packages/common/string.babel-plugin.cjs +++ /dev/null @@ -1,73 +0,0 @@ -/** - * This plugin saves overall about 10KB on the final bundle size, so it's - * sort of worth it. - * - * We are using a .cjs extension because: - * - * 1. Webpack CLI only supports CommonJS modules; - * 2. tgui-dev-server supports both, but we still need to signal NodeJS - * to import it as a CommonJS module, hence .cjs extension. - * - * We need to copy-paste the whole "multiline" function because we can't - * synchronously import an ES module from a CommonJS module. - * - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -/** - * Removes excess whitespace and indentation from the string. - */ -const multiline = (str) => { - const lines = str.split('\n'); - // Determine base indentation - let minIndent; - for (let line of lines) { - for (let indent = 0; indent < line.length; indent++) { - const char = line[indent]; - if (char !== ' ') { - if (minIndent === undefined || indent < minIndent) { - minIndent = indent; - } - break; - } - } - } - if (!minIndent) { - minIndent = 0; - } - // Remove this base indentation and trim the resulting string - // from both ends. - return lines - .map((line) => line.substr(minIndent).trimRight()) - .join('\n') - .trim(); -}; - -const StringPlugin = (ref) => { - return { - visitor: { - TaggedTemplateExpression: (path) => { - if (path.node.tag.name === 'multiline') { - const { quasi } = path.node; - if (quasi.expressions.length > 0) { - throw new Error('Multiline tag does not support expressions!'); - } - if (quasi.quasis.length > 1) { - throw new Error('Quasis is longer than 1'); - } - const { value } = quasi.quasis[0]; - value.raw = multiline(value.raw); - value.cooked = multiline(value.cooked); - path.replaceWith(quasi); - } - }, - }, - }; -}; - -module.exports = { - __esModule: true, - default: StringPlugin, -}; diff --git a/tgui/packages/common/string.js b/tgui/packages/common/string.js deleted file mode 100644 index 5906d83cb84f7..0000000000000 --- a/tgui/packages/common/string.js +++ /dev/null @@ -1,196 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -/** - * Removes excess whitespace and indentation from the string. - */ -export const multiline = (str) => { - if (Array.isArray(str)) { - // Small stub to allow usage as a template tag - return multiline(str.join('')); - } - const lines = str.split('\n'); - // Determine base indentation - let minIndent; - for (let line of lines) { - for (let indent = 0; indent < line.length; indent++) { - const char = line[indent]; - if (char !== ' ') { - if (minIndent === undefined || indent < minIndent) { - minIndent = indent; - } - break; - } - } - } - if (!minIndent) { - minIndent = 0; - } - // Remove this base indentation and trim the resulting string - // from both ends. - return lines - .map((line) => line.substr(minIndent).trimRight()) - .join('\n') - .trim(); -}; - -/** - * Creates a glob pattern matcher. - * - * Matches strings with wildcards. - * - * Example: createGlobPattern('*@domain')('user@domain') === true - */ -export const createGlobPattern = (pattern) => { - const escapeString = (str) => str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); - // prettier-ignore - const regex = new RegExp('^' - + pattern.split(/\*+/).map(escapeString).join('.*') - + '$'); - return (str) => regex.test(str); -}; - -/** - * Creates a search terms matcher. - * - * Returns true if given string matches the search text. - * - * @template T - * @param {string} searchText - * @param {(obj: T) => string} stringifier - * @returns {(obj: T) => boolean} - */ -export const createSearch = (searchText, stringifier) => { - const preparedSearchText = searchText.toLowerCase().trim(); - return (obj) => { - if (!preparedSearchText) { - return true; - } - const str = stringifier ? stringifier(obj) : obj; - if (!str) { - return false; - } - return str.toLowerCase().includes(preparedSearchText); - }; -}; - -/** - * Capitalizes a word and lowercases the rest. - * @param {string} str - * @returns {string} capitalized string - * - * @example capitalize('heLLo') === 'Hello' - */ -export const capitalize = (str) => { - // Handle array - if (Array.isArray(str)) { - return str.map(capitalize); - } - // Handle string - return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); -}; - -/** - * Similar to capitalize, this takes a string and replaces all first letters - * of any words. - * - * @param {string} str - * @return {string} The string with the first letters capitalized. - * - * @example capitalizeAll('heLLo woRLd') === 'HeLLo WoRLd' - */ -export const capitalizeAll = (str) => { - return str.replace(/(^\w{1})|(\s+\w{1})/g, (letter) => letter.toUpperCase()); -}; - -/** - * Capitalizes only the first letter of the str. - * - * @param {string} str - * @return {string} capitalized string - * - * @example capitalizeFirst('heLLo woRLd') === 'HeLLo woRLd' - */ -export const capitalizeFirst = (str) => { - return str.replace(/^\w/, (letter) => letter.toUpperCase()); -}; - -export const toTitleCase = (str) => { - // Handle array - if (Array.isArray(str)) { - return str.map(toTitleCase); - } - // Pass non-string - if (typeof str !== 'string') { - return str; - } - // Handle string - const WORDS_UPPER = ['Id', 'Tv']; - // prettier-ignore - const WORDS_LOWER = [ - 'A', 'An', 'And', 'As', 'At', 'But', 'By', 'For', 'For', 'From', 'In', - 'Into', 'Near', 'Nor', 'Of', 'On', 'Onto', 'Or', 'The', 'To', 'With', - ]; - let currentStr = str.replace(/([^\W_]+[^\s-]*) */g, (str) => { - return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase(); - }); - for (let word of WORDS_LOWER) { - const regex = new RegExp('\\s' + word + '\\s', 'g'); - currentStr = currentStr.replace(regex, (str) => str.toLowerCase()); - } - for (let word of WORDS_UPPER) { - const regex = new RegExp('\\b' + word + '\\b', 'g'); - currentStr = currentStr.replace(regex, (str) => str.toLowerCase()); - } - return currentStr; -}; - -/** - * Decodes HTML entities, and removes unnecessary HTML tags. - * - * @param {String} str Encoded HTML string - * @return {String} Decoded HTML string - */ -export const decodeHtmlEntities = (str) => { - if (!str) { - return str; - } - const translate_re = /&(nbsp|amp|quot|lt|gt|apos);/g; - const translate = { - nbsp: ' ', - amp: '&', - quot: '"', - lt: '<', - gt: '>', - apos: "'", - }; - // prettier-ignore - return str - // Newline tags - .replace(/
    /gi, '\n') - .replace(/<\/?[a-z0-9-_]+[^>]*>/gi, '') - // Basic entities - .replace(translate_re, (match, entity) => translate[entity]) - // Decimal entities - .replace(/&#?([0-9]+);/gi, (match, numStr) => { - const num = parseInt(numStr, 10); - return String.fromCharCode(num); - }) - // Hex entities - .replace(/&#x?([0-9a-f]+);/gi, (match, numStr) => { - const num = parseInt(numStr, 16); - return String.fromCharCode(num); - }); -}; - -/** - * Converts an object into a query string, - */ -// prettier-ignore -export const buildQueryString = obj => Object.keys(obj) - .map(key => encodeURIComponent(key) - + '=' + encodeURIComponent(obj[key])) - .join('&'); diff --git a/tgui/packages/common/string.test.ts b/tgui/packages/common/string.test.ts new file mode 100644 index 0000000000000..06b24da801361 --- /dev/null +++ b/tgui/packages/common/string.test.ts @@ -0,0 +1,35 @@ +import { createSearch, decodeHtmlEntities, toTitleCase } from './string'; + +describe('createSearch', () => { + it('matches search terms correctly', () => { + const search = createSearch('test', (obj: { value: string }) => obj.value); + + const obj1 = { value: 'This is a test string.' }; + const obj2 = { value: 'This is a different string.' }; + const obj3 = { value: 'This is a test string.' }; + + const objects = [obj1, obj2, obj3]; + + expect(objects.filter(search)).toEqual([obj1, obj3]); + }); +}); + +describe('toTitleCase', () => { + it('converts strings to title case correctly', () => { + expect(toTitleCase('hello world')).toBe('Hello World'); + expect(toTitleCase('HELLO WORLD')).toBe('Hello World'); + expect(toTitleCase('HeLLo wORLd')).toBe('Hello World'); + expect(toTitleCase('a tale of two cities')).toBe('A Tale of Two Cities'); + expect(toTitleCase('war and peace')).toBe('War and Peace'); + }); +}); + +describe('decodeHtmlEntities', () => { + it('decodes HTML entities and removes unnecessary HTML tags correctly', () => { + expect(decodeHtmlEntities('
    ')).toBe('\n'); + expect(decodeHtmlEntities('

    Hello World

    ')).toBe('Hello World'); + expect(decodeHtmlEntities('&')).toBe('&'); + expect(decodeHtmlEntities('&')).toBe('&'); + expect(decodeHtmlEntities('&')).toBe('&'); + }); +}); diff --git a/tgui/packages/common/string.ts b/tgui/packages/common/string.ts new file mode 100644 index 0000000000000..d6f328750c42b --- /dev/null +++ b/tgui/packages/common/string.ts @@ -0,0 +1,173 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +/** + * Creates a search terms matcher. Returns true if given string matches the search text. + * + * @example + * ```tsx + * type Thing = { id: string; name: string }; + * + * const objects = [ + * { id: '123', name: 'Test' }, + * { id: '456', name: 'Test' }, + * ]; + * + * const search = createSearch('123', (obj: Thing) => obj.id); + * + * objects.filter(search); // returns [{ id: '123', name: 'Test' }] + * ``` + */ +export function createSearch( + searchText: string, + stringifier = (obj: TObj) => JSON.stringify(obj), +): (obj: TObj) => boolean { + const preparedSearchText = searchText.toLowerCase().trim(); + + return (obj) => { + if (!preparedSearchText) { + return true; + } + const str = stringifier(obj); + if (!str) { + return false; + } + return str.toLowerCase().includes(preparedSearchText); + }; +} + +/** + * Capitalizes a word and lowercases the rest. + * + * @example + * ```tsx + * capitalize('heLLo') // Hello + * ``` + */ +export function capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); +} + +/** + * Similar to capitalize, this takes a string and replaces all first letters + * of any words. + * + * @example + * ```tsx + * capitalizeAll('heLLo woRLd') // 'HeLLo WoRLd' + * ``` + */ +export function capitalizeAll(str: string): string { + return str.replace(/(^\w{1})|(\s+\w{1})/g, (letter) => letter.toUpperCase()); +} + +/** + * Capitalizes only the first letter of the str, leaving others untouched. + * + * @example + * ```tsx + * capitalizeFirst('heLLo woRLd') // 'HeLLo woRLd' + * ``` + */ +export function capitalizeFirst(str: string): string { + return str.replace(/^\w/, (letter) => letter.toUpperCase()); +} + +const WORDS_UPPER = ['Id', 'Tv'] as const; + +const WORDS_LOWER = [ + 'A', + 'An', + 'And', + 'As', + 'At', + 'But', + 'By', + 'For', + 'For', + 'From', + 'In', + 'Into', + 'Near', + 'Nor', + 'Of', + 'On', + 'Onto', + 'Or', + 'The', + 'To', + 'With', +] as const; + +/** + * Converts a string to title case. + * + * @example + * ```tsx + * toTitleCase('a tale of two cities') // 'A Tale of Two Cities' + * ``` + */ +export function toTitleCase(str: string): string { + if (!str) return str; + + let currentStr = str.replace(/([^\W_]+[^\s-]*) */g, (str) => { + return capitalize(str); + }); + + for (let word of WORDS_LOWER) { + const regex = new RegExp('\\s' + word + '\\s', 'g'); + currentStr = currentStr.replace(regex, (str) => str.toLowerCase()); + } + + for (let word of WORDS_UPPER) { + const regex = new RegExp('\\b' + word + '\\b', 'g'); + currentStr = currentStr.replace(regex, (str) => str.toLowerCase()); + } + + return currentStr; +} + +const TRANSLATE_REGEX = /&(nbsp|amp|quot|lt|gt|apos);/g; +const TRANSLATIONS = { + amp: '&', + apos: "'", + gt: '>', + lt: '<', + nbsp: ' ', + quot: '"', +} as const; + +/** + * Decodes HTML entities and removes unnecessary HTML tags. + * + * @example + * ```tsx + * decodeHtmlEntities('&') // returns '&' + * decodeHtmlEntities('<') // returns '<' + * ``` + */ +export function decodeHtmlEntities(str: string): string { + if (!str) return str; + + return ( + str + // Newline tags + .replace(/
    /gi, '\n') + .replace(/<\/?[a-z0-9-_]+[^>]*>/gi, '') + // Basic entities + .replace(TRANSLATE_REGEX, (match, entity) => TRANSLATIONS[entity]) + // Decimal entities + .replace(/&#?([0-9]+);/gi, (match, numStr) => { + const num = parseInt(numStr, 10); + return String.fromCharCode(num); + }) + // Hex entities + .replace(/&#x?([0-9a-f]+);/gi, (match, numStr) => { + const num = parseInt(numStr, 16); + return String.fromCharCode(num); + }) + ); +} diff --git a/tgui/packages/common/type-utils.ts b/tgui/packages/common/type-utils.ts new file mode 100644 index 0000000000000..a73c0c1d59567 --- /dev/null +++ b/tgui/packages/common/type-utils.ts @@ -0,0 +1,41 @@ +/** + * Helps visualize highly complex ui data on the fly. + * @example + * ```tsx + * const { data } = useBackend(); + * logger.log(getShallowTypes(data)); + * ``` + */ +export function getShallowTypes( + data: Record, +): Record { + const output = {}; + + for (const key in data) { + if (Array.isArray(data[key])) { + const arr: any[] = data[key]; + + // Return the first array item if it exists + if (data[key].length > 0) { + output[key] = arr[0]; + continue; + } + + output[key] = 'emptyarray'; + } else if (typeof data[key] === 'object' && data[key] !== null) { + // Please inspect it further and make a new type for it + output[key] = 'object (inspect) || Record'; + } else if (typeof data[key] === 'number') { + const num = Number(data[key]); + + // 0 and 1 could be booleans from byond + if (num === 1 || num === 0) { + output[key] = `${num}, BooleanLike?`; + continue; + } + output[key] = data[key]; + } + } + + return output; +} diff --git a/tgui/packages/common/uuid.test.ts b/tgui/packages/common/uuid.test.ts new file mode 100644 index 0000000000000..e3af57c472675 --- /dev/null +++ b/tgui/packages/common/uuid.test.ts @@ -0,0 +1,11 @@ +import { createUuid } from './uuid'; + +describe('createUuid', () => { + it('generates a UUID v4 string', () => { + const uuid = createUuid(); + expect(uuid).toHaveLength(36); + expect(uuid).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, + ); + }); +}); diff --git a/tgui/packages/common/uuid.js b/tgui/packages/common/uuid.ts similarity index 60% rename from tgui/packages/common/uuid.js rename to tgui/packages/common/uuid.ts index 6e156d8649bc7..250809ab6a7d2 100644 --- a/tgui/packages/common/uuid.js +++ b/tgui/packages/common/uuid.ts @@ -7,14 +7,18 @@ /** * Creates a UUID v4 string * - * @return {string} + * @example + * ```tsx + * createUuid(); // 'f47ac10b-58cc-4372-a567-0e02b2c3d479' + * ``` */ -export const createUuid = () => { +export function createUuid(): string { let d = new Date().getTime(); + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); - // prettier-ignore - return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); + + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); }); -}; +} diff --git a/tgui/packages/common/vector.js b/tgui/packages/common/vector.js deleted file mode 100644 index b1f85f7429db8..0000000000000 --- a/tgui/packages/common/vector.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * N-dimensional vector manipulation functions. - * - * Vectors are plain number arrays, i.e. [x, y, z]. - * - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -import { map, reduce, zipWith } from './collections'; - -const ADD = (a, b) => a + b; -const SUB = (a, b) => a - b; -const MUL = (a, b) => a * b; -const DIV = (a, b) => a / b; - -export const vecAdd = (...vecs) => { - return reduce((a, b) => zipWith(ADD)(a, b))(vecs); -}; - -export const vecSubtract = (...vecs) => { - return reduce((a, b) => zipWith(SUB)(a, b))(vecs); -}; - -export const vecMultiply = (...vecs) => { - return reduce((a, b) => zipWith(MUL)(a, b))(vecs); -}; - -export const vecDivide = (...vecs) => { - return reduce((a, b) => zipWith(DIV)(a, b))(vecs); -}; - -export const vecScale = (vec, n) => { - return map((x) => x * n)(vec); -}; - -export const vecInverse = (vec) => { - return map((x) => -x)(vec); -}; - -export const vecLength = (vec) => { - return Math.sqrt(reduce(ADD)(zipWith(MUL)(vec, vec))); -}; - -export const vecNormalize = (vec) => { - return vecDivide(vec, vecLength(vec)); -}; diff --git a/tgui/packages/common/vector.ts b/tgui/packages/common/vector.ts new file mode 100644 index 0000000000000..c91715a8f995e --- /dev/null +++ b/tgui/packages/common/vector.ts @@ -0,0 +1,51 @@ +/** + * N-dimensional vector manipulation functions. + * + * Vectors are plain number arrays, i.e. [x, y, z]. + * + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { map, reduce, zip } from './collections'; + +const ADD = (a: number, b: number): number => a + b; +const SUB = (a: number, b: number): number => a - b; +const MUL = (a: number, b: number): number => a * b; +const DIV = (a: number, b: number): number => a / b; + +export type Vector = number[]; + +export const vecAdd = (...vecs: Vector[]): Vector => { + return map(zip(...vecs), (x) => reduce(x, ADD)); +}; + +export const vecSubtract = (...vecs: Vector[]): Vector => { + return map(zip(...vecs), (x) => reduce(x, SUB)); +}; + +export const vecMultiply = (...vecs: Vector[]): Vector => { + return map(zip(...vecs), (x) => reduce(x, MUL)); +}; + +export const vecDivide = (...vecs: Vector[]): Vector => { + return map(zip(...vecs), (x) => reduce(x, DIV)); +}; + +export const vecScale = (vec: Vector, n: number): Vector => { + return map(vec, (x) => x * n); +}; + +export const vecInverse = (vec: Vector): Vector => { + return map(vec, (x) => -x); +}; + +export const vecLength = (vec: Vector): number => { + return Math.sqrt(reduce(vecMultiply(vec, vec), ADD)); +}; + +export const vecNormalize = (vec: Vector): Vector => { + const length = vecLength(vec); + return map(vec, (c) => c / length); +}; diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index 0d26061f60b0a..7e30a0274acfa 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -6,7 +6,7 @@ import { EventEmitter } from 'common/events'; import { classes } from 'common/react'; -import { render } from 'react-dom'; +import { createRoot } from 'react-dom/client'; import { Tooltip } from 'tgui/components'; import { createLogger } from 'tgui/logging'; @@ -168,7 +168,7 @@ class ChatRenderer { // Find scrollable parent this.scrollNode = findNearestScrollableParent(this.rootNode); this.scrollNode.addEventListener('scroll', this.handleScroll); - setImmediate(() => { + setTimeout(() => { this.scrollToBottom(); }); // Flush the queue @@ -413,14 +413,16 @@ class ChatRenderer { childNode.removeChild(childNode.firstChild); } const Element = TGUI_CHAT_COMPONENTS[targetName]; + + const reactRoot = createRoot(childNode); + /* eslint-disable react/no-danger */ - render( + reactRoot.render( , childNode, ); - /* eslint-enable react/no-danger */ } // Highlight text @@ -455,15 +457,9 @@ class ChatRenderer { message.node = node; // Query all possible selectors to find out the message type if (!message.type) { - // IE8: Does not support querySelector on elements that - // are not yet in the document. - - const typeDef = - !Byond.IS_LTE_IE8 && - MESSAGE_TYPES.find( - (typeDef) => - typeDef.selector && node.querySelector(typeDef.selector), - ); + const typeDef = MESSAGE_TYPES.find( + (typeDef) => typeDef.selector && node.querySelector(typeDef.selector), + ); message.type = typeDef?.type || MESSAGE_TYPE_UNKNOWN; } updateMessageBadge(message); @@ -486,7 +482,7 @@ class ChatRenderer { this.rootNode.appendChild(fragment); } if (this.scrollTracking) { - setImmediate(() => this.scrollToBottom()); + setTimeout(() => this.scrollToBottom()); } } // Notify listeners that we have processed the batch @@ -586,10 +582,6 @@ class ChatRenderer { } saveToDisk() { - // Allow only on IE11 - if (Byond.IS_LTE_IE10) { - return; - } // Compile currently loaded stylesheets as CSS text let cssText = ''; const styleSheets = document.styleSheets; diff --git a/tgui/packages/tgui-panel/chat/selectors.ts b/tgui/packages/tgui-panel/chat/selectors.ts index 2908f661264a2..3c1e0b4f429c6 100644 --- a/tgui/packages/tgui-panel/chat/selectors.ts +++ b/tgui/packages/tgui-panel/chat/selectors.ts @@ -9,7 +9,7 @@ import { map } from 'common/collections'; export const selectChat = (state) => state.chat; export const selectChatPages = (state) => - map((id: string) => state.chat.pageById[id])(state.chat.pages); + map(state.chat.pages, (id: string) => state.chat.pageById[id]); export const selectCurrentChatPage = (state) => state.chat.pageById[state.chat.currentPageId]; diff --git a/tgui/packages/tgui-panel/panelFocus.js b/tgui/packages/tgui-panel/panelFocus.js index b7cea2293149e..8cff4a361b3eb 100644 --- a/tgui/packages/tgui-panel/panelFocus.js +++ b/tgui/packages/tgui-panel/panelFocus.js @@ -15,7 +15,7 @@ import { focusMap } from 'tgui/focus'; // text you can select with the mouse. const MIN_SELECTION_DISTANCE = 10; -const deferredFocusMap = () => setImmediate(() => focusMap()); +const deferredFocusMap = () => setTimeout(() => focusMap()); export const setupPanelFocusHacks = () => { let focusStolen = false; diff --git a/tgui/packages/tgui-panel/ping/PingIndicator.jsx b/tgui/packages/tgui-panel/ping/PingIndicator.tsx similarity index 97% rename from tgui/packages/tgui-panel/ping/PingIndicator.jsx rename to tgui/packages/tgui-panel/ping/PingIndicator.tsx index 549cd09cf74a8..717f57213ae8f 100644 --- a/tgui/packages/tgui-panel/ping/PingIndicator.jsx +++ b/tgui/packages/tgui-panel/ping/PingIndicator.tsx @@ -17,7 +17,7 @@ export const PingIndicator = (props) => { new Color(220, 40, 40), new Color(220, 200, 40), new Color(60, 220, 40), - ]); + ]).toString(); const roundtrip = ping.roundtrip ? toFixed(ping.roundtrip) : '--'; return (
    diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.jsx b/tgui/packages/tgui-panel/settings/SettingsPanel.jsx index 130f59d80537d..e5691037bba68 100644 --- a/tgui/packages/tgui-panel/settings/SettingsPanel.jsx +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.jsx @@ -5,14 +5,15 @@ */ import { toFixed } from 'common/math'; +import { capitalize } from 'common/string'; import { useLocalState } from 'tgui/backend'; import { useDispatch, useSelector } from 'tgui/backend'; import { Box, Button, + Collapsible, ColorBox, Divider, - Dropdown, Input, LabeledList, NumberInput, @@ -84,37 +85,62 @@ export const SettingsGeneral = (props) => {
    - - dispatch( - updateSettings({ - theme: value, - }), - ) - } - /> + {THEMES.map((THEME) => ( +
    } > -
    -
    -
    { - if (disabled && !open) { - return; - } - setOpen(!open); - onClick?.(event); +
    +
    { + if (disabled && !open) { + return; + } + setOpen(!open); + onClick?.(event); + }} + > + {icon && ( + + )} + - {icon && ( - - )} - - {displayText || selected} + {displayText || + (selected && getOptionValue(selected)) || + placeholder} + + {!noChevron && ( + + - {!noChevron && ( - - - - )} -
    - {buttons && ( - <> -
    + {buttons && ( + <> +
    ); diff --git a/tgui/packages/tgui/components/Flex.tsx b/tgui/packages/tgui/components/Flex.tsx index 50dba27795871..41ea6bd8275af 100644 --- a/tgui/packages/tgui/components/Flex.tsx +++ b/tgui/packages/tgui/components/Flex.tsx @@ -23,8 +23,6 @@ export const computeFlexClassName = (props: FlexProps) => { return classes([ 'Flex', props.inline && 'Flex--inline', - Byond.IS_LTE_IE10 && 'Flex--iefix', - Byond.IS_LTE_IE10 && props.direction === 'column' && 'Flex--iefix--column', computeBoxClassName(props), ]); }; @@ -65,11 +63,7 @@ export type FlexItemProps = BoxProps & }>; export const computeFlexItemClassName = (props: FlexItemProps) => { - return classes([ - 'Flex__item', - Byond.IS_LTE_IE10 && 'Flex__item--iefix', - computeBoxClassName(props), - ]); + return classes(['Flex__item', computeBoxClassName(props)]); }; export const computeFlexItemProps = (props: FlexItemProps) => { diff --git a/tgui/packages/tgui/components/Grid.jsx b/tgui/packages/tgui/components/Grid.jsx deleted file mode 100644 index f5593c9e00a55..0000000000000 --- a/tgui/packages/tgui/components/Grid.jsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -import { Table } from './Table'; - -/** @deprecated */ -export const Grid = (props) => { - const { children, ...rest } = props; - return ( - - {children} -
    - ); -}; - -/** @deprecated */ -export const GridColumn = (props) => { - const { size = 1, style, ...rest } = props; - return ( - - ); -}; - -Grid.Column = GridColumn; diff --git a/tgui/packages/tgui/components/Grid.tsx b/tgui/packages/tgui/components/Grid.tsx new file mode 100644 index 0000000000000..91c9256753bd3 --- /dev/null +++ b/tgui/packages/tgui/components/Grid.tsx @@ -0,0 +1,44 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { PropsWithChildren } from 'react'; + +import { logger } from '../logging'; +import { BoxProps } from './Box'; +import { Table } from './Table'; + +/** @deprecated Do not use. Use stack instead. */ +export function Grid(props: PropsWithChildren) { + const { children, ...rest } = props; + logger.error('Grid component is deprecated. Use a Stack instead.'); + return ( + + {children} +
    + ); +} + +type Props = Partial<{ + /** Width of the column in percentage. */ + size: number; +}> & + BoxProps; + +/** @deprecated Do not use. Use stack instead. */ +export function GridColumn(props: Props) { + const { size = 1, style, ...rest } = props; + return ( + + ); +} + +Grid.Column = GridColumn; diff --git a/tgui/packages/tgui/components/Image.tsx b/tgui/packages/tgui/components/Image.tsx index 3e1519bfbbf05..5d3a943feb0f2 100644 --- a/tgui/packages/tgui/components/Image.tsx +++ b/tgui/packages/tgui/components/Image.tsx @@ -1,12 +1,14 @@ -import { ReactNode } from 'react'; +import { useRef } from 'react'; import { BoxProps, computeBoxProps } from './Box'; -import { Tooltip } from './Tooltip'; type Props = Partial<{ - fixBlur: boolean; // true is default, this is an ie thing - objectFit: 'contain' | 'cover'; // fill is default - tooltip: ReactNode; + /** True is default, this fixes an ie thing */ + fixBlur: boolean; + /** False by default. Good if you're fetching images on UIs that do not auto update. This will attempt to fix the 'x' icon 5 times. */ + fixErrors: boolean; + /** Fill is default. */ + objectFit: 'contain' | 'cover'; }> & IconUnion & BoxProps; @@ -22,16 +24,18 @@ type IconUnion = src?: string; }; +const maxAttempts = 5; + /** Image component. Use this instead of Box as="img". */ -export const Image = (props: Props) => { +export function Image(props: Props) { const { - className, fixBlur = true, + fixErrors = false, objectFit = 'fill', src, - tooltip, ...rest } = props; + const attempts = useRef(0); const computedProps = computeBoxProps(rest); computedProps['style'] = { @@ -40,11 +44,20 @@ export const Image = (props: Props) => { objectFit, }; - let content = ; - - if (tooltip) { - content = {content}; - } - - return content; -}; + return ( + { + if (fixErrors && attempts.current < maxAttempts) { + const imgElement = event.currentTarget; + + setTimeout(() => { + imgElement.src = `${src}?attempt=${attempts.current}`; + attempts.current++; + }, 1000); + } + }} + src={src} + {...computedProps} + /> + ); +} diff --git a/tgui/packages/tgui/components/Stack.tsx b/tgui/packages/tgui/components/Stack.tsx index 18ae34c09e8c6..3f5cf72123cc0 100644 --- a/tgui/packages/tgui/components/Stack.tsx +++ b/tgui/packages/tgui/components/Stack.tsx @@ -17,14 +17,23 @@ import { } from './Flex'; type Props = Partial<{ - vertical: boolean; + /** Fills available space. */ fill: boolean; + /** Reverses the stack. */ + reverse: boolean; + /** Flex column */ + vertical: boolean; + /** Adds zebra striping to the stack. */ zebra: boolean; }> & FlexProps; -export const Stack = (props: Props) => { - const { className, vertical, fill, zebra, ...rest } = props; +export function Stack(props: Props) { + const { className, vertical, fill, reverse, zebra, ...rest } = props; + + const directionPrefix = vertical ? 'column' : 'row'; + const directionSuffix = reverse ? '-reverse' : ''; + return (
    { fill && 'Stack--fill', vertical ? 'Stack--vertical' : 'Stack--horizontal', zebra && 'Stack--zebra', + reverse && `Stack--reverse${vertical ? '--vertical' : ''}`, className, computeFlexClassName(props), ])} {...computeFlexProps({ - direction: vertical ? 'column' : 'row', + direction: `${directionPrefix}${directionSuffix}`, ...rest, })} /> ); -}; +} type StackItemProps = FlexItemProps & Partial<{ innerRef: RefObject; }>; -const StackItem = (props: StackItemProps) => { +function StackItem(props: StackItemProps) { const { className, innerRef, ...rest } = props; + return (
    { {...computeFlexItemProps(rest)} /> ); -}; +} Stack.Item = StackItem; @@ -70,8 +81,9 @@ type StackDividerProps = FlexItemProps & hidden: boolean; }>; -const StackDivider = (props: StackDividerProps) => { +function StackDivider(props: StackDividerProps) { const { className, hidden, ...rest } = props; + return (
    { {...computeFlexItemProps(rest)} /> ); -}; +} Stack.Divider = StackDivider; diff --git a/tgui/packages/tgui/components/Table.tsx b/tgui/packages/tgui/components/Table.tsx index 87edfbb8fc959..f4dcf6f3f522f 100644 --- a/tgui/packages/tgui/components/Table.tsx +++ b/tgui/packages/tgui/components/Table.tsx @@ -64,6 +64,8 @@ type CellProps = Partial<{ colSpan: number; /** Whether this is a header cell. */ header: boolean; + /** Rows for this cell to expand, assuming there is room. */ + rowSpan: number; }> & BoxProps; diff --git a/tgui/packages/tgui/components/index.ts b/tgui/packages/tgui/components/index.ts index 1a5f477d256b5..fdeb475ed3b8d 100644 --- a/tgui/packages/tgui/components/index.ts +++ b/tgui/packages/tgui/components/index.ts @@ -17,6 +17,7 @@ export { ColorBox } from './ColorBox'; export { Dialog } from './Dialog'; export { Dimmer } from './Dimmer'; export { Divider } from './Divider'; +export { DmIcon } from './DmIcon'; export { DraggableControl } from './DraggableControl'; export { Dropdown } from './Dropdown'; export { FitText } from './FitText'; diff --git a/tgui/packages/tgui/debug/KitchenSink.jsx b/tgui/packages/tgui/debug/KitchenSink.jsx index d215ab777d802..19044ca98d0c7 100644 --- a/tgui/packages/tgui/debug/KitchenSink.jsx +++ b/tgui/packages/tgui/debug/KitchenSink.jsx @@ -4,11 +4,12 @@ * @license MIT */ -import { useLocalState } from '../backend'; +import { useState } from 'react'; + import { Flex, Section, Tabs } from '../components'; import { Pane, Window } from '../layouts'; -const r = require.context('../stories', false, /\.stories\.js$/); +const r = require.context('../stories', false, /\.stories\.jsx$/); /** * @returns {{ @@ -22,8 +23,8 @@ const getStories = () => r.keys().map((path) => r(path)); export const KitchenSink = (props) => { const { panel } = props; - const [theme] = useLocalState('kitchenSinkTheme'); - const [pageIndex, setPageIndex] = useLocalState('pageIndex', 0); + const [theme] = useState(null); + const [pageIndex, setPageIndex] = useState(0); const stories = getStories(); const story = stories[pageIndex]; const Layout = panel ? Pane : Window; diff --git a/tgui/packages/tgui/drag.ts b/tgui/packages/tgui/drag.ts index 584666a97a631..0884b1b0bd78c 100644 --- a/tgui/packages/tgui/drag.ts +++ b/tgui/packages/tgui/drag.ts @@ -209,7 +209,7 @@ export const dragStartHandler = (event) => { dragPointOffset = vecSubtract( [event.screenX, event.screenY], getWindowPosition(), - ); + ) as [number, number]; // Focus click target (event.target as HTMLElement)?.focus(); document.addEventListener('mousemove', dragMoveHandler); @@ -234,7 +234,10 @@ const dragMoveHandler = (event: MouseEvent) => { } event.preventDefault(); setWindowPosition( - vecSubtract([event.screenX, event.screenY], dragPointOffset), + vecSubtract([event.screenX, event.screenY], dragPointOffset) as [ + number, + number, + ], ); }; @@ -247,7 +250,7 @@ export const resizeStartHandler = dragPointOffset = vecSubtract( [event.screenX, event.screenY], getWindowPosition(), - ); + ) as [number, number]; initialSize = getWindowSize(); // Focus click target (event.target as HTMLElement)?.focus(); @@ -278,7 +281,10 @@ const resizeMoveHandler = (event: MouseEvent) => { ); const delta = vecSubtract(currentOffset, dragPointOffset); // Extra 1x1 area is added to ensure the browser can see the cursor - size = vecAdd(initialSize, vecMultiply(resizeMatrix, delta), [1, 1]); + size = vecAdd(initialSize, vecMultiply(resizeMatrix, delta), [1, 1]) as [ + number, + number, + ]; // Sane window size values size[0] = Math.max(size[0], 150 * pixelRatio); size[1] = Math.max(size[1], 50 * pixelRatio); diff --git a/tgui/packages/tgui/interfaces/AdminFax.jsx b/tgui/packages/tgui/interfaces/AdminFax.jsx index 9aeef3247a34d..3e6026d4ce46e 100644 --- a/tgui/packages/tgui/interfaces/AdminFax.jsx +++ b/tgui/packages/tgui/interfaces/AdminFax.jsx @@ -63,10 +63,9 @@ export const FaxMainPanel = (props) => { setFax(value)} /> diff --git a/tgui/packages/tgui/interfaces/AdminPDA.jsx b/tgui/packages/tgui/interfaces/AdminPDA.jsx index 09570265a207e..fa83f200e52c7 100644 --- a/tgui/packages/tgui/interfaces/AdminPDA.jsx +++ b/tgui/packages/tgui/interfaces/AdminPDA.jsx @@ -33,7 +33,8 @@ const ReceiverChoice = (props) => { showInvisible || !rcvr.invisible) .map((rcvr) => ({ diff --git a/tgui/packages/tgui/interfaces/AiVoiceChanger.tsx b/tgui/packages/tgui/interfaces/AiVoiceChanger.tsx index 9e248a0103344..09c1aa04e57f1 100644 --- a/tgui/packages/tgui/interfaces/AiVoiceChanger.tsx +++ b/tgui/packages/tgui/interfaces/AiVoiceChanger.tsx @@ -5,37 +5,40 @@ import { Button, Dropdown, Input, LabeledList, Section } from '../components'; import { Window } from '../layouts'; type Data = { - on: BooleanLike; - voices: string[]; - say_verb: string; loud: BooleanLike; name: string; + on: BooleanLike; + say_verb: string; + selected: string; + voices: string[]; }; -export const AiVoiceChanger = (props) => { +export function AiVoiceChanger(props) { const { act, data } = useBackend(); - const { loud, name, on, say_verb, voices } = data; + const { loud, name, on, say_verb, voices, selected } = data; return ( -
    +
    + onSelected={(value) => { act('look', { look: value, - }) - } + }); + }} + selected={selected} /> @@ -51,10 +54,11 @@ export const AiVoiceChanger = (props) => { {
    ); -}; +} diff --git a/tgui/packages/tgui/interfaces/AirlockElectronics.tsx b/tgui/packages/tgui/interfaces/AirlockElectronics.tsx index 7e0ebba0bb43d..b90e8ac3b578f 100644 --- a/tgui/packages/tgui/interfaces/AirlockElectronics.tsx +++ b/tgui/packages/tgui/interfaces/AirlockElectronics.tsx @@ -1,21 +1,31 @@ import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; -import { Button, Input, LabeledList, Section } from '../components'; +import { Button, Input, LabeledList, Section, Stack } from '../components'; import { Window } from '../layouts'; -import { AccessConfig } from './common/AccessConfig'; +import { AccessConfig, Region } from './common/AccessConfig'; type Data = { + accesses: string[]; oneAccess: BooleanLike; - unres_direction: number; - passedName: string; passedCycleId: number; - regions: string[]; - accesses: string[]; + passedName: string; + regions: Region[]; shell: BooleanLike; + unres_direction: number; }; -export const AirLockMainSection = (props) => { +export function AirlockElectronics(props) { + return ( + + + + + + ); +} + +export function AirLockMainSection(props) { const { act, data } = useBackend(); const { accesses = [], @@ -28,123 +38,125 @@ export const AirLockMainSection = (props) => { } = data; return ( -
    - - - { - act('set_shell', { on: !shell }); - }} - tooltip="Whether this airlock can have an integrated circuit placed inside of it or not." - /> - - -
    - ); -}; - -export const AirlockElectronics = (props) => { - return ( - - - - - + + +
    + + + { + act('set_shell', { on: !shell }); + }} + tooltip="Whether this airlock can have an integrated circuit placed inside of it or not." + > + Shell + + + + + + + + + + + + + + act('passedName', { + passedName: value, + }) + } + /> + + + + act('passedCycleId', { + passedCycleId: value, + }) + } + /> + + +
    +
    + + + act('set', { + access: ref, + }) + } + grantAll={() => act('grant_all')} + denyAll={() => act('clear_all')} + grantDep={(ref) => + act('grant_region', { + region: ref, + }) + } + denyDep={(ref) => + act('deny_region', { + region: ref, + }) + } + /> + +
    ); -}; +} diff --git a/tgui/packages/tgui/interfaces/AlertModal.tsx b/tgui/packages/tgui/interfaces/AlertModal.tsx index d5b931dc08c7c..62b6e8bbbc328 100644 --- a/tgui/packages/tgui/interfaces/AlertModal.tsx +++ b/tgui/packages/tgui/interfaces/AlertModal.tsx @@ -1,33 +1,29 @@ -import { useState } from 'react'; - -import { - KEY_ENTER, - KEY_ESCAPE, - KEY_LEFT, - KEY_RIGHT, - KEY_SPACE, - KEY_TAB, -} from '../../common/keycodes'; +import { KEY } from 'common/keys'; +import { BooleanLike } from 'common/react'; +import { KeyboardEvent, useState } from 'react'; + import { useBackend } from '../backend'; -import { Autofocus, Box, Button, Flex, Section, Stack } from '../components'; +import { Autofocus, Box, Button, Section, Stack } from '../components'; import { Window } from '../layouts'; import { Loader } from './common/Loader'; -type AlertModalData = { - autofocus: boolean; +type Data = { + autofocus: BooleanLike; buttons: string[]; - large_buttons: boolean; + large_buttons: BooleanLike; message: string; - swapped_buttons: boolean; + swapped_buttons: BooleanLike; timeout: number; title: string; }; -const KEY_DECREMENT = -1; -const KEY_INCREMENT = 1; +enum DIRECTION { + Increment = 1, + Decrement = -1, +} -export const AlertModal = (props) => { - const { act, data } = useBackend(); +export function AlertModal(props) { + const { act, data } = useBackend(); const { autofocus, buttons = [], @@ -36,128 +32,148 @@ export const AlertModal = (props) => { timeout, title, } = data; + const [selected, setSelected] = useState(0); + + // At least one of the buttons has a long text message + const isVerbose = buttons.some((button) => button.length > 10); + const largeSpacing = isVerbose && large_buttons ? 20 : 15; + // Dynamically sets window dimensions const windowHeight = - 115 + + 120 + + (isVerbose ? largeSpacing * buttons.length : 0) + (message.length > 30 ? Math.ceil(message.length / 4) : 0) + (message.length && large_buttons ? 5 : 0); - const windowWidth = 325 + (buttons.length > 2 ? 55 : 0); - const onKey = (direction: number) => { - if (selected === 0 && direction === KEY_DECREMENT) { - setSelected(buttons.length - 1); - } else if (selected === buttons.length - 1 && direction === KEY_INCREMENT) { - setSelected(0); - } else { - setSelected(selected + direction); + + const windowWidth = 345 + (buttons.length > 2 ? 55 : 0); + + /** Changes button selection, etc */ + function keyDownHandler(event: KeyboardEvent) { + switch (event.key) { + case KEY.Space: + case KEY.Enter: + act('choose', { choice: buttons[selected] }); + return; + case KEY.Escape: + act('cancel'); + return; + case KEY.Left: + event.preventDefault(); + onKey(DIRECTION.Decrement); + return; + case KEY.Tab: + case KEY.Right: + event.preventDefault(); + onKey(DIRECTION.Increment); + return; } - }; + } + + /** Manages iterating through the buttons */ + function onKey(direction: DIRECTION) { + const newIndex = (selected + direction + buttons.length) % buttons.length; + setSelected(newIndex); + } return ( {!!timeout && } - { - const keyCode = window.event ? e.which : e.keyCode; - /** - * Simulate a click when pressing space or enter, - * allow keyboard navigation, override tab behavior - */ - if (keyCode === KEY_SPACE || keyCode === KEY_ENTER) { - act('choose', { choice: buttons[selected] }); - } else if (keyCode === KEY_ESCAPE) { - act('cancel'); - } else if (keyCode === KEY_LEFT) { - e.preventDefault(); - onKey(KEY_DECREMENT); - } else if (keyCode === KEY_TAB || keyCode === KEY_RIGHT) { - e.preventDefault(); - onKey(KEY_INCREMENT); - } - }} - > +
    - + {message} - + {!!autofocus && } - + {isVerbose ? ( + + ) : ( + + )}
    ); +} + +type ButtonDisplayProps = { + selected: number; }; /** * Displays a list of buttons ordered by user prefs. - * Technically this handles more than 2 buttons, but you - * should just be using a list input in that case. */ -const ButtonDisplay = (props) => { - const { data } = useBackend(); +function HorizontalButtons(props: ButtonDisplayProps) { + const { act, data } = useBackend(); const { buttons = [], large_buttons, swapped_buttons } = data; const { selected } = props; return ( - - {buttons?.map((button, index) => - !!large_buttons && buttons.length < 3 ? ( - - - - ) : ( - - - - ), - )} - + + {buttons.map((button, index) => ( + + + + ))} + ); -}; +} /** - * Displays a button with variable sizing. + * Technically the parent handles more than 2 buttons, but you + * should just be using a list input in that case. */ -const AlertButton = (props) => { - const { act, data } = useBackend(); - const { large_buttons } = data; - const { button, selected } = props; - const buttonWidth = button.length > 7 ? button.length : 7; +function VerticalButtons(props: ButtonDisplayProps) { + const { act, data } = useBackend(); + const { buttons = [], large_buttons, swapped_buttons } = data; + const { selected } = props; return ( - + {buttons.map((button, index) => ( + + + + ))} + ); -}; +} diff --git a/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx b/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx index 5b1a46c0070e5..2f41fa7c46d05 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx @@ -1,5 +1,4 @@ import { BooleanLike } from 'common/react'; -import { multiline } from 'common/string'; import { useState } from 'react'; import { useBackend } from '../backend'; @@ -227,7 +226,7 @@ const MemoriesSection = (props) => { + ))} + + +
    + ); +}; + +const WorldMapPanel = (props) => { + const { act, data } = useBackend(); + const { all_worlds, latest_unlocked_world_position } = data; + return ( +
    + + + {all_worlds.map((world, index) => ( + + ))} +
    + ); +}; + +const BattlePanel = (props) => { + const { act, data } = useBackend(); + const { + attack_types, + enemy_icon_id, + enemy_name, + enemy_max_hp, + enemy_hp, + enemy_mp, + feedback_message, + } = data; + return ( +
    + {feedback_message && {feedback_message}} + + {enemy_name}'s HP: {enemy_hp}/{enemy_max_hp} + + + {enemy_name}'s MP: {enemy_mp} + + + {attack_types.map((attack, index) => ( + + ))} + act('flee')} + > + Flee (Lose half your Gold) + +
    + ); +}; + +const BetweenBattlePanel = (props) => { + const { act, data } = useBackend(); + return ( +
    + + + As night sets, you can choose to rest. This will restore your health and + mana to full before the next battle, but you may also be ambushed, + forcing you into the next fight without any additional healing. + + + + +
    + ); +}; + +const GameOverPanel = (props) => { + const { act, data } = useBackend(); + return ( +
    + + Game Over + + + + +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/Blueprints.tsx b/tgui/packages/tgui/interfaces/Blueprints.tsx new file mode 100644 index 0000000000000..644412a9a777e --- /dev/null +++ b/tgui/packages/tgui/interfaces/Blueprints.tsx @@ -0,0 +1,186 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../backend'; +import { Box, Button, Divider, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type Data = { + area_notice: string; + area_name: string; + wire_data: WireData[]; + legend: string; + legend_viewing_list: string; + legend_off: string; + fluff_notice: string; + station_name: string; + wires_name: string; + wire_devices: WireDevices[]; + viewing: BooleanLike; +}; + +type WireDevices = { + name: string; + ref: string; +}; + +type WireData = { + color: string; + message: string; +}; + +export const Blueprints = () => { + const { act, data } = useBackend(); + const { legend, legend_viewing_list, legend_off } = data; + + return ( + + + {legend === legend_viewing_list ? ( + + ) : legend === legend_off ? ( + + ) : ( + + )} + + + ); +}; + +const WireList = () => { + const { act, data } = useBackend(); + const { wire_devices = [] } = data; + + return ( +
    + + + {wire_devices.map((wire) => ( + + ))} + +
    + ); +}; + +const WireArea = () => { + const { act, data } = useBackend(); + const { wires_name, wire_data = [] } = data; + + return ( +
    + + {wires_name} wires: + {wire_data.map((wire) => ( + + {wire.color}:{' '} + {wire.message} + + ))} +
    + ); +}; + +const MainMenu = () => { + const { act, data } = useBackend(); + const { area_notice, area_name, fluff_notice, station_name, viewing } = data; + + return ( +
    + + {fluff_notice} + + + + {area_notice} + + + + + + + + + + + + {viewing ? ( + <> + + + + + + + + ) : ( + + + + )} + +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/BluespaceSender.tsx b/tgui/packages/tgui/interfaces/BluespaceSender.tsx index 24e88f6ef5d28..2f94af4cfaa9d 100644 --- a/tgui/packages/tgui/interfaces/BluespaceSender.tsx +++ b/tgui/packages/tgui/interfaces/BluespaceSender.tsx @@ -1,8 +1,6 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { toFixed } from 'common/math'; import { BooleanLike } from 'common/react'; -import { multiline } from 'common/string'; import { useBackend } from '../backend'; import { @@ -43,10 +41,10 @@ export const BluespaceSender = (props) => { const { act, data } = useBackend(); const { gas_transfer_rate, credits, bluespace_network_gases = [], on } = data; - const gases: Gas[] = flow([ - filter((gas) => gas.amount >= 0.01), - sortBy((gas) => -gas.amount), - ])(bluespace_network_gases); + const gases: Gas[] = sortBy( + filter(bluespace_network_gases, (gas) => gas.amount >= 0.01), + (gas) => -gas.amount, + ); const gasMax = Math.max(1, ...gases.map((gas) => gas.amount)); @@ -64,7 +62,7 @@ export const BluespaceSender = (props) => { color="transparent" icon="info" tooltipPosition="bottom-start" - tooltip={multiline` + tooltip={` Any gas you pipe into here will be added to the Bluespace Network! That means any connected Bluespace Vendor (multitool) will hook up to all the gas stored in this, and charge diff --git a/tgui/packages/tgui/interfaces/BluespaceVendor.tsx b/tgui/packages/tgui/interfaces/BluespaceVendor.tsx index 3ba8289356be9..7b9619de26e55 100644 --- a/tgui/packages/tgui/interfaces/BluespaceVendor.tsx +++ b/tgui/packages/tgui/interfaces/BluespaceVendor.tsx @@ -1,8 +1,6 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { toFixed } from 'common/math'; import { BooleanLike } from 'common/react'; -import { multiline } from 'common/string'; import { useBackend } from '../backend'; import { @@ -50,10 +48,10 @@ export const BluespaceVendor = (props) => { tank_full, } = data; - const gases: Gas[] = flow([ - filter((gas) => gas.amount >= 0.01), - sortBy((gas) => -gas.amount), - ])(bluespace_network_gases); + const gases: Gas[] = sortBy( + filter(bluespace_network_gases, (gas) => gas.amount >= 0.01), + (gas) => -gas.amount, + ); const gasMax = Math.max(1, ...gases.map((gas) => gas.amount)); @@ -125,7 +123,7 @@ export const BluespaceVendor = (props) => { color="transparent" icon="info" tooltipPosition="bottom-start" - tooltip={multiline` + tooltip={` Quick guide for machine use: Prepare a tank to create a new one in the machine, pick how much you want it filled, and finally press start on the gas of your choice! diff --git a/tgui/packages/tgui/interfaces/CameraConsole.tsx b/tgui/packages/tgui/interfaces/CameraConsole.tsx index adad4f8748ed8..3dafe1240dfe3 100644 --- a/tgui/packages/tgui/interfaces/CameraConsole.tsx +++ b/tgui/packages/tgui/interfaces/CameraConsole.tsx @@ -1,5 +1,4 @@ -import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; +import { filter, sort } from 'common/collections'; import { BooleanLike, classes } from 'common/react'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -68,15 +67,17 @@ const prevNextCamera = ( * Filters cameras, applies search terms and sorts the alphabetically. */ const selectCameras = (cameras: Camera[], searchText = ''): Camera[] => { - const testSearch = createSearch(searchText, (camera: Camera) => camera.name); - - return flow([ - filter((camera: Camera) => !!camera.name), - // Optional search term - searchText && filter(testSearch), - // Slightly expensive, but way better than sorting in BYOND - sortBy((camera: Camera) => camera), - ])(cameras); + let queriedCameras = filter(cameras, (camera: Camera) => !!camera.name); + if (searchText) { + const testSearch = createSearch( + searchText, + (camera: Camera) => camera.name, + ); + queriedCameras = filter(queriedCameras, testSearch); + } + queriedCameras = sort(queriedCameras); + + return queriedCameras; }; export const CameraConsole = (props) => { diff --git a/tgui/packages/tgui/interfaces/Canvas.tsx b/tgui/packages/tgui/interfaces/Canvas.tsx index 09565831ea06d..648418e7abd06 100644 --- a/tgui/packages/tgui/interfaces/Canvas.tsx +++ b/tgui/packages/tgui/interfaces/Canvas.tsx @@ -1,5 +1,5 @@ import { Color } from 'common/color'; -import { decodeHtmlEntities, multiline } from 'common/string'; +import { decodeHtmlEntities } from 'common/string'; import { Component, createRef, RefObject } from 'react'; import { useBackend } from '../backend'; @@ -278,11 +278,11 @@ export const Canvas = (props) => { { - return ( - - - - - - ); -}; - -export const CargoContent = (props) => { - const { data } = useBackend(); - const [tab, setTab] = useSharedState('tab', 'catalog'); - const { cart = [], requests = [], requestonly } = data; - const cart_length = cart.reduce((total, entry) => total + entry.amount, 0); - - return ( - - -
    - - setTab('catalog')} - > - Catalog - - 0 && 'yellow'} - selected={tab === 'requests'} - onClick={() => setTab('requests')} - > - Requests ({requests.length}) - - {!requestonly && ( - <> - 0 && 'yellow'} - selected={tab === 'cart'} - onClick={() => setTab('cart')} - > - Checkout ({cart_length}) - - setTab('help')} - > - Help - - - )} - -
    - {tab === 'catalog' && } - {tab === 'requests' && } - {tab === 'cart' && } - {tab === 'help' && } -
    - ); -}; - -const CargoStatus = (props) => { - const { act, data } = useBackend(); - const { - department, - grocery, - away, - docked, - loan, - loan_dispatched, - location, - message, - points, - requestonly, - can_send, - } = data; - - return ( -
    - formatMoney(value)} - /> - {' credits'} - - } - > - - - {(docked && !requestonly && can_send && ( -
    - ); -}; - -/** - * Take entire supplies tree - * and return a flat supply pack list that matches search, - * sorted by name and only the first page. - * @param {any[]} supplies Supplies list. - * @param {string} search The search term - * @returns {any[]} The flat list of supply packs. - */ -const searchForSupplies = (supplies, search) => { - search = search.toLowerCase(); - - return flow([ - (categories) => categories.flatMap((category) => category.packs), - filter( - (pack) => - pack.name?.toLowerCase().includes(search.toLowerCase()) || - pack.desc?.toLowerCase().includes(search.toLowerCase()), - ), - sortBy((pack) => pack.name), - (packs) => packs.slice(0, 25), - ])(supplies); -}; - -export const CargoCatalog = (props) => { - const { express } = props; - const { act, data } = useBackend(); - - const { self_paid, app_cost } = data; - - const supplies = Object.values(data.supplies); - const { amount_by_name = [], max_order } = data; - - const [activeSupplyName, setActiveSupplyName] = useSharedState( - 'supply', - supplies[0]?.name, - ); - - const [searchText, setSearchText] = useSharedState('search_text', ''); - - const activeSupply = - activeSupplyName === 'search_results' - ? { packs: searchForSupplies(supplies, searchText) } - : supplies.find((supply) => supply.name === activeSupplyName); - - return ( -
    - - act('toggleprivate')} - /> - - ) - } - > - - - - - - - - - - { - if (value === searchText) { - return; - } - - if (value.length) { - // Start showing results - setActiveSupplyName('search_results'); - } else if (activeSupplyName === 'search_results') { - // return to normal category - setActiveSupplyName(supplies[0]?.name); - } - setSearchText(value); - }} - /> - - - - {supplies.map((supply) => ( - { - setActiveSupplyName(supply.name); - setSearchText(''); - }} - > - {supply.name} ({supply.packs.length}) - - ))} - - - - - {activeSupply?.packs.map((pack) => { - const tags = []; - if (pack.small_item) { - tags.push('Small'); - } - if (pack.access) { - tags.push('Restricted'); - } - return ( - - {pack.name} - - {tags.join(', ')} - - - - - - ); - })} -
    -
    -
    -
    - ); -}; - -const CargoRequests = (props) => { - const { act, data } = useBackend(); - const { requestonly, can_send, can_approve_requests } = data; - const requests = data.requests || []; - // Labeled list reimplementation to squeeze extra columns out of it - return ( -
    act('denyall')} - /> - ) - } - > - {requests.length === 0 && No Requests} - {requests.length > 0 && ( - - {requests.map((request) => ( - - - #{request.id} - - {request.object} - - {request.orderer} - - - {request.reason} - - - {formatMoney(request.cost)} cr - - {(!requestonly || can_send) && can_approve_requests && ( - -
    - )} -
    - ); -}; - -const CargoCartButtons = (props) => { - const { act, data } = useBackend(); - const { requestonly, can_send, can_approve_requests } = data; - const cart = data.cart || []; - const total = cart.reduce((total, entry) => total + entry.cost, 0); - return ( - <> - - {cart.length === 0 && 'Cart is empty'} - {cart.length === 1 && '1 item'} - {cart.length >= 2 && cart.length + ' items'}{' '} - {total > 0 && `(${formatMoney(total)} cr)`} - - {!requestonly && !!can_send && !!can_approve_requests && ( - + + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoCart.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoCart.tsx new file mode 100644 index 0000000000000..39642fa334084 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoCart.tsx @@ -0,0 +1,130 @@ +import { useBackend } from '../../backend'; +import { + Button, + Icon, + Input, + NoticeBox, + RestrictedInput, + Section, + Stack, + Table, +} from '../../components'; +import { formatMoney } from '../../format'; +import { CargoCartButtons } from './CargoButtons'; +import { CargoData } from './types'; + +export function CargoCart(props) { + const { act, data } = useBackend(); + const { requestonly, away, cart = [], docked, location } = data; + + const sendable = !!away && !!docked; + + return ( + + +
    }> + +
    +
    + + {cart.length > 0 && !requestonly && ( +
    + + + {!sendable && } + + + + + +
    + )} +
    +
    + ); +} + +function CheckoutItems(props) { + const { act, data } = useBackend(); + const { amount_by_name = {}, can_send, cart = [], max_order } = data; + + if (cart.length === 0) { + return Nothing in cart; + } + + return ( + + + ID + Supply Type + Amount + + + Cost + + + + {cart.map((entry) => ( + + + #{entry.id} + + {entry.object} + + + {can_send && entry.can_be_cancelled ? ( + + act('modify', { + order_name: entry.object, + amount: value, + }) + } + /> + ) : ( + + )} + + {!!can_send && !!entry.can_be_cancelled && ( + <> +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx new file mode 100644 index 0000000000000..baccf90c4bd3a --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx @@ -0,0 +1,238 @@ +import { sortBy } from 'common/collections'; +import { useMemo } from 'react'; + +import { useBackend, useSharedState } from '../../backend'; +import { + Button, + Icon, + Input, + Section, + Stack, + Table, + Tabs, + Tooltip, +} from '../../components'; +import { formatMoney } from '../../format'; +import { CargoCartButtons } from './CargoButtons'; +import { searchForSupplies } from './helpers'; +import { CargoData, Supply, SupplyCategory } from './types'; + +type Props = { + express?: boolean; +}; + +export function CargoCatalog(props: Props) { + const { express } = props; + const { act, data } = useBackend(); + const { self_paid } = data; + + const supplies = Object.values(data.supplies); + + const [activeSupplyName, setActiveSupplyName] = useSharedState( + 'supply', + supplies[0]?.name, + ); + + const [searchText, setSearchText] = useSharedState('search_text', ''); + + const packs = useMemo(() => { + let fetched: Supply[] | undefined; + + if (activeSupplyName === 'search_results') { + fetched = searchForSupplies(supplies, searchText); + } else { + fetched = supplies.find( + (supply) => supply.name === activeSupplyName, + )?.packs; + } + + if (!fetched) return []; + + fetched = sortBy(fetched, (pack: Supply) => pack.name); + + return fetched; + }, [activeSupplyName, supplies, searchText]); + + return ( +
    + + + + ) + } + > + + + + + + + + + +
    + ); +} + +type CatalogTabsProps = { + activeSupplyName: string; + categories: SupplyCategory[]; + searchText: string; + setActiveSupplyName: (name: string) => void; + setSearchText: (text: string) => void; +}; + +function CatalogTabs(props: CatalogTabsProps) { + const { + activeSupplyName, + categories, + searchText, + setActiveSupplyName, + setSearchText, + } = props; + + const sorted = sortBy(categories, (supply) => supply.name); + + return ( + + + + + + + + { + if (value === searchText) { + return; + } + + if (value.length) { + // Start showing results + setActiveSupplyName('search_results'); + } else if (activeSupplyName === 'search_results') { + // return to normal category + setActiveSupplyName(sorted[0]?.name); + } + setSearchText(value); + }} + /> + + + + + {sorted.map((supply) => ( + { + setActiveSupplyName(supply.name); + setSearchText(''); + }} + > +
    + {supply.name} + {supply.packs.length} +
    +
    + ))} +
    + ); +} + +type CatalogListProps = { + packs: SupplyCategory['packs']; +}; + +function CatalogList(props: CatalogListProps) { + const { act, data } = useBackend(); + const { amount_by_name = {}, max_order, self_paid, app_cost } = data; + const { packs = [] } = props; + + return ( +
    + + {packs.map((pack) => { + let color = ''; + const digits = Math.floor(Math.log10(pack.cost) + 1); + if (self_paid) { + color = 'caution'; + } else if (digits >= 5 && digits <= 6) { + color = 'yellow'; + } else if (digits > 6) { + color = 'bad'; + } + + return ( + + {pack.name} + + {!!pack.small_item && ( + + + + )} + + + {!!pack.access && ( + + + + )} + + + + + + ); + })} +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoHelp.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoHelp.tsx new file mode 100644 index 0000000000000..841ded71fb7e7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoHelp.tsx @@ -0,0 +1,80 @@ +import { Box, NoticeBox, Section, Stack } from '../../components'; + +const ORDER_TEXT = `Each department on the station will order crates from their own personal + consoles. These orders are ENTIRELY FREE! They do not come out of + cargo's budget, and rather put the consoles on cooldown. So + here's where you come in: The ordered crates will show up on your + supply console, and you need to deliver the crates to the orderers. + You'll actually be paid the full value of the department crate on + delivery if the crate was not tampered with, making the system a good + source of income.`; + +const DISPOSAL_TEXT = `In addition to MULEs and hand-deliveries, you can also make use of the + disposals mailing system. Note that a break in the disposal piping could + cause your package to be lost (this hardly ever happens), so this is not + always the most secure ways to deliver something. You can wrap up a + piece of paper and mail it the same way if you (or someone at the desk) + wants to mail a letter.`; + +export function CargoHelp(props) { + return ( + + +
    +
    + {ORDER_TEXT} +
    +
    + Examine a department order crate to get specific details about where + the crate needs to go. +
    +
    + + MULEbots are slow but loyal delivery bots that will get crates + delivered with minimal technician effort required. It is slow, + though, and can be tampered with while en route. + +
    + + Setting up a MULEbot is easy: + + 1. Drag the crate you want to deliver next to the MULEbot. +
    + 2. Drag the crate on top of MULEbot. It should load on. +
    + 3. Open your PDA. +
    + 4. Click Delivery Bot Control.
    + 5. Click Scan for Active Bots.
    + 6. Choose your MULE. +
    + 7. Click on Destination: (set).
    + 8. Choose a destination and click OK. +
    + 9. Click Proceed. +
    +
    + {DISPOSAL_TEXT} +
    + + Using the Disposals Delivery System is even easier: + + 1. Wrap your item/crate in packaging paper. +
    + 2. Use the destinations tagger to choose where to send it. +
    + 3. Tag the package. +
    + 4. Stick it on the conveyor and let the system handle it. +
    +
    +
    +
    + + + Pondering something not included here? When in doubt, ask the QM! + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoRequests.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoRequests.tsx new file mode 100644 index 0000000000000..3a53efb45e980 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoRequests.tsx @@ -0,0 +1,85 @@ +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, NoticeBox, Section, Table } from '../../components'; +import { TableCell, TableRow } from '../../components/Table'; +import { formatMoney } from '../../format'; +import { CargoData } from './types'; + +export function CargoRequests(props) { + const { act, data } = useBackend(); + const { requests = [], requestonly, can_send, can_approve_requests } = data; + + return ( +
    act('denyall')} + > + Clear + + ) + } + > + {requests.length === 0 && No Requests} + {requests.length > 0 && ( + + + ID + Object + Orderer + Reason + Cost + {(!requestonly || !!can_send) && !!can_approve_requests && ( + Actions + )} + + + {requests.map((request) => ( + + #{request.id} + {request.object} + + {request.orderer} + + + {decodeHtmlEntities(request.reason)} + + + {formatMoney(request.cost)} cr + + {(!requestonly || !!can_send) && !!can_approve_requests && ( + +
    + )} +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoStatus.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoStatus.tsx new file mode 100644 index 0000000000000..b230400e4e3f9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoStatus.tsx @@ -0,0 +1,75 @@ +import { useBackend } from '../../backend'; +import { + AnimatedNumber, + Box, + Button, + LabeledList, + Section, +} from '../../components'; +import { formatMoney } from '../../format'; +import { CargoData } from './types'; + +export function CargoStatus(props) { + const { act, data } = useBackend(); + const { + department, + grocery, + away, + docked, + loan, + loan_dispatched, + location, + message, + points, + requestonly, + can_send, + } = data; + + return ( +
    + formatMoney(value)} + /> + {' credits'} + + } + > + + + {!!docked && !requestonly && !!can_send ? ( + + ) : ( + String(location) + )} + + {message} + {!!loan && !requestonly && ( + + {!loan_dispatched ? ( + + ) : ( + Loaned to Centcom + )} + + )} + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/helpers.ts b/tgui/packages/tgui/interfaces/Cargo/helpers.ts new file mode 100644 index 0000000000000..e6b67f8ff6dd1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/helpers.ts @@ -0,0 +1,35 @@ +import { filter } from 'common/collections'; +import { flow } from 'common/fp'; + +import { Supply, SupplyCategory } from './types'; + +/** + * Take entire supplies tree + * and return a flat supply pack list that matches search, + * sorted by name and only the first page. + * @param {Supply[]} supplies Supplies list, aka Object.values(data.supplies) + * @param {string} search The search term + * @returns {Supply[]} The flat list of supply packs. + */ +export function searchForSupplies( + supplies: SupplyCategory[], + search: string, +): Supply[] { + const lowerSearch = search.toLowerCase(); + + return flow([ + // Flat categories + (initialSupplies: SupplyCategory[]) => + initialSupplies.flatMap((category) => category.packs), + // Filter by name or desc + (flatMapped: Supply[]) => + filter( + flatMapped, + (pack: Supply) => + pack.name?.toLowerCase().includes(lowerSearch) || + pack.desc?.toLowerCase().includes(lowerSearch), + ), + // Just the first page + (filtered: Supply[]) => filtered.slice(0, 25), + ])(supplies); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/index.tsx b/tgui/packages/tgui/interfaces/Cargo/index.tsx new file mode 100644 index 0000000000000..d39435f4cd953 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/index.tsx @@ -0,0 +1,91 @@ +import { useBackend, useSharedState } from '../../backend'; +import { Stack, Tabs } from '../../components'; +import { Window } from '../../layouts'; +import { CargoCart } from './CargoCart'; +import { CargoCatalog } from './CargoCatalog'; +import { CargoHelp } from './CargoHelp'; +import { CargoRequests } from './CargoRequests'; +import { CargoStatus } from './CargoStatus'; +import { CargoData } from './types'; + +enum TAB { + Catalog = 'catalog', + Requests = 'requests', + Cart = 'cart', + Help = 'help', +} + +export function Cargo(props) { + return ( + + + + + + ); +} + +export function CargoContent(props) { + const { data } = useBackend(); + + const { cart = [], requests = [], requestonly } = data; + + const [tab, setTab] = useSharedState('cargotab', TAB.Catalog); + + let amount = 0; + for (let i = 0; i < cart.length; i++) { + amount += cart[i].amount; + } + + return ( + + + + + + + setTab(TAB.Catalog)} + > + Catalog + + 0 && 'yellow'} + selected={tab === TAB.Requests} + onClick={() => setTab(TAB.Requests)} + > + Requests ({requests.length}) + + {!requestonly && ( + <> + 0 && 'yellow'} + selected={tab === TAB.Cart} + onClick={() => setTab(TAB.Cart)} + > + Checkout ({amount}) + + setTab(TAB.Help)} + > + Help + + + )} + + + + {tab === TAB.Catalog && } + {tab === TAB.Requests && } + {tab === TAB.Cart && } + {tab === TAB.Help && } + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/types.ts b/tgui/packages/tgui/interfaces/Cargo/types.ts new file mode 100644 index 0000000000000..4d9e2817d61fc --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/types.ts @@ -0,0 +1,58 @@ +import { BooleanLike } from 'common/react'; + +export type CargoData = { + amount_by_name: Record | undefined; + app_cost?: number; + away: BooleanLike; + can_approve_requests: BooleanLike; + can_send: BooleanLike; + cart: CartEntry[]; + department: string; + docked: BooleanLike; + grocery: number; + loan_dispatched: BooleanLike; + loan: BooleanLike; + location: string; + max_order: number; + message: string; + points: number; + requests: Request[]; + requestonly: BooleanLike; + self_paid: BooleanLike; + supplies: Record; +}; + +export type SupplyCategory = { + name: string; + packs: Supply[]; +}; + +export type Supply = { + access: BooleanLike; + cost: number; + desc: string; + goody: BooleanLike; + id: string; + name: string; + small_item: BooleanLike; +}; + +type CartEntry = { + amount: number; + can_be_cancelled: BooleanLike; + cost_type: string; + cost: number; + dep_order: BooleanLike; + id: string; + object: string; + orderer: string; + paid: BooleanLike; +}; + +type Request = { + cost: number; + id: string; + object: string; + orderer: string; + reason: string; +}; diff --git a/tgui/packages/tgui/interfaces/CargoExpress.tsx b/tgui/packages/tgui/interfaces/CargoExpress.tsx index 0983e685f7d2e..83947b5adc473 100644 --- a/tgui/packages/tgui/interfaces/CargoExpress.tsx +++ b/tgui/packages/tgui/interfaces/CargoExpress.tsx @@ -9,7 +9,7 @@ import { Section, } from '../components'; import { Window } from '../layouts'; -import { CargoCatalog } from './Cargo'; +import { CargoCatalog } from './Cargo/CargoCatalog'; import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox'; type Data = { @@ -24,7 +24,7 @@ type Data = { message: string; }; -export const CargoExpress = (props) => { +export function CargoExpress(props) { const { data } = useBackend(); const { locked } = data; @@ -36,9 +36,9 @@ export const CargoExpress = (props) => {
    ); -}; +} -const CargoExpressContent = (props) => { +function CargoExpressContent(props) { const { act, data } = useBackend(); const { hasBeacon, @@ -64,11 +64,9 @@ const CargoExpressContent = (props) => { > - - {message} @@ -88,4 +84,4 @@ const CargoExpressContent = (props) => { ); -}; +} diff --git a/tgui/packages/tgui/interfaces/CentcomPodLauncher/PodBays.tsx b/tgui/packages/tgui/interfaces/CentcomPodLauncher/PodBays.tsx index 264df99a3c501..023ff2afb05ea 100644 --- a/tgui/packages/tgui/interfaces/CentcomPodLauncher/PodBays.tsx +++ b/tgui/packages/tgui/interfaces/CentcomPodLauncher/PodBays.tsx @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { useBackend } from '../../backend'; import { Button, Section } from '../../components'; import { BAYS } from './constants'; @@ -17,7 +15,7 @@ export function PodBays(props) { color="transparent" icon="trash" onClick={() => act('clearBay')} - tooltip={multiline` + tooltip={` Clears everything from the selected bay`} tooltipPosition="top-end" @@ -25,7 +23,7 @@ export function PodBays(props) {
    ) } > - {!hasBeaker && ( + {!beaker ? ( No beaker loaded. - )} - {!!hasBeaker && beakerCurrentVolume === 0 && ( + ) : beaker.currentVolume === 0 ? ( Beaker is empty. + ) : ( + + {beaker.contents.map((chemical) => ( + + ))} +
    )} - - {beakerContents.map((chemical) => ( - - ))} -
    - - {` / ${bufferMaxVolume} units`} + + {` / ${buffer.maxVolume} units`} } > - {bufferContents.length === 0 && ( + {buffer_contents.length === 0 ? ( Buffer is empty. + ) : ( + + {buffer_contents.map((chemical) => ( + + ))} +
    )} - - {bufferContents.map((chemical) => ( - - ))} -
    {!isPrinting && (
    + + setShowPreferredContainer((currentValue) => !currentValue) + } + > + Suggest + { setItemCount(value); }} @@ -200,51 +208,36 @@ const ChemMasterContent = (props) => { Math.round( Math.min( selectedContainerVolume, - bufferCurrentVolume / itemCount, + buffer.currentVolume / itemCount, ) * 100, ) / 100 } u. each`} - ) : ( -
    @@ -256,9 +249,10 @@ const ChemMasterContent = (props) => { } > { ); }; -const ReagentEntry = (props) => { +type ReagentProps = { + chemical: AnalyzableReagent; + transferTo: string; + analyze: (chemical: AnalyzableReagent) => void; +}; + +const ReagentEntry = (props: ReagentProps) => { const { data, act } = useBackend(); - const { chemical, transferTo } = props; + const { chemical, transferTo, analyze } = props; const { isPrinting } = data; return ( @@ -295,7 +295,6 @@ const ReagentEntry = (props) => { } > @@ -438,7 +454,6 @@ const AnalysisResults = (props) => { {pH} - {state} {color} diff --git a/tgui/packages/tgui/interfaces/CircuitAccessChecker.tsx b/tgui/packages/tgui/interfaces/CircuitAccessChecker.tsx index 0c81311a43167..f37414a86f52f 100644 --- a/tgui/packages/tgui/interfaces/CircuitAccessChecker.tsx +++ b/tgui/packages/tgui/interfaces/CircuitAccessChecker.tsx @@ -3,11 +3,11 @@ import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { Button, LabeledList } from '../components'; import { Window } from '../layouts'; -import { AccessConfig } from './common/AccessConfig'; +import { AccessConfig, Region } from './common/AccessConfig'; type Data = { oneAccess: BooleanLike; - regions: string[]; + regions: Region[]; accesses: string[]; }; @@ -28,8 +28,8 @@ export const CircuitAccessChecker = (props) => { act('set', { access: ref, diff --git a/tgui/packages/tgui/interfaces/CircuitModule.jsx b/tgui/packages/tgui/interfaces/CircuitModule.jsx index 799fea9d15ffb..bbb323e5e5a7e 100644 --- a/tgui/packages/tgui/interfaces/CircuitModule.jsx +++ b/tgui/packages/tgui/interfaces/CircuitModule.jsx @@ -130,7 +130,7 @@ const PortEntry = (props) => { diff --git a/tgui/packages/tgui/interfaces/CircuitSignalHandler.tsx b/tgui/packages/tgui/interfaces/CircuitSignalHandler.tsx index 1fc1f8397f920..66d04644391c3 100644 --- a/tgui/packages/tgui/interfaces/CircuitSignalHandler.tsx +++ b/tgui/packages/tgui/interfaces/CircuitSignalHandler.tsx @@ -221,7 +221,7 @@ const Entry = (props: EntryProps) => { {(options.length && ( diff --git a/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx b/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx index 386f3c5721a0c..438030e39472c 100644 --- a/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx +++ b/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx @@ -96,41 +96,66 @@ const BountyTextBox = (props) => { const BountyPickBox = (props) => { const { act, data } = useBackend(); - const { id_bounty_names, id_bounty_values } = data; + const { id_bounty_names, id_bounty_infos, id_bounty_values } = data; return (
    - + - + - +
    ); }; + +const BountyPickButton = (props) => { + return ( + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ColorMatrixEditor.tsx b/tgui/packages/tgui/interfaces/ColorMatrixEditor.tsx index 897c43e6234b7..edf75dcf161d9 100644 --- a/tgui/packages/tgui/interfaces/ColorMatrixEditor.tsx +++ b/tgui/packages/tgui/interfaces/ColorMatrixEditor.tsx @@ -13,7 +13,7 @@ import { Window } from '../layouts'; type Data = { mapRef: string; - currentColor: string[]; + currentColor: number[]; }; const PREFIXES = ['r', 'g', 'b', 'a', 'c'] as const; @@ -49,7 +49,7 @@ export const ColorMatrixEditor = (props) => { format={(value) => toFixed(value, 2)} onDrag={(value) => { let retColor = currentColor; - retColor[row * 4 + col] = `${value}`; + retColor[row * 4 + col] = value; act('transition_color', { color: retColor, }); diff --git a/tgui/packages/tgui/interfaces/CommandReport.tsx b/tgui/packages/tgui/interfaces/CommandReport.tsx index dfe8cf9ff3d63..9185bebb5b4cd 100644 --- a/tgui/packages/tgui/interfaces/CommandReport.tsx +++ b/tgui/packages/tgui/interfaces/CommandReport.tsx @@ -117,7 +117,7 @@ const AnnouncementColor = (props) => {
    act('update_announcement_color', { @@ -138,7 +138,7 @@ const AnnouncementSound = (props) => {
    act('set_report_sound', { diff --git a/tgui/packages/tgui/interfaces/CommunicationsConsole.jsx b/tgui/packages/tgui/interfaces/CommunicationsConsole.jsx index e816d27be1ecd..48a7d98a40155 100644 --- a/tgui/packages/tgui/interfaces/CommunicationsConsole.jsx +++ b/tgui/packages/tgui/interfaces/CommunicationsConsole.jsx @@ -29,10 +29,12 @@ const SWIPE_NEEDED = 'SWIPE_NEEDED'; const EMAG_SHUTTLE_NOTICE = 'This shuttle is deemed significantly dangerous to the crew, and is only supplied by the Syndicate.'; -const sortShuttles = sortBy( - (shuttle) => !shuttle.emagOnly, - (shuttle) => shuttle.initial_cost, -); +const sortShuttles = (shuttles) => + sortBy( + shuttles, + (shuttle) => !shuttle.emagOnly, + (shuttle) => shuttle.initial_cost, + ); const AlertButton = (props) => { const { act, data } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/OverviewSection.tsx b/tgui/packages/tgui/interfaces/ControllerOverview/OverviewSection.tsx new file mode 100644 index 0000000000000..919c19631f6fc --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/OverviewSection.tsx @@ -0,0 +1,57 @@ +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section, Stack } from '../../components'; +import { ControllerData } from './types'; + +export function OverviewSection(props) { + const { act, data } = useBackend(); + const { fast_update, map_cpu, subsystems = [], world_time } = data; + + let overallUsage = 0; + let overallOverrun = 0; + for (let i = 0; i < subsystems.length; i++) { + overallUsage += subsystems[i].tick_usage; + overallOverrun += subsystems[i].tick_overrun; + } + + return ( +
    { + act('toggle_fast_update'); + }} + > + Fast + + } + > + + + + + {world_time.toFixed(1)} + + + {map_cpu.toFixed(2)}% + + + + + + + {(overallUsage * 0.01).toFixed(2)}% + + + {(overallOverrun * 0.01).toFixed(2)}% + + + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemDialog.tsx b/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemDialog.tsx new file mode 100644 index 0000000000000..21acd2dca1d95 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemDialog.tsx @@ -0,0 +1,69 @@ +import { + Box, + Button, + Divider, + LabeledList, + Modal, + Stack, +} from '../../components'; +import { SubsystemData } from './types'; + +type Props = { + subsystem: SubsystemData; + onClose: () => void; +}; + +export function SubsystemDialog(props: Props) { + const { subsystem, onClose } = props; + const { + cost_ms, + init_order, + initialization_failure_message, + last_fire, + name, + next_fire, + tick_overrun, + tick_usage, + } = subsystem; + + return ( + + + + {name} + + + + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemRow.tsx b/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemRow.tsx new file mode 100644 index 0000000000000..0a0bef6a9e6ec --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemRow.tsx @@ -0,0 +1,107 @@ +import { Dispatch } from 'react'; + +import { useBackend } from '../../backend'; +import { + Button, + Icon, + ProgressBar, + Stack, + Table, + Tooltip, +} from '../../components'; +import { SORTING_TYPES } from './contants'; +import { SortType, SubsystemData } from './types'; + +type Props = { + max: number; + setSelected: Dispatch; + showBars: boolean; + sortType: SortType; + subsystem: SubsystemData; +}; + +export function SubsystemRow(props: Props) { + const { act } = useBackend(); + const { max, setSelected, showBars, sortType, subsystem } = props; + const { can_fire, doesnt_fire, initialized, name, ref } = subsystem; + + const { propName } = SORTING_TYPES[sortType]; + const value = subsystem[propName]; + + let icon = 'play'; + let color = 'good'; + let tooltip = 'Operational'; + if (!initialized) { + icon = 'circle-exclamation'; + color = 'darkgreen'; + tooltip = 'Not initialized'; + } else if (doesnt_fire) { + icon = 'check'; + color = 'grey'; + tooltip = 'Does not fire'; + } else if (!can_fire) { + icon = 'pause'; + color = 'grey'; + tooltip = 'Paused'; + } + + let valueDisplay = ''; + let rangeDisplay = {}; + if (showBars) { + if (sortType === SortType.Cost) { + valueDisplay = value.toFixed(0) + 'ms'; + rangeDisplay = { + average: [75, 124.99], + bad: [125, Infinity], + }; + } else { + valueDisplay = (value * 0.01).toFixed(2) + '%'; + rangeDisplay = { + average: [10, 24.99], + bad: [25, Infinity], + }; + } + } else { + valueDisplay = value; + } + + return ( + + + + + + + setSelected(subsystem)}> + {showBars ? ( + + {name} {valueDisplay} + + ) : ( + + )} + + + + + + } + > + + {sorted.map((subsystem) => ( + + ))} +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/contants.ts b/tgui/packages/tgui/interfaces/ControllerOverview/contants.ts new file mode 100644 index 0000000000000..fdd28bfd36b0a --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/contants.ts @@ -0,0 +1,43 @@ +type SortType = { + label: string; + propName: string; + inDeciseconds: boolean; +}; + +export const SORTING_TYPES: readonly SortType[] = [ + { + label: 'Alphabetical', + propName: 'name', + inDeciseconds: false, + }, + { + label: 'Cost', + propName: 'cost_ms', + inDeciseconds: true, + }, + { + label: 'Init Order', + propName: 'init_order', + inDeciseconds: false, + }, + { + label: 'Last Fire', + propName: 'last_fire', + inDeciseconds: false, + }, + { + label: 'Next Fire', + propName: 'next_fire', + inDeciseconds: false, + }, + { + label: 'Tick Usage', + propName: 'tick_usage', + inDeciseconds: true, + }, + { + label: 'Tick Overrun', + propName: 'tick_overrun', + inDeciseconds: true, + }, +]; diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/filters.ts b/tgui/packages/tgui/interfaces/ControllerOverview/filters.ts new file mode 100644 index 0000000000000..8d975ac9a7108 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/filters.ts @@ -0,0 +1,45 @@ +import { SortType } from './types'; + +export type FilterState = { + ascending: boolean; + inactive: boolean; + query: string; + smallValues: boolean; + sortType: SortType; +}; + +export enum FilterAction { + Ascending = 'SET_SORT_ASCENDING', + Inactive = 'SET_FILTER_INACTIVE', + SmallValues = 'SET_FILTER_SMALL_VALUES', + SortType = 'SET_SORT_TYPE', + Query = 'SET_FILTER_QUERY', + Update = 'UPDATE_FILTER', +} + +type Action = + | { type: FilterAction.Ascending; payload: boolean } + | { type: FilterAction.Inactive; payload: boolean } + | { type: FilterAction.SmallValues; payload: boolean } + | { type: FilterAction.SortType; payload: SortType } + | { type: FilterAction.Query; payload: string } + | { type: FilterAction.Update; payload: Partial }; + +export function filterReducer(state: FilterState, action: Action): FilterState { + switch (action.type) { + case FilterAction.Inactive: + return { ...state, inactive: action.payload }; + case FilterAction.SmallValues: + return { ...state, smallValues: action.payload }; + case FilterAction.Ascending: + return { ...state, ascending: action.payload }; + case FilterAction.SortType: + return { ...state, sortType: action.payload }; + case FilterAction.Query: + return { ...state, query: action.payload }; + case FilterAction.Update: + return { ...state, ...action.payload }; + default: + return state; + } +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/index.tsx b/tgui/packages/tgui/interfaces/ControllerOverview/index.tsx new file mode 100644 index 0000000000000..388d3d436789d --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/index.tsx @@ -0,0 +1,152 @@ +import { useReducer, useState } from 'react'; + +import { Button, Dropdown, Input, Section, Stack } from '../../components'; +import { Window } from '../../layouts'; +import { SORTING_TYPES } from './contants'; +import { FilterAction, filterReducer, FilterState } from './filters'; +import { OverviewSection } from './OverviewSection'; +import { SubsystemDialog } from './SubsystemDialog'; +import { SubsystemViews } from './SubsystemViews'; +import { SortType, SubsystemData } from './types'; + +export function ControllerOverview(props) { + return ( + + + + + + ); +} + +export function ControllerContent(props) { + const [state, dispatch] = useReducer(filterReducer, { + ascending: true, + inactive: true, + query: '', + smallValues: false, + sortType: SortType.Name, + }); + + const [selected, setSelected] = useState(); + + const { label, inDeciseconds } = + SORTING_TYPES?.[state.sortType] || SORTING_TYPES[0]; + + function onSelectionHandler(value: string) { + const updates: Partial = { + sortType: SORTING_TYPES.findIndex((type) => type.label === value), + }; + + if (updates.sortType === undefined) return; + + const { inDeciseconds } = SORTING_TYPES[updates.sortType]; + + updates.ascending = !inDeciseconds; + updates.smallValues = inDeciseconds; + + dispatch({ type: FilterAction.Update, payload: updates }); + } + + return ( + + {selected && ( + setSelected(undefined)} + subsystem={selected} + /> + )} + + + + +
    + + + + + + dispatch({ type: FilterAction.Query, payload: value }) + } + placeholder="By name" + value={state.query} + width="85%" + /> + + + + + + + + + + + type.label)} + selected={label} + displayText={label} + onSelected={onSelectionHandler} + /> + + + + + + + + +
    +
    + + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/types.ts b/tgui/packages/tgui/interfaces/ControllerOverview/types.ts new file mode 100644 index 0000000000000..604989b1f75c5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/types.ts @@ -0,0 +1,33 @@ +import { BooleanLike } from 'common/react'; + +export type SubsystemData = { + can_fire: BooleanLike; + cost_ms: number; + doesnt_fire: BooleanLike; + init_order: number; + initialization_failure_message: string | undefined; + initialized: BooleanLike; + last_fire: number; + name: string; + next_fire: number; + ref: string; + tick_overrun: number; + tick_usage: number; +}; + +export type ControllerData = { + world_time: number; + fast_update: BooleanLike; + map_cpu: number; + subsystems: SubsystemData[]; +}; + +export enum SortType { + Name, + Cost, + InitOrder, + LastFire, + NextFire, + TickUsage, + TickOverrun, +} diff --git a/tgui/packages/tgui/interfaces/CrewConsole.jsx b/tgui/packages/tgui/interfaces/CrewConsole.jsx deleted file mode 100644 index 8ed7efa5c1137..0000000000000 --- a/tgui/packages/tgui/interfaces/CrewConsole.jsx +++ /dev/null @@ -1,195 +0,0 @@ -import { sortBy } from 'common/collections'; - -import { useBackend } from '../backend'; -import { Box, Button, Icon, Section, Table } from '../components'; -import { COLORS } from '../constants'; -import { Window } from '../layouts'; - -const HEALTH_COLOR_BY_LEVEL = [ - '#17d568', - '#c4cf2d', - '#e67e22', - '#ed5100', - '#e74c3c', - '#801308', -]; - -const STAT_LIVING = 0; -const STAT_DEAD = 4; - -const jobIsHead = (jobId) => jobId % 10 === 0; - -const jobToColor = (jobId) => { - if (jobId === 0) { - return COLORS.department.captain; - } - if (jobId >= 10 && jobId < 20) { - return COLORS.department.security; - } - if (jobId >= 20 && jobId < 30) { - return COLORS.department.medbay; - } - if (jobId >= 30 && jobId < 40) { - return COLORS.department.science; - } - if (jobId >= 40 && jobId < 50) { - return COLORS.department.engineering; - } - if (jobId >= 50 && jobId < 60) { - return COLORS.department.cargo; - } - if (jobId >= 60 && jobId < 200) { - return COLORS.department.service; - } - if (jobId >= 200 && jobId < 230) { - return COLORS.department.centcom; - } - return COLORS.department.other; -}; - -const statToIcon = (life_status) => { - switch (life_status) { - case STAT_LIVING: - return 'heart'; - case STAT_DEAD: - return 'skull'; - } - return 'heartbeat'; -}; - -const healthToAttribute = (oxy, tox, burn, brute, attributeList) => { - const healthSum = oxy + tox + burn + brute; - const level = Math.min(Math.max(Math.ceil(healthSum / 25), 0), 5); - return attributeList[level]; -}; - -const HealthStat = (props) => { - const { type, value } = props; - return ( - - {value} - - ); -}; - -export const CrewConsole = () => { - return ( - - -
    - -
    -
    -
    - ); -}; - -const CrewTable = (props) => { - const { act, data } = useBackend(); - const sensors = sortBy((s) => s.ijob)(data.sensors ?? []); - return ( - - - Name - - - Vitals - - - Position - - {!!data.link_allowed && ( - - Tracking - - )} - - {sensors.map((sensor) => ( - - ))} -
    - ); -}; - -const CrewTableEntry = (props) => { - const { act, data } = useBackend(); - const { link_allowed } = data; - const { sensor_data } = props; - const { - name, - assignment, - ijob, - life_status, - oxydam, - toxdam, - burndam, - brutedam, - area, - can_track, - } = sensor_data; - - return ( - - - {name} - {assignment !== undefined ? ` (${assignment})` : ''} - - - {oxydam !== undefined ? ( - - ) : life_status !== STAT_DEAD ? ( - - ) : ( - - )} - - - {oxydam !== undefined ? ( - - - {'/'} - - {'/'} - - {'/'} - - - ) : life_status !== STAT_DEAD ? ( - 'Alive' - ) : ( - 'Dead' - )} - - - {area !== undefined ? ( - area - ) : ( - - )} - - {!!link_allowed && ( - - + + + setSearchQuery((e.target as HTMLTextAreaElement).value) + } + /> + + } + > + + + Name + + + Vitals + + + Position + + {!!data.link_allowed && ( + + Tracking + + )} + + {sorted.map((sensor) => ( + + ))} +
    +
    + ); +}; + +type CrewTableEntryProps = { + sensor_data: CrewSensor; +}; + +const CrewTableEntry = (props: CrewTableEntryProps) => { + const { act, data } = useBackend(); + const { link_allowed } = data; + const { sensor_data } = props; + const { + name, + assignment, + ijob, + life_status, + oxydam, + toxdam, + burndam, + brutedam, + area, + can_track, + } = sensor_data; + + return ( + + + {name} + {assignment !== undefined ? ` (${assignment})` : ''} + + + {oxydam !== undefined ? ( + + ) : life_status !== STAT_DEAD ? ( + + ) : ( + + )} + + + {oxydam !== undefined ? ( + + + {'/'} + + {'/'} + + {'/'} + + + ) : life_status !== STAT_DEAD ? ( + 'Alive' + ) : ( + 'Dead' + )} + + + {area !== '~' && area !== undefined ? ( + area + ) : ( + + )} + + {!!link_allowed && ( + + + + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/CyborgBootDebug.jsx b/tgui/packages/tgui/interfaces/CyborgBootDebug.jsx index 1daed59197abf..914d4373ea082 100644 --- a/tgui/packages/tgui/interfaces/CyborgBootDebug.jsx +++ b/tgui/packages/tgui/interfaces/CyborgBootDebug.jsx @@ -1,35 +1,33 @@ -import { multiline } from 'common/string'; - import { useBackend } from '../backend'; import { Button, Input, LabeledList, Section } from '../components'; import { Window } from '../layouts'; -const TOOLTIP_NAME = multiline` +const TOOLTIP_NAME = ` Enter a new name for this unit. Set to blank to reset to default, which means unit will be able to choose it's own name. `; -const TOOLTIP_LOCOMOTION = multiline` +const TOOLTIP_LOCOMOTION = ` If restricted, unit will be under lockdown until released. `; -const TOOLTIP_PANEL = multiline` +const TOOLTIP_PANEL = ` If unlocked, unit's cover panel will be accessible even without proper authorization. `; -const TOOLTIP_AISYNC = multiline` +const TOOLTIP_AISYNC = ` If closed, this unit will not be paired with any AI. `; -const TOOLTIP_AI = multiline` +const TOOLTIP_AI = ` Controls who will be the master AI of this unit. `; -const TOOLTIP_LAWSYNC = multiline` +const TOOLTIP_LAWSYNC = ` If closed, this unit will not synchronize it's laws with it's master AI. `; diff --git a/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx b/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx index 457c909b2ca7a..e7b66093d2099 100644 --- a/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx +++ b/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx @@ -6,261 +6,395 @@ import { Button, Divider, Dropdown, - Flex, Icon, + LabeledList, Modal, + NoticeBox, Section, + Stack, Table, + Tooltip, } from '../components'; import { ButtonCheckbox } from '../components/Button'; import { Window } from '../layouts'; -type PlayerLike = { - [key: string]: { - host: number; - ready: BooleanLike; - }; +type Player = { + host: number; + key: string; + loadout: string; + ready: BooleanLike; + mob: string; }; type Modifier = { - name: string; desc: string; modpath: string; - selected: BooleanLike; - selectable: BooleanLike; - player_selected: BooleanLike; + name: string; player_selectable: BooleanLike; + player_selected: BooleanLike; + selectable: BooleanLike; + selected: BooleanLike; +}; + +type Map = { + desc: string; + max_players: number; + min_players: number; + name: string; + time: number; }; type Data = { - self: string; - host: BooleanLike; + active_mods: string; admin: BooleanLike; - playing: BooleanLike; + host: BooleanLike; + loadoutdesc: string; loadouts: string[]; + map: Map; maps: string[]; - map: { - name: string; - desc: string; - time: number; - min_players: number; - max_players: number; - }; mod_menu_open: BooleanLike; modifiers: Modifier[]; - active_mods: string; - loadoutdesc: string; - players: PlayerLike[]; - observers: PlayerLike[]; + observers: Player[]; + players: Player[]; + playing: BooleanLike; + self: string; }; -export const DeathmatchLobby = (props) => { +export function DeathmatchLobby(props) { const { act, data } = useBackend(); - const { modifiers = [] } = data; + const { + admin, + host, + mod_menu_open, + observers = [], + players = [], + self, + } = data; + + const allReady = players.every((player) => player.ready); + + const fullAccess = !!host || !!admin; + const showMenu = fullAccess && !!mod_menu_open; + + const isObserver = observers.find((observer) => observer.key === self); + return ( - + {showMenu && } - - -
    - - - - Name - Loadout - Ready - - {Object.keys(data.players).map((player) => ( - - - {!!data.players[player].host && } - - - {(!( - (data.host && !data.players[player].host) || - data.admin - ) && {player}) || ( - - act('host', { - id: player, - func: value, - }) - } - /> - )} - - - - act('change_loadout', { - player: player, - loadout: value, - }) - } - /> - - - act('ready')} - /> - - - ))} - {Object.keys(data.observers).map((observer) => ( - - - {(!!data.observers[observer].host && ( - - )) || } - - - {(!( - (data.host && !data.observers[observer].host) || - data.admin - ) && {observer}) || ( - - act('host', { - id: observer, - func: value, - }) - } - /> - )} - - Observing - - ))} -
    -
    -
    - + + + + + + + + + + + +
    - - {(!!data.host && ( + + + {!!admin && ( + + )} + + + + + + + +
    +
    +
    +
    +
    + ); +} + +function PlayerColumn(props) { + const { act, data } = useBackend(); + const { + admin, + host, + loadouts = [], + observers = [], + players = [], + self, + } = data; + + const allReady = players.every((player) => player.ready); + + const fullAccess = !!host || !!admin; + + return ( +
    30}> + + + + Name + Loadout + + + + + + + {players.map((player) => { + const isHost = !!player.host; + const isSelf = player.key === self; + const canBoot = fullAccess && !isSelf; + + return ( + + + {isHost && ( + + + + )} + {!host && isSelf && ( + + + + )} + + + + {!canBoot ? ( + {player.key} + ) : ( act('host', { - func: 'change_map', - map: value, + id: player.key, + func: value, }) } /> - )) || {data.map.name}} - - - {data.map.desc} - - - Maximum Play Time: {`${data.map.time / 600}min`} -
    - Min players: {data.map.min_players} -
    - Max players: {data.map.max_players} -
    - Current players: {Object.keys(data.players).length} -
    - - {data.active_mods} - {(!!data.admin || !!data.host) && ( - <> - -
    +
    ); -}; +} + +function HostControls(props) { + const { act, data } = useBackend(); + const { active_mods = [], admin, host, loadoutdesc, playing } = data; + + const fullAccess = !!host || !!admin; + + return ( +
    + + + + {active_mods} + + {fullAccess && ( + <> + + + + )} + + + Loadout Description + + + {loadoutdesc} + {!!playing && ( + <> + + + The game is currently in progress, or loading. + + + )} +
    + ); +} const ModSelector = (props) => { const { act, data } = useBackend(); - const { admin, host, mod_menu_open, modifiers = [] } = data; - if (!mod_menu_open || !(host || admin)) { - return null; - } + const { modifiers = [] } = data; + return ( - + {modifiers.map((mod, index) => ( + + act('toggle_modifier', { + modpath: mod.modpath, + }) + } + > + {mod.name} + + ))} + + ); +}; + +function MapInfo(props) { + const { act, data } = useBackend(); + const { host, maps = [], map, players } = data; + + if (!host && !map?.name) { + return No map selected; + } + + return ( + <> + {!host ? ( + {map.name} + ) : ( + <> + + act('host', { + func: 'change_map', + map: value, }) } /> - ); - })} - + + + )} + {map.desc} + + + + {`${map.time / 600}min`} + + + {map.min_players} + + + {map.max_players} + + + {players.length} + + + ); -}; +} diff --git a/tgui/packages/tgui/interfaces/DeathmatchPanel.jsx b/tgui/packages/tgui/interfaces/DeathmatchPanel.jsx deleted file mode 100644 index 8ac2ff5f76d1d..0000000000000 --- a/tgui/packages/tgui/interfaces/DeathmatchPanel.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import { useBackend } from '../backend'; -import { - Button, - Dropdown, - Flex, - NoticeBox, - Section, - Stack, - Table, -} from '../components'; -import { Window } from '../layouts'; - -export const DeathmatchPanel = (props, context) => { - const { act, data } = useBackend(context); - const playing = data.playing || ''; - return ( - - - - If you play, you can still possibly be returned to your body (No - Guarantees)! - -
    - - - Host - Map - Players - - {data.lobbies.map((lobby) => ( - - - {(!data.admin && lobby.name) || ( - - act('admin', { - id: lobby.name, - func: value, - }) - } - /> - )} - - {lobby.map} - - {lobby.players}/{lobby.max_players} - - - {(!lobby.playing && ( - <> -
    -
    - +
    + + + + ); +} + +function LobbyPane(props) { + const { data } = useBackend(); + const { lobbies = [] } = data; + + return ( +
    + + + Host + Map + + + + + + + + + + + {lobbies.length === 0 && ( + + + + No lobbies found. Start one! + + + + )} + + {lobbies.map((lobby, index) => ( + + ))} +
    +
    + ); +} + +function LobbyDisplay(props) { + const { act, data } = useBackend(); + const { admin, playing, hosting } = data; + const { lobby } = props; + + const isActive = (!!hosting || !!playing) && playing !== lobby.name; + + return ( + + + {!admin ? ( + lobby.name + ) : ( + + act('admin', { + id: lobby.name, + func: value, + }) + } + /> + )} + + {lobby.map} + + {lobby.players}/{lobby.max_players} + + + {!lobby.playing ? ( + <> + + + )} + + + ); +} diff --git a/tgui/packages/tgui/interfaces/DestinationTagger.tsx b/tgui/packages/tgui/interfaces/DestinationTagger.tsx index b1acfe192a7ca..5326f93e01bac 100644 --- a/tgui/packages/tgui/interfaces/DestinationTagger.tsx +++ b/tgui/packages/tgui/interfaces/DestinationTagger.tsx @@ -1,5 +1,4 @@ import { map, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { useBackend } from '../backend'; import { Button, Section, Stack } from '../components'; @@ -25,13 +24,17 @@ type DestinationInfo = { * @returns The alphetically sorted list of destinations. */ const sortDestinations = (locations: string[]): DestinationInfo[] => { - return flow([ - map((name, index) => ({ - name: name.toUpperCase(), - sorting_id: index + 1, - })), - sortBy((dest) => dest.name), - ])(locations); + return sortBy( + map( + locations, + (name, index) => + ({ + name: name.toUpperCase(), + sorting_id: index + 1, + }) as DestinationInfo, + ), + (dest) => dest.name, + ); }; export const DestinationTagger = (props) => { diff --git a/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleStorage.jsx b/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleStorage.jsx index 43c22b321a036..681b4f211d7d5 100644 --- a/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleStorage.jsx +++ b/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleStorage.jsx @@ -211,7 +211,7 @@ const StorageButtons = (props) => { const StorageChromosomes = (props) => { const { data, act } = useBackend(); const chromos = data.chromoStorage ?? []; - const uniqueChromos = uniqBy((chromo) => chromo.Name)(chromos); + const uniqueChromos = uniqBy(chromos, (chromo) => chromo.Name); const chromoName = data.view.storageChromoName; const chromo = chromos.find((chromo) => chromo.Name === chromoName); diff --git a/tgui/packages/tgui/interfaces/DnaConsole/MutationInfo.jsx b/tgui/packages/tgui/interfaces/DnaConsole/MutationInfo.jsx index 89a1468d95333..2629a029fa8fb 100644 --- a/tgui/packages/tgui/interfaces/DnaConsole/MutationInfo.jsx +++ b/tgui/packages/tgui/interfaces/DnaConsole/MutationInfo.jsx @@ -1,5 +1,4 @@ import { filter, uniqBy } from 'common/collections'; -import { flow } from 'common/fp'; import { useBackend } from '../../backend'; import { @@ -122,10 +121,10 @@ export const MutationInfo = (props) => { isSameMutation(x, mutation), ); const savedToDisk = diskMutations.find((x) => isSameMutation(x, mutation)); - const combinedMutations = flow([ - uniqBy((mutation) => mutation.Name), - filter((x) => x.Name !== mutation.Name), - ])([...diskMutations, ...mutationStorage]); + const combinedMutations = filter( + uniqBy([...diskMutations, ...mutationStorage], (mutation) => mutation.Name), + (x) => x.Name !== mutation.Name, + ); return ( <> diff --git a/tgui/packages/tgui/interfaces/DnaVault.jsx b/tgui/packages/tgui/interfaces/DnaVault.tsx similarity index 75% rename from tgui/packages/tgui/interfaces/DnaVault.jsx rename to tgui/packages/tgui/interfaces/DnaVault.tsx index 5ac7711412d06..2b6781d6cf747 100644 --- a/tgui/packages/tgui/interfaces/DnaVault.jsx +++ b/tgui/packages/tgui/interfaces/DnaVault.tsx @@ -1,28 +1,44 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, - Grid, LabeledList, ProgressBar, Section, + Stack, } from '../components'; import { Window } from '../layouts'; -export const DnaVault = (props) => { - const { act, data } = useBackend(); +type Data = { + animals_max: number; + animals: number; + choiceA: string; + choiceB: string; + completed: BooleanLike; + dna_max: number; + dna: number; + plants_max: number; + plants: number; + used: BooleanLike; +}; + +export function DnaVault(props) { + const { act, data } = useBackend(); const { - completed, - used, + animals_max, + animals, choiceA, choiceB, - dna, + completed, dna_max, - plants, + dna, plants_max, - animals, - animals_max, + plants, + used, } = data; + return ( @@ -50,37 +66,39 @@ export const DnaVault = (props) => { Applicable Gene Therapy Treatments - - + + + + + + )} ); -}; +} diff --git a/tgui/packages/tgui/interfaces/EightBallVote.tsx b/tgui/packages/tgui/interfaces/EightBallVote.tsx index 30ab7baae4800..f85b8724ffefb 100644 --- a/tgui/packages/tgui/interfaces/EightBallVote.tsx +++ b/tgui/packages/tgui/interfaces/EightBallVote.tsx @@ -2,50 +2,51 @@ import { BooleanLike } from 'common/react'; import { toTitleCase } from 'common/string'; import { useBackend } from '../backend'; -import { Box, Button, Grid, NoticeBox, Section } from '../components'; +import { Box, Button, NoticeBox, Section, Stack } from '../components'; import { Window } from '../layouts'; type Data = { - shaking: BooleanLike; - question: string; answers: Answer[]; + question: string; + shaking: BooleanLike; }; type Answer = { - answer: string; amount: number; + answer: string; selected: BooleanLike; }; -export const EightBallVote = (props) => { - const { act, data } = useBackend(); +export function EightBallVote(props) { + const { data } = useBackend(); const { shaking } = data; + return ( - {(!shaking && ( + {(shaking && ( No question is currently being asked. )) || } ); -}; +} -const EightBallVoteQuestion = (props) => { +function EightBallVoteQuestion(props) { const { act, data } = useBackend(); const { question, answers = [] } = data; + return (
    "{question}" - + {answers.map((answer) => ( - + {answer.amount} - + ))} - +
    ); -}; +} diff --git a/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.jsx b/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.tsx similarity index 73% rename from tgui/packages/tgui/interfaces/EmergencyShuttleConsole.jsx rename to tgui/packages/tgui/interfaces/EmergencyShuttleConsole.tsx index b7b09bdca6a84..04214e092d634 100644 --- a/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.jsx +++ b/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.tsx @@ -1,17 +1,34 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; -import { Box, Button, Grid, Section } from '../components'; +import { Box, Button, Section, Stack } from '../components'; import { Window } from '../layouts'; -export const EmergencyShuttleConsole = (props) => { - const { act, data } = useBackend(); +type Data = { + authorizations_remaining: number; + authorizations: Authorization[]; + emagged: BooleanLike; + enabled: BooleanLike; + engines_started: BooleanLike; + timer_str: string; +}; + +type Authorization = { + job: string; + name: string; +}; + +export function EmergencyShuttleConsole(props) { + const { act, data } = useBackend(); const { - timer_str, - enabled, + authorizations = [], + authorizations_remaining, emagged, + enabled, engines_started, - authorizations_remaining, - authorizations = [], + timer_str, } = data; + return ( @@ -29,41 +46,42 @@ export const EmergencyShuttleConsole = (props) => {
    act('abort')} - /> + > + Repeal All + } > - - + + + + + +
    @@ -71,7 +89,11 @@ export const EmergencyShuttleConsole = (props) => { } > - {authorizations.length > 0 ? ( + {authorizations.length === 0 ? ( + + No Active Authorizations + + ) : ( authorizations.map((authorization) => ( { {authorization.name} ({authorization.job}) )) - ) : ( - - No Active Authorizations - )}
    @@ -93,4 +111,4 @@ export const EmergencyShuttleConsole = (props) => {
    ); -}; +} diff --git a/tgui/packages/tgui/interfaces/ExperimentConfigure.jsx b/tgui/packages/tgui/interfaces/ExperimentConfigure.jsx index 0c632afd283b8..d91bc564e4449 100644 --- a/tgui/packages/tgui/interfaces/ExperimentConfigure.jsx +++ b/tgui/packages/tgui/interfaces/ExperimentConfigure.jsx @@ -109,7 +109,7 @@ export const ExperimentConfigure = (props) => { const { always_active, has_start_callback } = data; let techwebs = data.techwebs ?? []; - const experiments = sortBy((exp) => exp.name)(data.experiments ?? []); + const experiments = sortBy(data.experiments ?? [], (exp) => exp.name); // Group servers together by web let webs = new Map(); diff --git a/tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx b/tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx index af5bddf4d5bdf..e4951bd0041d2 100644 --- a/tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx +++ b/tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx @@ -229,8 +229,9 @@ export const DesignBrowser = (
    - {sortBy((category: Category) => category.title)( + {sortBy( Object.values(root.subcategories), + (category: Category) => category.title, ).map((category) => ( (
    {searchText.length > 0 ? ( - {sortBy((design: T) => design.name)( + {sortBy( Object.values(root.descendants), + (design: T) => design.name, ) .filter((design) => design.name @@ -290,8 +292,9 @@ export const DesignBrowser = ( ) : selectedCategory === ALL_CATEGORY ? ( - {sortBy((design: T) => design.name)( + {sortBy( Object.values(root.descendants), + (design: T) => design.name, ).map((design) => buildRecipeElement( design, @@ -380,8 +383,9 @@ const DesignBrowserTab = ( Object.entries(category.subcategories).length > 0 && selectedCategory === category.title && (
    - {sortBy((category: Category) => category.title)( + {sortBy( Object.values(category.subcategories), + (category: Category) => category.title, ).map((subcategory) => ( ( const body = ( - {sortBy((design: T) => design.name)(category.children).map((design) => + {sortBy(category.children, (design: T) => design.name).map((design) => buildRecipeElement( design, availableMaterials || {}, diff --git a/tgui/packages/tgui/interfaces/Fabrication/MaterialAccessBar.tsx b/tgui/packages/tgui/interfaces/Fabrication/MaterialAccessBar.tsx index 2936d93df3fb2..83923d5bd4896 100644 --- a/tgui/packages/tgui/interfaces/Fabrication/MaterialAccessBar.tsx +++ b/tgui/packages/tgui/interfaces/Fabrication/MaterialAccessBar.tsx @@ -55,7 +55,7 @@ export const MaterialAccessBar = (props: MaterialAccessBarProps) => { return ( - {sortBy((m: Material) => MATERIAL_RARITY[m.name])(availableMaterials).map( + {sortBy(availableMaterials, (m: Material) => MATERIAL_RARITY[m.name]).map( (material) => ( { const { act } = useBackend(); const { data } = useBackend(); const faxes = data.faxes - ? sortBy((sortFax: FaxInfo) => sortFax.fax_name)( + ? sortBy( data.syndicate_network ? data.faxes.filter((filterFax: FaxInfo) => filterFax.visible) : data.faxes.filter( (filterFax: FaxInfo) => filterFax.visible && !filterFax.syndicate_network, ), + (sortFax: FaxInfo) => sortFax.fax_name, ) : []; return ( diff --git a/tgui/packages/tgui/interfaces/Filteriffic.jsx b/tgui/packages/tgui/interfaces/Filteriffic.jsx index b13cddc34f438..09bd14264523d 100644 --- a/tgui/packages/tgui/interfaces/Filteriffic.jsx +++ b/tgui/packages/tgui/interfaces/Filteriffic.jsx @@ -155,10 +155,9 @@ const FilterFlagsEntry = (props) => { const filterInfo = data.filter_info; const flags = filterInfo[filterType]['flags']; - return map((bitField, flagName) => ( + return map(flags, (bitField, flagName) => ( act('modify_filter_value', { name: filterName, @@ -167,8 +166,11 @@ const FilterFlagsEntry = (props) => { }, }) } - /> - ))(flags); + key={flagName} + > + {flagName} + + )); }; const FilterDataEntry = (props) => { @@ -340,9 +342,9 @@ export const Filteriffic = (props) => { {!hasFilters ? ( No filters ) : ( - map((entry, key) => ( + map(filters, (entry, key) => ( - ))(filters) + )) )}
    diff --git a/tgui/packages/tgui/interfaces/FishCatalog.tsx b/tgui/packages/tgui/interfaces/FishCatalog.tsx index 01efc5e353176..7bb85054fb002 100644 --- a/tgui/packages/tgui/interfaces/FishCatalog.tsx +++ b/tgui/packages/tgui/interfaces/FishCatalog.tsx @@ -1,5 +1,4 @@ import { sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { classes } from 'common/react'; import { capitalize } from 'common/string'; import { useState } from 'react'; @@ -38,9 +37,7 @@ type FishCatalogData = { export const FishCatalog = (props) => { const { act, data } = useBackend(); const { fish_info, sponsored_by } = data; - const fish_by_name = flow([sortBy((fish: FishInfo) => fish.name)])( - fish_info || [], - ); + const fish_by_name = sortBy(fish_info || [], (fish: FishInfo) => fish.name); const [currentFish, setCurrentFish] = useState(null); return ( diff --git a/tgui/packages/tgui/interfaces/Gps.jsx b/tgui/packages/tgui/interfaces/Gps.jsx index 662335fcdc3b7..c12ba6a9efd7e 100644 --- a/tgui/packages/tgui/interfaces/Gps.jsx +++ b/tgui/packages/tgui/interfaces/Gps.jsx @@ -7,30 +7,36 @@ import { useBackend } from '../backend'; import { Box, Button, Icon, LabeledList, Section, Table } from '../components'; import { Window } from '../layouts'; -const coordsToVec = (coords) => map(parseFloat)(coords.split(', ')); +const coordsToVec = (coords) => map(coords.split(', '), parseFloat); export const Gps = (props) => { const { act, data } = useBackend(); const { currentArea, currentCoords, globalmode, power, tag, updating } = data; const signals = flow([ - map((signal, index) => { - // Calculate distance to the target. BYOND distance is capped to 127, - // that's why we roll our own calculations here. - const dist = - signal.dist && - Math.round( - vecLength( - vecSubtract(coordsToVec(currentCoords), coordsToVec(signal.coords)), - ), - ); - return { ...signal, dist, index }; - }), - sortBy( - // Signals with distance metric go first - (signal) => signal.dist === undefined, - // Sort alphabetically - (signal) => signal.entrytag, - ), + (signals) => + map(signals, (signal, index) => { + // Calculate distance to the target. BYOND distance is capped to 127, + // that's why we roll our own calculations here. + const dist = + signal.dist && + Math.round( + vecLength( + vecSubtract( + coordsToVec(currentCoords), + coordsToVec(signal.coords), + ), + ), + ); + return { ...signal, dist, index }; + }), + (signals) => + sortBy( + signals, + // Signals with distance metric go first + (signal) => signal.dist === undefined, + // Sort alphabetically + (signal) => signal.entrytag, + ), ])(data.signals || []); return ( diff --git a/tgui/packages/tgui/interfaces/HealthSensor.tsx b/tgui/packages/tgui/interfaces/HealthSensor.tsx new file mode 100644 index 0000000000000..fbff3aaa1eae0 --- /dev/null +++ b/tgui/packages/tgui/interfaces/HealthSensor.tsx @@ -0,0 +1,55 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../backend'; +import { AnimatedNumber, Button, ProgressBar, Section } from '../components'; +import { Window } from '../layouts'; + +type Data = { + health: number; + scanning: BooleanLike; + target: BooleanLike; +}; + +export const HealthSensor = (props) => { + const { act, data } = useBackend(); + const { health, scanning, target } = data; + + return ( + + +
    +
    +
    +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/Hypertorus/Gases.tsx b/tgui/packages/tgui/interfaces/Hypertorus/Gases.tsx index 8482bd665ec98..74457a365bb4e 100644 --- a/tgui/packages/tgui/interfaces/Hypertorus/Gases.tsx +++ b/tgui/packages/tgui/interfaces/Hypertorus/Gases.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { toFixed } from 'common/math'; import { useBackend } from 'tgui/backend'; import { @@ -90,10 +89,10 @@ const GasList = (props: GasListProps) => { } = props; const { start_power, start_cooling } = data; - const gases: HypertorusGas[] = flow([ - filter((gas: HypertorusGas) => gas.amount >= 0.01), - sortBy((gas: HypertorusGas) => -gas.amount), - ])(raw_gases); + const gases: HypertorusGas[] = sortBy( + filter(raw_gases, (gas) => gas.amount >= 0.01), + (gas) => -gas.amount, + ); if (stickyGases) { ensure_gases(gases, stickyGases); diff --git a/tgui/packages/tgui/interfaces/InfuserBook.tsx b/tgui/packages/tgui/interfaces/InfuserBook.tsx index 7266e7a5f86ed..70169b44651de 100644 --- a/tgui/packages/tgui/interfaces/InfuserBook.tsx +++ b/tgui/packages/tgui/interfaces/InfuserBook.tsx @@ -1,5 +1,4 @@ import { paginate, range } from 'common/collections'; -import { multiline } from 'common/string'; import { useState } from 'react'; import { useBackend } from '../backend'; @@ -35,7 +34,7 @@ const PAGE_HEIGHT = 30; const TIER2TIERDATA: TierData[] = [ { name: 'Lesser Mutant', - desc: multiline` + desc: ` Lesser Mutants usually have a smaller list of potential mutations, and do not have bonuses for infusing many organs. Common species, cosmetics, and things of that sort are here. Always available! @@ -44,7 +43,7 @@ const TIER2TIERDATA: TierData[] = [ }, { name: 'Regular Mutant', - desc: multiline` + desc: ` Regular Mutants all have bonuses for infusing DNA into yourself, and are common enough to find consistently in a shift. Always available! `, @@ -52,7 +51,7 @@ const TIER2TIERDATA: TierData[] = [ }, { name: 'Greater Mutant', - desc: multiline` + desc: ` Greater Mutants have stronger upsides and downsides along with their bonus, and are harder to find in a shift. Must be unlocked by first unlocking a DNA Mutant bonus of a lower tier. @@ -61,7 +60,7 @@ const TIER2TIERDATA: TierData[] = [ }, { name: 'Abberation', - desc: multiline` + desc: ` We've been able to get stronger mutants out of vatgrown specimen, henceforth named "Abberations". Abberations have either strong utility purpose, anomalous qualities, or deadly capabilities. diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx b/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx index 9b91ef348fa15..e243ef365b067 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx @@ -120,7 +120,8 @@ export class ComponentMenu extends Component { currentLimit: DEFAULT_COMPONENT_MENU_LIMIT, }) } - displayText={`Category: ${selectedTab}`} + selected={selectedTab} + placeholder="Category" color="transparent" className="IntegratedCircuit__BlueBorder" /> diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx b/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx index 2ea8ce922aa77..65d0814d8ce24 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx @@ -88,7 +88,7 @@ export const FUNDAMENTAL_DATA_TYPES = { color={'transparent'} options={data} onSelected={setValue} - displayText={value} + selected={value} menuWidth={large ? '200px' : undefined} /> ); diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.jsx b/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.jsx index d51c39714efc6..22f7c6ce1a84f 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.jsx +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.jsx @@ -39,8 +39,8 @@ export class ObjectComponent extends Component { if (dragPos) { act('set_component_coordinates', { component_id: index, - rel_x: dragPos.x, - rel_y: dragPos.y, + rel_x: this.roundToGrid(dragPos.x), + rel_y: this.roundToGrid(dragPos.y), }); } @@ -81,6 +81,12 @@ export class ObjectComponent extends Component { ); } + // Round the units to the grid (bypass if grid mode is off) + roundToGrid(input_value) { + if (!this.props.gridMode) return input_value; + return Math.round(input_value / 10) * 10; + } + render() { const { input_ports, @@ -99,14 +105,15 @@ export class ObjectComponent extends Component { onPortRightClick = noop, onPortMouseUp = noop, act = noop, + gridMode = true, ...rest } = this.props; const { startPos, dragPos } = this.state; let [x_pos, y_pos] = [x, y]; if (dragPos && startPos && startPos.x === x_pos && startPos.y === y_pos) { - x_pos = dragPos.x; - y_pos = dragPos.y; + x_pos = this.roundToGrid(dragPos.x); + y_pos = this.roundToGrid(dragPos.y); } // Assigned onto the ports diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx b/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx index 955e45da41be0..07a34d8a58ba2 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx @@ -15,7 +15,6 @@ import { VARIABLE_LIST, VARIABLE_NOT_A_LIST, } from './constants'; -import { multiline } from 'common/string'; export class VariableMenu extends Component { constructor(props) { @@ -97,7 +96,7 @@ export class VariableMenu extends Component { onMouseDown={(e) => handleMouseDownSetter(e, val)} color={val.color} disabled={!!val.is_list} - tooltip={multiline` + tooltip={` Drag me onto the circuit's grid to make a setter for this variable`} icon="pen" @@ -106,7 +105,7 @@ export class VariableMenu extends Component { + + + + ); +} + +function LaunchpadButtonPad(props) { + const { act } = useBackend(); + + return ( +
    + + {buttonConfigs.map((buttonRow, i) => ( + + {buttonRow.map((buttonConfig, j) => ( + + ))} + + ))} + +
    + ); +} + +function TargetingControls(props) { + const { act, data } = useBackend(); + const { x, y, range } = data; + + const inputConfigs = [ + { value: x, axis: 'x', icon: 'arrows-alt-h' }, + { value: y, axis: 'y', icon: 'arrows-alt-v' }, + ]; + + return ( +
    + {inputConfigs.map((inputConfig, i) => ( + + + + {inputConfig.axis.toUpperCase()} + + + + + act('set_pos', { + [inputConfig.axis]: value, + }) + } + step={1} + stepPixelSize={10} + value={inputConfig.value} + width="90px" + /> + + + ))} +
    + ); +} + +function DeliveryButtons(props) { + const { act } = useBackend(); + + return ( +
    + + + + + + + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/LibraryAdmin.tsx b/tgui/packages/tgui/interfaces/LibraryAdmin.tsx index f805a46c7fb9d..fd88fdc48fb2f 100644 --- a/tgui/packages/tgui/interfaces/LibraryAdmin.tsx +++ b/tgui/packages/tgui/interfaces/LibraryAdmin.tsx @@ -1,5 +1,4 @@ import { map, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { capitalize } from 'common/string'; import { useState } from 'react'; @@ -81,10 +80,14 @@ type Book = { category: string; title: string; id: number; +}; + +type AdminBook = Book & { + author_ckey: string; deleted: boolean; }; -type DisplayBook = Book & { +type DisplayAdminBook = AdminBook & { key: number; }; @@ -120,14 +123,18 @@ const SearchAndDisplay = (props) => { view_raw, show_deleted, } = data; - const books = flow([ - map((book, i) => ({ - ...book, - // Generate a unique id - key: i, - })), - sortBy((book) => book.key), - ])(pages); + const books = sortBy( + map( + pages, + (book, i) => + ({ + ...book, + // Generate a unique id + key: i, + }) as DisplayAdminBook, + ), + (book) => book.key, + ); return (
    diff --git a/tgui/packages/tgui/interfaces/LibraryConsole.jsx b/tgui/packages/tgui/interfaces/LibraryConsole.jsx index 83d034915b893..de10b3a2e86b0 100644 --- a/tgui/packages/tgui/interfaces/LibraryConsole.jsx +++ b/tgui/packages/tgui/interfaces/LibraryConsole.jsx @@ -1,5 +1,4 @@ import { map, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { classes } from 'common/react'; import { useState } from 'react'; @@ -136,14 +135,14 @@ export const Inventory = (props) => { export const InventoryDetails = (props) => { const { act, data } = useBackend(); - const inventory = flow([ - map((book, i) => ({ + const inventory = sortBy( + map(data.inventory, (book, i) => ({ ...book, // Generate a unique id key: i, })), - sortBy((book) => book.key), - ])(data.inventory); + (book) => book.key, + ); return (
    @@ -261,14 +260,14 @@ export const CheckoutEntries = (props) => { const CheckoutModal = (props) => { const { act, data } = useBackend(); - const inventory = flow([ - map((book, i) => ({ + const inventory = sortBy( + map(data.inventory, (book, i) => ({ ...book, // Generate a unique id key: i, })), - sortBy((book) => book.key), - ])(data.inventory); + (book) => book.key, + ); const [checkoutBook, setCheckoutBook] = useLocalState('CheckoutBook', false); const [bookName, setBookName] = useState('Insert Book name...'); @@ -283,7 +282,7 @@ const CheckoutModal = (props) => { over mb={1.7} width="100%" - displayText={bookName} + selected={bookName} options={inventory.map((book) => book.title)} value={bookName} onSelected={(e) => setBookName(e)} @@ -387,14 +386,14 @@ export const SearchAndDisplay = (props) => { params_changed, can_db_request, } = data; - const records = flow([ - map((record, i) => ({ + const records = sortBy( + map(data.pages, (record, i) => ({ ...record, // Generate a unique id key: i, })), - sortBy((record) => record.key), - ])(data.pages); + (record) => record.key, + ); return ( diff --git a/tgui/packages/tgui/interfaces/LibraryVisitor.jsx b/tgui/packages/tgui/interfaces/LibraryVisitor.jsx index 6b8edb380be46..cb27e42704d98 100644 --- a/tgui/packages/tgui/interfaces/LibraryVisitor.jsx +++ b/tgui/packages/tgui/interfaces/LibraryVisitor.jsx @@ -1,5 +1,4 @@ import { map, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { useBackend } from '../backend'; import { @@ -71,14 +70,14 @@ const SearchAndDisplay = (props) => { author, params_changed, } = data; - const records = flow([ - map((record, i) => ({ + const records = sortBy( + map(data.pages, (record, i) => ({ ...record, // Generate a unique id key: i, })), - sortBy((record) => record.key), - ])(data.pages); + (record) => record.key, + ); return (
    diff --git a/tgui/packages/tgui/interfaces/ListInputModal.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx similarity index 57% rename from tgui/packages/tgui/interfaces/ListInputModal.tsx rename to tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx index 8695ac842f72e..a56363f231097 100644 --- a/tgui/packages/tgui/interfaces/ListInputModal.tsx +++ b/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx @@ -7,35 +7,26 @@ import { KEY_ESCAPE, KEY_UP, KEY_Z, -} from '../../common/keycodes'; -import { useBackend } from '../backend'; -import { Autofocus, Button, Input, Section, Stack } from '../components'; -import { Window } from '../layouts'; -import { InputButtons } from './common/InputButtons'; -import { Loader } from './common/Loader'; +} from '../../../common/keycodes'; +import { useBackend } from '../../backend'; +import { Autofocus, Button, Input, Section, Stack } from '../../components'; +import { InputButtons } from '../common/InputButtons'; -type ListInputData = { - init_value: string; +type ListInputModalProps = { items: string[]; - large_buttons: boolean; + default_item: string; message: string; - timeout: number; - title: string; + on_selected: (entry: string) => void; + on_cancel: () => void; }; -export const ListInputModal = (props) => { - const { act, data } = useBackend(); - const { - items = [], - message = '', - init_value, - large_buttons, - timeout, - title, - } = data; - const [selected, setSelected] = useState(items.indexOf(init_value)); +export const ListInputModal = (props: ListInputModalProps) => { + const { items = [], default_item, message, on_selected, on_cancel } = props; + + const [selected, setSelected] = useState(items.indexOf(default_item)); const [searchBarVisible, setSearchBarVisible] = useState(items.length > 9); const [searchQuery, setSearchQuery] = useState(''); + // User presses up or down on keyboard // Simulates clicking an item const onArrowKey = (key: number) => { @@ -99,82 +90,77 @@ export const ListInputModal = (props) => { const filteredItems = items.filter((item) => item?.toLowerCase().includes(searchQuery.toLowerCase()), ); - // Dynamically changes the window height based on the message. - const windowHeight = - 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); // Grabs the cursor when no search bar is visible. if (!searchBarVisible) { setTimeout(() => document!.getElementById(selected.toString())?.focus(), 1); } return ( - - {timeout && } - { - const keyCode = window.event ? event.which : event.keyCode; - if (keyCode === KEY_DOWN || keyCode === KEY_UP) { - event.preventDefault(); - onArrowKey(keyCode); - } - if (keyCode === KEY_ENTER) { - event.preventDefault(); - act('submit', { entry: filteredItems[selected] }); - } - if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { - event.preventDefault(); - onLetterSearch(keyCode); - } - if (keyCode === KEY_ESCAPE) { - event.preventDefault(); - act('cancel'); - } - }} - > -
    onSearchBarToggle()} - /> +
    { + const keyCode = window.event ? event.which : event.keyCode; + if (keyCode === KEY_DOWN || keyCode === KEY_UP) { + event.preventDefault(); + onArrowKey(keyCode); + } + if (keyCode === KEY_ENTER) { + event.preventDefault(); + on_selected(filteredItems[selected]); + } + if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { + event.preventDefault(); + onLetterSearch(keyCode); + } + if (keyCode === KEY_ESCAPE) { + event.preventDefault(); + on_cancel(); + } + }} + buttons={ +
    - - + tooltipPosition="left" + onClick={() => onSearchBarToggle()} + /> + } + className="ListInput__Section" + fill + title={message} + > + + + + + {searchBarVisible && ( + + )} + + on_selected(filteredItems[selected])} + on_cancel={on_cancel} + /> + + +
    ); }; @@ -183,7 +169,7 @@ export const ListInputModal = (props) => { * If a search query is provided, filters the items. */ const ListDisplay = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onClick, onFocusSearch, searchBarVisible, selected } = props; @@ -227,7 +213,7 @@ const ListDisplay = (props) => { * Closing the bar defaults input to an empty string. */ const SearchBar = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onSearch, searchQuery, selected } = props; return ( diff --git a/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx new file mode 100644 index 0000000000000..29355ff5d213f --- /dev/null +++ b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx @@ -0,0 +1,44 @@ +import { useBackend } from '../../backend'; +import { Window } from '../../layouts'; +import { Loader } from '../common/Loader'; +import { ListInputModal } from './ListInputModal'; + +type ListInputData = { + init_value: string; + items: string[]; + large_buttons: boolean; + message: string; + timeout: number; + title: string; +}; + +export const ListInputWindow = () => { + const { act, data } = useBackend(); + const { + items = [], + message = '', + init_value, + large_buttons, + timeout, + title, + } = data; + + // Dynamically changes the window height based on the message. + const windowHeight = + 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); + + return ( + + {timeout && } + + act('submit', { entry })} + on_cancel={() => act('cancel')} + /> + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/LootPanel/GroupedContents.tsx b/tgui/packages/tgui/interfaces/LootPanel/GroupedContents.tsx new file mode 100644 index 0000000000000..5bfecce0b8ae9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/GroupedContents.tsx @@ -0,0 +1,47 @@ +import { createSearch } from 'common/string'; +import { useMemo } from 'react'; + +import { Flex } from '../../components'; +import { LootBox } from './LootBox'; +import { SearchGroup, SearchItem } from './types'; + +type Props = { + contents: SearchItem[]; + searchText: string; +}; + +export function GroupedContents(props: Props) { + const { contents, searchText } = props; + + // limitations: items with different stack counts, charges etc. + const contentsByPath = useMemo(() => { + const acc: Record = {}; + + for (let i = 0; i < contents.length; i++) { + const item = contents[i]; + if (item.path) { + if (!acc[item.path]) { + acc[item.path] = []; + } + acc[item.path].push(item); + } else { + acc[item.ref] = [item]; + } + } + return acc; + }, [contents]); + + const filteredContents: SearchGroup[] = Object.entries(contentsByPath) + .filter(createSearch(searchText, ([_, items]) => items[0].name)) + .map(([_, items]) => ({ amount: items.length, item: items[0] })); + + return ( + + {filteredContents.map((group) => ( + + + + ))} + + ); +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx b/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx new file mode 100644 index 0000000000000..9a078f3f755ae --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx @@ -0,0 +1,36 @@ +import { DmIcon, Icon, Image } from '../../components'; +import { SearchItem } from './types'; + +type Props = { + item: SearchItem; +}; + +export function IconDisplay(props: Props) { + const { + item: { icon, icon_state }, + } = props; + + const fallback = ; + + if (!icon) { + return fallback; + } + + if (icon === 'n/a') { + return ; + } + + if (icon_state) { + return ( + + ); + } + + return ; +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx b/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx new file mode 100644 index 0000000000000..137021b34ef77 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx @@ -0,0 +1,60 @@ +import { capitalizeAll, capitalizeFirst } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Tooltip } from '../../components'; +import { IconDisplay } from './IconDisplay'; +import { SearchGroup, SearchItem } from './types'; + +type Props = + | { + item: SearchItem; + } + | { + group: SearchGroup; + }; + +export function LootBox(props: Props) { + const { act } = useBackend(); + + let amount = 0; + let item: SearchItem; + if ('group' in props) { + amount = props.group.amount; + item = props.group.item; + } else { + item = props.item; + } + + const name = !item.name + ? '???' + : capitalizeFirst(item.name.split(' ')[0]).slice(0, 5); + + return ( + +
    +
    + act('grab', { + alt: event.altKey, + ctrl: event.ctrlKey, + ref: item.ref, + shift: event.shiftKey, + }) + } + onContextMenu={(event) => { + event.preventDefault(); + act('grab', { + right: true, + ref: item.ref, + }); + }} + > + + {amount > 1 &&
    {amount}
    } +
    + {name} +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx b/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx new file mode 100644 index 0000000000000..4241d36dc0aa2 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx @@ -0,0 +1,28 @@ +import { createSearch } from 'common/string'; + +import { Flex } from '../../components'; +import { LootBox } from './LootBox'; +import { SearchItem } from './types'; + +type Props = { + contents: SearchItem[]; + searchText: string; +}; + +export function RawContents(props: Props) { + const { contents, searchText } = props; + + const filteredContents = contents.filter( + createSearch(searchText, (item: SearchItem) => item.name), + ); + + return ( + + {filteredContents.map((item) => ( + + + + ))} + + ); +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/index.tsx b/tgui/packages/tgui/interfaces/LootPanel/index.tsx new file mode 100644 index 0000000000000..bc6330b1806f7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/index.tsx @@ -0,0 +1,76 @@ +import { KEY } from 'common/keys'; +import { BooleanLike } from 'common/react'; +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Button, Input, Section, Stack } from '../../components'; +import { Window } from '../../layouts'; +import { GroupedContents } from './GroupedContents'; +import { RawContents } from './RawContents'; +import { SearchItem } from './types'; + +type Data = { + contents: SearchItem[]; + searching: BooleanLike; +}; + +export function LootPanel(props) { + const { act, data } = useBackend(); + const { contents = [], searching } = data; + + const [grouping, setGrouping] = useState(true); + const [searchText, setSearchText] = useState(''); + + const total = contents.length ? contents.length - 1 : 0; + + return ( + + { + if (event.key === KEY.Escape) { + Byond.sendMessage('close'); + } + }} + > +
    + + setSearchText(value)} + placeholder="Search" + /> + + +
    +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/types.ts b/tgui/packages/tgui/interfaces/LootPanel/types.ts new file mode 100644 index 0000000000000..f17b02b0c1381 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/types.ts @@ -0,0 +1,13 @@ +export type SearchItem = { + name: string; + path: string; + ref: string; +} & Partial<{ + icon: string; + icon_state: string; +}>; + +export type SearchGroup = { + amount: number; + item: SearchItem; +}; diff --git a/tgui/packages/tgui/interfaces/MODsuit.tsx b/tgui/packages/tgui/interfaces/MODsuit.tsx index 874f1b4774dee..8752fc3c8741a 100644 --- a/tgui/packages/tgui/interfaces/MODsuit.tsx +++ b/tgui/packages/tgui/interfaces/MODsuit.tsx @@ -226,7 +226,7 @@ const ConfigureListEntry = (props) => { const { act } = useBackend(); return ( act('configure', { diff --git a/tgui/packages/tgui/interfaces/MafiaPanel.tsx b/tgui/packages/tgui/interfaces/MafiaPanel.tsx index d00a498062ccb..179ef4d38094c 100644 --- a/tgui/packages/tgui/interfaces/MafiaPanel.tsx +++ b/tgui/packages/tgui/interfaces/MafiaPanel.tsx @@ -1,6 +1,5 @@ import { BooleanLike, classes } from 'common/react'; import { decodeHtmlEntities } from 'common/string'; -import { multiline } from 'common/string'; import { useState } from 'react'; import { useBackend } from '../backend'; @@ -124,7 +123,7 @@ export const MafiaPanelData = (props) => { color="transparent" icon="address-book" tooltipPosition="bottom-start" - tooltip={multiline` + tooltip={` This is the list of roles in the game. You can press the question mark to get a quick blurb about the role itself.`} @@ -140,7 +139,7 @@ export const MafiaPanelData = (props) => { color="transparent" icon="pencil" tooltipPosition="bottom-start" - tooltip={multiline` + tooltip={` This is your notes, anything you want to write can be saved for future reference. You can also send it to chat with a button.`} @@ -234,7 +233,7 @@ const MafiaLobby = (props) => {
    - {sortBy((tempmat: Material) => tempmat.rarity)(materials).map( + {sortBy(materials, (tempmat: Material) => tempmat.rarity).map( (material, i) => (
    diff --git a/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx b/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx index 31ed70080cb17..e1ea1b81ef5b2 100644 --- a/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx +++ b/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx @@ -228,8 +228,8 @@ const ModuleDetailsBasic = (props) => { label="Integrity" buttons={ + + + ))} + ); }; @@ -473,17 +525,17 @@ const SnowflakeSyringe = (props) => { } = props.module.snowflake; return ( <> - + {`${syringe} of ${max_syringe}`} - + {`${reagents} of ${total_reagents} units`} - +
    - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/NtosArcade.tsx b/tgui/packages/tgui/interfaces/NtosArcade.tsx new file mode 100644 index 0000000000000..ea63e62e037bb --- /dev/null +++ b/tgui/packages/tgui/interfaces/NtosArcade.tsx @@ -0,0 +1,178 @@ +import { BooleanLike } from 'common/react'; + +import { resolveAsset } from '../assets'; +import { useBackend } from '../backend'; +import { + AnimatedNumber, + Box, + Button, + Divider, + LabeledList, + NoticeBox, + ProgressBar, + Section, + Stack, +} from '../components'; +import { NtosWindow } from '../layouts'; + +type Data = { + BossID: string; + GameActive: BooleanLike; + Hitpoints: number; + PauseState: BooleanLike; + PlayerHitpoints: number; + PlayerMP: number; + Status: string; + TicketCount: number; +}; + +export function NtosArcade(props) { + return ( + + +
    + + + + + + + + + +
    +
    +
    + ); +} + +function PlayerStats(props) { + const { data } = useBackend(); + const { PauseState, PlayerHitpoints, PlayerMP, Status } = data; + + return ( + <> + + + + {PlayerHitpoints}HP + + + + + {PlayerMP}MP + + + + + {Status} + + ); +} + +function BossBar(props) { + const { data } = useBackend(); + const { BossID, Hitpoints } = data; + + return ( + <> + + + HP + + +
    + +
    + + ); +} + +function BottomButtons(props) { + const { act, data } = useBackend(); + const { GameActive, PauseState, TicketCount } = data; + + return ( + <> + + + + + + + + + = 1 ? 'good' : 'normal'}> + Earned Tickets: {TicketCount} + + + ); +} diff --git a/tgui/packages/tgui/interfaces/NtosCard.tsx b/tgui/packages/tgui/interfaces/NtosCard.tsx index 7c3991a487c26..5997aa0e91c12 100644 --- a/tgui/packages/tgui/interfaces/NtosCard.tsx +++ b/tgui/packages/tgui/interfaces/NtosCard.tsx @@ -240,7 +240,7 @@ const TemplateDropdown = (props) => { { return templates[path]; })} @@ -249,6 +249,7 @@ const TemplateDropdown = (props) => { name: sel, }) } + selected="None" /> diff --git a/tgui/packages/tgui/interfaces/NtosCrewManifest.jsx b/tgui/packages/tgui/interfaces/NtosCrewManifest.jsx index 5deb1d27c8a7a..74485397c2df4 100644 --- a/tgui/packages/tgui/interfaces/NtosCrewManifest.jsx +++ b/tgui/packages/tgui/interfaces/NtosCrewManifest.jsx @@ -20,7 +20,7 @@ export const NtosCrewManifest = (props) => { /> } > - {map((entries, department) => ( + {map(manifest, (entries, department) => (
    {entries.map((entry) => ( @@ -31,7 +31,7 @@ export const NtosCrewManifest = (props) => { ))}
    - ))(manifest)} + ))}
    diff --git a/tgui/packages/tgui/interfaces/NtosEmojipedia.tsx b/tgui/packages/tgui/interfaces/NtosEmojipedia.tsx index 3852e90ac26fc..d9e6c7233eef9 100644 --- a/tgui/packages/tgui/interfaces/NtosEmojipedia.tsx +++ b/tgui/packages/tgui/interfaces/NtosEmojipedia.tsx @@ -3,7 +3,7 @@ import { createSearch } from 'common/string'; import { useState } from 'react'; import { useBackend } from '../backend'; -import { Button, Image, Input, Section } from '../components'; +import { Button, Image, Input, Section, Tooltip } from '../components'; import { NtosWindow } from '../layouts'; type Data = { @@ -44,15 +44,15 @@ export const NtosEmojipedia = (props) => { } > {filteredEmojis.map((emoji) => ( - { - copyText(emoji.name); - }} - /> + + { + copyText(emoji.name); + }} + /> + ))} diff --git a/tgui/packages/tgui/interfaces/NtosMessenger/index.tsx b/tgui/packages/tgui/interfaces/NtosMessenger/index.tsx index 852ca62cc5594..896ca90d60270 100644 --- a/tgui/packages/tgui/interfaces/NtosMessenger/index.tsx +++ b/tgui/packages/tgui/interfaces/NtosMessenger/index.tsx @@ -100,7 +100,8 @@ const ContactsScreen = (props: any) => { const [searchUser, setSearchUser] = useState(''); - const sortByUnreads = sortBy((chat) => chat.unread_messages); + const sortByUnreads = (array: NtChat[]) => + sortBy(array, (chat) => chat.unread_messages); const searchChatByName = createSearch( searchUser, diff --git a/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx b/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx index 0bfdafc7b6202..489c443f0c1ad 100644 --- a/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx +++ b/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { scale, toFixed } from 'common/math'; import { BooleanLike } from 'common/react'; import { createSearch } from 'common/string'; @@ -70,20 +69,22 @@ export const NtosNetDownloader = (props) => { searchItem, (program) => program.filedesc, ); - const items = flow([ + let items = searchItem.length > 0 ? // If we have a query, search everything for it. - filter(search) + filter(programs, search) : // Otherwise, show respective programs for the category. - filter((program: ProgramData) => program.category === selectedCategory), - // This sorts all programs in the lists by name and compatibility - sortBy( - (program: ProgramData) => !program.compatible, - (program: ProgramData) => program.filedesc, - ), + filter(programs, (program) => program.category === selectedCategory); + // This sorts all programs in the lists by name and compatibility + items = sortBy( + items, + (program: ProgramData) => !program.compatible, + (program: ProgramData) => program.filedesc, + ); + if (!emagged) { // This filters the list to only contain verified programs - !emagged && filter((program: ProgramData) => program.verifiedsource === 1), - ])(programs); + items = filter(items, (program) => program.verifiedsource === 1); + } const disk_free_space = downloading ? disk_size - Number(toFixed(disk_used + downloadcompletion)) : disk_size - disk_used; diff --git a/tgui/packages/tgui/interfaces/NtosRoboControl.jsx b/tgui/packages/tgui/interfaces/NtosRoboControl.jsx index 20c70220d3697..9b55c90a45628 100644 --- a/tgui/packages/tgui/interfaces/NtosRoboControl.jsx +++ b/tgui/packages/tgui/interfaces/NtosRoboControl.jsx @@ -2,7 +2,6 @@ import { useBackend, useSharedState } from '../backend'; import { Box, Button, - Dropdown, LabeledList, ProgressBar, Section, @@ -71,19 +70,22 @@ export const NtosRoboControl = (props) => { + Drone Pings + {dronepingtypes.map((ping_type) => ( + + ))} {drones?.map((drone) => ( diff --git a/tgui/packages/tgui/interfaces/NtosScipaper.jsx b/tgui/packages/tgui/interfaces/NtosScipaper.jsx index 3866ccab24ce7..2af2cd12f43f9 100644 --- a/tgui/packages/tgui/interfaces/NtosScipaper.jsx +++ b/tgui/packages/tgui/interfaces/NtosScipaper.jsx @@ -93,7 +93,7 @@ const PaperPublishing = (props) => { act('select_file', { selected_uid: fileList[ordfile_name], @@ -117,7 +117,7 @@ const PaperPublishing = (props) => { act('select_experiment', { selected_expath: expList[experiment_name], @@ -141,7 +141,7 @@ const PaperPublishing = (props) => { String(number))} - displayText={tier ? String(tier) : '-'} + selected={String(tier)} onSelected={(new_tier) => act('select_tier', { selected_tier: Number(new_tier), @@ -165,7 +165,7 @@ const PaperPublishing = (props) => { act('select_partner', { selected_partner: allowedPartners[new_partner], diff --git a/tgui/packages/tgui/interfaces/NtosVirtualPet.tsx b/tgui/packages/tgui/interfaces/NtosVirtualPet.tsx index 7b61f2b566e54..1894aa703d667 100644 --- a/tgui/packages/tgui/interfaces/NtosVirtualPet.tsx +++ b/tgui/packages/tgui/interfaces/NtosVirtualPet.tsx @@ -268,7 +268,7 @@ const PetTricks = (props) => { UpdateSequence(index, selected)} /> @@ -354,7 +354,7 @@ const Customization = (props) => {
    { return selected_hat.hat_name; })} @@ -369,7 +369,7 @@ const Customization = (props) => {
    { return possible_color.color_name; })} diff --git a/tgui/packages/tgui/interfaces/NuclearBomb.jsx b/tgui/packages/tgui/interfaces/NuclearBomb.tsx similarity index 64% rename from tgui/packages/tgui/interfaces/NuclearBomb.jsx rename to tgui/packages/tgui/interfaces/NuclearBomb.tsx index 81b2e622e9d50..5cda6d97cbb40 100644 --- a/tgui/packages/tgui/interfaces/NuclearBomb.jsx +++ b/tgui/packages/tgui/interfaces/NuclearBomb.tsx @@ -1,32 +1,40 @@ -import { classes } from 'common/react'; +import { BooleanLike, classes } from 'common/react'; import { useBackend } from '../backend'; -import { Box, Button, Flex, Grid, Icon } from '../components'; +import { Box, Button, Icon, Stack } from '../components'; import { Window } from '../layouts'; +type Data = { + disk_present: BooleanLike; + status1: string; + status2: string; + anchored: BooleanLike; +}; + +const KEYPAD = [ + ['1', '4', '7', 'C'], + ['2', '5', '8', '0'], + ['3', '6', '9', 'E'], +] as const; + // This ui is so many manual overrides and !important tags // and hand made width sets that changing pretty much anything // is going to require a lot of tweaking it get it looking correct again // I'm sorry, but it looks bangin -export const NukeKeypad = (props) => { +export function NukeKeypad(props) { const { act } = useBackend(); - const keypadKeys = [ - ['1', '4', '7', 'C'], - ['2', '5', '8', '0'], - ['3', '6', '9', 'E'], - ]; + return ( - - {keypadKeys.map((keyColumn) => ( - + + {KEYPAD.map((keyColumn) => ( + {keyColumn.map((key) => ( ))} - + ))} - + ); -}; +} + +export function NuclearBomb(props) { + const { act, data } = useBackend(); + const { status1, status2 } = data; -export const NuclearBomb = (props) => { - const { act, data } = useBackend(); - const { anchored, disk_present, status1, status2 } = data; return ( - - + + {status1} - - + + {status2} - - + + - - + + ); -}; +} diff --git a/tgui/packages/tgui/interfaces/Orbit/JobIcon.tsx b/tgui/packages/tgui/interfaces/Orbit/JobIcon.tsx new file mode 100644 index 0000000000000..70c3ae0f5dc02 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/JobIcon.tsx @@ -0,0 +1,57 @@ +import { DmIcon, Icon } from '../../components'; +import { JOB2ICON } from '../common/JobToIcon'; +import { Antagonist, Observable } from './types'; + +type Props = { + item: Observable | Antagonist; +}; + +type IconSettings = { + dmi: string; + transform: string; +}; + +const normalIcon: IconSettings = { + dmi: 'icons/mob/huds/hud.dmi', + transform: 'scale(2.3) translateX(8px) translateY(1px)', +}; + +const antagIcon: IconSettings = { + dmi: 'icons/mob/huds/antag_hud.dmi', + transform: 'scale(1.8) translateX(-16px) translateY(7px)', +}; + +export function JobIcon(props: Props) { + const { item } = props; + + let iconSettings: IconSettings; + if ('antag' in item) { + iconSettings = antagIcon; + } else { + iconSettings = normalIcon; + } + + // We don't need to cast here but typescript isn't smart enough to know that + const { icon = '', job = '' } = item; + + return ( +
    + {icon === 'borg' ? ( + + ) : ( +
    + +
    + )} +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitBlade.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitBlade.tsx new file mode 100644 index 0000000000000..07c5a1c08f6c7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitBlade.tsx @@ -0,0 +1,188 @@ +import { capitalizeFirst, toTitleCase } from 'common/string'; +import { useContext } from 'react'; + +import { useBackend } from '../../backend'; +import { + Button, + Icon, + ProgressBar, + Section, + Stack, + Tooltip, +} from '../../components'; +import { OrbitContext } from '.'; +import { HEALTH, VIEWMODE } from './constants'; +import { getDepartmentByJob, getDisplayName } from './helpers'; +import { JobIcon } from './JobIcon'; +import { OrbitData } from './types'; + +/** Slide open menu with more info about the current observable */ +export function OrbitBlade(props) { + const { data } = useBackend(); + const { orbiting } = data; + + const { setBladeOpen } = useContext(OrbitContext); + + return ( + + +
    setBladeOpen(false)} + /> + } + color="label" + title="Orbit Settings" + > + Keep in mind: Orbit does not update automatically. You will need to + click the "Refresh" button to see the latest data. +
    +
    + + + + {!!orbiting && ( + + + + )} +
    + ); +} + +function ViewModeSelector(props) { + const { viewMode, setViewMode } = useContext(OrbitContext); + + return ( +
    + + + Change the color and sorting scheme of observable items. + + + {Object.entries(VIEWMODE).map(([key, value]) => ( + + ))} + +
    + ); +} + +function OrbitInfo(props) { + const { data } = useBackend(); + + const { orbiting } = data; + if (!orbiting) return; + + const { name, full_name, health, job } = orbiting; + + let department; + if ('job' in orbiting && !!job) { + department = getDepartmentByJob(job); + } + + let showAFK; + if ('client' in orbiting && !orbiting.client) { + showAFK = true; + } + + return ( +
    + + + {toTitleCase(getDisplayName(full_name, name))} + {showAFK && ( + + + + )} + + + {!!job && ( + + + + + + + {job} + + {!!department && ( + + {capitalizeFirst(department)} + + )} + + + )} + {health !== undefined && ( + + + + )} + + + +
    + ); +} + +function HealthDisplay(props: { health: number }) { + const { health } = props; + + let icon = 'heart'; + let howDead; + switch (true) { + case health <= HEALTH.Ruined: + howDead = `Very Dead: ${health}`; + icon = 'skull'; + break; + case health <= HEALTH.Dead: + howDead = `Dead: ${health}`; + icon = 'heart-broken'; + break; + case health <= HEALTH.Crit: + howDead = `Health critical: ${health}`; + icon = 'tired'; + break; + case health <= HEALTH.Bad: + howDead = `Bad: ${health}`; + icon = 'heartbeat'; + break; + } + + return ( + + + + + + {howDead || ( + + )} + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitCollapsible.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitCollapsible.tsx new file mode 100644 index 0000000000000..fa5e78bd1f725 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitCollapsible.tsx @@ -0,0 +1,80 @@ +import { useContext } from 'react'; + +import { Collapsible, Flex, Tooltip } from '../../components'; +import { OrbitContext } from '.'; +import { VIEWMODE } from './constants'; +import { + isJobOrNameMatch, + sortByDepartment, + sortByDisplayName, +} from './helpers'; +import { OrbitItem } from './OrbitItem'; +import { OrbitTooltip } from './OrbitTooltip'; +import { Observable } from './types'; + +type Props = { + color?: string; + section: Observable[]; + title: string; +}; + +/** + * Displays a collapsible with a map of observable items. + * Filters the results if there is a provided search query. + */ +export function OrbitCollapsible(props: Props) { + const { color, section = [], title } = props; + + const { autoObserve, searchQuery, viewMode } = useContext(OrbitContext); + + const filteredSection = section.filter((observable) => + isJobOrNameMatch(observable, searchQuery), + ); + + if (viewMode === VIEWMODE.Department) { + filteredSection.sort(sortByDepartment); + } else { + filteredSection.sort(sortByDisplayName); + } + + if (!filteredSection.length) { + return; + } + + return ( + + + {filteredSection.map((item) => { + const content = ( + + ); + + if (!item.health && !item.extra) { + return content; + } + + return ( + } + key={item.ref} + position="bottom-start" + > + {content} + + ); + })} + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitContent.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitContent.tsx new file mode 100644 index 0000000000000..91502644faade --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitContent.tsx @@ -0,0 +1,99 @@ +import { toTitleCase } from 'common/string'; + +import { useBackend } from '../../backend'; +import { NoticeBox, Section, Stack, Table, Tooltip } from '../../components'; +import { ANTAG2COLOR } from './constants'; +import { getAntagCategories } from './helpers'; +import { OrbitCollapsible } from './OrbitCollapsible'; +import { AntagGroup, Observable, OrbitData } from './types'; + +type ContentSection = { + content: Observable[]; + title: string; + color?: string; +}; + +/** + * The primary content display for points of interest. + * Renders a scrollable section replete collapsibles for each + * observable group. + */ +export function OrbitContent(props) { + const { act, data } = useBackend(); + const { antagonists = [], critical = [] } = data; + + let antagGroups: AntagGroup[] = []; + if (antagonists.length) { + antagGroups = getAntagCategories(antagonists); + } + + const sections: readonly ContentSection[] = [ + { + color: 'purple', + content: data.deadchat_controlled, + title: 'Deadchat Controlled', + }, + { + color: 'blue', + content: data.alive, + title: 'Alive', + }, + { + content: data.dead, + title: 'Dead', + }, + { + content: data.ghosts, + title: 'Ghosts', + }, + { + content: data.misc, + title: 'Misc', + }, + { + content: data.npcs, + title: 'NPCs', + }, + ]; + + return ( +
    + + {critical.map((crit) => ( + + act('orbit', { ref: crit.ref })} + > + + + {toTitleCase(crit.full_name)} + {crit.extra} + +
    +
    +
    + ))} + + {antagGroups.map(([title, members]) => ( + + ))} + + {sections.map((section) => ( + + ))} +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitItem.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitItem.tsx new file mode 100644 index 0000000000000..992904988ece4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitItem.tsx @@ -0,0 +1,57 @@ +import { capitalizeFirst } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, Flex, Icon, Stack } from '../../components'; +import { getDisplayColor, getDisplayName } from './helpers'; +import { JobIcon } from './JobIcon'; +import { Antagonist, Observable, OrbitData, ViewMode } from './types'; + +type Props = { + item: Observable | Antagonist; + autoObserve: boolean; + viewMode: ViewMode; + color: string | undefined; +}; + +/** Each button on the observable section */ +export function OrbitItem(props: Props) { + const { item, autoObserve, viewMode, color } = props; + const { full_name, icon, job, name, orbiters, ref } = item; + + const { act, data } = useBackend(); + const { orbiting } = data; + + const selected = ref === orbiting?.ref; + const validIcon = !!job && !!icon && icon !== 'hudunknown'; + + return ( + act('orbit', { auto_observe: autoObserve, ref })} + style={{ + display: 'flex', + }} + > + {validIcon && } + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitSearchBar.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitSearchBar.tsx new file mode 100644 index 0000000000000..c83512c39c731 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitSearchBar.tsx @@ -0,0 +1,119 @@ +import { useContext } from 'react'; + +import { useBackend } from '../../backend'; +import { Button, Icon, Input, Section, Stack } from '../../components'; +import { OrbitContext } from '.'; +import { VIEWMODE } from './constants'; +import { isJobOrNameMatch, sortByOrbiters } from './helpers'; +import { OrbitData } from './types'; + +/** Search bar for the orbit ui. Has a few buttons to switch between view modes and auto-observe */ +export function OrbitSearchBar(props) { + const { + autoObserve, + bladeOpen, + searchQuery, + viewMode, + setAutoObserve, + setBladeOpen, + setSearchQuery, + setViewMode, + } = useContext(OrbitContext); + + const { act, data } = useBackend(); + + /** Gets a list of Observables, then filters the most relevant to orbit */ + function orbitMostRelevant() { + const mostRelevant = [ + data.alive, + data.antagonists, + data.critical, + data.deadchat_controlled, + data.dead, + data.ghosts, + data.misc, + data.npcs, + ] + .flat() + .filter((observable) => isJobOrNameMatch(observable, searchQuery)) + .sort(sortByOrbiters)[0]; + + if (mostRelevant !== undefined) { + act('orbit', { + ref: mostRelevant.ref, + auto_observe: autoObserve, + }); + } + } + + /** Iterates through the view modes and switches to the next one */ + function swapViewMode() { + const thisIndex = Object.values(VIEWMODE).indexOf(viewMode); + const nextIndex = (thisIndex + 1) % Object.values(VIEWMODE).length; + + setViewMode(Object.values(VIEWMODE)[nextIndex]); + } + + const viewModeTitle = Object.entries(VIEWMODE).find( + ([_key, value]) => value === viewMode, + )?.[0]; + + return ( +
    + + + + + + setSearchQuery(value)} + placeholder="Search..." + value={searchQuery} + /> + + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Orbit/OrbitTooltip.tsx b/tgui/packages/tgui/interfaces/Orbit/OrbitTooltip.tsx new file mode 100644 index 0000000000000..6c06838be4f16 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/OrbitTooltip.tsx @@ -0,0 +1,54 @@ +import { LabeledList, NoticeBox } from '../../components'; +import { Antagonist, Observable } from './types'; + +type Props = { + item: Observable | Antagonist; +}; + +/** Displays some info on the mob as a tooltip. */ +export function OrbitTooltip(props: Props) { + const { item } = props; + const { extra, full_name, health, job } = item; + + let antag; + if ('antag' in item) { + antag = item.antag; + } + + const extraInfo = extra?.split(':'); + const displayHealth = !!health && health >= 0 ? `${health}%` : 'Critical'; + const showAFK = 'client' in item && !item.client; + + return ( + <> + + Last Known Data + + + {extraInfo ? ( + + {extraInfo[1]} + + ) : ( + <> + {!!full_name && ( + {full_name} + )} + {!!job && !antag && ( + {job} + )} + {!!antag && ( + {antag} + )} + {!!health && ( + + {displayHealth} + + )} + + )} + {showAFK && Away} + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Orbit/constants.ts b/tgui/packages/tgui/interfaces/Orbit/constants.ts index 2ef6b605eb659..d683561f3825b 100644 --- a/tgui/packages/tgui/interfaces/Orbit/constants.ts +++ b/tgui/packages/tgui/interfaces/Orbit/constants.ts @@ -13,6 +13,60 @@ export const ANTAG2COLOR = { 'Invasive Overgrowth': 'green', } as const; +type Department = { + color: string; + trims: string[]; +}; + +export const DEPARTMENT2COLOR: Record = { + cargo: { + color: 'brown', + trims: ['Bitrunner', 'Cargo Technician', 'Shaft Miner', 'Quartermaster'], + }, + command: { + color: 'blue', + trims: ['Captain', 'Head of Personnel'], + }, + engineering: { + color: 'orange', + trims: ['Atmospheric Technician', 'Chief Engineer', 'Station Engineer'], + }, + medical: { + color: 'teal', + trims: [ + 'Chemist', + 'Chief Medical Officer', + 'Coroner', + 'Medical Doctor', + 'Paramedic', + ], + }, + science: { + color: 'pink', + trims: ['Geneticist', 'Research Director', 'Roboticist', 'Scientist'], + }, + security: { + color: 'red', + trims: ['Detective', 'Head of Security', 'Security Officer', 'Warden'], + }, + service: { + color: 'green', + trims: [ + 'Bartender', + 'Botanist', + 'Chaplain', + 'Chef', + 'Clown', + 'Cook', + 'Curator', + 'Janitor', + 'Lawyer', + 'Mime', + 'Psychologist', + ], + }, +}; + export const THREAT = { Low: 1, Medium: 5, @@ -22,4 +76,14 @@ export const THREAT = { export const HEALTH = { Good: 69, // nice Average: 19, + Bad: 0, + Crit: -30, + Dead: -100, + Ruined: -200, +} as const; + +export const VIEWMODE = { + Health: 'heart', + Orbiters: 'ghost', + Department: 'id-badge', } as const; diff --git a/tgui/packages/tgui/interfaces/Orbit/helpers.ts b/tgui/packages/tgui/interfaces/Orbit/helpers.ts index 8ad071c699b70..9263ea599615a 100644 --- a/tgui/packages/tgui/interfaces/Orbit/helpers.ts +++ b/tgui/packages/tgui/interfaces/Orbit/helpers.ts @@ -1,29 +1,34 @@ -import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; - -import { HEALTH, THREAT } from './constants'; -import type { AntagGroup, Antagonist, Observable } from './types'; +import { DEPARTMENT2COLOR, HEALTH, THREAT, VIEWMODE } from './constants'; +import { AntagGroup, Antagonist, Observable, ViewMode } from './types'; /** Return a map of strings with each antag in its antag_category */ -export const getAntagCategories = (antagonists: Antagonist[]) => { - const categories: Record = {}; +export function getAntagCategories(antagonists: Antagonist[]): AntagGroup[] { + const categories = new Map(); - antagonists.map((player) => { + for (const player of antagonists) { const { antag_group } = player; - if (!categories[antag_group]) { - categories[antag_group] = []; + if (!categories.has(antag_group)) { + categories.set(antag_group, []); } + categories.get(antag_group)!.push(player); + } - categories[antag_group].push(player); + const sorted = Array.from(categories.entries()).sort((a, b) => { + const lowerA = a[0].toLowerCase(); + const lowerB = b[0].toLowerCase(); + + if (lowerA < lowerB) return -1; + if (lowerA > lowerB) return 1; + return 0; }); - return sortBy(([key]) => key)(Object.entries(categories)); -}; + return sorted; +} /** Returns a disguised name in case the person is wearing someone else's ID */ -export const getDisplayName = (full_name: string, name?: string) => { - if (!name) { +export function getDisplayName(full_name: string, nickname?: string): string { + if (!nickname) { return full_name; } @@ -32,30 +37,36 @@ export const getDisplayName = (full_name: string, name?: string) => { full_name.match(/\(as /) || full_name.match(/^Unknown/) ) { - return name; + return nickname; } // return only the name before the first ' [' or ' (' return `"${full_name.split(/ \[| \(/)[0]}"`; -}; +} -export const getMostRelevant = ( - searchQuery: string, - observables: Observable[][], -): Observable => { - return flow([ - // Filters out anything that doesn't match search - filter((observable) => - isJobOrNameMatch(observable, searchQuery), - ), - // Sorts descending by orbiters - sortBy((observable) => -(observable.orbiters || 0)), - // Makes a single Observables list for an easy search - ])(observables.flat())[0]; -}; +/** Returns the department the player is in */ +export function getDepartmentByJob(job: string): string | undefined { + const withoutParenthesis = job.replace(/ \(.*\)/, ''); + + for (const department in DEPARTMENT2COLOR) { + if (DEPARTMENT2COLOR[department].trims.includes(withoutParenthesis)) { + return department; + } + } +} + +/** Gets department color for a job */ +function getDepartmentColor(job: string | undefined): string { + if (!job) return 'grey'; + + const department = getDepartmentByJob(job); + if (!department) return 'grey'; + + return DEPARTMENT2COLOR[department].color; +} /** Returns the display color for certain health percentages */ -const getHealthColor = (health: number) => { +function getHealthColor(health: number): string { switch (true) { case health > HEALTH.Good: return 'good'; @@ -64,10 +75,10 @@ const getHealthColor = (health: number) => { default: return 'bad'; } -}; +} /** Returns the display color based on orbiter numbers */ -const getThreatColor = (orbiters = 0) => { +function getThreatColor(orbiters = 0): string { switch (true) { case orbiters > THREAT.High: return 'violet'; @@ -78,32 +89,43 @@ const getThreatColor = (orbiters = 0) => { default: return 'good'; } -}; +} /** Displays color for buttons based on the health or orbiter count. */ -export const getDisplayColor = ( +export function getDisplayColor( item: Observable, - heatMap: boolean, - color?: string, -) => { - const { health, orbiters } = item; + mode: ViewMode, + override?: string, +): string { + const { job, health, orbiters } = item; + + // Things like blob camera, etc if (typeof health !== 'number') { - return color ? 'good' : 'grey'; + return override ? 'good' : 'grey'; } - if (heatMap) { - return getThreatColor(orbiters); + + // Players that are AFK + if ('client' in item && !item.client) { + return 'grey'; } - return getHealthColor(health); -}; + + switch (mode) { + case VIEWMODE.Orbiters: + return getThreatColor(orbiters); + case VIEWMODE.Department: + return getDepartmentColor(job); + default: + return getHealthColor(health); + } +} /** Checks if a full name or job title matches the search. */ -export const isJobOrNameMatch = ( +export function isJobOrNameMatch( observable: Observable, searchQuery: string, -) => { - if (!searchQuery) { - return true; - } +): boolean { + if (!searchQuery) return true; + const { full_name, job } = observable; return ( @@ -111,4 +133,46 @@ export const isJobOrNameMatch = ( job?.toLowerCase().includes(searchQuery?.toLowerCase()) || false ); -}; +} + +/** Sorts by department */ +export function sortByDepartment(poiA: Observable, poiB: Observable): number { + const departmentA = (poiA.job && getDepartmentByJob(poiA.job)) || 'unknown'; + const departmentB = (poiB.job && getDepartmentByJob(poiB.job)) || 'unknown'; + + if (departmentA < departmentB) return -1; + if (departmentA > departmentB) return 1; + return 0; +} + +/** Sorts based on real name */ +export function sortByDisplayName(poiA: Observable, poiB: Observable): number { + const nameA = getDisplayName(poiA.full_name, poiA.name) + .replace(/^"/, '') + .toLowerCase(); + const nameB = getDisplayName(poiB.full_name, poiB.name) + .replace(/^"/, '') + .toLowerCase(); + + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; + } + return 0; +} + +/** Sorts by most orbiters */ +export function sortByOrbiters(poiA: Observable, poiB: Observable): number { + const orbitersA = poiA.orbiters || 0; + const orbitersB = poiB.orbiters || 0; + + if (orbitersA < orbitersB) { + return -1; + } + if (orbitersA > orbitersB) { + return 1; + } + return 0; +} diff --git a/tgui/packages/tgui/interfaces/Orbit/index.tsx b/tgui/packages/tgui/interfaces/Orbit/index.tsx index 0d992d981a81c..d537548107cba 100644 --- a/tgui/packages/tgui/interfaces/Orbit/index.tsx +++ b/tgui/packages/tgui/interfaces/Orbit/index.tsx @@ -1,310 +1,68 @@ -import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; -import { capitalizeFirst, multiline } from 'common/string'; -import { useBackend, useLocalState } from 'tgui/backend'; -import { - Button, - Collapsible, - Icon, - Input, - LabeledList, - NoticeBox, - Section, - Stack, -} from 'tgui/components'; +import { createContext, Dispatch, SetStateAction, useState } from 'react'; +import { Stack } from 'tgui/components'; import { Window } from 'tgui/layouts'; -import { JOB2ICON } from '../common/JobToIcon'; -import { ANTAG2COLOR } from './constants'; -import { - getAntagCategories, - getDisplayColor, - getDisplayName, - getMostRelevant, - isJobOrNameMatch, -} from './helpers'; -import type { AntagGroup, Antagonist, Observable, OrbitData } from './types'; +import { VIEWMODE } from './constants'; +import { OrbitBlade } from './OrbitBlade'; +import { OrbitContent } from './OrbitContent'; +import { OrbitSearchBar } from './OrbitSearchBar'; +import { ViewMode } from './types'; -export const Orbit = (props) => { - return ( - - - - - - - -
    - -
    -
    -
    -
    -
    - ); -}; - -/** Controls filtering out the list of observables via search */ -const ObservableSearch = (props) => { - const { act, data } = useBackend(); - const { - alive = [], - antagonists = [], - deadchat_controlled = [], - dead = [], - ghosts = [], - misc = [], - npcs = [], - } = data; - - const [autoObserve, setAutoObserve] = useLocalState( - 'autoObserve', - false, - ); - const [heatMap, setHeatMap] = useLocalState('heatMap', false); - const [searchQuery, setSearchQuery] = useLocalState( - 'searchQuery', - '', - ); - - /** Gets a list of Observables, then filters the most relevant to orbit */ - const orbitMostRelevant = (searchQuery: string) => { - const mostRelevant = getMostRelevant(searchQuery, [ - alive, - antagonists, - deadchat_controlled, - dead, - ghosts, - misc, - npcs, - ]); - - if (mostRelevant !== undefined) { - act('orbit', { - ref: mostRelevant.ref, - auto_observe: autoObserve, - }); - } - }; - - return ( -
    - - - - - - orbitMostRelevant(value)} - onInput={(event, value) => setSearchQuery(value)} - placeholder="Search..." - value={searchQuery} - /> - - - -
    - ); -}; - -/** - * The primary content display for points of interest. - * Renders a scrollable section replete with subsections for each - * observable group. - */ -const ObservableContent = (props) => { - const { data } = useBackend(); - const { - alive = [], - antagonists = [], - deadchat_controlled = [], - dead = [], - ghosts = [], - misc = [], - npcs = [], - } = data; - - let collatedAntagonists: AntagGroup[] = []; - - if (antagonists.length) { - collatedAntagonists = getAntagCategories(antagonists); - } - - return ( - - {collatedAntagonists?.map(([title, antagonists]) => { - return ( - - ); - })} - - - - - - - - ); -}; +export function Orbit(props) { + const [autoObserve, setAutoObserve] = useState(false); + const [bladeOpen, setBladeOpen] = useState(false); + const [searchQuery, setSearchQuery] = useState(''); + const [viewMode, setViewMode] = useState(VIEWMODE.Health); -/** - * Displays a collapsible with a map of observable items. - * Filters the results if there is a provided search query. - */ -const ObservableSection = (props: { - color?: string; - section: Observable[]; - title: string; -}) => { - const { color, section = [], title } = props; - - if (!section.length) { - return null; - } - - const [searchQuery] = useLocalState('searchQuery', ''); - - const filteredSection: Observable[] = flow([ - filter((observable) => - isJobOrNameMatch(observable, searchQuery), - ), - sortBy((observable) => - getDisplayName(observable.full_name, observable.name) - .replace(/^"/, '') - .toLowerCase(), - ), - ])(section); - - if (!filteredSection.length) { - return null; - } - - return ( - - - {filteredSection.map((poi, index) => { - return ; - })} - - - ); -}; - -/** Renders an observable button that has tooltip info for living Observables*/ -const ObservableItem = (props: { color?: string; item: Observable }) => { - const { act } = useBackend(); - const { color, item } = props; - const { extra, full_name, job, health, name, orbiters, ref } = item; - - const [autoObserve] = useLocalState('autoObserve', false); - const [heatMap] = useLocalState('heatMap', false); + const dynamicWidth = bladeOpen ? 650 : 400; return ( - - ); -}; - -/** Displays some info on the mob as a tooltip. */ -const ObservableTooltip = (props: { item: Observable | Antagonist }) => { - const { item } = props; - const { extra, full_name, health, job } = item; - let antag; - if ('antag' in item) { - antag = item.antag; - } - - const extraInfo = extra?.split(':'); - const displayHealth = !!health && health >= 0 ? `${health}%` : 'Critical'; - - return ( - <> - - Last Known Data - - - {extraInfo ? ( - - {extraInfo[1]} - - ) : ( - <> - {!!full_name && ( - {full_name} - )} - {!!job && !antag && ( - {job} - )} - {!!antag && ( - {antag} + + + + + + + + + + + + + + {bladeOpen && ( + + + )} - {!!health && ( - - {displayHealth} - - )} - - )} - - + + + + ); +} + +type Context = { + autoObserve: boolean; + setAutoObserve: Dispatch>; + bladeOpen: boolean; + setBladeOpen: Dispatch>; + searchQuery: string; + setSearchQuery: Dispatch>; + viewMode: ViewMode; + setViewMode: Dispatch>; }; + +export const OrbitContext = createContext({} as Context); diff --git a/tgui/packages/tgui/interfaces/Orbit/types.ts b/tgui/packages/tgui/interfaces/Orbit/types.ts index dfbcf4afa6185..ffeea321a3c81 100644 --- a/tgui/packages/tgui/interfaces/Orbit/types.ts +++ b/tgui/packages/tgui/interfaces/Orbit/types.ts @@ -1,3 +1,7 @@ +import { BooleanLike } from 'common/react'; + +import { VIEWMODE } from './constants'; + export type Antagonist = Observable & { antag: string; antag_group: string }; export type AntagGroup = [string, Antagonist[]]; @@ -5,19 +9,33 @@ export type AntagGroup = [string, Antagonist[]]; export type OrbitData = { alive: Observable[]; antagonists: Antagonist[]; + critical: Critical[]; dead: Observable[]; deadchat_controlled: Observable[]; ghosts: Observable[]; misc: Observable[]; npcs: Observable[]; + orbiting: Observable | null; }; export type Observable = { - extra?: string; full_name: string; - health?: number; - job?: string; - name?: string; - orbiters?: number; + ref: string; + // Optionals +} & Partial<{ + client: BooleanLike; + extra: string; + health: number; + icon: string; + job: string; + name: string; + orbiters: number; +}>; + +type Critical = { + extra: string; + full_name: string; ref: string; }; + +export type ViewMode = (typeof VIEWMODE)[keyof typeof VIEWMODE]; diff --git a/tgui/packages/tgui/interfaces/PersonalCrafting.tsx b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx index 58ba4d81708bd..166ab59b44ece 100644 --- a/tgui/packages/tgui/interfaces/PersonalCrafting.tsx +++ b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { BooleanLike, classes } from 'common/react'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -183,44 +182,44 @@ export const PersonalCrafting = (props) => { const [activeType, setFoodType] = useState( Object.keys(craftability).length ? 'Can Make' : data.foodtypes[0], ); - const material_occurences = flow([ - sortBy((material) => -material.occurences), - ])(data.material_occurences); + const material_occurences = sortBy( + data.material_occurences, + (material) => -material.occurences, + ); const [activeMaterial, setMaterial] = useState( material_occurences[0].atom_id, ); const [tabMode, setTabMode] = useState(0); const searchName = createSearch(searchText, (item: Recipe) => item.name); - let recipes = flow([ - filter( - (recipe) => - // If craftable only is selected, then filter by craftability - (!display_craftable_only || Boolean(craftability[recipe.ref])) && - // Ignore categories and types when searching - (searchText.length > 0 || - // Is foodtype mode and the active type matches - (tabMode === TABS.foodtype && - mode === MODE.cooking && - ((activeType === 'Can Make' && Boolean(craftability[recipe.ref])) || - recipe.foodtypes?.includes(activeType))) || - // Is material mode and the active material or catalysts match - (tabMode === TABS.material && - Object.keys(recipe.reqs).includes(activeMaterial)) || - // Is category mode and the active categroy matches - (tabMode === TABS.category && - ((activeCategory === 'Can Make' && - Boolean(craftability[recipe.ref])) || - recipe.category === activeCategory))), - ), - sortBy((recipe) => [ - activeCategory === 'Can Make' - ? 99 - Object.keys(recipe.reqs).length - : Number(craftability[recipe.ref]), - recipe.name.toLowerCase(), - ]), - ])(data.recipes); + let recipes = filter( + data.recipes, + (recipe) => + // If craftable only is selected, then filter by craftability + (!display_craftable_only || Boolean(craftability[recipe.ref])) && + // Ignore categories and types when searching + (searchText.length > 0 || + // Is foodtype mode and the active type matches + (tabMode === TABS.foodtype && + mode === MODE.cooking && + ((activeType === 'Can Make' && Boolean(craftability[recipe.ref])) || + recipe.foodtypes?.includes(activeType))) || + // Is material mode and the active material or catalysts match + (tabMode === TABS.material && + Object.keys(recipe.reqs).includes(activeMaterial)) || + // Is category mode and the active categroy matches + (tabMode === TABS.category && + ((activeCategory === 'Can Make' && + Boolean(craftability[recipe.ref])) || + recipe.category === activeCategory))), + ); + recipes = sortBy(recipes, (recipe) => [ + activeCategory === 'Can Make' + ? 99 - Object.keys(recipe.reqs).length + : Number(craftability[recipe.ref]), + recipe.name.toLowerCase(), + ]); if (searchText.length > 0) { - recipes = recipes.filter(searchName); + recipes = filter(recipes, searchName); } const canMake = ['Can Make']; const categories = canMake @@ -707,13 +706,33 @@ const RecipeContentCompact = ({ item, craftable, busy, mode }) => { ? 'utensils' : 'hammer' } - iconSpin={busy ? 1 : 0} + iconSpin={!!busy} onClick={() => act('make', { recipe: item.ref, }) } /> + {!!item.mass_craftable && ( + - - ); - })} + + + ); + }, + )} @@ -186,6 +199,17 @@ const ChoicedSelection = (props: { ); }; +const searchInCatalog = (searchText = '', catalog: Record) => { + let items = Object.entries(catalog); + if (searchText) { + items = filter( + items, + createSearch(searchText, ([name, _icon]) => name), + ); + } + return items; +}; + const GenderButton = (props: { handleSetGender: (gender: Gender) => void; gender: Gender; @@ -348,10 +372,11 @@ const createSetRandomization = }); }; -const sortPreferences = sortBy<[string, unknown]>(([featureId, _]) => { - const feature = features[featureId]; - return feature?.name; -}); +const sortPreferences = (array: [string, unknown][]) => + sortBy(array, ([featureId, _]) => { + const feature = features[featureId]; + return feature?.name; + }); export const PreferenceList = (props: { act: typeof sendAct; @@ -431,22 +456,20 @@ export const getRandomization = ( const { data } = useBackend(); - return Object.fromEntries( - filterMap(Object.keys(preferences), (preferenceKey) => { - if (serverData.random.randomizable.indexOf(preferenceKey) === -1) { - return undefined; - } - - if (!randomBodyEnabled) { - return undefined; - } + if (!randomBodyEnabled) { + return {}; + } - return [ - preferenceKey, - data.character_preferences.randomization[preferenceKey] || - RandomSetting.Disabled, - ]; - }), + return Object.fromEntries( + map( + filter(Object.keys(preferences), (key) => + serverData.random.randomizable.includes(key), + ), + (key) => [ + key, + data.character_preferences.randomization[key] || RandomSetting.Disabled, + ], + ), ); }; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx index c145b7eb3db34..2dde5ab60cc5a 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx @@ -1,4 +1,4 @@ -import { filterMap } from 'common/collections'; +import { filter } from 'common/collections'; import { useState } from 'react'; import { useBackend } from '../../backend'; @@ -23,13 +23,9 @@ function getCorrespondingPreferences( relevant_preferences: Record, ) { return Object.fromEntries( - filterMap(Object.keys(relevant_preferences), (key) => { - if (!customization_options.includes(key)) { - return undefined; - } - - return [key, relevant_preferences[key]]; - }), + filter(Object.entries(relevant_preferences), ([key, value]) => + customization_options.includes(key), + ), ); } diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx index 4152e2d77c196..0620f22da3a95 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx @@ -1,6 +1,6 @@ import { exhaustiveCheck } from 'common/exhaustive'; -import { Dropdown, Icon } from '../../components'; +import { Dropdown } from '../../components'; import { RandomSetting } from './data'; const options = [ @@ -48,12 +48,13 @@ export const RandomizationButton = (props: { color={color} {...dropdownProps} clipSelectedText={false} - displayText={} + icon="dice-d20" options={options} noChevron onSelected={setValue} menuWidth="120px" width={1.85} + selected="None" /> ); }; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/abductor.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/abductor.ts index cc77194f0cbcb..789e5e9823a15 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/abductor.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/abductor.ts @@ -1,18 +1,16 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Abductor: Antagonist = { key: 'abductor', name: 'Abductor', description: [ - multiline` + ` Abductors are technologically advanced alien society set on cataloging all species in the system. Unfortunately for their subjects their methods are quite invasive. `, - multiline` + ` You and a partner will become the abductor scientist and agent duo. As an agent, abduct unassuming victims and bring them back to your UFO. As a scientist, scout out victims for your agent, keep them safe, and diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/blob.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/blob.ts index 99861d530caf4..92cd5bdc447c8 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/blob.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/blob.ts @@ -1,8 +1,6 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; -export const BLOB_MECHANICAL_DESCRIPTION = multiline` +export const BLOB_MECHANICAL_DESCRIPTION = ` The blob infests the station and destroys everything in its path, including hull, fixtures, and creatures. Spread your mass, collect resources, and consume the entire station. Make sure to prepare your defenses, because the diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/blobinfection.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/blobinfection.ts index 33bc8405d49b7..d8a5f135fed9b 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/blobinfection.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/blobinfection.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { BLOB_MECHANICAL_DESCRIPTION } from './blob'; @@ -7,7 +5,7 @@ const BlobInfection: Antagonist = { key: 'blobinfection', name: 'Blob Infection', description: [ - multiline` + ` At any point in the middle of the shift, be strucken with an infection that will turn you into the terrifying blob. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/bloodbrother.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/bloodbrother.ts index 176cd39a7ea48..56cbcbfc97e1f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/bloodbrother.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/bloodbrother.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const BloodBrother: Antagonist = { key: 'bloodbrother', name: 'Blood Brother', description: [ - multiline` + ` Team up with other crew members as blood brothers to combine the strengths of your departments, break each other out of prison, and overwhelm the station. diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/changeling.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/changeling.ts index 2c9698d0bda21..9124a07063e0c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/changeling.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/changeling.ts @@ -1,8 +1,6 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; -export const CHANGELING_MECHANICAL_DESCRIPTION = multiline` +export const CHANGELING_MECHANICAL_DESCRIPTION = ` Transform yourself or others into different identities, and buy from an arsenal of biological weaponry with the DNA you collect. `; @@ -11,7 +9,7 @@ const Changeling: Antagonist = { key: 'changeling', name: 'Changeling', description: [ - multiline` + ` A highly intelligent alien predator that is capable of altering their shape to flawlessly resemble a human. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/changelingmidround.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/changelingmidround.ts index 90692d2824321..8324bdb85865a 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/changelingmidround.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/changelingmidround.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { CHANGELING_MECHANICAL_DESCRIPTION } from './changeling'; @@ -7,7 +5,7 @@ const ChangelingMidround: Antagonist = { key: 'changelingmidround', name: 'Space Changeling', description: [ - multiline` + ` A midround changeling does not receive a crew identity, instead arriving from space. This will be more difficult than being a round-start changeling! `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clownoperative.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clownoperative.ts index f32c6c6d3b0f2..61f874a2e938f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clownoperative.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clownoperative.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { OPERATIVE_MECHANICAL_DESCRIPTION } from './operative'; @@ -7,7 +5,7 @@ const ClownOperative: Antagonist = { key: 'clownoperative', name: 'Clown Operative', description: [ - multiline` + ` Honk! You have been chosen, for better or worse to join the Syndicate Clown Operative strike team. Your mission, whether or not you choose to tickle it, is to honk Nanotrasen's most advanced research facility! diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/cultist.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/cultist.ts index 252f7e65b63d7..c5cfaf61c2f65 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/cultist.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/cultist.ts @@ -1,19 +1,17 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Cultist: Antagonist = { key: 'cultist', name: 'Cultist', description: [ - multiline` + ` The Geometer of Blood, Nar-Sie, has sent a number of her followers to Space Station 13. As a cultist, you have an abundance of cult magics at your disposal, something for all situations. You must work with your brethren to summon an avatar of your eldritch goddess! `, - multiline` + ` Armed with blood magic, convert crew members to the Blood Cult, sacrifice those who get in the way, and summon Nar-Sie. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/fugitive.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/fugitive.ts index 1d7158484a101..f05a96c2ec46a 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/fugitive.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/fugitive.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Fugitive: Antagonist = { key: 'fugitive', name: 'Fugitive', description: [ - multiline` + ` Wherever you come from, you're being hunted. You have 10 minutes to prepare before fugitive hunters arrive and start hunting you and your friends down! `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/glitch.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/glitch.ts index 227ad99b02d6c..3d269c54ca4b4 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/glitch.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/glitch.ts @@ -1,16 +1,14 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Glitch: Antagonist = { key: 'glitch', name: 'Glitch', description: [ - multiline` + ` The virtual domain is a dangerous place for bitrunners. Make it so. `, - multiline` + ` You are a short-term antagonist, a glitch in the system. Use martial arts \ and lethal weaponry to terminate organics. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/headrevolutionary.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/headrevolutionary.ts index 7ef4908368aed..0a1d644266f00 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/headrevolutionary.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/headrevolutionary.ts @@ -1,8 +1,6 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; -export const REVOLUTIONARY_MECHANICAL_DESCRIPTION = multiline` +export const REVOLUTIONARY_MECHANICAL_DESCRIPTION = ` Armed with a flash, convert as many people to the revolution as you can. Kill or exile all heads of staff on the station. `; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/heretic.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/heretic.ts index 7d378e6c850dd..8c2d631bd58a8 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/heretic.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/heretic.ts @@ -1,8 +1,6 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; -export const HERETIC_MECHANICAL_DESCRIPTION = multiline` +export const HERETIC_MECHANICAL_DESCRIPTION = ` Find hidden influences and sacrifice crew members to gain magical powers and ascend as one of several paths. `; @@ -11,7 +9,7 @@ const Heretic: Antagonist = { key: 'heretic', name: 'Heretic', description: [ - multiline` + ` Forgotten, devoured, gutted. Humanity has forgotten the eldritch forces of decay, but the mansus veil has weakened. We will make them taste fear again... diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/loneoperative.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/loneoperative.ts index b9330e415477c..3f8ac5c5b7616 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/loneoperative.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/loneoperative.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { OPERATIVE_MECHANICAL_DESCRIPTION } from './operative'; @@ -7,7 +5,7 @@ const LoneOperative: Antagonist = { key: 'loneoperative', name: 'Lone Operative', description: [ - multiline` + ` A solo nuclear operative that has a higher chance of spawning the longer the nuclear authentication disk stays in one place. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/malfai.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/malfai.ts index 614e97447f776..03aadd752c61f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/malfai.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/malfai.ts @@ -1,8 +1,6 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; -export const MALF_AI_MECHANICAL_DESCRIPTION = multiline` +export const MALF_AI_MECHANICAL_DESCRIPTION = ` With a law zero to complete your objectives at all costs, combine your omnipotence and malfunction modules to wreak havoc across the station. Go delta to destroy the station and all those who opposed you. diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/malfaimidround.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/malfaimidround.ts index 9b0cd861f13d0..84e52b43dc12b 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/malfaimidround.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/malfaimidround.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { MALF_AI_MECHANICAL_DESCRIPTION } from './malfai'; @@ -7,7 +5,7 @@ const MalfAIMidround: Antagonist = { key: 'malfaimidround', name: 'Value Drifted AI', description: [ - multiline` + ` A form of malfunctioning AI that is given to existing AIs in the middle of the shift. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/nightmare.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/nightmare.ts index 4f317ff0b4887..90046dd625e10 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/nightmare.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/nightmare.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Nightmare: Antagonist = { key: 'nightmare', name: 'Nightmare', description: [ - multiline` + ` Use your light eater to break sources of light to survive and thrive. Jaunt through the darkness and seek your prey with night vision. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/obsessed.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/obsessed.ts index 9e38e37cfe153..8d4c98139872b 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/obsessed.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/obsessed.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Obsessed: Antagonist = { key: 'obsessed', name: 'Obsessed', description: [ - multiline` + ` You're obsessed with someone! Your obsession may begin to notice their personal items are stolen and their coworkers have gone missing, but will they realize they are your next victim in time? diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/operative.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/operative.ts index 2b179a2bd6719..a8182de9e0318 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/operative.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/operative.ts @@ -1,8 +1,6 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; -export const OPERATIVE_MECHANICAL_DESCRIPTION = multiline` +export const OPERATIVE_MECHANICAL_DESCRIPTION = ` Retrieve the nuclear authentication disk, use it to activate the nuclear fission explosive, and destroy the station. `; @@ -11,7 +9,7 @@ const Operative: Antagonist = { key: 'operative', name: 'Nuclear Operative', description: [ - multiline` + ` Congratulations, agent. You have been chosen to join the Syndicate Nuclear Operative strike team. Your mission, whether or not you choose to accept it, is to destroy Nanotrasen's most advanced research facility! diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/operativemidround.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/operativemidround.ts index cf79eae9bdc48..7497c6442fcc4 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/operativemidround.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/operativemidround.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { OPERATIVE_MECHANICAL_DESCRIPTION } from './operative'; @@ -7,7 +5,7 @@ const OperativeMidround: Antagonist = { key: 'operativemidround', name: 'Nuclear Assailant', description: [ - multiline` + ` A form of nuclear operative that is offered to ghosts in the middle of the shift. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/paradoxclone.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/paradoxclone.ts index 9217c3aeb1334..1456df3ec6e5d 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/paradoxclone.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/paradoxclone.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const ParadoxClone: Antagonist = { key: 'paradoxclone', name: 'Paradox Clone', description: [ - multiline` + ` A freak time-space anomaly has teleported you into another reality! Now you have to find your counterpart and kill and replace them. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/provocateur.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/provocateur.ts index cd8ef1a380f4c..1d2879c867594 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/provocateur.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/provocateur.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { REVOLUTIONARY_MECHANICAL_DESCRIPTION } from './headrevolutionary'; @@ -7,7 +5,7 @@ const Provocateur: Antagonist = { key: 'provocateur', name: 'Provocateur', description: [ - multiline` + ` A form of head revolutionary that can activate when joining an ongoing shift. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/revenant.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/revenant.ts index e9fdf3c178db3..241b52b3e4022 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/revenant.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/revenant.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Revenant: Antagonist = { key: 'revenant', name: 'Revenant', description: [ - multiline` + ` Become the mysterious revenant. Break windows, overload lights, and eat the crew's life force, all while talking to your old community of disgruntled ghosts. diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentiencepotionspawn.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentiencepotionspawn.ts index 6b4cad30e18b5..e69db3bec337a 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentiencepotionspawn.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentiencepotionspawn.ts @@ -1,20 +1,18 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const SentientCreature: Antagonist = { key: 'sentiencepotionspawn', name: 'Sentient Creature', description: [ - multiline` + ` Either by cosmic happenstance, or due to crew's shenanigans, you have been given sentience! `, - multiline` - This is a blanket preference. The more benign ones include random human - level intelligence events, the cargorilla, and creatures uplifted via sentience - potions. The less friendly ones include the regal rat, and the boosted + ` + This is a blanket preference. The more benign ones include random human + level intelligence events, the cargorilla, and creatures uplifted via sentience + potions. The less friendly ones include the regal rat, and the boosted mining elite mobs. `, ], diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentientdisease.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentientdisease.ts index f2b2be6ca7860..a9c11eda72910 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentientdisease.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/sentientdisease.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const SentientDisease: Antagonist = { key: 'sentientdisease', name: 'Sentient Disease', description: [ - multiline` + ` Mutate and spread yourself and infect as much of the crew as possible with a deadly plague of your own creation. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spacedragon.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spacedragon.ts index 79e55a0060d68..4a11cc94d118c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spacedragon.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spacedragon.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const SpaceDragon: Antagonist = { key: 'spacedragon', name: 'Space Dragon', description: [ - multiline` + ` Become a ferocious space dragon. Breathe fire, summon an army of space carps, crush walls, and terrorize the station. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spaceninja.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spaceninja.ts index aee97dbdd2309..e6db1b96f9753 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spaceninja.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spaceninja.ts @@ -1,17 +1,15 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const SpaceNinja: Antagonist = { key: 'spaceninja', name: 'Space Ninja', description: [ - multiline` + ` The Spider Clan practice a sort of augmentation of human flesh in order to achieve a more perfect state of being and follow Postmodern Space Bushido. `, - multiline` + ` Become a conniving space ninja, equipped with a katana, gloves to hack into airlocks and APCs, a suit to make you go near-invisible, as well as a variety of abilities in your kit. Hack into arrest consoles diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spy.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spy.ts index 395baf8791504..b004b972d447d 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spy.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/spy.ts @@ -1,19 +1,17 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Spy: Antagonist = { key: 'spy', name: 'Spy', description: [ - multiline` + ` Your mission, should you choose to accept it: Infiltrate Space Station 13. Disguise yourself as a member of their crew and steal vital equipment. Should you be caught or killed, your employer will disavow any knowledge of your actions. Good luck agent. `, - multiline` + ` Complete Spy Bounties to earn rewards from your employer. Use these rewards to sow chaos and mischief! `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/stowawaychangeling.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/stowawaychangeling.ts index 59049ca39feea..20ba22ee074f5 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/stowawaychangeling.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/stowawaychangeling.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { CHANGELING_MECHANICAL_DESCRIPTION } from './changeling'; @@ -7,7 +5,7 @@ const Stowaway_Changeling: Antagonist = { key: 'stowawaychangeling', name: 'Stowaway Changeling', description: [ - multiline` + ` A Changeling that found its way onto the shuttle unbeknownst to the crewmembers on board. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/syndicatesleeperagent.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/syndicatesleeperagent.ts index cce7f70ea6f81..4a680e5d347c9 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/syndicatesleeperagent.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/syndicatesleeperagent.ts @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; import { TRAITOR_MECHANICAL_DESCRIPTION } from './traitor'; @@ -7,7 +5,7 @@ const SyndicateSleeperAgent: Antagonist = { key: 'syndicatesleeperagent', name: 'Syndicate Sleeper Agent', description: [ - multiline` + ` A form of traitor that can activate at any point in the middle of the shift. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/traitor.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/traitor.ts index b815039cbb655..ccb63919982ed 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/traitor.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/traitor.ts @@ -1,8 +1,6 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; -export const TRAITOR_MECHANICAL_DESCRIPTION = multiline` +export const TRAITOR_MECHANICAL_DESCRIPTION = ` Start with an uplink to purchase your gear and take on your sinister objectives. Ascend through the ranks and become an infamous legend. `; @@ -11,7 +9,7 @@ const Traitor: Antagonist = { key: 'traitor', name: 'Traitor', description: [ - multiline` + ` An unpaid debt. A score to be settled. Maybe you were just in the wrong place at the wrong time. Whatever the reasons, you were selected to infiltrate Space Station 13. diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/wizard.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/wizard.ts index 67118697da00e..62530a26f67c0 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/wizard.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/wizard.ts @@ -1,8 +1,6 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; -export const WIZARD_MECHANICAL_DESCRIPTION = multiline` +export const WIZARD_MECHANICAL_DESCRIPTION = ` Choose between a variety of powerful spells in order to cause chaos among Space Station 13. `; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/xenomorph.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/xenomorph.ts index c759696926457..a9a1960f3b2ce 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/xenomorph.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/xenomorph.ts @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { Antagonist, Category } from '../base'; const Xenomorph: Antagonist = { key: 'xenomorph', name: 'Xenomorph', description: [ - multiline` + ` Become the extraterrestrial xenomorph. Start as a larva, and progress your way up the caste, including even the Queen! `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/names.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/names.tsx index eadb6e94d4291..039fb8027ad68 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/names.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/names.tsx @@ -21,9 +21,11 @@ type NameWithKey = { name: Name; }; -const binaryInsertName = binaryInsertWith(({ key }) => key); +const binaryInsertName = (collection: NameWithKey[], value: NameWithKey) => + binaryInsertWith(collection, value, ({ key }) => key); -const sortNameWithKeyEntries = sortBy<[string, NameWithKey[]]>(([key]) => key); +const sortNameWithKeyEntries = (array: [string, NameWithKey[]][]) => + sortBy(array, ([key]) => key); export const MultiNameInput = (props: { handleClose: () => void; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx index f481c129d2886..452eb677519b1 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx @@ -1,5 +1,5 @@ -import { sortBy, sortStrings } from 'common/collections'; -import { BooleanLike, classes } from 'common/react'; +import { sortBy } from 'common/collections'; +import { BooleanLike } from 'common/react'; import { ComponentType, createElement, @@ -21,7 +21,8 @@ import { import { createSetPreference, PreferencesMenuData } from '../../data'; import { ServerPreferencesFetcher } from '../../ServerPreferencesFetcher'; -export const sortChoices = sortBy<[string, ReactNode]>(([name]) => name); +export const sortChoices = (array: [string, ReactNode][]) => + sortBy(array, ([name]) => name); export type Feature< TReceiving, @@ -122,16 +123,15 @@ export const CheckboxInputInverse = ( ); }; -export const createDropdownInput = ( +export function createDropdownInput( // Map of value to display texts choices: Record, dropdownProps?: Record, -): FeatureValue => { +): FeatureValue { return (props: FeatureValueProps) => { return ( ( /> ); }; -}; +} export type FeatureChoicedServerData = { choices: string[]; @@ -156,136 +156,6 @@ export type FeatureChoicedServerData = { export type FeatureChoiced = Feature; -const capitalizeFirstLetter = (text: string) => - text.toString().charAt(0).toUpperCase() + text.toString().slice(1); - -export const StandardizedDropdown = (props: { - choices: string[]; - disabled?: boolean; - displayNames: Record; - onSetValue: (newValue: string) => void; - value: string; - buttons?: boolean; -}) => { - const { choices, disabled, buttons, displayNames, onSetValue, value } = props; - - return ( - { - return { - displayText: displayNames[choice], - value: choice, - }; - })} - /> - ); -}; - -export const FeatureDropdownInput = ( - props: FeatureValueProps & { - disabled?: boolean; - buttons?: boolean; - }, -) => { - const serverData = props.serverData; - if (!serverData) { - return null; - } - - const displayNames = - serverData.display_names || - Object.fromEntries( - serverData.choices.map((choice) => [ - choice, - capitalizeFirstLetter(choice), - ]), - ); - - return ( - - ); -}; - -export type FeatureWithIcons = Feature< - { value: T }, - T, - FeatureChoicedServerData ->; - -export const FeatureIconnedDropdownInput = ( - props: FeatureValueProps< - { - value: string; - }, - string, - FeatureChoicedServerData - >, -) => { - const serverData = props.serverData; - if (!serverData) { - return null; - } - - const icons = serverData.icons; - - const textNames = - serverData.display_names || - Object.fromEntries( - serverData.choices.map((choice) => [ - choice, - capitalizeFirstLetter(choice), - ]), - ); - - const displayNames = Object.fromEntries( - Object.entries(textNames).map(([choice, textName]) => { - let element: ReactNode = textName; - - if (icons && icons[choice]) { - const icon = icons[choice]; - element = ( - - - - - - {element} - - ); - } - - return [choice, element]; - }), - ); - - return ( - - ); -}; - export type FeatureNumericData = { minimum: number; maximum: number; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_core_display.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_core_display.tsx index 6b3e10bb10cc0..0e73c28526a94 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_core_display.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_core_display.tsx @@ -1,4 +1,5 @@ -import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../base'; +import {} from '../base'; +import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../dropdowns'; export const preferred_ai_core_display: FeatureWithIcons = { name: 'AI core display', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_emote_display.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_emote_display.tsx index c8a59a5d9a441..3e958297b8882 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_emote_display.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_emote_display.tsx @@ -1,4 +1,4 @@ -import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../base'; +import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../dropdowns'; export const preferred_ai_emote_display: FeatureWithIcons = { name: 'AI emote display', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_hologram_display.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_hologram_display.tsx index 423fcea8ed2f6..46d572fcda6b4 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_hologram_display.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_hologram_display.tsx @@ -1,4 +1,4 @@ -import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../base'; +import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../dropdowns'; export const preferred_ai_hologram_display: FeatureWithIcons = { name: 'AI hologram display', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx index de9d6523e2c42..3746e62ceeec9 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const body_type: FeatureChoiced = { name: 'Body type', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/food_allergy.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/food_allergy.tsx index f5b0ea37ca89b..bdcd91ac7afab 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/food_allergy.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/food_allergy.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const food_allergy: FeatureChoiced = { name: 'Food Allergy', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/glasses.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/glasses.tsx index 60cb3131f1b83..df73451c35a20 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/glasses.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/glasses.tsx @@ -1,4 +1,4 @@ -import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../base'; +import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../dropdowns'; export const glasses: FeatureWithIcons = { name: 'Glasses', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/hemiplegic.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/hemiplegic.tsx index 0494558ba7781..35837c80099c6 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/hemiplegic.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/hemiplegic.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const hemiplegic: FeatureChoiced = { name: 'Hemiplegic', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/junkie.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/junkie.tsx index 8ac11ed968d1f..586b69d86c2b2 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/junkie.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/junkie.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const junkie: FeatureChoiced = { name: 'Addiction', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx index 6b1a1be1220b2..39c48ae40d6ad 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const language: FeatureChoiced = { name: 'Language', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pda.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pda.tsx index fdc9a2be5dad0..196dea45c5d16 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pda.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pda.tsx @@ -1,9 +1,5 @@ -import { - Feature, - FeatureChoiced, - FeatureDropdownInput, - FeatureShortTextInput, -} from '../base'; +import { Feature, FeatureChoiced, FeatureShortTextInput } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const pda_theme: FeatureChoiced = { name: 'PDA Theme', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/phobia.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/phobia.tsx index dd14349277fec..f2f35f65e16df 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/phobia.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/phobia.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const phobia: FeatureChoiced = { name: 'Phobia', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx index b0fae6092a1e9..70c6f8a8efec3 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const pride_pin: FeatureChoiced = { name: 'Pride Pin', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prisoner_crime.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prisoner_crime.tsx index 2ca17aa4e36d6..b551b68ee2ec5 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prisoner_crime.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prisoner_crime.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const prisoner_crime: FeatureChoiced = { name: 'Prisoner crime', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_limb.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_limb.tsx index adbaefe90c8f2..87a8ea23de199 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_limb.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_limb.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const prosthetic: FeatureChoiced = { name: 'Prosthetic', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_organ.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_organ.tsx index da0e37a4173b2..5b484d5960e7f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_organ.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_organ.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const prosthetic_organ: FeatureChoiced = { name: 'Prosthetic Organ', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx index e9f380bd67562..a1311e347c80f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const prefered_security_department: FeatureChoiced = { name: 'Security department', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx index fe18a89418d40..95029374bd23c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx @@ -1,12 +1,8 @@ import { sortBy } from 'common/collections'; +import { useMemo } from 'react'; +import { Box, Dropdown, Stack } from 'tgui/components'; -import { Box, Stack } from '../../../../../components'; -import { - Feature, - FeatureChoicedServerData, - FeatureValueProps, - StandardizedDropdown, -} from '../base'; +import { Feature, FeatureChoicedServerData, FeatureValueProps } from '../base'; type HexValue = { lightness: number; @@ -18,50 +14,59 @@ type SkinToneServerData = FeatureChoicedServerData & { to_hex: Record; }; -const sortHexValues = sortBy<[string, HexValue]>( - ([_, hexValue]) => -hexValue.lightness, -); +const sortHexValues = (array: [string, HexValue][]) => + sortBy(array, ([_, hexValue]) => -hexValue.lightness); export const skin_tone: Feature = { name: 'Skin tone', component: (props: FeatureValueProps) => { - const { handleSetValue, serverData, value } = props; + const { handleSetValue, serverData } = props; if (!serverData) { return null; } - return ( - key, - )} - displayNames={Object.fromEntries( - Object.entries(serverData.display_names).map(([key, displayName]) => { - const hexColor = serverData.to_hex[key]; + const value = { value: props.value }; + + const displayNames = useMemo(() => { + const sorted = sortHexValues(Object.entries(serverData.to_hex)); + + return sorted.map(([key, colorInfo]) => { + const displayName = serverData.display_names[key]; - return [ - key, - - - - + return { + value: key, + displayText: ( + + + + - {displayName} - , - ]; - }), - )} - onSetValue={handleSetValue} - value={value} + {displayName} + + ), + }; + }); + }, [serverData.display_names]); + + return ( + option.value === value.value) + ?.displayText + } + onSelected={(value) => handleSetValue(value)} + options={displayNames} + selected={value.value} + width="100%" /> ); }, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx new file mode 100644 index 0000000000000..fc8601e3cc7e1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx @@ -0,0 +1,7 @@ +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; + +export const trans_prosthetic: FeatureChoiced = { + name: 'Augment', + component: FeatureDropdownInput, +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/tts_voice.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/tts_voice.tsx index 94a208158c504..1f588f07f15b4 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/tts_voice.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/tts_voice.tsx @@ -2,11 +2,11 @@ import { Button, Stack } from '../../../../../components'; import { FeatureChoiced, FeatureChoicedServerData, - FeatureDropdownInput, FeatureNumeric, FeatureSliderInput, FeatureValueProps, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; const FeatureTTSDropdownInput = ( props: FeatureValueProps, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/uplink_loc.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/uplink_loc.tsx index 06c125c33fc30..2b1ffe26a3289 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/uplink_loc.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/uplink_loc.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const uplink_loc: FeatureChoiced = { name: 'Uplink Spawn Location', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx new file mode 100644 index 0000000000000..32e1161e636aa --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx @@ -0,0 +1,113 @@ +import { classes } from 'common/react'; +import { capitalizeFirst } from 'common/string'; +import { ReactNode } from 'react'; + +import { Box, Dropdown, Stack } from '../../../../components'; +import { Feature, FeatureChoicedServerData, FeatureValueProps } from './base'; + +type DropdownInputProps = FeatureValueProps< + string, + string, + FeatureChoicedServerData +> & + Partial<{ + disabled: boolean; + buttons: boolean; + }>; + +type IconnedDropdownInputProps = FeatureValueProps< + string, + string, + FeatureChoicedServerData +>; + +export type FeatureWithIcons = Feature; + +export function FeatureDropdownInput(props: DropdownInputProps) { + const { serverData, disabled, buttons, handleSetValue, value } = props; + + if (!serverData) { + return null; + } + + const { choices, display_names } = serverData; + + const dropdownOptions = choices.map((choice) => { + let displayText: ReactNode = display_names + ? display_names[choice] + : capitalizeFirst(choice); + + return { + displayText, + value: choice, + }; + }); + + let display_text = value; + if (display_names) { + display_text = display_names[value]; + } + + return ( + + ); +} + +export function FeatureIconnedDropdownInput(props: IconnedDropdownInputProps) { + const { serverData, handleSetValue, value } = props; + + if (!serverData) { + return null; + } + + const { choices, display_names, icons } = serverData; + + const dropdownOptions = choices.map((choice) => { + let displayText: ReactNode = display_names + ? display_names[choice] + : capitalizeFirst(choice); + + if (icons?.[choice]) { + displayText = ( + + + + + {displayText} + + ); + } + + return { + displayText, + value: choice, + }; + }); + + let display_text = value; + if (display_names) { + display_text = display_names[value]; + } + + return ( + + ); +} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/admin.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/admin.tsx index 03244e9f6ee7d..7888a53e0038b 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/admin.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/admin.tsx @@ -1,12 +1,10 @@ -import { multiline } from 'common/string'; - import { CheckboxInput, Feature, FeatureColorInput, - FeatureDropdownInput, FeatureToggle, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const asaycolor: Feature = { name: 'Admin chat color', @@ -41,7 +39,7 @@ export const fast_mc_refresh: FeatureToggle = { export const ghost_roles_as_admin: FeatureToggle = { name: 'Get ghost roles while adminned', category: 'ADMIN', - description: multiline` + description: ` If you de-select this, you will not get any ghost role pop-ups while adminned! Every single pop-up WILL never show up for you in an adminned state. However, this does not suppress notifications when you are diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/broadcast_login_logout.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/broadcast_login_logout.tsx index de2ad66bd99db..772e619bc5733 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/broadcast_login_logout.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/broadcast_login_logout.tsx @@ -1,11 +1,9 @@ -import { multiline } from 'common/string'; - import { CheckboxInput, FeatureToggle } from '../base'; export const broadcast_login_logout: FeatureToggle = { name: 'Broadcast login/logout', category: 'GAMEPLAY', - description: multiline` + description: ` When enabled, disconnecting and reconnecting will announce to deadchat. `, component: CheckboxInput, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/darkened_flash.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/darkened_flash.tsx index a60c6d9d31c43..3184b43a456bf 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/darkened_flash.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/darkened_flash.tsx @@ -1,11 +1,9 @@ -import { multiline } from 'common/string'; - import { CheckboxInput, FeatureToggle } from '../base'; export const darkened_flash: FeatureToggle = { name: 'Enable darkened flashes', category: 'GAMEPLAY', - description: multiline` + description: ` When toggled, being flashed will show a dark screen rather than a bright one. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx index cfa323dce2c69..d217418350337 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx @@ -1,6 +1,5 @@ import { binaryInsertWith } from 'common/collections'; import { classes } from 'common/react'; -import { multiline } from 'common/string'; import { ReactNode } from 'react'; import { useBackend } from '../../../../../backend'; @@ -10,10 +9,10 @@ import { CheckboxInput, FeatureChoiced, FeatureChoicedServerData, - FeatureDropdownInput, FeatureToggle, FeatureValueProps, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const ghost_accs: FeatureChoiced = { name: 'Ghost accessories', @@ -22,10 +21,13 @@ export const ghost_accs: FeatureChoiced = { component: FeatureDropdownInput, }; -const insertGhostForm = binaryInsertWith<{ +type GhostForm = { displayText: ReactNode; value: string; -}>(({ value }) => value); +}; + +const insertGhostForm = (collection: GhostForm[], value: GhostForm) => + binaryInsertWith(collection, value, ({ value }) => value); const GhostFormInput = ( props: FeatureValueProps, @@ -78,9 +80,10 @@ const GhostFormInput = ( return ( = { name: 'MOD active module key', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/parallax.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/parallax.tsx index a7b143a6d3d0d..914af27c38281 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/parallax.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/parallax.tsx @@ -1,4 +1,5 @@ -import { Feature, FeatureDropdownInput } from '../base'; +import { Feature } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const parallax: Feature = { name: 'Parallax (fancy space)', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/preferred_map.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/preferred_map.tsx index 1a1755ce71466..d00ce9dd04df7 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/preferred_map.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/preferred_map.tsx @@ -1,11 +1,10 @@ -import { multiline } from 'common/string'; - -import { Feature, FeatureDropdownInput } from '../base'; +import { Feature } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const preferred_map: Feature = { name: 'Preferred map', category: 'GAMEPLAY', - description: multiline` + description: ` During map rotation, prefer this map be chosen. This does not affect the map vote, only random rotation when a vote is not held. diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/screentips.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/screentips.tsx index 5c65c4f100a4c..8cdc6c0ddf105 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/screentips.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/screentips.tsx @@ -1,18 +1,16 @@ -import { multiline } from 'common/string'; - import { CheckboxInput, Feature, FeatureChoiced, FeatureColorInput, - FeatureDropdownInput, FeatureToggle, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const screentip_color: Feature = { name: 'Screentips: Screentips color', category: 'UI', - description: multiline` + description: ` The color of screen tips, the text you see when hovering over something. `, component: FeatureColorInput, @@ -21,7 +19,7 @@ export const screentip_color: Feature = { export const screentip_images: FeatureToggle = { name: 'Screentips: Allow images', category: 'UI', - description: multiline`When enabled, screentip hints use images for + description: `When enabled, screentip hints use images for the mouse button rather than LMB/RMB.`, component: CheckboxInput, }; @@ -29,7 +27,7 @@ export const screentip_images: FeatureToggle = { export const screentip_pref: FeatureChoiced = { name: 'Screentips: Enable screentips', category: 'UI', - description: multiline` + description: ` Enables screen tips, the text you see when hovering over something. When set to "Only with tips", will only show when there is more information than just the name, such as what right-clicking it does. diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx index 0bce5e0982e0b..8516823a5587f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx @@ -1,13 +1,11 @@ -import { multiline } from 'common/string'; - import { CheckboxInput, Feature, FeatureChoiced, - FeatureDropdownInput, FeatureSliderInput, FeatureToggle, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const sound_ambience: FeatureToggle = { name: 'Enable ambience', @@ -46,7 +44,7 @@ export const sound_instruments: FeatureToggle = { export const sound_tts: FeatureChoiced = { name: 'Enable TTS', category: 'SOUND', - description: multiline` + description: ` When enabled, be able to hear text-to-speech sounds in game. When set to "Blips", text to speech will be replaced with blip sounds based on the voice. `, @@ -95,7 +93,7 @@ export const sound_elevator: FeatureToggle = { export const sound_achievement: FeatureChoiced = { name: 'Achievement unlock sound', category: 'SOUND', - description: multiline` + description: ` The sound that's played when unlocking an achievement. If disabled, no sound will be played. `, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/tooltips.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/tooltips.tsx index d3df346a83f05..edbdb25ef1cbf 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/tooltips.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/tooltips.tsx @@ -1,5 +1,3 @@ -import { multiline } from 'common/string'; - import { CheckboxInput, Feature, @@ -10,7 +8,7 @@ import { export const enable_tips: FeatureToggle = { name: 'Enable tooltips', category: 'TOOLTIPS', - description: multiline` + description: ` Do you want to see tooltips when hovering over items? `, component: CheckboxInput, @@ -19,7 +17,7 @@ export const enable_tips: FeatureToggle = { export const tip_delay: Feature = { name: 'Tooltip delay (in milliseconds)', category: 'TOOLTIPS', - description: multiline` + description: ` How long should it take to see a tooltip when hovering over items? `, component: FeatureNumberInput, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ui_style.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ui_style.tsx index 218b5b3c5809c..d3fdc0b94de1c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ui_style.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ui_style.tsx @@ -46,7 +46,6 @@ const UIStyleInput = ( = { name: 'Eye color', @@ -68,6 +68,15 @@ export const feature_human_tail: FeatureChoiced = { }, }; +export const feature_monkey_tail: FeatureChoiced = { + name: 'Tail', + component: ( + props: FeatureValueProps, + ) => { + return ; + }, +}; + export const feature_lizard_legs: FeatureChoiced = { name: 'Legs', component: ( diff --git a/tgui/packages/tgui/interfaces/ProcCallMenu.tsx b/tgui/packages/tgui/interfaces/ProcCallMenu.tsx index 716ae19a14795..6db723bcfb423 100644 --- a/tgui/packages/tgui/interfaces/ProcCallMenu.tsx +++ b/tgui/packages/tgui/interfaces/ProcCallMenu.tsx @@ -45,7 +45,7 @@ export const ProcCallMenu = (props) => { @@ -139,7 +139,7 @@ const PortEntry = (props) => { { const tunedChannel = RADIO_CHANNELS.find( (channel) => channel.freq === frequency, ); - const channels = map((value, key) => ({ + const channels = map(data.channels, (value, key) => ({ name: key, status: !!value, - }))(data.channels); + })); // Calculate window height let height = 106; if (subspace) { diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser.tsx b/tgui/packages/tgui/interfaces/RapidPipeDispenser.tsx index 37b8f77cb8877..3bfe22f816479 100644 --- a/tgui/packages/tgui/interfaces/RapidPipeDispenser.tsx +++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser.tsx @@ -1,5 +1,4 @@ import { BooleanLike, classes } from 'common/react'; -import { multiline } from 'common/string'; import { capitalizeAll } from 'common/string'; import { useState } from 'react'; @@ -347,11 +346,10 @@ export const SmartPipeBlockSection = (props) => { color="transparent" icon="info" tooltipPosition="right" - tooltip={multiline` - This is a panel for blocking certain connection + tooltip="This is a panel for blocking certain connection directions for the smart pipes. The button in the center resets to - default (all directions can connect)`} + default (all directions can connect)" /> diff --git a/tgui/packages/tgui/interfaces/RaptorDex.tsx b/tgui/packages/tgui/interfaces/RaptorDex.tsx new file mode 100644 index 0000000000000..946f8fb2b9553 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RaptorDex.tsx @@ -0,0 +1,130 @@ +import { useBackend } from '../backend'; +import { Image, LabeledList, ProgressBar, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type Data = { + raptor_attack: number; + raptor_health: number; + raptor_speed: number; + raptor_color: String; + raptor_image: String; + raptor_gender: String; + raptor_happiness: String; + raptor_description: String; + inherited_attack: number; + inherited_attack_max: number; + inherited_health: number; + inherited_health_max: number; + inherited_traits: String[]; +}; + +export const RaptorDex = (props) => { + const { act, data } = useBackend(); + const { + raptor_attack, + raptor_health, + raptor_speed, + raptor_image, + raptor_gender, + inherited_attack, + inherited_attack_max, + inherited_health, + inherited_health_max, + raptor_happiness, + inherited_traits, + raptor_description, + raptor_color, + } = data; + return ( + + + + +
    + +
    +
    + +
    + + + {raptor_health} + + + {raptor_attack} + + + {10 - raptor_speed} + + + {raptor_gender} + + +
    +
    + + + + + + + + +
    +
    + +
    + +
    +
    + + {inherited_traits.map((trait, index) => ( + {trait} + ))} + +
    +
    +
    +
    + {raptor_description} +
    +
    +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/RequestsConsole/MessageWriteTab.tsx b/tgui/packages/tgui/interfaces/RequestsConsole/MessageWriteTab.tsx index 5195c451838f6..b85f2424534ff 100644 --- a/tgui/packages/tgui/interfaces/RequestsConsole/MessageWriteTab.tsx +++ b/tgui/packages/tgui/interfaces/RequestsConsole/MessageWriteTab.tsx @@ -1,4 +1,4 @@ -import { sortStrings } from 'common/collections'; +import { sort } from 'common/collections'; import { useState } from 'react'; import { useBackend, useLocalState } from '../../backend'; @@ -22,9 +22,9 @@ export const MessageWriteTab = (props) => { information_consoles = [], } = data; - const sorted_assistance = sortStrings(assistance_consoles); - const sorted_supply = sortStrings(supply_consoles); - const sorted_information = sortStrings(information_consoles); + const sorted_assistance = sort(assistance_consoles); + const sorted_supply = sort(supply_consoles); + const sorted_information = sort(information_consoles); const resetMessage = () => { setMessageText(''); @@ -85,7 +85,7 @@ export const MessageWriteTab = (props) => { width="100%" options={sorted_assistance} selected={recipient} - displayText={recipient || 'Pick a Recipient'} + placeholder="Pick a Recipient" onSelected={(value) => setRecipient(value)} /> )} @@ -94,7 +94,7 @@ export const MessageWriteTab = (props) => { width="100%" options={sorted_supply} selected={recipient} - displayText={recipient || 'Pick a Recipient'} + placeholder="Pick a Recipient" onSelected={(value) => setRecipient(value)} /> )} @@ -103,7 +103,7 @@ export const MessageWriteTab = (props) => { width="100%" options={sorted_information} selected={recipient} - displayText={recipient || 'Pick a Recipient'} + placeholder="Pick a Recipient" onSelected={(value) => setRecipient(value)} /> )} diff --git a/tgui/packages/tgui/interfaces/RestockTracker.jsx b/tgui/packages/tgui/interfaces/RestockTracker.jsx index 236f486069cb5..7df606adffcd3 100644 --- a/tgui/packages/tgui/interfaces/RestockTracker.jsx +++ b/tgui/packages/tgui/interfaces/RestockTracker.jsx @@ -17,8 +17,9 @@ export const Restock = (props) => { export const RestockTracker = (props) => { const { data } = useBackend(); - const vending_list = sortBy((vend) => vend.percentage)( + const vending_list = sortBy( data.vending_list ?? [], + (vend) => vend.percentage, ); return (
    diff --git a/tgui/packages/tgui/interfaces/RideMinigame.tsx b/tgui/packages/tgui/interfaces/RideMinigame.tsx new file mode 100644 index 0000000000000..6ed708840b9e4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RideMinigame.tsx @@ -0,0 +1,131 @@ +import { randomPick } from 'common/random'; +import { useEffect, useState } from 'react'; + +import { useBackend } from '../backend'; +import { Button, Image, LabeledList, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type Data = { + current_attempts: number; + current_failures: number; + all_icons: Icon_Data[]; + maximum_attempts: number; + maximum_failures: number; +}; + +type Icon_Data = { + direction: String; + icon: String; +}; + +export const RideMinigame = (props) => { + const { act, data } = useBackend(); + const { all_icons, maximum_attempts, maximum_failures } = data; + const [CurrIcon, setCurrIcon] = useState(randomPick(all_icons)); + const [CurrDisabled, setCurrDisabled] = useState(false); + const [ChosenAnswer, setChosenAnswer] = useState(''); + const [CurrentFailures, setCurrentFailures] = useState(0); + const [CurrentAttempts, setCurrentAttempts] = useState(0); + + const UpdateAnswer = (Answer: string) => { + setChosenAnswer(Answer); + setCurrDisabled(true); + }; + useEffect(() => { + const intervalId = setInterval(() => { + if (CurrentFailures >= maximum_failures) { + act('lose_game'); + return; + } + if (CurrentAttempts >= maximum_attempts) { + act('win_game'); + return; + } + setCurrentAttempts(CurrentAttempts + 1); + if (CurrIcon.direction !== ChosenAnswer) { + setCurrentFailures(CurrentFailures + 1); + } + const ListToPickFrom = all_icons.filter((icon) => icon !== CurrIcon); + setCurrIcon(randomPick(ListToPickFrom)); + setChosenAnswer(''); + setCurrDisabled(false); + }, 1000); + return () => clearInterval(intervalId); + }, [CurrIcon, ChosenAnswer, CurrDisabled]); + return ( + + + + +
    + +
    +
    + +
    + + + {maximum_attempts - CurrentAttempts} + + + {maximum_failures - CurrentFailures} + + +
    +
    + + +
    +
    +
    +
    +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/Roulette.jsx b/tgui/packages/tgui/interfaces/Roulette.jsx deleted file mode 100644 index e07cf4e0ef463..0000000000000 --- a/tgui/packages/tgui/interfaces/Roulette.jsx +++ /dev/null @@ -1,313 +0,0 @@ -import { classes } from 'common/react'; -import { useState } from 'react'; - -import { useBackend } from '../backend'; -import { Box, Button, Grid, NumberInput, Table } from '../components'; -import { Window } from '../layouts'; - -const getNumberColor = (number) => { - const inRedOddRange = - (number >= 1 && number <= 10) || (number >= 19 && number <= 28); - - if (number % 2 === 1) { - return inRedOddRange ? 'red' : 'black'; - } - return inRedOddRange ? 'black' : 'red'; -}; - -export const RouletteNumberCell = (props) => { - const { - buttonClass = null, - cellClass = null, - color, - colspan = '1', - rowspan = '1', - text, - value, - } = props; - const { act } = useBackend(); - - return ( - - - - ); -}; - -export const RouletteBoard = () => { - const firstRow = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36]; - const secondRow = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35]; - const thirdRow = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34]; - const fourthRow = { - 's1-12': '1st 12', - 's13-24': '2nd 12', - 's25-36': '3rd 12', - }; - const fifthRow = [ - { color: 'transparent', text: '1-18', value: 's1-18' }, - { color: 'transparent', text: 'Even', value: 'even' }, - { color: 'black', text: 'Black', value: 'black' }, - { color: 'red', text: 'Red', value: 'red' }, - { color: 'transparent', text: 'Odd', value: 'odd' }, - { color: 'transparent', text: '19-36', value: 's19-36' }, - ]; - - return ( - - - - - {firstRow.map((number) => ( - - ))} - - - - {secondRow.map((number) => ( - - ))} - - - - {thirdRow.map((number) => ( - - ))} - - - - - {Object.entries(fourthRow).map(([value, text]) => ( - - ))} - - - - {fifthRow.map((cell) => ( - - ))} - -
    -
    - ); -}; - -export const RouletteBetTable = (props) => { - const { act, data } = useBackend(); - - const [customBet, setCustomBet] = useState(500); - - let { BetType } = data; - - if (BetType.startsWith('s')) { - BetType = BetType.substring(1, BetType.length); - } - - return ( - - - - Last Spin: - - - Current Bet: - - - - - {data.LastSpin} - - - - {data.BetAmount} cr on {BetType} - - -
    - ); -}; - -export const Roulette = (props) => { - return ( - - - - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/Roulette/BetTable.tsx b/tgui/packages/tgui/interfaces/Roulette/BetTable.tsx new file mode 100644 index 0000000000000..8abf081b288a3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/BetTable.tsx @@ -0,0 +1,171 @@ +import { BooleanLike, classes } from 'common/react'; +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Box, Button, NumberInput, Stack, Table } from '../../components'; +import { getNumberColor } from './helpers'; + +type Data = { + IsAnchored: BooleanLike; + BetAmount: number; + BetType: string; + HouseBalance: number; + LastSpin: number; + Spinning: BooleanLike; + AccountBalance: number; + CanUnbolt: BooleanLike; +}; + +export function RouletteBetTable(props) { + const { act, data } = useBackend(); + const { LastSpin, HouseBalance, BetAmount, IsAnchored } = data; + + const [customBet, setCustomBet] = useState(500); + + let BetType = data.BetType; + + if (BetType.startsWith('s')) { + BetType = BetType.substring(1, BetType.length); + } + + return ( + + + + Last Spin: + + + Current Bet: + + + + + {LastSpin} + + + + {BetAmount} cr on {BetType} + + + + + + + + + + + + setCustomBet(value)} + /> + + + + + + + + + Swipe an ID card with a connected account to spin! + + + + + + + House Balance: + + {HouseBalance ? HouseBalance + ' cr' : 'None'} + + + + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Roulette/Board.tsx b/tgui/packages/tgui/interfaces/Roulette/Board.tsx new file mode 100644 index 0000000000000..0f0fbcdc681c1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/Board.tsx @@ -0,0 +1,107 @@ +import { Box, Table } from '../../components'; +import { getNumberColor } from './helpers'; +import { RouletteNumberCell } from './NumberCell'; + +const firstRow = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36] as const; +const secondRow = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35] as const; +const thirdRow = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34] as const; +const fourthRow = { + 's1-12': '1st 12', + 's13-24': '2nd 12', + 's25-36': '3rd 12', +} as const; +const fifthRow = [ + { color: 'transparent', text: '1-18', value: 's1-18' }, + { color: 'transparent', text: 'Even', value: 'even' }, + { color: 'black', text: 'Black', value: 'black' }, + { color: 'red', text: 'Red', value: 'red' }, + { color: 'transparent', text: 'Odd', value: 'odd' }, + { color: 'transparent', text: '19-36', value: 's19-36' }, +] as const; + +export function RouletteBoard(props) { + return ( + + + + + {firstRow.map((number) => ( + + ))} + + + + {secondRow.map((number) => ( + + ))} + + + + {thirdRow.map((number) => ( + + ))} + + + + + {Object.entries(fourthRow).map(([value, text]) => ( + + ))} + + + + {fifthRow.map((cell) => ( + + ))} + +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Roulette/NumberCell.tsx b/tgui/packages/tgui/interfaces/Roulette/NumberCell.tsx new file mode 100644 index 0000000000000..1b8143905c314 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/NumberCell.tsx @@ -0,0 +1,48 @@ +import { classes } from 'common/react'; + +import { useBackend } from '../../backend'; +import { Button, Table } from '../../components'; + +type Props = { + color: string; + text: string; + value: string; +} & Partial<{ + buttonClass: string; + cellClass: string; + colspan: number; + rowspan: number; +}>; + +export function RouletteNumberCell(props: Props) { + const { + buttonClass, + cellClass, + color, + colspan = 1, + rowspan = 1, + text, + value, + } = props; + const { act } = useBackend(); + + return ( + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Roulette/helpers.tsx b/tgui/packages/tgui/interfaces/Roulette/helpers.tsx new file mode 100644 index 0000000000000..b5c4f9b9b3330 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/helpers.tsx @@ -0,0 +1,9 @@ +export function getNumberColor(number: number): 'red' | 'black' { + const inRedOddRange = + (number >= 1 && number <= 10) || (number >= 19 && number <= 28); + + if (number % 2 === 1) { + return inRedOddRange ? 'red' : 'black'; + } + return inRedOddRange ? 'black' : 'red'; +} diff --git a/tgui/packages/tgui/interfaces/Roulette/index.tsx b/tgui/packages/tgui/interfaces/Roulette/index.tsx new file mode 100644 index 0000000000000..8c27a052a02f6 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/index.tsx @@ -0,0 +1,14 @@ +import { Window } from '../../layouts'; +import { RouletteBetTable } from './BetTable'; +import { RouletteBoard } from './Board'; + +export function Roulette(props) { + return ( + + + + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx index 492321b3d3a07..a00f4a3be1477 100644 --- a/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx +++ b/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { useState } from 'react'; import { useBackend, useLocalState } from 'tgui/backend'; import { @@ -29,10 +28,10 @@ export const SecurityRecordTabs = (props) => { const [search, setSearch] = useState(''); - const sorted: SecurityRecord[] = flow([ - filter((record: SecurityRecord) => isRecordMatch(record, search)), - sortBy((record: SecurityRecord) => record.name), - ])(records); + const sorted = sortBy( + filter(records, (record) => isRecordMatch(record, search)), + (record) => record.name, + ); return ( diff --git a/tgui/packages/tgui/interfaces/SeedExtractor.tsx b/tgui/packages/tgui/interfaces/SeedExtractor.tsx index 3c05b3d0498e9..87955da243f5b 100644 --- a/tgui/packages/tgui/interfaces/SeedExtractor.tsx +++ b/tgui/packages/tgui/interfaces/SeedExtractor.tsx @@ -1,5 +1,4 @@ import { sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { classes } from 'common/react'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -67,9 +66,10 @@ export const SeedExtractor = (props) => { const search = createSearch(searchText, (item: SeedData) => item.name); const seeds_filtered = searchText.length > 0 ? data.seeds.filter(search) : data.seeds; - const seeds = flow([ - sortBy((item: SeedData) => item[sortField as keyof SeedData]), - ])(seeds_filtered || []); + const seeds = sortBy( + seeds_filtered || [], + (item: SeedData) => item[sortField as keyof SeedData], + ); sortField !== 'name' && seeds.reverse(); return ( diff --git a/tgui/packages/tgui/interfaces/SelectEquipment.jsx b/tgui/packages/tgui/interfaces/SelectEquipment.jsx index d43d28961e216..d8df6c71e7c35 100644 --- a/tgui/packages/tgui/interfaces/SelectEquipment.jsx +++ b/tgui/packages/tgui/interfaces/SelectEquipment.jsx @@ -1,5 +1,4 @@ import { filter, map, sortBy, uniq } from 'common/collections'; -import { flow } from 'common/fp'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -30,10 +29,10 @@ export const SelectEquipment = (props) => { const isFavorited = (entry) => favorites?.includes(entry.path); - const outfits = map((entry) => ({ + const outfits = map([...data.outfits, ...data.custom_outfits], (entry) => ({ ...entry, favorite: isFavorited(entry), - }))([...data.outfits, ...data.custom_outfits]); + })); // even if no custom outfits were sent, we still want to make sure there's // at least a 'Custom' tab so the button to create a new one pops up @@ -49,15 +48,15 @@ export const SelectEquipment = (props) => { (entry) => entry.name + entry.path, ); - const visibleOutfits = flow([ - filter((entry) => entry.category === tab), - filter(searchFilter), - sortBy( - (entry) => !entry.favorite, - (entry) => !entry.priority, - (entry) => entry.name, + const visibleOutfits = sortBy( + filter( + filter(outfits, (entry) => entry.category === tab), + searchFilter, ), - ])(outfits); + (entry) => !entry.favorite, + (entry) => !entry.priority, + (entry) => entry.name, + ); const getOutfitEntry = (current_outfit) => outfits.find((outfit) => getOutfitKey(outfit) === current_outfit); diff --git a/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx b/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx index e64f47086cdc4..8cff913e8e93e 100644 --- a/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx +++ b/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx @@ -104,7 +104,7 @@ export const ShuttleManipulatorTemplates = (props) => { - {map((template, templateId) => ( + {map(templateObject, (template, templateId) => ( { > {template.port_id} - ))(templateObject)} + ))} diff --git a/tgui/packages/tgui/interfaces/SimpleBot.tsx b/tgui/packages/tgui/interfaces/SimpleBot.tsx index b5feb1cc20a8b..8ac2b4201a74c 100644 --- a/tgui/packages/tgui/interfaces/SimpleBot.tsx +++ b/tgui/packages/tgui/interfaces/SimpleBot.tsx @@ -1,4 +1,5 @@ -import { capitalizeAll, multiline } from 'common/string'; +import { BooleanLike } from 'common/react'; +import { capitalizeAll } from 'common/string'; import { useBackend } from 'tgui/backend'; import { Button, @@ -12,34 +13,30 @@ import { } from 'tgui/components'; import { Window } from 'tgui/layouts'; -type SimpleBotContext = { - can_hack: number; - locked: number; - emagged: number; - has_access: number; +type Data = { + can_hack: BooleanLike; + custom_controls: Record; + emagged: BooleanLike; + has_access: BooleanLike; + locked: BooleanLike; settings: Settings; - custom_controls: Controls; }; type Settings = { - power: number; - airplane_mode: number; - maintenance_lock: number; - patrol_station: number; - allow_possession: number; - possession_enabled: number; - has_personality: number; + airplane_mode: BooleanLike; + allow_possession: BooleanLike; + has_personality: BooleanLike; + maintenance_lock: BooleanLike; pai_inserted: boolean; + patrol_station: BooleanLike; + possession_enabled: BooleanLike; + power: BooleanLike; }; -type Controls = { - [Control: string]: [Value: number]; -}; - -export const SimpleBot = (props) => { - const { data } = useBackend(); - const { can_hack, locked } = data; - const access = !locked || can_hack; +export function SimpleBot(props) { + const { data } = useBackend(); + const { can_hack, custom_controls, locked } = data; + const access = !locked || !!can_hack; return ( @@ -50,10 +47,20 @@ export const SimpleBot = (props) => { {!access ? Locked! : }
    - {access && ( + {!!access && (
    - + + {Object.entries(custom_controls).map((control) => ( + + + + ))} +
    )} @@ -61,17 +68,37 @@ export const SimpleBot = (props) => { ); -}; +} /** Creates a lock button at the top of the controls */ -const TabDisplay = (props) => { - const { act, data } = useBackend(); - const { can_hack, has_access, locked } = data; - const { allow_possession } = data.settings; +function TabDisplay(props) { + const { act, data } = useBackend(); + const { + can_hack, + emagged, + has_access, + locked, + settings: { allow_possession }, + } = data; return ( <> - {!!can_hack && } + {!!can_hack && ( + + )} {!!allow_possession && } ); -}; - -/** If user is a bad silicon, they can press this button to hack the bot */ -const HackButton = (props) => { - const { act, data } = useBackend(); - const { can_hack, emagged } = data; - - return ( - - ); -}; +} /** Creates a button indicating PAI status and offers the eject action */ -const PaiButton = (props) => { - const { act, data } = useBackend(); - const { pai_inserted } = data.settings; +function PaiButton(props) { + const { act, data } = useBackend(); + const { + settings: { pai_inserted }, + } = data; if (!pai_inserted) { return ( ); - } else { - return ( - - ); } -}; + + return ( + + ); +} /** Displays the bot's standard settings: Power, patrol, etc. */ -const SettingsDisplay = (props) => { - const { act, data } = useBackend(); - const { settings } = data; +function SettingsDisplay(props) { + const { act, data } = useBackend(); const { - airplane_mode, - patrol_station, - power, - maintenance_lock, - allow_possession, - possession_enabled, - } = settings; + settings: { + airplane_mode, + patrol_station, + power, + maintenance_lock, + allow_possession, + possession_enabled, + }, + } = data; return ( @@ -236,68 +243,54 @@ const SettingsDisplay = (props) => { )} ); -}; +} -/** Iterates over custom controls. - * Calls the helper to identify which button to use. - */ -const ControlsDisplay = (props) => { - const { data } = useBackend(); - const { custom_controls } = data; +enum ControlType { + MedbotSync = 'sync_tech', + MedbotThreshold = 'heal_threshold', + FloorbotTiles = 'tile_stack', + FloorbotLine = 'line_mode', +} - return ( - - {Object.entries(custom_controls).map((control) => { - return ( - - - - ); - })} - - ); +type ControlProps = { + control: [string, number]; }; /** Helper function which identifies which button to create. * Might need some fine tuning if you are using more advanced controls. */ -const ControlHelper = (props) => { - const { act } = useBackend(); +function ControlHelper(props: ControlProps) { + const { act } = useBackend(); const { control } = props; - if (control[0] === 'sync_tech') { - /** Control is for sync - this is medbot specific */ - return ; - } else if (control[0] === 'heal_threshold') { - /** Control is a threshold - this is medbot specific */ - return ; - } else if (control[0] === 'tile_stack') { - return ; - } else if (control[0] === 'line_mode') { - return ; - } else { - /** Control is a boolean of some type */ - return ( - act(control[0])} - /> - ); + + switch (control[0]) { + case ControlType.MedbotSync: + return ; + case ControlType.MedbotThreshold: + return ; + case ControlType.FloorbotTiles: + return ; + case ControlType.FloorbotLine: + return ; + default: + return ( + act(control[0])} + /> + ); } -}; +} /** Small button to sync medbots with research. */ -const MedbotSync = (props) => { - const { act } = useBackend(); +function MedbotSync(props) { + const { act } = useBackend(); return ( { /> ); -}; +} /** Slider button for medbot healing thresholds */ -const MedbotThreshold = (props) => { - const { act } = useBackend(); +function MedbotThreshold(props: ControlProps) { + const { act } = useBackend(); const { control } = props; return ( @@ -332,11 +325,11 @@ const MedbotThreshold = (props) => { /> ); -}; +} /** Tile stacks for floorbots - shows number and eject button */ -const FloorbotTiles = (props) => { - const { act } = useBackend(); +function FloorbotTiles(props: ControlProps) { + const { act } = useBackend(); const { control } = props; return ( @@ -349,11 +342,11 @@ const FloorbotTiles = (props) => { {control[1] ? `${control[1]}` : 'Empty'} ); -}; +} /** Direction indicator for floorbot when line mode is chosen. */ -const FloorbotLine = (props) => { - const { act } = useBackend(); +function FloorbotLine(props: ControlProps) { + const { act } = useBackend(); const { control } = props; return ( @@ -369,4 +362,4 @@ const FloorbotLine = (props) => { ); -}; +} diff --git a/tgui/packages/tgui/interfaces/SmokeMachine.tsx b/tgui/packages/tgui/interfaces/SmokeMachine.tsx index 6832583fd6bc4..4ee825ef2e802 100644 --- a/tgui/packages/tgui/interfaces/SmokeMachine.tsx +++ b/tgui/packages/tgui/interfaces/SmokeMachine.tsx @@ -10,31 +10,18 @@ import { Section, } from '../components'; import { Window } from '../layouts'; +import { Beaker } from './common/BeakerDisplay'; type Data = { active: BooleanLike; maxSetting: number; setting: number; - tankContents: Reagent[]; - tankCurrentVolume: number; - tankMaxVolume: number; -}; - -type Reagent = { - name: string; - volume: number; + tank: Beaker; }; export const SmokeMachine = (props) => { const { act, data } = useBackend(); - const { - tankContents, - tankCurrentVolume, - tankMaxVolume, - active, - setting, - maxSetting, - } = data; + const { tank, active, setting, maxSetting } = data; return ( @@ -52,13 +39,13 @@ export const SmokeMachine = (props) => { } > - - {' / ' + tankMaxVolume} + + {' / ' + tank.maxVolume} @@ -86,7 +73,7 @@ export const SmokeMachine = (props) => { } > - {tankContents.map((chemical) => ( + {tank.contents.map((chemical) => ( units of{' '} {chemical.name} diff --git a/tgui/packages/tgui/interfaces/SpaceHeater.jsx b/tgui/packages/tgui/interfaces/SpaceHeater.jsx index b7cc8d7bb9b78..ea0b75028ea36 100644 --- a/tgui/packages/tgui/interfaces/SpaceHeater.jsx +++ b/tgui/packages/tgui/interfaces/SpaceHeater.jsx @@ -1,3 +1,5 @@ +import { capitalize } from 'common/string'; + import { useBackend } from '../backend'; import { Box, @@ -96,7 +98,7 @@ export const SpaceHeater = (props) => { data.targetTemp + '°C'} - {(!data.open && 'Auto') || ( + {(!data.open && capitalize(data.mode)) || ( <> @@ -136,11 +135,9 @@ export const SyndicateContractorContent = (props) => { return (
    - {!!error && {error}}
    @@ -167,11 +164,12 @@ export const SyndicateContractorContent = (props) => {
    ); } @@ -183,38 +181,38 @@ export const SyndicateContractorContent = (props) => { ); -}; +} -export const StatusPane = (props) => { +function StatusPane(props) { const { act, data } = useBackend(); const { redeemable_tc, earned_tc, contracts_completed } = data; return (
    - Contractor Status - } + title="Contractor Status" > - - + + act('PRG_redeem_TC')} - /> + > + Claim + } > {String(redeemable_tc)} @@ -223,24 +221,28 @@ export const StatusPane = (props) => { {String(earned_tc)} - - + + {String(contracts_completed)} ACTIVE - - + +
    ); -}; +} -const ContractsTab = (props) => { +function ContractsTab(props) { const { act, data } = useBackend(); - const { contracts, ongoing_contract, extraction_enroute, dropoff_direction } = - data; + const { + contracts = [], + ongoing_contract, + extraction_enroute, + dropoff_direction, + } = data; return ( <> @@ -248,18 +250,19 @@ const ContractsTab = (props) => { title="Available Contracts" buttons={ } > {contracts.map((contract) => { - if (ongoing_contract && contract.status !== CONTRACT_STATUS_ACTIVE) { + if (ongoing_contract && contract.status !== CONTRACT.Active) { return; } - const active = contract.status > CONTRACT_STATUS_INACTIVE; - if (contract.status >= CONTRACT_STATUS_COMPLETE) { + const active = contract.status > CONTRACT.Inactive; + if (contract.status >= CONTRACT.Complete) { return; } return ( @@ -276,27 +279,28 @@ const ContractsTab = (props) => { {`${contract.payout} (+${contract.payout_bonus}) TC`}
    } > - - {contract.message} - + + {contract.message} + Dropoff Location: {contract.dropoff} - - + +
    ); })} @@ -310,4 +314,4 @@ const ContractsTab = (props) => {
    ); -}; +} diff --git a/tgui/packages/tgui/interfaces/Techweb.jsx b/tgui/packages/tgui/interfaces/Techweb.jsx index 96b52983adee9..c041d646d7d99 100644 --- a/tgui/packages/tgui/interfaces/Techweb.jsx +++ b/tgui/packages/tgui/interfaces/Techweb.jsx @@ -41,9 +41,9 @@ const selectRemappedStaticData = (data) => { ...node, id: remapId(id), costs, - prereq_ids: map(remapId)(node.prereq_ids || []), - design_ids: map(remapId)(node.design_ids || []), - unlock_ids: map(remapId)(node.unlock_ids || []), + prereq_ids: map(node.prereq_ids || [], remapId), + design_ids: map(node.design_ids || [], remapId), + unlock_ids: map(node.unlock_ids || [], remapId), required_experiments: node.required_experiments || [], discount_experiments: node.discount_experiments || [], }; @@ -251,10 +251,11 @@ const TechwebOverview = (props) => { ); }); } else { - displayedNodes = sortBy((x) => node_cache[x.id].name)( + displayedNodes = sortBy( tabIndex < 2 ? nodes.filter((x) => x.tier === tabIndex) : nodes.filter((x) => x.tier >= tabIndex), + (x) => node_cache[x.id].name, ); } diff --git a/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx b/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx index 3f1a3dcb543e2..f59b01b8b5d31 100644 --- a/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx +++ b/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx @@ -7,7 +7,7 @@ import { Window } from '../layouts'; const JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED = 1; const JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS = 2; -const sortByPlaytime = sortBy(([_, playtime]) => -playtime); +const sortByPlaytime = (array) => sortBy(array, ([_, playtime]) => -playtime); const PlaytimeSection = (props) => { const { playtimes } = props; diff --git a/tgui/packages/tgui/interfaces/TramController.tsx b/tgui/packages/tgui/interfaces/TramController.tsx index 0fccd23a911cb..f787c8726b583 100644 --- a/tgui/packages/tgui/interfaces/TramController.tsx +++ b/tgui/packages/tgui/interfaces/TramController.tsx @@ -193,7 +193,7 @@ export const TramController = (props) => { width="98.5%" options={destinations.map((id) => id.name)} selected={tripDestination} - displayText={tripDestination || 'Pick a Destination'} + placeholder="Pick a Destination" onSelected={(value) => setTripDestination(value)} /> + + + + + + + + )} diff --git a/tgui/packages/tgui/interfaces/WarrantConsole.tsx b/tgui/packages/tgui/interfaces/WarrantConsole.tsx index 14415b3ee79d1..a87de8e017cba 100644 --- a/tgui/packages/tgui/interfaces/WarrantConsole.tsx +++ b/tgui/packages/tgui/interfaces/WarrantConsole.tsx @@ -63,7 +63,7 @@ export const WarrantConsole = (props) => { const RecordList = (props) => { const { act, data } = useBackend(); const { records = [] } = data; - const sorted = sortBy((record: WarrantRecord) => record.crew_name)(records); + const sorted = sortBy(records, (record) => record.crew_name); const [selectedRecord, setSelectedRecord] = useLocalState< WarrantRecord | undefined diff --git a/tgui/packages/tgui/interfaces/common/AccessConfig.jsx b/tgui/packages/tgui/interfaces/common/AccessConfig.jsx deleted file mode 100644 index e91abecbde794..0000000000000 --- a/tgui/packages/tgui/interfaces/common/AccessConfig.jsx +++ /dev/null @@ -1,136 +0,0 @@ -import { sortBy } from 'common/collections'; -import { useState } from 'react'; - -import { Button, Flex, Grid, Section, Tabs } from '../../components'; - -export const AccessConfig = (props) => { - const { - accesses = [], - selectedList = [], - accessMod, - grantAll, - denyAll, - grantDep, - denyDep, - } = props; - const [selectedAccessName, setSelectedAccessName] = useState( - accesses[0]?.name, - ); - const selectedAccess = accesses.find( - (access) => access.name === selectedAccessName, - ); - const selectedAccessEntries = sortBy((entry) => entry.desc)( - selectedAccess?.accesses || [], - ); - - const checkAccessIcon = (accesses) => { - let oneAccess = false; - let oneInaccess = false; - for (let element of accesses) { - if (selectedList.includes(element.ref)) { - oneAccess = true; - } else { - oneInaccess = true; - } - } - if (!oneAccess && oneInaccess) { - return 0; - } else if (oneAccess && oneInaccess) { - return 1; - } else { - return 2; - } - }; - - return ( -
    -
    - ); -}; - -const diffMap = { - 0: { - icon: 'times-circle', - color: 'bad', - }, - 1: { - icon: 'stop-circle', - color: null, - }, - 2: { - icon: 'check-circle', - color: 'good', - }, -}; diff --git a/tgui/packages/tgui/interfaces/common/AccessConfig.tsx b/tgui/packages/tgui/interfaces/common/AccessConfig.tsx new file mode 100644 index 0000000000000..766a6724d77a4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/common/AccessConfig.tsx @@ -0,0 +1,204 @@ +import { sortBy } from 'common/collections'; +import { useState } from 'react'; + +import { Button, Section, Stack, Tabs } from '../../components'; + +type BaseProps = { + accessMod: (ref: string) => void; + denyDep: (ref: string) => void; + grantDep: (ref: string) => void; +}; + +type ConfigProps = { + accesses: Region[]; + denyAll: () => void; + grantAll: () => void; + selectedList: string[]; +} & BaseProps; + +type AccessButtonProps = { + selectedAccess: Region; + selectedAccessEntries: Area[]; + selectedList: string[]; +} & BaseProps; + +export type Region = { + accesses: Area[]; + name: string; +}; + +export type Area = { + desc: string; + ref: string; +}; + +enum ACCESS { + Denied = 0, + Partial = 1, + Granted = 2, +} + +const DIFFMAP = [ + { + icon: 'times-circle', + color: 'bad', + }, + { + icon: 'stop-circle', + color: null, + }, + { + icon: 'check-circle', + color: 'good', + }, +] as const; + +export function AccessConfig(props: ConfigProps) { + const { + accesses = [], + selectedList = [], + accessMod, + grantAll, + denyAll, + grantDep, + denyDep, + } = props; + + const [selectedAccessName, setSelectedAccessName] = useState( + accesses[0]?.name, + ); + + const selectedAccess = + accesses.find((access) => access.name === selectedAccessName) || + accesses[0]; + + const selectedAccessEntries = sortBy( + selectedAccess?.accesses || [], + (entry: Area) => entry.desc, + ); + + function checkAccessIcon(accesses: Area[]) { + let oneAccess = false; + let oneInaccess = false; + for (let element of accesses) { + if (selectedList.includes(element.ref)) { + oneAccess = true; + } else { + oneInaccess = true; + } + } + if (!oneAccess && oneInaccess) { + return ACCESS.Denied; + } else if (oneAccess && oneInaccess) { + return ACCESS.Partial; + } else { + return ACCESS.Granted; + } + } + + return ( +
    + + + + } + > + + + + {accesses.map((access) => { + const entries = access.accesses || []; + const icon = DIFFMAP[checkAccessIcon(entries)].icon; + const color = DIFFMAP[checkAccessIcon(entries)].color; + return ( + setSelectedAccessName(access.name)} + > + {access.name} + + ); + })} + + + + + + + +
    + ); +} + +function AccessButtons(props: AccessButtonProps) { + const { + selectedAccessEntries, + selectedList, + accessMod, + grantDep, + denyDep, + selectedAccess, + } = props; + + return ( + + + + + + + + + + + + + +
    + {selectedAccessEntries.map((entry) => ( + accessMod(entry.ref)} + > + {entry.desc} + + ))} +
    +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/common/AccessList.jsx b/tgui/packages/tgui/interfaces/common/AccessList.jsx index a4096b6ce3051..9ac1fe913b3af 100644 --- a/tgui/packages/tgui/interfaces/common/AccessList.jsx +++ b/tgui/packages/tgui/interfaces/common/AccessList.jsx @@ -248,8 +248,9 @@ const RegionAccessList = (props) => { const selectedAccess = accesses.find( (access) => access.name === selectedAccessName, ); - const selectedAccessEntries = sortBy((entry) => entry.desc)( + const selectedAccessEntries = sortBy( selectedAccess?.accesses || [], + (entry) => entry.desc, ); const allWildcards = Object.keys(wildcardSlots); diff --git a/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx b/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx index 6c2d364932538..3483c3ceede80 100644 --- a/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx +++ b/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx @@ -8,7 +8,7 @@ import { Section, } from '../../components'; -type BeakerReagent = { +export type BeakerReagent = { name: string; volume: number; }; diff --git a/tgui/packages/tgui/interfaces/common/InputButtons.tsx b/tgui/packages/tgui/interfaces/common/InputButtons.tsx index aad3d92f081fb..aa74ff1fdc017 100644 --- a/tgui/packages/tgui/interfaces/common/InputButtons.tsx +++ b/tgui/packages/tgui/interfaces/common/InputButtons.tsx @@ -8,19 +8,36 @@ type InputButtonsData = { type InputButtonsProps = { input: string | number | string[]; + on_submit?: () => void; + on_cancel?: () => void; message?: string; }; export const InputButtons = (props: InputButtonsProps) => { const { act, data } = useBackend(); const { large_buttons, swapped_buttons } = data; - const { input, message } = props; + const { input, message, on_submit, on_cancel } = props; + + let on_submit_actual = on_submit; + if (!on_submit_actual) { + on_submit_actual = () => { + act('submit', { entry: input }); + }; + } + + let on_cancel_actual = on_cancel; + if (!on_cancel_actual) { + on_cancel_actual = () => { + act('cancel'); + }; + } + const submitButton = (