So it turns out the spacebet app verifies that the user has the money to
make a bet only if they already have an active bet and they're
increasing the amount of money it is, with a fresh bet this is never
checked. This means someone can bet 10k credits on an option, it will
place the bet with no regard for their account balance, then they can
set their bet back to zero and the app will happily refund them 10k. Now
they have 10k. They can do this as fast as they can type the numbers
## About The Pull Request
This has the potential to create a lot of needless mob updates which is
not great. Now should only update a mob's clothing if it was actually
washed.
This PR
1) ensures that all wash() procs return a bitflag.
2) ensures that `wash()` proccalls which result in expensive operations
like icon updates only do so when it is necessary
## Why It's Good For The Game
Updating mob sprites is expensive, and doing it when nothing has been
changed is bad.
## Changelog
Nothing really player facing
## About The Pull Request
Adds a new PDA app that allows you to create polls that people can bet
on with credits, the owner can then lock the bets, decide what the
answer is (up to the player for whatever poll they made), and send it
off, giving the money the losers bet into the accounts of the winners.
It's a small PDA app that currently doesn't make any announcements or
come preinstalled in anything, but that's subject to change. PDA screen
sprite is codersprited.
Video demonstration
https://github.com/user-attachments/assets/449e1f0b-7fd3-4948-bff8-2793af831360
Not shown (as I added later), it now uses newscasters as well.

###### Code bounty of
https://forums.tgstation13.org/viewtopic.php?t=38278
## Why It's Good For The Game
Allows people to host polls for station events, allowing for the SS13
version of sports betting.
## Changelog
🆑
add: Adds a new sports betting app on your PDA, you can now host and
vote on polls using in-game credits.
/🆑
---------
Co-authored-by: san7890 <the@san7890.com>
## About The Pull Request
Cyborgs now have an alert that shows when someone is watching their
internal camera through a security camera console. SyndEye is excluded
from this as it's spying instead.
Made as an alternative to
https://github.com/tgstation/tgstation/pull/90410 but they also aren't
mutually exclusive, though I have the same fix for borg camera cutting
in this one too.
https://github.com/user-attachments/assets/5dfe92f8-8948-4a80-bb64-cbeaca4f80e0
##### This is part of the same code bounty as
https://github.com/tgstation/tgstation/pull/90410
## Why It's Good For The Game
Pretty much the same reason this PR is an alternative to, it's hard for
borgs to get away with doing antagonist stuff when people are able to
silently watch them at any point from any console or laptop laying
around the station, of which there are many. This hopefully lets borgs
know if someone is watching, to avoid doing anything in front of the
cameras, and to encourage them to get said cameras cut if they plan on
doing anything.
## Changelog
🆑
add: Drones now have internal cameras that shows up on camera consoles
(like Cyborgs)
balance: Cyborgs (and drones) now get a notification when someone is
watching them through a security camera console.
fix: Cutting a Cyborg's camera wire now properly disables it, and
mending it now properly re-enables it.
/🆑
---------
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
## About The Pull Request
This won't actually do anything on live, since those are all set to
UTC±0 currently
Pins logging and IC uses of time2text to UTC±0 instead of using the
system timezone (byond default)
Timezones not being set to utc0 caused issues before (and is again)
All timezones are now passed explicitly to make it more likely it's
cargo culted properly at least
Deletes worldtime2text cus it was gameTimestamp default args
## Why It's Good For The Game
Server timezone changes probably shouldn't affect logging, round times,
file hashes, IC time, when you caught fish, etc
## Changelog
🆑
refactor: Logging and IC timestamps will now always use UTC±0 and not be
affected by server system timezone changes
fix: Station and round times will not longer be incorrect if the system
timezone is not UTC±0
/🆑
---------
Co-authored-by: TiviPlus <572233640+TiviPlus@users.noreply.com>
## About The Pull Request
516 requires float layered overlays to be using pixel_w and pixel_z
instead of pixel_x and pixel_y respectively, unless we want
visual/layering errors. This makes sense, as w,z are for visual effects
only. Sadly seems we were not entirely consistent in this, and many
things seem to have been using x,y incorrectly.
This hopefully fixes that, and thus also fixes layering issues. Complete
1:1 compatibility not guaranteed.
I did the lazy way suggested to me by SmArtKar to speed it up (Runtiming
inside apply_overlays), and this is still included in the PR to flash
out possible issues in a TM (Plus I will need someone to grep the
runtimes for me after the TM period to make sure nothing was missed).
After this is done I'll remove all these extra checks.
Lints will probably be failing for a bit, got to wait for [this
update](4b77cd487d)
to them to make it into release. Or just unlint the lines, though that's
probably gonna produce code debt
## Why It's Good For The Game
Fixes this massive 516 mess, hopefully.
closes#90281
## Changelog
🆑
refactor: Changed many of our use cases for pixel_x and pixel_y
correctly into pixel_w and pixel_z, fixing layering issues in the
process.
/🆑
---------
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: SmArtKar <master.of.bagets@gmail.com>
## About The Pull Request
This PR should fix the problem of small previews in TGUI once and for
all (I hope).
What was causing it? Because TGUI takes a long time to open, that's why
previews were generated broken (small).
On Byond 515 this problem was not so noticeable as the interfaces opened
faster, but with the release of 516 it became much worse.
Previews were generated inside a window that was not yet open, so the
scale was broken, sometimes the window would open before the preview was
done and sent, usually with small interfaces, or when reopening.
I'm not very good at working with signals, and to tell the truth this is
my second experience with them, so I hope I did it right.
## Why It's Good For The Game
No more small map previews
<details> <summary> Video </summary>
https://github.com/user-attachments/assets/834f3820-cc6a-4f65-90e5-d6bb2a118bcf
</details>
## Changelog
🆑
fix: Fixed small character preview, color matrix preview, mech preview,
and other previews with uses ByondUI map
/🆑
---------
Co-authored-by: Gaxeer <44334376+Gaxeer@users.noreply.github.com>
## About The Pull Request
This trainwreck of a PR is (hopefully) a final solution to all rendering
jank stemming from the new filter-based coloring system. I went over
every single instance of RESET_COLOR, either adding KEEP_APART or
rewriting them entirely so they render properly. I've also fixed blood
rendering issues by utilizing alpha filters and adding an abstract
"holder" appearance for worn items, which holds blood overlays on worn
clothing as to avoid coloring it. I've also fixed horrible
inconsistencies with atmos pipe coloring as a result (of getting sucked
down that rabbit hole) and converted all uses of COLOR_VERY_LIGHT_GRAY
in atmos code to ATMOS_COLOR_OMNI to avoid confusion.
MODsuit modules still get colored into MOD unit's color, need to
refactor their rendering for this.
Closes#88989Closes#87526Closes#89837
## Changelog
🆑
refactor: Audited all remaining coloring code - among noticeable
changes, blood should no longer get colored or "leak out" of item
bounds, atmos pipes no longer color weirdly and repairbots are white
again.
/🆑
## About The Pull Request
Robotact is now at the top of borg PDAs' main screen. Same as Messenger
for crew PDAs.

