-
Notifications
You must be signed in to change notification settings - Fork 48
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 25.01.2025 #1067
Conversation
## About The Pull Request This adds a new function for Lua scripts: `SS13.check_tick()` - it acts pretty much exactly like the `CHECK_TICK` macro in DM. It accepts a single argument, a boolean, which if true - it will act like `CHECK_TICK_HIGH_PRIORITY` instead. ## Why It's Good For The Game this function is a repeated code pattern in lua scripts, so having it in the SS13 lua library is useful. ## Changelog :cl: admin: Added a new function in Lua scripting, SS13.check_tick, to avoid causing too much lag during loops and such. /:cl:
## About The Pull Request This PR adds a "withdraw" button to the pAI candidacy menu, which immediately (or near-immediately, given there's a small delay between tgui refreshes) removes your information from the pAI device's candidate download screen. (The below video was recorded on a local instance of Monkestation, but I've verified that it works exactly the same on tgstation proper too.) https://github.com/user-attachments/assets/8508f17f-db61-4ae9-bdc8-b4214489b8b6 ## Why It's Good For The Game Being able to withdraw your candidacy means that, should you need to go AFK or otherwise leave the game for an extended period of time, your candidate details won't clog up the candidate download screen. Plus, you won't frustrate players who download a pAI, only to find that they're AFK. ## Changelog :cl:MichiRecRoom qol: pAIs can now withdraw their candidacy at any time. /:cl:
## About The Pull Request 1. Removed an errant :: in objectives list 2. Fixed height of modules selector, this fixes tgstation#89071 3. Fixed the categories loop, this fixes tgstation#86881 4. Did some stylistic code changes 5. Made a common ui component to reduce code duplication 6. Fixed a typo from a previous pr >[!Note] > This does not address tgstation#85999, which seems to be an issue on the DM side. <details> <summary>pics</summary> tgstation#89071 fixed ![Screenshot 2025-01-14 173954](https://github.com/user-attachments/assets/997ee3ff-4283-4b0c-a9b2-f05b68bb6fd2) tgstation#86881 fixed ![Screenshot 2025-01-14 175903](https://github.com/user-attachments/assets/a12f493b-fc58-49aa-b9bf-a8162cc794a6) </details> ## Why It's Good For The Game Better ui, bug fixes ## Changelog :cl: fix: Fixed some bugs in the malf ai screen: one bluescreen, an extra colon, modules view /:cl:
## About The Pull Request Removes uselocalstate from library admin. Did some stylistic changes as per usual, broke the code into multiple files ## Why It's Good For The Game useLocalstate is deprecated, I want it out of the codebase ## Changelog N/A
## About The Pull Request Another pretty easy conversion; this mob doesn't really do anything except melee people and become rideable after you feed it cheese fries. Changes in behaviour are that it will now seek out cheese fries by itself if they happen to be lying around, and if it stays mad at you for 10 seconds it will use its powerful tentacle slap ability to hurl you across the room, probably breaking a bone. Really just don't approach this thing if you don't have cheese fries. This mob basically only exists from cytology so I would be surprised if it has existed in more than one round in the past four months. ## Why It's Good For The Game I'm working down the remaining simple animals and a lot of them turn out to still be quick fixes. ## Changelog :cl: refactor: The Cytology Vatbeast now uses the basic mob framework, please report any unusual behaviour. /:cl:
## About The Pull Request adds Space Dragon, which is missing, to the banning panel as it should already be there ## Why It's Good For The Game makes it easier for admins ## Changelog :cl: admin: added Space Dragon role to the banning panel /:cl:
## About The Pull Request Simple animal Dark Wizard => Basic mob Dark Wizard. This mob is I think used in literally one ruin, and very occasionally spawned in deathmatch. They don't really do anything except shoot you with slowing projectiles and hit you with sticks. I gave them a version of blink with a longer cooldown that they use when attacked in melee range purely to make them very marginally more wizard-like, and they will also now try to back away from you while shooting you instead of running towards you. They will also retaliate against anyone who attacks them including as a response to friendly fire from other Dark Wizards, because I think it is funny if they have very little loyalty to each other and that's a fun thing to trigger when you are playing Doom. Finally, we have a component called "revenge ability" which is mostly a standin for AI responses to getting attacked. I made all existing uses of it turn off if you're controlled by a sapient player who can hit those buttons themselves, because they can choose when they want to use those abilities themselves. ## Why It's Good For The Game The march of progress is almost complete ## Changelog :cl: refactor: refactored some code balance: Dark Wizards now teleport when attacked, but are more likely to turn on their allies /:cl:
…Revision verbs (tgstation#89099) ## About The Pull Request ![image](https://github.com/user-attachments/assets/44018d96-c88a-479b-9db0-d87b0b68b92c) ## Why It's Good For The Game eyecandy is nice :3 ## Changelog :cl: qol: Restyled the Who, Adminwho, and Show Server Revision verbs to be prettier. /:cl:
…ation#88860) ## About The Pull Request I swear it's the last one ![image](https://github.com/user-attachments/assets/4572975f-5621-4b1d-9cbf-a3e923eac516) ### Added two new fishes to the rift pool: ![image](https://github.com/user-attachments/assets/0688d0d3-b9a1-4a98-ad61-8e47964acbc9) #### The __mossglob__ is the Fisherman's Bane. The apex of evil. The be-all-end-all in fisher destruction. It is haunted. It deals toxic damage. It throws itself around. It's coated in a deadly and hallucinogenic compound. Its mossy coating is slippery. It revives itself. It throws itself out of aquariums. Best of all, it is extremely easy to catch. How do you deal with it? Well, probably by not fishing in a portal to hell. Otherwise... good luck? Suiciding into it empowers it by 15% and seals you inside. JOIN THE MOSS! ![image](https://github.com/user-attachments/assets/50fb0695-08e7-4c2e-b223-ceba27dd7ffd) #### The __babbelfish__ is a strange sort of predator, a psychic fish. It casts a psychic aura near itself, ~~disturbing people~~ (nvm lol the demoralizer datum is bad), killing fish nearby and then eating their corpses. When it dies, it emits an awesome psychic wail, which will instantly kill all fish in audible range and severely incapacitate psy-sensitive humans: I can't play the ogg here but credits to grungus for it ![image](https://github.com/user-attachments/assets/657f293a-e43f-4e4a-8366-dd8f32dbb2fa) ![image](https://github.com/user-attachments/assets/adedd978-a0ff-4521-88eb-6a232cbaa177) There is also a secret, secondary function of the babbelfish: Splitting one in half (a terrible idea) and shoving it inside your ears will unlock your full psychic potential, granting you psychic resistance and grant you the ability to either understand or speak every single language, at a terrible cost. #### ARMS Failing the fishing minigame while fishing in a heretical rift will now cause the rift to tear your arm (and its fishing rod) off your joints and greedily slurp it up. The Mansus does not care for losers. (Getting bored and walking away while the minigame is up also counts as failure.) However, these missing items can, in fact, be fished back up, which also includes arms -and- heads lost normally to the rift! Not only that, but you're able to fish up random arms of any type, presumably from other fools across time and space. #### This PR probably shouldn't be merged until the bug that causes finite fish counts to not be finite is fixed. Infinite fire sharks are bad enough... Added ABSTRACT flag to profound_fisher fake rod. objectify() now works with instances of objects. Apparently snuck in a random-ass refactor to smoker lungs. Psychic resistance now prevents the instadeath from trying to telekinetically grasp at a opened rift. Hallucinogenic fish with a stinger now inject their hallucinogenic toxins. I woudl like to preemptively apologize to ghommie ## Why It's Good For The Game __Mossglob__ I think the game's missing a fish that's just extremely dangerous to be around, the piscine equivalent to radioactive waste. You can't bin or tank it, because it flies off. You can't kill it, because it's atmos-proof and revives itself anyway. Trying to keep it on a table to turn into disgusting mold 'slices' is a challenge in and of itself. This fish will (not) make people think twice about fishing in hell, and give another reason for security and command to give PSAs to not interact with the rifts across space and time around the station, which I think is wonderful. __Babbelfish__ This fish punishes sloppy fishermen who hold up their catch and then store it inside their bag for the poor fish to slowly asphixiate to death in. The fish griefing that will happen from it will be _wonderful_. The organ thing is a clear reference to HHG, but it has its own twist. You can speak all languages, or understand all languages... but rarely both. It'll make for some silly situations where people just 'make strange noises' at you or try to act as translator for, say, ashwalkers or xenomorphs while being completely clueless as to what anyone is actually saying. __ARMS__ Arms. Arms arms. Someone asked me if rifts let you fish up arms and i said ___IT DOES NOW___. ## Changelog :cl: Ghommie, carlarc, grungus add: Added two new fish to heretic rift fishing. add: You can now fish up arms, heads, and other items lost to heretic rifts! admin: objectify() now works with instances of objects. Mark a player, then an object, and use those marks to call that global proc and you can turn people into pre-existing items. add: Psychic resistance now prevents the instadeath from trying to telekinetically grasp at a opened rift. /:cl: --------- Co-authored-by: Ghom <[email protected]>
… over xenobio (tgstation#88935) ## About The Pull Request Basically if there's too many slimes on a single turf, the slime will not split. The define I set is 2 (which can change) so you can still reasonably spam a few monkeys inside a 3x3 cell and expect the slimes to split. Overcrowding isn't really meant to stop people from doing xenobio like this, it's to stop instances where people add way too many monkeys and in 30 minutes everyone's clients turn into a powerpoint when entering xenobiology. Basically to prevent this from happening. ``` ADMIN LOG: '(thesharkenning)'/(white wolf) deleted all instances of type or subtype of /mob/living/basic/slime (979 instances deleted) ADMIN LOG: '(thesharkenning)'/(white wolf) deleted all instances of type or subtype of /mob/living/basic/slime (641 instances deleted) ADMIN LOG: '(thesharkenning)'/(white wolf) deleted all instances of type or subtype of /mob/living/basic/slime (962 instances deleted) ``` ## Why It's Good For The Game I'm sure it's hell on the server too, but it's definitely something that makes byond cry. You don't need a whole lot of time: just a lot of monkeys and a single slime. ## Changelog :cl: fix: Fixes uncapped xenobio slime multiplication which can easily result in hundreds of slimes. /:cl:
…8714) ## About The Pull Request <details> <summary> expand to spoil the fun of exploring something for yourself </summary> firstly, the new ruin: outpost 31 its layout is vaguely based off an official map of the Outpost 31 from the Thing movie but i ran out of space halfway ![image](https://github.com/user-attachments/assets/6db1aa9f-40d3-4693-897b-01e32b3ee1d2) the boss drops a keycard for the storage room that you cant get in otherwise, containing its own special item, and other stuff probably useful for crew crusher loot: trophy that heals you on each hit the ruin is guarded by like 3 flesh blobs, very resilient (and slow) masses of flesh that deal 3 brute damage, not harmful in melee but WILL attempt to grab and devour/assimilate you which is FAR more lethal https://github.com/user-attachments/assets/542cc6d0-f4ee-4598-9677-a03170c6c1c3 Boss: The Thing (with creative liberties otherwise this thing would instakill you if it was true to source material) difficulty: medium apparently idk mining jesus beat it with 400ms or so HP: 1800 It is a much higher ranking changeling than those infiltrating SS13 It has 3 phases, 600hp each. Depleting its phase health will turn it invincible and it will heal back half in 10 seconds. In order to prevent this, the two Molecular Accelerators must be overloaded by interacting with them to blast the changeling with deadly scifi magic or whatever they do, forcing it to shed its form further and go to the next phase. Not necessary for phase 3 because it literally just dies then it focuses mostly on meleeing you and making certain tiles impassable for you with 1hp tendrils, all attacks are telegraphed so theres no dumb instakills here it alternates between aoe abilities and abilities melee behavior: - if too far, charge at target (charges twice on phase 3) - too close, shriek (unavailable in phase 1) (technically AOE but its more like a melee ability you know??) - otherwise just try to melee Shriek: if the player is too close emit a confusing shriek that makes them confused and drop items aoe behavior (phase 2, 3 only): 1: Puts 4 tendrils in a line cardinally 2: Puts tendrils around itself 3. Puts a patch of tendrils around and under the target, 3x3 in phase 3 4. Phase 3 only - spits patches of acid into the air that hurt when stepped on _(crusher is hard ok)_ https://github.com/user-attachments/assets/cbb98209-d3f0-470d-b0e8-4e310c5b709c unique megafauna loot for this boss is like 1 AI-Uplink brain its like a BORIS module but for humans i think you can figure out what that means while in a human shell they cannot roll non-malf midrounds and cannot be converted, and cannot be mindswapped the human MUST have all robotic organs (minus tongue because its not in the exosuit fab and that kinda sucks to get) will undeploy if polymorphed https://github.com/user-attachments/assets/abcc277a-995a-4fa7-b980-0549b6b7cf52 </details> ## Why It's Good For The Game icebox is severely lacking in actual good ruins (fuck that one fountain ruin) i feel that the loot given by megafauna has been and still apparently is exclusively to make the victor more powerful, which kinda sucks because thats just powergaming???? the loot of this boss is more crewsided, specifically aiding the AI in a VERY limited quantity (1), so its not anything good for powergamers, good for crew if the AI is not rogue ## Changelog :cl: add: outpost 31, the icebox ruin. Also its associated mobs, and megafauna, and loot. Im not spoiling anything, find it yourself. /:cl: --------- Co-authored-by: Ben10Omintrix <[email protected]>
## About The Pull Request AIs can now examine things that don't have a specific shiftclick interaction, which is solely APCs and airlocks. Also fixes Dullahans not being able to examine through their head, because that's a thing I found accidentally. ## Why It's Good For The Game AIs only being able to examine things near its core has always been very annoying, and you're currently able to examine things through security cameras anyways so it's not like we're consistent on how much details the cameras are able to see. This at least makes it a consistent "yes, you can examine through cameras". AIs also don't really have enough ShiftClick interactions to block all of examine just for their existence. ## Changelog :cl: balance: AIs can now examine through their eye. fix: Dullahans can also examine through their head again. /:cl: --------- Co-authored-by: SmArtKar <[email protected]>
…89166) ## About The Pull Request this removes the arbitrary maximum of 10 chat highlights. no clue why this was limited in the first place. ## Why It's Good For The Game it is my god-given right to have a morbillion chat highlights and make IE on my own computer slow to a crawl doing so ## Changelog :cl: qol: Removed the arbitrary limit of 10 maximum highlights. /:cl:
…tion#88489) ## About The Pull Request The spooky element is quite old with a lot of single-letter variables. Had too many species typechecks, and there's an issue that's been bothering me, so I had to bring the code a bit up to date. Furthermore the element wasn't used anywhere but on a couple of very rare instruments, so I've been thinking a likewise very rare fantasy suffix (mythril and wizard rpg event) would've been cool. ## Why It's Good For The Game This will fix tgstation#88474. I believe the single-use versions of the spectral instruments should be spent once someone is skeletonized, not before. It was my fault for not noticing it earlier. ## Changelog :cl: fix: Fixed single-use spectral instruments losing their powers before skeletonizing anyone. add: A very rare spooky suffix for mythril items and the wizard RPG event. /:cl: --------- Co-authored-by: Jacquerel <[email protected]>
…(boulders) (tgstation#89168) ## About The Pull Request Set the minimum flight distance to 3 tiles for objects hit by baseball bat parry, so instead of the boulder being sucked into wielder when the baseball bat hits it, it now bounces back a little. ## Why It's Good For The Game Closes tgstation#87877 ## Changelog :cl: fix: objects with throw_range 0 now properly parried with baseball bats /:cl:
…ve global procs to `cameranet` datum (tgstation#89087) ## 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 :cl: refactor: replace bubble sort with timsort for cameralist, move global procs to `cameranet` datum /:cl:
…lances shotgun shells. (tgstation#89125)
## About The Pull Request Modularizes the comms agent ruin on icebox only includes the actual comms agent's office part because i am tired ok <details> <summary>comms_luxury</summary> (![image](https://github.com/user-attachments/assets/703d0dab-ba57-4e94-babf-9b09c4b90d86)) </details> <details> <summary>comms_cheap</summary> ![image](https://github.com/user-attachments/assets/cf6ad70e-d527-41b5-b90e-b2968794dc18) </details> and comms_standard is the previous office that was in the non modularized map ## Why It's Good For The Game modularized things are unique and good ## Changelog :cl: map: modularizes the comms agent ruin on icebox /:cl:
## About The Pull Request Adds a search bar to the quirks menu ![image](https://github.com/user-attachments/assets/c31f68a1-642a-4099-98a5-e516f5150514) ## Why It's Good For The Game I hate endless scroll lists. Also I want to learn tgui. ## Changelog :cl: qol: Quirk menu now has a search bar /:cl:
…or PDA (tgstation#89177) ## About The Pull Request Closes tgstation#88618 Head IDs now keep the large pointer effect when slotted into a PDA or displayed as the front ID in a wallet ## Changelog :cl: fix: Head IDs now keep the large pointer effect when slotted into a PDA or displayed as the front ID in a wallet /:cl:
Reviewer's Guide by SourceryThis pull request merges a large number of changes from upstream, including new features, bug fixes, refactors, and balance adjustments. The changes span multiple areas of the codebase, including UI, game logic, and content. Class diagram for updated PreferencesMenu componentsclassDiagram
class PreferencesMenuData {
+character_preferences
+selected_quirks
+active_slot
}
class FeatureValueInput {
+feature: Feature
+featureId: string
+shrink?: boolean
+value: unknown
+handleSetValue()
}
class FeatureDropdownInput {
+serverData
+disabled
+buttons
+handleSetValue()
+value
+populateOptions()
}
class QuirksPage {
+selectedQuirks: string[]
+searchQuery: string
+handleQuirkSelection()
+renderQuirkList()
}
FeatureValueInput --> PreferencesMenuData
FeatureDropdownInput --> PreferencesMenuData
QuirksPage --> PreferencesMenuData
Class diagram for new fish types and organsclassDiagram
class Fish {
+fish_id: string
+status: number
+size: number
+weight: number
+set_status()
}
class Mossglob {
+health: number
+death_text: string
+fish_traits: list
+suicide_act()
+get_force_rank()
}
class Babbelfish {
+moron_inside: mob
+psy_wail()
+fishes_die_twice()
+check_loc()
}
class BabbelfishEars {
+organ_traits: list
+healing_factor: number
+bound_component
+on_mob_insert()
+on_mob_remove()
}
Fish <|-- Mossglob
Fish <|-- Babbelfish
BabbelfishEars --|> Organ
State diagram for phobia system changesstateDiagram-v2
[*] --> Normal
Normal --> Phobia: Trigger encountered
Phobia --> Intensified: Prolonged exposure
Intensified --> Normal: Trigger removed
Phobia --> Normal: Trigger removed
state Phobia {
[*] --> Initial
Initial --> Debuff: Apply effects
Debuff --> CheckType: Check phobia type
CheckType --> Fish: Fish phobia
CheckType --> Blood: Blood phobia
CheckType --> Other: Other phobias
}
state Intensified {
[*] --> IncreasedEffects
IncreasedEffects --> MaxDebuff
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have skipped reviewing this pull request. It seems to have been created by a bot (hey, ss220app[bot]!). We assume it knows what it's doing!
This PR causes following conflicts on translate branch: code/modules/antagonists/heretic/influences.dm++<<<<<<< HEAD
+ visible_message(span_userdanger("Psychic tendrils lash out from [src], psychically grabbing onto [user]'s psychically sensitive mind and tearing [user.p_their()] head off!"))
++||||||| afae02264af
++ to_chat(human_user, span_userdanger("Eldritch energy lashes out, piercing your fragile mind, tearing it to pieces!"))
++ human_user.ghostize()
++=======
+ to_chat(human_user, span_userdanger("Миситческая энергия пронзает ваш хрупкий разум, разрывая его на куски!"))
+ human_user.ghostize()
++>>>>>>> origin/translate
tgui/packages/tgui/interfaces/CommunicationsConsole.jsxtgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsxtgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx++<<<<<<< HEAD:tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx
+ const randomizationOfMainFeatures = getRandomization(
+ Object.fromEntries(mainFeatures),
+ serverData,
+ randomBodyEnabled,
++||||||| afae02264af:tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx
++ <Stack height={`${CLOTHING_SIDEBAR_ROWS * CLOTHING_CELL_SIZE}px`}>
++ <Stack.Item>
++ <Stack vertical fill>
++ <Stack.Item>
++ <CharacterControls
++ gender={data.character_preferences.misc.gender}
++ handleOpenSpecies={props.openSpecies}
++ handleRotate={() => {
++ act('rotate');
++ }}
++ setGender={createSetPreference(act, 'gender')}
++ showGender={
++ currentSpeciesData ? !!currentSpeciesData.sexes : true
++ }
++ />
++ </Stack.Item>
+
- {deleteCharacterPopupOpen && (
- <DeleteCharacterPopup
- close={() => setDeleteCharacterPopupOpen(false)}
- />
- )}
++ <Stack.Item grow>
++ <CharacterPreview
++ height="100%"
++ id={data.character_preview_view}
++ />
++ </Stack.Item>
++
++ <Stack.Item position="relative">
++ <NameInput
++ name={data.character_preferences.names[data.name_to_use]}
++ handleUpdateName={createSetPreference(
++ act,
++ data.name_to_use,
++ )}
++ openMultiNameInput={() => {
++ setMultiNameInputOpen(true);
++ }}
++ />
++ </Stack.Item>
++ </Stack>
++ </Stack.Item>
++
++ <Stack.Item width={`${CLOTHING_CELL_SIZE * 2 + 15}px`}>
++ <Stack height="100%" vertical wrap>
++ {mainFeatures.map(([clothingKey, clothing]) => {
++ const catalog =
++ serverData &&
++ (serverData[clothingKey] as FeatureChoicedServerData & {
++ name: string;
++ });
++
++ return (
++ catalog && (
++ <Stack.Item key={clothingKey} mt={0.5} px={0.5}>
++ <MainFeature
++ catalog={catalog}
++ currentValue={clothing}
++ isOpen={currentClothingMenu === clothingKey}
++ handleClose={() => {
++ setCurrentClothingMenu(null);
++ }}
++ handleOpen={() => {
++ setCurrentClothingMenu(clothingKey);
++ }}
++ handleSelect={createSetPreference(act, clothingKey)}
++ randomization={
++ randomizationOfMainFeatures[clothingKey]
++ }
++ setRandomization={createSetRandomization(
++ act,
++ clothingKey,
++ )}
++ />
++ </Stack.Item>
++ )
++ );
++ })}
++ </Stack>
++ </Stack.Item>
+
++ <Stack.Item grow basis={0}>
++ <Stack vertical fill>
++ <PreferenceList
++ act={act}
++ randomizations={getRandomization(
++ contextualPreferences,
++ serverData,
++ randomBodyEnabled,
++ )}
++ preferences={contextualPreferences}
++ maxHeight="auto"
++ />
++
++ <PreferenceList
++ act={act}
++ randomizations={getRandomization(
++ nonContextualPreferences,
++ serverData,
++ randomBodyEnabled,
++ )}
++ preferences={nonContextualPreferences}
++ maxHeight="auto"
++ >
++ <Box my={0.5}>
++ <Button
++ color="red"
++ disabled={
++ Object.values(data.character_profiles).filter(
++ (name) => name,
++ ).length < 2
++ } // check if existing chars more than one
++ onClick={() => setDeleteCharacterPopupOpen(true)}
++ >
++ Delete Character
++ </Button>
++ </Box>
++ </PreferenceList>
++ </Stack>
++ </Stack.Item>
++ </Stack>
++ </>
++ );
++ }}
++ />
++=======
+ <Stack height={`${CLOTHING_SIDEBAR_ROWS * CLOTHING_CELL_SIZE}px`}>
+ <Stack.Item>
+ <Stack vertical fill>
+ <Stack.Item>
+ <CharacterControls
+ gender={data.character_preferences.misc.gender}
+ handleOpenSpecies={props.openSpecies}
+ handleRotate={() => {
+ act('rotate');
+ }}
+ setGender={createSetPreference(act, 'gender')}
+ showGender={
+ currentSpeciesData ? !!currentSpeciesData.sexes : true
+ }
+ />
+ </Stack.Item>
+
+ <Stack.Item grow>
+ <CharacterPreview
+ height="100%"
+ id={data.character_preview_view}
+ />
+ </Stack.Item>
+
+ <Stack.Item position="relative">
+ <NameInput
+ name={data.character_preferences.names[data.name_to_use]}
+ handleUpdateName={createSetPreference(
+ act,
+ data.name_to_use,
+ )}
+ openMultiNameInput={() => {
+ setMultiNameInputOpen(true);
+ }}
+ />
+ </Stack.Item>
+ </Stack>
+ </Stack.Item>
+
+ <Stack.Item width={`${CLOTHING_CELL_SIZE * 2 + 15}px`}>
+ <Stack height="100%" vertical wrap>
+ {mainFeatures.map(([clothingKey, clothing]) => {
+ const catalog =
+ serverData &&
+ (serverData[clothingKey] as FeatureChoicedServerData & {
+ name: string;
+ });
+
+ return (
+ catalog && (
+ <Stack.Item key={clothingKey} mt={0.5} px={0.5}>
+ <MainFeature
+ catalog={catalog}
+ currentValue={clothing}
+ isOpen={currentClothingMenu === clothingKey}
+ handleClose={() => {
+ setCurrentClothingMenu(null);
+ }}
+ handleOpen={() => {
+ setCurrentClothingMenu(clothingKey);
+ }}
+ handleSelect={createSetPreference(act, clothingKey)}
+ randomization={
+ randomizationOfMainFeatures[clothingKey]
+ }
+ setRandomization={createSetRandomization(
+ act,
+ clothingKey,
+ )}
+ />
+ </Stack.Item>
+ )
+ );
+ })}
+ </Stack>
+ </Stack.Item>
+
+ <Stack.Item grow basis={0}>
+ <Stack vertical fill>
+ <PreferenceList
+ act={act}
+ randomizations={getRandomization(
+ contextualPreferences,
+ serverData,
+ randomBodyEnabled,
+ )}
+ preferences={contextualPreferences}
+ maxHeight="auto"
+ />
+
+ <PreferenceList
+ act={act}
+ randomizations={getRandomization(
+ nonContextualPreferences,
+ serverData,
+ randomBodyEnabled,
+ )}
+ preferences={nonContextualPreferences}
+ maxHeight="auto"
+ >
+ <Box my={0.5}>
+ <Button
+ color="red"
+ disabled={
+ Object.values(data.character_profiles).filter(
+ (name) => name,
+ ).length < 2
+ } // check if existing chars more than one
+ onClick={() => setDeleteCharacterPopupOpen(true)}
+ >
+ Удалить персонажа
+ </Button>
+ </Box>
+ </PreferenceList>
+ </Stack>
+ </Stack.Item>
+ </Stack>
+ </>
+ );
+ }}
+ />
++>>>>>>> origin/translate:tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx
tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/QuirksPage.tsx++<<<<<<< HEAD:tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/QuirksPage.tsx
+ act('remove_quirk', { quirk: quirk.name });
+ }}
+ quirks={quirks
+ .filter(([quirkName, _]) => {
+ return selectedQuirks.indexOf(quirkName) !== -1;
+ })
+ .map(([quirkName, quirk]) => {
+ return [
+ quirkName,
+ {
+ ...quirk,
+ failTooltip: getReasonToNotRemove(quirkName),
+ },
+ ];
+ })}
+ serverData={server_data}
+ randomBodyEnabled={randomBodyEnabled}
+ />
+ </Stack.Item>
+ </Stack>
+ </Stack.Item>
+ </Stack>
++||||||| afae02264af:tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx
++ if (quirk.value > 0) {
++ if (
++ maxPositiveQuirks !== -1 &&
++ positiveQuirks >= maxPositiveQuirks
++ ) {
++ return "You can't have any more positive quirks!";
++ } else if (pointsEnabled && balance + quirk.value > 0) {
++ return 'You need a negative quirk to balance this out!';
++ }
+ }
+
- if (selectedQuirk.value > 0) {
- positiveQuirks += 1;
++ const selectedQuirkNames = selectedQuirks.map((quirkKey) => {
++ return quirkInfo[quirkKey].name;
++ });
++
++ for (const blacklist of quirkBlacklist) {
++ if (blacklist.indexOf(quirk.name) === -1) {
++ continue;
++ }
++
++ for (const incompatibleQuirk of blacklist) {
++ if (
++ incompatibleQuirk !== quirk.name &&
++ selectedQuirkNames.indexOf(incompatibleQuirk) !== -1
++ ) {
++ return `This is incompatible with ${incompatibleQuirk}!`;
++ }
++ }
+ }
+
- balance += selectedQuirk.value;
- }
++ return undefined;
++ };
+
- const getReasonToNotAdd = (quirkName: string) => {
++ const getReasonToNotRemove = (quirkName: string) => {
+ const quirk = quirkInfo[quirkName];
+
++ if (pointsEnabled && balance - quirk.value > 0) {
++ return 'You need to remove a positive quirk first!';
++ }
++
++ return undefined;
++ };
++
++ return (
++ <Stack fill>
++ <Stack.Item basis="50%">
++ <Stack vertical fill align="center">
++ <Stack.Item>
++ {maxPositiveQuirks > 0 ? (
++ <Box fontSize="1.3em">Positive Quirks</Box>
++ ) : (
++ <Box mt={pointsEnabled ? 3.4 : 0} />
++ )}
++ </Stack.Item>
++
++ <Stack.Item>
++ {maxPositiveQuirks > 0 ? (
++ <StatDisplay>
++ {positiveQuirks} / {maxPositiveQuirks}
++ </StatDisplay>
++ ) : (
++ <Box mt={pointsEnabled ? 3.4 : 0} />
++ )}
++ </Stack.Item>
++
++ <Stack.Item>
++ <Box as="b" fontSize="1.6em">
++ Available Quirks
++ </Box>
++ </Stack.Item>
++
++ <Stack.Item grow width="100%">
++ <QuirkList
++ selected={false}
++ onClick={(quirkName, quirk) => {
++ if (getReasonToNotAdd(quirkName) !== undefined) {
++ return;
++ }
++
++ setSelectedQuirks(selectedQuirks.concat(quirkName));
++
++ act('give_quirk', { quirk: quirk.name });
++ }}
++ quirks={quirks
++ .filter(([quirkName, _]) => {
++ return selectedQuirks.indexOf(quirkName) === -1;
++ })
++ .map(([quirkName, quirk]) => {
++ return [
++ quirkName,
++ {
++ ...quirk,
++ failTooltip: getReasonToNotAdd(quirkName),
++ },
++ ];
++ })}
++ serverData={server_data}
++ randomBodyEnabled={randomBodyEnabled}
++ />
++ </Stack.Item>
++ </Stack>
++ </Stack.Item>
++
++ <Stack.Item align="center">
++ <Icon name="exchange-alt" size={1.5} ml={2} mr={2} />
++ </Stack.Item>
++
++ <Stack.Item basis="50%">
++ <Stack vertical fill align="center">
++ <Stack.Item>
++ {pointsEnabled ? (
++ <Box fontSize="1.3em">Quirk Balance</Box>
++ ) : (
++ <Box mt={maxPositiveQuirks > 0 ? 3.4 : 0} />
++ )}
++ </Stack.Item>
++
++ <Stack.Item>
++ {pointsEnabled ? (
++ <StatDisplay>{balance}</StatDisplay>
++ ) : (
++ <Box mt={maxPositiveQuirks > 0 ? 3.4 : 0} />
++ )}
++ </Stack.Item>
++
++ <Stack.Item>
++ <Box as="b" fontSize="1.6em">
++ Current Quirks
++ </Box>
++ </Stack.Item>
++
++ <Stack.Item grow width="100%">
++ <QuirkList
++ selected
++ onClick={(quirkName, quirk) => {
++ if (getReasonToNotRemove(quirkName) !== undefined) {
++ return;
++ }
++
++ setSelectedQuirks(
++ selectedQuirks.filter(
++ (otherQuirk) => quirkName !== otherQuirk,
++ ),
++ );
++
++ act('remove_quirk', { quirk: quirk.name });
++ }}
++ quirks={quirks
++ .filter(([quirkName, _]) => {
++ return selectedQuirks.indexOf(quirkName) !== -1;
++ })
++ .map(([quirkName, quirk]) => {
++ return [
++ quirkName,
++ {
++ ...quirk,
++ failTooltip: getReasonToNotRemove(quirkName),
++ },
++ ];
++ })}
++ serverData={server_data}
++ randomBodyEnabled={randomBodyEnabled}
++ />
++ </Stack.Item>
++ </Stack>
++ </Stack.Item>
++ </Stack>
++ );
++ }}
++ />
++=======
+ if (quirk.value > 0) {
+ if (
+ maxPositiveQuirks !== -1 &&
+ positiveQuirks >= maxPositiveQuirks
+ ) {
+ return 'Нельзя иметь больше положительных черт!';
+ } else if (pointsEnabled && balance + quirk.value > 0) {
+ return 'Необходим баланс с отрицательными чертами!';
+ }
+ }
+
+ const selectedQuirkNames = selectedQuirks.map((quirkKey) => {
+ return quirkInfo[quirkKey].name;
+ });
+
+ for (const blacklist of quirkBlacklist) {
+ if (blacklist.indexOf(quirk.name) === -1) {
+ continue;
+ }
+
+ for (const incompatibleQuirk of blacklist) {
+ if (
+ incompatibleQuirk !== quirk.name &&
+ selectedQuirkNames.indexOf(incompatibleQuirk) !== -1
+ ) {
+ return `Черта несовместима с ${incompatibleQuirk}!`;
+ }
+ }
+ }
+
+ return undefined;
+ };
+
+ const getReasonToNotRemove = (quirkName: string) => {
+ const quirk = quirkInfo[quirkName];
+
+ if (pointsEnabled && balance - quirk.value > 0) {
+ return 'Сначала вам нужно убрать позитивную черту!';
+ }
+
+ return undefined;
+ };
+
+ return (
+ <Stack fill>
+ <Stack.Item basis="50%">
+ <Stack vertical fill align="center">
+ <Stack.Item>
+ {maxPositiveQuirks > 0 ? (
+ <Box fontSize="1.3em">Положительные черты</Box>
+ ) : (
+ <Box mt={pointsEnabled ? 3.4 : 0} />
+ )}
+ </Stack.Item>
+
+ <Stack.Item>
+ {maxPositiveQuirks > 0 ? (
+ <StatDisplay>
+ {positiveQuirks} / {maxPositiveQuirks}
+ </StatDisplay>
+ ) : (
+ <Box mt={pointsEnabled ? 3.4 : 0} />
+ )}
+ </Stack.Item>
+
+ <Stack.Item>
+ <Box as="b" fontSize="1.6em">
+ Доступные черты
+ </Box>
+ </Stack.Item>
+
+ <Stack.Item grow width="100%">
+ <QuirkList
+ selected={false}
+ onClick={(quirkName, quirk) => {
+ if (getReasonToNotAdd(quirkName) !== undefined) {
+ return;
+ }
+
+ setSelectedQuirks(selectedQuirks.concat(quirkName));
+
+ act('give_quirk', { quirk: quirk.name });
+ }}
+ quirks={quirks
+ .filter(([quirkName, _]) => {
+ return selectedQuirks.indexOf(quirkName) === -1;
+ })
+ .map(([quirkName, quirk]) => {
+ return [
+ quirkName,
+ {
+ ...quirk,
+ failTooltip: getReasonToNotAdd(quirkName),
+ },
+ ];
+ })}
+ serverData={server_data}
+ randomBodyEnabled={randomBodyEnabled}
+ />
+ </Stack.Item>
+ </Stack>
+ </Stack.Item>
+
+ <Stack.Item align="center">
+ <Icon name="exchange-alt" size={1.5} ml={2} mr={2} />
+ </Stack.Item>
+
+ <Stack.Item basis="50%">
+ <Stack vertical fill align="center">
+ <Stack.Item>
+ {pointsEnabled ? (
+ <Box fontSize="1.3em">Баланс черт</Box>
+ ) : (
+ <Box mt={maxPositiveQuirks > 0 ? 3.4 : 0} />
+ )}
+ </Stack.Item>
+
+ <Stack.Item>
+ {pointsEnabled ? (
+ <StatDisplay>{balance}</StatDisplay>
+ ) : (
+ <Box mt={maxPositiveQuirks > 0 ? 3.4 : 0} />
+ )}
+ </Stack.Item>
+
+ <Stack.Item>
+ <Box as="b" fontSize="1.6em">
+ Текущие черты
+ </Box>
+ </Stack.Item>
+
+ <Stack.Item grow width="100%">
+ <QuirkList
+ selected
+ onClick={(quirkName, quirk) => {
+ if (getReasonToNotRemove(quirkName) !== undefined) {
+ return;
+ }
+
+ setSelectedQuirks(
+ selectedQuirks.filter(
+ (otherQuirk) => quirkName !== otherQuirk,
+ ),
+ );
+
+ act('remove_quirk', { quirk: quirk.name });
+ }}
+ quirks={quirks
+ .filter(([quirkName, _]) => {
+ return selectedQuirks.indexOf(quirkName) !== -1;
+ })
+ .map(([quirkName, quirk]) => {
+ return [
+ quirkName,
+ {
+ ...quirk,
+ failTooltip: getReasonToNotRemove(quirkName),
+ },
+ ];
+ })}
+ serverData={server_data}
+ randomBodyEnabled={randomBodyEnabled}
+ />
+ </Stack.Item>
+ </Stack>
+ </Stack.Item>
+ </Stack>
+ );
+ }}
+ />
++>>>>>>> origin/translate:tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx
tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/SpeciesPage.tsx++<<<<<<< HEAD:tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/SpeciesPage.tsx
+ <Button icon="arrow-left" onClick={props.handleClose}>
+ Go Back
+ </Button>
++||||||| afae02264af:tgui/packages/tgui/interfaces/PreferencesMenu/SpeciesPage.tsx
++ <Button
++ icon="arrow-left"
++ onClick={props.handleClose}
++ content="Go Back"
++ />
++=======
+ <Button icon="arrow-left" onClick={props.handleClose} content="Назад" />
++>>>>>>> origin/translate:tgui/packages/tgui/interfaces/PreferencesMenu/SpeciesPage.tsx
++<<<<<<< HEAD:tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/SpeciesPage.tsx
+ <SpeciesPageInner
+ handleClose={props.closeSpecies}
+ species={serverData.species}
++||||||| afae02264af:tgui/packages/tgui/interfaces/PreferencesMenu/SpeciesPage.tsx
++ <ServerPreferencesFetcher
++ render={(serverData) => {
++ if (serverData) {
++ return (
++ <SpeciesPageInner
++ handleClose={props.closeSpecies}
++ species={serverData.species}
++ />
++ );
++ } else {
++ return <Box>Loading species...</Box>;
++ }
++ }}
++=======
+ <ServerPreferencesFetcher
+ render={(serverData) => {
+ if (serverData) {
+ return (
+ <SpeciesPageInner
+ handleClose={props.closeSpecies}
+ species={serverData.species}
+ />
+ );
+ } else {
+ return <Box>Загрузка видов...</Box>;
+ }
+ }}
++>>>>>>> origin/translate:tgui/packages/tgui/interfaces/PreferencesMenu/SpeciesPage.tsx
tgui/packages/tgui/interfaces/PreferencesMenu/GamePreferenceWindow.tsxtgui/packages/tgui/interfaces/PreferencesMenu/GamePreferences/KeybindingsPage.tsx++<<<<<<< HEAD:tgui/packages/tgui/interfaces/PreferencesMenu/GamePreferences/KeybindingsPage.tsx
+ <Button.Confirm onClick={() => act('reset_all_keybinds')}>
+ Reset all keybindings
+ </Button.Confirm>
++||||||| afae02264af:tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx
++ <Button.Confirm
++ content="Reset all keybindings"
++ onClick={() => act('reset_all_keybinds')}
++ />
++=======
+ <Button.Confirm
+ content="Сбросить все привязки клавиш"
+ onClick={() => act('reset_all_keybinds')}
+ />
++>>>>>>> origin/translate:tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx
tgui/packages/tgui/interfaces/PreferencesMenu/names.tsxtgui/packages/tgui/interfaces/Techweb.jsx |
This pull request merges upstream/master. Resolve possible conflicts manually and make sure all the changes are applied correctly.
Changelog
🆑 tgstation
admin: Добавлена новая функция в Lua-скриптинге, SS13.check_tick, для предотвращения чрезмерной нагрузки в процессе выполнения циклов и подобных операций.
qol: pAI теперь могут отозвать свою кандидатуру в любой момент.
fix: Исправлены некоторые ошибки в интерфейсе malf AI: один синий экран, лишнее двоеточие и проблемы с отображением модулей.
refactor: Cytology Vatbeast теперь basic mobы (более продвинутый ИИ), пожалуйста, сообщайте о любом необычном поведении.
admin: Добавлена роль Space Dragon в бан панель.
balance: Темные волшебники теперь телепортируются при атаке, но с большей вероятностью могут атаковать своих союзников.
qol: Улучшенно визуальное оформление для информации из вербов Who, Adminwho и Show Server Revision.
fix: Исправлена бесконтрольная мультипликация слаймов ксенобиологии, которая могла приводить к появлению сотен этих существ.
add: Добавлена локация outpost 31, айсбокс-руина, а также связанные с ней мобы, мегафауна и лут. Никаких спойлеров — ищите сами.
balance: ИИ теперь могут осматривать(examine) объекты.
fix: Дуллаханы могут осматривать (examine) объекты через свою голову.
qol: Удалено произвольно установленное ограничение в 10 максимальных выделений (highlights) в ТГчате.
fix: Исправлена ошибка, из-за которой одноразовые спектральные инструменты теряли свои способности до завершения "скелетизации" цели.
add: Добавлен очень редкий "жуткий" суффикс для предметов из мифрила и RPG события волшебника.
fix: Объекты с параметром throw_range 0 теперь корректно блокируются бейсбольными битами.
qol: Срывание привязей (tethers) теперь также удаляет их маяки.
qol: Теперь вы можете разрезать привязи, к которым вы прикреплены, даже находясь в движении.
qol: Привязи теперь рвутся при втягивании перчаток или отключении вашего MODsuit.
fix: Исправлены проблемы со "стеканием" привязей.
qol: Палитра действий теперь не исчезает, если у вас есть активные "плавающие" способности. (относится к HUD способностей)
fix: Словесные фобии теперь должны всегда применяться, а не пропускаться.
del: Удален станционный трейт дефицита продукции в торговых автоматах.
fix: Химические реакции теперь могут достигать минимально необходимой температуры/уровня pH.
code: Улучшен код для отладки хим-диспенсера.
balance: Фобии теперь стали чуть менее пагубными, однако их эффекты усиливаются, если вы дольше находитесь вблизи объекта страха.
balance: Карпофобы теперь боятся всех рыб.
del: Фобия еретиков удалена, так как она практически не использовалась.
fix: Stargazer, форма вознесения еретика пути Космоса, снова может корректно управляться.
code: Базовые мобы-питомцы теперь могут нацеливаться на объекты или на объекты и стены, используя две новые стратегии поиска цели.
qol: Эфириалы снова могут питаться вином.
fix: Окно TGUI Say слегка изменено для чистого внешнего вида и более плавной работы.
fix: Меню настроек персонажа было значительно переработано и теперь должно открываться быстрее.
fix: Исправлена опечатка в пути к файлу cavesound3.ogg.
balance: Если вы одновременно обладаете чертами, которые облегчают и затрудняют получение ранений, они будут компенсировать друг друга.
refactor: Заменён алгоритм bubble sort на timsort для списка камер, глобальные proc'и перенесены в
cameranet
датум.add: Отдел снабжения теперь может заказывать боевые патроны для дробовика через вкладку Imports по завышенной цене.
balance: На черном рынке можно заполучить обычные виды дроби, но иногда она может быть сомнительного качества.
balance: Дробь теперь больше сосредоточена на нанесении ранений вместо прямого урона. Пули для дробовика (slugs) теперь имеют большее бронепробитие, но меньший урон.
balance: Дробовик типа "Bulldog" в остальном остался без изменений по части урона, но получил соответствующие вышеуказанные бонусы.
map: Модульная система руины комм-агента на Icebox обновлена.
qol: В меню черт характера добавлена строка поиска.
fix: IED теперь можно создавать, используя трубы, вырванные из земли.
fix: ID глав теперь сохраняют эффект указателя (жирный указатель и тд.), если вставлены в ПДА или отображены в качестве главной карты в бумажнике.
/:cl:
Summary by Sourcery
Update character preferences, quirks, and jobs pages to use server preferences. Add two new fish, the mossglob and babbelfish, to the heretic rift. Add a new AI-uplink brain that allows AIs to control a body with no organic internal organs. Modularize the comms agent ruin on Icebox. Add a search bar to the quirk menu. Allow IEDs to be crafted using pipes ripped from the ground. Fix issues with tethers, xenobio slime multiplication, malf AI screen, and other bugs.
New Features:
Bug Fixes:
Tests: