Huge Mirror fixes (#27488)

* Fixes incorrect operator usage in mecha code (#82570)

## About The Pull Request

I completely screwed up and told the original PR author of #82415
(9922d2f237) to use the `XOR` operator
instead of the `OR` operator (I wasn't thinking right for some reason
when I was reading the ref), anyways this PR just fixes that because I
misled the contributor into doing something that wasn't correct and
actually would BREAK functionality instead.

* Fixes TGUI debugging tools (#82569)

This project doesn't interfere with the game logic and aims to fix
multiple debugging features that are currently broken. Unfortunately,
kitchen sink and debug layout became broken after migration to Redux.
This PR aims to fix those features.

* Removes unused code for HTML UIs (#82589)

## About The Pull Request

This is the final PR for https://hackmd.io/XLt5MoRvRxuhFbwtk4VAUA that
I've been slowly inching towards the past few months.

This removes ``updateDialog``, ``updateUsrDialog``, ``IN_USE``,
``INTERACT_MACHINE_SET_MACHINE``, and everything surrounding it. Also
fixes advanced camera consoles not booting you off when you're moved out
of reach.

We called ``check_eye`` on mob life whenever they had their machine var
set, but their machine var would never be set to anything that actually
used it, which I found to be a little funny but was also probably my
fault.

## Why It's Good For The Game

This is poor and unmaintained code used for HTML UIs that we no longer
need thanks to TGUI, we should get rid of it to encourage the use of
TGUI in the future instead.

## Changelog


🆑
fix: Advanced camera consoles now boots you off when you're moved out of
reach.
/🆑

* Fixes a variety of input stalling exploits (#82577)

## About The Pull Request

Fixes the following input stalling exploits (maybe missed some): 

- Changing GPS tag 
- Setting teleporter destination
- Request Console Reply
- Various AI law board interactions
- Note, I used `is_holding` but technically this means these fail with
telekinesis. I can swap them to `can_perform_action(...)`, which allows
TK, but I noticed some places explicitly deny TK interactions with Ai
law boards. Not sure which is preferred.
- Borg Rename Board
- Plumbing Machines and Ducts
- APCs and SMES terminal placements
- Stargazers Telepathy
- Go Go Gadget Hat

## Changelog

🆑 Melbert
fix: You can't change the GPS tag of something unless you can actually
use the GPS
fix: You can't set the teleporter to a location unless you can actually
use the teleporter
fix: You can't reply to request console requests unless you can actually
use the console
fix: You can't update AI lawboards unless you're actually holding them 
fix: You can't update a borg rename board unless you're actually holding
it
fix: You can't mess with plumbing machines unless you can actually use
them
fix: You can't recolor / relayer ducts unless you're actually holding
them
fix: You can't magically wire APCs and SMESs unless you're right by them
fix: You can't use Stargazer Telepathy on people who you can't see
fix: You can't configure the Inspector Hat unless you can actually use
it
/🆑

* [NO GBP] Power outage operation fixes for chem master (#82591)

## About The Pull Request
- If the chem master runs out of power mid printing, it will properly
stop the printing process and its animation
- When transferring reagents it correctly checks if we have enough power
without forcing it

## Changelog
🆑
fix: chem master properly shuts down if it loses power mid printing and
won't transfer reagents for the same
/🆑

* Refactor renaming UNIQUE_RENAME items from the pen to an element (#82491)

## About The Pull Request

So a bit ago someone in code_general wanted to make plushies renamable,
but learnt that just adding the `UNIQUE_RENAME` flag wouldn't work as
pens would murder the plushie and only THEN let you rename it. I noted
refactoring both pens and plushies to use the new
`item_interaction(...)` procs would Just Solve This, but, well, they
didn't really have any coding experience.

But, hey, renaming being hardcoded to the pens has annoyed me ever since
I laid my eyes upon the hot mess that is paperwork code.
So here we are!

### We're making it an element.

There's not really much to this, this is mostly the same code but moved
to an element and with some minor cleanups.

First, we move it all from `/obj/item/pen` to a new element we called
`/datum/element/tool_renaming`. With this, instead of having it proc on
`/obj/item/pen/afterattack(...)`, we register it to proc on the
`COMSIG_ITEM_INTERACTING_WITH_ATOM` signal.

https://github.com/tgstation/tgstation/blob/6e36ed984070d53e16bed4fa43eb0cbe6460deed/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm#L59-L62
Secondly, we realize the code is just going through each if statement
regardless of whether the previous was correct.

https://github.com/tgstation/tgstation/blob/6e36ed984070d53e16bed4fa43eb0cbe6460deed/code/modules/paperwork/pen.dm#L225-L258
And, as we're dealing with text, just make it a switch statement
instead.
```dm
switch(pen_choice)
		if("Rename")
			(...)

		if("Description")
			(...)

		if("Reset")
			(...)
```
Then, we replace all single letter variables with descriptive ones,
replace the if-elses with early returns, and make it actually return
item interaction flags.

Finally, we slap this onto the pen, and we're done.
Now we can slap it onto other fitting renaming tools, and it uses the
proper item interaction system.
## Why It's Good For The Game

I feel it's generally better to not hardcode this to just pens, we have
plenty other writing utensils and possible renaming tools.
It's also a bit cleaner than before.
Apart from that, moves it from using `afterattack(...)` to the proper
item interaction chain by using `COMSIG_ITEM_INTERACTING_WITH_ATOM`,
which should reduce janky interactions.
## Changelog
🆑
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.
/🆑

* Adds various quality of life changes for cooking to make it less click intensive. (#82566)

## About The Pull Request

- Increases tray item size by 1 item.

- Ranges and griddles can now be fed from trays.

Click when closed => fill soup pot.
Click when open => fill associated oven tray.
Right click when open => fill tray from oven tray
Click griddle => fill griddle surface.
Right click => fill tray from griddle surface

- Martian batter is now 5u of each ingredient into 10u of batter.

Hopefully will make it bug out less where it makes far fewer reagents
than it is supposed to, fixing reagents, or well soups specifically...
is out of scope for this PR.

- Adds the ability to print soup pots and large trays from the service
lathe

Soup pot: 5 Iron sheets, 0.4 bluespace crystal (given their size of
200U)
Large serving tray: 2 iron sheets

## Why It's Good For The Game

Makes cooking a lot less tedious. Especially for people with low
precision when it comes to filling oven trays. This also bring the
behavior up to parity with how you can click microwaves with trays to
fill them, ditto for the food processor. It also allows chef to use the
whole capacity of an oven, as previously you couldn't easily click 6
cake batters or other giant sprites onto the tiny tray.

The tray is now sized to be able to easily feed a griddle 8 items.

## Changelog

🆑
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
/🆑

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>

* Removes grid usage + heavy refactors (#82571)

## About The Pull Request
Grid has been deprecated for quite some time and we still use it. I
won't completely remove the component, this way downstreams won't
immediately suffer, but I can remove it from usage.

Some of these UIs had issues with them and as a hobby project I've
refactored them into typescript / rebuilt them. Airlock electronics, for
instance, looks substantially better.

<details>
<summary>before/after as requested</summary>

current airlock electronics scrolls into oblivion

![6RJ29HCPob](https://github.com/tgstation/tgstation/assets/42397676/ba82bc20-40fa-4af0-b709-7c8846c25652)

updated
![Screenshot 2024-04-11
164321](https://github.com/tgstation/tgstation/assets/42397676/05507e06-6305-4175-8476-778c345f02c8)

</details>

## Why It's Good For The Game
Code improvement + probably UI bug fixes
## Changelog
🆑
fix: Airlock electronics and other access-config type UIs should look
much better.
/🆑

* modular fixes

* [No GBP] Removes cogbar from some stealthy actions (#82593)

Issue brought some missed hidden actions to my attention.

I left cogbars in for _breaking_ handcuffs because resisting is sort of
a gray area. On one hand, you don't want someone to see you doing it; on
the other, there is a visible warning that you started doing it. So,
meet in the the middle, breaking handcuffs is still visible while
resisting isn't.
Closes #82583
Cogbars are not intended to ruin stealth
🆑
fix: Deviants buffed: Rogue shoelacing, pickpocketing and restraint
resisting no longer give cogbar icons.
/🆑

* [NO GBP] ...Remember to add SIGNAL_HANDLER (#82630)

## About The Pull Request

Just realized I forgot to add `SIGNAL_HANDLER` to the all-nighter
`on_removed_limb(...)` proc, even though it handles signals.
## Why It's Good For The Game


https://github.com/tgstation/tgstation/blob/fe26373572e41415ec12e2b0785f0c6dc2567577/code/__DEFINES/dcs/helpers.dm#L9-L11

* React cleanup (#82607)

## About The Pull Request
- No defaultHooks in react. Might fix issues where pages were not
scrollable on hover.
- createRef in a functional component. should be useref

## Why It's Good For The Game
Code improvement

* Security photobooths have their own ID (#82628)

## About The Pull Request

Prevents the HoP's photobooth button from connecting to the security
photobooth via having the same ID.

## Why It's Good For The Game

I forgot to add this when I made the security photobooth but it's
important that by default without any varedits, the HoP and security
photobooths stay separate.

## Changelog

🆑
fix: The HoP's photobooth button is now consistently connected to the
HoP's photobooth.
/🆑

* Fix buckled alert unbuckling not working properly (#82627)

## About The Pull Request

So funny thing, while trying to reproduce a different issue on the
current master, I coincidentally let my local instance start without
reading, latejoined on the shuttle, and I noticed it wasn't letting me
unbuckle as easily.

Looking into this a bit later, it seems as if it's a line #82593
accidentally changed while moving around the
`/mob/living/carbon/resist_buckle()` proc's flow.

https://github.com/tgstation/tgstation/blob/fe26373572e41415ec12e2b0785f0c6dc2567577/code/modules/mob/living/carbon/carbon.dm#L238-L241
While before it was
```dm
/mob/living/carbon/resist_buckle()
	if(HAS_TRAIT(src, TRAIT_RESTRAINED))
		(...)
	else
		buckled.user_unbuckle_mob(src,src)
```
Just changing this to `buckled.user_unbuckle_mob(src, src)` fixes this.
## Why It's Good For The Game

Fixes buckled alert unbuckling not working properly.
Fixes #82627.

## Changelog
🆑
fix: Clicking the buckled alert unbuckles you again.
/🆑

* Advanced camera consoles correctly deactivates when something happens to it or the user (#82619)

## About The Pull Request
- Fixes #82520

1. The eye deactivates when the machine is destroyed/deleted
2. The eye deactivates when the machine loses power
3. The computer constantly moniters the users status inside `process()`
and will deactivate when anything happens to them. Its not enough to
just hook onto to the mobs `COMSIG_MOVABLE_MOVED` signal. Literarly
anything can happen to them so we have to check constantly for any
changes

## Changelog
🆑
fix: advanced camera consoles correctly deactivate when something
happens(no proximity, no power etc) to its user
/🆑

* Oven tray checks for ovens (#82615)

## About The Pull Request
- Fixes #82610

Only oven trays have this proc not serving trays or other stuff
![Screenshot
(408)](https://github.com/tgstation/tgstation/assets/110812394/4867cc14-9df3-4398-9d2d-f8e38b5f0da9)

Also oven trays have a null atom storage which prevents it from being
put back in the oven after taking it out. So we remove that check

## Changelog
🆑
fix: you can put back the oven tray after you take it out
fix: only oven trays are allowed in ovens preventing baked food runtimes
/🆑

* Living Limb fixes (feat: Basic mobs attack random body zones again) (#82556)

## About The Pull Request

Reworks Living Limb code to fix a bunch of runtimes and issues I saw
while testing Bioscrambler.
Specifically, the contained mobs are now initialised via element
following attachment so that signal registration can occur at the
correct time. This allows limbs to function correctly when added from
nullspace via admin panel or bioscrambler.

Secondarily (and more wide-ranging) at some point (probably #79563) we
inadvertently made basic mobs only attack the target's chest instead of
spreading damage.
This is problematic for Living Flesh which can only attach itself to
damaged limbs but was left unable to attack damaged limbs.

I've fixed this in a way which is maybe stupid: adding an element which
randomises attack zone pre-attack.
Living limbs also limit this to _only_ limbs (although it will fall back
to chest if you have no limbs at all).
This is _technically_ still different, the previous behaviour used
`adjustBruteLoss` and `adjustFireLoss` and would spread the damage
across your entire body, but there isn't a route to that via the new
interface and this seems close enough.

## Changelog

🆑
fix: Living Limbs created by Bioscrambler will be alive.
fix: Living Limbs can once more attach themselves to your body.
balance: Living Limbs will prioritise attacking your limbs.
fix: Basic Mobs will once again spread their damage across body zones
instead of only attacking your chest.
/🆑

* RPG Loot: Revisited & READY (#82533)

Revival of #72881

A new alt click window with a tarkov-y loading spinner. Replaces the
object item window in stat panel.

<details>
<summary>vids</summary>

toggleable grouping:

![syAA5zf6RK](https://github.com/tgstation/tgstation/assets/42397676/c89b372d-29f6-4ebe-895d-f73bbdc41c19)

now lists the floor as first obj:

![abc](https://github.com/tgstation/tgstation/assets/42397676/cd8dc962-2ac7-41bf-a5d3-b9e926116b06)

in action:

![dreamseeker_IkrPKt2QZt](https://github.com/tgstation/tgstation/assets/42397676/1f990aa0-60f0-47e7-9d93-b63e35d05273)

</details>

- search by name
- 515 image generator is much faster than alt click menu
- opening a gargantuan amount of items shouldnt freeze your screen
- groups similar items together in stacks by default, toggleable
- shows tile as first item
- <kbd>Shift</kbd> and <kbd>Ctrl</kbd> compatible with LMB
🖱️
- RMB points points at items (sry i could not get MMB working)
- key <kbd>Esc</kbd> to exit the window.

For devs:
- A new image generation tech.
- An error refetch mechanic to the Image component
- It does not "smart track" the items being added to the pile, just
reopen or refresh. This was a design decision.

Honestly I just dislike the stat panel

Fixes #53824

Fixes

![image](https://github.com/tgstation/tgstation/assets/42397676/0e50faab-7d4d-4bf7-8c5b-4ac28547bfbd)

🆑
add: Added a loot window for alt-clicking tiles.
del: Removed the item browser from the stat panel.
/🆑

---------

Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: AnturK <AnturK@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>

* Reverts parts of #82602 (nodeath checks) (#82637)

## About The Pull Request

Reverts the nodeath checks of #82602

I opened a review thinking these checks were sus and the PR author said
they would remove them, but it was merged before that happened.

TL;DR 

1. I just noticed this now but it only affects carbons / humans it
doesn't even cover living or any other subtypes
2. Kinda sus. Some code intentionally skips checking nodeath (I guess?
Like removing the brain for example) so we would need a larger audit of
this rather than haphazardly throwing it in.

* Fixes to battle arcade (#82620)

## About The Pull Request

Added gear for world nine, removed the "Gear" gear that did nothing.
Made counterattacks to kill an enemy properly kill the enemy.
I renamed some gear items to fit the theme of the area they are unlocked
in just as a small thing.

## Why It's Good For The Game

Closes https://github.com/tgstation/tgstation/issues/82613

## Changelog

🆑
fix: Battle arcade's higher levels no longer gives you a "Gear" gear,
and counterattacks can now properly kill enemies.
/🆑

* Fixes SMES terminal placing under the SMES and not under the player (#82665)

## About The Pull Request

Changes `src` to`user` to get intended behavior.

* Birdshot: Toy crate (#82633)

## About The Pull Request
Gives the clown+mime their toy crate.
## Why It's Good For The Game
*honk*

* tram ai sat starts with a full smes (#82646)

## About The Pull Request

consistency and also this is fixes a bug introduced by that one power
refactor

## Why It's Good For The Game

bug bad

## Changelog
🆑
fix: tramstation AI sat starts full
/🆑

* [no gbp] Space Ruin bioscramblers shouldn't chase people around (#82649)

## About The Pull Request

See title
They wouldn't lock on to people on the station from a space ruin, but
would to whoever entered their z level the second it was entered.
Also fixes bug where I changed `status_flags` to `status_effects` for
some reason which isn't where you look for godmode

## Why It's Good For The Game

We have a space ruin whcih several (coreless) anomalies spawn on, the
bioscrambler was put as an option because it was already immortal. It's
weird though to zone into the ruin and immediately have every anomaly in
there lock onto you, the best intended effect is probably for these ones
specifically not to be bloodthirsty.
We kind of only care about that behaviour on the station.

## Changelog

🆑
fix: Anomalous Research ruin Bioscrambler anomalies won't home in on
targets
fix: Bioscrambler won't randomly drop its target for no reason
/🆑

* Sunders the many unused sprites and organizes what's left in structures.dmi (#82658)

## About The Pull Request
Hello again, I noticed the /obj/structures.dmi file had a lot of unused
stuff like tables from two generations ago, so I changed some stuff
around:
- Many unused, old icons deleted, mostly window variants used in old
smoothing systems I imagine
- Reorganized many sprites in the file so they're more grouped together
- Tweaked some barricade sprite naming to be consistent/standardized,
and to let others know they're not _too_ old...
- Fixed a misnomer that I believe was making directional tinted windows
look like frosted windows

## Why It's Good For The Game
Saves on file space, and satisfies your brain's pattern recognition bits

### Spriting
Old: 

![image](https://github.com/tgstation/tgstation/assets/143908044/0717940e-787e-40ee-85e2-0a0c5ebc0837)

New:

![image](https://github.com/tgstation/tgstation/assets/143908044/3954ba3b-b261-4700-986a-d30f3aa0e2a6)
also good lord those linen bin sprites are a crime

## Changelog
🆑
fix: Probably fixed directional tinted windows looking like directional
frosted windows
image: Deleted a bunch of unused structure sprites
/🆑

* Birdshot Wall Sanity Pass (#82598)

## About The Pull Request

Cleans up minor artifacting in the Birdshot Sec-Tram Closed Turfs

## Why It's Good For The Game

Someone definitely didn't mean to place some machines under Closed
Turfs. This barely qualifies as player facing.

## Changelog

🆑
fix: Cleans up some rocks on Birdshot
/🆑

* [NO GBP] Fixes deconstruction of closets & crates under a special case (#82612)

## About The Pull Request
So if a closet/crate has the `NO_DEBRIS_AFTER_DECONSTRUCTION` set on it
and if someone/something is still inside, then after deconstruction they
get deleted rather than getting dumped out first.

Could cause potential hard delete of mobs & stuff. We don't want to deal
with that

## Changelog
🆑
fix: 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
/🆑

* Fixes ordinance lab igniter in IceBox (#82595)

## About The Pull Request
- Fixes #82294

Basically the same idea of merging ordanance lab with the burn chamber
so they share the same apc as already implemented in #82322

## Changelog
🆑
fix: Ordinance lab igniter in Icebox works again 
/🆑

* Birdshot: engi wardrope. (#82639)

## About The Pull Request

Add engi wardrope on Birdshot.

## Why It's Good For The Game

Birdshot doesn't have engi wardrope.

🆑
fix: Birdshot now have engi wardrope
/🆑

* Gives shadow walk a new, spookier, and shorter sound effect that no longer ignores walls (#82689)

## About The Pull Request

This gives shadow walk a snazzy new sound effect for entering/exiting
jaunt.


https://github.com/tgstation/tgstation/assets/28870487/c25f720f-5bad-4063-8d6e-140fd41bd740

This also has the sounds it plays no longer passes through walls.
## Why It's Good For The Game

The ethereal_entrance/exit sound effects are drawn out, and pretty
grating. They work for the other jaunts they're used for because a jaunt
typically lasts longer than the sound itself. Nightmares are frequently
dancing in and out of jaunt, and the sound effects for entering/exiting
tend to overlap. It gets loud and annoying really fast.

This sound effect is quicker, spookier, and more distinct.

As for making the sound not ignore walls, I think it's pretty dumb how
easy it is to detect the spooky scary shadow antag just by sitting in
your department. It takes a lot of the initial fear and paranoia they
have the potential for is wasted when Joe Geneticist can hear them
messing around in their territory without having to leave their chair.
## Changelog
🆑 Rhials
sound: Nightmare has a new sound effect for entering/exiting shadow
jaunt. It also no longer can be heard through walls.
/🆑

* [MIRROR] Alt click refactor (#2029)

* Alt click refactor

* Some early conflict removal

* Big modular refactor

* Update console.dm

* Update paper.dm

---------

Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Co-authored-by: Mal <13398309+vinylspiders@users.noreply.github.com>

* Yeets `ATTACK_QDELETED`, fixes welding torches not using fuel on attacking non-mobs (2 year old bug)  (#82694)

## About The Pull Request

- Deletes `ATTACK_QDELETED`
- May have been necessary in the past but it's pointless now. All it
does is clutter the attack chain. Perish.

- Fixes welders not using fuel on attacking non-mobs
- #65762 "fixed" welders consuming fuel on clicking turfs by adding an
`isliving` check and not an `ismovable` check?


## Changelog

🆑 Melbert
fix: Blobs may rejoice, welding torches now consume fuel when attacking
objects again after two years.
/🆑

* electric_welder fire

* Quirks, which give items, now have quirk_item arg specified as obj/item, instead of being just a var (#82650)

## About The Pull Request
quirk_item is now /obj/item, since it will allow for calling procs or
getting variables from this item

It's required for non-modular translation to call for item's name to
remove articles

## Why It's Good For The Game
It's always an item, and if it's a path, it's already checked for it.
Better usage in the future.

* turns martial arts gloves into a component (#82599)

sleeping carp gloves also work on mind init

this means for the sake of deathmatch you dont have to put them off and
on

fixes #82321

🆑
fix: you no longer need to put your sleeping carp gloves off and on in
Deathmatch to get the martial art
/🆑

---------

Co-authored-by: san7890 <the@san7890.com>

* Regal Rats can now tear down posters (#82673)

## About The Pull Request

i was fixing something on bagil and someone who was playing a regal rat
(after the round ended) said they wanted to be able to tear down posters
as a regal rat so i decided to code it because it made sense.

it's an element so literally any mob can tear down posters but i can't
think of any other mobs that would make sense to let it tear down
posters so we'll leave it just for _The Champion of All Mislaid
Creatures_ for now
## Why It's Good For The Game

Regal Rats should be all about sludgemaxxing and fucking up maintenance
to make it look even more grody than it should be. Being able to tear up
those disgusting and well-drawn posters to leave behind nothing but
scraps fits that motif. The element has a `do_after()` just to make sure
His Holiness doesn't accidentally tear down his posters while clicking
(i think all mobs should have this but that's a different issue man)

also includes some code improvement and user feedback in some failure
cases that already existed in the code.
## Changelog
🆑
add: 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.
/🆑

* Adds "Strong Stomach" quirk, a core CDDA/PZ quirk we've sorely been missing. Also Deviant Tastes dirty food re-nerf. (#82562)

## About The Pull Request

- Adds Strong Stomach quirk. 
   - 4 points
   - You can eat dirty food without risk of getting disease. 
- You suffer less negative effects from vomiting. Vomit stuns you for
half the duration, and you lose half as much nutrition.

- Reverts https://github.com/tgstation/tgstation/pull/76864 , integrates
its effects into Strong Stomach instead.

## Why It's Good For The Game

- Lotta people (namely Lizards and sometimes Felines with Deviant
Tastes) run gimmicks involving them being a gremlin person and eating
trash off the ground, and it's rather hard to accomplish this now since
it makes you a public medbay enemy # 1. This quirk should give them an
option to avoid that.
- Also (as mentioned in the title) both CDDA and PZ have this trait and
I can't believe we're missing it! This is something in
modifiable-character-traits/quirks-101.

- I moved the effects from #76864 to this quirk because 1. I thought it
was more fitting and 2. I thought the original PR was kinda wack for
what is (generally) a neutral quirk.

## Changelog

🆑 Melbert
add: 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.
del: Deviant Tastes no longer prevents you from getting a negative
moodlet from eating dirty food. Strong Stomach does that now.
/🆑

---------

Co-authored-by: Jacquerel <hnevard@gmail.com>

* Remove several functions from collections.js which have ES5 equivalents (#82417)

* Makes it EVEN EASIER to work with atom item interactions ft. "Leaf and Branch" & "Death to Chains" (#82625)

* apc fix

* Gulag Adjustments Two (#82561)

## About The Pull Request

I have received feedback that after the prior changes in #81971, the
gulag is still a little bit too subject to RNG.
The main culprit (as in my previous PR) is Iron being kind of cheap and
the fact that unlike the old Gulag you no longer have any way of
headhunting more valuable materials (everything appears as boulders on
your ore scanner).

My solution to this is wider than the last one of tweaking point values,
but also much simpler:
Just make every boulder you mine be worth the same amount of points
regardless of what is inside of it.

On the average test I made I could comfortably mine about 40-45 boulders
in ten minutes.
We'll make some adjustments to that rather than leaving 40 as the target
number;
Most players upon being teleported to the gulag are going to spend a few
minutes whining and bemoaning their fate instead of getting straight to
work. I had the benefit of being able to make sure my run started as
soon as a storm ended so I wouldn't need any kind of midpoint break. I
was also always the only person playing on my local instance, there
hadn't been any other pesky prisoners before me who had already mined
out all the nearest available deposits. And of course, let us not
forget, I am an MLG master league ss13 player who was surely performing
well above average.

So we'll round that down to: Each boulder is worth 33 points, meaning
you need to collect 31 boulders to complete a 1000 point (roughly ten
minute) sentence.

How do I ensure that every boulder is worth the same amount of points?
Well it's pretty easy.
One boulder = one material sheet. One material sheet = 33 points.
Simple.

"Now Jacquerel", I hear you not saying because you don't want me to know
about this thing you would prefer to do instead of hitting rocks
outside; "if I simply smash all of the tables and microwaves and botany
trays and bed in the gulag I can easily get like 65 sheets of Iron,
which is almost enough to buy the freedom for two entire people!"
Unfortunately I knew you were going to try and do that and the prisoner
point machine will only give you points for material sheets which have
been printed from the material smelter (well, any material smelter
actually but you should probably use the one in the gulag). You'll be
able to tell because if you examine a valid material sheet it will
mention a little maker's mark on it, which is absent in the beat-up iron
that you get from smashing furniture to bits.

Also glass is worth 0 points. Don't waste time digging up that shit. 

As glass has had all of its point value removed, I have added a "work
pit" to the gulag to compensate. You can pull boulders out of this
indefinitely via effort, however it also stamcrits you every time.
It's not very fun to do this, but that's because I would prefer you to
go find the rocks out in the field instead. This is a last resort.
You can do this if there's no boulders left to mine or if you really
really really hate mining and would rather very slowly click on one tile
repeatedly to get your boulders instead.
As a tiny bonus doing this gives workout experience.

This isn't a totally ideal solution but I think it'll do for now.

## Why It's Good For The Game

What we want out of the gulag is:
- Something where officers can vaguely approximate an expected sentence
duration.
- A task that requires players to actually be spending that time doing
something to get out of here.
- Produces at least some amount of useful materials.

In I think roughly that order.
I hope this change accomplishes all three of these in a way that is
somewhat predictable rather than throwing darts at a board.

## Changelog

🆑
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.
add: 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...
/🆑

* stone

* Makes test merge bot continue with other PRs if updating one fails. (#82717)

Right now updating
https://github.com/tgstation/tgstation/pull/81089#issuecomment-1907296233
fails because it exceeds github character limit for comments.

This will make it work until backed is updated.

* Fixes the RnD console by adding a removed import (#82750)

## About The Pull Request
The 'map' import was removed from this file by #82417 but it's still
used in place in code. This re-adds the import

## Why It's Good For The Game
Fixes RnD consoles

## Changelog
🆑
fix: Fixed RnD consoles not being able to be opened.
/🆑

Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>

* Fixes cargo import (#82755)

## About The Pull Request
One of the imports got removed and there were no warnings... Man if only
there were a technology that could warn us in advance
## Why It's Good For The Game
UI fixes
## Changelog
🆑
fix: Fixed a bluescreen in cargo console
/🆑

* fixes

* Fixes, fixes.

* Pre-emptive mirror of https://github.com/tgstation/tgstation/pull/82892

* Turf weakref persists in changeturf / Fix plasma cutters  (#82906)

## About The Pull Request

Turf references don't change so logically, turf weakrefs wouldn't change
if the turf changes.

By not doing this this can cause bugs: See #82886 . (This Fixes #82886) 

(Projectiles hold a list of weakrefs to atoms hit to determine what they
have already hit.

Because turf weakrefs reset, we could "hit" the same turf twice if it
destroyed the turf.

Old behavior - this was fine but now that they're weakrefs, we get two
weakref datums in the list that point to the same ref.)

Less hacky alternative to #82901 . (Closes #82901) 

## Changelog

🆑 Melbert
fix: Plasma cutters work again
/🆑

---------

Co-authored-by: san7890 <the@san7890.com>
Co-authored-by: Interception&? <137328283+intercepti0n@users.noreply.github.com>
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: Ketrai <zottielolly@gmail.com>
Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Co-authored-by: Jacquerel <hnevard@gmail.com>
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: AnturK <AnturK@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: Iajret <8430839+Iajret@users.noreply.github.com>
Co-authored-by: vect0r <71346830+Vect0r2@users.noreply.github.com>
Co-authored-by: jimmyl <70376633+mc-oofert@users.noreply.github.com>
Co-authored-by: AMyriad <143908044+AMyriad@users.noreply.github.com>
Co-authored-by: Zytolg <33048583+Zytolg@users.noreply.github.com>
Co-authored-by: Xackii <120736708+Xackii@users.noreply.github.com>
Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com>
Co-authored-by: NovaBot <154629622+NovaBot13@users.noreply.github.com>
Co-authored-by: Mal <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: larentoun <31931237+larentoun@users.noreply.github.com>
Co-authored-by: Arthri <41360489+Arthri@users.noreply.github.com>
Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
Co-authored-by: Useroth <37159550+Useroth@users.noreply.github.com>
This commit is contained in:
SpaceLoveSs13
2024-04-29 01:54:01 +05:30
committed by GitHub
parent c54406fff1
commit ba5c112a86
549 changed files with 6500 additions and 5378 deletions
+7 -4
View File
@@ -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 = ""
@@ -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)
@@ -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 @@
<br>
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"
@@ -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)
+1 -1
View File
@@ -491,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
+6 -4
View File
@@ -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))
-2
View File
@@ -44,8 +44,6 @@
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/atom_deconstruct(disassembled = TRUE)
var/amount_mod = disassembled ? 0 : -2
+2 -4
View File
@@ -37,16 +37,14 @@
update_appearance()
return secured
/obj/item/assembly/health/AltClick(mob/living/user)
if(!can_interact(user))
return
/obj/item/assembly/health/click_alt(mob/living/user)
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."))
return CLICK_ACTION_SUCCESS
/obj/item/assembly/health/process()
//not ready yet
-2
View File
@@ -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(..())
-2
View File
@@ -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)
. = ..()
@@ -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
@@ -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
@@ -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
@@ -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()
@@ -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)
@@ -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)]"
@@ -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)
@@ -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)]"
@@ -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)]"
@@ -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)
@@ -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()
. = ..()
@@ -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()
. = ..()
@@ -645,14 +645,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)
@@ -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()
@@ -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()
@@ -144,12 +144,10 @@
. += span_notice("Heat capacity at <b>[heat_capacity] Joules per Kelvin</b>.")
. += span_notice("Temperature range <b>[min_temperature]K - [max_temperature]K ([(T0C-min_temperature)*-1]C - [(T0C-max_temperature)*-1]C)</b>.")
/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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -162,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)
. = ..()
@@ -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
+2 -2
View File
@@ -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)
+8 -7
View File
@@ -11,6 +11,7 @@
hitsound = null
attack_verb_continuous = list("attacks")
attack_verb_simple = list("attack")
interaction_flags_click = NEED_DEXTERITY|FORBID_TELEKINESIS_REACH
/// The amount of time it takes to shuffle
var/shuffle_time = DECK_SHUFFLE_TIME
/// Deck shuffling cooldown.
@@ -145,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())
+4 -4
View File
@@ -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
/// 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
+10 -6
View File
@@ -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
+3 -3
View File
@@ -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)
. = ..()
+3 -2
View File
@@ -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
+3 -2
View File
@@ -549,6 +549,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()
@@ -589,8 +591,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
@@ -621,6 +621,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
QDEL_NULL(void)
QDEL_NULL(tooltips)
QDEL_NULL(open_loadout_ui) //SKYRAT EDIT ADDITION
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
+24 -27
View File
@@ -65,23 +65,19 @@
H.set_eye_blur_if_lower(10 SECONDS)
eyes.apply_organ_damage(5)
/obj/item/clothing/glasses/AltClick(mob/user)
. = ..() //SKYRAT EDIT ADDITION
if(glass_colour_type && !forced_glass_color && ishuman(user))
var/mob/living/carbon/human/human_user = user
/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 (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)
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
@@ -664,18 +660,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"
+18 -16
View File
@@ -173,6 +173,8 @@
armor_type = /datum/armor/fedora_det_hat
icon_state = "detective"
inhand_icon_state = "det_hat"
interaction_flags_click = NEED_DEXTERITY|NEED_HANDS
/// Cooldown for retrieving precious candy corn on alt click
var/candy_cooldown = 0
dog_fashion = /datum/dog_fashion/head/detective
///Path for the flask that spawns inside their hat roundstart
@@ -198,17 +200,16 @@
. = ..()
. += span_notice("Alt-click to take a candy corn.")
/obj/item/clothing/head/fedora/det_hat/AltClick(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
/obj/item/clothing/head/fedora/det_hat/click_alt(mob/user)
if(candy_cooldown >= world.time)
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/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
return CLICK_ACTION_SUCCESS
/obj/item/clothing/head/fedora/det_hat/minor
flask_path = /obj/item/reagent_containers/cup/glass/flask/det/minor
@@ -221,6 +222,7 @@
icon_state = "detective"
inhand_icon_state = "det_hat"
dog_fashion = /datum/dog_fashion/head/detective
interaction_flags_click = FORBID_TELEKINESIS_REACH
///prefix our phrases must begin with
var/prefix = "go go gadget"
///an assoc list of phrase = item (like gun = revolver)
@@ -277,7 +279,7 @@
return
var/input = tgui_input_text(user, "What is the activation phrase?", "Activation phrase", "gadget", max_length = 26)
if(!input)
if(!input || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
if(input in items_by_phrase)
balloon_alert(user, "already used!")
@@ -293,16 +295,16 @@
/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)
if(!phrase || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
user.put_in_inactive_hand(items_by_phrase[phrase])
/obj/item/clothing/head/fedora/inspector_hat/AltClick(mob/user)
. = ..()
/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
if(!new_prefix || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return CLICK_ACTION_BLOCKING
prefix = new_prefix
return CLICK_ACTION_SUCCESS
/obj/item/clothing/head/fedora/inspector_hat/Exited(atom/movable/gone, direction)
. = ..()
+7 -5
View File
@@ -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
/// 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)
+6 -5
View File
@@ -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"]. <b>Alt-click</b> 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)
+35 -31
View File
@@ -53,34 +53,36 @@
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
/obj/item/clothing/mask/bandana/click_alt(mob/user)
if(!iscarbon(user))
return NONE
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."))
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"
@@ -229,14 +231,16 @@
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
/obj/item/clothing/mask/facescarf/attack_self(mob/user)
adjustmask(user)
/obj/item/clothing/mask/facescarf/AltClick(mob/user)
..()
if(user.can_perform_action(src, NEED_DEXTERITY))
adjustmask(user)
/obj/item/clothing/mask/facescarf/click_alt(mob/user)
adjustmask(user)
return CLICK_ACTION_SUCCESS
/obj/item/clothing/mask/facescarf/examine(mob/user)
. = ..()
+4 -4
View File
@@ -12,6 +12,7 @@
flags_cover = MASKCOVERSMOUTH
visor_flags_cover = MASKCOVERSMOUTH
resistance_flags = NONE
interaction_flags_click = NEED_DEXTERITY
/datum/armor/mask_breath
bio = 50
@@ -23,10 +24,9 @@
/obj/item/clothing/mask/breath/attack_self(mob/user)
adjustmask(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)
adjustmask(user)
return CLICK_ACTION_SUCCESS
/obj/item/clothing/mask/breath/examine(mob/user)
. = ..()
-8
View File
@@ -12,14 +12,6 @@
"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)
. = ..()
+5 -5
View File
@@ -73,10 +73,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 +87,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 +100,7 @@
)
update_appearance(UPDATE_ICON)
user.update_clothing(ITEM_SLOT_NECK)
return CLICK_ACTION_SUCCESS
/obj/item/clothing/neck/tie/update_icon()
. = ..()
+8 -9
View File
@@ -181,8 +181,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)
@@ -196,11 +195,11 @@
to_chat(user, span_notice("You quietly set to work [tied ? "untying" : "knotting"] [loc]'s [src.name]..."))
if(HAS_TRAIT(user, TRAIT_CLUMSY)) // based clowns trained their whole lives for this
mod_time *= 0.75
// SKYRAT EDIT START
// SKYRAT EDIT ADDITION START
if(HAS_TRAIT(user, TRAIT_STICKY_FINGERS)) // Clowns with thieving gloves will be a menace
mod_time *= 0.5
// SKYRAT EDIT END
if(do_after(user, mod_time, target = our_guy, extra_checks = CALLBACK(src, PROC_REF(still_shoed), our_guy)))
// SKYRAT EDIT ADDITION END
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)
@@ -210,12 +209,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)
@@ -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
/// 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)
@@ -87,9 +87,9 @@
else
. += span_notice("There's nothing placed on the helmet.")
/obj/item/clothing/head/helmet/space/plasmaman/AltClick(mob/user)
if(user.can_perform_action(src))
toggle_welding_screen(user)
/obj/item/clothing/head/helmet/space/plasmaman/click_alt(mob/user)
toggle_welding_screen(user)
return CLICK_ACTION_SUCCESS
/obj/item/clothing/head/helmet/space/plasmaman/ui_action_click(mob/user, action)
if(istype(action, /datum/action/item_action/toggle_welding_screen))
+2 -6
View File
@@ -47,12 +47,7 @@
. += span_notice("<b>Alt-click</b> 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"
+17 -16
View File
@@ -51,33 +51,37 @@
if(random_sensor)
//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()
if(!unique_reskin) // Already registered via unique reskin
register_context()
AddElement(/datum/element/update_icon_updates_onmob, flags = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING, body = TRUE)
/obj/item/clothing/under/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
. = NONE
/obj/item/clothing/under/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
. = ..()
var/changed = FALSE
if(isnull(held_item) && has_sensor == HAS_SENSORS)
context[SCREENTIP_CONTEXT_RMB] = "Toggle suit sensors"
. = CONTEXTUAL_SCREENTIP_SET
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 : NONE
return .
/obj/item/clothing/under/worn_overlays(mutable_appearance/standing, isinhands = FALSE, file2use = null, mutant_styles = NONE)
. = ..()
@@ -349,17 +353,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)
. = ..()
+1
View File
@@ -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."
+9 -9
View File
@@ -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)
. = ..()
@@ -238,6 +238,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
+2 -4
View File
@@ -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)
. = ..()
@@ -63,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
@@ -79,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()
+15 -15
View File
@@ -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)
@@ -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)
. = ..()
@@ -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)
. = ..()
+53 -7
View File
@@ -99,15 +99,24 @@
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
@@ -243,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
@@ -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
@@ -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))
@@ -280,8 +280,8 @@
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
+2 -3
View File
@@ -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!
+4 -4
View File
@@ -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
-2
View File
@@ -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)
. = ..()
+2 -2
View File
@@ -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)
+75
View File
@@ -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
+49
View File
@@ -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)
+19
View File
@@ -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()
+48
View File
@@ -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("\
<span class='bolddanger'>Your version of Byond doesn't support fast image loading.</span>\n\
Detected: [version].[build]\n\
Required version for this feature: <b>515.1635</b> or later.\n\
Visit <a href=\"https://secure.byond.com/download\">BYOND's website</a> 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)
+84
View File
@@ -0,0 +1,84 @@
/**
* ## 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))
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)
if(ismob(item) || length(item.overlays) > 2)
icon = costly_icon2html(item, owner, sourceonly = TRUE)
else // our pre 515.1635 fallback for normal items
icon = 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)
+39
View File
@@ -0,0 +1,39 @@
/// Queues image generation for search objects without icons
SUBSYSTEM_DEF(looting)
name = "Loot Icon Generation"
init_order = INIT_ORDER_LOOT
priority = FIRE_PRIORITY_PROCESS
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--
+42
View File
@@ -0,0 +1,42 @@
/// 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;"
user.ClickOn(thing, modifiers)
return TRUE
@@ -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)
@@ -363,20 +363,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/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/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/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"
+3 -4
View File
@@ -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)
@@ -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
@@ -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
+19 -18
View File
@@ -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
+10 -13
View File
@@ -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"
@@ -154,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 */
@@ -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")
+6 -16
View File
@@ -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
@@ -155,8 +142,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 +178,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
+9 -3
View File
@@ -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
+10 -12
View File
@@ -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)
+9 -9
View File
@@ -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
+6
View File
@@ -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)
+3 -6
View File
@@ -41,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.
@@ -362,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)
@@ -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)
@@ -38,6 +38,9 @@
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)
. = ..()
if(current_bodypart)
@@ -71,6 +74,8 @@
if(!victim.CanReach(movable))
continue
candidates += movable
if(!length(candidates))
return
var/atom/movable/candidate = pick(candidates)
if(isnull(candidate))
return
@@ -123,9 +128,9 @@
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!"))
var/obj/item/bodypart/new_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here
new_bodypart.replace_limb(target, TRUE)
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)
@@ -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,\
@@ -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)
+4 -5
View File
@@ -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
+63 -39
View File
@@ -240,25 +240,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)
@@ -282,34 +291,40 @@
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)
@@ -410,6 +425,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)
@@ -426,7 +444,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
@@ -449,11 +470,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)
+1 -1
View File
@@ -1,5 +1,5 @@
/mob/living/carbon/death(gibbed)
if(stat == DEAD || HAS_TRAIT(src, TRAIT_NODEATH) && !gibbed)
if(stat == DEAD)
return
losebreath = 0
@@ -20,7 +20,7 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift)
new /obj/effect/decal/remains/human(loc)
/mob/living/carbon/human/death(gibbed)
if(stat == DEAD || HAS_TRAIT(src, TRAIT_NODEATH) && !gibbed)
if(stat == DEAD)
return
stop_sound_channel(CHANNEL_HEARTBEAT)
var/obj/item/organ/internal/heart/human_heart = get_organ_slot(ORGAN_SLOT_HEART)
@@ -222,7 +222,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 || HAS_TRAIT(user, TRAIT_STICKY_FINGERS))) //SKYRAT EDIT ADDITION original if (!result)
warn_owner(source)
@@ -731,10 +731,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."))
-1
View File
@@ -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)
-1
View File
@@ -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.
-3
View File
@@ -66,9 +66,6 @@
handle_wounds(seconds_per_tick, times_fired)
if(machine)
machine.check_eye(src)
if(stat != DEAD)
return 1

Some files were not shown because too many files have changed in this diff Show More