Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge upstream 18.01.2025 #1014

Merged
merged 107 commits into from
Jan 18, 2025
Merged

Merge upstream 18.01.2025 #1014

merged 107 commits into from
Jan 18, 2025

Conversation

Gaxeer
Copy link
Collaborator

@Gaxeer Gaxeer commented Jan 18, 2025

Что этот PR делает

Merge upstream 18.01.2025

Summary by Sourcery

Update the plant analyzer to use a TGUI interface, add new features to the hydroponics system, and apply various bug fixes and quality-of-life improvements.

New Features:

  • Added a TGUI-based UI for the plant analyzer, replacing the previous chat-based output.

Tests:

  • Added unit tests for nearsightedness.

MrMelbert and others added 30 commits January 13, 2025 12:49
## About The Pull Request
Adds a pair of nuar glasses in detdrobe premium tab, which makes them
see the world in black and white colors.
## About The Pull Request

It just fixes a small typo i caught while testing other things on my
private server.

## Why It's Good For The Game

TYPOS BAD. ENGLISH GOOD.
## About The Pull Request

balloon_alert is async and thus should not be called on objects that are
about to qdelete
## About The Pull Request

Add `span_class` macro to use instead of <span class='class'> (now only
used for changes I made to radio examine).
Make radio channel tokens info from headset examine more readable by
color coding and displaying it in list format.
Currently set broadcast frequence is also color coded and bold.

## Why It's Good For The Game

It's now easier to understand headset examine info :D

<details>
<summary>
Before
</summary>


