## About The Pull Request
Lets you copy characters in the character customizer. This'll be useful
if you ever want to create variants of your character or Need to move
characters to different slots.
This needs large scale testing, I couldn't break anything on local but
given this involves tinkering with saves better safe than sorry.
## Why It's Good For The Game
I saw a complaint on discord about having to delete characters to
reorganize the list, this resolves that.
This also lets you create a "base" character to use as a template or to
generate variants of an existing character without making them from
scratch or editing them.
## Proof Of Testing
<details>
<summary>Screenshots/Videos</summary>
Soon....
</details>
## Changelog
🆑
qol: You can now copy your characters into other slots.
/🆑
---------
Co-authored-by: xPokee <catmc8565@gmail.com>
## About The Pull Request
`create_from_ghost` can be called from stuff like... dynamic executing a
ruleset, so putting a sleep/user input within it causes problems
So I refactored ghost spawns a fair bit, creating a clear delineation
between where you can and can't put user input
## Changelog
🆑 Melbert
fix: Pirates will no longer randomly spawn as human
fix: Servant Golems have numbered names again
refactor: Refactored ghost spawns (like spider eggs or pirate spawners),
report any oddities
/🆑
## About The Pull Request
A verb is now available on localhost called `"Export Save as Dev
Preferences"`
This exports your current savefile to `/config/dev_preferences.json`
If you then connect to your localhost as a guest, it will load
`dev_preferences.json` as your preference datum
This allows for devs testing the game locally to load preferences for
guests.
(Guests connecting to live servers are completely unaffected.)
## Why It's Good For The Game
Initially I only did this because the recent keybinding changes have
destroyed my muscle memory when testing w/o logging in.
But as I worked on it I thought of a few other usecases, like when
implementing preference version migration - the dev preference is never
saved which means you can re-compile as much as you want without needing
to revert your save manually.
Quirks can now define if they're "species appropriate," where the base
proc's behavior is simply "does this species already have the quirk's
main trait"
I am unsure if that on its own imposes any new restrictions, currently.
Additionally, blood deficiency cannot be picked on any species without
blood or that doesn't breathe.
I'm sure there's more that might make sense, I'm open to suggestions
Alternative to #90238
Currently, reduces the possibility of taking something like blood
deficiency on a race which suffers no downside from it in order to get
free positive quirks.
Future-ly, potentially allows quirks exclusive to only a select few
species as offered by #90238🆑
fix: Species without blood can no longer be blood deficient
/🆑
## About The Pull Request
Quirks can now define if they're "species appropriate," where the base
proc's behavior is simply "does this species already have the quirk's
main trait"
I am unsure if that on its own imposes any new restrictions, currently.
Additionally, blood deficiency cannot be picked on any species without
blood or that doesn't breathe.
I'm sure there's more that might make sense, I'm open to suggestions
Alternative to #90238
## Why It's Good For The Game
Currently, reduces the possibility of taking something like blood
deficiency on a race which suffers no downside from it in order to get
free positive quirks.
Future-ly, potentially allows quirks exclusive to only a select few
species as offered by #90238
## Changelog
🆑
fix: Species without blood can no longer be blood deficient
/🆑
## 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 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>
<!-- 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
_**SPECIAL THANKS TO ARTUR**_
TL;DR read the title. But I ported the ability to change the background
of the character creator [from
Virgo](https://github.com/VOREStation/VOREStation/pull/2341). They are
able to be changed in the character creation menu. Also character
resizing works now, so you can properly see your oversized characters.
All of the possible backgrounds are:
- 000 (Pure Black)
- Midgrey (Grey)
- FFF (Pure White)
- White (White Tiles)
- Plasteel (Normal Tiles)
- Dark (Dark Tiles)
- Plating (Maints Plating)
- Reinforced (Reinforced Floor)
<!-- Describe The Pull Request. Please be sure every change is
documented or this can delay review and even discourage maintainers from
merging your PR! -->
<!-- Please make sure to actually test your PRs. If you have not tested
your PR mention it. -->
## Why It's Good For The Game
Some people play characters that have pure black parts or are really
dark, so the ability to change the background helps them better preview
their character.
<!-- 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. -->
## Proof Of Testing
It worked and I was able to update the background in game and change it
to other ones.
<!-- Compile and run your code locally. Make sure it works. This is the
place to show off your changes! We are not responsible for testing your
features. -->
<details>
<summary>Screenshots/Videos</summary>

</details>
## 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. -->
🆑 xPokee, RimiNosha
add: Added the ability to change the character creator background via
the character visuals tab.
fix: Fixed oversized characters and larger characters not being fully
visible in the character creator
image: Added additional background icons for the character creator.
/🆑
<!-- 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. -->
<!-- By opening a pull request. You have read and understood the
repository rules located on the main README.md on this project. -->
---------
Co-authored-by: RimiNosha <riminosha@gmail.com>
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.)

