Commit Graph
1802 Commits
Author SHA1 Message Date
df7832aa43 Replaced our NPC AI with Behavior Trees. (#96628)
This PR replaces our current NPC AI with a [behavior tree
system](https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)).
Behavior trees are a common way of creating AI in which you place nodes
in a tree structure to define what actions an AI should take.

AI controllers defined a list of /datum/ai_planning_subtree types in
behavior_nodes. Each subtree was a self-contained unit that could call
queue_behavior() to fire off /datum/ai_behavior actions. The controller
iterated subtrees in order, each one deciding independently whether to
queue something and deciding whether the next subtree would run.

This has a few issues:
1. There's no real structure; you are just defining a list of things to
try in order.
2. There was a loooot of subtrees that were basically the same as
another but with some slight modification
3. It was hard to understand.

Controllers now define a single json file describing a tree of nodes.
The tree is composed of structural composites:

Sequence - do A, then B, then C (and so on)
Selector - try A, if it fails try B, then C (and so on)
Parallel - run A and B simultaneously, with configurable failure/success
policies and or looping behavior
Subplan - loop a child continiously

Along that we also have "Decorators". These are nodes that basically
check a condition (E.g.; do we have a combat target). These decorators
can be used to gate behavior and are re-useable across behavior trees.
They also have a concept known as "Observers". Which lets them cancel
lower priority behavior in case their condition changes (Which we check
whenever a signal fires that fits that specific decorator). This makes
the AI much more responsive to change in environment.

For behaviors, we still use the ai_behavior datums. These are the actual
behaviors such as "Move to X", "Attack X". The only major change is that
these can no longer sleep() since they now run in the ai_controller.

Lastly, we now also have subtrees, except now they are essentially
pieces of behavior tree that can be re-used, or even overriden at
runtime or as a variable. Allowing for making modular AI made out of
several smaller trees.

You can set variables on these nodes directly via the extension (see
below), which should reduce the need to make subtypes of behaviors by a
lot. All of these vars are saved on the JSON and will be applied at
runtime.

If you are using subtrees, you can also assign "bindings" to these
variables, which will allow instances of the subtree to override those
variables.

Since a tree structure with variables becomes hard to parse in a JSON,
I've made a VSCode extension to edit these JSONs:

https://marketplace.visualstudio.com/items?itemName=BehaviorTreeG.behaviortreeg
https://github.com/CabinetOnFire/BehaviorTreeG

<img width="1795" height="1268" alt="image"
src="https://github.com/user-attachments/assets/56aa2f0b-3cf9-449f-bca4-8281fca82db6"
/>

This extension allows you to edit the behavior tree JSONs, and browse
through all the behaviors/decorators/subtrees we have

If you'd like more info on how to build these AI check out the
learn_ai.md. I will also make a tutorial to go over more depth on what
the system offers because I kind of suck at doing technical write-ups.

Targetting has been changed to. I've made a new acquire_targets behavior
that takes a target_source (what am I targetting) and
targetting_strategy (what does the candidate need to fulfill to be
considered a target). This allows us to make composites targetting
combinations to reduce the amount of specific find_and_set esque
behaviors we had before. Not everything is ported to this system but
that would be a longer term goal.

I've added a new build_bt script that converts all the behavior tree
JSONs into compiled versions. Why is this needed? Because I wanted to
keep using defines in behavior trees, so we need a way to convert this
into literal values before we send it to DM. This script runs on compile
and should also run in CI (If I didn't fuck that up!). This saves to a
new build/ folder.

I've ported every single AI in the game to this system (except raptors,
Kobsa is working on those so should be in soon!), so I do expect some
bugs to come out of this. But I also fixed some issues that have
probably been in the game for a long time such as:
- Fixed penguins being unable to fish
- Fixed bileworms not being able to devour people
- Fixes goldgrubs not grubbing gold (they could not mine!)
- Lizards actually eat food they find

Either way, I'd reccomend a long TM on this.

1. (Hopefully) a better development experience for making AI
2. Less copy-paste for behaviors, we should be able to re-use more
pieces to make behavior
3. Behavior trees is a more common pattern in making AI, so it should be
easier to find resources to find out how to do things.

🆑 CabinetOnFire, Iamgoofball, SmartKar, Ben10omintrix
refactor: Replaces our AI system with behavior trees, porting all
datum/ai to it
/🆑

I will add this PR with more details down the line. I think I got the
big picture but its a big PR, so sorry if I missed something important.