![image](https://github.com/user-attachments/assets/6b5d7533-6b8e-47b9-9cd2-7c7a92552ca2)

![image](https://github.com/user-attachments/assets/7fcbde2b-0817-4db6-aca8-d15c17d708be)
</details>

<details>
<summary>
After
</summary>


![image](https://github.com/user-attachments/assets/6e9a7156-9c76-4843-8a45-7fce752a7b27)

![image](https://github.com/user-attachments/assets/50e5fb70-eb18-4fc5-803a-070774c73ccf)
</details>

## Changelog

:cl:
qol: tokens and channel names in radio headset examine are now color
coded and display in list format
qol: broadcast frequency in examine is also color coded
code: add new `span_class` macro
/:cl:
## About The Pull Request

This PR adds the fish pun speech filter to space carp.
This was originally added and implemented for crabs and lobsters but it
seems like it should be fine on space fish as well.

Space Dragons don't have this because Dragons are more refined than the
riff-raff and take classes on proper diction.

## Why It's Good For The Game

For some reason space carp can speak common if they are sapient.
Most sapient space carp come from space dragon rifts so it's useful for
them to be able to speak to each other and coordinate.
I think it's kind of weird that they can talk to the crew to be honest,
but it's probably more fun that they can. That said, if they are going
to be able to communicate with the crew then they should have to talk
like a fish.

## Changelog

:cl:
add: Space Carp now have a more distinctive accent when speaking Common.
/:cl:
…tation tests (tgstation#89026)

## About The Pull Request

this stops gibs from being streaked from spawners during unit tests, as
there's a chance it might just go into space, causing a mapping
nearstation test failure.

there's already a precedent for the "just disable it during unit tests"
solution with tgstation#87878

## Why It's Good For The Game

flaky tests bad :3

## Changelog

no player-facing changes
## About The Pull Request
An alternate to tgstation#89040
![Screenshot 2025-01-12
035024](https://github.com/user-attachments/assets/230e599a-8cae-4dba-8dee-4e9975b7a61e)

Refactors the UI
Adds scrollbar to section rather than window so that the title doesnt
disappear
Gives more contrast to the window's main content section
Tooltip now shows closer to the mouse. It was far off in some cases
Functions!
## Why It's Good For The Game
Fixes a ui bug
## Changelog
:cl:
fix: Fixed icon spacing in the late join menu.
/:cl:
…hen perceived food quality is too high (tgstation#89011)

## About The Pull Request

When going through runtime logs earlier, I noticed the edible
component's examine logic would have an index out of bounds runtime
whenever a lizard were to observe a piece of stinging flatbread.
This seems to be because its `examine(...)` proc would call
`get_perceived_food_quality(...)`, getting an `8`, and then use the
resulting value as an index for `GLOB.food_quality_description`, while
the highest value for such is `FOOD_QUALITY_TOP = 7`.

Trying to find similar issues I noticed `checkLiked(...)` would cap it
to `min(food_quality, FOOD_QUALITY_TOP)` before running anything that
cared about it.
So in this pr we just move that `min(food_quality, FOOD_QUALITY_TOP)`
call into `get_perceived_food_quality(...)` right before it returns,
catching all our potential out of bounds issues.

This fixes our issues.
## Why It's Good For The Game

Fixes jank.
## Changelog
:cl:
fix: Examining edible items with too high of a perceived food quality no
longer runtimes and actually displays a food quality message.
/:cl:
## About The Pull Request
tgstation#82676 Added medipens into deepfryer blacklist as it allowed them to be
filled with custom reagents. Xenobio autoinjectors that are made from
industrial crossbreeds function very similarly to medipens with few
differences. However, they have a different typepath from medipens so
they were not included in the original PR. This adds them into the
blacklist too.
## Why It's Good For The Game
Xenobio autoinjectors are not ment to be filled with custom reagents,
this fixes that.
## Changelog
:cl:
fix: Xenobio autoinjectors, such as mending solution from industrial
purple crossbreed, cannot be deepfried and thus filled with custom
reagents using saltshaker anymore.
/:cl:
… loading (tgstation#89024)

## About The Pull Request

So, funny thing. The syndie base lazy template loads recursively, as it
contains two shuttle docks (infiltrator and steel rain).

But stationary shuttle docks will immediately load their
`roundstart_template` _asynchronously_ upon Initialize. This can cause
issues - such as the shuttle's atoms being initialized before everything
else is, in a weird way. The usual side-effect of this would be runtimes
resulting from the shuttle's initialized walls trying to smooth with
non-initialized turfs on the template that loaded it.

I simply moved to stationary docking port's async load to
LateInitialize. There's prolly a better long-term solution, but this
doesn't hurt, and solves the relevant issue.

you know i really hope we don't have _3_ layer map templates anywhere.

## Why It's Good For The Game

less runtime good.

## Changelog
:cl:
fix: Fixed an icon smoothing error caused by shuttles during recursive
map loading, i.e the nukie shuttles with their base.
/:cl:
## About The Pull Request
currently, the watcher trophy has no effect on 95% of the lavaland mobs
since theyve all been refactored to basic mobs, this rectifies that

## Why It's Good For The Game
Fixes the watcher trophy not working on basic mobs

## Changelog
:cl:
fix: Fixes the watcher trophy not working on basic mobs
/:cl:

---------

Co-authored-by: Jacquerel <[email protected]>
## About The Pull Request

I've noticed that the RCD can print every station airlock type besides
hydroponics, this seems to be an oversight.

It still cannot be used to print science airlocks (not research) as
these do not appear on the station by default, if you want to use these
you'll need to use the airlock painter.
## Why It's Good For The Game

This allows the RCD to print all airlock types that start on the station
by default, fufilling its role as a repair tool.
## Changelog
:cl:
fix: The RCD can print Hydroponics airlocks
/:cl:
…text (tgstation#89048)

## About The Pull Request

Admiring was broken, and looking into it, it's because it didn't
actually pass the user as `user` and instead as `source`, which is
supposed to be the aquarium movable.
Changing this fixes our issue.

Then I noticed admiring was kind of jank for fish tanks (item)- you
could right click to admire it, but only if it's not in-hand.
At the same time, you could left click admire aquariums when the panel
is closed, but you _can't_ left click admire fish tanks even when
they're in hand.
So in this pr we actually let you admire fish tanks when in your active
hand, both left click and right click, left click only working if the
panel is closed.

Similarly, the tooltips for such would only get displayed when your hand
were to be empty, so this makes it also account for the held item being
the fish tank.

I also noticed the open/close panel tooltip was inverted, so I inverted
it to be the right way around.
## Why It's Good For The Game

Nice if it works.
Nice if it doesn't feel incredibly jank.
Nice if the tooltips display more.
## Changelog
:cl:
fix: Aquarium/fish tank admiring works again.
fix: Inverted aquarium/fish tank panel opening tooltip to be the right
way.
qol: You can actually admire an in-hand fish tank by clicking on it.
qol: Aquarium/fish tank admiring tooltips are more consistent.
/:cl:
…ion#89042)

## About The Pull Request

Fully black eyes caused division by zero in their overlays yeah.

## Changelog
:cl:
fix: Fixed division by zero runtimes caused by black eyes
/:cl:
… examine code (tgstation#89036)

## About The Pull Request

Closes tgstation#89006
Also fixed a division by zero in very, very weird examine code

## Changelog
:cl:
fix: Custom vendors now sanitize their inputs
fix: Fixed a division by zero in custom vendor code
/:cl:
tgstation-ci bot and others added 15 commits January 16, 2025 14:11
…on#89112)

## About The Pull Request
Forgot about airless plating when designing it, so some air always
leaked out from the breached insulator wall every round.

## Changelog
:cl:
fix: Fixed active turfs on the new Turreted Outpost ruin.
/:cl:
## About The Pull Request
Another SmartFridge restyle aimed at improving the UI/UX.

Finally used the new component (ImageButton) as I originally wanted to,
but I kept failing.

If you need to get a certain amount of fruit, you don't have to type in
how much you need and then click on the fruit, just type it in and the
fruit will be dispensed immediately, example in the video below.

There are a total of 3 options to get what you need with SmartFridge:
1. Just click on the product, you will get 1 unit, nothing new.
2. Enter the required value, this was already there but it became a bit
more convenient because you don't have to click on the product after
entering it.
3. Press Right Mouse Button to get everything at once.

## Why It's Good For The Game
Better UI/UX (No offense to those who made the past variations, they
tried their best, but now there is a special component for such
purposes, which makes it very much easier)

## Demonstration
<details><summary> Comparison screenshots </summary>

| Old (Grid) | New (Grid) | 
| - | - |
|
![image](https://github.com/user-attachments/assets/e4ee68fd-c984-402b-a265-864c08f17771)
|
![image](https://github.com/user-attachments/assets/a5334f86-22a4-4509-a6c7-09e5b39cc113)
|

| Old (List) | New (List)
| - | - |
|
![image](https://github.com/user-attachments/assets/ef5e4a29-470d-4c5e-9776-5bf2af508fb5)
|
![image](https://github.com/user-attachments/assets/653ad2f0-247e-4002-8f1f-93b76c77ff67)
|

</details>
<details><summary> Video </summary>


https://github.com/user-attachments/assets/c8788707-5947-4f1e-8a3c-6a56ac983e98

</details>

## Changelog

:cl:
qol: SmartFridge got another redesign, and you can dispense all amount
of product in one click (RMB on product)
/:cl:
…ather than trait gene [NO GBP] (tgstation#89089)

## About The Pull Request


![image](https://github.com/user-attachments/assets/3d4c5d7a-904c-4b63-a6c8-8c65e1a490da)

Didn't know that some plants have reagent traits defined for grafted
traits.

It didn't work because the trait_db contained only subtypes of
`/datum/plant_gene/trait`, but not `/datum/plant_gene/reagent`.

## Why It's Good For The Game

Fix

## Changelog

:cl:
fix: Fixed plant analyzer UI crashing on plants that have a reagent gene
on their graft
fix: Plants with reagent traits in the graft now properly say the name
of the grafted reagent
/:cl:
Copy link

sourcery-ai bot commented Jan 18, 2025

🧙 Sourcery has finished reviewing your pull request!


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions github-actions bot added TGUI Добавление или изменение существующего интерфейса на базе фреймворка TGUI 🖌️ Спрайты Вы заработали свою миска-рис и кошко-жена. Партия гордится вами! 🗺️ Изменение Карты В этом ПРе затронут файл не станционной карты. Может и не один. 🎸 Инструменты Мы выдаем себя за реальное сообщество разработчиков. 🙏 Слияние с восходящим потоком О великий восходящий поток, спасибо что приносишь нам свои дары контента и багфиксов labels Jan 18, 2025
@ss220app ss220app bot added the 📜 CL невалиден Этот чейнджлог не пройдет валидацию перед публикацией. Исправить или удалить, если не требуется label Jan 18, 2025
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've reviewed this pull request using the Sourcery rules engine.

tgui/packages/tgui/interfaces/AdminPDA.tsx Show resolved Hide resolved
tgui/packages/tgui/interfaces/AdminPDA.tsx Show resolved Hide resolved
tgui/packages/tgui/interfaces/AdminPDA.tsx Show resolved Hide resolved
tgui/packages/tgui/interfaces/AdminPDA.tsx Show resolved Hide resolved
Copy link

This PR causes following conflicts on translate branch:

code/game/objects/items/devices/radio/headset.dm
++<<<<<<< HEAD
 +	if(!(item_flags & IN_INVENTORY) || loc != user)
 +		. += span_notice("A small screen on the headset flashes, it's too small to read without holding or wearing the headset.")
 +		return
 +
 +	// construction of frequency description
 +	var/list/available_channels = list()
 +	available_channels += "<li><b>[span_radio(RADIO_KEY_COMMON)]</b> for the currently tuned frequency</li>"
 +	if(special_channels & RADIO_SPECIAL_BINARY)
 +		available_channels += "<li><b>[span_binarysay(MODE_TOKEN_BINARY)] for [span_binarysay(capitalize(MODE_BINARY))]</b></li>"
 +
 +	for(var/i in 1 to length(channels))
 +		var/channel_name = channels[i]
 +		var/channel_token = GLOB.channel_tokens[channel_name]
 +		var/channel_span_class = get_radio_span(GLOB.radiochannels[channel_name])
 +
 +		if(i == 1)
 +			available_channels += "<li><b>[span_class(channel_span_class, MODE_TOKEN_DEPARTMENT)]</b> or <b>[span_class(channel_span_class, channel_token)]</b> for <b>[span_class(channel_span_class, channel_name)]</b></li>"
 +		else
 +			available_channels += "<li><b>[span_class(channel_span_class, channel_token)]</b> for <b>[span_class(channel_span_class, channel_name)]</b></li>"
 +
 +	. += span_notice("A small screen on the headset displays the following available frequencies:")
 +	. += span_notice("<ul style='display:inline-block; margin: 0; list-style: square;'>[available_channels.Join()]</ul>")
 +
 +	if(command)
 +		. += span_info("<b>Alt-click</b> to toggle the high-volume mode.")
++||||||| 62c8820bf71
++	if(item_flags & IN_INVENTORY && loc == user)
++		// construction of frequency description
++		var/list/avail_chans = list("Use [RADIO_KEY_COMMON] for the currently tuned frequency")
++		if(special_channels & RADIO_SPECIAL_BINARY)
++			avail_chans += "use [MODE_TOKEN_BINARY] for [MODE_BINARY]"
++		if(length(channels))
++			for(var/i in 1 to length(channels))
++				if(i == 1)
++					avail_chans += "use [MODE_TOKEN_DEPARTMENT] or [GLOB.channel_tokens[channels[i]]] for [LOWER_TEXT(channels[i])]"
++				else
++					avail_chans += "use [GLOB.channel_tokens[channels[i]]] for [LOWER_TEXT(channels[i])]"
++		. += span_notice("A small screen on the headset displays the following available frequencies:\n[english_list(avail_chans)].")
++
++		if(command)
++			. += span_info("Alt-click to toggle the high-volume mode.")
++	else
++		. += span_notice("A small screen on the headset flashes, it's too small to read without holding or wearing the headset.")
++=======
+ 	if(item_flags & IN_INVENTORY && loc == user)
+ 		// construction of frequency description
+ 		var/list/avail_chans = list("Используйте [RADIO_KEY_COMMON] для текущей настроенной частоты")
+ 		if(special_channels & RADIO_SPECIAL_BINARY)
+ 			avail_chans += "используйте [MODE_TOKEN_BINARY] для канала \"[MODE_BINARY]\""
+ 		if(length(channels))
+ 			for(var/i in 1 to length(channels))
+ 				if(i == 1)
+ 					avail_chans += "используйте [MODE_TOKEN_DEPARTMENT] или [GLOB.channel_tokens[channels[i]]] для канала \"[LOWER_TEXT(channels[i])]\""
+ 				else
+ 					avail_chans += "используйте [GLOB.channel_tokens[channels[i]]] для канала \"[LOWER_TEXT(channels[i])]\""
+ 		. += span_notice("Маленький экран на дисплее наушника показывает следующие доступные частоты:\n[english_list(avail_chans)].")
+ 
+ 		if(command)
+ 			. += span_info("Альт-Клик для переключения режима повышенной громкости.")
+ 	else
+ 		. += span_notice("Маленький экран на наушнике мигает, но его не разобрать, только если вы не держите или носите наушник.")
++>>>>>>> origin/translate
code/game/objects/items/devices/radio/radio.dm
++<<<<<<< HEAD
 +		. += span_notice("It is set to broadcast over the [span_radio("[frequency/10]")] frequency.")
++||||||| 62c8820bf71
++		. += span_notice("It is set to broadcast over the [frequency/10] frequency.")
++=======
+ 		. += span_notice("Передача настроена на частоту [frequency/10].")
++>>>>>>> origin/translate
code/game/objects/items/storage/lockbox.dm
++<<<<<<< HEAD
 +	if(!silent)
 +		balloon_alert(user, "access denied!")
++||||||| 62c8820bf71
++
++	balloon_alert(user, "access denied!")
++=======
+ 
+ 	balloon_alert(user, "в доступе отказано!")
++>>>>>>> origin/translate
code/modules/mob/living/basic/space_fauna/carp/carp.dm
++<<<<<<< HEAD
 +	AddComponent(/datum/component/speechmod, replacements = strings("crustacean_replacement.json", "crustacean"))
 +	AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("gnashes")))
++||||||| 62c8820bf71
++	AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("gnashes")))
++=======
+ 	AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("скалится")))
++>>>>>>> origin/translate
code/modules/uplink/uplink_items/contractor.dm
++<<<<<<< HEAD
 +	desc = "A reinforcement operative will be sent to aid you in your goals, \
 +		they are paid separately, and will not take a cut from your profits."
++||||||| 62c8820bf71
++	desc = "A reinforecment operative will be sent to aid you in your goals, \
++		they are paid separately, and will not take a cut from your profits."
++=======
+ 	desc = "Подкрепление в виде оперативника будет отправлено для помощи в достижении ваших целей - \
+ 		они оплачиваются отдельно и не отнимают часть вашей прибыли."
++>>>>>>> origin/translate
tgui/packages/tgui/interfaces/ApcControl.jsx
tgui/packages/tgui/interfaces/JobSelection.tsx
++<<<<<<< HEAD
 +};
 +
 +function JobEntry(props: JobEntryProps) {
 +  const { jobName, job, department, onClick } = props;
 +
 +  const jobIcon = JOB2ICON[jobName] || null;
 +
++||||||| 62c8820bf71
++}) => {
++  const jobName = data.jobName;
++  const job = data.job;
++  const department = data.department;
++  const jobIcon = JOB2ICON[jobName] || null;
++=======
+ }) => {
+   const jobName = data.jobName;
+   const job = data.job;
+   const department = data.department;
+   const jobIcon = JOB2ICON[ReverseJobsRu(jobName)] || null;
++>>>>>>> origin/translate
++<<<<<<< HEAD
 +              {shuttle_status && <NoticeBox info>{shuttle_status}</NoticeBox>}
 +              <Box as="span" color="label">
 +                It is currently {round_duration} into the shift.
 +              </Box>
++||||||| 62c8820bf71
++              {data.shuttle_status && (
++                <NoticeBox info>{data.shuttle_status}</NoticeBox>
++              )}
++              <span style={{ color: 'grey' }}>
++                It is currently {data.round_duration} into the shift.
++              </span>
++              <Button
++                style={{ position: 'absolute', right: '1em' }}
++                onClick={() => act('select_job', { job: 'Random' })}
++                content="Random Job!"
++                tooltip="Roll target random job. You can re-roll or cancel your random job if you don't like it."
++              />
++=======
+               {data.shuttle_status && (
+                 <NoticeBox info>{data.shuttle_status}</NoticeBox>
+               )}
+               <span style={{ color: 'grey' }}>
+                 Смена идёт уже: {data.round_duration}.
+               </span>
+               <Button
+                 style={{ position: 'absolute', right: '1em' }}
+                 onClick={() => act('select_job', { job: 'Random' })}
+                 content="Случайная профессия!"
+                 tooltip="Случайно выбрать профессию. Вы можете повторно выбирать случайную профессию или отказаться от этого."
+               />
++>>>>>>> origin/translate
++<<<<<<< HEAD
 +            {Object.entries(departments).map(([name, department]) => (
 +              <DepartmentEntry
 +                key={name}
 +                name={DEPARTMENTS_RU[name] || name}
 +                department={department}
 +              />
 +            ))}
++||||||| 62c8820bf71
++            {Object.entries(departments).map((departmentEntry) => {
++              const departmentName = departmentEntry[0];
++              const entry = departmentEntry[1];
++              return (
++                <Box key={departmentName} minWidth="30%">
++                  <StyleableSection
++                    title={
++                      <>
++                        {DEPARTMENTS_RU[departmentName] || departmentName}
++                        <span
++                          style={{
++                            fontSize: '1rem',
++                            whiteSpace: 'nowrap',
++                            position: 'absolute',
++                            right: '1em',
++                            color: Color.fromHex(entry.color)
++                              .darken(60)
++                              .toString(),
++                          }}
++                        >
++                          {entry.open_slots +
++                            (entry.open_slots === 1 ? ' slot' : ' slots') +
++                            ' available'}
++                        </span>
++                      </>
++                    }
++                    style={{
++                      backgroundColor: entry.color,
++                      marginBottom: '1em',
++                      breakInside: 'avoid-column',
++                    }}
++                    titleStyle={{
++                      'border-bottom-color': Color.fromHex(entry.color)
++                        .darken(50)
++                        .toString(),
++                    }}
++                    textStyle={{
++                      color: Color.fromHex(entry.color).darken(80).toString(),
++                    }}
++                  >
++                    <Stack vertical>
++                      {Object.entries(entry.jobs).map((job) => (
++                        <Stack.Item key={job[0]}>
++                          <JobEntry
++                            key={job[0]}
++                            jobName={job[0]}
++                            job={job[1]}
++                            department={entry}
++                            onClick={() => {
++                              act('select_job', { job: job[0] });
++                            }}
++                          />
++                        </Stack.Item>
++                      ))}
++                    </Stack>
++                  </StyleableSection>
++                </Box>
++              );
++            })}
++=======
+             {Object.entries(departments).map((departmentEntry) => {
+               const departmentName = departmentEntry[0];
+               const entry = departmentEntry[1];
+               return (
+                 <Box key={departmentName} minWidth="30%">
+                   <StyleableSection
+                     title={
+                       <>
+                         {DEPARTMENTS_RU[departmentName] || departmentName}
+                         <span
+                           style={{
+                             fontSize: '1rem',
+                             whiteSpace: 'nowrap',
+                             position: 'absolute',
+                             right: '1em',
+                             color: Color.fromHex(entry.color)
+                               .darken(60)
+                               .toString(),
+                           }}
+                         >
+                           {'позиций доступно: ' + entry.open_slots}
+                         </span>
+                       </>
+                     }
+                     style={{
+                       backgroundColor: entry.color,
+                       marginBottom: '1em',
+                       breakInside: 'avoid-column',
+                     }}
+                     titleStyle={{
+                       'border-bottom-color': Color.fromHex(entry.color)
+                         .darken(50)
+                         .toString(),
+                     }}
+                     textStyle={{
+                       color: Color.fromHex(entry.color).darken(80).toString(),
+                     }}
+                   >
+                     <Stack vertical>
+                       {Object.entries(entry.jobs).map((job) => (
+                         <Stack.Item key={job[0]}>
+                           <JobEntry
+                             key={job[0]}
+                             jobName={job[0]}
+                             job={job[1]}
+                             department={entry}
+                             onClick={() => {
+                               act('select_job', { job: job[0] });
+                             }}
+                           />
+                         </Stack.Item>
+                       ))}
+                     </Stack>
+                   </StyleableSection>
+                 </Box>
+               );
+             })}
++>>>>>>> origin/translate
tgui/packages/tgui/interfaces/NtosDeptOrder.tsx
++<<<<<<< HEAD
 +    (cost >= COST_VERY_LONG_BOUND && 'very long') ||
 +    (cost >= COST_LONG_BOUND && 'long') ||
 +    (cost >= COST_MODERATE_BOUND && 'moderate') ||
 +    'short';
++||||||| 62c8820bf71
++    (cost > COST_UPPER_BOUND * 0.75 && 'long') ||
++    (cost > COST_UPPER_BOUND * 0.25 && 'moderate') ||
++    'short';
++=======
+     (cost > COST_UPPER_BOUND * 0.75 && 'Долгое') ||
+     (cost > COST_UPPER_BOUND * 0.25 && 'Приличное') ||
+     'Короткое';
++>>>>>>> origin/translate

@Gaxeer Gaxeer added 📜 CL не требуется Эти изменения не влияют на игровой процесс или игроки по какой-то причине не должны о них знать and removed 📜 CL невалиден Этот чейнджлог не пройдет валидацию перед публикацией. Исправить или удалить, если не требуется labels Jan 18, 2025
@Gaxeer Gaxeer merged commit cb3b30e into master Jan 18, 2025
28 of 34 checks passed
Gaxeer added a commit that referenced this pull request Jan 18, 2025
## Что этот PR делает

Исправляем ветку translate после слияния с восходящим потоком
#1014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🎸 Инструменты Мы выдаем себя за реальное сообщество разработчиков. 🖌️ Спрайты Вы заработали свою миска-рис и кошко-жена. Партия гордится вами! 🙏 Слияние с восходящим потоком О великий восходящий поток, спасибо что приносишь нам свои дары контента и багфиксов 📜 CL не требуется Эти изменения не влияют на игровой процесс или игроки по какой-то причине не должны о них знать TGUI Добавление или изменение существующего интерфейса на базе фреймворка TGUI 🗺️ Изменение Карты В этом ПРе затронут файл не станционной карты. Может и не один.
Projects
None yet
Development

Successfully merging this pull request may close these issues.