## Why It's Good For The Game
Robotact is just as important to borgs as Messenger is to carbons, so we
should make it easier to find at a glance.
## Changelog
🆑
qol: Cyborg PDAs' home screens now have Robotact at the top of the
screen.
/🆑
## About The Pull Request
Adds a new Retcon smite, it makes the person fade out into nothingness
with a configurable timer, deletes their records and reopens their job
slot, as if they were never there at all.
I was also annoyed that to play around with temporary_atom I had to
slowy add a component, and it doesn't really have much of a reason to BE
a component, so I refactored it into an atom level proc called
fade_into_nothing
## Why It's Good For The Game
The smite is useful for when you wanna get rid of someone who had to
leave roundstart and whatnot, on top of just being funny. the refactor
is also good because i can now put that proc on build mode and go to
town.
## Changelog
🆑
add: Added new mechanics or gameplay changes
add: Added more things
del: Removed old things
qol: made something easier to use
balance: rebalanced something
fix: fixed a few things
sound: added/modified/removed audio or sound effects
image: added/modified/removed some icons or images
map: added/modified/removed map content
spellcheck: fixed a few typos
code: changed some code
refactor: refactored some code
config: changed some config setting
admin: messed with admin stuff
server: something server ops should know
/🆑
---------
Co-authored-by: Jacquerel <hnevard@gmail.com>
## About The Pull Request
Replaces the asset subsystem's spritesheet generator with a rust-based
implementation (https://github.com/tgstation/rust-g/pull/160).
This is a rough port of
https://github.com/BeeStation/BeeStation-Hornet/pull/10404, but it
includes fixes for some cases I didn't catch that apply on TG.
(FWIW we've been using this system on prod for over a year and
encountered no major issues.)
### TG MAINTAINER NOTE

### Batched Spritesheets
`/datum/asset/spritesheet_batched`: A version of the spritesheet system
that collects a list of `/datum/universal_icon`s and sends them off to
rustg asynchronously, and the generation also runs on another thread, so
the game doesn't block during realize_spritesheet. The rust generation
is about 10x faster when it comes to actual icon generation, but the
biggest perk of the batched spritesheets is the caching system.
This PR notably does not convert a few things to the new spritesheet
generator.
- Species and antagonist icons in the preferences view because they use
getFlatIcon ~~which can't be converted to universal icons~~.
- Yes, this is still a *massive* cost to init, unfortunately. On Bee, I
actually enabled the 'legacy' cache on prod and development, which you
can see in my PR. That's why I added the 'clear cache' verb and the
`unregister()` procs, because it can force a regeneration at runtime. I
decided not to port this, since I think it would be detrimental to the
large amount of contributors here.
- It is *technically* possible to port parts of this to the uni_icon
system by making a uni_icon version of getFlatIcon. However, some
overlays use runtime-generated icons which are ~~completely unparseable
to IconForge, since they're stored in the RSC and don't exist as files
anywhere~~. This is most noticeable with things like hair (which blend
additively with the hair mask on the server, thus making them invisible
to `get_flat_uni_icon`). It also doesn't help that species and antag
icons will still need to generate a bunch of dummies and delete them to
even verify cache validity.
- It is actually possible to write the RSC icons to the filesystem
(using fcopy) and reference them in IconForge. However, I'm going to
wait on doing this until I port my GAGS implementation because it
requires GAGS to exist on the filesystem as well.
#### Caching
IconForge generates a cache based on the set of icons used, all
transform operations applied, and the source DMIs of each icon used
within the spritesheet. It can compare the hashes and invalidate the
cache automatically if any of these change. This means we can enable
caching on development, and have absolutely no downsides, because if
anything changes, the cache invalidates itself.
The caching has a mean cost of ~5ms and saves a lot of time compared to
generating the spritesheet, even with rust's faster generation. The main
downside is that the cache still requires building the list of icons and
their transforms, then json encoding it to send to rustg.
Here's an abbreviated example of a cache JSON. All of these need to
match for the cache to be valid. `input_hash` contains the transform
definitions for all the sprites in the spritesheet, so if the input to
iconforge changes, that hash catches it. The `sizes` and `sprites` are
loaded into DM.
```json
{
"input_hash": "99f1bc67d590e000",
"dmi_hashes": {
"icons/ui/achievements/achievements.dmi": "771200c75da11c62"
},
"sizes": [
"76x76"
],
"sprites": {
"achievement-rustascend": {
"size_id": "76x76",
"position": 1
}
},
"rustg_version": "3.6.0",
"dm_version": 1
}
```
### Universal Icons
Universal icons are just a collection of DMI, Icon State, and any icon
transformation procs you apply (blends, crops, scales). They can be
convered to DM icons via `to_icon()`. I've included an implementation of
GAGS that produces universal icons, allowing GAGS items to be converted
into them. IconForge can read universal icons and add them to
spritesheets. It's basically just a wrapper that reimplements BYOND icon
procs.
### Other Stuff
Converts some uses of md5asfile within legacy spritesheets to use
rustg_hash_file instead, improving the performance of their generation.
Fixes lizard body markings not showing in previews, and re-adds eyes to
the ethereal color preview. This is a side effect of IconForge having
*much* better error handling than DM icon procs. Invalid stuff that gets
passed around will error instead of silently doing nothing.
Changes the CSS used in legacy spritesheet generation to split
`background: url(...) no-repeat` into separate props. This is necessary
for WebView2, as IE treats these properties differently - adding
`background-color` to an icon object (as seen in the R&D console) won't
work if you don't split these out.
Deletes unused spritesheets and their associated icons (condiments
spritesheet, old PDA spritesheet)
## Why It's Good For The Game
If you press "Character Setup", the 10-13sec of lag is now approximately
0.5-2 seconds.
Tracy profile showing the time spent on get_asset_datum. I pressed the
preferences button during init on both branches. Do note that this was
ran with a smart cache HIT, so no generation occurred.

Much lower worst-case for /datum/asset/New (which includes
`create_spritesheets()` and `register()`)

Here's a look at the internal costs from rustg - as you can see
`generate_spritesheet()` is very fast:

### Comparison for a single spritesheet - chat spritesheet:
**Before**

**After**

## Changelog
🆑
fix: Fixed lizard body markings and ethereal feature previews in the
preference menu missing some overlays.
refactor: Optimized spritesheet asset generation greatly using rustg
IconForge, greatly reducing post-initialization lag as well as reducing
init times and saving server computation.
config: Added 'smart' asset caching, for batched rustg IconForge
spritesheets. It is persistent and suitable for use on local, with
automatic invalidation.
add: Added admin verbs - Debug -> Clear Smart/Legacy Asset Cache for
spritesheets.
fix: Fixed R&D console icons breaking on WebView2/516
/🆑
## About The Pull Request
Port of a fix from
https://github.com/Monkestation/Monkestation2.0/pull/4995
Due to how modular computers worked with the nested tgui stuff, the
SecurEye app wouldn't properly autoupdate whenever a camera it was
watching moved (when there's not any tracking going on)
This "fixes" that issue by adding a new var, `always_update_ui`, to
modular computer programs, which will make the modpc call the active
program's `ui_interact` even after the UI is opened.
## Why It's Good For The Game
bugfix good. if the whole "watch broadcast camera streams on PDA" thing
ever gets ported here, this is a needed fix for that.
## Changelog
🆑
fix: SecurEye now properly follows moving cameras.
/🆑
## About The Pull Request
I standardized stuff in AASs code, and all current reference to it. Also
added interactions for bounty cubes, weather reports and request
consoles, all of it can be changed from AASs UI.
Also it's easier now to add new config entries for AAS to proceed, and
it's now downstream friendly.
## Why It's Good For The Game
Well, because kind of order in code and because it's funny to make
custom messages for... Almost everything?
BTW any entry can be blocked from ingame changes, by default you can't
change Broken Arrival shuttle and Security Officer arrival
announcements, how it was before. But may be we should allow it - it's
an open question.
## Changelog
🆑
add: Many things now handles via AAS: Bounty Cubes, Request Consoles,
Brig Cells, Vending Machines and Orion Trails alerts, Weather Reports,
Cargo Order Console
code: Now anyone can make their own entry for AAS
refactor: AAS internals, also cleanup
/🆑
## About The Pull Request
Closes#89329
Also added a balloon_alert
## Changelog
🆑
qol: SiliConnect now informs you that you're successfully downloading
logs
fix: Fixes SiliConnect not being able to download logs
/🆑
## About The Pull Request
-Creates a new button in the "Secrets" menu that can override the
cooldown for ordering items from department consoles. It can be used to
make the cooldown longer, shorter or non-existent.
-Creates a new global var to manage this override on every console in
dept_order.dm
## Why It's Good For The Game
This tool assists in finding and fixing bugs related to cargo orders and
cargo crates. The wait time for these cooldowns can be ten minutes or
longer, and this speeds up the process significantly.
It could also be used by admins during play to make the cooldown lower,
or cause absolute mayhem on cargo by setting the cooldown duration to 0.
## Changelog
🆑
add: Added a button in the "Secrets" menu to alter the department
console order delay.
qol: Button makes it easier to find cargo related bugs.
code: Changed code in department_order.dm to allow for overriding the
order cooldown duration.
admin: Created an admin button in the "Secrets" panel.
/🆑
---------
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
## About The Pull Request
fix image display in `NT IRN` PDA app
<details>
<summary>
Images present!
</summary>

</details>
## Why It's Good For The Game
Bug fixes good
## Changelog
🆑
fix: fix image display in `NT IRN` PDA app for preview and contents
/🆑
## About The Pull Request
PDAs no longer go white when the virtual pet app is opened
## Why It's Good For The Game
fixes virtual pet app changing PDA's colors when open
## Changelog
🆑
fix: fixes virtual pet app changing PDA's colors when open
/🆑
## About The Pull Request
Replace bubble sort with timsort for cameralist
Move cameralist related global procs to `cameranet` datum
Other minor code cleanup things
## Why It's Good For The Game
Cameralist reads for UIs are now more performant
## Changelog
🆑
refactor: replace bubble sort with timsort for cameralist, move global
procs to `cameranet` datum
/🆑
## About The Pull Request
This PR makes the reward and cooldown for departmental orders scale with
crate cost using a logarithmic scaling, instead of comparing the price
to preset thresholds for time, or awarding the same amount as the
crate's cost.
Previously, to calculate the cooldown time, the code was calculated via
the following manner:
```
credits = clamp(credits, min, max)
time_y = 10 MINUTES * ((credits - min)/(max - min) + 1)
```
Minimum was 320 credits, max was 3000, thus, all crates slid around
between 10 minutes to 20 minutes.
The reward for delivering the crates was the same as the crate's value.
This meant ordering egregiously expensive crates, far beyond 3000 was
way too desirable.
This PR changes both to use logarithmic scaling.
Cooldown time uses `60* log(price)^2.2`, and reward uses `140 *
log(price)^1.4`.
**Cooldown analysis**
At 320 it's 7.54 minutes, at 1400 it's 12.44 minutes, at 3000 (around
gun crates) it's 15.5 minutes, at 8000 (hat crate) 20 minutes, at 9000
(expensive atmos cans) it's 20.58 minutes, and at the 20k crate it's
24.76 minutes.
**Crate rewards analysis**
At 320 it's 475 credits, at 1400 it's 669 credits, at 3000 (around gun
crates) its 778, at 8000 (hat crate) it's 925 credits, at 9000
(expensive atmos cans) it's 943 credits, and at the 20k crate it's 1070
credits.
Up to 540 credits, you are actually getting a higher reward than what
the crate costs, but this is okay, as its a reward for delivering
simpler orders. A little surplus for you.
For the console UI, I have made items costing 3000 or more display
Moderate, and items costing 8000 or more, Long cooldowns.
## Why It's Good For The Game
Ordering really expensive crates should be a luxury, not a way to
generate money. The money is supposed to be a bonus, in addition to the
free crate to sell. Using a logarithmic scale, the credit bonus is
reigned in more evenly, making it more predictable for economy tweaking,
and avoids players double dipping credits in their free purchase.
Decreasing the rewards also give space for other new ways to generate
rewards in relation to departmental orders, such as stamping the
manifest with the correct head's stamp being worth more money and such.
<details>
<summary>Old PR Text, which was using a price cap instead</summary>
## About The Pull Request
Departmental orders are a neat feature, but some of the available packs
had problems economywise. The cooldown of range from 10 to 20 minutes,
with 10 minutes being the base for anything costing less than 320
credits, and 20 minutes at 3000 credits. I have no problem with the
lower cap, but the upper cap has issues, as recently, a 20k crate was
added to cargo, which means it is possible to dump quite a large amount
of funds into cargo every 20 minutes.
Departmental orders probably need a bigger overhaul, and this solution
is imperfect, but I have talked with @ArcaneMusic about this as an
interim stop gap measure.
This PR also autodocs a proc, and moves some values to global defines,
for ease of balancing.
This PR affects the following crates, with the uncapped crate values in
brackets.
Armoury
- Combat Shotguns (3500 credits)
- Energy Guns (3600 credits)
- NT BR-38 Crate (20,000 credits)
Engineering
- BSA parts (6000 credits)
- DNA Vault Parts (4800 credits)
Engine Construction
- HFR Crate (4800)
- Supermatter Shard Crate (4000)
Materials
- BZ Crate (9000 credits)
- Nitrous Oxide (9000 credits)
- Water Vapor Crate (3010 credits)
Toys
- Collectible Hats Crate (8000 credits)
## Why It's Good For The Game
Instantly awarding 20k to cargo every 20 minute, in addition to 27k from
the other consoles (if both engineering and science orders BZ, service
orders collectible hats, and medical orders something around 1000), is a
bit too much. The money gained should be along a much more predictable
and expected value. With this chance, the most they can get is 13k every
20 minutes across all departments.
</details>
## Changelog
🆑
balance: Rewards from departmental orders use a logarithmic scale,
resulting in less rewards for high tier crates. The cooldown time is
also logarithmic now, which has slightly decreased cooldown values on
cheaper crates.
/🆑
## About The Pull Request
when you summon a virtual pet's hologram, itll automatically follow you
on release rather than u having to give it the command
## Why It's Good For The Game
adds some minor convenience to the minigame.
## Changelog
🆑
qol: virtual pet holograms now automatically follow you when released
rather than having to give it the command post summon
/🆑
## About The Pull Request
Was just scrolling through the Paradise github since they seem to have
more work done for 516 to see if there's anything I can port over, found
this and thought why not.
Ports parts of https://github.com/ParadiseSS13/Paradise/pull/25105
Specifically, updaing all hrefs to use the internal ``byond://``, and
adding it to grep.
## Why It's Good For The Game
More work towards 516.
## Changelog
Nothing player-facing.
## About The Pull Request
Fixes issues with var typing and proc arguments, discovered using
OpenDream's WIP TypeMaker feature (using improvements I haven't PR'd
upstream yet).
## Why It's Good For The Game
Codebase maintenance.
## About The Pull Request
See name, if a dummy somehow gets hold of a PDA with the camera app
installed (This just so happens to be a default PDA program in the case
on Nova, Skyrat, and Bubber), and the delete_equipment proc is called,
the camera inside the PDA gets sent to the wardrobe because of
`/datum/outfit/job/assistant/gimmick/hall_monitor` having one, and then
qdelled with the PDA, leaving a hanging ref
This causes a harddel during tests that has caused me great pains to
locate. Turns out a single example holodisk with the clown holds a
magical key to trigger all this: a single PDA
## Why It's Good For The Game
Fixes a harddel. There might be other similar ones hiding in the dark
like cameras in other objects.
## Changelog
🆑
fix: Fixes SSWardrobe stealing a camera from the camera app when on a
dummy, causing a harddel
/🆑
## About The Pull Request
As before, more fiddling with NTNRC, more bugs.
This time, the same user sending the same message within the same second
would cause this message to spawn a new copy each time the channel was
opened, until the UI was closed and re-opened.
Looking into it, this seemed to be because we would set the `Box`'s
`key` value to the message contents:
<b0d71024c0/tgui/packages/tgui/interfaces/NtosNetChat.jsx (L156)>
Which isn't actually unique.
To fix this, we instead make each channel keep track of an incrementing
`id` number to assign to each message, and convert the `messages` list
to an associative list using those numerical ids stringified.
We don't just use the list index as a key, as we later may want to
target specific messages, so a consistent unique key is important.
This fixes our primary issue.
In the process of making the rest of the code account for this, I
noticed that the NTNRC program header that's supposed to show new
messages in the active channel when the program is idle didn't actually
work.
Just at all.
So I rewrote the entire thing, and it now tracks the last read message's
id rather than the full message, and sets this when you actually
background the program. The rest still runs on process tick, where it
updates the header if there's a new message with a different id on top.
Finally, the header part of the UI wasn't actually updating if there
were no headers, so now it forwards a lack of headers change as well.
## Why It's Good For The Game
Reduces more NTNRC jank.
Good if shit like, actually works.
## Changelog
🆑
fix: NTNRC no longer endlessly duplicates messages with duplicate
contents upon switching channels.
fix: The new message header you get when NTNRC runs in the background
actually works.
fix: NtOS header actually updates if there are no program headers.
/🆑
---------
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
## About The Pull Request
- SiliConnect is no longer a default app for cyborgs.
- RoboTact, the borg self-status app now has a Network tab, which lists
other borgs' status.
- The Network tab will only list borgs connected to the same AI as you.
If your AI goes down, you lose connection to other borgs' status info.
- Your AI is also listed on the Network tab, with their own status in a
very binary good/bad form.
- Syndicate borgs are able to see other syndicate borgs on the Network
list, even though they lack an AI.
## Why It's Good For The Game
SiliConnect was recently added to the default borg apps list. But it has
a lot of features that borgs can't actually use, and so feels rather
messy. It was added with the goal of letting borgs see eachother's
status, and so I've ported that functionality into RoboTact. SiliConnect
is no longer a default borg app (though it *can* be installed if a borg
and human really want it to be).
Showing the AI's status is certainly a balance choice. But it's not
really that much of a secret when the AI dying already adjusts the
monitors across the station to a BSOD image. On the flip side, we get to
shut off borg status sharing when the AI goes offline, which is neat.
## Changelog
🆑
del: SiliConnect, a tool meant for Roboticists, is no longer included by
default on borgs.
add: RoboTact, the borg self-status app, now shows the status of other
borgs synced to the same AI. Syndicate borgs can likewise see
eachother's status, even without an AI.
balance: RoboTact also shows their synced AI's very basic status of
functional or offline.
/🆑
UI Pictures:

Dead AI:

Syndicate borgs do not see station borg status, but can see eachother's

~~Drafting because I need to do edge-case testing, and the AI box isn't
quite functioning correctly when the borg has no AI master.~~
## About The Pull Request
During all that fiddling with NTNRC I noticed that sometimes the
download percentage would shoot above 100%.
Looking into it, it seems that that's just because it isn't actually
capped at the downloaded file size.
So we cap it to the file size after adding our next download chunk, but
parallel to before don't complete it immediately so that we stay on 100%
for another cycle before finishing. For style reasons.
Then I noticed files with a size of 0 would sometimes display NaN% or
Infinite%, presumably because both of the progress percentage
calculations in the ui would be dividing by zero.
So to avoid this, we just skip the downloading cycle entirely for 0 size
programs, and go to download completion immediately on clicking.
This fixes our issues.
## Why It's Good For The Game
Fixes some jank.
## Changelog
🆑
fix: NT Software Hub no longer displays >100% completion on downloads
sometimes.
fix: NT Software Hub no longer displays NaN% or Infinite% completion on
files with a size of 0 sometimes.
/🆑
---------
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
## About The Pull Request
While looking into getting the NTNRC username list sorted, I found out
that it was _already_ supposed to be sorted by status, but just got
broken in a pr that removes the program status variable forwarded for
this reason.
In this pr we simply add a `get_numerical_status()` proc that converts
the new logic into a number we can sort by, then make the tgui sort
account for this.
Additionally, we make it sort alphabetically in its subcategories, for
sanity's sake.
It now sorts by operator perms first, then
online>away(background)>offline, then alphabetically.
While I dislike operators being at the top regardless of their status,
it seems like that is how it was intended to work, and doing so sanely
would requite rethinking how names are coloured entirely. On the other
end, I think it's potentially good to have operators be at the top and
thus easily pingable at all times.
## Why It's Good For The Game
Fixes broken status sorting.
Alphabetical sorting makes finding a specific user to mute or ping them
less of a pain.
## Changelog
🆑
fix: NTNRC channel user list is sorted by status again. It goes
operator>online>away>offline.
qol: NTNRC channel user list is now alphabetically sorted under its
status subcategories.
/🆑
## About The Pull Request
When fiddling around with NTNRC, I noticed that muted clients... can
still talk.
While the input bar is reddened and displays a mute message, it isn't
actually disabled- even more so, there's no sanity checks for being
muted on the `ui_act(...)`.
In this pr we just make it so the input gets disabled, and add a sanity
check to avoid people bypassing it.
## Why It's Good For The Game
...good if the app's muting feature like, actually works.
## Changelog
🆑
fix: NTNRC muting actually works again.
/🆑
## About The Pull Request
Closes#87592
You could pass additional args into emotes with zero sanitization if you
got yourself a way to call TGUI acts
## Changelog
🆑
fix: Fixed HTML injections via pet tricks
/🆑
## About The Pull Request
Does as title says. Doesn't take effect if the ID has no job listed.
## Why It's Good For The Game
Gives a bit more context about who is sending a message.
## Changelog
🆑
add: Borgs now get the job title of someone sending them a message
through SiliConnect.
/🆑
## About The Pull Request
- Removes the restriction from borgs and AIs opening PDA interfaces.
- Adds a restriction on Messenger if the PDA is being viewed by an AI or
Cyborg *and* the PDA is not a silicon-type PDA. Messenger is completely
unusable in this case.
- The AI's own PDA is unaffected, due to it being a silicon-type PDA.
Downstreams that give Borg PDAs the Messenger app should likewise be
unaffected. Though mainly unrelated to the PR, pAIs were also tested and
have not been affected.
## Why It's Good For The Game
Back before tablets and PDAs were squished together, silicons could
access tablets freely. TGUI PDAs were restricted from Silicons mainly to
keep parity with the old PDAs, of which Messenger is the major feature
that was ported over. Thus, I'm blocking Messenger specifically while
allowing the rest of a PDA's features to be unblocked.
As an aside, the old fluff text `It doesn't feel right to snoop around
like that...` was kinda terrible, since there are many times you do, in
fact, want to snoop. The AI trying to track down a known killer's
accomplice would want to snoop. The Malf AI that's trying to trick the
Captain would want to snoop. The prior owner of the PDA before they were
borged wouldn't even feel like it's snooping. So now it's a connection
refused thing, not an AI's feelings thing.
## Changelog
🆑
balance: Borgs and AIs can now access dropped PDAs. The Messenger app
does not work over a remote connection, however.
/🆑
Messenger interface when accessed remotely, by the by;

## About The Pull Request
This makes it so receiving a PDA message will give the holder a balloon
alert with their ringtone.
## Why It's Good For The Game
PDA messages are often ignored due to not being noticed, as many players
are more often focused on the main game screen (which runechat has
somewhat normalized) than the chat window. This makes things more
obvious that there's a PDA message.
## Changelog
🆑
add: PDA ringtones now show a balloon alert to the PDA holder.
/🆑
## About The Pull Request
<details>
- renamed ai folder to announcer
-- announcer --
- moved vox_fem to announcer
- moved approachingTG to announcer
- separated the ambience folder into ambience and instrumental
-- ambience --
- created holy folder moved all related sounds there
- created engineering folder and moved all related sounds there
- created security folder and moved ambidet there
- created general folder and moved ambigen there
- created icemoon folder and moved all icebox-related ambience there
- created medical folder and moved all medbay-related ambi there
- created ruin folder and moves all ruins ambi there
- created beach folder and moved seag and shore there
- created lavaland folder and moved related ambi there
- created aurora_caelus folder and placed its ambi there
- created misc folder and moved the rest of the files that don't have a
specific category into it
-- instrumental --
- moved traitor folder here
- created lobby_music folder and placed our songs there (title0 not used
anywhere? - server-side modification?)
-- items --
- moved secdeath to hailer
- moved surgery to handling
-- effects --
- moved chemistry into effects
- moved hallucinations into effects
- moved health into effects
- moved magic into effects
-- vehicles --
- moved mecha into vehicles
created mobs folder
-- mobs --
- moved creatures folder into mobs
- moved voice into mobs
renamed creatures to non-humanoids
renamed voice to humanoids
-- non-humanoids--
created cyborg folder
created hiss folder
moved harmalarm.ogg to cyborg
-- humanoids --
-- misc --
moved ghostwhisper to misc
moved insane_low_laugh to misc
I give up trying to document this.
</details>
- [X] ambience
- [x] announcer
- [x] effects
- [X] instrumental
- [x] items
- [x] machines
- [x] misc
- [X] mobs
- [X] runtime
- [X] vehicles
- [ ] attributions
## Why It's Good For The Game
This folder is so disorganized that it's vomit inducing, will make it
easier to find and add new sounds, providng a minor structure to the
sound folder.
## Changelog
🆑 grungussuss
refactor: the sound folder in the source code has been reorganized,
please report any oddities with sounds playing or not playing
server: lobby music has been repathed to sound/music/lobby_music
/🆑
## About The Pull Request
So, do you remember orbies, those cutesy virtual PDA pets from that PR
that Ben made roughly six months ago before moving on his next project,
leaving them to be probably forgotten in a near future/present/past?
Yeah, personally I never played around, however I recalled that they do
have customizable virtual hats, which can be selected from a dropdown in
the UI, and I thought that it would be a perfect target for some
achievement-related content, as they're totally cosmetic that provides
no gameplay advantage nor affects balance in no way whatsoever. I cannot
sit well with cheevos being purely an end to itself, that's the reason
this PR exists.
The new additions to orbies hats, and their respective required
achievements are:
- The fishing hat (Legendary Fisher)
- A huge-ass rollie (Unhealthy Snacks) (yeah, it isn't exactly a hat but
the code in no way assume that the item has to be a hat, beside vars
named like that for the sake of convenience)
- A tape wizard hat (Archmage)
- An energy cakehat (Very Important Piscis)
- A bounty hunter cowboy hat (Hot Damn!)
- A fancy crown (Outdebted)
The huge-ass rollie (called fat dart) in the game, is a new cigarette,
rarely found in hacked cigarette vending machines. It's obviously a
reference to that Ralsei meme from 3 years ago or so but I personally
don't care, I just wanted to give an excessively big cigarette to orbies
to symbolize the proposterous accomplishment of eating 500 cigarettes in
a single round without dying from nicotine OD less than halfway through,
but since orbie hats use actual items are references for their
appearance, I found myself obliged to add one to the code. Overall, the
fat dart comes from an old PR on Citadel, though I had to resprite it
myself.
Here's a lazy collage of the hats. For some reason unbeknownst to me,
the hats are horizontally squished. I need to ask Ben why he did them
this way when Orbies' heads are as wide as a rugby ball.

## Why It's Good For The Game
Simple, extra cosmetic stuff for a simple feature that's as relevant as
playing around with plushes.
## Changelog
🆑
add: Added more customizable options to PDA virtual pets, which can be
unlocked by completing achievements.
add: Added a fat dart that can be rarely found in hacked cigarette
vending machines.
/🆑
Fixes#86784
## About The Pull Request
Although some of the issues found were a direct result from #86692
(c698196766), there was still 40% of
length-related issues that wouldn't be covered anyways that are fixed in
this PR. I.E.:
* Name inputs without `MAX_NAME_LEN`
* Desc inputs without `MAX_DESC_LEN`
* Plaque inputs without `MAX_PLAQUE_LEN`
* Some people just screwed up the arguments so it would prefill
something like "40" in the `default` var because they didn't name their
vars.
To help me audit I added a lot of `max_length` named arguments to help
people understand it better. I think it might be kinder to have a
wrapper that handles adding `MAX_MESSAGE_LEN` in a lot of these cases
but I think there is some reason for a coder to be cognitive about input
texts? Let me know what you think. I didn't update anything
admin-related from what I can recall, let me know if anything needs to
be unlimited again.
## Why It's Good For The Game
The change to `INFINITY` notwithstanding, there were still an abundance
of issues that we needed to check up on. A lot of these are filtered on
down the line but it is clear that there needs to be something to catch
these issues. Maybe we could lint to make `max_length` a mandatory
argument? I don't know if that's necessary at all but I think that the
limit should be set by the invoker due to the wide arrangement of cases
that this proc could be used in.
This could all be a big nothingburger if the aforementioned PR is
reverted but a big chunk of cases fixed in this PR need to be fixed
regardless of that since people could put in 1024 character names for
stuff like guardians (or more now with the change). Consider this
"revert agnostic".
## Changelog
🆑
fix: A lot of instances where you could fill in 1024-character names
(normal limit is 42) have been patched out, along with too-long plaque
names, too-long descriptions, and more.
/🆑
## About The Previous Pull Request
#85308 reverted by #85929

~~Causes the round to not start when a player isn't eligible for any
jobs at a specific priority level due to runtimes trying to `pick()`
from an empty list aborting the entire job assignment stack.~~
(Fixed???? by
e0e9f2f430)
Maybe we should test merge this for a mo just to make sure no more
cheeky runtimes pop up before merging.
## About The Pull Request
This PR does a couple of minor things:
Makes the job debug logging a bit easier to follow.
Minorly brings some SSjob code up to code standards, converting proc
names to snake_case and doing some otherm is cleanup.
Refactored some stuff into different procs, updated some comments.
And some major things:
Changes the job assignment logic.
Old behaviour
> Assign dynamic priority roles
> Force one Head of Staff (if possible)
> Assign all AIs
> Assign overflow roles (bugged in 2 ways)
> Shuffle the available jobs list once, at the start of the random job
assignment loop
> Pick and assign random jobs for random players from High prefs down,
with a priority on Head of Staff roles
> Handle everyone that couldn't be assigned a random job
New behaviour
> Assign dynamic priority roles
> Assign all Head of Staff roles to players with High prefs
> If no Head of Staff was made in the above way, force one Head of Staff
(if possible)
> Assign all AIs
> Assign overflow roles (fixed)
> Prioritise and fill unfilled head roles at each job priority pref
level, from High prefs down.
> Build a list of all jobs that each unassigned player could be eligible
for at the above pref level.
> Pick a job from that list at random and assign it to the player.
> Handle everyone that couldn't be assigned a random job.
In reality there should be little impact on overall job assignment, the
code changes read more as semantics. For example, the priority check for
filling Head slots will have the same candidate pool in both old and new
versions, but in the new version we're more clearly saying that Heads
are important and we want to prioritise filling them for the sake of
round progression even though the outcome in new and old is the same.
A key change will lead to an increase in assistants - Overflow fixes.
Currently the code block to do early assignments to the Overflow role
doesn't work - or works but not as you'd expect. The idea was is that
because enabling the Overflow role in the prefs menu is an On/Off toggle
that sets the job to High priority when enabled and prevents any other
High priority pref, players that have the Overflow role enabled will
**always** get it. It's their highest priority job with infinite slots.
So we do a pass right at the start to give everyone with the Overflow
role enabled that role and save us wasting time later on in random job
code giving them that same role but with more work.
The problem is the code for this only assigns the Overflow role to
people with it set to Low priority in their prefs, resulting in log
readouts like:
```
[2024-07-27 09:49:43.469] DEBUG-JOB: DO, Running Overflow Check 1
[2024-07-27 09:49:43.469] DEBUG-JOB: Running FOC, Job: /datum/job/assistant, Level: Low Priority
[2024-07-27 09:49:43.472] DEBUG-JOB: FOC player job enabled at wrong level, Player: Radioprague, TheirLevel: Medium Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.472] DEBUG-JOB: FOC player job enabled at wrong level, Player: Caluan, TheirLevel: High Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.473] DEBUG-JOB: FOC player job enabled at wrong level, Player: Caractaser, TheirLevel: High Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.473] DEBUG-JOB: FOC player job enabled at wrong level, Player: Apsua, TheirLevel: High Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.475] DEBUG-JOB: FOC player job enabled at wrong level, Player: Bebrus2, TheirLevel: Medium Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.475] DEBUG-JOB: AC1, Candidates: 0
```
Where nobody gets pre-assigned the overflow role because their prefs are
all set to the High priority from being toggled... Except wait a second,
some people have it at Medium priority when it should just be a No
Role/High Priority Role toggle?
And herein we meet a problem. My hypothesis is that traits and stuff
that change the overflow have allowed players to set the "ordinary"
overflow role of Assistant to Medium and/or Low priority.
This still shows as enabled in the prefs menu, but leads to an outcome
where a player with assistant enabled is assigned Cook instead.
```
[2024-07-27 09:49:47.775] DEBUG-JOB: DO, Running Overflow Check 1
[2024-07-27 09:49:47.775] DEBUG-JOB: Running FOC, Job: /datum/job/assistant, Level: Low Priority
...
[2024-07-27 09:49:43.475] DEBUG-JOB: FOC player job enabled at wrong level, Player: Bebrus2, TheirLevel: Medium Priority, ReqLevel: Low Priority
...
[2024-07-27 09:49:47.987] DEBUG-JOB: Running AR, Player: Bebrus2, Job: /datum/job/cook, LateJoin: 0
```
So players with the Overflow job pref set to Low (an unexpected state,
should be disabled or High) would be guaranteed to get that role if none
of the higher priority Head of Staff/AI/Dynamic roles took over via the
bugged "force overflow for people with the pref enabled" proc.
Players with the Overflow job pref set to High would be guaranteed to
get that role if none of the higher priority Head of Staff/AI/Dynamic
roles took over via the random job assignment code giving them their
Highest priority role thanks to the infinite job slots of the Overflow.
And players with the Overflow job pref set to Medium (an unexpected
state, should be disabled or High) would get Assistant if the shuffle
step of the available jobs list put Assisstant before any of the other
jobs they had prefs enabled for at Medium that weren't already filled,
otherwise they'd get another random job.
This code is now changed to ignore the priority the player has set when
looking for people to fill the overflow role. As long as it **is**
enabled, the player will get it unless they're forced into a dynamic
ruleset role (AI when malf rolls) or a Head of Staff role due to their
other prefs (they have RD set to med or low, and no other player has a
Head of Staff at high so they get randomly picked and miss the overflow
role).
This will increase the number of assistants in shifts where their pref
state has Assisstant in the bugged Medium priority, but doesn't change
it for bugged Low and not-bugged High/On priority.
On the other side of the coin, we have how the random jobs are picked.
They're kinda not random, and I noticed this reading the logs then
reading the code.
The list of available jobs to pick from is randomly shuffled - but only
**once**. All players pull from a list of jobs in the same order. So you
end up with a log block like this:
```
[2024-07-27 09:49:47.985] DEBUG-JOB: DO pass, Player: Pierow, Level:3, Job:Botanist
[2024-07-27 09:49:47.985] DEBUG-JOB: Running AR, Player: Pierow, Job: /datum/job/botanist, LateJoin: 0
[2024-07-27 09:49:47.985] DEBUG-JOB: Player: Pierow is now Rank: Botanist, JCP:0, JPL:2
[2024-07-27 09:49:47.986] DEBUG-JOB: DO pass, Player: Daddos, Level:3, Job:Botanist
[2024-07-27 09:49:47.986] DEBUG-JOB: Running AR, Player: Daddos, Job: /datum/job/botanist, LateJoin: 0
[2024-07-27 09:49:47.986] DEBUG-JOB: Player: Daddos is now Rank: Botanist, JCP:1, JPL:2
[2024-07-27 09:49:47.986] DEBUG-JOB: FOC job filled and not overflow, Player: Bebrus2, Job: /datum/job/botanist, Current: 2, Limit: 2
[2024-07-27 09:49:47.987] DEBUG-JOB: FOC player job not enabled, Player: Bebrus2
[2024-07-27 09:49:47.987] DEBUG-JOB: DO pass, Player: Bebrus2, Level:3, Job:Cook
[2024-07-27 09:49:47.987] DEBUG-JOB: Running AR, Player: Bebrus2, Job: /datum/job/cook, LateJoin: 0
[2024-07-27 09:49:47.988] DEBUG-JOB: Player: Bebrus2 is now Rank: Cook, JCP:0, JPL:1
[2024-07-27 09:49:47.988] DEBUG-JOB: FOC player job not enabled, Player: Redwizz
[2024-07-27 09:49:47.988] DEBUG-JOB: FOC job filled and not overflow, Player: Redwizz, Job: /datum/job/cook, Current: 1, Limit: 1
```
The list is shuffled into an order of something like `list("Scientist",
"Botanist", "Cook", "Sec Officer", ...)` then iterated over for each
player. So every random job selection goes:
> "Does Player1 have Scientist enabled and at the right priority? No?
Okay, Botanist? Yes? You get botanist."
> "Does Player2 have Scientist enabled and at the right priority? No?
Okay, Botanist? Yes? You get botanist."
> "Does Player3 have Scientist enabled and at the right priority? No?
Okay, Botanist has no slots left so we'll remove it from the list. Okay,
Cook? Yes? You get cook."
> "Does Player4 have Scientist enabled and at the right priority? No?
Okay, Cook has no slots left so we'll remove it from the list. Okay, Sec
Officer? ..."
This can lead to stacked individual departments if it gets randomly
rolled to the start of the list in the shuffle, and completely empty
departments if they end up at the end.
On high pop shifts this is probably less of an issue. Player prefs add
noise to this and as departments at the front fill up, those at the back
pick up some of the lower pref players.
But have you ever had a shift where there's just like... No fucking sec
even though there's tons of players? The logging (before I made changes
in this PR) was a bit ass, but my hypothesis there is that sec officer
was shuffled right at the end of the random job list, so every other
department was filled up before sec officers were picked.
To mitigate this, I made the list shuffle every single time the game
picks a random available job for the player. This should lead to a more
balanced selection of available jobs by avoiding situations where the
code is biased towards packing some departments by accident.
## Why It's Good For The Game
Overflow fixes mean people who go to their prefs and see the Overflow
Role is On will all have the same experience - They will be the Overflow
role.
More random random job selection should prevent individual departments
having a jobs be stacked when it would have otherwise been possible for
a more balanced selection but the code unintentially biased random
departments to be overstaffed and understaffed each shift.
## Changelog
🆑
fix: Having the Overflow Role set to On will properly ensure you get
that role at a High priority as intended by the game code.
fix: Job selection is now a little bit more random. Fixes an
unintentional bias in random job assignment that could lead to
feast-or-famine for roles where everyone is assigned one job and nobody
is assigned another job.
/🆑
## About The Pull Request
Plexagon Crew Manifest has been made into a publicly accessible and
roundstart installed PDA app instead of being restricted to heads,
security and a few odd medical jobs. For this, it lost its major
Detomatix resistance which has been added to security records (minor
resistance) and status display control (major resistance)
To ensure that noone has to wipe their PDAs roundstart, its size on PDA
drives has been halved.
## Why It's Good For The Game
Crew manifest can be easily accessed from the messenger app, but without
nice formatting that plexagon has. The app itself does not have any
capabilities beyond reading crew manifest and printing it out on paper
from consoles, neither of which are something that cannot be already
done with ease. I believe this is a remnant from old PDA days and
doesn't really deserve to stay.
## Changelog
🆑
balance: Plexagon Crew Manifest is now a default PDA app for everyone,
and is free.
balance: Plexagon Crew Manifest no longer provides Detomatix resistance,
but security records and status display control now do.
/🆑
## About The Pull Request
This PR adds a pair of fishing gloves that let you fish and work out at
once, and also a MODsuit module that lets you use MOD gloves to do the
same thing (without the workout, an external fishing rod has to be
inserted first). In both cases, you can equip or unequip bait, hook and
line by using the fishing rod interface which you can open by
right-clicking the gloves. To get both of them, you've to perform the
first fish scanning experiment.
I had to refactor the profound fisher component a bit to do this.
## Why It's Good For The Game
Interweaving a few different features with fishing. Fishing and
Athletics are both skills, so I thought it'd be nice if it were a way to
take advantage of both, and level them up accordingly. Also fishing
gloves with maxxed out athletics can make fishing a lot noticeably
easier at higher difficulty.
## Changelog
🆑
add: Added Athletic Fishing Gloves and Fishing Glove Module to the
advanced fishing tech node. Both can be used to fish without having to
hold a fishing rod. The athletic fishing gloves will also train your
athletics skill.
/🆑
## About The Pull Request
This PR does a couple of minor things:
Makes the job debug logging a bit easier to follow.
Minorly brings some SSjob code up to code standards, converting proc
names to snake_case and doing some otherm is cleanup.
Refactored some stuff into different procs, updated some comments.
And some major things:
Changes the job assignment logic.
Old behaviour
> Assign dynamic priority roles
> Force one Head of Staff (if possible)
> Assign all AIs
> Assign overflow roles (bugged in 2 ways)
> Shuffle the available jobs list once, at the start of the random job
assignment loop
> Pick and assign random jobs for random players from High prefs down,
with a priority on Head of Staff roles
> Handle everyone that couldn't be assigned a random job
New behaviour
> Assign dynamic priority roles
> Assign all Head of Staff roles to players with High prefs
> If no Head of Staff was made in the above way, force one Head of Staff
(if possible)
> Assign all AIs
> Assign overflow roles (fixed)
> Prioritise and fill unfilled head roles at each job priority pref
level, from High prefs down.
> Build a list of all jobs that each unassigned player could be eligible
for at the above pref level.
> Pick a job from that list at random and assign it to the player.
> Handle everyone that couldn't be assigned a random job.
In reality there should be little impact on overall job assignment, the
code changes read more as semantics. For example, the priority check for
filling Head slots will have the same candidate pool in both old and new
versions, but in the new version we're more clearly saying that Heads
are important and we want to prioritise filling them for the sake of
round progression even though the outcome in new and old is the same.
A key change will lead to an increase in assistants - Overflow fixes.
Currently the code block to do early assignments to the Overflow role
doesn't work - or works but not as you'd expect. The idea was is that
because enabling the Overflow role in the prefs menu is an On/Off toggle
that sets the job to High priority when enabled and prevents any other
High priority pref, players that have the Overflow role enabled will
**always** get it. It's their highest priority job with infinite slots.
So we do a pass right at the start to give everyone with the Overflow
role enabled that role and save us wasting time later on in random job
code giving them that same role but with more work.
The problem is the code for this only assigns the Overflow role to
people with it set to Low priority in their prefs, resulting in log
readouts like:
```
[2024-07-27 09:49:43.469] DEBUG-JOB: DO, Running Overflow Check 1
[2024-07-27 09:49:43.469] DEBUG-JOB: Running FOC, Job: /datum/job/assistant, Level: Low Priority
[2024-07-27 09:49:43.472] DEBUG-JOB: FOC player job enabled at wrong level, Player: Radioprague, TheirLevel: Medium Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.472] DEBUG-JOB: FOC player job enabled at wrong level, Player: Caluan, TheirLevel: High Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.473] DEBUG-JOB: FOC player job enabled at wrong level, Player: Caractaser, TheirLevel: High Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.473] DEBUG-JOB: FOC player job enabled at wrong level, Player: Apsua, TheirLevel: High Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.475] DEBUG-JOB: FOC player job enabled at wrong level, Player: Bebrus2, TheirLevel: Medium Priority, ReqLevel: Low Priority
[2024-07-27 09:49:43.475] DEBUG-JOB: AC1, Candidates: 0
```
Where nobody gets pre-assigned the overflow role because their prefs are
all set to the High priority from being toggled... Except wait a second,
some people have it at Medium priority when it should just be a No
Role/High Priority Role toggle?
And herein we meet a problem. My hypothesis is that traits and stuff
that change the overflow have allowed players to set the "ordinary"
overflow role of Assistant to Medium and/or Low priority.
This still shows as enabled in the prefs menu, but leads to an outcome
where a player with assistant enabled is assigned Cook instead.
```
[2024-07-27 09:49:47.775] DEBUG-JOB: DO, Running Overflow Check 1
[2024-07-27 09:49:47.775] DEBUG-JOB: Running FOC, Job: /datum/job/assistant, Level: Low Priority
...
[2024-07-27 09:49:43.475] DEBUG-JOB: FOC player job enabled at wrong level, Player: Bebrus2, TheirLevel: Medium Priority, ReqLevel: Low Priority
...
[2024-07-27 09:49:47.987] DEBUG-JOB: Running AR, Player: Bebrus2, Job: /datum/job/cook, LateJoin: 0
```
So players with the Overflow job pref set to Low (an unexpected state,
should be disabled or High) would be guaranteed to get that role if none
of the higher priority Head of Staff/AI/Dynamic roles took over via the
bugged "force overflow for people with the pref enabled" proc.
Players with the Overflow job pref set to High would be guaranteed to
get that role if none of the higher priority Head of Staff/AI/Dynamic
roles took over via the random job assignment code giving them their
Highest priority role thanks to the infinite job slots of the Overflow.
And players with the Overflow job pref set to Medium (an unexpected
state, should be disabled or High) would get Assistant if the shuffle
step of the available jobs list put Assisstant before any of the other
jobs they had prefs enabled for at Medium that weren't already filled,
otherwise they'd get another random job.
This code is now changed to ignore the priority the player has set when
looking for people to fill the overflow role. As long as it **is**
enabled, the player will get it unless they're forced into a dynamic
ruleset role (AI when malf rolls) or a Head of Staff role due to their
other prefs (they have RD set to med or low, and no other player has a
Head of Staff at high so they get randomly picked and miss the overflow
role).
This will increase the number of assistants in shifts where their pref
state has Assisstant in the bugged Medium priority, but doesn't change
it for bugged Low and not-bugged High/On priority.
On the other side of the coin, we have how the random jobs are picked.
They're kinda not random, and I noticed this reading the logs then
reading the code.
The list of available jobs to pick from is randomly shuffled - but only
**once**. All players pull from a list of jobs in the same order. So you
end up with a log block like this:
```
[2024-07-27 09:49:47.985] DEBUG-JOB: DO pass, Player: Pierow, Level:3, Job:Botanist
[2024-07-27 09:49:47.985] DEBUG-JOB: Running AR, Player: Pierow, Job: /datum/job/botanist, LateJoin: 0
[2024-07-27 09:49:47.985] DEBUG-JOB: Player: Pierow is now Rank: Botanist, JCP:0, JPL:2
[2024-07-27 09:49:47.986] DEBUG-JOB: DO pass, Player: Daddos, Level:3, Job:Botanist
[2024-07-27 09:49:47.986] DEBUG-JOB: Running AR, Player: Daddos, Job: /datum/job/botanist, LateJoin: 0
[2024-07-27 09:49:47.986] DEBUG-JOB: Player: Daddos is now Rank: Botanist, JCP:1, JPL:2
[2024-07-27 09:49:47.986] DEBUG-JOB: FOC job filled and not overflow, Player: Bebrus2, Job: /datum/job/botanist, Current: 2, Limit: 2
[2024-07-27 09:49:47.987] DEBUG-JOB: FOC player job not enabled, Player: Bebrus2
[2024-07-27 09:49:47.987] DEBUG-JOB: DO pass, Player: Bebrus2, Level:3, Job:Cook
[2024-07-27 09:49:47.987] DEBUG-JOB: Running AR, Player: Bebrus2, Job: /datum/job/cook, LateJoin: 0
[2024-07-27 09:49:47.988] DEBUG-JOB: Player: Bebrus2 is now Rank: Cook, JCP:0, JPL:1
[2024-07-27 09:49:47.988] DEBUG-JOB: FOC player job not enabled, Player: Redwizz
[2024-07-27 09:49:47.988] DEBUG-JOB: FOC job filled and not overflow, Player: Redwizz, Job: /datum/job/cook, Current: 1, Limit: 1
```
The list is shuffled into an order of something like `list("Scientist",
"Botanist", "Cook", "Sec Officer", ...)` then iterated over for each
player. So every random job selection goes:
> "Does Player1 have Scientist enabled and at the right priority? No?
Okay, Botanist? Yes? You get botanist."
> "Does Player2 have Scientist enabled and at the right priority? No?
Okay, Botanist? Yes? You get botanist."
> "Does Player3 have Scientist enabled and at the right priority? No?
Okay, Botanist has no slots left so we'll remove it from the list. Okay,
Cook? Yes? You get cook."
> "Does Player4 have Scientist enabled and at the right priority? No?
Okay, Cook has no slots left so we'll remove it from the list. Okay, Sec
Officer? ..."
This can lead to stacked individual departments if it gets randomly
rolled to the start of the list in the shuffle, and completely empty
departments if they end up at the end.
On high pop shifts this is probably less of an issue. Player prefs add
noise to this and as departments at the front fill up, those at the back
pick up some of the lower pref players.
But have you ever had a shift where there's just like... No fucking sec
even though there's tons of players? The logging (before I made changes
in this PR) was a bit ass, but my hypothesis there is that sec officer
was shuffled right at the end of the random job list, so every other
department was filled up before sec officers were picked.
To mitigate this, I made the list shuffle every single time the game
picks a random available job for the player. This should lead to a more
balanced selection of available jobs by avoiding situations where the
code is biased towards packing some departments by accident.
## Why It's Good For The Game
Overflow fixes mean people who go to their prefs and see the Overflow
Role is On will all have the same experience - They will be the Overflow
role.
More random random job selection should prevent individual departments
having a jobs be stacked when it would have otherwise been possible for
a more balanced selection but the code unintentially biased random
departments to be overstaffed and understaffed each shift.
## Changelog
🆑
fix: Having the Overflow Role set to On will properly ensure you get
that role at a High priority as intended by the game code.
fix: Job selection is now a little bit more random. Fixes an
unintentional bias in random job assignment that could lead to
feast-or-famine for roles where everyone is assigned one job and nobody
is assigned another job.
/🆑
---------
Co-authored-by: san7890 <the@san7890.com>
## About The Pull Request
More techweb feedback processing.
1. NT frontier app is much more useful and the partners give discounts
for big nodes. Now you can accelerate the research a lot if you focus on
NT frontier. Find [green text in the
tree](https://www.figma.com/board/IhOqYfG5XFBxcgaRSprWzK/Tech-New?node-id=0-1&t=uDMlvA6QcXgz6umU-1)
to see which nodes can have full discounts.
2. Roboticists now have access to ordnance to be able to work on gas
shells for faster mech weapon unlocks
3. BZ shell was rarely performed on LRP servers due to people not
knowing that you can easily make BZ in a portable pump, so it is no
longer a required experiment on the path to experimental tools and a
discount experiment for exp tools instead
4. Cytology experiment is a discount one to ease the path to Genetics
node
5. Cryostasis prerequisite got removed by accident in one of the techweb
tweaks
6. Atmos techs can download NT frontier and build compressor board in
engi imprinter
## Why It's Good For The Game
Balancing the tree out according to the player's behaviour.
## Changelog
🆑
balance: TechWeb: NT Frontier partners now give full discounts for many
high tier nodes, corresponding to the partner theme, instead of partial
discounts for random nodes
qol: Atmos techs can download NT frontier and build compressor board in
engi imprinter
balance: Roboticists now always have ordnance access for the discount
experiments they need
balance: TechWeb: BZ shell is now a discount experiment for experimental
tools instead of required exp for fusion
balance: TechWeb: Noblium shell is a discount experiment for RCD
upgrades instead of exp tools discount
balance: TechWeb: Vat-grown slime scan is a discount experiment instead
of required one
fix: TechWeb: Cryostasis node properly requires advanced medbay
equipment as it should
/🆑
## About The Pull Request
it's - conjunction of "it" and "is"
its - possessive form of "it"
grammar is hard, and there were a lot of places where "it's" was used
where it shouldn't have been. i went and painstakingly searched the
entire repository for these instances, spending a few hours on it. i
completely ignored the changelog archive, and i may have missed some
outliers. most player-facing ones should be corrected, though
## Why It's Good For The Game
proper grammar is good
## Changelog
🆑
spellcheck: Numerous instances of "it's" have been properly replaced
with "its"
/🆑
## About The Pull Request
### EDITED, see spoiler for previous about section.
This pr adds the `TRAIT_SILICON_EMOTES_ALLOWED`, which is now used to
determine what can perform silicons emotes instead of typechecks.
We do this by adding a `trait_required` var to emotes, which if set is
checked for in `can_run_emote(...)` and means the mob must have that
trait to use the emote.
We then adds this trait to all of the mobs previously capable of using
silicon emotes and the beep emote, being:
All silicons, basic bots, simple bots, orbies, and brain mobs.
In addition, we add the trait to robotic voicebox users.
Finally, it makes beeping a silicon emote.
What this changes is that robotic voicebox users can beep and use other
silicon emotes, basic and simple bots can actually beep, sentient orbies
could use other silicon emotes, and brains can beep and use silicon
emotes.
Previously brains where on the allowed types list for beeping, but
living emotes also blocked brains generally, so they couldn't _actually_
beep.
<details>
<summary>Previous About Section</summary>
All this really does is add a new trait, `TRAIT_SILICON_EMOTES_ALLOWED`,
which when given to a human allows them to use silicon emotes.
It does this by adding the `/mob/living/carbon/human` type to the
allowed types for these emotes, but then adding an additional check to
`can_run_emote(...)` for these emotes to block it for humans if they
don't have the trait.
We add it to the typecache because the base checks for
`can_run_emote(...)` would block if not for that, but we _do_ want the
other checks it runs.
</details>
## Why It's Good For The Game
I just think it'd be fun, really. Like, _I'd_ want to beep at people
when I'm going out of my way to augment the shit out of my character.
It's an item primarily accessible by roboticists and transhumanists,
both of which are encouraged/required to interact with silicons, so I
think this'd lead to fun interactions for those that do commit to
getting the silicon-speech tongue replacement.
Finally, I mean, it's a funky synthesizer that makes you sound like a
silicon. Why shouldn't it let you synthesize these sounds too? Hell,
even its attack verbs are beeping and booping already.
### EDITED, additional justification:
It's weird for basic/simple bots to be able to use all other silicon
emotes except beeping.
MMI'd brains/posibrains being able to beep looked intentional, just
broken. This fixes that.
I feel we might as well just allow them to use other silicon emotes
while we're at it.
## About The Pull Request
<img alt="2dZbpr8MK1"
src="https://github.com/tgstation/tgstation/assets/3625094/dd78feba-224a-41a1-8d4a-83af3a8b68df">
Added an ability to queue up to one node per player in a techweb for an
automatic research.
You can queue up a node only when all requirements are met, but there
are not enough points.
People can't research when there is something in the queue, only add
things to the queue. So a 40 points node can't be researched if someone
queued up a 200 points node ahead of it.
When a node is enqueued by RD, it is placed in front of the queue.
The research button is available when the queue is empty.
TODO:
- [x] Bypass queue when the node cost is zero
## Why It's Good For The Game
No need to stay at the console to wait for the points. No "Research"
button spamming.
## Changelog
🆑
qol: Research nodes can be queued, one per player. RDs can place their
node at the beginning of the queue.
/🆑