---------

Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
2026-08-15 10:33:57 -06:00
Alexis 88e84645b1 Merge commit '6b52b564a50e4f3091470529c683587e5de15d49' into upstream-sync-7-22-2026 2026-07-22 13:39:09 -04:00
krookodilehunterandGitHub a814b1c8e4 You can pick up chicks now (and their moms) (#96873)
## About The Pull Request
For some reason, you couldn't pick up chickens or chicks. Now you can!
They can go in bags and even on your head!

A side effect of this change is baby chicks won't grow up until you drop
them on the ground, or else they would just disappear upon growing up.

In-hand sprites by [mms142](https://github.com/mms142):
<img width="258" height="130" alt="chick"
src="https://github.com/user-attachments/assets/329192cd-be75-4140-b46e-de12c58ba928"
/>
<img width="258" height="130" alt="black"
src="https://github.com/user-attachments/assets/64c29cc1-d8f5-4a3c-b678-32a307cc5003"
/>
<img width="258" height="130" alt="brown"
src="https://github.com/user-attachments/assets/325c3ecf-f374-46db-be93-25ce5165ad13"
/>
<img width="258" height="130" alt="white"
src="https://github.com/user-attachments/assets/d9c82fc3-4d1b-44be-8703-2e14ff4609f6"
/>
## Why It's Good For The Game
Chicks and chickens are small and cute and they deserve to be held
sometimes.
## Changelog
🆑
add: Chickens can be picked up and held now! Sprites by mms142
/🆑
2026-07-17 15:45:48 +02:00
0716e3fff4 Atmos refactor & speedup by utilizing BYOND 516 vector functions (#96448)
## About The Pull Request

### Summary
This PR changes internal structure of `/datum/gas_mixture`:
`gases[gas_id][MOLES]` refactored into `moles[gas_id]`,
`gases[gas_id][ARCHIVE]` into `moles_archive[gas_id]` and
`gases[gas_id][GAS_META]` into `gas_meta` static variable. This allows
us to use BYOND 516 vector functions for calculating total moles and
heat capacity. Also it simplifies some parts of the code, allowing us to
get rid of macros `ADD_GAS` and `ASSERT_GAS`. According to the profiler
`/turf/open/process_cell` time is reduced by ~20%.

### Details
`gas_mixture.gases` was a nested 2d-list with MOLES, ARCHIVE and
GAS_META for each gas_id. For example, to get gas moles you had to do
`gases[gas_id][MOLES]`. I've changed this structure to be as follows:
`moles[gas_id]` - moles for the gas, `moles_archive[gas_id]` - archived
version of moles, `gas_meta[KEY][gas_id]` - static var with meta
information for the gas.

Since I removed key GAS_META from the gases, `gas_meta` was moved to the
static variable and the order of keys in the array was changed from
`gas_meta[gas_id][META_KEY]' to 'gas_meta[META_KEY][gas_id]`. This was
done to allow using it in vector calculations (for example heat capacity
or fusion power). Static variable access is very fast and it is
considered as accessing a global in the bytecode.

Byond 516 introduced new vector functions: `values_sum`, `values_dot`
and others. These functions are very fast, but operate only on
associative lists. This allows us to change the way we calculate
total_moles and heat_capacity - very hot and heavily used functions.
`total_moles()` became just `values_sum(moles)`, and `heat_capacity` is
just a dot product: `values_dot(moles,
gas_meta[META_GAS_SPECIFIC_HEAT])`.

As a side bonus, since `moles` is just an associative list, you don't
really need old macros `ADD_GAS` and `ASSERT_GAS` - all they did was to
make a copy of a list[3] with default value [0, 0, gas_meta] for
specific gas. Now when you're adding gas you can just use `moles[gas_id]
+= amount` and when you query amount of gas you can just query the key
(for example `moles[/datum/gas/oxygen]`) if the key does not exist, it
returns null and works as 0 for all arithmetic and logic operations. For
example, old code would be `if (!air.gases[/datum/gas/oxygen] ||
air.gases[/datum/gas/oxygen][MOLES] < 1)` and now it is `if
(moles[/datum/gas/oxygen] < 1)`. This simplifies some parts of the code
and also speeds things up.

For the performance comparison I used Tracy profiler. I've done many
different tests, and they all show slightly different numbers, but
overall speedup for `process_cell` is about 20%. (-20% to average time
per call from ). My testing setup was as follows:
Load Icebox, drop 30/60/90 radius bomb in the middle of the bridge, set
code to blue, wait 10 minutes until the round ends.
Also I fixed random seed in the master controller and in the planetary
gas randomization so generated maps are the same between tests.
Althought it's not very realistic, it generates a lot of samples for the
`process_cell` (around ~3.5M per 10 minutes).
Another test I did was a plasmafire in an 8x8 space, on runtime station,
it showed (-24% time on process_cell).
Another test was a emagged holodeck burn test, it showed (-13% time)
As for other functions of gas_mixture: `total_moles`: -50%(2x speedup),
`heat_capacity`: -65%(3x speedup), `share`: -30%, `react`: -20%. Timings
of all those functions is in microseconds range and they are very hot
(call count is in the same order as process_cell)

<details><summary>Some pictures from profiler</summary>
<img width="569" height="642" alt="process_cell"
src="https://github.com/user-attachments/assets/76fa0c27-719d-485d-9bfc-859fef788999"
/>
<img width="572" height="315" alt="image"
src="https://github.com/user-attachments/assets/f68497e9-4db8-4a9c-b43f-ad04e6dc5cac"
/>
<img width="569" height="317" alt="image"
src="https://github.com/user-attachments/assets/d7249e7b-f344-47a6-8b39-1bab0521182d"
/>
<img width="541" height="316" alt="image"
src="https://github.com/user-attachments/assets/1bef71fd-533d-40fa-a85e-7a803ad322f7"
/>
<img width="519" height="409" alt="image"
src="https://github.com/user-attachments/assets/51165289-174e-403d-a09c-787dd9af136a"
/>
<img width="523" height="318" alt="image"
src="https://github.com/user-attachments/assets/fe4b1db0-17d8-47f9-8fd0-e2ecef2ee66a"
/>
</details>

<details><summary>Setting up a profiler</summary>
If you wanna to reproduce my results here is a list of steps

1. download: https://github.com/goonstation/byond-tracy-writer (this one
has offsets for my version 1677)
2. build the dll, drop in the tgstation/ folder
3. download rtracy https://github.com/Dimach/rtracy
4. download Tracy profiler (0.13.1) https://github.com/wolfpld/tracy
5. uncomment `#define USE_BYOND_TRACY` in `_compile_options.dm`
6. build tgstation
7. open dream daemon, run the desired test, after round end dream daemon
closes
8. navigate to tgstation/data/profiler, find the `123412341234.utracy`
file
9. run `rtracty 123412341234.utracy`
10. open tracy-profiler.exe, press Connect, save the profiler data
11. repeat steps 5-10 with another branch, save another profiler data
12. open tracy-profiler, open first data, press compare, open second
data
</details>

## Why It's Good For The Game

## Changelog
🆑
refactor: Atmos refactor & speedup by utilizing BYOND 516 vector
functions
/🆑

---------

Co-authored-by: san7890 <the@san7890.com>
2026-07-14 20:34:31 -07:00
CabinetOnFireandGitHub ef8cfb8b8d Fixes some procs that sleep inside SHOULD_NOT_SLEEP procs (#96959)
## About The Pull Request

I fixed should_not_sleep() locally as it wasn't catching all cases. I
PR'd this but want to do some damage control before its merged so our
linters dont fail on master

This revealed some procs that are sleeping but could run in
SHOULD_NOT_SLEEP procs.

I'll probably keep doing more of these.

## Why It's Good For The Game

prevents procs that shouldnt nap from napping

## Changelog

🆑
fix: Fixed some sleeping procs that could run in procs that arent
allowed to sleep
/🆑
2026-07-14 21:12:31 +02:00
6cbee1bcc9 Gives mirror maids random 1920s English/Welsh names (#96936)
## About The Pull Request
This PR adds a list of 100 1920s English/Welsh names for Maids in the
Mirror. The names have been sourced from and attributed to the United
Kingdom's Office for National Statistics. Admittedly I haven't worked
with licenses much, so please correct me if I've gotten the attribution
wrong. Example names are as follows:

"Mirror Maid Mildred"
"Mirror Maid Gertrude"
"Mirror Maid Gwendoline"

I've attempted to code this such that names only get reused after all
are randomly gone through.
## Why It's Good For The Game
It is currently difficult to distinguish between several Maids in the
Mirror, and this PR attempts to remedy that in a thematically
appropriate way.

Additionally, this PR may address issue #96587. (While this doesn't
provide mob numbers specifically, it does make their names distinct.)
## Changelog
🆑
add: Maids in the Mirror now get random 1920s English/Welsh names.
/🆑

---------

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
2026-07-13 21:17:43 -07:00
san7890andGitHub cb535cdfa6 Refactor var/can_be_held to an element (#96917)
## About The Pull Request

We were doing a lot of mental gymnastics in a bunch of other places, so
let's change this wonky var to a streamlined element that will rely on
the same signals that a lot of stuff was already using/accounting for in
its own signal handling pathways, instead of being a weird coverage gap.
This patch should also make the whole "checking if someone is attempting
to pick a mob up" thing make a lot more sense and use a unified proc
instead of spot-checking whatever random things it wants to spot-check.
## Why It's Good For The Game

I didn't know this was a thing until I looked at #96873 and it made me
sad because literally everything else involving mob drag-and-drop is
already signal-based except this weird stinker that relied on proc
overrides. Never mind that now, let's use nice traits to avoid
typecasting and elements to avoid duplicating code. It should also be
much cleaner to add holdability to a mob isntead of having to do
`can_be_held = FALSE` as a weird behavior (at least one instance had
this non-necessarily). All this really is is just middleware on the
extant /mob/living code but still making it in proper lockstep with the
other signalling procs.

I did port over raptor code faithfully but I'm not 100% sure if it was
meant to be like this? Regardless, that's how it is.
## Changelog
🆑
refactor: Picking up mobs has been altered a bit, please report any bugs
or glitches.
/🆑
2026-07-13 16:57:47 +02:00
Leland KembleandGitHub f29fccfc2c Not as scary as it looks attackby() to item_interaction() (#96795) 2026-07-12 13:45:35 +02:00
GhomandGitHub 54df8cab2d Moved a few monkeys features out of species code (+ updated a couple infusion organs) (#96735)
## About The Pull Request
Title. I'm moving a few monkey features away from the species and into
its bodyparts and organs. I plan on following up with another PR for the
various `ismonkey()` in the code, as these are necessary changes for a
niche thing I'm ultimately working on.

Also one carp organ and one stoat organ both had bits of code made
redundant by available traits. This takes care of them.
Also removed the passwindow_on/off and passtable_on/off procs. We can
just register the associated trait signals on init for living mobs (plus
they were being misused on non-mobs).

## Why It's Good For The Game
Less code associated directly to the species and more to its body parts
and organs, which is basically something we've been doing for a few
years ~~(also I need it for skeletonized monkeys)~~.

## Changelog
N/A
2026-07-11 21:51:39 +01:00
SmArtKarandGitHub 25a78286d1 Adult raptors can no longer be picked up (#96914)
## About The Pull Request
Closes #96912

## Changelog
🆑
fix: Adult raptors can no longer be picked up
/🆑
2026-07-10 22:41:48 -06:00
SmArtKarandGitHub c7039b06a9 Fixes goldgrubs leaving floating emissives after dying (#96865)
## About The Pull Request

<img width="240" height="141" alt="dreamseeker_yU7zcN5nNC"
src="https://github.com/user-attachments/assets/08957f26-6347-429b-97d5-dc24a8c3f486"
/>

## Changelog
🆑
fix: Fixed goldgrubs leaving floating emissives after dying
/🆑
2026-07-09 16:32:10 +02:00
Aliceee2chandGitHub 80e7ce6c48 Makes tendril special mob (#96843)
## About The Pull Request

title

## Why It's Good For The Game

to prevent shit like making infinite necropolis chests with black
regenerative extract from xenobio and possibly other wacky interactions

## Changelog

🆑
fix: Fixed players being able to turn into tendril/dupe necrochests from
it by turning it into MOB_SPECIAL biotype.
/🆑
2026-07-09 16:13:56 +02:00
FalloutFalconandGitHub e7fc4366a7 Fixes update_overlays() being called by itself (#96825)
## About The Pull Request
calling this proc by itself SHOULD do literally nothing as all it does
is builds and returns a list of icons

I wonder if this changes anything.
## Changelog
🆑
code: Ensures some code actually updates overlays instead of return a
list of them to nobody
/🆑
2026-07-07 09:18:47 +02:00
SmArtKarandGitHub 3f3b569c65 Makes crusher trophies craftable, reworks icewing/magmawing/blaster tube trophies (#96670) 2026-07-07 07:58:38 +10:00
GhomandGitHub 6eb2d1674a Implementing materials checks for techweb designs. (#96257)
## About The Pull Request
In similar fashion to what was done with crafting recipes last year,
this year it's time for techweb designs and printed items to be audited.
This is mostly just about consistency, we've a lot of items that can be
printed by protolathes, autolathes, circuit printers and techfab etc.
However they almost all (except most stacks, mainly) have custom
materials that do not match in one way or another with the materials
used by the design, which is what this PR is for.

"But items printed from lathes etc. already get the mats used to make
them." Yes, they do, however that isn't the case for items of the same
type that were spawned in some other way (cargo shuttle, space/maints
loot, mapped, admins), this create a subtle discrepancy. It isn't a huge
deal (in spite of the size of this PR, ton of designs), but given that I
have done something similar with crafting recipes before, I may as well
give it a second arc of some sort and bring things to completion. And
fix a few possible oversights.

TL;DR consistency and stuff

## Why It's Good For The Game
Consistency, unit test checks to make it harder not to be consistent in
the future. Still has a few TODOs like:

- [x] Fixed newly printed, fully charged RCDs costing less than the RCD
cartridges required to fully charge one. EDIT: I had to tweak the newly
added RDD as well because it suffered from the same fundamental issue.
- [x] Fixed plates being made of iron and yet shattering like ceramic
ones. A new subtype for metallic ones has been made.

## Changelog

🆑
refactor: Refactored a few things with techweb designs (the ones for
autolathes, protolathes, circuit printers, mechfabs etc.) to make sure
that the materials of items that can be made from these designs more
closely match the materials used to make them.
fix: Lizard fries no longer need a plate to be made, like all other
treats that used to require plates in a distant past.
balance: Tweaked the materials cost of RCD, RDD and RCD cartridges.
image: Oven trays now have a more metallic hue.
balance: Plates printed printed from lathes won't shatter like ceramic
ones, in virtue of them being made out of iron instead.
/🆑
2026-07-06 00:13:02 -07:00
Leland KembleandGitHub e816dfebeb Moves a great many things from attackby() to item_interaction() (#96642)
## About The Pull Request

21 things.
Additionally, an actual refactor(a real one) of refunding of item-based
spellbook entries, as in the three summons, which hasn't worked for four
years and now does.
Lastly, the holopayment stand IDs can project can now accept payment.


## Why It's Good For The Game

They want you to think this is worth 210 gbp, don't believe the lies

## Changelog
🆑

fix: Wizards can now successfully refund summoning items
fix: Holopayment stands can now take payment

code: 21 things have been moved from attackby() to item_interaction()

/🆑
2026-07-05 10:02:06 +02:00
SmArtKarandGitHub e0c86db67d Readds lost tendril death SFX, tendrils now remove their corruption upon dying (#96748)
## About The Pull Request

Tendril rework accidentally got rid of tendril death SFX which this PR
restores (does not use death_sound as it needs to be louder), and I've
also decided to make tendrils remove their corruption tiles upon dying.


https://github.com/user-attachments/assets/7cb7a6d0-f58f-4fe9-ac5c-587266f63572

(Retraction has been slightly slowed after recording)
## Why It's Good For The Game
Adds some nice flavor to tendrils

## Changelog
🆑
add: Tendrils now remove their corrupted tiles after death
fix: Tendrils got their death sound back
/🆑
2026-07-05 09:59:50 +02:00
ff006aa4a5 verb macro system (pr 1/3) (#96720)
## About The Pull Request

just macro-izes all the usages of verbs in the codebase as a
pre-requisite to my follow up pr that serializes all the verbs arguments
so we can tgui-ify the command bar, so we can then put it on the
onscreen map.

this also basically does the same as #94487 so can easily be integrated
into the verb queueing stuff... but does not actually do any verb
queueing by itself. basically im just trying to be
https://github.com/tgstation/tgstation/labels/Atomic
## Why It's Good For The Game
it doesn't really do anything by itself but it does let us do more stuff

## Changelog
🆑
code: the backend to all verbs in the game has been played with, please
report any issues to github
/🆑

---------

Co-authored-by: harryob <55142896+harryob@users.noreply.github.com>
2026-07-04 02:45:07 -04:00
SmArtKarandGitHub 01f6864748 Refactors atom HUD positioning on mobs, fixes some inlay overlays on wide humans (#96682)
## About The Pull Request
This PR moves out hud offsets into a separate proc on atom level, which
lets mobs override it as to control their atom HUD positioning. This
fixes weird hud offsets on mobs who are located in files larger than
their own icon, or have a very offset but small/detached detail on their
sprite (blood-drunk miner, raptors, megacarps)
This also lets humans adjust their HUDs based on their height, which
should prevent hud clipping for spacers.
<img width="93" height="88" alt="dreamseeker_iBapCH9y5a"
src="https://github.com/user-attachments/assets/f429d4d9-6e1f-451e-9908-54c8a1373f1a"
/>

Main reason behind this change is to allow humans to override their
sprite width/height according to their bodypart overlays, which fixes
immerse and brimdust sac inlaid overlays being shorter/thinner than
expected.

Before & after:

<img width="172" height="188" alt="dreamseeker_5l78R30uLI"
src="https://github.com/user-attachments/assets/0b62ac27-71e6-4b3b-92d0-cf3e73eb458d"
/>
<img width="222" height="189" alt="dreamseeker_9hX6FXLvK9"
src="https://github.com/user-attachments/assets/ab36bc36-abd5-4bdf-965d-ee3951ce9b11"
/>

These values are cached and only updated on ``update_body_parts`` as to
save on a bit of performance.

## Why It's Good For The Game

Fixes jank visuals

## Changelog
🆑
fix: Brimdust sac and fluid immersion overlays no longer look weird on
humans with extra-wide or tall bodyparts or organs
fix: Some mobs now have more sensible health HUD positions
fix: Health and security HUD now scales with player height, no more huds
clipping into spacer hair
/🆑
2026-07-02 09:56:14 +02:00
SmArtKarandGitHub 99f6ed63c9 Raptor eggs no longer hatch into fully grown raptors (#96738)
## About The Pull Request

Closes #94485 

## Changelog
🆑
fix: Raptor eggs no longer hatch into fully grown raptors
/🆑
2026-07-02 07:11:27 +02:00
cb87e54d93 Lung cleanup ft. minor suffocation tweak (#96659)
## About The Pull Request

### Notable changes

Before: When taking suffocation damage, 3 oxyloss damage is dealt, or
0.66 damage if below 0 health (soft crit threshold). If below 0 hp, and
you have `NOCRITDAMAGE`, gets nullified.
After: When taking suffocation damage, 3 oxyloss damage is dealt,
reduced if you had a partially successful breath (i.e. 75% of a breath =
0.25x damage) or are in soft crit or hard crit (0.22x less damage). If
in crit, and you have `NOCRITDAMAGE`, gets nullified.

Before: You skip 1 in every 4 breaths when your health is below 0 (soft
crit threshold), and skip every breath when your health is below -30
(hard crit threshold)
After: You skip 1 in every 4 breaths when in soft crit, and skip every
breath when in hard crit

Before: You don't heal from successful breaths when below 0 health (soft
crit threshold)
After: You don't heal from successful breaths when in soft or hard crit

### Other changes

- Removed `gasp` from losebreath processing, ie removed chance to gasp
twice in one tick when choking.
- Deletes `respiration_type`s
- Deletes `crit_stabilizing_reagent`
- Deletes species `breathid`, replaces it with `get_breath_type` that
checks the species' lungs

## Why It's Good For The Game

- There was a strange inconsistency where being in crit would
drastically reduce the amount of suffocation damage you were dealt, but
only if you were not breathing. If you were somehow breathing, you took
the full damage. I thought this was a little obtuse, so I wanted to
change it to be consistent: Being in crit is just a multiplier.

- Making them check for `stat` instead of `health` means they affect
people with `NO_SOFTCRIT` or `NO_HARDCRIT` nicer.

- See above.

- Really just to be cleaner, handle gasping in one place.

- I'm not sure why we have `respiration_type`. The only time they're
(practically) referred to is in reagent handling, but there are no
reagents that set it anything but `ALL`. All it does is make our oxyloss
handling made more complicated and harder to read for no purpose. So I
decided to axe it - I think anything special handing that should arise
should just have some bespoke checks instead.

- Nothing set this value to anything else. And guess what, if you
changed it, epinephrine still worked because it applies `NO_CRITDAMAGE`.

- Species de-hardcoding. Makes it easier to add new breath types. 


## Changelog

🆑 Melbert
balance: Suffocation damage is slightly more consistent now: You take 3
oxyloss per suffocation tick, reduced for partially successful breaths
and or if you are in crit. Alternatively, if you are in crit and you
have epinephrine/atropine in your system, it gets nullified entirely.
code: Cleaned up lungs a bit, particularly relating to abnormal lungs
like plasmamen or fish, report any oddities with them.
del: You no longer have a chance to gasp twice in one suffocation tick.
/🆑

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
Co-authored-by: san7890 <the@san7890.com>
2026-07-02 01:59:27 +00:00
364227eb94 Buffs parrots immensely (#96637)
## About The Pull Request
Gives parrots hand (singular), removing snowflaked item carrying from
it. Parrots can now interact with items it's carrying. Tremble before
Poly's new strength!

Also made hand keybinds works on singlehanded mobs.
## Why It's Good For The Game
was bored, figured I can knock off parrots off the stat panel phase out.
looked at the code and realized that parrots have snowflaked item
pickup, thought to myself "wait, isn't there multihanded support? surely
that means that means theres one handed support too!" which is how this
PR came to be.

removes another thing from the stat-panel phase out and makes parrots
handling items much more intuitive.

## Changelog
🆑
code: Swaps out parrot's sovlful unique item carrying ability with a
soulless hand (singular)
fix: Fixes specific hands hotkey breaking hands on singlehanded mobs
/🆑

---------

Co-authored-by: san7890 <the@san7890.com>
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
2026-07-01 13:22:04 -04:00
7f4171fd4d Adds bodyshape arg to a lot of missing spots, generalizes 'wear_digi_version', adds female gender shaping to digi sprites (#96633)
## About The Pull Request

Adds female gender shaping to digi species (such as lizards), for the
top half only.

<details><summary>Shown here</summary>

<img width="337" height="464" alt="dreamseeker_HhKjfrmJ1f"
src="https://github.com/user-attachments/assets/a5a57580-6798-40e4-925c-b3a63e0e540e"
/>

</details>

Also just adds a bunch of bodyshape args now that we are passing that to
the clothing rendering. This will help with anything where you want
unique digi handling for any specific items. Also fixes some missing
args and even improper args in some of these proc overrides.

## Why It's Good For The Game

Makes things more convenient for coders. Adds some more customization
options for feminine lizardfolk.

## Changelog

🆑
code: bodyshape is now accessible in build_worn_overlays() and similar
procs.
image: lizards now have support female gender shaping for their suits
/🆑

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
2026-06-30 20:02:53 +00:00
SmArtKarandGitHub 1c70edf11c Goliath tentacles now detach when the goliath dies (#96681)
## About The Pull Request

Doesn't make sense for tentacles to keep pulling you towards the goliath
after it dies

## Changelog
🆑
fix: Goliath tentacles now detach when the goliath dies
/🆑
2026-06-29 18:32:16 +02:00
MrMelbertandGitHub 21ea64aec5 Height and minor bodypart overlay refactor (#96570)
## About The Pull Request

### Main changes

Height is no longer applied in `apply_overlay`

There is now a proc titled `apply_height()` which is passed an
appearance and a body area, and handles either applying a filter or
adjusting the offset of the appearance up or down

`apply_height` is now called directly when applying item appearances
(ie, `update_worn_x`)
`apply_height` is also called directly in `get_limb_icon` (as height is
included in limb render keys).

### Other changes

Bodypart overlays were cleaned up a bit. You can now apply and remove
bodypart overlays directly with just the typepath, which is a bit more
convenient.

Bodypart textures were split into a separate type. Previously, textures
relied on insertion order to be "correctly" added (any bodypart overlays
added later would not be modified by the bodypart texture). Now

Fixed a bug with cybernetics while I was there. They reskin by changing
DMI so they needed to have their DMI included in their render keys.

## Why It's Good For The Game

This allows us to be more specific and less wasteful about applying
height filters and whatnot - We can now specify whether certain overlays
are offset or given a filter.

For example: In the past, horns and frills were filtered solely because
they were attached to the head and the head was filtered.
We couldn't independently say "Offsets the horns and frills, they don't
need filters".
But now, not only are we able to say "rather than filter the head, just
apply an offset", we can also say "horns and frills should be offset
rather than filtered".

TL;DR fixes the issue where horns or cat ears are cut off by height
filters, yippee.

## Changelog

🆑 Melbert
fix: Cybernetic reskinning should break less. 
fix: Horns and cat ears should be cut off less by height.
fix: Bodypart textures should apply more consistently. 
refactor: Mutant parts like moth wings, lizard tails, cat eats, etc.
have been refactored a tiny bit, report any oddities.
refactor: Bodypart textures were refactored a tiny bit, report any
oddities.
refactor: Refactored the way height works, report anything weird looking
things involving that.
/🆑
2026-06-27 10:28:43 +02:00
GhomandGitHub ef7794f578 LET THE DRONES HAVE HEAD ARMOR (#96648) 2026-06-26 14:32:04 -04:00
CabinetOnFireandGitHub d9b2026afc Fixes target prioritization not working consistently due to not all mining mobs having ai_retaliate (#96655)
target prioritization makes use of retaliation, but not all mobs had it,
now they do (should)

🆑 CabinetOnFire
fix: All mining mobs now remember who hit them, so target prioritization
works as intended
/🆑
2026-06-25 18:00:43 +02:00
SmArtKarandGitHub 8525920dde Adds a visual hint to watcher gaze ability showing if you're going to be affected or not (#96636) 2026-06-24 19:43:44 -04:00
GhomandGitHub 7d686ad1fc Drain the soul away from pigs (#96615) 2026-06-23 19:07:29 -04:00
Roxy de4c3b255d Merge branch 'master' of github.com:tgstation/tgstation into upstream-2026-06-23 2026-06-23 15:51:55 -04:00
308853cee3 Stasis crates (#96505)
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
2026-06-18 17:54:04 +02:00
33824ac7c1 TTS 3.0: Blips Rework, Radio TTS, Unknown Languages are Blips now (#95369)
## About The Pull Request

Re-did blips to be significantly nicer sounding and way better. Alien
speech you don't understand now comes through as Blips. If you have TTS
entirely disabled, you won't hear blips. Blips also now include more
customization options, and a dedicated Blips preview button by clicking
the leaf icon.

<img width="1749" height="354" alt="ApplicationFrameHost_5nKJEvaNV1"
src="https://github.com/user-attachments/assets/ef6c6b61-7c22-4a87-94c9-be50e89c65bb"
/>


https://github.com/user-attachments/assets/8cab7e55-6370-4e4e-99ba-ea2475569453

Radio TTS has been implemented. By default, you will hear all TTS over
the radio, but will not hear yourself over the radio. You can configure
this in Game Settings.


https://github.com/user-attachments/assets/94a44d84-17a9-4e6e-ac5c-3b800b11c159

<img width="743" height="193" alt="chrome_MOIcXaC2gh"
src="https://github.com/user-attachments/assets/907379b7-0689-486c-b29c-9be0a2259b05"
/>

The new TTS stack is located at
https://github.com/Iamgoofball/tgtts-qwen3 and is AGPLv3 licensed. The
new blips design was inspired by
https://github.com/joshxviii/animalese-typing.

The configuration to disable TTS on whispering has been removed, as it
is no longer needed and also interferes with radio TTS functioning
properly.

The Tram now utilizes TTS, and has had a general audio tune-up.


https://github.com/user-attachments/assets/f532d002-939c-43a1-95d0-0f0c43048997

TTS audio is now 3D and in space, see attached.


https://github.com/user-attachments/assets/b00df49a-9d1d-4b27-a8a0-d103099f5c7e

## Why It's Good For The Game

Quality of life improvements to the TTS system, long overdue. Also, TGMC
can migrate to this new method of doing radio audio so they aren't
sending double the TTS requests anymore.

## Changelog

🆑
add: Added support for Radio TTS. You will now hear players over the
radio via the TTS system.
add: Configure this in Game Options under the Sound tab.
sound: Re-did blips to be significantly nicer sounding and way better. 
sound: Alien speech you don't understand now comes through as Blips. If
you have TTS entirely disabled, you won't hear blips.
sound: The Tram and Computers now utilize the TTS system. Configs have
been added to set a consistent voice.
sound: TTS audio now utilizes 3D audio; you can now walk away from
people saying stupid shit and it gets quieter.
sound: Blips also now include more customization options, and a
dedicated Blips preview button by clicking the leaf icon.
del: The configuration to disable TTS on whispering has been removed, as
it is no longer needed and also interferes with radio TTS functioning
properly.
/🆑

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: Aleksej Komarov <stylemistake@gmail.com>
2026-06-15 18:54:24 -04:00
Ben10OmintrixandGitHub fc55a930a9 Baby stoats can become adults (#96491)
## About The Pull Request
Baby stoats can now grow into adult stoats. ive also included kits into
the spawn pool of maints, (the overall chance of running into a stoat
whether adult/baby remains the same), and you can also now find baby
stoats rummaging through bins. since baby stoats are cute ive made their
growth rates slow so people can enjoy them at their youths for longer.

## Why It's Good For The Game
fixes an oversight.

## Changelog
🆑
fix: baby stoats can now become adults
add: baby stoats are added to the spawn pool of maints, (the overall
chance of running into a stoat whether adult/baby remains the same)
/🆑
2026-06-15 15:41:27 +12:00
AlexisandGitHub ea30cc7d13 Revenants can change their name [OCULIS PORT] (#5768)
## About The Pull Request
**PORT OF https://github.com/Monkestation/OculisStation/pull/129.**

Allows revenants to choose their own name or use the default name.
## Why It's Good For The Game
This allows for more roleplay opportunities as you can now run with a
potential gimmick without needing admin intervention. There is also
precedent with antagonists being able to rename themselves due to Space
Dragon.
## Proof Of Testing
See below.
<details>
<summary>Screenshots/Videos</summary>


https://github.com/user-attachments/assets/0b0c73c0-d9a8-4ffd-bc43-f34df5eccde7

<img width="650" height="116" alt="Ghouling Spirit"
src="https://github.com/user-attachments/assets/a4459720-0c8d-43c0-9ddf-95342e32be40"
/>

<img width="648" height="63" alt="That&#39;s Ghouling Spirit"
src="https://github.com/user-attachments/assets/0c2e2d51-8ff1-4002-9407-75aa44fe4c73"
/>

</details>

## Changelog
🆑 Absolucy
add: Revenants can now rename themselves.
/🆑
2026-06-14 04:10:55 -06:00
SmArtKarandGitHub ae90af1a60 Changes tendril regeneration outlinefrom bright green to maroon red (#96449) 2026-06-12 16:05:26 -04:00
Ben10OmintrixandGitHub 64baa1979d Basic mulebots. last basic bot refactor (#95899)
my watch has ended

<img width="401" height="256" alt="ffffff"
src="https://github.com/user-attachments/assets/a539203c-020b-4ad8-b034-f69ec0eafa78"
/>



## Changelog
🆑 Profakos (originally pulled from their branch, did massive chunk of
this), Ben10omintrix
refactor: mulebots have been refactored. please report any bugs
/🆑
2026-06-11 23:58:13 -07:00
gavlaandnevimer 565be62966 🌭 2026-06-11 15:36:38 -04:00
SmArtKarandnevimer 8c9d33fbb4 Fixes and improves tendril animations, makes the fight easier (#96388) 2026-06-11 15:36:37 -04:00
SmArtKarandnevimer 4f8b9f2418 Makes tendrils less out for blood, cleans up The Thing's code (#96332)
## About The Pull Request

I didn't realize that default aggro range for mobs is 9, so tendrils
would try to attack you with their whips and spikes despite you being
completely out of their range, which looks pretty funny.
I've fixed this by separating out aggro ***grab*** range and aggro
sustain ranges, lowering latter to 5 for tendrils, and adding checks for
target distance for both abilities it has. The Thing also had a similar
behavior but used rather jank code for that (which I don't think even
worked), so I've modified it to use the new system as well.

## Why It's Good For The Game

Stationary mobs probably shouldn't try to attack mobs completely out of
their reach

## Changelog
🆑
fix: Tendrils no longer try to attack you when you're out of their reach
code: Cleaned up The Thing's aggro code
/🆑
2026-06-11 15:36:37 -04:00
Leland KembleandGitHub 7942ad800a Fixes runtime when a corgi would try to open a door (#96419)
## About The Pull Request

Doesn't necessarily have a pinned ID

## Why It's Good For The Game

Runtime

## Changelog
🆑

fix: Corgis no longer runtime when trying to open doors without an ID

/🆑
2026-06-11 03:19:26 +02:00
SmArtKarandGitHub e73d636d2f Fixes and improves tendril animations, makes the fight easier (#96388) 2026-06-09 20:18:33 -04:00
0bd4b0820f Adds TGMC Tactical maps to the game and to Nuclear Operatives! (#96068)
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->
<!-- You can view Contributing.MD for a detailed description of the pull
request process. -->

## About The Pull Request

Brought to you by Team Powercrèpe.(same group of people that delivered
the Heretic Overhaul)

This PR ports the TGMC Tacmaps and grants em to our NukeOps.

Code by Me, @Xander3359, @Arturlang, @Absolucy.

Mapping by @RipGrayson 

Sprites by @KillerOrcaCora

Writing bits by @necromanceranne

Tacmaps are essentially dynamically generated minimaps,

<img width="1711" height="1335" alt="Tac map examples"
src="https://github.com/user-attachments/assets/f936fac0-fb7c-4b84-970d-7195b4995ca7"
/>



<img width="1274" height="714" alt="Tac-Maps Icons"
src="https://github.com/user-attachments/assets/0f04e388-af4b-4955-be7a-04650cfd746b"
/>






As you can see from the screenshots above, departments are classified by
color, hovering your cursor over an area or a team mate, will display
their name, the system does allow the user to switch between Multi-Z,
and lastly you can draw and add labels to the map, although the last
option is only available to the NukeOps Leader and OW agents.


The functionality is tied to the Syndicate implants nukies start with,
Cayenne, Syndie borgs and Mechs also have the ability to toggle the map.

Likewise, the tacmaps will display the positioning of the following in
real time!

- Nuke ops agents

- Syndie borgs and Mechs

- Cayenne

- Location of the nuclear fission device (and beer nuke)

- Location of the Nuclear Authentication Disk.

<img width="1274" height="714" alt="SkyBridge OFF"
src="https://github.com/user-attachments/assets/3915e7d7-644a-4e9a-b213-997834dde2ea"
/>

<img width="1274" height="714" alt="SkyBridge ON"
src="https://github.com/user-attachments/assets/13748290-fd16-42ba-a9c4-a6b4f7e69c79"
/>

<img width="566" height="459" alt="Holo table done"
src="https://github.com/user-attachments/assets/1a43c5b7-ee51-4794-9c09-16b4fb50e2ad"
/>






https://github.com/user-attachments/assets/caf38538-ef04-4330-992c-3137a67ea0d0






Lastly The tactiical map implant cannot be be used on the nuke ops
base,If the team wishes to interact with the map they'll have to
Interact with the "Reconnaisance Platform" (Sprite by Orcacora) in the
briefing room, which has seen some mapping changes (Brought to you by
TheLastGrayson).



<!-- Describe The Pull Request. Please be sure every change is
documented or this can delay review and even discourage maintainers from
merging your PR! -->

## Why It's Good For The Game

Originally this feature was planned for the Upcoming Contractor Rework
our team is currently working on, but given the massive size of it all,
we decided to atomize it.

But without that consideration in mind, I think it makes sense for
Nuclear operatives of all antagonists to have the means to Recon and
plot an assault plan onto the station and actually be able to know the
whereabouts of their teammates.

Obviously this feature has a lot of other potential applications, we
have wanted to have functional Maps for a very long time, if someone
wants to give it a go once the feature is merged, by all means.

<!-- Argue for the merits of your changes and how they benefit the game,
especially if they are controversial and/or far reaching. If you can't
actually explain WHY what you are doing will improve the game, then it
probably isn't good for the game in the first place. -->

## Changelog

<!-- If your PR modifies aspects of the game that can be concretely
observed by players or admins you should add a changelog. If your change
does NOT meet this description, remove this section. Be sure to properly
mark your PRs to prevent unnecessary GBP loss. You can read up on GBP
and its effects on PRs in the tgstation guides for contributors. Please
note that maintainers freely reserve the right to remove and add tags
should they deem it appropriate. You can attempt to finagle the system
all you want, but it's best to shoot for clear communication right off
the bat. -->

🆑
add: Tactical Maps have been added to the game!
add: Nuclear Operatives implants now grant the ability to open a
Minimap, this map will display and show the names of various areas of
the station, and the positioning of the Nukeops team,borgs,mechs,Cayenne
and the nuke disk in real time!
add: Nukie leaders and OW agents can also draw and apply labels to the
map.
add: the "Recoinassance Platform" has been added to the Nukie Base, it
allows displaying of the Tactical maps while on the Syndicate Base Z
level.
map: The briefing room in the NukeOps base has been remapped to better
accomodate the new Holographic table.
map: Changed the front shutters on the Syndicate Infiltrator to the more
fitting Syndicate Shutters.
/🆑

<!-- Both 🆑's are required for the changelog to work! You can put
your name to the right of the first 🆑 if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->

---------

Co-authored-by: Xander3359 <66163761+Xander3359@users.noreply.github.com>
Co-authored-by: Artur Lang <24881678+Arturlang@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: RipGrayson <49290523+RipGrayson@users.noreply.github.com>
Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com>
2026-06-09 16:38:00 +02:00
SmArtKarandGitHub 9b110eb64e Reworks and fixes blood drunk miner megafauna (#96286)
## About The Pull Request

Blood-drunk miner has been reworked to change it from a DPS race into a
more dynamic fight

- Buffed health from 900 to 1300 (45% increase), slightly increased
speed (3 -> 2.5), increased saw damage (6/10 -> 8/12) to compensate for
other changes below
- Slightly reduced PKA shot damage (20 -> 18)
- Saw attacks now have a slightly longer delay inbetween hits
(especially in unfolded form), ***no longer are guaranteed to hit no
matter what*** (was a bug which forced players to eat 50 damage to the
face) and slow down the miner during the combo
- Singular PKA shot has been replaced with a telegraphed barrage of 3
projectiles, during which the miner cannot move, letting players gain
some distance
- Dash is no longer a teleport but a proper charge akin to that of
lobstrocities with a very short chargeup that deals no damage or
knockdown, but allows the miner to travel further
- Miner's attacks no longer give the target stun immunity for a brief
moment (why?)
- Default PKA it drops has been replaced with an infernal version, which
comes with a cheaper (30% vs 50% of the default one) in-built rapid
repeater (that also has a less punishing miss delay)

<img width="169" height="143" alt="Aseprite_UfXRbgVuqB"
src="https://github.com/user-attachments/assets/3ac257a4-5443-4c7f-a891-4e69f8188cb4"
/>

---

Full fight with a single basic pen and 2 legion cores, no PKC trophies:
(fumbled a bit midway though, pre-PKA projectile damage nerf)


https://github.com/user-attachments/assets/40c8af0d-035c-49da-861b-5e74ca7d7551

## Why It's Good For The Game

Current blood-drunk miner is a hard DPS check with unavoidable damage
(both due to the bug and instant dashes/PKA hits) that simply requires
you to facetank the damage using heals and kill it first before it kills
you.
This should make the fight a bit longer, more engaging and fairer than
it is right now.

## Changelog
🆑
add: Blood-drunk miner now drops an infernal PKA with an in-built
improved rapid repeater modification
balance: Blood-drunk miner has been reworked with new attacks and
patterns
fix: Blood-drunk miner's combos are no longer guaranteed to land even if
you move away from it
/🆑
2026-06-05 18:03:12 +02:00
John WillardandGitHub e094b84448 Handcuffs removes pull verb (#96276) 2026-06-04 15:34:28 -04:00
AnturKandGitHub a62838fcc8 Polar bear basic mob conversion (#96295)
Straightforward conversion to basic mob. Only effective change is slight
increase in movement speed. They're still walking punching bags.

🆑
balance: polar bears are tiny bit faster
/🆑
2026-06-04 12:29:22 -06:00
Leland KembleandGitHub e61ba89237 Toxin bees get toxin (#96337)
## About The Pull Request

`assign_reagent()` does not take paths

## Why It's Good For The Game

fixes #96333

## Changelog
🆑

fix: Toxin bees get toxin

/🆑
2026-06-04 17:17:52 +02:00
SmArtKarandGitHub 8c0d8073ef Makes tendrils less out for blood, cleans up The Thing's code (#96332)
## About The Pull Request

I didn't realize that default aggro range for mobs is 9, so tendrils
would try to attack you with their whips and spikes despite you being
completely out of their range, which looks pretty funny.
I've fixed this by separating out aggro ***grab*** range and aggro
sustain ranges, lowering latter to 5 for tendrils, and adding checks for
target distance for both abilities it has. The Thing also had a similar
behavior but used rather jank code for that (which I don't think even
worked), so I've modified it to use the new system as well.

## Why It's Good For The Game

Stationary mobs probably shouldn't try to attack mobs completely out of
their reach

## Changelog
🆑
fix: Tendrils no longer try to attack you when you're out of their reach
code: Cleaned up The Thing's aggro code
/🆑
2026-06-04 17:17:12 +02:00
shayoki f601a6ddaf Merge remote-tracking branch 'tgstation/master' into upstream-6-2-2026 2026-06-03 01:23:54 -05:00
SmArtKarandGitHub f3283799e7 Reworks lavaland tendrils into minibosses (#96186) 2026-06-02 21:00:15 +10:00
8eed335b94 Refactors inventory UI to be completely datum and vis_contents-based (#95998)
## About The Pull Request

Completely removes individual inventory UI handling from mob and HUD
code and moves it to slot datums.
``/datum/inventory_slot`` now is responsible for displaying items on the
player UI and does so through vis_contests as opposed to screen_loc -
which ensures that wide items will display properly rather than be
offset to the right.
Centralized, slot_id based handling allows us to significantly simplify
inventory and HUD code (see how many lines were removed) as you no
longer need to individually track all items for both the HUD owner and
the observer, and makes it easier for us to fully datumize inventory
handling in the future.

Also fixes a bug where observers would see players' storage UI and have
the items linger on-screen after its closed.

## Why It's Good For The Game

Makes working with inventories and HUDs easier, fixes visual issues with
wide items, I need this for human rendering refactors.

## Changelog
🆑
refactor: Refactors inventory UI to be completely datum and
vis_contents-based
fix: Observers should no longer see doubled up inventory UIs
/🆑

---------

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
2026-05-31 14:27:23 -07:00