`/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.
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 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.
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)
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:

**Before**

**After**

🆑
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
So basically there's some byond bug that has made character previews
small and things like cameras offset for the longest time when you open
them.
Basically when ``/atom/movable/screen/proc/set_position`` is called and
it has an ``assigned_map``, sleep, add three to the x and y offset,
sleep, then reset it. Sorry @Mothblocks but your original code to update
the character after a second doesn't seem to work anymore.

## Why It's Good For The Game
This is not good for the game
## Changelog
🆑
fix: Character creator preview being miniature
/🆑
## About The Pull Request
So basically there's some byond bug that has made character previews
small and things like cameras offset for the longest time when you open
them.
Basically when ``/atom/movable/screen/proc/set_position`` is called and
it has an ``assigned_map``, sleep, add three to the x and y offset,
sleep, then reset it. Sorry @Mothblocks but your original code to update
the character after a second doesn't seem to work anymore.

## Why It's Good For The Game
This is not good for the game
## Changelog
🆑
fix: Character creator preview being miniature
/🆑
## 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
Fixes https://github.com/Bubberstation/Bubberstation/issues/2879
The reason for the issue seems rooted in skyrat's own port of the
original json configs on tg (or perhaps the loads of changes they've
made to it over the years). This pr patches it so that characters won't
reset between rounds.
original fixes by smartkar
## Why It's Good For The Game
Guess
## Proof Of Testing
<details>
<summary>Screenshots/Videos</summary>

</details>
It saves the character on creation and works fine after re-accessing the
savefile
## Changelog
🆑
fixes: fixes the issue where characters would reset after a round or on
switching character slots
/🆑
## About The Pull Request
Add the `visuals_only` argument to `safe_transfer_prefs_to_with_damage`
so we can pass it down in the SAD call
## Why It's Good For The Game
Fixes#2273
## Proof Of Testing
Tested it with a breathing tube implant I prommy
## Changelog
🆑
fix: fixed SAD duplicating your round start implants.
/🆑
## About The Pull Request
A few people are having issues getting byond membership features
disabled even though they're a byond member. This is *likely* due to
byond server troubles, and according to lummox the lookup proc should
return null when a connection issue happens. So I've put some handling
in there for that case as well as a single retry.
🆑
fix: Byond membership lookup should now warn you when it fails due to a
connection failure.
/🆑
# Conflicts:
# code/modules/client/preferences.dm
## About The Pull Request
Adds 20 more slots I'm out of character slots I must create more
creatures
## Why It's Good For The Game
I'm out of slots and need more
## Proof Of Testing
i changed a number
## Changelog
🆑
add: Adds 20 more slots for free players and up to 100 slots for BYOND
members
/🆑
3591 individual conflicts
Update build.js
Update install_node.sh
Update byond.js
oh my fucking god
hat
slow
huh
holy shit
we all fall down
2 more I missed
2900 individual conflicts
2700 Individual conflicts
replaces yarn file with tg version, bumping us down to 2200-ish
Down to 2000 individual conflicts
140 down
mmm
aaaaaaaaaaaaaaaaaaa
not yt
575
soon
900 individual conflicts
600 individual conflicts, 121 file conflicts
im not okay
160 across 19 files
29 in 4 files
0 conflicts, compiletime fix time
some minor incap stuff
missed ticks
weird dupe definition stuff
missed ticks 2
incap fixes
undefs and pie fix
Radio update and some extra minor stuff
returns a single override
no more dupe definitions, 175 compiletime errors
Unticked file fix
sound and emote stuff
honk and more radio stuff
## About The Pull Request
A few people are having issues getting byond membership features
disabled even though they're a byond member. This is *likely* due to
byond server troubles, and according to lummox the lookup proc should
return null when a connection issue happens. So I've put some handling
in there for that case as well as a single retry.
🆑
fix: Byond membership lookup should now warn you when it fails due to a
connection failure.
/🆑
## 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
https://github.com/tgstation/tgstation/pull/85947/commits/e0e9f2f430079d4ab7097abe12e75f934131a638)
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
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>
* "Job Playtime Exempt" now also applies to Account Age Restrictions (#84878)
## About The Pull Request
Fixes#84478
Basically, this database flag only worked on playtime restrictions (i.e.
how many hours you had to play on the server as a living person before
you could unlock stuff like Captain). However, this database flag did
not exempt BYOND Account Age restrictions, which is a bit of an annoying
gap to have when it comes to fast-tracking new accounts for whatever an
admin would need. This gap has been closed by having the
`available_in_days` also listen to the same database flag.
If you want me to split it up into multiple flags (which might be
annoying due to how the UI is setup, but possible), let me know.
## Why It's Good For The Game
Administration confusions are weird. I think if an admin is waiving an
account through like this, they should expect to see everything unfurl
as a result - which is why the aforementioned issue report was made.
I also typed the `dbflags` var as a bitflag instead of being null.
Should work.
## Changelog
🆑
admin: Ticking "Job Playtime Exempt" on a player's Job Playtime Tracker
panel will also exempt them from BYOND Account Age restrictions now. It
previously only exempted them from actual living playtime minutes - this
is for the BYOND Account Age in days.
/🆑
* "Job Playtime Exempt" now also applies to Account Age Restrictions
---------
Co-authored-by: san7890 <the@san7890.com>
Co-authored-by: SpaceLoveSs13 <68121607+SpaceLoveSs13@users.noreply.github.com>
## About The Pull Request
Fixes#84478
Basically, this database flag only worked on playtime restrictions (i.e.
how many hours you had to play on the server as a living person before
you could unlock stuff like Captain). However, this database flag did
not exempt BYOND Account Age restrictions, which is a bit of an annoying
gap to have when it comes to fast-tracking new accounts for whatever an
admin would need. This gap has been closed by having the
`available_in_days` also listen to the same database flag.
If you want me to split it up into multiple flags (which might be
annoying due to how the UI is setup, but possible), let me know.
## Why It's Good For The Game
Administration confusions are weird. I think if an admin is waiving an
account through like this, they should expect to see everything unfurl
as a result - which is why the aforementioned issue report was made.
I also typed the `dbflags` var as a bitflag instead of being null.
Should work.
## Changelog
🆑
admin: Ticking "Job Playtime Exempt" on a player's Job Playtime Tracker
panel will also exempt them from BYOND Account Age restrictions now. It
previously only exempted them from actual living playtime minutes - this
is for the BYOND Account Age in days.
/🆑
* Adds Character Loadout Tab to preferences (with just a small handful of items to start)
* step one rip out all the old nasties
* fixes, current bugs: donator lock, ckey lock, one item in case
* opps
* sanity checks, fixed, donator implementation, ckey locking. fixes.
* wew
* final fixes
* Update loadout_categories.dm
* Update loadout_items.dm
* Update loadout_items.dm
* Update declarations.dm
---------
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
Co-authored-by: SpaceLoveSs13 <68121607+SpaceLoveSs13@users.noreply.github.com>
I didn't see https://github.com/tgstation/tgstation/pull/83989 and that
is on me. The UX of it is not suitable enough for preferences menu.
- New row with only one entry makes the UI look much worse and adds too
much blank space
- The deleting confirmation prompt is a weird amount of work and also
doesn't tell you when you get it wrong
- A weird amount was being handled in JavaScript
This reverts the PR and just starts over. You can see the UX here.
https://github.com/tgstation/tgstation/assets/35135081/8106bca7-8c01-41da-8ede-e33a5a548583
## Changelog
🆑
qol: Dramatically improves delete character UI and UX.
/🆑
## About The Pull Request
Adds a button to delete characters, and when deleted it flips to the
nearest character, wow(the last character can't be deleted(I guess)).
### Video:
https://github.com/tgstation/tgstation/assets/78199449/3ad1157a-6c1c-4fb2-9b0d-1da791cad989
## Why It's Good For The Game
Once you know how to create characters, you sometimes want to be able to
delete them.
The reasons for this can be... as simple as freeing up a slot, or
deleting them in order to remake them.
I think this is quite a useful feature that should have been there
before.
## Changelog
🆑 Vishenka0704
qol: Ability to delete characters(yourself)
/🆑
* Add: 2 Quirks Configs (#81033)
This PR adds two new config options for quirks:
- *Flag* `DISABLE_QUIRK_POINTS`
- When enabled, disables quirk points balancing.
- When enabled, players can select positive quirks without first
selecting negative ones.
- When enabled, the quirk points balance visually hides itself on the
Quirks page.
- *Number* `MAX_POSITIVE_QUIRKS`
- Limits the maximum quantity of positive quirks which players can
select using the Character Preferences page.
- I ported this from the old `MAX_QUIRKS` define.
- When set to `0`, players won't be able to select any positive quirks,
and they won't appear on the Quirks page.
- When set to `-1`, players will be able to select any quantity of
positive quirks.
- When commented-out or undefined, the default is `6`.
- When set to `0` or `-1`, the positive quirk balance visually hides
itself on the Quirks page.
There is some downstream repositories asking for the quirks system to be
configurable. Additionally, I always find myself tweaking these values
on my own private servers and I thought it would be nice to share my
edits. Usually I was simply commenting-out sections of this code in
order to get the same result, so it helps to have an official way to
disable quirk points.
🆑 A.C.M.O.
config: Added two new config flags for quirks, DISABLE_QUIRK_POINTS and
MAX_POSITIVE_QUIRKS.
/🆑
* Oh come on
---------
Co-authored-by: Dani Glore <fantasticdragons@gmail.com>
Co-authored-by: Useroth <37159550+Useroth@users.noreply.github.com>
## About The Pull Request
This PR adds two new config options for quirks:
- *Flag* `DISABLE_QUIRK_POINTS`
- When enabled, disables quirk points balancing.
- When enabled, players can select positive quirks without first
selecting negative ones.
- When enabled, the quirk points balance visually hides itself on the
Quirks page.
- *Number* `MAX_POSITIVE_QUIRKS`
- Limits the maximum quantity of positive quirks which players can
select using the Character Preferences page.
- I ported this from the old `MAX_QUIRKS` define.
- When set to `0`, players won't be able to select any positive quirks,
and they won't appear on the Quirks page.
- When set to `-1`, players will be able to select any quantity of
positive quirks.
- When commented-out or undefined, the default is `6`.
- When set to `0` or `-1`, the positive quirk balance visually hides
itself on the Quirks page.
## Why It's Good For The Game
There is some downstream repositories asking for the quirks system to be
configurable. Additionally, I always find myself tweaking these values
on my own private servers and I thought it would be nice to share my
edits. Usually I was simply commenting-out sections of this code in
order to get the same result, so it helps to have an official way to
disable quirk points.
## Changelog
🆑 A.C.M.O.
config: Added two new config flags for quirks, DISABLE_QUIRK_POINTS and
MAX_POSITIVE_QUIRKS.
/🆑
## About The Pull Request
After https://github.com/tgstation/tgstation/pull/80628, these shouldn't
be needed anymore right?
## Why It's Good For The Game
Cleans up some vestigial code
## Changelog
EDIT: Not player-facing.
* Adds a search function to the loadout menu, and improves readability
* Removes the tutorial button that never did anything
* Trims a lot of the fat, deprecated code
Data was being passed to the ui that isn't even being used any more.
* Update preferences.dm
## About The Pull Request
as we added a command role that isn't a head of staff, itd be good to
untie some checks from the command department
so i added a job flag for that, and moved what made sense to different
traits that are added to head of staff minds
## Why It's Good For The Game
revs (the gamemode not the players) shouldnt care about the bridge
assistant existing
## Changelog
🆑
fix: bridge assistant no longer passes some head of staff checks
qol: if you steal a command member's liver, you can now sabre better!
/🆑