diff --git a/.editorconfig b/.editorconfig index 72e85029ef6..c07643f1122 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,21 +2,11 @@ root = true [*] -indent_style = tab -end_of_line = lf charset = utf-8 -trim_trailing_whitespace = true +end_of_line = lf +indent_style = space insert_final_newline = true +trim_trailing_whitespace = true -[*.yml] -indent_style = space -indent_size = 2 - -[*.py] -indent_style = space - -[*.md] -trim_trailing_whitespace = false - -[Dockerfile] -indent_style = space +[*.{dm,json,md}] +indent_style = tab diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 230695b02de..7a21c0693ef 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -4,9 +4,9 @@ 2. [Introduction](#introduction) 3. [Getting Started](#getting-started) 4. [Meet the Team](#meet-the-team) - 1. [Headcoder](#headcoder) - 2. [Maintainers](#maintainers) - 3. [Issue Managers](#issue-managers) + 1. [Headcoder](#headcoder) + 2. [Maintainers](#maintainers) + 3. [Issue Managers](#issue-managers) 5. [Development Guides](#development-guides) 6. [Pull Request Process](#pull-request-process) 7. [Good Boy Points](#good-boy-points) @@ -80,13 +80,15 @@ Issue Managers help out the project by labelling bug reports and PRs and closing This should help you understand what you can and can't do with your newfound github permissions. Things you **CAN** do: -* Label issues appropriately -* Close issues when appropriate -* Label PRs, unless you are goofball. + +- Label issues appropriately +- Close issues when appropriate +- Label PRs, unless you are goofball. Things you **CAN'T** do: -* [Close PRs](https://imgur.com/w2RqpX8.png): Only maintainers are allowed to close PRs. Do not hit that button. -* Close issues purely for breaking a template if the same information is contained without it. + +- [Close PRs](https://imgur.com/w2RqpX8.png): Only maintainers are allowed to close PRs. Do not hit that button. +- Close issues purely for breaking a template if the same information is contained without it. For more information reference the [Issue Manager Guide](./guides/ISSUE_MANAGER.md). @@ -99,12 +101,15 @@ Our team is entirely voluntary, as such we extend our thanks to maintainers, iss ## Development Guides #### Writing readable code + [Style guide](./guides/STYLE.md) #### Writing sane code + [Code standards](./guides/STANDARDS.md) #### Writing understandable code + [Autodocumenting code](./guides/AUTODOC.md) #### Misc @@ -124,39 +129,42 @@ Our team is entirely voluntary, as such we extend our thanks to maintainers, iss There is no strict process when it comes to merging pull requests. Pull requests will sometimes take a while before they are looked at by a maintainer; the bigger the change, the more time it will take before they are accepted into the code. Every team member is a volunteer who is giving up their own time to help maintain and contribute, so please be courteous and respectful. Here are some helpful ways to make it easier for you and for the maintainers when making a pull request. -* Make sure your pull request complies to the requirements outlined here +- Make sure your pull request complies to the requirements outlined here -* You are expected to have tested your pull requests if it is anything that would warrant testing. Text only changes, single number balance changes, and similar generally don't need testing, but anything else does. This means by extension web edits are disallowed for larger changes. +- You are expected to have tested your pull requests if it is anything that would warrant testing. Text only changes, single number balance changes, and similar generally don't need testing, but anything else does. This means by extension web edits are disallowed for larger changes. -* You are going to be expected to document all your changes in the pull request. Failing to do so will mean delaying it as we will have to question why you made the change. On the other hand, you can speed up the process by making the pull request readable and easy to understand, with diagrams or before/after data. Should you be optimizing a routine you must provide proof by way of profiling that your changes are faster. +- You are going to be expected to document all your changes in the pull request. Failing to do so will mean delaying it as we will have to question why you made the change. On the other hand, you can speed up the process by making the pull request readable and easy to understand, with diagrams or before/after data. Should you be optimizing a routine you must provide proof by way of profiling that your changes are faster. -* We ask that you use the changelog system to document your player facing changes, which prevents our players from being caught unaware by said changes - you can find more information about this [on this wiki page](http://tgstation13.org/wiki/Guide_to_Changelogs). +- We ask that you use the changelog system to document your player facing changes, which prevents our players from being caught unaware by said changes - you can find more information about this [on this wiki page](http://tgstation13.org/wiki/Guide_to_Changelogs). -* If you are proposing multiple changes, which change many different aspects of the code, you are expected to section them off into different pull requests in order to make it easier to review them and to deny/accept the changes that are deemed acceptable. +- If you are proposing multiple changes, which change many different aspects of the code, you are expected to section them off into different pull requests in order to make it easier to review them and to deny/accept the changes that are deemed acceptable. -* If your pull request is accepted, the code you add no longer belongs exclusively to you but to everyone; everyone is free to work on it, but you are also free to support or object to any changes being made, which will likely hold more weight, as you're the one who added the feature. It is a shame this has to be explicitly said, but there have been cases where this would've saved some trouble. +- If your pull request is accepted, the code you add no longer belongs exclusively to you but to everyone; everyone is free to work on it, but you are also free to support or object to any changes being made, which will likely hold more weight, as you're the one who added the feature. It is a shame this has to be explicitly said, but there have been cases where this would've saved some trouble. -* If your pull request is not finished, you may open it as a draft for potential review. If you open it as a full-fledged PR make sure it is at least testable in a live environment. Pull requests that do not at least meet this requirement will be closed. You may request a maintainer reopen the pull request when you're ready, or make a new one. +- If your pull request is not finished, you may open it as a draft for potential review. If you open it as a full-fledged PR make sure it is at least testable in a live environment. Pull requests that do not at least meet this requirement will be closed. You may request a maintainer reopen the pull request when you're ready, or make a new one. -* While we have no issue helping contributors (and especially new contributors) bring reasonably sized contributions up to standards via the pull request review process, larger contributions are expected to pass a higher bar of completeness and code quality *before* you open a pull request. Maintainers may close such pull requests that are deemed to be substantially flawed. You should take some time to discuss with maintainers or other contributors on how to improve the changes. +- While we have no issue helping contributors (and especially new contributors) bring reasonably sized contributions up to standards via the pull request review process, larger contributions are expected to pass a higher bar of completeness and code quality _before_ you open a pull request. Maintainers may close such pull requests that are deemed to be substantially flawed. You should take some time to discuss with maintainers or other contributors on how to improve the changes. -* After leaving reviews on an open pull request, maintainers may convert it to a draft. Once you have addressed all their comments to the best of your ability, feel free to mark the pull as `Ready for Review` again. +- After leaving reviews on an open pull request, maintainers may convert it to a draft. Once you have addressed all their comments to the best of your ability, feel free to mark the pull as `Ready for Review` again. * **Pull requests that include sprites must have in-game screenshots that were taken on your own test-server in the PR body.** For instance, if you're adding new clothes, a screenshot of those clothes being worn is expected in the PR body. Not every single direction needs to be displayed, but each icon that's actually being used in-game should be showcased. + ## Justifying Your Changes You must explain why you are submitting the pull request in the "Why It's Good For The Game" section of your pull request, and how you think your change will be beneficial to the game. Failure to do so will be grounds for rejecting your pull request wholesale, or requiring that you fix it before your pull request is merged. A reasonable justification for your changes is a requirement. Your "How This Contributes To The Skyrat Roleplay Experience" section must make a good faith and reasonable attempt to: -* Assert and argue that the current state of affairs in the game is not good, and needs changing. -* Assert and argue that your pull request will either fix or help fix the problems you described. -* Assert and argue that any downsides introduced by your solution as a matter of design, if any, are worth it, and why they are worth it. + +- Assert and argue that the current state of affairs in the game is not good, and needs changing. +- Assert and argue that your pull request will either fix or help fix the problems you described. +- Assert and argue that any downsides introduced by your solution as a matter of design, if any, are worth it, and why they are worth it. More controversial changes have higher standards for justification to be considered reasonable. A bugfix for example does not typically require any effort at all in justification as its value to the game is usually self evident, however a major feature overhaul or balance change may require significant explanation to adequately justify its supposed benefit to the game. This is still a requirement if your pull request is supported and/or requested by maintainers before it is opened. This is still a requirement if your pull request is supported and/or requested by head coders before it is opened. The purpose of arguing for your changes is not to convince just the maintainer team of its merits, it is to document the "why" behind your changes to the game to a necessary level of detail. The reason behind a change must exist as it is the purpose of this codebase to improve the game, thus said reasoning must be adequately stated and explained. This is also still a requirement if your pull request has a corresponding design document that justifies your changes inside it. You must always properly justify changes (those that actually need justification) within the pull request, even if you also do it elsewhere. This is to ensure that: + 1. All reviewers can easily see the reasoning behind your changes on the pull request itself, no reliance on other sites required. 2. The actual, manifested implementation of the idea behind the design document is being justified after said implementation is actually realized. This is in contrast to any reasoning put on the design document itself, which very well may have been made before any work was done on it, possibly even by an author different from the author of the pull request. Any idea in the design document may have had compromises put into it due to complications not seen in the original vision, thus the current state of the implementation (the pull request as it stands) must be defended, explained, and ultimately justified in and of itself. Of course, you should still list the design document the pull request is implementing, and may even use arguments from the design document if said arguments are applicable to the current reality of your proposed changes. @@ -183,14 +191,17 @@ Regarding sprites & sounds, you must credit the artist and possibly the codebase Regarding sprites in particular, you still need to take your own screenshots of the sprites in-game on your Bubber-Station code in your PR body, not just re-use the screenshots provided in the original PR. ## Banned content + Do not add any of the following in a Pull Request or risk getting the PR closed: -* National Socialist Party of Germany content, National Socialist Party of Germany related content, or National Socialist Party of Germany references -* Code adding, removing, or updating the availability of alien races/species/human mutants without prior approval. Pull requests attempting to add or remove features from said races/species/mutants require prior approval as well. -* Code which violates GitHub's [terms of service](https://github.com/site/terms). + +- National Socialist Party of Germany content, National Socialist Party of Germany related content, or National Socialist Party of Germany references +- Code adding, removing, or updating the availability of alien races/species/human mutants without prior approval. Pull requests attempting to add or remove features from said races/species/mutants require prior approval as well. +- Code which violates GitHub's [terms of service](https://github.com/site/terms). Just because something isn't on this list doesn't mean that it's acceptable. Use common sense above all else. ## A word on Git + This repository uses `LF` line endings for all code as specified in the **.gitattributes** and **.editorconfig** files. Unless overridden or a non standard git binary is used the line ending settings should be applied to your clone automatically. diff --git a/.github/actions/setup_node/action.yml b/.github/actions/setup_node/action.yml index 120dbf4639b..d017766117f 100644 --- a/.github/actions/setup_node/action.yml +++ b/.github/actions/setup_node/action.yml @@ -5,7 +5,7 @@ description: Install Node using the version specified in `dependencies.sh`; addi inputs: restore-yarn-cache: - description: 'If `true`, restores the Yarn cache alongside installing node.' + description: "If `true`, restores the Yarn cache alongside installing node." required: false type: boolean default: false diff --git a/.github/guides/AUTODOC.md b/.github/guides/AUTODOC.md index fef5d62c668..3e34cdb080d 100644 --- a/.github/guides/AUTODOC.md +++ b/.github/guides/AUTODOC.md @@ -1,8 +1,7 @@ # dmdoc + [DOCUMENTATION]: http://codedocs.tgstation13.org - [BYOND]: https://secure.byond.com/ - [DMDOC]: https://github.com/SpaceManiac/SpacemanDMM/tree/master/crates/dmdoc [DMDOC] is a documentation generator for DreamMaker, the scripting language @@ -16,6 +15,7 @@ This gives new developers a clickable reference [DOCUMENTATION] they can browse gain understanding of the /tg/station codebase structure and api reference. ## Documenting code on /tg/station + We use block comments to document procs and classes, and we use `///` line comments when documenting individual variables. @@ -25,22 +25,24 @@ We also require that when you touch older code, you must document the functions have touched in the process of updating that code ### Required -A class *must* always be autodocumented, and all public functions *must* be documented -All class level defined variables *must* be documented +A class _must_ always be autodocumented, and all public functions _must_ be documented -Internal functions *should* be documented, but may not be +All class level defined variables _must_ be documented + +Internal functions _should_ be documented, but may not be A public function is any function that a developer might reasonably call while using or interacting with your object. Internal functions are helper functions that your public functions rely on to implement logic - ### Documenting a proc + When documenting a proc, we give a short one line description (as this is shown next to the proc definition in the list of all procs for a type or global namespace), then a longer paragraph which will be shown when the user clicks on the proc to jump to its definition + ``` /** * Short description of the proc @@ -54,12 +56,14 @@ the proc to jump to its definition ``` ### Documenting a class + We first give the name of the class as a header, this can be omitted if the name is just going to be the typepath of the class, as dmdoc uses that by default Then we give a short oneline description of the class Finally we give a longer multi paragraph description of the class and its details + ``` /** * # Classname (Can be omitted if it's just going to be the typepath) @@ -74,13 +78,16 @@ Finally we give a longer multi paragraph description of the class and its detail ``` ### Documenting a variable/define + Give a short explanation of what the variable, in the context of the class, or define is. + ``` /// Type path of item to go in suit slot var/suit = null ``` ## Module level description of code + Modules are the best way to describe the structure/intent of a package of code where you don't want to be tied to the formal layout of the class structure. @@ -92,7 +99,9 @@ you would like. [Here is a representative example of what you might write](http://codedocs.tgstation13.org/code/modules/keybindings/readme.html) ## Special variables + You can use certain special template variables in DM DOC comments and they will be expanded + ``` [DEFINE_NAME] - Expands to a link to the define definition if documented [/mob] - Expands to a link to the docs for the /mob class diff --git a/.github/guides/CI.md b/.github/guides/CI.md index d9cb429982d..4ecdfab1b67 100644 --- a/.github/guides/CI.md +++ b/.github/guides/CI.md @@ -1,6 +1,6 @@ # Required Tests (Continuous Integration) -> ℹ️ This is not the documentation for *writing* a test. You can find that in [the unit tests folder](../../code/modules/unit_tests/README.md). +> ℹ️ This is not the documentation for _writing_ a test. You can find that in [the unit tests folder](../../code/modules/unit_tests/README.md). Every pull request runs through a series of checks and tests to ensure its quality. @@ -10,7 +10,7 @@ If after reading this guide you still do not understand why a check suite is fai ## Run Linters -The [linters](https://en.wikipedia.org/wiki/Lint_(software)) check the maps and code for common mistakes. This includes things like: +The [linters]() check the maps and code for common mistakes. This includes things like: - Files not being included in the .dme - Misspelling Nanotrasen as NanoTrasen @@ -32,7 +32,7 @@ Linter failures are usually very easy to fix, and will hopefully be clear from t ## Compile Maps -This checks nothing more than that your code actually compiles, with slightly different requirements. Compile Maps forces all maps (including space ruins etc) to be compiled in, to make sure all of them are valid. If these tests pass, but other tests fail, it means your code *compiles* but not necessarily that it *works*. +This checks nothing more than that your code actually compiles, with slightly different requirements. Compile Maps forces all maps (including space ruins etc) to be compiled in, to make sure all of them are valid. If these tests pass, but other tests fail, it means your code _compiles_ but not necessarily that it _works_. ## Integration Tests @@ -44,7 +44,7 @@ Sometimes a test will fail on only one map, and not the others. This means two t Screenshot tests exist to make sure things look the same before and after your commit. This helps us detect bugs such as humans not properly rendering clothing/limbs. -If your commit *does* change the appearance of something saved in a screenshot test, you will automatically receive a message on your PR showing you the before and after. From here, it will contain instructions for how to resolve the issue, whether it's a bug or intentional. +If your commit _does_ change the appearance of something saved in a screenshot test, you will automatically receive a message on your PR showing you the before and after. From here, it will contain instructions for how to resolve the issue, whether it's a bug or intentional. ## Codeowner Reviews diff --git a/.github/guides/DOWNLOADING.md b/.github/guides/DOWNLOADING.md index 0f518be607b..af9f9a82c42 100644 --- a/.github/guides/DOWNLOADING.md +++ b/.github/guides/DOWNLOADING.md @@ -1,4 +1,5 @@ ## DOWNLOADING + There are a number of ways to download the source code. Some are described here, an alternative all-inclusive guide is also located at https://tgstation13.org/wiki/Downloading_the_source_code Option 1: @@ -11,11 +12,10 @@ hassle if you want to make any changes at all, so it's not recommended.) Option 3: Download a pre-compiled nightly at https://tgstation13.download/nightlies/ (same caveats as option 2) -*Warning: option 4 is out of date, and not maintained, use at your own risk* +_Warning: option 4 is out of date, and not maintained, use at your own risk_ Option 4: Use our docker image that tracks the master branch (See commits for build status. Again, same caveats as option 2) ``` docker run -d -p :1337 -v /path/to/your/config:/tgstation/config -v /path/to/your/data:/tgstation/data tgstation/tgstation ``` - diff --git a/.github/guides/EZDB.md b/.github/guides/EZDB.md index 428a819ab4d..b587da6dcc7 100644 --- a/.github/guides/EZDB.md +++ b/.github/guides/EZDB.md @@ -1,4 +1,5 @@ # Quickly setting up a development database with ezdb + While you do not need a database to code for tgstation, it is a prerequisite to many important features, especially on the admin side. Thus, if you are working in any code that benefits from it, it can be helpful to have one handy. **ezdb** is a tool for quickly setting up an isolated development database. It will manage downloading MariaDB, creating the database, setting it up, and updating it when the code evolves. It is not recommended for use in production servers, but is perfect for quick development. diff --git a/.github/guides/HARDDELETES.md b/.github/guides/HARDDELETES.md index 6817de0d9b3..cc7bf301d7d 100644 --- a/.github/guides/HARDDELETES.md +++ b/.github/guides/HARDDELETES.md @@ -2,9 +2,9 @@ > Garbage collection is pretty gothic when you think about it. > ->An object in code is like a ghost, clinging to its former life, and especially to the people it knew. It can only pass on and truly die when it has dealt with its unfinished business. And only when its been forgotten by everyone who ever knew it. If even one other object remembers it, it has a connection to the living world that lets it keep hanging on +> An object in code is like a ghost, clinging to its former life, and especially to the people it knew. It can only pass on and truly die when it has dealt with its unfinished business. And only when its been forgotten by everyone who ever knew it. If even one other object remembers it, it has a connection to the living world that lets it keep hanging on > ->There is a kind of sombre tone to fixing GC errors too, its almost shamanistic, making sure all these little objects clear up their final affairs in life before they die, to ensure they don't become ghosts +> There is a kind of sombre tone to fixing GC errors too, its almost shamanistic, making sure all these little objects clear up their final affairs in life before they die, to ensure they don't become ghosts > > -- Nanako @@ -16,7 +16,6 @@ 4. [Techniques for fixing hard deletes](#techniques-for-fixing-hard-deletes) 5. [Help my code is erroring how fix](#help-my-code-is-erroring-how-fix) - ## What is Hard Deletion Hard deletion is a very expensive operation that basically clears all references to some "thing" from memory. Objects that undergo this process are referred to as hard deletes, or simply harddels @@ -93,15 +92,15 @@ Now that you know the theory, let's go over what can actually cause hard deletes The BYOND reference has a list [Here](https://secure.byond.com/docs/ref/#/DM/garbage), but it's not a complete one -* Stored in a var -* An item in a list, or associated with a list item -* Has a tag -* Is on the map (always true for turfs) -* Inside another atom's contents -* Inside an atom's vis_contents -* A temporary value in a still-running proc -* Is a mob with a key -* Is an image object attached to an atom +- Stored in a var +- An item in a list, or associated with a list item +- Has a tag +- Is on the map (always true for turfs) +- Inside another atom's contents +- Inside an atom's vis_contents +- A temporary value in a still-running proc +- Is a mob with a key +- Is an image object attached to an atom Let's briefly go over the more painful ones yeah? @@ -284,6 +283,6 @@ If this fails, you're just gonna have to read over this doc. You can skip the th > -- Armhulenn - The reference tracker, while powerful, is incredibly easy to break
-If it weren't for those unit tests we'd still be missing list["a"] = list(ref) + If it weren't for those unit tests we'd still be missing list["a"] = list(ref) - Everyone but me sucks, because everyone but me keeps adding new hard deletes - Garbage collection is a spook, best practice is to use a random reference in place of null, it scares the compiler demons diff --git a/.github/guides/ISSUE_MANAGER.md b/.github/guides/ISSUE_MANAGER.md index 9e5745d7731..d51864b5c13 100644 --- a/.github/guides/ISSUE_MANAGER.md +++ b/.github/guides/ISSUE_MANAGER.md @@ -1,6 +1,6 @@ ## What is an Issue Manager -Issue Managers proactively manage issues for the repo by providing feedback, performing triage, and troubleshooting problems. They search through the codebase to link relevant code, issues, and PRs that help contributors identify and solve an issue. +Issue Managers proactively manage issues for the repo by providing feedback, performing triage, and troubleshooting problems. They search through the codebase to link relevant code, issues, and PRs that help contributors identify and solve an issue. ## Triage An Issue @@ -15,38 +15,41 @@ When examining new issues you should immediately notify a maintainer if you see - **Server Lagging** [[1]](https://github.com/tgstation/tgstation/issues/60193) [[2]](https://github.com/tgstation/tgstation/issues/51927) [[3]](https://github.com/tgstation/tgstation/issues/32762) - Something that is causing a _severe_ amount of lag during the game #### Runtime Issue Reports + If an issue reports a runtime, it must have the actual runtime call stack provided by round logging or in-game debug menu (https://github.com/tgstation/tgstation/issues/70329#issuecomment-1279853883). +
Example runtime call stack - ``` - [2022-10-15 16:12:38.902] runtime error: Cannot execute null.add(). - - proc name: visibility (/datum/cameranet/proc/visibility) - - source file: cameranet.dm,88 - - usr: AI (/mob/living/silicon/ai) - - src: Camera Net (/datum/cameranet) - - usr.loc: the floor (150,25,4) (/turf/open/floor/circuit) - - call stack: - - Camera Net (/datum/cameranet): visibility(/list (/list), null, /list (/list), 1) - - AI (/mob/living/silicon/ai): camera visibility(Inactive AI Eye (/mob/eye/camera/ai)) - - Inactive AI Eye (/mob/eye/camera/ai): setLoc(the floor (150,25,4) (/turf/open/floor/circuit), 0) - - AI (/mob/living/silicon/ai): create eye() - - AI (/mob/living/silicon/ai): Initialize(0, null, TagGamerGame2 (/mob/dead/new_player)) - - Atoms (/datum/controller/subsystem/atoms): InitAtom(AI (/mob/living/silicon/ai), 0, /list (/list)) - - AI (/mob/living/silicon/ai): New(0, null, TagGamerGame2 (/mob/dead/new_player)) - - AI (/mob/living/silicon/ai): New(the floor (150,25,4) (/turf/open/floor/circuit), null, TagGamerGame2 (/mob/dead/new_player)) - - /datum/job/ai (/datum/job/ai): get spawn mob(TagGamerGame2 (/client), AI (/obj/effect/landmark/start/ai)) - - TagGamerGame2 (/mob/dead/new_player): create character(AI (/obj/effect/landmark/start/ai)) - - Ticker (/datum/controller/subsystem/ticker): create characters() - - Ticker (/datum/controller/subsystem/ticker): setup() - - Ticker (/datum/controller/subsystem/ticker): fire(0) - - Ticker (/datum/controller/subsystem/ticker): ignite(0) - ``` +``` +[2022-10-15 16:12:38.902] runtime error: Cannot execute null.add(). +- proc name: visibility (/datum/cameranet/proc/visibility) +- source file: cameranet.dm,88 +- usr: AI (/mob/living/silicon/ai) +- src: Camera Net (/datum/cameranet) +- usr.loc: the floor (150,25,4) (/turf/open/floor/circuit) +- call stack: +- Camera Net (/datum/cameranet): visibility(/list (/list), null, /list (/list), 1) +- AI (/mob/living/silicon/ai): camera visibility(Inactive AI Eye (/mob/eye/camera/ai)) +- Inactive AI Eye (/mob/eye/camera/ai): setLoc(the floor (150,25,4) (/turf/open/floor/circuit), 0) +- AI (/mob/living/silicon/ai): create eye() +- AI (/mob/living/silicon/ai): Initialize(0, null, TagGamerGame2 (/mob/dead/new_player)) +- Atoms (/datum/controller/subsystem/atoms): InitAtom(AI (/mob/living/silicon/ai), 0, /list (/list)) +- AI (/mob/living/silicon/ai): New(0, null, TagGamerGame2 (/mob/dead/new_player)) +- AI (/mob/living/silicon/ai): New(the floor (150,25,4) (/turf/open/floor/circuit), null, TagGamerGame2 (/mob/dead/new_player)) +- /datum/job/ai (/datum/job/ai): get spawn mob(TagGamerGame2 (/client), AI (/obj/effect/landmark/start/ai)) +- TagGamerGame2 (/mob/dead/new_player): create character(AI (/obj/effect/landmark/start/ai)) +- Ticker (/datum/controller/subsystem/ticker): create characters() +- Ticker (/datum/controller/subsystem/ticker): setup() +- Ticker (/datum/controller/subsystem/ticker): fire(0) +- Ticker (/datum/controller/subsystem/ticker): ignite(0) +```
#### Downstream Issues Taken Upstream -If an issue reports a bug encountered at a branch of the codebase or on a downstream server, it __MUST__ have a link to the branch or downstream codebase repo or it is eligible for closing (https://github.com/tgstation/tgstation/issues/70875#issuecomment-1295767891). Reproducing the issue on the compiled master of our codebase is also encouraged. + +If an issue reports a bug encountered at a branch of the codebase or on a downstream server, it **MUST** have a link to the branch or downstream codebase repo or it is eligible for closing (https://github.com/tgstation/tgstation/issues/70875#issuecomment-1295767891). Reproducing the issue on the compiled master of our codebase is also encouraged.
Image macro for your issue marking pleasure @@ -54,19 +57,20 @@ If an issue reports a bug encountered at a branch of the codebase or on a downst ![image](https://user-images.githubusercontent.com/39163353/198381160-f0aa7fc4-4f2d-486f-8b33-44a1965e2ad1.svg) `![image](https://user-images.githubusercontent.com/39163353/198381160-f0aa7fc4-4f2d-486f-8b33-44a1965e2ad1.svg)` +
#### Link Code Snippets -To help triangulate bugs, search the GitHub repo to locate relevant code and attach it to an issue. Do this by creating a [link to the code](https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/creating-a-permanent-link-to-a-code-snippet). This saves the contributors time from having to identify the problem and will be appreciated. +To help triangulate bugs, search the GitHub repo to locate relevant code and attach it to an issue. Do this by creating a [link to the code](https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/creating-a-permanent-link-to-a-code-snippet). This saves the contributors time from having to identify the problem and will be appreciated. #### Use Gitblame -GitHub also has a tool called `gitblame` that is useful in [tracking code](https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#viewing-the-line-by-line-revision-history-for-a-file) to determine who and when someone made a change. This is ideally used to help solve old issues when there is uncertainty over which PR might have fixed it. It is also a good tool to use to link PRs that caused the issue. +GitHub also has a tool called `gitblame` that is useful in [tracking code](https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#viewing-the-line-by-line-revision-history-for-a-file) to determine who and when someone made a change. This is ideally used to help solve old issues when there is uncertainty over which PR might have fixed it. It is also a good tool to use to link PRs that caused the issue. #### Search For Keywords -When a new issue appears search for any keywords involved with the issue. This is important to prune for duplicates, match several issues to a test merge PR, or if you want to link multiple issues together since there is overlapping problems. (but not duplicate) +When a new issue appears search for any keywords involved with the issue. This is important to prune for duplicates, match several issues to a test merge PR, or if you want to link multiple issues together since there is overlapping problems. (but not duplicate) ## Closing Issues @@ -74,10 +78,10 @@ It is recommended to close issues in the following situations: - **Feature Requests** [[1]](https://github.com/tgstation/tgstation/issues/55919) [[2]](https://github.com/tgstation/tgstation/issues/53342) [[3]](https://github.com/tgstation/tgstation/issues/45412) - The issue is a suggestion or request for a new feature to be added to the game. - **Working as Intended** [[1]](https://github.com/tgstation/tgstation/issues/62619) [[2]](https://github.com/tgstation/tgstation/issues/61511) [[3]](https://github.com/tgstation/tgstation/issues/60942) - The issue is detailing a problem that is _specifically intended_ by the code and is not considered a bug. -- **Duplicates** [[1]](https://github.com/tgstation/tgstation/issues/62709) [[2]](https://github.com/tgstation/tgstation/issues/62364) [[3]](https://github.com/tgstation/tgstation/issues/61823) - The issue is detailing an identical problem from another issue. Do not automatically close the most recent issue. Instead compare both and close the one that provides the least information. +- **Duplicates** [[1]](https://github.com/tgstation/tgstation/issues/62709) [[2]](https://github.com/tgstation/tgstation/issues/62364) [[3]](https://github.com/tgstation/tgstation/issues/61823) - The issue is detailing an identical problem from another issue. Do not automatically close the most recent issue. Instead compare both and close the one that provides the least information. - **Removed Features** [[1]](https://github.com/tgstation/tgstation/issues/48255) [[2]](https://github.com/tgstation/tgstation/issues/47194) [[3]](https://github.com/tgstation/tgstation/issues/45653) - The issue is referring to something that was removed from the codebase and no longer exists. -- **Defective Issues** [[1]](https://github.com/tgstation/tgstation/issues/57366) [[2]](https://github.com/tgstation/tgstation/issues/48778) [[3]](https://github.com/tgstation/tgstation/issues/51520) - The issue is badly written and lacking information. Politely ask the person to add more information or rewrite the issue. If there is no response after a sufficient amount of time close the issue. -- **Irreproducible Issues** [[1]](https://github.com/tgstation/tgstation/issues/51493) [[2]](https://github.com/tgstation/tgstation/issues/22796) [[3]](https://github.com/tgstation/tgstation/issues/25610) - The issue is old, cannot be reproduced, and nobody has reported a duplicate issue recently. If you feel _confident_ that the issue has been fixed at some point, list your reasons or link possible PRs that could have fixed it. +- **Defective Issues** [[1]](https://github.com/tgstation/tgstation/issues/57366) [[2]](https://github.com/tgstation/tgstation/issues/48778) [[3]](https://github.com/tgstation/tgstation/issues/51520) - The issue is badly written and lacking information. Politely ask the person to add more information or rewrite the issue. If there is no response after a sufficient amount of time close the issue. +- **Irreproducible Issues** [[1]](https://github.com/tgstation/tgstation/issues/51493) [[2]](https://github.com/tgstation/tgstation/issues/22796) [[3]](https://github.com/tgstation/tgstation/issues/25610) - The issue is old, cannot be reproduced, and nobody has reported a duplicate issue recently. If you feel _confident_ that the issue has been fixed at some point, list your reasons or link possible PRs that could have fixed it. - **Impossible to Fix Issues** [[1]](https://github.com/tgstation/tgstation/issues/524) [[2]](https://github.com/tgstation/tgstation/issues/2679) [[3]](https://github.com/tgstation/tgstation/issues/9637) - The issue is not possible to fix due to either vague details or a clearly defined problem. ## Reopening Issues @@ -88,4 +92,4 @@ In special cases a closed issue should be reopened if: - The initial problem has reappeared (after it was presumably fixed in a PR) - Someone feels that the issue was closed prematurely during discussion -If there is a dispute on whether an issue should remain closed, ask for a second opinion. Get clarification from another Issue Manager or Maintainer and respect their judgement as the final verdict. +If there is a dispute on whether an issue should remain closed, ask for a second opinion. Get clarification from another Issue Manager or Maintainer and respect their judgement as the final verdict. diff --git a/.github/guides/MAPS_AND_AWAY_MISSIONS.md b/.github/guides/MAPS_AND_AWAY_MISSIONS.md index 5cda5ad88dd..74708d51238 100644 --- a/.github/guides/MAPS_AND_AWAY_MISSIONS.md +++ b/.github/guides/MAPS_AND_AWAY_MISSIONS.md @@ -1,16 +1,18 @@ ## MAPS /tg/station currently has six station maps in rotation. -* [Birdshot](https://tgstation13.org/wiki/Birdshot) -* [DeltaStation](https://tgstation13.org/wiki/DeltaStation) -* [IceBoxStation](https://tgstation13.org/wiki/IceboxStation) -* [MetaStation](https://tgstation13.org/wiki/MetaStation) -* [NorthStar](https://tgstation13.org/wiki/The_North_Star) -* [TramStation](https://tgstation13.org/wiki/Tramstation) + +- [Birdshot](https://tgstation13.org/wiki/Birdshot) +- [DeltaStation](https://tgstation13.org/wiki/DeltaStation) +- [IceBoxStation](https://tgstation13.org/wiki/IceboxStation) +- [MetaStation](https://tgstation13.org/wiki/MetaStation) +- [NorthStar](https://tgstation13.org/wiki/The_North_Star) +- [TramStation](https://tgstation13.org/wiki/Tramstation) Debug station maps. -* [RuntimeStation](https://tgstation13.org/wiki/RuntimeStation) -* [MultiZ](https://tgstation13.org/wiki/MultiZ) + +- [RuntimeStation](https://tgstation13.org/wiki/RuntimeStation) +- [MultiZ](https://tgstation13.org/wiki/MultiZ) All maps have their own code file that is in the base of the `_maps` directory, or elsewhere in the codebase. For example, all of the station maps in rotation each have a corresponding JSON file and are loaded using the server's [configuration](#configuration) passed onto the Mapping subsystem. Maps are loaded dynamically when the game starts. Follow this guideline when adding your own map, to your fork, for easy compatibility. @@ -25,8 +27,9 @@ If you are hosting a server, and want randomly picked maps to be played each rou It is absolutely inadvisable to ever use the mapping utility offered by Dream Maker. It is clunky and dated software that will steal your time, patience, and creative desires. Instead, /tg/station map maintainers will always recommend using one of two modern and actively maintained programs. -* [StrongDMM](https://github.com/SpaiR/StrongDMM) (Windows/Linux/MacOS) -* [FastDMM2](https://github.com/monster860/FastDMM2) (Web-based Utility) + +- [StrongDMM](https://github.com/SpaiR/StrongDMM) (Windows/Linux/MacOS) +- [FastDMM2](https://github.com/monster860/FastDMM2) (Web-based Utility) Both of the above programs have native TGM support, which is mandatory for all maps being submitted to this repository. Anytime you want to make changes to a map, it is imperative you use the [Map Merging tools](https://tgstation13.org/wiki/Map_Merger). When you clone your repository onto your machine for mapping, it's always a great idea to run `tools/hooks/Install.bat` at the very start of your mapping endeavors, as this will install Git hooks that help you automatically resolve any merge conflicts that come up while mapping. @@ -38,7 +41,6 @@ UpdatePaths is a scripting tool that will automatically update all instances of As a fast example, let's say you refactor some code, and you've changed the path of `/obj/item/weapon/gun/energy/laser` to `/obj/item/weapon/gun/energy/laser/pistol`. First, you would have to make a new file in the `tools/UpdatePaths/Scripts` [directory](https://github.com/tgstation/tgstation/tree/master/tools/UpdatePaths/Scripts), and name it `PRNUMBER_laser_pistol_split.txt` (with PRNUMBER being the number that your PR is assigned to, for book-keeping purposes). Then, you would have to add the following code to the file: - ```txt /obj/item/weapon/gun/energy/laser : /obj/item/weapon/gun/energy/laser/pistol{@OLD} ``` @@ -59,14 +61,14 @@ Map files for away missions are located in the `_maps/RandomZLevels` directory. A majority of maps (outlined below) must be placed in their corresponding configuration file to allow server operators to enable/disable the map for any reason they desire. Follow the chart to see where you should add your new map. -| Type of Map | Associated File with Link | -| ----------- | ----------- | -| Station Maps | [`config/maps.txt`](https://github.com/tgstation/tgstation/blob/master/config/maps.txt) | -| Space Ruins | [`config/spaceruinblacklist.txt`](https://github.com/tgstation/tgstation/blob/master/config/spaceruinblacklist.txt) | -| Lavaland Ruins | [`config/lavaruinblacklist.txt`](https://github.com/tgstation/tgstation/blob/master/config/lavaruinblacklist.txt) | -| Icemoon Ruins | [`config/iceruinblacklist.txt`](https://github.com/tgstation/tgstation/blob/master/config/iceruinblacklist.txt) | -| Escape Shuttles | [`config/unbuyableshuttles.txt`](https://github.com/tgstation/tgstation/blob/master/config/unbuyableshuttles.txt) | -| Away Missions | [`config/awaymissionconfig.txt`](https://github.com/tgstation/tgstation/blob/master/config/awaymissionconfig.txt) | +| Type of Map | Associated File with Link | +| --------------- | ------------------------------------------------------------------------------------------------------------------- | +| Station Maps | [`config/maps.txt`](https://github.com/tgstation/tgstation/blob/master/config/maps.txt) | +| Space Ruins | [`config/spaceruinblacklist.txt`](https://github.com/tgstation/tgstation/blob/master/config/spaceruinblacklist.txt) | +| Lavaland Ruins | [`config/lavaruinblacklist.txt`](https://github.com/tgstation/tgstation/blob/master/config/lavaruinblacklist.txt) | +| Icemoon Ruins | [`config/iceruinblacklist.txt`](https://github.com/tgstation/tgstation/blob/master/config/iceruinblacklist.txt) | +| Escape Shuttles | [`config/unbuyableshuttles.txt`](https://github.com/tgstation/tgstation/blob/master/config/unbuyableshuttles.txt) | +| Away Missions | [`config/awaymissionconfig.txt`](https://github.com/tgstation/tgstation/blob/master/config/awaymissionconfig.txt) | Each .txt file will have instructions on how to appropriately add your map to the file. If you're unsure about certain values, ask for help during the PR process (or beforehand). diff --git a/.github/guides/MC_tab.md b/.github/guides/MC_tab.md index 01ad1e6aa17..0754083d6b2 100644 --- a/.github/guides/MC_tab.md +++ b/.github/guides/MC_tab.md @@ -4,26 +4,26 @@ If you already know what these numbers mean and you want to see them update fast # Main Entries: - * CPU: What percentage of a tick the game is using before starting the next tick. If this is above 100 it means we are over budget. +- CPU: What percentage of a tick the game is using before starting the next tick. If this is above 100 it means we are over budget. - * TickCount: How many ticks should have elapsed since the start of the game if no ticks were ever delayed from starting. +- TickCount: How many ticks should have elapsed since the start of the game if no ticks were ever delayed from starting. - * TickDrift: How many ticks since the game started that have been delayed. Essentially this is how many ticks the game is running behind. If this is increasing then the game is currently not able to keep up with demand. +- TickDrift: How many ticks since the game started that have been delayed. Essentially this is how many ticks the game is running behind. If this is increasing then the game is currently not able to keep up with demand. - * Internal Tick Usage: You might have heard of this referred to as "maptick". It's how much of the tick that an internal byond function called SendMaps() has taken recently. The higher this is the less time our code has to run. SendMaps() deals with sending players updates of their view of the game world so it has to run every tick but it's expensive so ideally this is optimized as much as possible. You can see a more detailed breakdown of the cost of SendMaps by looking at the profiler in the debug tab -> "Send Maps Profile". +- Internal Tick Usage: You might have heard of this referred to as "maptick". It's how much of the tick that an internal byond function called SendMaps() has taken recently. The higher this is the less time our code has to run. SendMaps() deals with sending players updates of their view of the game world so it has to run every tick but it's expensive so ideally this is optimized as much as possible. You can see a more detailed breakdown of the cost of SendMaps by looking at the profiler in the debug tab -> "Send Maps Profile". # Master Controller Entry: - * TickRate: How many Byond ticks go between each master controller iteration. By default this is 1 meaning the MC runs once every byond tick. But certain configurations can increase this slightly. +- TickRate: How many Byond ticks go between each master controller iteration. By default this is 1 meaning the MC runs once every byond tick. But certain configurations can increase this slightly. - * Iteration: How many times the MC has ran since starting. +- Iteration: How many times the MC has ran since starting. - * TickLimit: This SHOULD be what percentage of the tick the MC can use when it starts a run, however currently it just represents how much of the tick the MC can use by the time that SSstatpanels fires. Someone should fix that. +- TickLimit: This SHOULD be what percentage of the tick the MC can use when it starts a run, however currently it just represents how much of the tick the MC can use by the time that SSstatpanels fires. Someone should fix that. # Subsystem Entries: -Subsystems will typically have a base stat entry of the form: -[ ] Name 12ms|28%(2%)|3 +Subsystems will typically have a base stat entry of the form: +[ ] Name 12ms|28%(2%)|3 The brackets hold a letter if the subsystem is in a state other than idle. @@ -33,4 +33,4 @@ The second numbered entry is like cost, but in percentage of an ideal tick this The third entry (2%) is how much time this subsystem spent executing beyond the time it was allocated by the MC. This is bad, it means that this subsystem doesn't yield when it's taking too much time and makes the job of the MC harder. The MC will attempt to account for this but it is better for all subsystems to be able to correctly yield when their turn is done. -The fourth entry represents how many times this subsystem fires before it completes a run. +The fourth entry represents how many times this subsystem fires before it completes a run. diff --git a/.github/guides/POLICYCONFIG.md b/.github/guides/POLICYCONFIG.md index 9909e7bf626..2b1fce42d15 100644 --- a/.github/guides/POLICYCONFIG.md +++ b/.github/guides/POLICYCONFIG.md @@ -3,9 +3,11 @@ Welcome to this short guide to the POLICY config mechanism. You are probably reading this guide because you have been informed your antagonist or ghost role needs to support policy configuration. ## Requirements + It is a requirement of /tg/station development that all ghost roles, antags, minor antags and event mobs of any kind must support the policy system when implemented. ## What is policy configuration + Policy configuration is a json file that the administrators of a server can edit, which contains a dictionary of keywords -> string message. The policy text for a specific keyword should be displayed when relevant and appropriate, to allow server administrators to define the broad strokes of policy for some feature or mob. @@ -27,9 +29,11 @@ This is also accessible to the user if they use `/client/verb/policy()` which wi ### Relaying Specific Policy To Players, Example Here is a simple example taken from the slime pyroclastic event to relay specific policy. + ```DM var/policy = get_policy(ROLE_PYROCLASTIC_SLIME) if (policy) to_chat(S, policy) ``` + It's recommended to use a define for your policy keyword to make it easily changeable by a developer diff --git a/.github/guides/RUNNING_A_SERVER.md b/.github/guides/RUNNING_A_SERVER.md index d8b6f33e039..84112ffb7d1 100644 --- a/.github/guides/RUNNING_A_SERVER.md +++ b/.github/guides/RUNNING_A_SERVER.md @@ -1,4 +1,5 @@ # INSTALLATION + First-time installation should be fairly straightforward. First, you'll need BYOND installed. You can get it from https://www.byond.com/download. Once you've done that, extract the game files to wherever you want to keep them. This is a @@ -56,7 +57,7 @@ as these store your server configuration, player preferences and banlist. Then, extract the new files (preferably into a clean directory, but updating in place should work fine), copy your /config and /data folders back into the new install, overwriting when prompted except if we've specified otherwise, and -recompile the game. Once you start the server up again, you should be running +recompile the game. Once you start the server up again, you should be running the new version. ## HOSTING @@ -68,15 +69,15 @@ https://github.com/tgstation/tgstation-server If you decide to go this route, here are /tg/ specific details on hosting with TGS. - We have two directories which should be setup in the instance's `Configuration/GameStaticFiles` directory: - - `config` should be where you place your production configuration. Overwrites the default contents of the repo's [config](../../config) directory. - - `data` should be initially created as an empty directory. The game stores persistent data here. + - `config` should be where you place your production configuration. Overwrites the default contents of the repo's [config](../../config) directory. + - `data` should be initially created as an empty directory. The game stores persistent data here. - You should incorporate our [custom build scripts for TGS](../../tools/tgs_scripts) in the instance's `Configuration/EventScripts` directory. These handle including TGUI in the build and setting up rust-g on Linux. - Deployment security level must be set to `Trusted` or it will likely fail due to our native library usage. - We highly recommend using the BYOND version specified in [dependencies.sh](../../dependencies.sh) to avoid potential unrecorded issues. ## SQL SETUP -The SQL backend requires a Mariadb server running 10.2 or later. Mysql is not supported but Mariadb is a drop in replacement for mysql. SQL is required for the library, stats tracking, admin notes, and job-only bans, among other features, mostly related to server administration. Your server details go in /config/dbconfig.txt, and the SQL schema is in /SQL/tgstation_schema.sql and /SQL/tgstation_schema_prefix.sql depending on if you want table prefixes. More detailed setup instructions are located here: https://tgstation13.org/wiki/Downloading_the_source_code#Setting_up_the_database +The SQL backend requires a Mariadb server running 10.2 or later. Mysql is not supported but Mariadb is a drop in replacement for mysql. SQL is required for the library, stats tracking, admin notes, and job-only bans, among other features, mostly related to server administration. Your server details go in /config/dbconfig.txt, and the SQL schema is in /SQL/tgstation_schema.sql and /SQL/tgstation_schema_prefix.sql depending on if you want table prefixes. More detailed setup instructions are located here: https://tgstation13.org/wiki/Downloading_the_source_code#Setting_up_the_database If you are hosting a testing server on windows you can use a standalone version of MariaDB pre load with a blank (but initialized) tgdb database. Find them here: https://tgstation13.download/database/ Just unzip and run for a working (but insecure) database server. Includes a zipped copy of the data folder for easy resetting back to square one. @@ -86,12 +87,13 @@ Web delivery of game resources makes it quicker for players to join and reduces 1. Edit compile_options.dm to set the `PRELOAD_RSC` define to `0` 1. Add a url to config/external_rsc_urls pointing to a .zip file containing the .rsc. - * If you keep up to date with /tg/ you could reuse /tg/'s rsc cdn at http://tgstation13.download/byond/tgstation.zip. Otherwise you can use cdn services like CDN77 or cloudflare (requires adding a page rule to enable caching of the zip), or roll your own cdn using route 53 and vps providers. - * Regardless even offloading the rsc to a website without a CDN will be a massive improvement over the in game system for transferring files. + - If you keep up to date with /tg/ you could reuse /tg/'s rsc cdn at http://tgstation13.download/byond/tgstation.zip. Otherwise you can use cdn services like CDN77 or cloudflare (requires adding a page rule to enable caching of the zip), or roll your own cdn using route 53 and vps providers. + - Regardless even offloading the rsc to a website without a CDN will be a massive improvement over the in game system for transferring files. ### All In One Amazon Web Services Hosting and Content delivery network. + **Important Note** -It is very Importat to note that since AWS is all highly integrated its "easier" than some solutions. However the Price to ***Performance Ratio is terrible***. +It is very Importat to note that since AWS is all highly integrated its "easier" than some solutions. However the Price to **_Performance Ratio is terrible_**. /tg/ Using around 7TB of bandwidth a month. These costs add up. So AWS is probly only a solution for low to mid pop servers @@ -103,16 +105,18 @@ This guide is also assuming you are setting up a production server and not a ser It is highly recommended to reference AWS support documentation while reading this guide. This guide is not a How to AWS. **Required AWS Services** + 1. Elastic Computer 2 (EC2) - * What size and class is up to you but 4GB of RAM is a minimum. + - What size and class is up to you but 4GB of RAM is a minimum. 1. Route53 - * Domain registration and assigning "Elastic" IP addresses to said web addresses + - Domain registration and assigning "Elastic" IP addresses to said web addresses 1. S3 - * This will be your storage point and distrobution point for your .RSC file + - This will be your storage point and distrobution point for your .RSC file 1. Identity and Access Management (IAM) - * Required for EC2 to S3 file transfers + - Required for EC2 to S3 file transfers **Required Software** + 1. Microsoft Windows 1. MariaDB 1. tgstation-server (TGS) @@ -120,30 +124,32 @@ It is highly recommended to reference AWS support documentation while reading th 1. AWS Command Line V2 **Instructions** + 1. After you go through setting up an AWS account you will need to create an IAM role and an IAM user. the IAM user will be made for debug testing. The IAM role will be used as an internal credential for the EC2 instance to talk with S3 - * The role and user creation are almost identical. give them names, select programatic access, then you will click atatych existing policey, Here you can use admin access or S3 full access. both can be found via search. the difference for roles is that you will on the first step declare it for use with EC2 and this one will need full admin access + - The role and user creation are almost identical. give them names, select programatic access, then you will click atatych existing policey, Here you can use admin access or S3 full access. both can be found via search. the difference for roles is that you will on the first step declare it for use with EC2 and this one will need full admin access 1. Create your Amazon EC2 instance. There will be a config option asking for an IAM role. use the IAM role created in the previous step. - * A blank Windows Server is recommended - * You will also need to define a security policey. 3 are recommended. a Remote Desktop Protocol Policey, a Maria DB Policey, and an SS13 policey. the Latter will use the port(s) of your dream demon settings. Make sure the SS13 policey whitelists all IP addresses. + - A blank Windows Server is recommended + - You will also need to define a security policey. 3 are recommended. a Remote Desktop Protocol Policey, a Maria DB Policey, and an SS13 policey. the Latter will use the port(s) of your dream demon settings. Make sure the SS13 policey whitelists all IP addresses. 1. Creat your S3 bucket. this is a very simple process. only thing you need to edit is making the bucket public and making sure its in the same region as your EC2 instance. 1. In the EC2 control panel, go to Elastic IP's. get one and assign it to your EC2 instance. This will result in the server IP address not changing and is required for joining the game via url instead of ip address 1. In Route 53 you will register a domain name. The you will create a hosted zone and tell your domain to use the IP address you used for your EC2 instance. 1. Install the required software - * AWSCL2 you will need to run the configuration using the IAM User you created above. - * TGS: Make sure the scripts from /tools/tgs_scripts are installed per instructions after you have set up your repository and done your first fetch. You will need to Also install a batch file similar to what i have provided into the event scripts folder. You can manually run the batch file to test connection to your S3 bucket. - * Copy `compile_options.dm` into code overrides preserving the directory structure and altering the code as mentioned in the above CDN instructions. - * Filename: DeploymentComplete.bat + - AWSCL2 you will need to run the configuration using the IAM User you created above. + - TGS: Make sure the scripts from /tools/tgs_scripts are installed per instructions after you have set up your repository and done your first fetch. You will need to Also install a batch file similar to what i have provided into the event scripts folder. You can manually run the batch file to test connection to your S3 bucket. + - Copy `compile_options.dm` into code overrides preserving the directory structure and altering the code as mentioned in the above CDN instructions. + - Filename: DeploymentComplete.bat + ```Batch @echo off cd "C:\Program Files\Amazon\AWSCLIV2" aws s3 cp "C:\Instance_Path\Game\Live\tgstation.rsc" s3://BucketName/tgstation.rsc --acl public-read ``` -7. In your TGS's instance's static config files edit resources.txt to point to the resource file uploaded by the batch file. it should resemble `http://BucketName.s3.AWSRegion.amazonaws.com/tgstation.rsc` You can get this url from the S3 object management page after its been uploaded for the first time. *Make sure you do not use use HTTPS. Byond can not do encryption* -7. Tell TGS to fetch and deploy. If everything goes according to plan, your server will be compiled and the resource uploaded automatically to amazon S3. You can verify that by checking on the file your bucket via aws web management. -7. Test your client side connection. - * Tell TGS to run the compiled server - * Attempt to log in. AWS has a stupid fast transfer speed. you should download client side data faster than you can recognize it happened. +7. In your TGS's instance's static config files edit resources.txt to point to the resource file uploaded by the batch file. it should resemble `http://BucketName.s3.AWSRegion.amazonaws.com/tgstation.rsc` You can get this url from the S3 object management page after its been uploaded for the first time. _Make sure you do not use use HTTPS. Byond can not do encryption_ +8. Tell TGS to fetch and deploy. If everything goes according to plan, your server will be compiled and the resource uploaded automatically to amazon S3. You can verify that by checking on the file your bucket via aws web management. +9. Test your client side connection. + - Tell TGS to run the compiled server + - Attempt to log in. AWS has a stupid fast transfer speed. you should download client side data faster than you can recognize it happened. ## IRC BOT SETUP diff --git a/.github/guides/STANDARDS.md b/.github/guides/STANDARDS.md index cdaf630adb6..36a1b0263c2 100644 --- a/.github/guides/STANDARDS.md +++ b/.github/guides/STANDARDS.md @@ -17,41 +17,45 @@ As with the style guide, you are expected to follow these specifications in orde As BYOND's Dream Maker (henceforth "DM") is an object-oriented language, code must be object-oriented when possible in order to be more flexible when adding content to it. If you don't know what "object-oriented" means, we highly recommend you do some light research to grasp the basics. ### Avoid hacky code -Hacky code, such as adding specific checks, is highly discouraged and only allowed when there is ***no*** other option. (Protip: "I couldn't immediately think of a proper way so thus there must be no other option" is not gonna cut it here! If you can't think of anything else, say that outright and admit that you need help with it. Maintainers exist for exactly that reason.) + +Hacky code, such as adding specific checks, is highly discouraged and only allowed when there is **_no_** other option. (Protip: "I couldn't immediately think of a proper way so thus there must be no other option" is not gonna cut it here! If you can't think of anything else, say that outright and admit that you need help with it. Maintainers exist for exactly that reason.) You can avoid hacky code by using object-oriented methodologies, such as overriding a function (called "procs" in DM) or sectioning code into functions and then overriding them as required. ### Develop Secure Code -* Player input must always be escaped safely, we recommend you use stripped_input in all cases where you would use input. Essentially, just always treat input from players as inherently malicious and design with that use case in mind. - * This extends to much further than just numbers or strings. You should always sanity check that an input is valid, especially when it comes to datums or references! - * Input stalling is a very common exploit / bug that involves opening an input window when in a valid state, and triggering the input after exiting the valid state. These can be very serious, and allow players to teleport across the map or remove someone's brain at any given moment. If you check the player must be in a specific context before an input, you should generally check that they are still in the context AFTER the input resolves. - * For example, if you have an item which can be used (in hand) by a player to make it explode, but you want them to confirm (via prompt) that they want it to explode, you should check that the item is still in the player's hands after confirming. Otherwise, they could drop it and explode it at any moment they want. - * Another less common exploit involves allowing a player to open multiple of an input at once. This may allow the player to stack effects, such as triggering 10 explosions when only 1 should be allowed. While a lot of code is generally built in a way making this infeasible (usually due to runtime errors), it is noteworthy regardless. - * You should also consider if it would make sense to apply a timeout to your input, to prevent players from opening it and keeping it on their screen until convenient. +- Player input must always be escaped safely, we recommend you use stripped_input in all cases where you would use input. Essentially, just always treat input from players as inherently malicious and design with that use case in mind. -* SQL queries **must** use parameters for any sort of input data, and `format_table_name` for table names. Directly substituting input into SQL queries is how SQL injections happen, which parameterized queries prevent. - * Good: `SSdbcore.NewQuery({"UPDATE [format_table_name("round")] SET map_name = :map_name WHERE id = :round_id"}, list("map_name" = current_map.map_name, "round_id" = GLOB.round_id))` - * Bad: `SSdbcore.NewQuery({"UPDATE round SET map_name = '[current_map.map_name]' WHERE id = [GLOB.round_id]"}` + - This extends to much further than just numbers or strings. You should always sanity check that an input is valid, especially when it comes to datums or references! + - Input stalling is a very common exploit / bug that involves opening an input window when in a valid state, and triggering the input after exiting the valid state. These can be very serious, and allow players to teleport across the map or remove someone's brain at any given moment. If you check the player must be in a specific context before an input, you should generally check that they are still in the context AFTER the input resolves. + - For example, if you have an item which can be used (in hand) by a player to make it explode, but you want them to confirm (via prompt) that they want it to explode, you should check that the item is still in the player's hands after confirming. Otherwise, they could drop it and explode it at any moment they want. + - Another less common exploit involves allowing a player to open multiple of an input at once. This may allow the player to stack effects, such as triggering 10 explosions when only 1 should be allowed. While a lot of code is generally built in a way making this infeasible (usually due to runtime errors), it is noteworthy regardless. + - You should also consider if it would make sense to apply a timeout to your input, to prevent players from opening it and keeping it on their screen until convenient. -* All calls to topics must be checked for correctness. Topic href calls can be easily faked by clients, so you should ensure that the call is valid for the state the item is in. Do not rely on the UI code to provide only valid topic calls, because it won't. - * Don't expose a topic call to more than what you need it to. If you are only looking for an item inside an atom, don't look for every item in the world - just look in the atom's contents. - * You rarely should call `locate(ref)` without specifying a list! This is a serious exploit vector which can be used to spawn Nar'sie or delete players across the map. Try narrowing it down via a list - such as `locate(ref) in contents`, to find an item in an atom's contents. +- SQL queries **must** use parameters for any sort of input data, and `format_table_name` for table names. Directly substituting input into SQL queries is how SQL injections happen, which parameterized queries prevent. -* Information that players could use to metagame (that is, to identify round information and/or antagonist type via information that would not be available to them in character) should be kept as administrator only. + - Good: `SSdbcore.NewQuery({"UPDATE [format_table_name("round")] SET map_name = :map_name WHERE id = :round_id"}, list("map_name" = current_map.map_name, "round_id" = GLOB.round_id))` + - Bad: `SSdbcore.NewQuery({"UPDATE round SET map_name = '[current_map.map_name]' WHERE id = [GLOB.round_id]"}` -* It is recommended as well you do not expose information about the players - even something as simple as the number of people who have readied up at the start of the round can and has been used to try to identify the round type. +- All calls to topics must be checked for correctness. Topic href calls can be easily faked by clients, so you should ensure that the call is valid for the state the item is in. Do not rely on the UI code to provide only valid topic calls, because it won't. -* Where you have code that can cause large-scale modification and *FUN*, make sure you start it out locked behind one of the default admin roles - use common sense to determine which role fits the level of damage a function could do. + - Don't expose a topic call to more than what you need it to. If you are only looking for an item inside an atom, don't look for every item in the world - just look in the atom's contents. + - You rarely should call `locate(ref)` without specifying a list! This is a serious exploit vector which can be used to spawn Nar'sie or delete players across the map. Try narrowing it down via a list - such as `locate(ref) in contents`, to find an item in an atom's contents. + +- Information that players could use to metagame (that is, to identify round information and/or antagonist type via information that would not be available to them in character) should be kept as administrator only. + +- It is recommended as well you do not expose information about the players - even something as simple as the number of people who have readied up at the start of the round can and has been used to try to identify the round type. + +- Where you have code that can cause large-scale modification and _FUN_, make sure you start it out locked behind one of the default admin roles - use common sense to determine which role fits the level of damage a function could do. ### User Interfaces -* All new player-facing user interfaces must use TGUI, unless they are critical user interfaces. -* All critical user interfaces must be usable with HTML or the interface.dmf, with tgui being *optional* for this UI. - * Examples of critical user interfaces are the chat box, the observe button, the stat panel, and the chat input. -* Documentation for TGUI can be found at: - * [tgui/README.md](../tgui/README.md) - * [tgui/tutorial-and-examples.md](../tgui/docs/tutorial-and-examples.md) +- All new player-facing user interfaces must use TGUI, unless they are critical user interfaces. +- All critical user interfaces must be usable with HTML or the interface.dmf, with tgui being _optional_ for this UI. + - Examples of critical user interfaces are the chat box, the observe button, the stat panel, and the chat input. +- Documentation for TGUI can be found at: + - [tgui/README.md](../tgui/README.md) + - [tgui/tutorial-and-examples.md](../tgui/docs/tutorial-and-examples.md) ### Dont override type safety checks @@ -71,20 +75,22 @@ var/path_type = "/obj/item/baseball_bat" ### Other Notes -* Code should be modular where possible; if you are working on a new addition, then strongly consider putting it in its own file unless it makes sense to put it with similar ones (i.e. a new tool would go in the "tools.dm" file) +- Code should be modular where possible; if you are working on a new addition, then strongly consider putting it in its own file unless it makes sense to put it with similar ones (i.e. a new tool would go in the "tools.dm" file) -* Bloated code may be necessary to add a certain feature, which means there has to be a judgement over whether the feature is worth having or not. You can help make this decision easier by making sure your code is modular. +- Bloated code may be necessary to add a certain feature, which means there has to be a judgement over whether the feature is worth having or not. You can help make this decision easier by making sure your code is modular. -* You are expected to help maintain the code that you add, meaning that if there is a problem then you are likely to be approached in order to fix any issues, runtimes, or bugs. +- You are expected to help maintain the code that you add, meaning that if there is a problem then you are likely to be approached in order to fix any issues, runtimes, or bugs. -* Separating single lines into more readable blocks is not banned, however you should use it only where it makes new information more accessible, or aids maintainability. We do not have a column limit, and mass conversions will not be received well. +- Separating single lines into more readable blocks is not banned, however you should use it only where it makes new information more accessible, or aids maintainability. We do not have a column limit, and mass conversions will not be received well. -* If you used regex to replace code during development of your code, post the regex in your PR for the benefit of future developers and downstream users. +- If you used regex to replace code during development of your code, post the regex in your PR for the benefit of future developers and downstream users. -* Changes to the `/config` tree must be made in a way that allows for updating server deployments while preserving previous behaviour. This is due to the fact that the config tree is to be considered owned by the user and not necessarily updated alongside the remainder of the code. The code to preserve previous behaviour may be removed at some point in the future given the OK by maintainers. +- Changes to the `/config` tree must be made in a way that allows for updating server deployments while preserving previous behaviour. This is due to the fact that the config tree is to be considered owned by the user and not necessarily updated alongside the remainder of the code. The code to preserve previous behaviour may be removed at some point in the future given the OK by maintainers. ## Structural + ### No duplicated code (Don't repeat yourself) + Copying code from one place to another may be suitable for small, short-time projects, but /tg/station is a long-term project and highly discourages this. Instead you can use object orientation, or simply placing repeated code in a function, to obey this specification easily. @@ -96,21 +102,23 @@ While we normally encourage (and in some cases, even require) bringing out of da ### Files -* Because runtime errors do not give the full path, try to avoid having files with the same name across folders. +- Because runtime errors do not give the full path, try to avoid having files with the same name across folders. -* File names should not be mixed case, or contain spaces or any character that would require escaping in a uri. +- File names should not be mixed case, or contain spaces or any character that would require escaping in a uri. -* Files and path accessed and referenced by code above simply being #included should be strictly lowercase to avoid issues on filesystems where case matters. +- Files and path accessed and referenced by code above simply being #included should be strictly lowercase to avoid issues on filesystems where case matters. ### RegisterSignal() #### PROC_REF Macros + When referencing procs in RegisterSignal, Callback and other procs you should use PROC_REF, TYPE_PROC_REF and GLOBAL_PROC_REF macros. They ensure compilation fails if the reffered to procs change names or get removed. The macro to be used depends on how the proc you're in relates to the proc you want to use: PROC_REF if the proc you want to use is defined on the current proc type or any of its ancestor types. Example: + ``` /mob/proc/funny() to_chat(world,"knock knock") @@ -127,6 +135,7 @@ Example: TYPE_PROC_REF if the proc you want to use is defined on a different unrelated type Example: + ``` /obj/thing/proc/funny() to_chat(world,"knock knock") @@ -139,6 +148,7 @@ Example: GLOBAL_PROC_REF if the proc you want to use is a global proc. Example: + ``` /proc/funny() to_chat(world,"knock knock") @@ -152,11 +162,13 @@ Note that the same rules go for verbs too! We have VERB_REF() and TYPE_VERB_REF( #### Signal Handlers All procs that are registered to listen for signals using `RegisterSignal()` must contain at the start of the proc `SIGNAL_HANDLER` eg; + ``` /type/path/proc/signal_callback() SIGNAL_HANDLER // rest of the code ``` + This is to ensure that it is clear the proc handles signals and turns on a lint to ensure it does not sleep. Any sleeping behaviour that you need to perform inside a `SIGNAL_HANDLER` proc must be called asynchronously (e.g. with `INVOKE_ASYNC()`) or be redone to work asynchronously. @@ -174,12 +186,14 @@ If you decide to do this, you should make it clear with a comment explaining why ### Enforcing parent calling When adding new signals to root level procs, eg; + ``` /atom/proc/setDir(newdir) SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir) dir = newdir ``` + The `SHOULD_CALL_PARENT(TRUE)` lint should be added to ensure that overrides/child procs call the parent chain and ensure the signal is sent. ### Avoid unnecessary type checks and obscuring nulls in lists @@ -191,6 +205,7 @@ If we know the list is supposed to only contain the desired type then we want to Nulls in lists tend to point to improperly-handled references, making hard deletes hard to debug. Generating a runtime in those cases is more often than not positive. This is bad: + ```DM var/list/bag_of_atoms = list(new /obj, new /mob, new /atom, new /atom/movable, new /atom/movable) var/highest_alpha = 0 @@ -201,6 +216,7 @@ for(var/atom/thing in bag_of_atoms) ``` This is good: + ```DM var/list/bag_of_atoms = list(new /obj, new /mob, new /atom, new /atom/movable, new /atom/movable) var/highest_alpha = 0 @@ -238,20 +254,21 @@ How do we solve this? By using delta-time. Delta-time is the amount of seconds y health -= health_loss * seconds_per_tick ``` -In the above example, we made our health_loss variable a per second value rather than per process. In the actual process() proc we then make use of deltatime. Because SSmobs runs once every 2 seconds. Delta_time would have a value of 2. This means that by doing health_loss * seconds_per_tick, you end up with the correct amount of health_loss per process, but if for some reason the SSmobs subsystem gets changed to be faster or slower in a PR, your health_loss variable will work the same. +In the above example, we made our health_loss variable a per second value rather than per process. In the actual process() proc we then make use of deltatime. Because SSmobs runs once every 2 seconds. Delta_time would have a value of 2. This means that by doing health_loss \* seconds_per_tick, you end up with the correct amount of health_loss per process, but if for some reason the SSmobs subsystem gets changed to be faster or slower in a PR, your health_loss variable will work the same. For example, if SSmobs is set to run once every 4 seconds, it would call process once every 4 seconds and multiply your health_loss var by 4 before subtracting it. Ensuring that your code is frame independent. ## Optimization + ### Startup/Runtime tradeoffs with lists and the "hidden" init proc First, read the comments in [this BYOND thread](http://www.byond.com/forum/?post=2086980&page=2#comment19776775), starting where the link takes you. There are two key points here: -1) Defining a list in the variable's definition calls a hidden proc - init. If you have to define a list at startup, do so in New() (or preferably Initialize()) and avoid the overhead of a second call (Init() and then New()) +1. Defining a list in the variable's definition calls a hidden proc - init. If you have to define a list at startup, do so in New() (or preferably Initialize()) and avoid the overhead of a second call (Init() and then New()) -2) It also consumes more memory to the point where the list is actually required, even if the object in question may never use it! +2. It also consumes more memory to the point where the list is actually required, even if the object in question may never use it! Remember: although this tradeoff makes sense in many cases, it doesn't cover them all. Think carefully about your addition before deciding if you need to use it. @@ -261,8 +278,8 @@ BYOND will allow you to use a raw icon file or even an icon datum for underlays, Converting them yourself to appearances and storing this converted value will ensure this process only has to happen once for the lifetime of the round. Helper functions exist to do most of the work for you. - Bad: + ```dm /obj/machine/update_overlays(blah) if (stat & broken) @@ -275,6 +292,7 @@ Bad: ``` Good: + ```dm /obj/machine/update_overlays(var/blah) var/static/on_overlay @@ -296,13 +314,12 @@ Good: Note: images are appearances with extra steps, and don't incur the overhead in conversion. - ### Do not abuse associated lists. Associated lists that could instead be variables or statically defined number indexed lists will use more memory, as associated lists have a 24 bytes per item overhead (vs 8 for lists and most vars), and are slower to search compared to static/global variables and lists with known indexes. - Bad: + ```dm /obj/machine/update_overlays(var/blah) var/static/our_overlays @@ -315,6 +332,7 @@ Bad: ``` Good: + ```dm #define OUR_ON_OVERLAY 1 #define OUR_OFF_OVERLAY 2 @@ -333,9 +351,11 @@ Good: #undef OUR_OFF_OVERLAY #undef OUR_BROKEN_OVERLAY ``` + Storing these in a flat (non-associated) list saves on memory, and using defines to reference locations in the list saves CPU time searching the list. Also good: + ```dm /obj/machine/update_overlays(var/blah) var/static/on_overlay @@ -350,6 +370,7 @@ Also good: return ... ``` + Proc variables, static variables, and global variables are resolved at compile time, so the above is equivalent to the second example, but is easier to read, and avoids the need to store a list. Note: While there has historically been a strong impulse to use associated lists for caching of computed values, this is the easy way out and leaves a lot of hidden overhead. Please keep this in mind when designing core/root systems that are intended for use by other code/coders. It's normally better for consumers of such systems to handle their own caching using vars and number indexed lists, than for you to do it using associated lists. @@ -359,6 +380,7 @@ Note: While there has historically been a strong impulse to use associated lists Like all languages, Dream Maker has its quirks, some of them are beneficial to us, some are harmful. ### Loops + #### In-To for-loops `for(var/i = 1, i <= some_value, i++)` is a fairly standard way to write an incremental for loop in most languages (especially those in the C family), but DM's `for(var/i in 1 to some_value)` syntax is oddly faster than its implementation of the former syntax; where possible, it's advised to use DM's syntax. (Note, the `to` keyword is inclusive, so it automatically defaults to replacing `<=`; if you want `<` then you should write it as `1 to some_value-1`). @@ -427,7 +449,7 @@ Because of these problems, it is encouraged to prefer standard, explicit return #### Exception: `. = ..()` -As hinted at before, `. = ..()` is *extremely* common. This will call the parent function, and preserve its return type. Code like this: +As hinted at before, `. = ..()` is _extremely_ common. This will call the parent function, and preserve its return type. Code like this: ```dm /obj/item/spoon/attack() @@ -435,7 +457,7 @@ As hinted at before, `. = ..()` is *extremely* common. This will call the parent visible_message("Whack!") ``` -...is completely accepted, and in fact, usually *prefered* over: +...is completely accepted, and in fact, usually _prefered_ over: ```dm /obj/item/spoon/attack() @@ -458,7 +480,7 @@ One unique property of DM is the ability for procs to error, but for code to con to_chat(world, "2") ``` -...would print both 1 *and* 2, which may be unexpected if you come from other languages. +...would print both 1 _and_ 2, which may be unexpected if you come from other languages. This is where `.` provides a new useful behavior--**a proc that runtimes will return `.`**. @@ -511,12 +533,12 @@ The way they pull this off, while fine for the language itself, makes a mess of The following is a list of procs, and their safe replacements. -* Removing something from the loop `walk(0)` -> `SSmove_manager.stop_looping()` -* Move in a direction `walk()` -> `SSmove_manager.move()` -* Move towards a thing, taking turf density into account`walk_to()` -> `SSmove_manager.move_to()` -* Move in a thing's direction, ignoring turf density `walk_towards()` -> `SSmove_manager.home_onto()` and `SSmove_manager.move_towards_legacy()`, check the documentation to see which you like better -* Move away from something, taking turf density into account `walk_away()` -> `SSmove_manager.move_away()` -* Move to a random place nearby. NOT random walk `walk_rand()` -> `SSmove_manager.move_rand()` is random walk, `SSmove_manager.move_to_rand()` is walk to a random place +- Removing something from the loop `walk(0)` -> `SSmove_manager.stop_looping()` +- Move in a direction `walk()` -> `SSmove_manager.move()` +- Move towards a thing, taking turf density into account`walk_to()` -> `SSmove_manager.move_to()` +- Move in a thing's direction, ignoring turf density `walk_towards()` -> `SSmove_manager.home_onto()` and `SSmove_manager.move_towards_legacy()`, check the documentation to see which you like better +- Move away from something, taking turf density into account `walk_away()` -> `SSmove_manager.move_away()` +- Move to a random place nearby. NOT random walk `walk_rand()` -> `SSmove_manager.move_rand()` is random walk, `SSmove_manager.move_to_rand()` is walk to a random place ### Avoid pointer use @@ -537,6 +559,7 @@ world << pointed_at // outputs "text a THIRD TIME" ``` The problem with this is twofold. + - First: if you use a pointer to reference a var on a datum, it is essentially as if you held an invisible reference to that datum. This risks hard deletes in very unclear ways that cannot be tested for. - Second: People don't like, understand how pointers work? They mix them up with classical C pointers, when they're more like `std::shared_ptr`. This leads to code that just doesn't work properly, or is hard to follow without first getting your mind around it. It also risks hiding what code does in dumb ways because pointers don't have unique types. @@ -553,18 +576,18 @@ Due to how they are internally represented as part of appearance, overlays and u ## SQL -* Do not use the shorthand sql insert format (where no column names are specified) because it unnecessarily breaks all queries on minor column changes and prevents using these tables for tracking outside related info such as in a connected site/forum. +- Do not use the shorthand sql insert format (where no column names are specified) because it unnecessarily breaks all queries on minor column changes and prevents using these tables for tracking outside related info such as in a connected site/forum. -* All changes to the database's layout(schema) must be specified in the database changelog in SQL, as well as reflected in the schema files +- All changes to the database's layout(schema) must be specified in the database changelog in SQL, as well as reflected in the schema files -* Any time the schema is changed the `schema_revision` table and `DB_MAJOR_VERSION` or `DB_MINOR_VERSION` defines must be incremented. +- Any time the schema is changed the `schema_revision` table and `DB_MAJOR_VERSION` or `DB_MINOR_VERSION` defines must be incremented. -* Queries must never specify the database, be it in code, or in text files in the repo. +- Queries must never specify the database, be it in code, or in text files in the repo. -* Primary keys are inherently immutable and you must never do anything to change the primary key of a row or entity. This includes preserving auto increment numbers of rows when copying data to a table in a conversion script. No amount of bitching about gaps in ids or out of order ids will save you from this policy. +- Primary keys are inherently immutable and you must never do anything to change the primary key of a row or entity. This includes preserving auto increment numbers of rows when copying data to a table in a conversion script. No amount of bitching about gaps in ids or out of order ids will save you from this policy. -* The ttl for data from the database is 10 seconds. You must have a compelling reason to store and reuse data for longer then this. +- The ttl for data from the database is 10 seconds. You must have a compelling reason to store and reuse data for longer then this. -* Do not write stored and transformed data to the database, instead, apply the transformation to the data in the database directly. - * ie: SELECTing a number from the database, doubling it, then updating the database with the doubled number. If the data in the database changed between step 1 and 3, you'll get an incorrect result. Instead, directly double it in the update query. `UPDATE table SET num = num*2` instead of `UPDATE table SET num = [num]`. - * if the transformation is user provided (such as allowing a user to edit a string), you should confirm the value being updated did not change in the database in the intervening time before writing the new user provided data by checking the old value with the current value in the database, and if it has changed, allow the user to decide what to do next. +- Do not write stored and transformed data to the database, instead, apply the transformation to the data in the database directly. + - ie: SELECTing a number from the database, doubling it, then updating the database with the doubled number. If the data in the database changed between step 1 and 3, you'll get an incorrect result. Instead, directly double it in the update query. `UPDATE table SET num = num*2` instead of `UPDATE table SET num = [num]`. + - if the transformation is user provided (such as allowing a user to edit a string), you should confirm the value being updated did not change in the database in the intervening time before writing the new user provided data by checking the old value with the current value in the database, and if it has changed, allow the user to decide what to do next. diff --git a/.github/guides/STYLE.md b/.github/guides/STYLE.md index 349933f38bf..51a22ec6535 100644 --- a/.github/guides/STYLE.md +++ b/.github/guides/STYLE.md @@ -1,4 +1,5 @@ # Style Guide + This is the style you must follow when writing code. It's important to note that large parts of the codebase do not consistently follow these rules, but this does not free you of the requirement to follow them. 1. [General Guidelines](#general-guidelines) @@ -11,6 +12,7 @@ This is the style you must follow when writing code. It's important to note that ## General Guidelines ### Tabs, not spaces + You must use tabs to indent your code, NOT SPACES. Do not use tabs/spaces for indentation in the middle of a code line. Not only is this inconsistent because the size of a tab is undefined, but it means that, should the line you're aligning to change size at all, we have to adjust a ton of other code. Plus, it often time hurts readability. @@ -28,40 +30,46 @@ Do not use tabs/spaces for indentation in the middle of a code line. Not only is ``` ### Control statements + (if, while, for, etc) -* No control statement may contain code on the same line as the statement (`if (blah) return`) -* All control statements comparing a variable to a number should use the formula of `thing` `operator` `number`, not the reverse (eg: `if (count <= 10)` not `if (10 >= count)`) +- No control statement may contain code on the same line as the statement (`if (blah) return`) +- All control statements comparing a variable to a number should use the formula of `thing` `operator` `number`, not the reverse (eg: `if (count <= 10)` not `if (10 >= count)`) ### Operators -#### Spacing -* Operators that should be separated by spaces - * Boolean and logic operators like &&, || <, >, ==, etc (but not !) - * Bitwise AND & - * Argument separator operators like , (and ; when used in a forloop) - * Assignment operators like = or += or the like -* Operators that should not be separated by spaces - * Bitwise OR | - * Access operators like . and : - * Parentheses () - * logical not ! -Math operators like +, -, /, *, etc are up in the air, just choose which version looks more readable. +#### Spacing + +- Operators that should be separated by spaces + - Boolean and logic operators like &&, || <, >, ==, etc (but not !) + - Bitwise AND & + - Argument separator operators like , (and ; when used in a forloop) + - Assignment operators like = or += or the like +- Operators that should not be separated by spaces + - Bitwise OR | + - Access operators like . and : + - Parentheses () + - logical not ! + +Math operators like +, -, /, \*, etc are up in the air, just choose which version looks more readable. #### Use -* Bitwise AND - '&' - * Should be written as `variable & CONSTANT` NEVER `CONSTANT & variable`. Both are valid, but the latter is confusing and nonstandard. -* Associated lists declarations must have their key value quoted if it's a string - * WRONG: `list(a = "b")` - * RIGHT: `list("a" = "b")` + +- Bitwise AND - '&' + - Should be written as `variable & CONSTANT` NEVER `CONSTANT & variable`. Both are valid, but the latter is confusing and nonstandard. +- Associated lists declarations must have their key value quoted if it's a string + - WRONG: `list(a = "b")` + - RIGHT: `list("a" = "b")` ### Use static instead of global + DM has a var keyword, called global. This var keyword is for vars inside of types. For instance: ```DM /mob var/global/thing = TRUE ``` + This does NOT mean that you can access it everywhere like a global var. Instead, it means that that var will only exist once for all instances of its type, in this case that var will only exist once for all mobs - it's shared across everything in its type. (Much more like the keyword `static` in other languages like PHP/C++/C#/Java) Isn't that confusing? @@ -69,17 +77,21 @@ Isn't that confusing? There is also an undocumented keyword called `static` that has the same behaviour as global but more correctly describes BYOND's behaviour. Therefore, we always use static instead of global where we need it, as it reduces suprise when reading BYOND code. ### Use early returns + Do not enclose a proc in an if-block when returning on a condition is more feasible This is bad: -````DM + +```DM /datum/datum1/proc/proc1() if (thing1) if (!thing2) if (thing3 == 30) do stuff -```` +``` + This is good: -````DM + +```DM /datum/datum1/proc/proc1() if (!thing1) return @@ -88,21 +100,26 @@ This is good: if (thing3 != 30) return do stuff -```` +``` + This prevents nesting levels from getting deeper then they need to be. ### No magic numbers or strings + This means stuff like having a "mode" variable for an object set to "1" or "2" with no clear indicator of what that means. Make these #defines with a name that more clearly states what it's for. For instance: -````DM + +```DM /datum/proc/do_the_thing(thing_to_do) switch(thing_to_do) if(1) (...) if(2) (...) -```` +``` + There's no indication of what "1" and "2" mean! Instead, you'd do something like this: -````DM + +```DM #define DO_THE_THING_REALLY_HARD 1 #define DO_THE_THING_EFFICIENTLY 2 /datum/proc/do_the_thing(thing_to_do) @@ -111,7 +128,8 @@ There's no indication of what "1" and "2" mean! Instead, you'd do something like (...) if(DO_THE_THING_EFFICIENTLY) (...) -```` +``` + This is clearer and enhances readability of your code! Get used to doing it! ### Use our time defines @@ -119,26 +137,31 @@ This is clearer and enhances readability of your code! Get used to doing it! The codebase contains some defines which will automatically multiply a number by the correct amount to get a number in deciseconds. Using these is preffered over using a literal amount in deciseconds. The defines are as follows: -* SECONDS -* MINUTES -* HOURS + +- SECONDS +- MINUTES +- HOURS This is bad: -````DM + +```DM /datum/datum1/proc/proc1() if(do_after(mob, 15)) mob.dothing() -```` +``` This is good: -````DM + +```DM /datum/datum1/proc/proc1() if(do_after(mob, 1.5 SECONDS)) mob.dothing() -```` +``` ## Paths and Inheritence + ### All BYOND paths must contain the full path + (i.e. absolute pathing) DM will allow you nest almost any type keyword into a block, such as: @@ -195,26 +218,33 @@ The previous code made compliant: ``` ### Type paths must begin with a `/` + eg: `/datum/thing`, not `datum/thing` ### Type paths must be snake case + eg: `/datum/blue_bird`, not `/datum/BLUEBIRD` or `/datum/BlueBird` or `/datum/Bluebird` or `/datum/blueBird` ### Datum type paths must began with "datum" + In DM, this is optional, but omitting it makes finding definitions harder. ## Variables ### Use `var/name` format when declaring variables + While DM allows other ways of declaring variables, this one should be used for consistency. ### Use descriptive and obvious names + Optimize for readability, not writability. While it is certainly easier to write `M` than `victim`, it will cause issues down the line for other developers to figure out what exactly your code is doing, even if you think the variable's purpose is obvious. #### Any variable or argument that holds time and uses a unit of time other than decisecond must include the unit of time in the name. + For example, a proc argument named `delta_time` that marks the seconds between fires could confuse somebody who assumes it stores deciseconds. Naming it `delta_time_seconds` makes this clearer, naming it `seconds_per_tick` makes its purpose even clearer. ### Don't use abbreviations + Avoid variables like C, M, and H. Prefer names like "user", "victim", "weapon", etc. ```dm @@ -226,10 +256,12 @@ Avoid variables like C, M, and H. Prefer names like "user", "victim", "weapon", /proc/use_item(mob/user, atom/target) ``` -Unless it is otherwise obvious, try to avoid just extending variables like "C" to "carbon"--this is slightly more helpful, but does not describe the *context* of the use of the variable. +Unless it is otherwise obvious, try to avoid just extending variables like "C" to "carbon"--this is slightly more helpful, but does not describe the _context_ of the use of the variable. ### Naming things when typecasting + When typecasting, keep your names descriptive: + ```dm var/mob/living/living_target = target var/mob/living/carbon/carbon_target = living_target @@ -238,6 +270,7 @@ var/mob/living/carbon/carbon_target = living_target Of course, if you have a variable name that better describes the situation when typecasting, feel free to use it. Note that it's okay, semantically, to use the same variable name as the type, e.g.: + ```dm var/atom/atom var/client/client @@ -254,15 +287,17 @@ client << browse(...) ``` ### Name things as directly as possible + `was_called` is better than `has_been_called`. `notify` is better than `do_notification`. ### Avoid negative variable names + `is_flying` is better than `is_not_flying`. `late` is better than `not_on_time`. This prevents double-negatives (such as `if (!is_not_flying)` which can make complex checks more difficult to parse. ### Exceptions to variable names -Exceptions can be made in the case of inheriting existing procs, as it makes it so you can use named parameters, but *new* variable names must follow these standards. It is also welcome, and encouraged, to refactor existing procs to use clearer variable names. +Exceptions can be made in the case of inheriting existing procs, as it makes it so you can use named parameters, but _new_ variable names must follow these standards. It is also welcome, and encouraged, to refactor existing procs to use clearer variable names. Naming numeral iterator variables `i` is also allowed, but do remember to [Avoid unnecessary type checks and obscuring nulls in lists](./STANDARDS.md#avoid-unnecessary-type-checks-and-obscuring-nulls-in-lists), and making more descriptive variables is always encouraged. @@ -284,7 +319,8 @@ for (var/i in reagents) ``` ### Don't abuse the increment/decrement operators -`x++` and `++x` both will increment x, but the former will return x *before* it was incremented, while the latter will return x *after* it was incremented. Great if you want to be clever, or if you were a C programmer in the 70s, but it hurts the readability of code to anyone who isn't familiar with this. The convenience is not nearly good enough to justify this burden. + +`x++` and `++x` both will increment x, but the former will return x _before_ it was incremented, while the latter will return x _after_ it was incremented. Great if you want to be clever, or if you were a C programmer in the 70s, but it hurts the readability of code to anyone who isn't familiar with this. The convenience is not nearly good enough to justify this burden. ```dm // Bad @@ -304,6 +340,7 @@ apples-- ``` ### initial() versus :: + `::` is a compile time scope operator which we use as an alternative to `initial()`. It's used within the definition of a datum as opposed to `Initialize` or other procs. @@ -323,6 +360,7 @@ It's used within the definition of a datum as opposed to `Initialize` or other p ``` Another good use for it easy access of the parent's variables. + ```dm /obj/item/fork/dangerous damage = parent_type::damage * 2 @@ -333,34 +371,37 @@ Another good use for it easy access of the parent's variables. flags_1 = parent_type::flags_1 | FLAG_COOLER ``` - It's important to note that `::` does not apply to every application of `initial()`. Primarily in cases where the type you're using for the initial value is not static. For example, + ```dm /proc/cmp_subsystem_init(datum/controller/subsystem/a, datum/controller/subsystem/b) return initial(b.init_order) - initial(a.init_order) ``` + could not use `::` as the provided types are not static. ## Procs ### Getters and setters -* Avoid getter procs. They are useful tools in languages with that properly enforce variable privacy and encapsulation, but DM is not one of them. The upfront cost in proc overhead is met with no benefits, and it may tempt to develop worse code. +- Avoid getter procs. They are useful tools in languages with that properly enforce variable privacy and encapsulation, but DM is not one of them. The upfront cost in proc overhead is met with no benefits, and it may tempt to develop worse code. This is bad: + ```DM /datum/datum1/proc/simple_getter() return gotten_variable ``` + Prefer to either access the variable directly or use a macro/define. - -* Make usage of variables or traits, set up through condition setters, for a more maintainable alternative to compex and redefined getters. +- Make usage of variables or traits, set up through condition setters, for a more maintainable alternative to compex and redefined getters. These are bad: + ```DM /datum/datum1/proc/complex_getter() return condition ? VALUE_A : VALUE_B @@ -370,6 +411,7 @@ These are bad: ``` This is good: + ```DM /datum/datum1 var/getter_turned_into_variable @@ -388,9 +430,11 @@ This is good: ``` ### When passing vars through New() or Initialize()'s arguments, use src.var + Using src.var + naming the arguments the same as the var is the most readable and intuitive way to pass arguments into a new instance's vars. The main benefit is that you do not need to give arguments odd names with prefixes and suffixes that are easily forgotten in `new()` when sending named args. This is very bad: + ```DM /atom/thing var/is_red @@ -405,6 +449,7 @@ This is very bad: Future coders using this code will have to remember two differently named variables which are near-synonyms of eachother. One of them is only used in Initialize for one line. This is bad: + ```DM /atom/thing var/is_red @@ -416,9 +461,10 @@ This is bad: new /atom/thing(null, _is_red = TRUE) ``` -`_is_red` is being used to set `is_red` and yet means a random '_' needs to be appended to the front of the arg, same as all other args like this. +`_is_red` is being used to set `is_red` and yet means a random '\_' needs to be appended to the front of the arg, same as all other args like this. This is good: + ```DM /atom/thing var/is_red @@ -477,6 +523,7 @@ proc_call_on_one_line( ``` For example: + ```dm /area/town var/list/places_to_visit = list( @@ -527,6 +574,7 @@ Macros are, in essence, direct copy and pastes into the code. They are one of th This section will assume you understand the following concepts: ### Language - Hygienic + We say a macro is [**hygienic**](https://en.wikipedia.org/wiki/Hygienic_macro) if, generally, it does not rely on input not given to it directly through the call site, and does not affect the call site outside of it in a way that could not be easily reused somewhere else. An example of a non-hygienic macro is: @@ -545,14 +593,17 @@ Here are two examples of non-hygienic macros, because it affects its call site: ``` ### Language - Side effects/Pure -We say something has [**side effects**](https://en.wikipedia.org/wiki/Side_effect_(computer_science)) if it mutates anything outside of itself. We say something is **pure** if it does not. + +We say something has [**side effects**]() if it mutates anything outside of itself. We say something is **pure** if it does not. For example, this has no side effects, and is pure: + ```dm #define MOTH_MAX_HEALTH 500 ``` This, however, performs a side effect of updating the health: + ```dm #define MOTH_SET_HEALTH(moth, new_health) ##moth.set_health(##new_health) ``` @@ -560,9 +611,11 @@ This, however, performs a side effect of updating the health: Now that you're caught up on the terms, let's get into the guidelines. ### Naming + With little exception, macros should be SCREAMING_SNAKE_CASE. ### Put macro segments inside parentheses where possible. + This will save you from bugs down the line with operator precedence. For example, the following macro: @@ -602,7 +655,7 @@ Consider the previously mentioned non-hygienic macro: #define GET_HEALTH(health_percent) ((##health_percent) * max_health) ``` -This relies on "max_health", but it is not obviously clear what the source is. This will also become worse if we *do* want to change where we get the source from. This would be preferential as: +This relies on "max*health", but it is not obviously clear what the source is. This will also become worse if we \_do* want to change where we get the source from. This would be preferential as: ```dm #define GET_HEALTH(source, health_percent) ((##health_percent) * (##source).max_health) @@ -757,7 +810,7 @@ Because of how common using defines as constants is, this would seemingly imply set_color(PARTY_LIGHT_COLOR()) ``` -...which *does* imply some work is happening. +...which _does_ imply some work is happening. BYOND does not support `#define PARTY_LIGHT_COLOR()`, so instead we would write the define as: @@ -839,6 +892,7 @@ Sometimes the best macro is one that doesn't exist at all. Macros can make some ``` This is a fairly egregious macro, and would be better off just written like: + ```dm /obj/item/sword/proc/hit(mob/victim) attack(victim) @@ -846,9 +900,10 @@ This is a fairly egregious macro, and would be better off just written like: ``` ## Things that do not matter + The following coding styles are not only not enforced at all, but are generally frowned upon to change for little to no reason: -* English/British spelling on var/proc names - * Color/Colour - both are fine, but keep in mind that BYOND uses `color` as a base variable -* Spaces after control statements - * `if()` and `if ()` - nobody cares! +- English/British spelling on var/proc names + - Color/Colour - both are fine, but keep in mind that BYOND uses `color` as a base variable +- Spaces after control statements + - `if()` and `if ()` - nobody cares! diff --git a/.github/guides/TICK_ORDER.md b/.github/guides/TICK_ORDER.md index 5c27617db4c..982565ab451 100644 --- a/.github/guides/TICK_ORDER.md +++ b/.github/guides/TICK_ORDER.md @@ -1,4 +1,5 @@ The byond tick proceeds as follows: + 1. procs sleeping via walk() are resumed (i dont know why these are first) 2. normal sleeping procs are resumed, in the order they went to sleep in the first place, this is where the MC wakes up and processes subsystems. a consequence of this is that the MC almost never resumes before other sleeping procs, because it only goes to sleep for 1 tick 99% of the time, and 99% of procs either go to sleep for less time than the MC (which guarantees that they entered the sleep queue earlier when its time to wake up) and/or were called synchronously from the MC's execution, almost all of the time the MC is the last sleeping proc to resume in any given tick. This is good because it means the MC can account for the cost of previous resuming procs in the tick, and minimizes overtime. @@ -8,14 +9,14 @@ The byond tick proceeds as follows: 4. a few small things happen in byond internals 5. SendMaps is called for this tick, which processes the game state for all clients connected to the game and handles sending them changes -in appearances within their view range. This is expensive and takes up a significant portion of our tick, about 0.45% per connected player -as of 3/20/2022. meaning that with 50 players, 22.5% of our tick is being used up by just SendMaps, after all of our code has stopped executing. Thats only the average across all rounds, for most highpop rounds it can look like 0.6% of the tick per player, which is 30% for 50 players. + in appearances within their view range. This is expensive and takes up a significant portion of our tick, about 0.45% per connected player + as of 3/20/2022. meaning that with 50 players, 22.5% of our tick is being used up by just SendMaps, after all of our code has stopped executing. Thats only the average across all rounds, for most highpop rounds it can look like 0.6% of the tick per player, which is 30% for 50 players. 6. After SendMaps ends, client verbs sent to the server are executed, and its the last major step before the next tick begins. -During the course of the tick, a client can send a command to the server saying that they have executed any verb. The actual code defined -for that /verb/name() proc isnt executed until this point, and the way the MC is designed makes this especially likely to make verbs -"overrun" the bounds of the tick they executed in, stopping the other tick from starting and thus delaying the MC firing in that tick. + During the course of the tick, a client can send a command to the server saying that they have executed any verb. The actual code defined + for that /verb/name() proc isnt executed until this point, and the way the MC is designed makes this especially likely to make verbs + "overrun" the bounds of the tick they executed in, stopping the other tick from starting and thus delaying the MC firing in that tick. -The master controller can derive how much of the tick was used in: procs executing before it woke up (because of world.tick_usage), and SendMaps (because of world.map_cpu, since this is a running average you cant derive the tick spent on maptick on any particular tick). It cannot derive how much of the tick was used for sleeping procs resuming after the MC ran, or for verbs executing after SendMaps. +The master controller can derive how much of the tick was used in: procs executing before it woke up (because of world.tick_usage), and SendMaps (because of world.map_cpu, since this is a running average you cant derive the tick spent on maptick on any particular tick). It cannot derive how much of the tick was used for sleeping procs resuming after the MC ran, or for verbs executing after SendMaps. It is for these reasons why you should heavily limit processing done in verbs, while procs resuming after the MC are rare, verbs are not, and are much more likely to cause overtime since theyre literally at the end of the tick. If you make a verb, try to offload any expensive work to the beginning of the next tick via a verb management subsystem. diff --git a/.github/guides/VISUALS.md b/.github/guides/VISUALS.md index 69194004d4c..3afdfe28e71 100644 --- a/.github/guides/VISUALS.md +++ b/.github/guides/VISUALS.md @@ -31,9 +31,9 @@ You'll find links to the relevant reference entries at the heading of each entry - [Gliding](#gliding) - [Sight](#sight) - [BYOND lighting](#byond-lighting) - - [Luminosity](#luminosity) - - [See in dark](#see-in-dark) - - [Infrared](#infrared) + - [Luminosity](#luminosity) + - [See in dark](#see-in-dark) + - [Infrared](#infrared) - [Invisibility](#invisibility) - [Layers](#layers) - [Planes](#planes) @@ -47,7 +47,7 @@ You'll find links to the relevant reference entries at the heading of each entry - [Color](#color) - [Transform](#transform) - [Lighting](#lighting) -- [Animate()](#animate()) +- [Animate()](<#animate()>) - [GAGS](#gags) ## Appearances in BYOND @@ -137,15 +137,16 @@ Be careful of this. The `vis_contents` list allows you to essentially say "Hey, render this thing ON me". -The definition of "ON" varies significantly with the `vis_flags` value of the *thing* being relayed. +The definition of "ON" varies significantly with the `vis_flags` value of the _thing_ being relayed. See the ref [here](https://www.byond.com/docs/ref/#/atom/var/vis_flags). Some flags of interest: + - `VIS_INHERIT_ID`: This allows you to link the object DIRECTLY to the thing it's drawn on, -so clicking on the `vis_contents`'d object is just like clicking on the thing + so clicking on the `vis_contents`'d object is just like clicking on the thing - `VIS_INHERIT_PLANE`: We will discuss [planes](#planes) more in future, but we use them to both effect rendering order and apply effects as a group. -This flag changes the plane of any `vis_contents`'d object (while displayed on the source object) to the source's. -This is occasionally useful, but should be used with care as it breaks any effects that rely on plane. + This flag changes the plane of any `vis_contents`'d object (while displayed on the source object) to the source's. + This is occasionally useful, but should be used with care as it breaks any effects that rely on plane. Anything inside a `vis_contents` list will have its loc stored in its `vis_locs` variable. We very rarely use this, primarily just for clearing references from `vis_contents`. @@ -159,7 +160,6 @@ Careful how much you use it. ## Images - - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/image) @@ -199,6 +199,7 @@ We then mirror this group of images into/out of the client's images list, based This is the pattern we use for things like the medihud, or robot trails. ## View + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/client/var/view) @@ -231,6 +232,7 @@ See the ref for more details, but `normal` is gonna have the sharpest output, `d which causes some blur, and `blur` uses bilinear sampling, which causes a LOT of blur. ## Eye + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/client/var/eye) @@ -241,10 +243,11 @@ It is by default `/client/var/mob` but it can be modified. This is how we accomplish ai eyes and ventcrawling, alongside most other effects that involve a player getting "into" something. ## Client Screen + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/HUD) -Similar to client images but not *quite* the same, we can also insert objects onto our client's literal screen +Similar to client images but not _quite_ the same, we can also insert objects onto our client's literal screen This is done by giving it an appropriate `screen_loc` value, and inserting it into the client's `screen` list. @@ -271,6 +274,7 @@ This gets into dmf fuckery but you can use [window ids](https://www.byond.com/do Useful for creating popup windows and such. ## Blend Mode + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/blend_mode) @@ -281,6 +285,7 @@ There's a whole bunch of options but really the only one you need to know offhan This is how we do lighting effects, since the lighting [plane](#planes) can be used to multiply just normal coloring. If it's all black, the full screen goes black. ## Appearance Flags + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance_flags) @@ -288,12 +293,14 @@ This is how we do lighting effects, since the lighting [plane](#planes) can be u I won't go over all of them, but I will discuss a few. Flags of interest: + - `LONG_GLIDE`: without this, diagonal movements will automatically take sqrt(2) more time, to account for the greater distance. We do this calculus automatically, and so want this flipped to disable the behavior. - `KEEP_TOGETHER`: this allows us to force overlays to render in the same manner as the thing they're overlaid on. Most useful for humans to make alpha changes effect all overlays. - `PLANE_MASTER`: I will get into this later, but this allows us to use the [plane](#planes) var to relay renders onto screen objects, so we can apply visual effects and masks and such. - `TILE_BOUND`: By default if something is part in one tile and part in another it will display if either is visible. With this set it'll go off its loc value only. ## Gliding + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/gliding) @@ -314,7 +321,7 @@ We will also occasionally use glide size as a way to force a transition between There's extra cruft here. > Something you should know: Our gliding system attempts to account for time dilation when setting move rates. -This is done in a very simplistic way however, so a spike in td will lead to jumping around as glide rate is outpaced by mob movement rate. +> This is done in a very simplistic way however, so a spike in td will lead to jumping around as glide rate is outpaced by mob movement rate. On that note, it is VERY important that glide rate is the same or near the same as actual move rate. Otherwise you will get strange jumping and jitter. @@ -328,17 +335,18 @@ This is why you'll sometime see a stutter in your step when slowed Just so you know, client movement works off `/client/var/move_delay` which sets the next time an input will be accepted. It's typically glide rate, but is in some cases just 1 tick. ## Sight + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/sight) -`/mob/var/sight` is a set of bitflags that *mostly* set what HAS to render on your screen. Be that mobs, turfs, etc. +`/mob/var/sight` is a set of bitflags that _mostly_ set what HAS to render on your screen. Be that mobs, turfs, etc. That said, there is some nuance here so I'ma get into that. - `SEE_INFRA`: I'll get into this later, but infrared is essentially a copy of BYOND darkness, it's not something we currently use. - `SEE_BLACKNESS`: This relates heavily to [planes](#planes), essentially typically the "blackness" (that darkness that masks things that you can't see) -is rendered separately, out of our control as "users". -However, if the `SEE_BLACKNESS` flag is set, it will instead render on plane 0, the default BYOND plane. -This allows us to capture it, and say, blur it, or redraw it elsewhere. This is in theory very powerful, but not possible with the 'side_map' [map format](https://www.byond.com/docs/ref/#/world/var/map_format) + is rendered separately, out of our control as "users". + However, if the `SEE_BLACKNESS` flag is set, it will instead render on plane 0, the default BYOND plane. + This allows us to capture it, and say, blur it, or redraw it elsewhere. This is in theory very powerful, but not possible with the 'side_map' [map format](https://www.byond.com/docs/ref/#/world/var/map_format) ## BYOND Lighting @@ -354,6 +362,7 @@ sort of like if there was a wall between them. This hiding uses BYOND darkness, I'll use this section to discuss all the little bits that contribute to this behavior ### Luminosity + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/luminosity) @@ -361,9 +370,10 @@ I'll use this section to discuss all the little bits that contribute to this beh It's real simple, just a range of tiles that will be lit, respecting sight-lines and such of course. > This "light" is how `/proc/view()` knows if something is in view or not. Oh by the by `view()` respects lighting. -You can actually force it to use a particular mob's sight to avoid aspects of this, this is what `dview()` is +> You can actually force it to use a particular mob's sight to avoid aspects of this, this is what `dview()` is ### See in Dark + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_in_dark) @@ -373,6 +383,7 @@ This is why when you stand in darkness you can see yourself, and why you can see It's quite simple, but worth describing. ### Infrared + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_infrared) @@ -380,6 +391,7 @@ Infrared vision can be thought of as a hidden copy of standard BYOND darkness. It's not something we actually use, but I think you should know about it, because the whole thing is real confusing without context. ## Invisibility + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/invisibility) @@ -391,6 +403,7 @@ It's also used to hide some more then ghost invisible things, like some timers a `/mob/var/see_invisible` is the catcher of invisibility. If a mob's see_invisible is higher then a target/s invisibility, it'll be shown. Really basic stuff. ## Layers + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/layer) @@ -412,6 +425,7 @@ We can think of this as applying to planes, since we don't want it interlaying w This allows us to keep relative layer differences while not needing to make all sources static. Often very useful. ## Planes + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/plane) @@ -440,12 +454,13 @@ called `/atom/movable/plane_master_controller`. This is somewhat outmoded by our use of [render relays](#render-targetsource), but it's still valid and occasionally useful. > Something you should know: Plane masters effect ONLY the map their screen_loc is on. -For this reason, we are forced to generate whole copies of the set of plane masters with the proper screen_loc to make subviews look right +> For this reason, we are forced to generate whole copies of the set of plane masters with the proper screen_loc to make subviews look right > Warning: Planes have some restrictions on valid values. They NEED to be whole integers, and they NEED to have an absolute value of `10000`. -This is to support `FLOAT_PLANE`, which lives out at the very edge of the 32 bit int range. +> This is to support `FLOAT_PLANE`, which lives out at the very edge of the 32 bit int range. ## Render Target/Source + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/render_target) @@ -454,7 +469,7 @@ The target object is given a `/atom/var/render_target` value, and anything that When I say render onto, I mean it literally. It is like adding a second step in the rendering process. -You can even prepend * to the render target value to disable the initial render, and JUST render via the render source. +You can even prepend \* to the render target value to disable the initial render, and JUST render via the render source. ### Our Implementation @@ -462,13 +477,14 @@ We use render targets to create "render relays" which can be used to link [plane See [the renderer documentation](../../code/_onclick/hud/rendering/_render_readme.md) for visualizations for this. > Of note: this linking behavior is accomplished by adding a screen object to link onto with a plane value of the desired PM we want to relay onto. -Layer is VERY important here, and will be set based off the layer of the last plane master. -This means plane order is not always the absolute order in which different plane masters render. Be careful of this. +> Layer is VERY important here, and will be set based off the layer of the last plane master. +> This means plane order is not always the absolute order in which different plane masters render. Be careful of this. > To edit and display planes and plane connections in game, run the `Edit/Debug Planes` command. -It will open a ui that allows you to view relay connections, plane master descriptions, and edit their values and effects. +> It will open a ui that allows you to view relay connections, plane master descriptions, and edit their values and effects. ## Multiz + - [Table of Contents](#table-of-contents) - Reference: Hell of our own creation @@ -483,10 +499,10 @@ Except not, for 2 reasons. One more annoying then the other. - 1: It looked like dog doo-doo. This pattern destroyed the old planes of everything vis_contents'd, so effects/lighting/dropshadows broke bad. - 2: I alluded to this earlier, but it totally breaks the `side_map` [map format](https://www.byond.com/docs/ref/#/world/var/map_format) -which I need for a massive resprite I'm helping with. This is because `side_map` changes how rendering order works, -going off "distance" from the front of the frame. -The issue here is it of course needs a way to group things that are even allowed to overlap, so it uses plane. -So when you squish everything down onto one plane, this of course breaks horribly and fucks you. + which I need for a massive resprite I'm helping with. This is because `side_map` changes how rendering order works, + going off "distance" from the front of the frame. + The issue here is it of course needs a way to group things that are even allowed to overlap, so it uses plane. + So when you squish everything down onto one plane, this of course breaks horribly and fucks you. Ok then, old way's not workable. What will we do instead? @@ -506,6 +522,7 @@ There are a few edge cases where we need to work in explicitly offsets, but thos This is stupid, but it's makable, and what we do. ## Mouse Opacity + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/mouse_opacity) @@ -519,12 +536,13 @@ We will on occasion use mouse opacity to expand hitboxes, but more often this is or just low alpha pixels on the sprite. > Note: Mouse opacity will only matter if the atom is being rendered on its own. [Overlays](#overlays)(and [images](#images)) -will NOT work as expected with this. -However, you can still have totally transparent overlays. If you render them onto a [plane master](#planes) with the desired mouse opacity value -it will work as expected. This is because as a step of the rendering pipeline the overlay is rendered ONTO the plane master, and then the plane -master's effects are applied. +> will NOT work as expected with this. +> However, you can still have totally transparent overlays. If you render them onto a [plane master](#planes) with the desired mouse opacity value +> it will work as expected. This is because as a step of the rendering pipeline the overlay is rendered ONTO the plane master, and then the plane +> master's effects are applied. ## Filters + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/filters) @@ -547,9 +565,10 @@ we will need our own management system. This is why we, unlike byond, use a wrap This system has the potential to break animations and other such things. Take care. > We have a debug tool for filters, called filterrific. You can access it in-game by vving an atom, going to the dropdown, and hitting `Edit Filters` -It'll let you add and tweak *most* of the filters in BYOND. +> It'll let you add and tweak _most_ of the filters in BYOND. ## Particles + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/particles) @@ -561,9 +580,10 @@ The type is `/obj/effect/abstract/particle_holder`. Interacting with it's real s It'll do the rest. > We have a debug tool for particles. You can access it in-game by vving an atom, going to the dropdown, and hitting `Edit Particles` -It'll let you add and tweak the particles attached to that atom. +> It'll let you add and tweak the particles attached to that atom. ## Pixel Offsets + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/pixel_x) @@ -582,6 +602,7 @@ This doesn't really matter for our current map format, but for anything that tak it matters a whole ton. It's kinda a hard idea to get across, but I hope you have at least some idea. ## Map Formats + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/world/var/map_format) @@ -621,6 +642,7 @@ That's because we use [`LEGACY_MOVEMENT_MODE`](https://www.byond.com/docs/ref/#/ This means we're almost always doomed to getting weird layering, cascading out from the source of the issue in a way that is quite hard to debug. Oh right I forgot to mention. Sorta touched on it with [Pixel offsets](#pixel-offsets). + - `pixel_x/y` change something's position in physical space. So if you shoot this real high it'll layer as if it is where it appears to be, - `pixel_w/z` change something's VISUAL position. So you can LAYER as if you're at the bottom of the screen, but actually sit at the top. @@ -632,13 +654,14 @@ What follows is a description, from lummox, of how physical conflicts are handle From [this post](https://www.byond.com/forum/post/2656961#comment26050050) For the physical position, Y increases upward relative to the screen; view position has Y going downward. The topological order between two icons goes like this, in order: -- 1) If the icons don't visually overlap, they don't care which goes first. -- 2) If the icons do not overlap on the physical Y axis, whichever one is further back is drawn first. -- 3) If one has a lower layer, it's drawn first. -- 4) If one's "near" edge (physical Y) is closer to the top of the screen than the other, it gets drawn first. -- 5) If one's center is left of the other, it's drawn first. -- 6) If the two physical bounds are identical, whichever icon came first in the original array order is drawn first. -- 7) All tiebreakers failed so the icons give up and don't care which goes first. + +- 1. If the icons don't visually overlap, they don't care which goes first. +- 2. If the icons do not overlap on the physical Y axis, whichever one is further back is drawn first. +- 3. If one has a lower layer, it's drawn first. +- 4. If one's "near" edge (physical Y) is closer to the top of the screen than the other, it gets drawn first. +- 5. If one's center is left of the other, it's drawn first. +- 6. If the two physical bounds are identical, whichever icon came first in the original array order is drawn first. +- 7. All tiebreakers failed so the icons give up and don't care which goes first. It is worth stating clearly. Things will only "visually overlap" if they sit on the same [plane](#planes). This is NOT counting [relays](#render-targetsource)/[plane masters](#planes) (when a plane master is relayed onto something else, you can think of it like drawing the WHOLE PLANE MASTER) @@ -651,7 +674,7 @@ One more thing. Big icons are fucked From the byond reference ->If you use an icon wider than one tile, the "footprint" of the isometric icon (the actual map tiles it takes up) will always be a square. That is, if your normal tile size is 64 and you want to show a 128x128 icon, the icon is two tiles wide and so it will take up a 2×2-tile area on the map. The height of a big icon is irrelevant--any excess height beyond width/2 is used to show vertical features. To draw this icon properly, other tiles on that same ground will be moved behind it in the drawing order. +> If you use an icon wider than one tile, the "footprint" of the isometric icon (the actual map tiles it takes up) will always be a square. That is, if your normal tile size is 64 and you want to show a 128x128 icon, the icon is two tiles wide and so it will take up a 2×2-tile area on the map. The height of a big icon is irrelevant--any excess height beyond width/2 is used to show vertical features. To draw this icon properly, other tiles on that same ground will be moved behind it in the drawing order. > One important warning about using big icons in isometric mode is that you should only do this with dense atoms. If part of a big mob icon covers the same tile as a tall building for instance, the tall building is moved back and it could be partially covered by other turfs that are actually behind it. A mob walking onto a very large non-dense turf icon would experience similar irregularities. These can cause very annoying flickering. In fact, MUCH of how rendering works causes flickering. This is because we don't decide on a pixel by pixel case, the engine groups sprites up into a sort of rendering stack, unable to split them up. @@ -683,6 +706,7 @@ Legacy support for how byond rendering used to work. It essentially locked icon it would be automatically broken down into smaller icon states, which you would need to manually display. Not something we need to care about ## Color + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/color) @@ -706,9 +730,10 @@ You can accomplish some really fun effects with this trick, it gives you a LOT o and leads to some fun vfx. > We have a debug tool for color matrixes. Just VV an atom, go to the VV dropdown and look for the `Edit Color as Matrix` entry. -It'll help visualize this process quite well. Play around with it, it's fun. +> It'll help visualize this process quite well. Play around with it, it's fun. ## Transform + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/transform) @@ -721,12 +746,13 @@ helper procs for pretty much everything it can do. It's not totally without explanation, and I figured you might wanna know about it. Not a whole lot more to say tho. Neat tool. ## Lighting + - [Table of Contents](#table-of-contents) - Reference: Hell of our own creation I wanted to take this chance to briefly explain the essentials of how our lighting system works. Essentially, each tile has a lighting [overlay](#overlays) (technically an [underlay](https://www.byond.com/docs/ref/#/atom/var/underlays) - which is just overlays but drawn under). +which is just overlays but drawn under). Anyway, each underlay is a color gradient, with red green and blue and alpha in each corner. Every "corner" (we call them lighting corners) on the map impacts the 4 colors that touch it. This is done with color matrixes. This allows us to apply color and lighting in a smooth way, while only needing 1 overlay per tile. @@ -736,6 +762,7 @@ But it covers the core idea, the rest should be derivable, and you're more quali and forget to update this file. ## Animate() + - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/proc/animate) @@ -750,6 +777,7 @@ parallel. It's got a lot of nuance to it, but it's real useful. Works on filters Lets you give radiation glow a warm pulse, that sort of thing. ## GAGS + - [Table of Contents](#table-of-contents) - Reference: Hell of our own creation diff --git a/.github/images/README.md b/.github/images/README.md index a3c0c24ade3..135aa8c1f06 100644 --- a/.github/images/README.md +++ b/.github/images/README.md @@ -1,6 +1,7 @@ # Attributions ## Badges + `built-with-resentment.svg` and `contains-technical-debt.svg` were originally sourced from https://forthebadge.com/, with the repository located at https://github.com/BraveUX/for-the-badge. `made-in-byond.gif` is a user-generated modification of one of these badges provided by this service. ## Comics diff --git a/.github/workflows/auto_changelog.yml b/.github/workflows/auto_changelog.yml index f0a1dad37b5..c713ed3b1e3 100644 --- a/.github/workflows/auto_changelog.yml +++ b/.github/workflows/auto_changelog.yml @@ -13,24 +13,24 @@ jobs: runs-on: ubuntu-latest if: github.event.pull_request.merged == true steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 - - name: Generate App Token - id: app-token-generation - uses: actions/create-github-app-token@v2 - if: env.APP_PRIVATE_KEY != '' && env.APP_ID != '' - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - env: - APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} - APP_ID: ${{ secrets.APP_ID }} + - name: Generate App Token + id: app-token-generation + uses: actions/create-github-app-token@v2 + if: env.APP_PRIVATE_KEY != '' && env.APP_ID != '' + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + env: + APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} + APP_ID: ${{ secrets.APP_ID }} - - name: Run auto changelog - uses: actions/github-script@v7 - with: - script: | - const { processAutoChangelog } = await import('${{ github.workspace }}/tools/pull_request_hooks/autoChangelog.js') - await processAutoChangelog({ github, context }) - github-token: ${{ secrets.BUBBERBOT_PAT || secrets.GITHUB_TOKEN }} + - name: Run auto changelog + uses: actions/github-script@v7 + with: + script: | + const { processAutoChangelog } = await import('${{ github.workspace }}/tools/pull_request_hooks/autoChangelog.js') + await processAutoChangelog({ github, context }) + github-token: ${{ secrets.BUBBERBOT_PAT || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/autowiki.yml b/.github/workflows/autowiki.yml index 5e10274a719..e988dfa2f07 100644 --- a/.github/workflows/autowiki.yml +++ b/.github/workflows/autowiki.yml @@ -1,7 +1,7 @@ name: Autowiki on: schedule: - - cron: "5 4 * * *" + - cron: "5 4 * * *" workflow_dispatch: permissions: contents: read @@ -10,36 +10,36 @@ jobs: autowiki: runs-on: ubuntu-latest steps: - - name: "Check for AUTOWIKI_USERNAME" - id: secrets_set - env: - ENABLER_SECRET: ${{ secrets.AUTOWIKI_USERNAME }} - run: | - unset SECRET_EXISTS - if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi - echo "SECRETS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT - - name: Checkout - if: steps.secrets_set.outputs.SECRETS_ENABLED - uses: actions/checkout@v4 - - name: Install BYOND - if: steps.secrets_set.outputs.SECRETS_ENABLED - uses: ./.github/actions/restore_or_install_byond - - name: Install rust-g - if: steps.secrets_set.outputs.SECRETS_ENABLED - run: | - bash tools/ci/install_rust_g.sh - - name: Compile and generate Autowiki files - if: steps.secrets_set.outputs.SECRETS_ENABLED - run: | - source $HOME/BYOND/byond/bin/byondsetup - tools/build/build --ci autowiki - - name: Run Autowiki - if: steps.secrets_set.outputs.SECRETS_ENABLED - env: - USERNAME: ${{ secrets.AUTOWIKI_USERNAME }} - PASSWORD: ${{ secrets.AUTOWIKI_PASSWORD }} - run: | - cd tools/autowiki - npm install - cd ../.. - node tools/autowiki/autowiki.js data/autowiki_edits.txt data/autowiki_files/ + - name: "Check for AUTOWIKI_USERNAME" + id: secrets_set + env: + ENABLER_SECRET: ${{ secrets.AUTOWIKI_USERNAME }} + run: | + unset SECRET_EXISTS + if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi + echo "SECRETS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT + - name: Checkout + if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: actions/checkout@v4 + - name: Install BYOND + if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: ./.github/actions/restore_or_install_byond + - name: Install rust-g + if: steps.secrets_set.outputs.SECRETS_ENABLED + run: | + bash tools/ci/install_rust_g.sh + - name: Compile and generate Autowiki files + if: steps.secrets_set.outputs.SECRETS_ENABLED + run: | + source $HOME/BYOND/byond/bin/byondsetup + tools/build/build --ci autowiki + - name: Run Autowiki + if: steps.secrets_set.outputs.SECRETS_ENABLED + env: + USERNAME: ${{ secrets.AUTOWIKI_USERNAME }} + PASSWORD: ${{ secrets.AUTOWIKI_PASSWORD }} + run: | + cd tools/autowiki + npm install + cd ../.. + node tools/autowiki/autowiki.js data/autowiki_edits.txt data/autowiki_files/ diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index 6655c8d1c4b..184fd52bd82 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -3,11 +3,11 @@ name: CI Suite on: pull_request: branches: - - master - - 'project/**' + - master + - "project/**" merge_group: branches: - - master + - master concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -65,14 +65,21 @@ jobs: compare_screenshots: if: needs.collect_data.outputs.alternate_tests == '[]' || needs.run_alternate_tests.result == 'success' - needs: [ collect_data, run_alternate_tests ] + needs: [collect_data, run_all_tests, run_alternate_tests] name: Compare Screenshot Tests uses: ./.github/workflows/compare_screenshots.yml completion_gate: # Serves as a non-moving target for branch rulesets if: always() && !cancelled() name: Completion Gate - needs: [ compare_screenshots, compile_all_maps, run_all_tests, run_alternate_tests, run_linters ] + needs: + [ + compare_screenshots, + compile_all_maps, + run_all_tests, + run_alternate_tests, + run_linters, + ] runs-on: ubuntu-latest steps: - name: Decide whether the needed jobs succeeded or failed diff --git a/.github/workflows/codeowner_reviews.yml.disabled b/.github/workflows/codeowner_reviews.yml.disabled index e6cfb980279..8ebaed36a53 100644 --- a/.github/workflows/codeowner_reviews.yml.disabled +++ b/.github/workflows/codeowner_reviews.yml.disabled @@ -7,7 +7,6 @@ on: jobs: assign-users: - runs-on: ubuntu-latest timeout-minutes: 5 @@ -26,5 +25,5 @@ jobs: if: steps.CodeOwnersParser.outputs.owners != '' uses: tgstation/RequestReviewFromUser@v1 with: - separator: ' ' + separator: " " users: ${{ steps.CodeOwnersParser.outputs.owners }} diff --git a/.github/workflows/compile_changelogs.yml b/.github/workflows/compile_changelogs.yml index 0d23f18404f..363bc48bd73 100644 --- a/.github/workflows/compile_changelogs.yml +++ b/.github/workflows/compile_changelogs.yml @@ -2,7 +2,7 @@ name: Compile changelogs on: schedule: - - cron: "2 23 * * *" + - cron: "2 23 * * *" workflow_dispatch: jobs: @@ -25,7 +25,7 @@ jobs: if: steps.value_holder.outputs.ACTIONS_ENABLED uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: "3.x" - name: "Install deps" if: steps.value_holder.outputs.ACTIONS_ENABLED diff --git a/.github/workflows/discord_pr_announce.yml b/.github/workflows/discord_pr_announce.yml index 83cb96beb3f..edd87b23cdd 100644 --- a/.github/workflows/discord_pr_announce.yml +++ b/.github/workflows/discord_pr_announce.yml @@ -1,4 +1,4 @@ -name: 'New PR Notification' +name: "New PR Notification" on: pull_request_target: types: [opened, closed] diff --git a/.github/workflows/gbp.yml.disabled b/.github/workflows/gbp.yml.disabled index face7b8f3d0..62e7dbec7db 100644 --- a/.github/workflows/gbp.yml.disabled +++ b/.github/workflows/gbp.yml.disabled @@ -11,56 +11,56 @@ jobs: pull-requests: write # to apply labels issues: write # to apply labels steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Run Auto Labeler - uses: actions/github-script@v7 - with: - script: | - const { get_updated_label_set } = await import('${{ github.workspace }}/tools/pull_request_hooks/autoLabel.js'); - const new_labels = await get_updated_label_set({ github, context }); - github.rest.issues.setLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: new_labels, - }); - console.log(`Labels updated: ${new_labels}`); + - name: Checkout + uses: actions/checkout@v4 + - name: Run Auto Labeler + uses: actions/github-script@v7 + with: + script: | + const { get_updated_label_set } = await import('${{ github.workspace }}/tools/pull_request_hooks/autoLabel.js'); + const new_labels = await get_updated_label_set({ github, context }); + github.rest.issues.setLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: new_labels, + }); + console.log(`Labels updated: ${new_labels}`); gbp: runs-on: ubuntu-latest if: github.event.action == 'opened' || github.event.action == 'closed' steps: - - name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps" - id: value_holder - env: - ENABLER_SECRET: ${{ secrets.ACTION_ENABLER }} - run: | - unset SECRET_EXISTS - if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi - echo "ACTIONS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT - - name: Checkout - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v4 - - name: Setup git - if: steps.value_holder.outputs.ACTIONS_ENABLED - run: | - git config --global user.name "gbp-action" - git config --global user.email "<>" - - name: Checkout alternate branch - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v4 - with: - ref: "gbp-balances" # The branch name - path: gbp-balances - # This is to ensure we keep the gbp.toml from master - # without having to update our separate branch. - - name: Copy configuration - if: steps.value_holder.outputs.ACTIONS_ENABLED - run: cp ./.github/gbp.toml ./gbp-balances/.github/gbp.toml - - name: GBP action - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: tgstation/gbp-action@master - with: - branch: "gbp-balances" - directory: ./gbp-balances - token: ${{ secrets.GITHUB_TOKEN }} + - name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps" + id: value_holder + env: + ENABLER_SECRET: ${{ secrets.ACTION_ENABLER }} + run: | + unset SECRET_EXISTS + if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi + echo "ACTIONS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT + - name: Checkout + if: steps.value_holder.outputs.ACTIONS_ENABLED + uses: actions/checkout@v4 + - name: Setup git + if: steps.value_holder.outputs.ACTIONS_ENABLED + run: | + git config --global user.name "gbp-action" + git config --global user.email "<>" + - name: Checkout alternate branch + if: steps.value_holder.outputs.ACTIONS_ENABLED + uses: actions/checkout@v4 + with: + ref: "gbp-balances" # The branch name + path: gbp-balances + # This is to ensure we keep the gbp.toml from master + # without having to update our separate branch. + - name: Copy configuration + if: steps.value_holder.outputs.ACTIONS_ENABLED + run: cp ./.github/gbp.toml ./gbp-balances/.github/gbp.toml + - name: GBP action + if: steps.value_holder.outputs.ACTIONS_ENABLED + uses: tgstation/gbp-action@master + with: + branch: "gbp-balances" + directory: ./gbp-balances + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/gbp_collect.yml.disabled b/.github/workflows/gbp_collect.yml.disabled index 4dd327abecd..644595e1336 100644 --- a/.github/workflows/gbp_collect.yml.disabled +++ b/.github/workflows/gbp_collect.yml.disabled @@ -2,43 +2,43 @@ name: GBP Collection # Every hour at the :20 minute mark. GitHub tells us to pick odd hours, instead of just using the start. on: schedule: - - cron: "20 * * * *" + - cron: "20 * * * *" workflow_dispatch: jobs: gbp_collection: runs-on: ubuntu-latest steps: - - name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps" - id: value_holder - env: - ENABLER_SECRET: ${{ secrets.ACTION_ENABLER }} - run: | - unset SECRET_EXISTS - if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi - echo "ACTIONS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT - - name: Checkout - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v4 - - name: Setup git - if: steps.value_holder.outputs.ACTIONS_ENABLED - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - - name: Checkout alternate branch - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v4 - with: - ref: "gbp-balances" # The branch name - path: gbp-balances - # This is to ensure we keep the gbp.toml from master - # without having to update our separate branch. - - name: Copy configuration - if: steps.value_holder.outputs.ACTIONS_ENABLED - run: cp ./.github/gbp.toml ./gbp-balances/.github/gbp.toml - - name: GBP action - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: tgstation/gbp-action@master - with: - collect: "true" - directory: ./gbp-balances - token: ${{ secrets.GITHUB_TOKEN }} + - name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps" + id: value_holder + env: + ENABLER_SECRET: ${{ secrets.ACTION_ENABLER }} + run: | + unset SECRET_EXISTS + if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi + echo "ACTIONS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT + - name: Checkout + if: steps.value_holder.outputs.ACTIONS_ENABLED + uses: actions/checkout@v4 + - name: Setup git + if: steps.value_holder.outputs.ACTIONS_ENABLED + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + - name: Checkout alternate branch + if: steps.value_holder.outputs.ACTIONS_ENABLED + uses: actions/checkout@v4 + with: + ref: "gbp-balances" # The branch name + path: gbp-balances + # This is to ensure we keep the gbp.toml from master + # without having to update our separate branch. + - name: Copy configuration + if: steps.value_holder.outputs.ACTIONS_ENABLED + run: cp ./.github/gbp.toml ./gbp-balances/.github/gbp.toml + - name: GBP action + if: steps.value_holder.outputs.ACTIONS_ENABLED + uses: tgstation/gbp-action@master + with: + collect: "true" + directory: ./gbp-balances + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml index f4db80344df..79c6f180ffe 100644 --- a/.github/workflows/generate_documentation.yml +++ b/.github/workflows/generate_documentation.yml @@ -1,14 +1,14 @@ name: Generate documentation on: schedule: - - cron: "44 */6 * * *" + - cron: "44 */6 * * *" workflow_dispatch: permissions: contents: read jobs: generate_documentation: permissions: - contents: write # for JamesIves/github-pages-deploy-action to push changes in repo + contents: write # for JamesIves/github-pages-deploy-action to push changes in repo if: ( !contains(github.event.head_commit.message, '[ci skip]') ) runs-on: ubuntu-22.04 concurrency: gen-docs diff --git a/.github/workflows/remove_guide_comments.yml b/.github/workflows/remove_guide_comments.yml index 621d860c5cd..2c65239133f 100644 --- a/.github/workflows/remove_guide_comments.yml +++ b/.github/workflows/remove_guide_comments.yml @@ -8,11 +8,11 @@ jobs: remove_guide_comments: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Remove guide comments - uses: actions/github-script@v7 - with: - script: | - const { removeGuideComments } = await import('${{ github.workspace }}/tools/pull_request_hooks/removeGuideComments.js') - await removeGuideComments({ github, context }) + - name: Checkout + uses: actions/checkout@v4 + - name: Remove guide comments + uses: actions/github-script@v7 + with: + script: | + const { removeGuideComments } = await import('${{ github.workspace }}/tools/pull_request_hooks/removeGuideComments.js') + await removeGuideComments({ github, context }) diff --git a/.github/workflows/rerun_flaky_tests.yml b/.github/workflows/rerun_flaky_tests.yml index 80ece468061..b7313767f4d 100644 --- a/.github/workflows/rerun_flaky_tests.yml +++ b/.github/workflows/rerun_flaky_tests.yml @@ -3,29 +3,29 @@ on: workflow_run: workflows: [CI Suite] types: - - completed + - completed jobs: rerun_flaky_tests: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.run_attempt == 1 }} steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Rerun flaky tests - uses: actions/github-script@v7 - with: - script: | - const { rerunFlakyTests } = await import('${{ github.workspace }}/tools/pull_request_hooks/rerunFlakyTests.js') - await rerunFlakyTests({ github, context }) + - name: Checkout + uses: actions/checkout@v4 + - name: Rerun flaky tests + uses: actions/github-script@v7 + with: + script: | + const { rerunFlakyTests } = await import('${{ github.workspace }}/tools/pull_request_hooks/rerunFlakyTests.js') + await rerunFlakyTests({ github, context }) report_flaky_tests: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.run_attempt == 2 }} steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Report flaky tests - uses: actions/github-script@v7 - with: - script: | - const { reportFlakyTests } = await import('${{ github.workspace }}/tools/pull_request_hooks/rerunFlakyTests.js') - await reportFlakyTests({ github, context }) + - name: Checkout + uses: actions/checkout@v4 + - name: Report flaky tests + uses: actions/github-script@v7 + with: + script: | + const { reportFlakyTests } = await import('${{ github.workspace }}/tools/pull_request_hooks/rerunFlakyTests.js') + await reportFlakyTests({ github, context }) diff --git a/.github/workflows/round_id_linker.yml.disabled b/.github/workflows/round_id_linker.yml.disabled index fb4a202d179..7fb0ee8c4f3 100644 --- a/.github/workflows/round_id_linker.yml.disabled +++ b/.github/workflows/round_id_linker.yml.disabled @@ -7,6 +7,6 @@ jobs: link_rounds: runs-on: ubuntu-22.04 steps: - - uses: tgstation/round_linker@master - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} + - uses: tgstation/round_linker@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/stale.yml.disabled b/.github/workflows/stale.yml.disabled index cb427593424..188931a31f0 100644 --- a/.github/workflows/stale.yml.disabled +++ b/.github/workflows/stale.yml.disabled @@ -2,29 +2,28 @@ name: Mark stale issues and pull requests on: schedule: - - cron: "0 0 * * *" + - cron: "0 0 * * *" permissions: contents: read jobs: stale: - permissions: - issues: write # for actions/stale to close stale issues - pull-requests: write # for actions/stale to close stale PRs + issues: write # for actions/stale to close stale issues + pull-requests: write # for actions/stale to close stale PRs runs-on: ubuntu-22.04 steps: - - uses: actions/stale@v9 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-pr-message: "This PR has been inactive for long enough to be automatically marked as stale. This means it is at risk of being auto closed in ~ 7 days, please address any outstanding review items and ensure your PR is finished, if these are all true and you are auto-staled anyway, you need to actively ask maintainers if your PR will be merged. Once you have done any of the previous actions then you should request a maintainer remove the stale label on your PR, to reset the stale timer. If you feel no maintainer will respond in that time, you may wish to close this PR youself, while you seek maintainer comment, as you will then be able to reopen the PR yourself." - days-before-stale: 7 - days-before-close: 7 - stale-pr-label: 'Stale' - days-before-issue-stale: -1 - stale-issue-label: 'Cleanup Flagged' - remove-issue-stale-when-updated: false - exempt-pr-labels: 'Good First PR,Upstream PR Merged,Stale-b-gone,Test Merged' - operations-per-run: 300 + - uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-pr-message: "This PR has been inactive for long enough to be automatically marked as stale. This means it is at risk of being auto closed in ~ 7 days, please address any outstanding review items and ensure your PR is finished, if these are all true and you are auto-staled anyway, you need to actively ask maintainers if your PR will be merged. Once you have done any of the previous actions then you should request a maintainer remove the stale label on your PR, to reset the stale timer. If you feel no maintainer will respond in that time, you may wish to close this PR youself, while you seek maintainer comment, as you will then be able to reopen the PR yourself" + days-before-stale: 7 + days-before-close: 7 + stale-pr-label: "Stale" + days-before-issue-stale: -1 + stale-issue-label: "Cleanup Flagged" + remove-issue-stale-when-updated: false + exempt-pr-labels: "RED LABEL,Good First PR" + operations-per-run: 300 diff --git a/.github/workflows/test_merge_bot.yml b/.github/workflows/test_merge_bot.yml index 76dcd3cabc5..00f6bd19cb5 100644 --- a/.github/workflows/test_merge_bot.yml +++ b/.github/workflows/test_merge_bot.yml @@ -6,36 +6,36 @@ name: Test Merge Detector on: schedule: - - cron: "*/30 * * * *" + - cron: "*/30 * * * *" workflow_dispatch: jobs: test_merge_bot: - name: Test Merge Detector - runs-on: ubuntu-22.04 - steps: - - name: Check for GET_TEST_MERGES_URL - id: secrets_set - env: - ENABLER_SECRET: ${{ secrets.GET_TEST_MERGES_URL }} - run: | - unset SECRET_EXISTS - if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi - echo "GET_TEST_MERGES_URL=$SECRET_EXISTS" >> $GITHUB_OUTPUT - - name: Checkout - if: steps.secrets_set.outputs.GET_TEST_MERGES_URL - uses: actions/checkout@v4 - - name: Prepare module - if: steps.secrets_set.outputs.GET_TEST_MERGES_URL - run: | - # This is needed because node-fetch needs import and doesn't work with require :/ - echo "{\"type\": \"module\"}" > package.json - npm install node-fetch - - name: Check for test merges - if: steps.secrets_set.outputs.GET_TEST_MERGES_URL - uses: actions/github-script@v7 - env: - GET_TEST_MERGES_URL: ${{ secrets.GET_TEST_MERGES_URL }} - with: - script: | - const { processTestMerges } = await import('${{ github.workspace }}/tools/test_merge_bot/main.js') - await processTestMerges({ github, context }) + name: Test Merge Detector + runs-on: ubuntu-22.04 + steps: + - name: Check for GET_TEST_MERGES_URL + id: secrets_set + env: + ENABLER_SECRET: ${{ secrets.GET_TEST_MERGES_URL }} + run: | + unset SECRET_EXISTS + if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi + echo "GET_TEST_MERGES_URL=$SECRET_EXISTS" >> $GITHUB_OUTPUT + - name: Checkout + if: steps.secrets_set.outputs.GET_TEST_MERGES_URL + uses: actions/checkout@v4 + - name: Prepare module + if: steps.secrets_set.outputs.GET_TEST_MERGES_URL + run: | + # This is needed because node-fetch needs import and doesn't work with require :/ + echo "{\"type\": \"module\"}" > package.json + npm install node-fetch + - name: Check for test merges + if: steps.secrets_set.outputs.GET_TEST_MERGES_URL + uses: actions/github-script@v7 + env: + GET_TEST_MERGES_URL: ${{ secrets.GET_TEST_MERGES_URL }} + with: + script: | + const { processTestMerges } = await import('${{ github.workspace }}/tools/test_merge_bot/main.js') + await processTestMerges({ github, context }) diff --git a/.github/workflows/tgs_test.yml b/.github/workflows/tgs_test.yml index 4b7853aa77c..466d4ee86cd 100644 --- a/.github/workflows/tgs_test.yml +++ b/.github/workflows/tgs_test.yml @@ -2,39 +2,39 @@ name: TGS Test Suite on: push: branches: - - master - - 'project/**' - - 'gh-readonly-queue/master/**' - - 'gh-readonly-queue/project/**' + - master + - "project/**" + - "gh-readonly-queue/master/**" + - "gh-readonly-queue/project/**" paths: - - '.tgs.yml' - - '.github/workflows/tgs_test.yml' - - 'dependencies.sh' - - 'code/__DEFINES/tgs.config.dm' - - 'code/__DEFINES/tgs.dm' - - 'code/game/world.dm' - - 'code/modules/tgs/**' - - 'tools/bootstrap/**' - - 'tools/tgs_scripts/**' - - 'tools/tgs_test/**' + - ".tgs.yml" + - ".github/workflows/tgs_test.yml" + - "dependencies.sh" + - "code/__DEFINES/tgs.config.dm" + - "code/__DEFINES/tgs.dm" + - "code/game/world.dm" + - "code/modules/tgs/**" + - "tools/bootstrap/**" + - "tools/tgs_scripts/**" + - "tools/tgs_test/**" pull_request: branches: - - master - - 'project/**' + - master + - "project/**" paths: - - '.tgs.yml' - - '.github/workflows/tgs_test.yml' - - 'dependencies.sh' - - 'code/__DEFINES/tgs.config.dm' - - 'code/__DEFINES/tgs.dm' - - 'code/game/world.dm' - - 'code/modules/tgs/**' - - 'tools/bootstrap/**' - - 'tools/tgs_scripts/**' - - 'tools/tgs_test/**' + - ".tgs.yml" + - ".github/workflows/tgs_test.yml" + - "dependencies.sh" + - "code/__DEFINES/tgs.config.dm" + - "code/__DEFINES/tgs.dm" + - "code/game/world.dm" + - "code/modules/tgs/**" + - "tools/bootstrap/**" + - "tools/tgs_scripts/**" + - "tools/tgs_test/**" merge_group: branches: - - master + - master env: TGS_API_PORT: 5000 PR_NUMBER: ${{ github.event.number }} diff --git a/.github/workflows/update_tgs_dmapi.yml b/.github/workflows/update_tgs_dmapi.yml index 72f84e0c0a8..977a8affc52 100644 --- a/.github/workflows/update_tgs_dmapi.yml +++ b/.github/workflows/update_tgs_dmapi.yml @@ -13,50 +13,50 @@ jobs: contents: write pull-requests: write steps: - - name: Clone - uses: actions/checkout@v4 + - name: Clone + uses: actions/checkout@v4 - - name: Branch - run: | - git branch -f tgs-dmapi-update - git checkout tgs-dmapi-update - git reset --hard master + - name: Branch + run: | + git branch -f tgs-dmapi-update + git checkout tgs-dmapi-update + git reset --hard master - - name: Apply DMAPI update - uses: tgstation/tgs-dmapi-updater@v2 - id: dmapi-update - with: - header-path: 'code/__DEFINES/tgs.dm' - library-path: 'code/modules/tgs' + - name: Apply DMAPI update + uses: tgstation/tgs-dmapi-updater@v2 + id: dmapi-update + with: + header-path: "code/__DEFINES/tgs.dm" + library-path: "code/modules/tgs" - - name: Commit and Push - continue-on-error: true - run: | - git config user.name "tgstation-ci[bot]" - git config user.email "179393467+tgstation-ci[bot]@users.noreply.github.com" - git add . - git commit -m 'Update TGS DMAPI' - git push -f -u origin tgs-dmapi-update + - name: Commit and Push + continue-on-error: true + run: | + git config user.name "tgstation-ci[bot]" + git config user.email "179393467+tgstation-ci[bot]@users.noreply.github.com" + git add . + git commit -m 'Update TGS DMAPI' + git push -f -u origin tgs-dmapi-update - - name: Generate App Token - id: app-token-generation - uses: actions/create-github-app-token@v2 - if: env.APP_PRIVATE_KEY != '' && env.APP_ID != '' - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - env: - APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} - APP_ID: ${{ secrets.APP_ID }} + - name: Generate App Token + id: app-token-generation + uses: actions/create-github-app-token@v2 + if: env.APP_PRIVATE_KEY != '' && env.APP_ID != '' + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + env: + APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} + APP_ID: ${{ secrets.APP_ID }} - - name: Create Pull Request - uses: repo-sync/pull-request@v2 - if: ${{ success() }} - with: - source_branch: "tgs-dmapi-update" - destination_branch: "master" - pr_title: "Automatic TGS DMAPI Update" - pr_body: "This pull request updates the TGS DMAPI to the latest version. Please note any changes that may be breaking or unimplemented in your codebase by checking what changes are in the definitions file: code/__DEFINES/tgs.dm before merging.\n\n${{ steps.dmapi-update.outputs.release-notes }}" - pr_label: "Tools" - pr_allow_empty: false - github_token: ${{ steps.app-token-generation.outputs.token || secrets.GITHUB_TOKEN }} + - name: Create Pull Request + uses: repo-sync/pull-request@v2 + if: ${{ success() }} + with: + source_branch: "tgs-dmapi-update" + destination_branch: "master" + pr_title: "Automatic TGS DMAPI Update" + pr_body: "This pull request updates the TGS DMAPI to the latest version. Please note any changes that may be breaking or unimplemented in your codebase by checking what changes are in the definitions file: code/__DEFINES/tgs.dm before merging.\n\n${{ steps.dmapi-update.outputs.release-notes }}" + pr_label: "Tools" + pr_allow_empty: false + github_token: ${{ steps.app-token-generation.outputs.token || secrets.GITHUB_TOKEN }} diff --git a/.prettierignore b/.prettierignore index 2b7500b2316..b4e6fd6e264 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,19 @@ -# We don't want prettier to run on anything outside of the TGUI folder, so we have to do this. -/* +# Directories +changelogs +data +font-awesome +jquery +juke -# We want it to run into the TGUI folder, however. -!/tgui +## Tgui +node_modules +.yarn +# Avoid running on any bundles. +tgui/public +# Running it on tgui.html is fine, however. +!/tgui/public/tgui.html +# Specific files +package-lock.json +# File names / types +*.min.* +*.pnp.* diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 00000000000..ce6d6543462 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1 @@ +# This file is okay being empty as it will tell prettier to run in the repo diff --git a/.vscode/launch.json b/.vscode/launch.json index 0fc7fd3e1cc..d87097ad419 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -82,10 +82,7 @@ "request": "launch", "program": "${command:dreammaker.returnDreamDaemonPath}", "cwd": "${workspaceRoot}", - "args": [ - "${command:dreammaker.getFilenameDmb}", - "-trusted" - ], + "args": ["${command:dreammaker.getFilenameDmb}", "-trusted"], "preLaunchTask": "Build All" }, { @@ -94,10 +91,7 @@ "request": "launch", "program": "${command:dreammaker.returnDreamDaemonPath}", "cwd": "${workspaceRoot}", - "args": [ - "${command:dreammaker.getFilenameDmb}", - "-trusted" - ], + "args": ["${command:dreammaker.getFilenameDmb}", "-trusted"], "preLaunchTask": "Build All (low memory mode)" }, { diff --git a/.vscode/settings.json b/.vscode/settings.json index ff41d606550..e433b4a4674 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,7 @@ "eslint.workingDirectories": ["./tgui"], "prettier.prettierPath": "./tgui/.yarn/sdks/prettier/index.cjs", "typescript.tsdk": "./tgui/.yarn/sdks/typescript/lib", - "typescript.enablePromptUseWorkspaceTsdk": true, + "typescript.enablePromptUseWorkspaceTsdk": true, "search.exclude": { "**/.yarn": true, "**/.pnp.*": true diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ffc67db7552..9e2fbce3cfc 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,11 +12,7 @@ "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build", "isDefault": true @@ -37,11 +33,7 @@ "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -51,21 +43,27 @@ { "type": "process", "command": "tools/build/build", - "args": ["-DTESTING","-DREAGENTS_TESTING","-DTIMER_DEBUG","-DREFERENCE_DOING_IT_LIVE"], + "args": [ + "-DTESTING", + "-DREAGENTS_TESTING", + "-DTIMER_DEBUG", + "-DREFERENCE_DOING_IT_LIVE" + ], "windows": { "command": ".\\tools\\build\\build.bat", - "args": ["-DTESTING","-DREAGENTS_TESTING","-DTIMER_DEBUG","-DREFERENCE_DOING_IT_LIVE"] + "args": [ + "-DTESTING", + "-DREAGENTS_TESTING", + "-DTIMER_DEBUG", + "-DREFERENCE_DOING_IT_LIVE" + ] }, "options": { "env": { "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -75,21 +73,29 @@ { "type": "process", "command": "tools/build/build", - "args": ["-DLOWMEMORYMODE","-DTESTING","-DREAGENTS_TESTING","-DTIMER_DEBUG","-DREFERENCE_DOING_IT_LIVE"], + "args": [ + "-DLOWMEMORYMODE", + "-DTESTING", + "-DREAGENTS_TESTING", + "-DTIMER_DEBUG", + "-DREFERENCE_DOING_IT_LIVE" + ], "windows": { "command": ".\\tools\\build\\build.bat", - "args": ["-DLOWMEMORYMODE","-DTESTING","-DREAGENTS_TESTING","-DTIMER_DEBUG","-DREFERENCE_DOING_IT_LIVE"] + "args": [ + "-DLOWMEMORYMODE", + "-DTESTING", + "-DREAGENTS_TESTING", + "-DTIMER_DEBUG", + "-DREFERENCE_DOING_IT_LIVE" + ] }, "options": { "env": { "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -99,21 +105,17 @@ { "type": "process", "command": "tools/build/build", - "args": ["-DTESTING","-DMAP_TEST"], + "args": ["-DTESTING", "-DMAP_TEST"], "windows": { "command": ".\\tools\\build\\build.bat", - "args": ["-DTESTING","-DMAP_TEST"] + "args": ["-DTESTING", "-DMAP_TEST"] }, "options": { "env": { "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -123,9 +125,7 @@ { "type": "dreammaker", "dme": "tgstation.dme", - "problemMatcher": [ - "$dreammaker" - ], + "problemMatcher": ["$dreammaker"], "group": "build", "label": "dm: build - tgstation.dme" }, @@ -140,10 +140,7 @@ "windows": { "command": ".\\bin\\tgui-build.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: build" }, @@ -153,10 +150,7 @@ "windows": { "command": ".\\bin\\tgui-dev.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: dev server" }, @@ -166,10 +160,7 @@ "windows": { "command": ".\\bin\\tgui-bench.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: bench" }, @@ -179,10 +170,7 @@ "windows": { "command": ".\\bin\\tgui-sonar.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: sonar" }, @@ -192,10 +180,7 @@ "windows": { "command": ".\\bin\\tgfont.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: rebuild tgfont" } diff --git a/README.md b/README.md index b5ae10e62c1..e4fc90c6eb1 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ [![resentment](.github/images/badges/built-with-resentment.svg)](.github/images/comics/131-bug-free.png) [![technical debt](.github/images/badges/contains-technical-debt.svg)](.github/images/comics/106-tech-debt-modified.png) [![forinfinityandbyond](.github/images/badges/made-in-byond.gif)](https://www.reddit.com/r/SS13/comments/5oplxp/what_is_the_main_problem_with_byond_as_an_engine/dclbu1a) -| Website | Link | -|---------------------------|------------------------------------------------| -| Git / GitHub cheatsheet | [https://www.notion.so/Git-GitHub-61bc81766b2e4c7d9a346db3078ce833](https://www.notion.so/Git-GitHub-61bc81766b2e4c7d9a346db3078ce833) | -| Guide to Modularization | [./modular_skyrat/readme.md](./modular_skyrat/readme.md) | -| Website | [https://wiki.bubberstation.org/index.php?title=Main_Page](https://wiki.bubberstation.org/index.php?title=Main_Page) | -| Code | [https://github.com/Bubberstation/Bubberstation](https://github.com/Bubberstation/Bubberstation) | -| Wiki | [https://tgstation13.org/wiki/Main_Page](https://tgstation13.org/wiki/Main_Page) | -| Codedocs | [https://skyrat-ss13.github.io/Skyrat-tg/](https://skyrat-ss13.github.io/Skyrat-tg/) | -| Bubberstation Discord | [https://discord.gg/x4CVEHy6u7](https://discord.gg/x4CVEHy6u7) | -| Coderbus Discord | [https://discord.gg/Vh8TJp9](https://discord.gg/Vh8TJp9) | +| Website | Link | +| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| Git / GitHub cheatsheet | [https://www.notion.so/Git-GitHub-61bc81766b2e4c7d9a346db3078ce833](https://www.notion.so/Git-GitHub-61bc81766b2e4c7d9a346db3078ce833) | +| Guide to Modularization | [./modular_skyrat/readme.md](./modular_skyrat/readme.md) | +| Website | [https://wiki.bubberstation.org/index.php?title=Main_Page](https://wiki.bubberstation.org/index.php?title=Main_Page) | +| Code | [https://github.com/Bubberstation/Bubberstation](https://github.com/Bubberstation/Bubberstation) | +| Wiki | [https://tgstation13.org/wiki/Main_Page](https://tgstation13.org/wiki/Main_Page) | +| Codedocs | [https://skyrat-ss13.github.io/Skyrat-tg/](https://skyrat-ss13.github.io/Skyrat-tg/) | +| Bubberstation Discord | [https://discord.gg/x4CVEHy6u7](https://discord.gg/x4CVEHy6u7) | +| Coderbus Discord | [https://discord.gg/Vh8TJp9](https://discord.gg/Vh8TJp9) | This is Bubberstation's fork of TG. Originally forked from Skyrat. @@ -24,10 +24,12 @@ Space Station 13 is a paranoia-laden round-based roleplaying game set against th ## Contribution Rules and Guidelines **1. Do Not Be A Dick** + - The Bubberstation main repository is maintained by and contributed to by volunteers and hobbiests. You are not entitled to our time and energy. We reserve the right to permanently remove anyone who does not show both our contributor's and maintainer's common decency. - Bubberstation does not operate a strict "goodboy" points system or have defined goals, and anyone is welcome to contribute to this project. That being said, the maintainers of this project are free to curate comments as seen fit to uphold a respectful environment. **2. The Licensing is Non-negotiable** + - You are free to take, redistribute, modify, and readapt any code or commit found on this repository. - All code files are under **GNU AGPL V3** - All asset files (images and sound) are **CC-BY-SA 3.0** unless otherwise stated @@ -40,7 +42,7 @@ Space Station 13 is a paranoia-laden round-based roleplaying game set against th - Modifications or adaptions must disclose the source, the author, and [any changes you've made](https://wiki.creativecommons.org/wiki/License_Versions#Modifications_and_adaptations_must_be_indicated). - Goonstation code is incompatible with this codebase and will not be accepted. -*Credit: [Goonstation contribution guidelines](https://hackmd.io/@goonstation/docs/%2F%40goonstation%2Fcontribute#What-if-I-change-my-mind-about-my-contributions-being-published)* +_Credit: [Goonstation contribution guidelines](https://hackmd.io/@goonstation/docs/%2F%40goonstation%2Fcontribute#What-if-I-change-my-mind-about-my-contributions-being-published)_ ## Modularization and codedocs note @@ -89,6 +91,6 @@ See LICENSE and GPLv3.txt for more details. The TGS DMAPI is licensed as a subproject under the MIT license. The TGS DMAPI is licensed as a subproject under the MIT license. -See the footer of [code/__DEFINES/tgs.dm](./code/__DEFINES/tgs.dm) and [code/modules/tgs/LICENSE](./code/modules/tgs/LICENSE) for the MIT license. +See the footer of [code/\_\_DEFINES/tgs.dm](./code/__DEFINES/tgs.dm) and [code/modules/tgs/LICENSE](./code/modules/tgs/LICENSE) for the MIT license. All assets including icons and sound are under a [Creative Commons 3.0 BY-SA license](https://creativecommons.org/licenses/by-sa/3.0/) unless otherwise indicated. diff --git a/SQL/database_changelog.md b/SQL/database_changelog.md index 7654210aa87..def6732b205 100644 --- a/SQL/database_changelog.md +++ b/SQL/database_changelog.md @@ -7,11 +7,13 @@ The latest database version is 5.34 (for bubberstation) (5.32 for /tg/); The que ```sql INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 34); ``` + or ```sql INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 34); ``` + In any query remember to add a prefix to the table names if you use one. --- @@ -45,7 +47,8 @@ CREATE TABLE `manifest` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ``` ------------------------------------------------------ +--- + Version 5.30, 1 May 2025, by Rengan Adds `crime_desc` field to the `citation` table to save the description of the crime. @@ -53,7 +56,9 @@ Adds `crime_desc` field to the `citation` table to save the description of the c ALTER TABLE `citation` ADD COLUMN `crime_desc` TEXT NULL DEFAULT NULL AFTER `crime`; ``` ------------------------------------------------------ + +--- + Version 5.29, 4 February 2024, by Tiviplus Fixed admin rank table flags being capped at 16 in the DB instead of 24 (byond max) @@ -63,7 +68,9 @@ ALTER TABLE `admin_ranks` MODIFY COLUMN `exclude_flags` mediumint(5) unsigned NOT NULL, MODIFY COLUMN `can_edit_flags` mediumint(5) unsigned NOT NULL; ``` ------------------------------------------------------ + +--- + Version 5.28, 1 November 2024, by Ghommie Added `fish_progress` as the first 'progress' subtype of 'datum/award/scores' @@ -75,9 +82,12 @@ CREATE TABLE `fish_progress` ( PRIMARY KEY (`ckey`,`progress_entry`) ) ENGINE=InnoDB; ``` ------------------------------------------------------ + +--- + Version 5.27, 26 April 2024, by zephyrtfa Add the ip intel whitelist table + ```sql DROP TABLE IF EXISTS `ipintel_whitelist`; /*!40101 SET @saved_cs_client = @@character_set_client */; @@ -89,7 +99,9 @@ CREATE TABLE `ipintel_whitelist` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; ``` ------------------------------------------------------ + +--- + Version 5.29, 08 January 2024, by Useroth Add a new table for age-checking purposes. Optional if you don't ever intend to use the age prompt. @@ -102,29 +114,36 @@ CREATE TABLE `player_dob` ( ); ``` ------------------------------------------------------ +--- + Version 5.28, 03 December 2023, by distributivgesetz Set the default value of cloneloss to 0, as it's obsolete and it won't be set by blackbox anymore. + ```sql ALTER TABLE `death` MODIFY COLUMN `cloneloss` SMALLINT(5) UNSIGNED DEFAULT '0'; ``` ------------------------------------------------------ +--- + Version 5.27, 27 September 2023, by Jimmyl Removes the text_adventures table because it is no longer used + ```sql DROP TABLE IF EXISTS `text_adventures`; ``` ------------------------------------------------------ +--- + Version 5.26, 17 May 2023, by LemonInTheDark Modified the library action table to fit ckeys properly, and to properly store ips. + ```sql ALTER TABLE `library_action` MODIFY COLUMN `ckey` varchar(32) NOT NULL; ALTER TABLE `library_action` MODIFY COLUMN `ip_addr` int(10) unsigned NOT NULL; ``` ------------------------------------------------------ +--- + Version 5.25, 28 December 2022, by Mothblocks Added `tutorial_completions` to mark what ckeys have completed contextual tutorials. @@ -137,14 +156,16 @@ CREATE TABLE `tutorial_completions` ( UNIQUE INDEX `ckey_tutorial_unique` (`ckey`, `tutorial_key`)); ``` ------------------------------------------------------ +--- + Version 5.24, 22 December 2021, by Mothblocks Fixes a bug in `telemetry_connections` that limited the range of IPs. ```sql ALTER TABLE `telemetry_connections` MODIFY COLUMN `address` INT(10) UNSIGNED NOT NULL; ``` ------------------------------------------------------ + +--- Version 5.23, 15 December 2021, by Mothblocks Adds `telemetry_connections` table for tracking tgui telemetry. @@ -162,7 +183,8 @@ CREATE TABLE `telemetry_connections` ( UNIQUE INDEX `unique_constraints` (`ckey` , `telemetry_ckey` , `address` , `computer_id`) ); ``` ------------------------------------------------------ + +--- Version 5.22, 11 November 2021, by Mothblocks Adds `admin_ckey` field to the `known_alts` table to track who added what. @@ -172,7 +194,8 @@ ALTER TABLE `known_alts` ADD COLUMN `admin_ckey` VARCHAR(32) NOT NULL DEFAULT '*no key*' AFTER `ckey2`; ``` ------------------------------------------------------ +--- + Version 5.21, 10 November 2021, by WalterMeldron Adds an urgent column to tickets for ahelps marked as urgent. @@ -180,7 +203,8 @@ Adds an urgent column to tickets for ahelps marked as urgent. ALTER TABLE `ticket` ADD COLUMN `urgent` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `sender`; ``` ------------------------------------------------------ +--- + Version 5.20, 1 November 2021, by Mothblocks Added `known_alts` table for tracking who not to create suspicious logins for. @@ -194,7 +218,8 @@ CREATE TABLE `known_alts` ( ); ``` ------------------------------------------------------ +--- + Version 5.19, 8 October 2021, by MrStonedOne + Mothblocks Changes any table that requrired a NOT NULL round ID to now accept NULL. In the BSQL past, these were handled as 0, but in the move to rust-g this behavior was lost. @@ -213,7 +238,8 @@ ALTER TABLE `player` CHANGE `lastseen_round_id` `lastseen_round_id` INT(11) UNSI ALTER TABLE `ticket` CHANGE `round_id` `round_id` INT(11) UNSIGNED NULL; ``` ------------------------------------------------------ +--- + Version 5.18, 23 August 2021, by GoldenAlpharex Added `discord_report` column to the `ban table` @@ -221,7 +247,8 @@ Added `discord_report` column to the `ban table` `discord_reported` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', /* SKYRAT EDIT - Labelling bans for ease of reporting them over Discord. */ ``` ------------------------------------------------------ +--- + Version 5.17, 31 July 2021, by Atlanta-Ned Added `library_action` table for tracking reported library books and actions taken on them. @@ -239,8 +266,10 @@ CREATE TABLE `library_action` ( ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; ``` +--- + +--- ------------------------------------------------------ Version 5.16, 2 June 2021, by Mothblocks Added verified admin connection log used for 2FA @@ -256,7 +285,7 @@ CREATE TABLE `admin_connections` ( UNIQUE INDEX `unique_constraints` (`ckey`, `ip`, `cid`)); ``` ------------------------------------------------------ +--- Version 5.15, xx May 2021, by Anturke Added exploration drone adventure table @@ -273,7 +302,7 @@ CREATE TABLE `text_adventures` ( ) ENGINE=InnoDB; ``` ------------------------------------------------------ +--- Version 5.14, 30 April 2021, by Atlanta Ned Added the `citation` table for tracking security citations in the database. @@ -302,7 +331,7 @@ AUTO_INCREMENT=1 ; ``` ------------------------------------------------------ +--- Version 5.13, 9 March, 2021, by Useroth @@ -335,8 +364,7 @@ ALTER TABLE `round` ADD COLUMN `server_name` VARCHAR(32) DEFAULT NULL AFTER `end_datetime`; ``` - ------------------------------------------------------ +--- Version 5.12, 29 December 2020, by Missfox Modified table `messages`, adding column `playtime` to show the user's playtime when the note was created. @@ -344,12 +372,12 @@ Modified table `messages`, adding column `playtime` to show the user's playtime ```sql ALTER TABLE `messages` ADD `playtime` INT(11) NULL DEFAULT(NULL) AFTER `severity` ``` + ======= Version 5.12, 29 December 2020, by Missfox Modified table `messages`, adding column `playtime` to show the user's playtime when the note was created. -ALTER TABLE `messages` ADD `playtime` INT(11) NULL DEFAULT(NULL) AFTER `severity` ------------------------------------------------------ +## ALTER TABLE `messages` ADD `playtime` INT(11) NULL DEFAULT(NULL) AFTER `severity` Version 5.11, 7 September 2020, by bobbahbrown, MrStonedOne, and Jordie0608 (Updated 26 March 2021 by bobbahbrown) @@ -363,7 +391,7 @@ ALTER TABLE `ticket` ADD INDEX `idx_ticket_act_time_rid` (`action`, `timestamp`, `round_id`); ``` ------------------------------------------------------ +--- Version 5.10, 7 August 2020, by oranges @@ -392,7 +420,7 @@ ALTER TABLE `player` DROP COLUMN `discord_id`; COMMIT; ``` ------------------------------------------------------ +--- Version 5.9, 19 April 2020, by Jordie0608 Updates and improvements to poll handling. @@ -435,7 +463,7 @@ $$ DELIMITER ; ``` ------------------------------------------------------ +--- Version 5.8, 7 April 2020, by Jordie0608 Modified table `messages`, adding column `deleted_ckey` to record who deleted a message. @@ -444,7 +472,7 @@ Modified table `messages`, adding column `deleted_ckey` to record who deleted a ALTER TABLE `messages` ADD COLUMN `deleted_ckey` VARCHAR(32) NULL DEFAULT NULL AFTER `deleted`; ``` ------------------------------------------------------ +--- Version 5.7, 10 January 2020 by Atlanta-Ned Added ticket table for tracking ahelp tickets in the database. @@ -466,7 +494,7 @@ CREATE TABLE `ticket` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` ------------------------------------------------------ +--- Version 5.6, 6 December 2019 by Anturke Added achievement_name and achievement_description columns to achievement_metadata table. @@ -475,7 +503,7 @@ Added achievement_name and achievement_description columns to achievement_metada ALTER TABLE `achievement_metadata` ADD COLUMN (`achievement_name` VARCHAR(64) NULL DEFAULT NULL, `achievement_description` VARCHAR(512) NULL DEFAULT NULL); ``` ------------------------------------------------------ +--- Version 5.5, 26 October 2019 by Anturke Added achievement_metadata table. @@ -490,11 +518,11 @@ CREATE TABLE `achievement_metadata` ( ) ENGINE=InnoDB; ``` ------------------------------------------------------ +--- Version 5.4, 5 October 2019 by Anturke Added achievements table. -See hub migration verb in _achievement_data.dm for details on migrating. +See hub migration verb in \_achievement_data.dm for details on migrating. ```sql CREATE TABLE `achievements` ( @@ -506,7 +534,7 @@ CREATE TABLE `achievements` ( ) ENGINE=InnoDB; ``` ----------------------------------------------------- +--- Version 5.3, 6 July 2019, by Atlanta-Ned Added a `feedback` column to the admin table, used for linking to individual admin feedback threads. Currently this is only used for statistics tracking tools such as Statbus and isn't used by the game. @@ -515,7 +543,7 @@ Added a `feedback` column to the admin table, used for linking to individual adm ALTER TABLE `admin` ADD `feedback` VARCHAR(255) NULL DEFAULT NULL AFTER `rank`; ``` ----------------------------------------------------- +--- Version 5.2, 30 May 2019, by AffectedArc07 Added a field to the `player` table to track ckey and discord ID relationships @@ -524,7 +552,8 @@ Added a field to the `player` table to track ckey and discord ID relationships ALTER TABLE `player` ADD COLUMN `discord_id` BIGINT NULL DEFAULT NULL AFTER `flags`; ``` ----------------------------------------------------- + +--- Version 5.1, 25 Feb 2018, by MrStonedOne Added four tables to enable storing of stickybans in the database since byond can lose them, and to enable disabling stickybans for a round without depending on a crash free round. Existing stickybans are automagically imported to the tables. @@ -564,7 +593,7 @@ CREATE TABLE `stickyban_matched_cid` ( ) ENGINE=InnoDB; ``` ----------------------------------------------------- +--- Version 5.0, 28 October 2018, by Jordie0608 Modified ban table to remove the need for the `bantype` column, a python script is used to migrate data to this new format. @@ -605,21 +634,21 @@ CREATE TABLE `ban` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ``` ----------------------------------------------------- +--- Version 4.7, 18 August 2018, by CitrusGender Modified table `messages`, adding column `severity` to classify notes based on their severity. ALTER TABLE `messages` ADD `severity` enum('high','medium','minor','none') DEFAULT NULL AFTER `expire_timestamp` ----------------------------------------------------- +--- Version 4.6, 11 August 2018, by Jordie0608 Modified table `messages`, adding column `expire_timestamp` to allow for auto-"deleting" messages. ALTER TABLE `messages` ADD `expire_timestamp` DATETIME NULL DEFAULT NULL AFTER `secret`; ----------------------------------------------------- +--- Version 4.5, 9 July 2018, by Jordie0608 Modified table `player`, adding column `byond_key` to store a user's key along with their ckey. @@ -627,20 +656,20 @@ To populate this new column run the included script 'populate_key_2018-07', see ALTER TABLE `player` ADD `byond_key` VARCHAR(32) DEFAULT NULL AFTER `ckey`; ----------------------------------------------------- +--- Version 4.4, 9 May 2018, by Jordie0608 Modified table `round`, renaming column `start_datetime` to `initialize_datetime` and `end_datetime` to `shutdown_datetime` and adding columns to replace both under the same name in preparation for changes to TGS server initialization. ALTER TABLE `round` - ALTER `start_datetime` DROP DEFAULT; +ALTER `start_datetime` DROP DEFAULT; ALTER TABLE `round` - CHANGE COLUMN `start_datetime` `initialize_datetime` DATETIME NOT NULL AFTER `id`, - ADD COLUMN `start_datetime` DATETIME NULL DEFAULT NULL AFTER `initialize_datetime`, - CHANGE COLUMN `end_datetime` `shutdown_datetime` DATETIME NULL DEFAULT NULL AFTER `start_datetime`, - ADD COLUMN `end_datetime` DATETIME NULL DEFAULT NULL AFTER `shutdown_datetime`; +CHANGE COLUMN `start_datetime` `initialize_datetime` DATETIME NOT NULL AFTER `id`, +ADD COLUMN `start_datetime` DATETIME NULL DEFAULT NULL AFTER `initialize_datetime`, +CHANGE COLUMN `end_datetime` `shutdown_datetime` DATETIME NULL DEFAULT NULL AFTER `start_datetime`, +ADD COLUMN `end_datetime` DATETIME NULL DEFAULT NULL AFTER `shutdown_datetime`; ----------------------------------------------------- +--- Version 4.3, 9 May 2018, by MrStonedOne Added table `role_time_log` and triggers `role_timeTlogupdate`, `role_timeTloginsert` and `role_timeTlogdelete` to update it from changes to `role_time` @@ -650,12 +679,15 @@ CREATE TABLE `role_time_log` ( `id` BIGINT NOT NULL AUTO_INCREMENT , `ckey` VARC DELIMITER $$ CREATE TRIGGER `role_timeTlogupdate` AFTER UPDATE ON `role_time` FOR EACH ROW BEGIN INSERT into role_time_log (ckey, job, delta) VALUES (NEW.CKEY, NEW.job, NEW.minutes-OLD.minutes); END + $$ CREATE TRIGGER `role_timeTloginsert` AFTER INSERT ON `role_time` FOR EACH ROW BEGIN INSERT into role_time_log (ckey, job, delta) VALUES (NEW.ckey, NEW.job, NEW.minutes); END $$ -CREATE TRIGGER `role_timeTlogdelete` AFTER DELETE ON `role_time` FOR EACH ROW BEGIN INSERT into role_time_log (ckey, job, delta) VALUES (OLD.ckey, OLD.job, 0-OLD.minutes); + +CREATE TRIGGER `role_timeTlogdelete` AFTER DELETE ON `role_time` FOR EACH ROW BEGIN INSERT into role_time_log (ckey, job, delta) VALUES (OLD.ckey, OLD.job, 0-OLD.minutes); END + $$ DELIMITER ; ---------------------------------------------------- @@ -1075,3 +1107,4 @@ UPDATE erro_library SET deleted = 1 WHERE id = someid (Replace someid with the id of the book you want to soft delete.) ---------------------------------------------------- +$$ diff --git a/_maps/metastation.json b/_maps/metastation.json index 86f73dc4e5f..e15f3ad7385 100644 --- a/_maps/metastation.json +++ b/_maps/metastation.json @@ -11,7 +11,10 @@ }, "job_changes": { "Cook": { - "additional_cqc_areas": ["/area/station/service/bar", "/area/station/commons/lounge"] + "additional_cqc_areas": [ + "/area/station/service/bar", + "/area/station/commons/lounge" + ] } } } diff --git a/_maps/safehouses/README.md b/_maps/safehouses/README.md index 17882fd96da..8d64502343b 100644 --- a/_maps/safehouses/README.md +++ b/_maps/safehouses/README.md @@ -4,9 +4,9 @@ 1. Create a new map inside the `_maps\safe_houses` folder using the TGM format. 2. Create a new dm file inside `modules\bitrunning\virtual_domain\safe_houses` folder.. -4. Place exit and goal landmarks (obj/effect/landmark/bitrunning/..). Generally, 3 exits and 2 goals are ok. -5. Ideally, leave 3 spaces for gear. This has usually been xy [1x1] [1x2] [1x3] -6. Place the modular map connector at the bottom left tile. +3. Place exit and goal landmarks (obj/effect/landmark/bitrunning/..). Generally, 3 exits and 2 goals are ok. +4. Ideally, leave 3 spaces for gear. This has usually been xy [1x1] [1x2] [1x3] +5. Place the modular map connector at the bottom left tile. ## Notes @@ -14,5 +14,4 @@ - Consider that avatars are not invincible and still require air. If you're making a safe house, it should start with an area that accommodates for this. - For compatibility, your safe house should have a route open from the top center xy [3x0] of the map. - If you want a custom safehouse for a custom map with no modularity, no problem. Make whatever sizes you want, just ensure there are exit and goal effects placed. -- Some maps can alter what is spawned into the safehouse by placing objects in the safehouse area. I'm using the left corner, starting from the top, for things like space gear. - +- Some maps can alter what is spawned into the safehouse by placing objects in the safehouse area. I'm using the left corner, starting from the top, for things like space gear. diff --git a/_maps/virtual_domains/README.md b/_maps/virtual_domains/README.md index f0a8a1ebfd2..f3619f02a3e 100644 --- a/_maps/virtual_domains/README.md +++ b/_maps/virtual_domains/README.md @@ -1,6 +1,7 @@ # Making new virtual domains ## REQUIRED: + 1. One way that the encrypted cache can spawn. This can be from a mob drop, a landmark (place a few, it'll pick one), or a signal landmark if you have a points system. 2. Place a virtual domain baseturf helper in each area. 3. If you're using modular safehouses, ensure that the map has ONE tile marked with the safehouse modular map loader (and set the KEY). it will need an open 7x6 area. @@ -9,12 +10,14 @@ 6. Place a virtual domain baseturf helper in each area. ## Converting an existing map + 1. Create a new map using the existing map's size - give yourself enough room to enclose it with a binary wall. There's no need for any space outside of it, so ensure that it fits and is enclosed, nothing outside of this. 2. Copy and paste the existing map into it. 3. Find an accessible area for a safehouse, 7x6. 4. Place a bottom left safehouse landmark somewhere on the map to load the safehouse. ## Notes + You shouldn't need to fully enclose your map in 15 tiles of binary filler. Using one solid wall should do the trick. For areas, ideally just one on the map and one for the safehouse. Vdoms should never last so long as to need individual area power and atmos unless you're specifically going for a gimmick. diff --git a/code/__DEFINES/README.md b/code/__DEFINES/README.md index 71ddfc1a973..70b1da1111a 100644 --- a/code/__DEFINES/README.md +++ b/code/__DEFINES/README.md @@ -1,8 +1,8 @@ -This folder is full of #define statements. They are similar to constants, +This folder is full of #define statements. They are similar to constants, but must come before any code that references them, and they do not take up memory the way constants do. -The values in this folder are NOT options. They are not for hosts to play with. +The values in this folder are NOT options. They are not for hosts to play with. Some of the values are arbitrary and only need to be different from similar constants; for example, the genetic mutation numbers in genetics.dm mean nothing, but MUST be distinct. diff --git a/code/_onclick/hud/rendering/_render_readme.md b/code/_onclick/hud/rendering/_render_readme.md index 493b9c68491..ceb822f4480 100644 --- a/code/_onclick/hud/rendering/_render_readme.md +++ b/code/_onclick/hud/rendering/_render_readme.md @@ -6,6 +6,7 @@ 4. [Render plates](#render-plates) ## Byond internal functionality + This part of the guide will assume that you have read the byond reference entry for rendering at www.byond.com/docs/ref//#/{notes}/renderer When you create an atom, this will always create an internal byond structure called an "appearance". This appearance you will likely be familiar with, as it is exposed through the /atom/var/appearance var. This appearance var holds data on how to render the object, ie what icon/icon_state/color etc it is using. Note that appearance vars will always copy, and do not hold a reference. When you update a var, for example lets pretend we add a filter, the appearance will be updated to include the filter. Note that, however, vis_contents objets are uniquely excluded from appearances. Then, when the filter is updated, the appearance will be recreated, and the atom marked as "dirty". After it has been updated, the SendMaps() function (sometimes also called maptick), which is a internal byond function that iterates over all objects in a clients view and in the clients.mob.contents, checks for "dirty" atoms, then resends any "dirty" appearances to clients as needed and unmarks them as dirty. This function is notoriously slow, but we can see its tick usage through the world.map_cpu var. We can also avoid more complex checks checking whether an object is visible on a clients screen by using the TILE_BOUND appearance flag. @@ -17,6 +18,7 @@ A) Talk to someone who has inside knowledge(like lummox) about it, most of this B) Use the undocumented debug printer which reads of data on icons rendering, this is very dense but can be useful in some cases. To use: Right click top tab -> Options & Messages -> Client -> Command -> Enter ".debug profile mapicons" and press Enter -> go to your Byond directory and find BYOND/cfg/mapicons.json . Yes this is one giant one-line json. ## Known internal snowflake + The following is an incomplete list of pitfalls that come from byond snowflake that are known, this list is obviously incomplete. 1. Transforms are very slow on clientside. This is not usually noticable, but if you start using large amounts of them it will grind you to a halt quickly, regardless of whether its on overlays or objs @@ -32,6 +34,7 @@ The following is an incomplete list of pitfalls that come from byond snowflake t 11. Displacement filter: The byond "displacement filter" does not, as the name would make you expect, use displacement maps, but instead uses normal maps. ## The rendering solution + One of the main issues with making pretty effects is how objects can only render to one plane, and how filters can only be applied to single objects. Quite simply it means we can't apply effects to multiple planes at once, and an effect to one plane only by treating it as a single unit: ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/rendering/renderpipe_old.png) @@ -52,6 +55,4 @@ Through these this allows us to treat planes as single objects, and lets us dist The rendering system uses two objects to unify planes: render_relay and render_plates. Render relays use render_target/source and the relay_render_to_plane proc to replicate the plane master on the render relay. This render relay is then rendered onto a render_plate, which is a plane master that renders the render_relays onto itself. This plate can then be hierarchically rendered with the same process until it reaches the master render_plate, which is the plate that will actually render to the player. These plates naturally in the byond style have quirks. For example, rendering to two plates will double any effects such as color or filters, and as such you need to carefully manage how you render them. Keep in mind as well that when sorting the layers for rendering on a plane that they should not be negative, this is handled automatically in relay_render_to_plane. When debugging note that mouse_opacity can act bizarrely with this method, such as only allowing you to click things that are layered over objects on a certain plane but automatically setting the mouse_opacity should be handling this. Note that if you decide to manipulate a plane with internal byond objects that you will have to manually extrapolate the vars that are set if you want to render them to another plane (See blackness plane for example), and that this is not documented anywhere. - -Good luck and godspeed with coding - - Just another contributor +Good luck and godspeed with coding - Just another contributor diff --git a/code/controllers/subsystem/dynamic/readme.md b/code/controllers/subsystem/dynamic/readme.md index ec21626945e..d59ed6215a9 100644 --- a/code/controllers/subsystem/dynamic/readme.md +++ b/code/controllers/subsystem/dynamic/readme.md @@ -7,6 +7,7 @@ Dynamic rolls threat based on a special sauce formula: > [dynamic_curve_width][/datum/controller/global_vars/var/dynamic_curve_width] \* tan((3.1416 \* (rand() - 0.5) \* 57.2957795)) + [dynamic_curve_centre][/datum/controller/global_vars/var/dynamic_curve_centre] This threat is split into two separate budgets--`round_start_budget` and `mid_round_budget`. For example, a round with 50 threat might be split into a 30 roundstart budget, and a 20 midround budget. The roundstart budget is used to apply antagonists applied on readied players when the roundstarts (`/datum/dynamic_ruleset/roundstart`). The midround budget is used for two types of rulesets: + - `/datum/dynamic_ruleset/midround` - Rulesets that apply to either existing alive players, or to ghosts. Think Blob or Space Ninja, which poll ghosts asking if they want to play as these roles. - `/datum/dynamic_ruleset/latejoin` - Rulesets that apply to the next player that joins. Think Syndicate Infiltrator, which converts a player just joining an existing round into traitor. @@ -15,14 +16,15 @@ This split is done with a similar method, known as the ["lorentz distribution"]( The process of creating these numbers occurs in `/datum/controller/subsystem/dynamic/proc/generate_threat` (for creating the threat level) and `/datum/controller/subsystem/dynamic/proc/generate_budgets` (for splitting the threat level into budgets). ## Deciding roundstart threats + In `/datum/controller/subsystem/dynamic/proc/roundstart()` (called when no admin chooses the rulesets explicitly), Dynamic uses the available roundstart budget to pick threats. This is done through the following system: - All roundstart rulesets (remember, `/datum/dynamic_ruleset/roundstart`) are put into an associative list with their weight as the values (`drafted_rules`). - Until there is either no roundstart budget left, or until there is no ruleset we can choose from with the available threat, a `pickweight` is done based on the drafted_rules. If the same threat is picked twice, it will "scale up". The meaning of this depends on the ruleset itself, using the `scaled_times` variable; traitors for instance will create more the higher they scale. - - If a ruleset is chosen with the `HIGH_IMPACT_RULESET` in its `flags`, then all other `HIGH_IMPACT_RULESET`s will be removed from `drafted_rules`. This is so that only one can ever be chosen. - - If a ruleset has `LONE_RULESET` in its `flags`, then it will be removed from `drafted_rules`. This is to ensure it will only ever be picked once. An example of this in use is Wizard, to avoid creating multiple wizards. + - If a ruleset is chosen with the `HIGH_IMPACT_RULESET` in its `flags`, then all other `HIGH_IMPACT_RULESET`s will be removed from `drafted_rules`. This is so that only one can ever be chosen. + - If a ruleset has `LONE_RULESET` in its `flags`, then it will be removed from `drafted_rules`. This is to ensure it will only ever be picked once. An example of this in use is Wizard, to avoid creating multiple wizards. - After all roundstart threats are chosen, `/datum/dynamic_ruleset/proc/picking_roundstart_rule` is called for each, passing in the ruleset and the number of times it is scaled. - - In this stage, `pre_execute` is called, which is the function that will determine what players get what antagonists. If this function returns FALSE for whatever reason (in the case of an error), then its threat is refunded. + - In this stage, `pre_execute` is called, which is the function that will determine what players get what antagonists. If this function returns FALSE for whatever reason (in the case of an error), then its threat is refunded. After this process is done, any leftover roundstart threat will be given to the existing midround budget (done in `/datum/controller/subsystem/dynamic/pre_setup()`). @@ -35,6 +37,7 @@ The frequency of midround threats is based on the midround threat of the round. These midround roll points are then equidistantly spaced across the round, starting from `midround_lower_bound` (configurable) to `midround_upper_bound` (configurable), with a +/- of `midround_roll_distance` (configurable). For example, if: + 1. `midround_lower_bound` is `10 MINUTES` 2. `midround_upper_bound` is `100 MINUTES` 3. `midround_roll_distance` is `3 MINUTES` @@ -79,7 +82,7 @@ process() -> (For each midround rule... ## Forced For latejoin, it simply sets forced_latejoin_rule -make_antag_chance(newPlayer) -> trim_candidates() -> ready(forced=TRUE) **NOTE no acceptable() call +make_antag_chance(newPlayer) -> trim_candidates() -> ready(forced=TRUE) \*\*NOTE no acceptable() call For midround, calls the below proc with forced = TRUE picking_specific_rule(ruletype,forced) -> forced OR acceptable(living_players, threat_level) -> trim_candidates() -> ready(forced) -> spend threat -> execute() @@ -89,25 +92,27 @@ picking_specific_rule(ruletype,forced) -> forced OR acceptable(living_players, t ## Ruleset acceptable(population,threat) just checks if enough threat_level for population indice. -**NOTE that we currently only send threat_level as the second arg, not threat. +\*\*NOTE that we currently only send threat_level as the second arg, not threat. ready(forced) checks if enough candidates and calls the map's map_ruleset(dynamic_ruleset) at the parent level trim_candidates() varies significantly according to the ruleset type Roundstart: All candidates are new_player mobs. Check them for standard stuff: connected, desire role, not banned, etc. -**NOTE Roundstart deals with both candidates (trimmed list of valid players) and mode.candidates (everyone readied up). Don't confuse them! +\*\*NOTE Roundstart deals with both candidates (trimmed list of valid players) and mode.candidates (everyone readied up). Don't confuse them! Latejoin: Only one candidate, the latejoiner. Standard checks. Midround: Instead of building a single list candidates, candidates contains four lists: living, dead, observing, and living antags. Standard checks in trim_list(list). Midround - Rulesets have additional types /from_ghosts: execute() -> send_applications() -> review_applications() -> finish_applications() -> finish_setup(mob/newcharacter, index) -> setup_role(role) -**NOTE: execute() here adds dead players and observers to candidates list +\*\*NOTE: execute() here adds dead players and observers to candidates list ## Configuration and variables ### Configuration + Configuration can be done through a `config/dynamic.json` file. One is provided as example in the codebase. This config file, loaded in `/datum/controller/subsystem/dynamic/pre_setup()`, directly overrides the values in the codebase, and so is perfect for making some rulesets harder/easier to get, turning them off completely, changing how much they cost, etc. The format of this file is: + ```json { "Dynamic": { @@ -142,37 +147,39 @@ The format of this file is: Note: Comments are not possible in this format, and are just in this document for the sake of readability. ### Rulesets + Rulesets have the following variables notable to developers and those interested in tuning. -- `required_candidates` - The number of people that *must be willing* (in their preferences) to be an antagonist with this ruleset. If the candidates do not meet this requirement, then the ruleset will not bother to be drafted. +- `required_candidates` - The number of people that _must be willing_ (in their preferences) to be an antagonist with this ruleset. If the candidates do not meet this requirement, then the ruleset will not bother to be drafted. - `antag_cap` - Judges the amount of antagonists to apply, for both solo and teams. Note that some antagonists (such as traitors, lings, heretics, etc) will add more based on how many times they've been scaled. Written as a linear equation--ceil(x/denominator) + offset, or as a fixed constant. If written as a linear equation, will be in the form of `list("denominator" = denominator, "offset" = offset)`. - - Examples include: - - Traitor: `antag_cap = list("denominator" = 24)`. This means that for every 24 players, 1 traitor will be added (assuming no scaling). - - Nuclear Emergency: `antag_cap = list("denominator" = 18, "offset" = 1)`. For every 18 players, 1 nuke op will be added. Starts at 1, meaning at 30 players, 3 nuke ops will be created, rather than 2. - - Revolution: `antag_cap = 3`. There will always be 3 rev-heads, no matter what. + - Examples include: + - Traitor: `antag_cap = list("denominator" = 24)`. This means that for every 24 players, 1 traitor will be added (assuming no scaling). + - Nuclear Emergency: `antag_cap = list("denominator" = 18, "offset" = 1)`. For every 18 players, 1 nuke op will be added. Starts at 1, meaning at 30 players, 3 nuke ops will be created, rather than 2. + - Revolution: `antag_cap = 3`. There will always be 3 rev-heads, no matter what. - `minimum_required_age` - The minimum age in order to apply for the ruleset. - `weight` - How likely this ruleset is to be picked. A higher weight results in a higher chance of drafting. - `cost` - The initial cost of the ruleset. This cost is taken from either the roundstart or midround budget, depending on the ruleset. -- `scaling_cost` - Cost for every *additional* application of this ruleset. - - Suppose traitors has a `cost` of 8, and a `scaling_cost` of 5. This means that buying 1 application of the traitor ruleset costs 8 threat, but buying two costs 13 (8 + 5). Buying it a third time is 18 (8 + 5 + 5), etc. +- `scaling_cost` - Cost for every _additional_ application of this ruleset. + - Suppose traitors has a `cost` of 8, and a `scaling_cost` of 5. This means that buying 1 application of the traitor ruleset costs 8 threat, but buying two costs 13 (8 + 5). Buying it a third time is 18 (8 + 5 + 5), etc. - `pop_per_requirement` - The range of population each value in `requirements` represents. By default, this is 6. - - If the value is five the range is 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+. - - If it is six the range is 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+. - - If it is seven the range is 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+. -- `requirements` - A list that represents, per population range (see: `pop_per_requirement`), how much threat is required to *consider* this ruleset. This is independent of how much it'll actually cost. This uses *threat level*, not the budget--meaning if a round has 50 threat level, but only 10 points of round start threat, a ruleset with a requirement of 40 can still be picked if it can be bought. - - Suppose wizard has a `requirements` of `list(90,90,70,40,30,20,10,10,10,10)`. This means that, at 0-5 and 6-11 players, A station must have 90 threat in order for a wizard to be possible. At 12-17, 70 threat is required instead, etc. -- `restricted_roles` - A list of jobs that *can't* be drafted by this ruleset. For example, cyborgs cannot be changelings, and so are in the `restricted_roles`. -- `protected_roles` - Serves the same purpose of `restricted_roles`, except it can be turned off through configuration (`protect_roles_from_antagonist`). For example, security officers *shouldn't* be made traitor, so they are in Traitor's `protected_roles`. - - When considering putting a role in `protected_roles` or `restricted_roles`, the rule of thumb is if it is *technically infeasible* to support that job in that role. There's no *technical* reason a security officer can't be a traitor, and so they are simply in `protected_roles`. There *are* technical reasons a cyborg can't be a changeling, so they are in `restricted_roles` instead. + - If the value is five the range is 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+. + - If it is six the range is 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+. + - If it is seven the range is 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+. +- `requirements` - A list that represents, per population range (see: `pop_per_requirement`), how much threat is required to _consider_ this ruleset. This is independent of how much it'll actually cost. This uses _threat level_, not the budget--meaning if a round has 50 threat level, but only 10 points of round start threat, a ruleset with a requirement of 40 can still be picked if it can be bought. + - Suppose wizard has a `requirements` of `list(90,90,70,40,30,20,10,10,10,10)`. This means that, at 0-5 and 6-11 players, A station must have 90 threat in order for a wizard to be possible. At 12-17, 70 threat is required instead, etc. +- `restricted_roles` - A list of jobs that _can't_ be drafted by this ruleset. For example, cyborgs cannot be changelings, and so are in the `restricted_roles`. +- `protected_roles` - Serves the same purpose of `restricted_roles`, except it can be turned off through configuration (`protect_roles_from_antagonist`). For example, security officers _shouldn't_ be made traitor, so they are in Traitor's `protected_roles`. + - When considering putting a role in `protected_roles` or `restricted_roles`, the rule of thumb is if it is _technically infeasible_ to support that job in that role. There's no _technical_ reason a security officer can't be a traitor, and so they are simply in `protected_roles`. There _are_ technical reasons a cyborg can't be a changeling, so they are in `restricted_roles` instead. This is not a complete list--search "configurable" in this README to learn more. ### Dynamic The "Dynamic" key has the following configurable values: + - `pop_per_requirement` - The default value of `pop_per_requirement` for any ruleset that does not explicitly set it. Defaults to 6. - `latejoin_delay_min`, `latejoin_delay_max` - The time range, in deciseconds (take your seconds, and multiply by 10), for a latejoin to attempt rolling. Once this timer is finished, a new one will be created within the same range. - - Suppose you have a `latejoin_delay_min` of 600 (60 seconds, 1 minute) and a `latejoin_delay_max` of 1800 (180 seconds, 3 minutes). Once the round starts, a random number in this range will be picked--let's suppose 1.5 minutes. After 1.5 minutes, Dynamic will decide if a latejoin threat should be created (a probability of `/datum/controller/subsystem/dynamic/proc/get_injection_chance()`). Regardless of its decision, a new timer will be started within the range of 1 to 3 minutes, repeatedly. + - Suppose you have a `latejoin_delay_min` of 600 (60 seconds, 1 minute) and a `latejoin_delay_max` of 1800 (180 seconds, 3 minutes). Once the round starts, a random number in this range will be picked--let's suppose 1.5 minutes. After 1.5 minutes, Dynamic will decide if a latejoin threat should be created (a probability of `/datum/controller/subsystem/dynamic/proc/get_injection_chance()`). Regardless of its decision, a new timer will be started within the range of 1 to 3 minutes, repeatedly. - `threat_curve_centre` - A number between -5 and +5. A negative value will give a more peaceful round and a positive value will give a round with higher threat. - `threat_curve_width` - A number between 0.5 and 4. Higher value will favour extreme rounds and lower value rounds closer to the average. - `roundstart_split_curve_centre` - A number between -5 and +5. Equivalent to threat_curve_centre, but for the budget split. A negative value will weigh towards midround rulesets, and a positive value will weight towards roundstart ones. @@ -180,9 +187,10 @@ The "Dynamic" key has the following configurable values: - `random_event_hijack_minimum` - The minimum amount of time for antag random events to be hijacked. (See [Random Event Hijacking](#random-event-hijacking)) - `random_event_hijack_maximum` - The maximum amount of time for antag random events to be hijacked. (See [Random Event Hijacking](#random-event-hijacking)) - `hijacked_random_event_injection_chance` - The amount of injection chance to give to Dynamic when a random event is hijacked. (See [Random Event Hijacking](#random-event-hijacking)) -- `max_threat_level` - Sets the maximum amount of threat that can be rolled. Defaults to 100. You should only use this to *lower* the maximum threat, as raising it higher will not do anything. +- `max_threat_level` - Sets the maximum amount of threat that can be rolled. Defaults to 100. You should only use this to _lower_ the maximum threat, as raising it higher will not do anything. ## Random Event "Hijacking" + Random events have the potential to be hijacked by Dynamic to keep the pace of midround injections, while also allowing greenshifts to contain some antagonists. `/datum/round_event_control/dynamic_should_hijack` is a variable to random events to allow Dynamic to hijack them, and defaults to FALSE. This is set to TRUE for random events that spawn antagonists. diff --git a/code/controllers/subsystem/networks/README.md b/code/controllers/subsystem/networks/README.md index f1ec85a6d43..0230293d1f7 100644 --- a/code/controllers/subsystem/networks/README.md +++ b/code/controllers/subsystem/networks/README.md @@ -1,4 +1,5 @@ # Networks: Subsystems that are conceptually networked IN-GAME + ### Specifically, these subsystems are for in-game mechanics that are intended to rely on a digital/radio/physical network, such as telecomms servers or the powernet The intent of this folder categorization is to be able to quickly reference what are intended to be in-game networks, vs what is logically networked inside the code. diff --git a/code/datums/ai/README.md b/code/datums/ai/README.md index b6477ba52fb..fb4022775e8 100644 --- a/code/datums/ai/README.md +++ b/code/datums/ai/README.md @@ -15,11 +15,12 @@ If behaviors are selected, and the AI is in range, it will try to perform them. They also hold data for any of the actions they might need to use, such as cooldowns, whether or not they're currently fighting, etcetera this is stored in the blackboard, more information on that below. ### Blackboard + The blackboard is an associated list keyed with strings and with values of whatever you want. These store information the mob has such as "Am I attacking someone", "Do I have a weapon". By using an associated list like this, no data needs to be stored on the actions themselves, and you could make actions that work on multiple ai controllers if you so pleased by making the key to use a variable. ## AI Behavior -AI behaviors are the actions an AI can take. These can range from "Do an emote" to "Attack this target until he is dead". They are singletons and should contain nothing but static data. Any dynamic data should be stored in the blackboard, to allow different controllers to use the same behaviors. +AI behaviors are the actions an AI can take. These can range from "Do an emote" to "Attack this target until he is dead". They are singletons and should contain nothing but static data. Any dynamic data should be stored in the blackboard, to allow different controllers to use the same behaviors. # Guides: diff --git a/code/datums/ai/learn_ai.md b/code/datums/ai/learn_ai.md index e4e8a712cf0..5fe38924489 100644 --- a/code/datums/ai/learn_ai.md +++ b/code/datums/ai/learn_ai.md @@ -1,4 +1,3 @@ - # Learn AI In ye olde days, we designed mob AI, and we built it into simple animals as they were the "non player controlled" mobs. Made sense at the time. But by coding AI directly into the mob, there was so little ability to make unique or complicated AI, and even when it was pulled off the code was hacky and non-reusable. the datum AI system was made to rectify these problems, and expand AI beyond just mobs. @@ -57,6 +56,7 @@ AI's work by planning specific behaviors, and subtrees are datums that bundle th ``` Finally, we have some more minor things. + - ai_traits are flags for the AI, things like "STOP_MOVING_WHEN_PULLED" slightly modifying how the AI acts under some situations. - ai_movement is how the mob moves to its movement target. ranges from simple behaviors like ai_movement/dumb that awlays move in the direction of the target and hope there's nothing in the way, all the way to ai_movement/jps that plans and occasionally recalcuates more complicated paths, at the cost of more lag. - idle_behavior is just some simpler behavior to perform when nothing has been planned at all, like idle_behavior/idle_random_walk making a mob wander passively. diff --git a/code/datums/components/COMPONENT_TEMPLATE.md b/code/datums/components/COMPONENT_TEMPLATE.md index 79dfddf1d08..4aff450cf83 100644 --- a/code/datums/components/COMPONENT_TEMPLATE.md +++ b/code/datums/components/COMPONENT_TEMPLATE.md @@ -1,7 +1,6 @@ - # Template file for your new component -See _component.dm for detailed explanations +See \_component.dm for detailed explanations ```dm /datum/component/mycomponent diff --git a/code/datums/components/README.md b/code/datums/components/README.md index 34aea1176e4..0d3d7fdad9b 100644 --- a/code/datums/components/README.md +++ b/code/datums/components/README.md @@ -6,4 +6,4 @@ Loosely adapted from /vg/. This is an entity component system for adding behavio ### [HackMD page for an introduction to the system as a whole.](https://hackmd.io/@tgstation/SignalsComponentsElements) -### See/Define signals and their arguments in [__DEFINES\components.dm](../../__DEFINES/components.dm) +### See/Define signals and their arguments in [\_\_DEFINES\components.dm](../../__DEFINES/components.dm) diff --git a/code/datums/elements/ELEMENT_TEMPLATE.md b/code/datums/elements/ELEMENT_TEMPLATE.md index 4bc1f72f2dc..33586bd94e5 100644 --- a/code/datums/elements/ELEMENT_TEMPLATE.md +++ b/code/datums/elements/ELEMENT_TEMPLATE.md @@ -1,7 +1,6 @@ - # Template file for your new element -See _element.dm for detailed explanations +See \_element.dm for detailed explanations ```dm /datum/element/myelement diff --git a/code/datums/elements/screentips/README.md b/code/datums/elements/screentips/README.md index 30d0e7a90cc..90c60c99636 100644 --- a/code/datums/elements/screentips/README.md +++ b/code/datums/elements/screentips/README.md @@ -80,6 +80,7 @@ This will display "LMB: Craft bola" when the user hovers over cable restraints w The basic system acknowledges the following two interactions: ### Self-defining items (Type A) + These are items that are defined by their behavior. These should define their contextual text within themselves, and not in their targets. - Stun batons (LMB to stun, RMB to harm) @@ -87,7 +88,8 @@ These are items that are defined by their behavior. These should define their co - Health analyzers (LMB to scan for health/wounds [another piece of context], RMB to scans for chemicals) ### Receiving action defining objects (Type B) -These are objects (not necessarily items) that are defined by what happens *to* them. These should define their contextual text within themselves, and not in their operating tools. + +These are objects (not necessarily items) that are defined by what happens _to_ them. These should define their contextual text within themselves, and not in their operating tools. - Tables (RMB with wrench to deconstruct) - Construction objects (LMB with glass to put in screen for computers) @@ -104,6 +106,7 @@ Note that you **must return `CONTEXTUAL_SCREENTIP_SET` if you change the context This signal is registered on **items**, and receives **the hovering object**, provided in the form of `obj/item/source, list/context, atom/target, mob/living/user`. ### `/atom/proc/register_item_context()`, and `/atom/proc/add_item_context()` + `/atom/proc/add_item_context()` is a proc intended to be overridden to easily create Type-B interactions (ones where atoms are hovered over by items). It receives the exact same arguments as `COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET`: `obj/item/source, list/context, atom/target, mob/living/user`. In order for your `add_item_context()` method to be run, you **must** call `register_item_context()`. @@ -113,6 +116,7 @@ In order for your `add_item_context()` method to be run, you **must** call `regi This signal is registered on **atoms**, and receives **what the user is hovering with**, provided in the form of `atom/source, list/context, obj/item/held_item, mob/living/user`. ### `/atom/proc/register_context()`, and `/atom/proc/add_context()` + `/atom/proc/add_context()` is a proc intended to be overridden to easily create Type-B interactions (ones where atoms are hovered over by items). It receives the exact same arguments as `COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM`: `atom/source, list/context, obj/item/held_item, mob/living/user`. In order for your `add_context()` method to be run, you **must** call `register_context()`. diff --git a/code/datums/greyscale/README.md b/code/datums/greyscale/README.md index 0d8106ebec6..fd9f30dd838 100644 --- a/code/datums/greyscale/README.md +++ b/code/datums/greyscale/README.md @@ -40,14 +40,14 @@ The json is made up of some metadata and a list of layers used while creating th "type": "reference", "reference_type": "/datum/greyscale_config/some_other_config", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, [ { "type": "icon_state", "icon_state": "highlights", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "reference", @@ -72,6 +72,7 @@ Once it is done generating it will be placed in an icon file with the icon state Most commonly, we'll only use the "icon_state" type... Thus, **this will be the most common layout**: + ```json { "full_icon_state_name": [ @@ -79,18 +80,18 @@ Thus, **this will be the most common layout**: "type": "icon_state", "icon_state": "component_state_1", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "component_state_2", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "non_colorable_component_state", - "blend_mode": "overlay", + "blend_mode": "overlay" } ] } @@ -106,12 +107,14 @@ Additionally, for the sake of mappers, it's appreciated if there's a pre-made ob While the amount of dm code required to make a greyscale sprite was minimized as much as possible, some small amount is required anyway if you want anything to use it. As an example: + ```c /datum/greyscale_config/canister name = "Canister" //Required for debugging, will runtime without one! icon_file = 'icons/obj/pipes_n_cables/canisters/default.dmi' json_config = 'code/datums/greyscale/json_configs/canister_default.json' ``` + And that's all you need to make it usable by other code: ```c @@ -157,8 +160,10 @@ If you want your item to be colorable in a vending machine (or other places if t ... flags_1 = IS_PLAYER_COLORABLE_1 ``` -However, **be extremely careful**, as this *requires* that you put *all* of the object's `flags_1` flags in that statement all over again. It's ugly, I know, but there's no + +However, **be extremely careful**, as this _requires_ that you put _all_ of the object's `flags_1` flags in that statement all over again. It's ugly, I know, but there's no better way to do this with BYOND just yet. You can put multiple flags like this (not real flags): + ```c /obj/item/clothing/head/beret ... diff --git a/code/datums/greyscale/json_configs/bandana.json b/code/datums/greyscale/json_configs/bandana.json index 268266fc0d6..94d4203bf80 100644 --- a/code/datums/greyscale/json_configs/bandana.json +++ b/code/datums/greyscale/json_configs/bandana.json @@ -1,18 +1,18 @@ { - "bandana": [ - { - "type": "icon_state", - "icon_state": "bandana_cloth", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } - ], + "bandana": [ + { + "type": "icon_state", + "icon_state": "bandana_cloth", + "blend_mode": "overlay", + "color_ids": [1] + } + ], "bandana_up": [ - { - "type": "icon_state", - "icon_state": "bandana_cloth_up", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } - ] + { + "type": "icon_state", + "icon_state": "bandana_cloth_up", + "blend_mode": "overlay", + "color_ids": [1] + } + ] } diff --git a/code/datums/greyscale/json_configs/bandana_inhands.json b/code/datums/greyscale/json_configs/bandana_inhands.json index 0948b930bb0..2a0b2b171f1 100644 --- a/code/datums/greyscale/json_configs/bandana_inhands.json +++ b/code/datums/greyscale/json_configs/bandana_inhands.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "greyscale_bandana", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/bandanaskull_inhands.json b/code/datums/greyscale/json_configs/bandanaskull_inhands.json index 40fade07973..5a685399f56 100644 --- a/code/datums/greyscale/json_configs/bandanaskull_inhands.json +++ b/code/datums/greyscale/json_configs/bandanaskull_inhands.json @@ -1,17 +1,16 @@ { - "greyscale_bandana": [ - { - "type": "icon_state", - "icon_state": "greyscale_bandana", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "greyscale_bandana": [ { - "type": "icon_state", - "icon_state": "greyscale_bandana_skull", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "type": "icon_state", + "icon_state": "greyscale_bandana", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "greyscale_bandana_skull", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } - diff --git a/code/datums/greyscale/json_configs/bandanastriped_inhands.json b/code/datums/greyscale/json_configs/bandanastriped_inhands.json index 106dce4db58..8d7f7214030 100644 --- a/code/datums/greyscale/json_configs/bandanastriped_inhands.json +++ b/code/datums/greyscale/json_configs/bandanastriped_inhands.json @@ -1,16 +1,16 @@ { - "greyscale_bandana": [ - { - "type": "icon_state", - "icon_state": "greyscale_bandana", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "greyscale_bandana": [ { - "type": "icon_state", - "icon_state": "greyscale_bandana_stripe", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "type": "icon_state", + "icon_state": "greyscale_bandana", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "greyscale_bandana_stripe", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } diff --git a/code/datums/greyscale/json_configs/bandskull.json b/code/datums/greyscale/json_configs/bandskull.json index 46dc76d9034..14193eb2544 100644 --- a/code/datums/greyscale/json_configs/bandskull.json +++ b/code/datums/greyscale/json_configs/bandskull.json @@ -1,30 +1,30 @@ { - "bandskull": [ - { - "type": "icon_state", - "icon_state": "bandana_cloth", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "bandskull": [ { - "type": "icon_state", - "icon_state": "bandana_skull", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ], + "type": "icon_state", + "icon_state": "bandana_cloth", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "bandana_skull", + "blend_mode": "overlay", + "color_ids": [2] + } + ], "bandskull_up": [ - { - "type": "icon_state", - "icon_state": "bandana_cloth_up", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, { - "type": "icon_state", - "icon_state": "bandana_skull_up", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "type": "icon_state", + "icon_state": "bandana_cloth_up", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "bandana_skull_up", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } diff --git a/code/datums/greyscale/json_configs/bandstriped.json b/code/datums/greyscale/json_configs/bandstriped.json index 370ec6722c7..653e0945124 100644 --- a/code/datums/greyscale/json_configs/bandstriped.json +++ b/code/datums/greyscale/json_configs/bandstriped.json @@ -1,30 +1,30 @@ { - "bandstriped": [ - { - "type": "icon_state", - "icon_state": "bandana_cloth", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "bandstriped": [ { - "type": "icon_state", - "icon_state": "bandana_stripe", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ], + "type": "icon_state", + "icon_state": "bandana_cloth", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "bandana_stripe", + "blend_mode": "overlay", + "color_ids": [2] + } + ], "bandstriped_up": [ - { - "type": "icon_state", - "icon_state": "bandana_cloth_up", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, { - "type": "icon_state", - "icon_state": "bandana_stripe_up", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "type": "icon_state", + "icon_state": "bandana_cloth_up", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "bandana_stripe_up", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } diff --git a/code/datums/greyscale/json_configs/beanie.json b/code/datums/greyscale/json_configs/beanie.json index 94865d64cbf..7b6b94083ed 100644 --- a/code/datums/greyscale/json_configs/beanie.json +++ b/code/datums/greyscale/json_configs/beanie.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "beanie_stripe", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "beanie_base", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/bench_corner.json b/code/datums/greyscale/json_configs/bench_corner.json index 3a86aea97e2..597641584cd 100644 --- a/code/datums/greyscale/json_configs/bench_corner.json +++ b/code/datums/greyscale/json_configs/bench_corner.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "bench_corner_cover", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/bench_left.json b/code/datums/greyscale/json_configs/bench_left.json index 36939f8b716..3ad8232e9ba 100644 --- a/code/datums/greyscale/json_configs/bench_left.json +++ b/code/datums/greyscale/json_configs/bench_left.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "bench_left_cover", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/bench_middle.json b/code/datums/greyscale/json_configs/bench_middle.json index a40df28984e..f63c43b3a32 100644 --- a/code/datums/greyscale/json_configs/bench_middle.json +++ b/code/datums/greyscale/json_configs/bench_middle.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "bench_middle_cover", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/bench_right.json b/code/datums/greyscale/json_configs/bench_right.json index ec1c3575613..fb524323c37 100644 --- a/code/datums/greyscale/json_configs/bench_right.json +++ b/code/datums/greyscale/json_configs/bench_right.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "bench_right_cover", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/bench_solo.json b/code/datums/greyscale/json_configs/bench_solo.json index 505be14387f..1e370d3f7e2 100644 --- a/code/datums/greyscale/json_configs/bench_solo.json +++ b/code/datums/greyscale/json_configs/bench_solo.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "bench_solo_cover", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/beret.json b/code/datums/greyscale/json_configs/beret.json index f7ee848d264..acf796ef1c5 100644 --- a/code/datums/greyscale/json_configs/beret.json +++ b/code/datums/greyscale/json_configs/beret.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "beret", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "beret_flat": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "beret_flat", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/beret_badge.json b/code/datums/greyscale/json_configs/beret_badge.json index f0eda0df5ae..390ffe9f1f6 100644 --- a/code/datums/greyscale/json_configs/beret_badge.json +++ b/code/datums/greyscale/json_configs/beret_badge.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "beret", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "badge", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/beret_badge_worn.json b/code/datums/greyscale/json_configs/beret_badge_worn.json index 47960e08daa..788f60512fb 100644 --- a/code/datums/greyscale/json_configs/beret_badge_worn.json +++ b/code/datums/greyscale/json_configs/beret_badge_worn.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "beret_worn", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "badge_worn", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/beret_worn.json b/code/datums/greyscale/json_configs/beret_worn.json index 8509136e53a..c95346ac670 100644 --- a/code/datums/greyscale/json_configs/beret_worn.json +++ b/code/datums/greyscale/json_configs/beret_worn.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "beret_worn", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "beret_flat": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "beret_worn", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/big_manipulator.json b/code/datums/greyscale/json_configs/big_manipulator.json index c7f96bac2ab..d67b7c4d6e8 100644 --- a/code/datums/greyscale/json_configs/big_manipulator.json +++ b/code/datums/greyscale/json_configs/big_manipulator.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "core_colour", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/blazer.json b/code/datums/greyscale/json_configs/blazer.json index d756f3db33e..fb8d361bdb0 100644 --- a/code/datums/greyscale/json_configs/blazer.json +++ b/code/datums/greyscale/json_configs/blazer.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "blazer", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/buttondown_shorts.json b/code/datums/greyscale/json_configs/buttondown_shorts.json index 3a8bba407fc..5e430c461a9 100644 --- a/code/datums/greyscale/json_configs/buttondown_shorts.json +++ b/code/datums/greyscale/json_configs/buttondown_shorts.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "buttondown", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buttondown_obj_buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "buttondown_obj_belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "buttondown_obj_shorts", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/buttondown_shorts_worn.json b/code/datums/greyscale/json_configs/buttondown_shorts_worn.json index 2575a5d1f8f..d9cdfea4ffa 100644 --- a/code/datums/greyscale/json_configs/buttondown_shorts_worn.json +++ b/code/datums/greyscale/json_configs/buttondown_shorts_worn.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "buttondown", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "shorts", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ], "buttondown_shorts_d": [ @@ -30,25 +30,25 @@ "type": "icon_state", "icon_state": "buttondown_d", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "shorts", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/buttondown_skirt.json b/code/datums/greyscale/json_configs/buttondown_skirt.json index 60d3d500f28..dea1a9990ea 100644 --- a/code/datums/greyscale/json_configs/buttondown_skirt.json +++ b/code/datums/greyscale/json_configs/buttondown_skirt.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "buttondown", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buttondown_obj_buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "buttondown_obj_belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "buttondown_obj_skirt", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/buttondown_skirt_worn.json b/code/datums/greyscale/json_configs/buttondown_skirt_worn.json index e34a900caf4..0ce5e28ad1a 100644 --- a/code/datums/greyscale/json_configs/buttondown_skirt_worn.json +++ b/code/datums/greyscale/json_configs/buttondown_skirt_worn.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "buttondown", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "skirt", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ], "buttondown_skirt_d": [ @@ -30,25 +30,25 @@ "type": "icon_state", "icon_state": "buttondown_d", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "skirt", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/buttondown_slacks.json b/code/datums/greyscale/json_configs/buttondown_slacks.json index 73d091e3d70..3f9077a6306 100644 --- a/code/datums/greyscale/json_configs/buttondown_slacks.json +++ b/code/datums/greyscale/json_configs/buttondown_slacks.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "buttondown", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buttondown_obj_buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "buttondown_obj_belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "buttondown_obj_slacks", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/buttondown_slacks_worn.json b/code/datums/greyscale/json_configs/buttondown_slacks_worn.json index 149ec9fefc6..8c29b4eab04 100644 --- a/code/datums/greyscale/json_configs/buttondown_slacks_worn.json +++ b/code/datums/greyscale/json_configs/buttondown_slacks_worn.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "buttondown", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "slacks", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ], "buttondown_slacks_d": [ @@ -30,25 +30,25 @@ "type": "icon_state", "icon_state": "buttondown_d", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "slacks", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/canister_base.json b/code/datums/greyscale/json_configs/canister_base.json index 4528c6225c6..38514eff119 100644 --- a/code/datums/greyscale/json_configs/canister_base.json +++ b/code/datums/greyscale/json_configs/canister_base.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/canister_default.json b/code/datums/greyscale/json_configs/canister_default.json index b965e9ec3fd..8c267544bb2 100644 --- a/code/datums/greyscale/json_configs/canister_default.json +++ b/code/datums/greyscale/json_configs/canister_default.json @@ -4,13 +4,13 @@ "type": "reference", "reference_type": "/datum/greyscale_config/canister/base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "reference", "reference_type": "/datum/greyscale_config/canister/post_effects", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "window-base": [ @@ -18,7 +18,7 @@ "type": "icon_state", "icon_state": "window-base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/canister_double_stripe.json b/code/datums/greyscale/json_configs/canister_double_stripe.json index 33dd115d3ea..6281f56e9ce 100644 --- a/code/datums/greyscale/json_configs/canister_double_stripe.json +++ b/code/datums/greyscale/json_configs/canister_double_stripe.json @@ -4,14 +4,14 @@ "type": "reference", "reference_type": "/datum/greyscale_config/canister/base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, [ { "type": "icon_state", "icon_state": "double_stripe", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", @@ -23,7 +23,7 @@ "type": "reference", "reference_type": "/datum/greyscale_config/canister/post_effects", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "window-base": [ @@ -31,7 +31,7 @@ "type": "icon_state", "icon_state": "window-base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/canister_hazard.json b/code/datums/greyscale/json_configs/canister_hazard.json index 81c19362231..39e7d8ef0a1 100644 --- a/code/datums/greyscale/json_configs/canister_hazard.json +++ b/code/datums/greyscale/json_configs/canister_hazard.json @@ -4,19 +4,19 @@ "type": "reference", "reference_type": "/datum/greyscale_config/canister/base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "hazard_stripes", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "reference", "reference_type": "/datum/greyscale_config/canister/post_effects", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "window-base": [ @@ -24,7 +24,7 @@ "type": "icon_state", "icon_state": "window-base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/canister_post_effects.json b/code/datums/greyscale/json_configs/canister_post_effects.json index 6756c3221f9..40845168718 100644 --- a/code/datums/greyscale/json_configs/canister_post_effects.json +++ b/code/datums/greyscale/json_configs/canister_post_effects.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "outline", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/canister_stripe.json b/code/datums/greyscale/json_configs/canister_stripe.json index 9e5f087c0ae..d6540ef61ea 100644 --- a/code/datums/greyscale/json_configs/canister_stripe.json +++ b/code/datums/greyscale/json_configs/canister_stripe.json @@ -4,19 +4,19 @@ "type": "reference", "reference_type": "/datum/greyscale_config/canister/base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "stripe", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "reference", "reference_type": "/datum/greyscale_config/canister/post_effects", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "window-base": [ @@ -24,7 +24,7 @@ "type": "icon_state", "icon_state": "window-base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/cardiganskirt.json b/code/datums/greyscale/json_configs/cardiganskirt.json index 97a87b6405c..e2ff9beba70 100644 --- a/code/datums/greyscale/json_configs/cardiganskirt.json +++ b/code/datums/greyscale/json_configs/cardiganskirt.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cardiganskirt_skirt", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cardiganskirt_cardigan", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/carp.json b/code/datums/greyscale/json_configs/carp.json index d01fda5a9ee..0d50e0a8734 100644 --- a/code/datums/greyscale/json_configs/carp.json +++ b/code/datums/greyscale/json_configs/carp.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -17,7 +17,7 @@ "type": "icon_state", "icon_state": "base_dead", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/carp_disk_mouth.json b/code/datums/greyscale/json_configs/carp_disk_mouth.json index f74fcfdeec6..af4b82b0a94 100644 --- a/code/datums/greyscale/json_configs/carp_disk_mouth.json +++ b/code/datums/greyscale/json_configs/carp_disk_mouth.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "disk_mouth", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/carp_friend.json b/code/datums/greyscale/json_configs/carp_friend.json index a5b3ffdf7a4..7fcf4752fdd 100644 --- a/code/datums/greyscale/json_configs/carp_friend.json +++ b/code/datums/greyscale/json_configs/carp_friend.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "base_friend", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -17,7 +17,7 @@ "type": "icon_state", "icon_state": "base_friend_dead", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/carp_magic.json b/code/datums/greyscale/json_configs/carp_magic.json index 947ea225b5f..2110bc708cf 100644 --- a/code/datums/greyscale/json_configs/carp_magic.json +++ b/code/datums/greyscale/json_configs/carp_magic.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -22,7 +22,7 @@ "type": "icon_state", "icon_state": "base_dead", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/carp_mega.json b/code/datums/greyscale/json_configs/carp_mega.json index 9b15cbf1c4b..cb93053a670 100644 --- a/code/datums/greyscale/json_configs/carp_mega.json +++ b/code/datums/greyscale/json_configs/carp_mega.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "megacarp_greyscale", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -17,7 +17,7 @@ "type": "icon_state", "icon_state": "megacarp_dead_greyscale", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/circuit.json b/code/datums/greyscale/json_configs/circuit.json index ed1569cda25..d7e5f6b5f24 100644 --- a/code/datums/greyscale/json_configs/circuit.json +++ b/code/datums/greyscale/json_configs/circuit.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "circuit_board", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/ctf_light.json b/code/datums/greyscale/json_configs/ctf_light.json index e48762afa67..bb45055651e 100644 --- a/code/datums/greyscale/json_configs/ctf_light.json +++ b/code/datums/greyscale/json_configs/ctf_light.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "light_colours", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/ctf_standard.json b/code/datums/greyscale/json_configs/ctf_standard.json index f56ed5d8c06..9d62d4bda1b 100644 --- a/code/datums/greyscale/json_configs/ctf_standard.json +++ b/code/datums/greyscale/json_configs/ctf_standard.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "standard_colours", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/digitigrade.json b/code/datums/greyscale/json_configs/digitigrade.json index 899dff334e4..f068457be94 100644 --- a/code/datums/greyscale/json_configs/digitigrade.json +++ b/code/datums/greyscale/json_configs/digitigrade.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "jumpsuit", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "oversuit_worn": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "oversuit", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "sneakers_worn": [ @@ -20,7 +20,7 @@ "type": "icon_state", "icon_state": "shoes_colored", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -33,7 +33,7 @@ "type": "icon_state", "icon_state": "boots", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/encryptionkey_basic.json b/code/datums/greyscale/json_configs/encryptionkey_basic.json index addefeea013..d215efe7e95 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_basic.json +++ b/code/datums/greyscale/json_configs/encryptionkey_basic.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_stripe", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_cargo.json b/code/datums/greyscale/json_configs/encryptionkey_cargo.json index 225ac9e02cc..c06f6e8a492 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_cargo.json +++ b/code/datums/greyscale/json_configs/encryptionkey_cargo.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_cargo", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_centcom.json b/code/datums/greyscale/json_configs/encryptionkey_centcom.json index 3683dd00183..1d363fca14a 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_centcom.json +++ b/code/datums/greyscale/json_configs/encryptionkey_centcom.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_cent", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_cube.json b/code/datums/greyscale/json_configs/encryptionkey_cube.json index 9eb63502b45..b68d1962d66 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_cube.json +++ b/code/datums/greyscale/json_configs/encryptionkey_cube.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_block", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_engineering.json b/code/datums/greyscale/json_configs/encryptionkey_engineering.json index 31160b2d18c..56d9dfe72e2 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_engineering.json +++ b/code/datums/greyscale/json_configs/encryptionkey_engineering.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_engi", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_medical.json b/code/datums/greyscale/json_configs/encryptionkey_medical.json index b2ef5ef818a..ef97701725c 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_medical.json +++ b/code/datums/greyscale/json_configs/encryptionkey_medical.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_med", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_research.json b/code/datums/greyscale/json_configs/encryptionkey_research.json index f5cc11f5c1d..efb6e332d02 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_research.json +++ b/code/datums/greyscale/json_configs/encryptionkey_research.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_res", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_security.json b/code/datums/greyscale/json_configs/encryptionkey_security.json index d10d7cb4083..2680cabb221 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_security.json +++ b/code/datums/greyscale/json_configs/encryptionkey_security.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_sec", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_service.json b/code/datums/greyscale/json_configs/encryptionkey_service.json index 7927e7ce4c0..13e8280fcdd 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_service.json +++ b/code/datums/greyscale/json_configs/encryptionkey_service.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_serv", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/encryptionkey_syndicate.json b/code/datums/greyscale/json_configs/encryptionkey_syndicate.json index a30ba6763f1..f114419a4fe 100644 --- a/code/datums/greyscale/json_configs/encryptionkey_syndicate.json +++ b/code/datums/greyscale/json_configs/encryptionkey_syndicate.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "cypher_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cypher_syn", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/eth_raincoat.json b/code/datums/greyscale/json_configs/eth_raincoat.json index b57f371b460..ac8ab4a70e7 100644 --- a/code/datums/greyscale/json_configs/eth_raincoat.json +++ b/code/datums/greyscale/json_configs/eth_raincoat.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "eth_raincoat_glow", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "eth_raincoat_t": [ @@ -22,7 +22,7 @@ "type": "icon_state", "icon_state": "eth_raincoat_glow", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/eth_raincoat_worn.json b/code/datums/greyscale/json_configs/eth_raincoat_worn.json index 7be0a52b5e7..c742f0dfbdb 100644 --- a/code/datums/greyscale/json_configs/eth_raincoat_worn.json +++ b/code/datums/greyscale/json_configs/eth_raincoat_worn.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "eth_raincoat_glow_worn", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "eth_raincoat_t": [ @@ -22,7 +22,7 @@ "type": "icon_state", "icon_state": "eth_raincoat_glow_worn_t", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/eth_tunic.json b/code/datums/greyscale/json_configs/eth_tunic.json index 5ef2f9771d6..2e2d2757b10 100644 --- a/code/datums/greyscale/json_configs/eth_tunic.json +++ b/code/datums/greyscale/json_configs/eth_tunic.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "eth_tunic_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/eveningdress.json b/code/datums/greyscale/json_configs/eveningdress.json index d08dc95bbbe..53cc93b642f 100644 --- a/code/datums/greyscale/json_configs/eveningdress.json +++ b/code/datums/greyscale/json_configs/eveningdress.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "evening_gown", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/facescarf.json b/code/datums/greyscale/json_configs/facescarf.json index eadb07dd927..523db542695 100644 --- a/code/datums/greyscale/json_configs/facescarf.json +++ b/code/datums/greyscale/json_configs/facescarf.json @@ -1,18 +1,18 @@ { - "facescarf": [ - { - "type": "icon_state", - "icon_state": "facescarf", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } - ], + "facescarf": [ + { + "type": "icon_state", + "icon_state": "facescarf", + "blend_mode": "overlay", + "color_ids": [1] + } + ], "facescarf_up": [ - { - "type": "icon_state", - "icon_state": "facescarf_up", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } - ] + { + "type": "icon_state", + "icon_state": "facescarf_up", + "blend_mode": "overlay", + "color_ids": [1] + } + ] } diff --git a/code/datums/greyscale/json_configs/facescarf_inhands.json b/code/datums/greyscale/json_configs/facescarf_inhands.json index eee4225a050..c08256fcb1b 100644 --- a/code/datums/greyscale/json_configs/facescarf_inhands.json +++ b/code/datums/greyscale/json_configs/facescarf_inhands.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "greyscale_bandana", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/fancy_coat.json b/code/datums/greyscale/json_configs/fancy_coat.json index b4bb94f4fef..2d3b7805658 100644 --- a/code/datums/greyscale/json_configs/fancy_coat.json +++ b/code/datums/greyscale/json_configs/fancy_coat.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "fancy_fur", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "fancy_coat", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/fancy_hat.json b/code/datums/greyscale/json_configs/fancy_hat.json index d3268100171..49a025ea964 100644 --- a/code/datums/greyscale/json_configs/fancy_hat.json +++ b/code/datums/greyscale/json_configs/fancy_hat.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "fancy_feather", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "fancy_hat", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/fedora.json b/code/datums/greyscale/json_configs/fedora.json index 2b7f6d0f89f..2e408295251 100644 --- a/code/datums/greyscale/json_configs/fedora.json +++ b/code/datums/greyscale/json_configs/fedora.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "fedora_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "fedora_sash", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/festive_hat.json b/code/datums/greyscale/json_configs/festive_hat.json index 15556411479..2fe78827f7e 100644 --- a/code/datums/greyscale/json_configs/festive_hat.json +++ b/code/datums/greyscale/json_configs/festive_hat.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "xmashat_grey", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/fish_analyzer_worn.json b/code/datums/greyscale/json_configs/fish_analyzer_worn.json index f2cc22bf1b5..644ce2e1381 100644 --- a/code/datums/greyscale/json_configs/fish_analyzer_worn.json +++ b/code/datums/greyscale/json_configs/fish_analyzer_worn.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "fish_analyzer_outer", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -12,4 +12,4 @@ "blend_mode": "overlay" } ] -} \ No newline at end of file +} diff --git a/code/datums/greyscale/json_configs/fish_tail.json b/code/datums/greyscale/json_configs/fish_tail.json index 3293c1df4ba..ec676b0bd2d 100644 --- a/code/datums/greyscale/json_configs/fish_tail.json +++ b/code/datums/greyscale/json_configs/fish_tail.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "fish_tail", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -12,4 +12,4 @@ "blend_mode": "overlay" } ] -} \ No newline at end of file +} diff --git a/code/datums/greyscale/json_configs/football_armor.json b/code/datums/greyscale/json_configs/football_armor.json index c928d84195f..96a3588ad21 100644 --- a/code/datums/greyscale/json_configs/football_armor.json +++ b/code/datums/greyscale/json_configs/football_armor.json @@ -1,15 +1,15 @@ { - "football_armor": [ - { - "type": "icon_state", - "icon_state": "football_armor", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "football_armor": [ { - "type": "icon_state", - "icon_state": "football_number", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "football_armor", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "football_number", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/football_helmet.json b/code/datums/greyscale/json_configs/football_helmet.json index 5c7aff3c7a9..30f736666de 100644 --- a/code/datums/greyscale/json_configs/football_helmet.json +++ b/code/datums/greyscale/json_configs/football_helmet.json @@ -1,15 +1,15 @@ { - "football_helmet": [ - { - "type": "icon_state", - "icon_state": "football_helmet", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "football_helmet": [ { - "type": "icon_state", - "icon_state": "football_stripe", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "football_helmet", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "football_stripe", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/football_suit.json b/code/datums/greyscale/json_configs/football_suit.json index d1830d6c83a..1bfdc312b94 100644 --- a/code/datums/greyscale/json_configs/football_suit.json +++ b/code/datums/greyscale/json_configs/football_suit.json @@ -1,15 +1,15 @@ { - "football_suit": [ - { - "type": "icon_state", - "icon_state": "football_suit", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "football_suit": [ { - "type": "icon_state", - "icon_state": "football_number", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "football_suit", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "football_number", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/garden_gnome.json b/code/datums/greyscale/json_configs/garden_gnome.json index c443e6f04a6..e130be4c1b1 100644 --- a/code/datums/greyscale/json_configs/garden_gnome.json +++ b/code/datums/greyscale/json_configs/garden_gnome.json @@ -9,25 +9,25 @@ "type": "icon_state", "icon_state": "gnome_hat", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "gnome_body", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "gnome_pants", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "gnome_beard", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ], "gnome_burried_1": [ @@ -40,25 +40,25 @@ "type": "icon_state", "icon_state": "gnome_hat_burried_1", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "gnome_body_burried_1", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "gnome_pants_burried_1", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "gnome_beard_burried_1", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ], "gnome_burried_2": [ @@ -71,25 +71,25 @@ "type": "icon_state", "icon_state": "gnome_hat_burried_2", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "gnome_body_burried_2", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "gnome_pants_burried_2", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "gnome_beard_burried_2", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ], "gnome_burried_3": [ @@ -102,25 +102,25 @@ "type": "icon_state", "icon_state": "gnome_hat_burried_3", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "gnome_body_burried_3", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "gnome_pants_burried_3", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "gnome_beard_burried_3", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/gi.json b/code/datums/greyscale/json_configs/gi.json index 7534552293b..f02bdb6aa54 100644 --- a/code/datums/greyscale/json_configs/gi.json +++ b/code/datums/greyscale/json_configs/gi.json @@ -1,36 +1,36 @@ { - "martial_arts_gi": [ - { - "type": "icon_state", - "icon_state": "gi_base", - "blend_mode": "overlay", - "color_ids": [1] - }, + "martial_arts_gi": [ { - "type": "icon_state", - "icon_state": "gi_belt", - "blend_mode": "overlay", + "type": "icon_state", + "icon_state": "gi_base", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "gi_belt", + "blend_mode": "overlay", "color_ids": [2] - } - ], + } + ], - "martial_arts_gi_goku": [ - { - "type": "icon_state", - "icon_state": "gi_base", - "blend_mode": "overlay", - "color_ids": [1] - }, + "martial_arts_gi_goku": [ { - "type": "icon_state", - "icon_state": "gi_belt", - "blend_mode": "overlay", + "type": "icon_state", + "icon_state": "gi_base", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "gi_belt", + "blend_mode": "overlay", "color_ids": [2] - }, + }, { - "type": "icon_state", - "icon_state": "gi_goku", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "gi_goku", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/giftdeliverybox.json b/code/datums/greyscale/json_configs/giftdeliverybox.json index 68c4ad1f76d..5e588005e12 100644 --- a/code/datums/greyscale/json_configs/giftdeliverybox.json +++ b/code/datums/greyscale/json_configs/giftdeliverybox.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "giftdeliverybox_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "giftdeliverybox_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/giftdeliverycloset.json b/code/datums/greyscale/json_configs/giftdeliverycloset.json index 9de529901a2..7bc125d5f56 100644 --- a/code/datums/greyscale/json_configs/giftdeliverycloset.json +++ b/code/datums/greyscale/json_configs/giftdeliverycloset.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "giftdeliverycloset_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "giftdeliverycloset_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/giftdeliverycrate.json b/code/datums/greyscale/json_configs/giftdeliverycrate.json index 78d864f4123..7ba95b621ca 100644 --- a/code/datums/greyscale/json_configs/giftdeliverycrate.json +++ b/code/datums/greyscale/json_configs/giftdeliverycrate.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "giftdeliverycrate_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "giftdeliverycrate_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/giftdeliverypackage1.json b/code/datums/greyscale/json_configs/giftdeliverypackage1.json index 7b61b49688c..6621119c23a 100644 --- a/code/datums/greyscale/json_configs/giftdeliverypackage1.json +++ b/code/datums/greyscale/json_configs/giftdeliverypackage1.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "giftdeliverypackage1_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "giftdeliverypackage1_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/giftdeliverypackage2.json b/code/datums/greyscale/json_configs/giftdeliverypackage2.json index a2724a4d4f5..799479eb353 100644 --- a/code/datums/greyscale/json_configs/giftdeliverypackage2.json +++ b/code/datums/greyscale/json_configs/giftdeliverypackage2.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "giftdeliverypackage2_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "giftdeliverypackage2_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/giftdeliverypackage3.json b/code/datums/greyscale/json_configs/giftdeliverypackage3.json index 20b2b2a1f10..d1dae2c0995 100644 --- a/code/datums/greyscale/json_configs/giftdeliverypackage3.json +++ b/code/datums/greyscale/json_configs/giftdeliverypackage3.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "giftdeliverypackage3_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "giftdeliverypackage3_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/giftdeliverypackage4.json b/code/datums/greyscale/json_configs/giftdeliverypackage4.json index a75521dfd7e..0fb6ce5d818 100644 --- a/code/datums/greyscale/json_configs/giftdeliverypackage4.json +++ b/code/datums/greyscale/json_configs/giftdeliverypackage4.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "giftdeliverypackage4_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "giftdeliverypackage4_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/giftdeliverypackage5.json b/code/datums/greyscale/json_configs/giftdeliverypackage5.json index 180cb27dddc..9f211641fd6 100644 --- a/code/datums/greyscale/json_configs/giftdeliverypackage5.json +++ b/code/datums/greyscale/json_configs/giftdeliverypackage5.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "giftdeliverypackage5_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "giftdeliverypackage5_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/gloves_inhand.json b/code/datums/greyscale/json_configs/gloves_inhand.json index 7b1bb5100f4..e0141c15cab 100644 --- a/code/datums/greyscale/json_configs/gloves_inhand.json +++ b/code/datums/greyscale/json_configs/gloves_inhand.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "greyscale_gloves", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/glow_shoes.json b/code/datums/greyscale/json_configs/glow_shoes.json index d78fe5b7de0..afc431c745e 100644 --- a/code/datums/greyscale/json_configs/glow_shoes.json +++ b/code/datums/greyscale/json_configs/glow_shoes.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "glow_shoes_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "glow_shoes_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/gutlunch.json b/code/datums/greyscale/json_configs/gutlunch.json index 0b930338163..4c73b04f2ff 100644 --- a/code/datums/greyscale/json_configs/gutlunch.json +++ b/code/datums/greyscale/json_configs/gutlunch.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "gutlunch", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/hawaiian_shirt.json b/code/datums/greyscale/json_configs/hawaiian_shirt.json index c3291638780..9bbbf268db0 100644 --- a/code/datums/greyscale/json_configs/hawaiian_shirt.json +++ b/code/datums/greyscale/json_configs/hawaiian_shirt.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "hawaiianbase", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "hawaiianflowers", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/heck_helmet.json b/code/datums/greyscale/json_configs/heck_helmet.json index dd0649f3007..7f75a0e641c 100644 --- a/code/datums/greyscale/json_configs/heck_helmet.json +++ b/code/datums/greyscale/json_configs/heck_helmet.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "hostile_env_head", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "hostile_env_jaw", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "hostile_env_visor", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/heck_suit.json b/code/datums/greyscale/json_configs/heck_suit.json index 72ad7f42b3d..02639967087 100644 --- a/code/datums/greyscale/json_configs/heck_suit.json +++ b/code/datums/greyscale/json_configs/heck_suit.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "hostile_env_plates", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "hostile_env_detail", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ], "hostile_env_t": [ @@ -18,13 +18,13 @@ "type": "icon_state", "icon_state": "hostile_env_plates", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "hostile_env_detail", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/heretic_rune.json b/code/datums/greyscale/json_configs/heretic_rune.json index b9d349ef40f..ac85f2aa7d1 100644 --- a/code/datums/greyscale/json_configs/heretic_rune.json +++ b/code/datums/greyscale/json_configs/heretic_rune.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "transmutation_rune", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "transmutation_rune_active": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "transmutation_rune_activate_colour", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -25,7 +25,7 @@ "type": "icon_state", "icon_state": "transmutation_rune_draw_colour", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -38,7 +38,7 @@ "type": "icon_state", "icon_state": "transmutation_rune_fast_colour", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -51,7 +51,7 @@ "type": "icon_state", "icon_state": "transmutation_rune_fail_colour", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/infinity_scarf.json b/code/datums/greyscale/json_configs/infinity_scarf.json index 80996df563b..2e0eec45e31 100644 --- a/code/datums/greyscale/json_configs/infinity_scarf.json +++ b/code/datums/greyscale/json_configs/infinity_scarf.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "infinity_scarf", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/items/ceremonial_blade.json b/code/datums/greyscale/json_configs/items/ceremonial_blade.json index 16360a5e889..4969a75efe7 100644 --- a/code/datums/greyscale/json_configs/items/ceremonial_blade.json +++ b/code/datums/greyscale/json_configs/items/ceremonial_blade.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/items/ceremonial_blade_lefthand.json b/code/datums/greyscale/json_configs/items/ceremonial_blade_lefthand.json index aafdb2d897e..2052c7dfa85 100644 --- a/code/datums/greyscale/json_configs/items/ceremonial_blade_lefthand.json +++ b/code/datums/greyscale/json_configs/items/ceremonial_blade_lefthand.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "inhand_left", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/items/ceremonial_blade_righthand.json b/code/datums/greyscale/json_configs/items/ceremonial_blade_righthand.json index d80b0c49a25..a93fe4b6950 100644 --- a/code/datums/greyscale/json_configs/items/ceremonial_blade_righthand.json +++ b/code/datums/greyscale/json_configs/items/ceremonial_blade_righthand.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "inhand_right", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/items/cleric_mace.json b/code/datums/greyscale/json_configs/items/cleric_mace.json index 5197ebc45a2..b09cd3a659a 100644 --- a/code/datums/greyscale/json_configs/items/cleric_mace.json +++ b/code/datums/greyscale/json_configs/items/cleric_mace.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "handle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ], "default_worn": [ @@ -18,13 +18,13 @@ "type": "icon_state", "icon_state": "worn_shaft", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "worn_handle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/items/cleric_mace_gold.json b/code/datums/greyscale/json_configs/items/cleric_mace_gold.json index 8ca0ba3b607..16d52555d1d 100644 --- a/code/datums/greyscale/json_configs/items/cleric_mace_gold.json +++ b/code/datums/greyscale/json_configs/items/cleric_mace_gold.json @@ -5,14 +5,14 @@ "reference_type": "/datum/greyscale_config/cleric_mace", "icon_state": "default", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, [ { "type": "reference", "reference_type": "/datum/greyscale_config/shimmer", "blend_mode": "overlay", - "color_ids": [ "#ffffff" ] + "color_ids": ["#ffffff"] }, { "type": "icon_state", @@ -27,14 +27,14 @@ "reference_type": "/datum/greyscale_config/cleric_mace", "icon_state": "default_worn", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, [ { "type": "reference", "reference_type": "/datum/greyscale_config/shimmer", "blend_mode": "overlay", - "color_ids": [ "#ffffff" ] + "color_ids": ["#ffffff"] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/items/cleric_mace_lefthand.json b/code/datums/greyscale/json_configs/items/cleric_mace_lefthand.json index aafdb2d897e..2052c7dfa85 100644 --- a/code/datums/greyscale/json_configs/items/cleric_mace_lefthand.json +++ b/code/datums/greyscale/json_configs/items/cleric_mace_lefthand.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "inhand_left", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/items/cleric_mace_lefthand_gold.json b/code/datums/greyscale/json_configs/items/cleric_mace_lefthand_gold.json index 9372b4b0551..199ffcce80b 100644 --- a/code/datums/greyscale/json_configs/items/cleric_mace_lefthand_gold.json +++ b/code/datums/greyscale/json_configs/items/cleric_mace_lefthand_gold.json @@ -5,14 +5,14 @@ "reference_type": "/datum/greyscale_config/cleric_mace_lefthand", "icon_state": "default", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, [ { "type": "reference", "reference_type": "/datum/greyscale_config/shimmer", "blend_mode": "overlay", - "color_ids": [ "#ffffff" ] + "color_ids": ["#ffffff"] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/items/cleric_mace_righthand.json b/code/datums/greyscale/json_configs/items/cleric_mace_righthand.json index d80b0c49a25..a93fe4b6950 100644 --- a/code/datums/greyscale/json_configs/items/cleric_mace_righthand.json +++ b/code/datums/greyscale/json_configs/items/cleric_mace_righthand.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "inhand_right", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/items/cleric_mace_righthand_gold.json b/code/datums/greyscale/json_configs/items/cleric_mace_righthand_gold.json index d91f1c0800c..07e0c697f38 100644 --- a/code/datums/greyscale/json_configs/items/cleric_mace_righthand_gold.json +++ b/code/datums/greyscale/json_configs/items/cleric_mace_righthand_gold.json @@ -5,14 +5,14 @@ "reference_type": "/datum/greyscale_config/cleric_mace_righthand", "icon_state": "default", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, [ { "type": "reference", "reference_type": "/datum/greyscale_config/shimmer", "blend_mode": "overlay", - "color_ids": [ "#ffffff" ] + "color_ids": ["#ffffff"] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/items/cleric_mace_worn.json b/code/datums/greyscale/json_configs/items/cleric_mace_worn.json index 5725cfa689a..c15a3d183d6 100644 --- a/code/datums/greyscale/json_configs/items/cleric_mace_worn.json +++ b/code/datums/greyscale/json_configs/items/cleric_mace_worn.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "worn_shaft", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "worn_handle", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/items/cleric_mace_worn_gold.json b/code/datums/greyscale/json_configs/items/cleric_mace_worn_gold.json index 21850436657..93ae279dbfd 100644 --- a/code/datums/greyscale/json_configs/items/cleric_mace_worn_gold.json +++ b/code/datums/greyscale/json_configs/items/cleric_mace_worn_gold.json @@ -5,14 +5,14 @@ "reference_type": "/datum/greyscale_config/cleric_mace_worn", "icon_state": "default", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, [ { "type": "reference", "reference_type": "/datum/greyscale_config/shimmer", "blend_mode": "overlay", - "color_ids": [ "#ffffff" ] + "color_ids": ["#ffffff"] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/jacket_lawyer.json b/code/datums/greyscale/json_configs/jacket_lawyer.json index 9593f9c90c3..971fa3b4378 100644 --- a/code/datums/greyscale/json_configs/jacket_lawyer.json +++ b/code/datums/greyscale/json_configs/jacket_lawyer.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "suitjacket", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "jacket_lawyer_t": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "suitjacket_t", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/jacket_oversized.json b/code/datums/greyscale/json_configs/jacket_oversized.json index e1aaa566bcd..7debbf85e58 100644 --- a/code/datums/greyscale/json_configs/jacket_oversized.json +++ b/code/datums/greyscale/json_configs/jacket_oversized.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "jacket_oversized", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/janicart_upgrade.json b/code/datums/greyscale/json_configs/janicart_upgrade.json index 7269059b3bc..40a1e30d6df 100644 --- a/code/datums/greyscale/json_configs/janicart_upgrade.json +++ b/code/datums/greyscale/json_configs/janicart_upgrade.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "housing", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "bristles", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "accent", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "light", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/janicart_upgrade_installed.json b/code/datums/greyscale/json_configs/janicart_upgrade_installed.json index c586c92709c..e7677253a78 100644 --- a/code/datums/greyscale/json_configs/janicart_upgrade_installed.json +++ b/code/datums/greyscale/json_configs/janicart_upgrade_installed.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "cart_housing", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "cart_bristles", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "cart_accent", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "cart_light", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/jeans.json b/code/datums/greyscale/json_configs/jeans.json index e16642511a3..28935a8808e 100644 --- a/code/datums/greyscale/json_configs/jeans.json +++ b/code/datums/greyscale/json_configs/jeans.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "jeans", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/jeanshorts.json b/code/datums/greyscale/json_configs/jeanshorts.json index 2d595b7a385..eabad860796 100644 --- a/code/datums/greyscale/json_configs/jeanshorts.json +++ b/code/datums/greyscale/json_configs/jeanshorts.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "jeanshorts", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/jester_hat.json b/code/datums/greyscale/json_configs/jester_hat.json index b5147e7a009..afbb36f1602 100644 --- a/code/datums/greyscale/json_configs/jester_hat.json +++ b/code/datums/greyscale/json_configs/jester_hat.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "jester_a", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "jester_b", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/jester_shoes.json b/code/datums/greyscale/json_configs/jester_shoes.json index b5147e7a009..afbb36f1602 100644 --- a/code/datums/greyscale/json_configs/jester_shoes.json +++ b/code/datums/greyscale/json_configs/jester_shoes.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "jester_a", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "jester_b", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/jester_suit.json b/code/datums/greyscale/json_configs/jester_suit.json index aac60f18be7..e4c1b01c6dc 100644 --- a/code/datums/greyscale/json_configs/jester_suit.json +++ b/code/datums/greyscale/json_configs/jester_suit.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "jester_a", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "jester_b", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/jumpsuit.json b/code/datums/greyscale/json_configs/jumpsuit.json index 03044770b95..d21f82d9cd1 100644 --- a/code/datums/greyscale/json_configs/jumpsuit.json +++ b/code/datums/greyscale/json_configs/jumpsuit.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "jumpsuit", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -17,7 +17,7 @@ "type": "icon_state", "icon_state": "jumpskirt", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/jumpsuit_inhand.json b/code/datums/greyscale/json_configs/jumpsuit_inhand.json index 754620651b9..e26dc7b336a 100644 --- a/code/datums/greyscale/json_configs/jumpsuit_inhand.json +++ b/code/datums/greyscale/json_configs/jumpsuit_inhand.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "jumpsuit", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/jumpsuit_prison.json b/code/datums/greyscale/json_configs/jumpsuit_prison.json index 1ac85b764bf..045c67c0ff9 100644 --- a/code/datums/greyscale/json_configs/jumpsuit_prison.json +++ b/code/datums/greyscale/json_configs/jumpsuit_prison.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "jumpsuit", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -17,7 +17,7 @@ "type": "icon_state", "icon_state": "jumpskirt", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/jumpsuit_prison_inhand.json b/code/datums/greyscale/json_configs/jumpsuit_prison_inhand.json index be537b5a00a..818cb2c3a01 100644 --- a/code/datums/greyscale/json_configs/jumpsuit_prison_inhand.json +++ b/code/datums/greyscale/json_configs/jumpsuit_prison_inhand.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "jumpsuit", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/jumpsuit_prison_worn.json b/code/datums/greyscale/json_configs/jumpsuit_prison_worn.json index 0096c95e812..3a5993e5bc4 100644 --- a/code/datums/greyscale/json_configs/jumpsuit_prison_worn.json +++ b/code/datums/greyscale/json_configs/jumpsuit_prison_worn.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "jumpsuit", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -12,12 +12,12 @@ "blend_mode": "overlay" } ], - "jumpsuit_d" : [ + "jumpsuit_d": [ { "type": "icon_state", "icon_state": "jumpsuit_d", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -30,7 +30,7 @@ "type": "icon_state", "icon_state": "jumpskirt", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -38,12 +38,12 @@ "blend_mode": "overlay" } ], - "jumpskirt_d" : [ + "jumpskirt_d": [ { "type": "icon_state", "icon_state": "jumpskirt_d", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/jumpsuit_worn.json b/code/datums/greyscale/json_configs/jumpsuit_worn.json index b2e81aa1b15..6ae10268cbb 100644 --- a/code/datums/greyscale/json_configs/jumpsuit_worn.json +++ b/code/datums/greyscale/json_configs/jumpsuit_worn.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "jumpsuit", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -12,12 +12,12 @@ "blend_mode": "overlay" } ], - "jumpsuit_d" : [ + "jumpsuit_d": [ { "type": "icon_state", "icon_state": "jumpsuit_d", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "jumpskirt": [ @@ -25,7 +25,7 @@ "type": "icon_state", "icon_state": "jumpskirt", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -33,12 +33,12 @@ "blend_mode": "overlay" } ], - "jumpskirt_d" : [ + "jumpskirt_d": [ { "type": "icon_state", "icon_state": "jumpskirt_d", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/kitsune.json b/code/datums/greyscale/json_configs/kitsune.json index 495520fbbd8..a33b528d8e6 100644 --- a/code/datums/greyscale/json_configs/kitsune.json +++ b/code/datums/greyscale/json_configs/kitsune.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "kitsune_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "kitsune_stripe", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ], "kitsune_up": [ @@ -18,13 +18,13 @@ "type": "icon_state", "icon_state": "kitsune_base_up", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "kitsune_stripe_up", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/labcoat.json b/code/datums/greyscale/json_configs/labcoat.json index f95b86893b0..59aec844f35 100644 --- a/code/datums/greyscale/json_configs/labcoat.json +++ b/code/datums/greyscale/json_configs/labcoat.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "labcoat_job", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sash", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "shoulder", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "back", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ], "labcoat_job_t": [ @@ -30,25 +30,25 @@ "type": "icon_state", "icon_state": "labcoat_job_t", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sash_t", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "shoulder", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "back_t", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] } ] } diff --git a/code/datums/greyscale/json_configs/manipulator_hand.json b/code/datums/greyscale/json_configs/manipulator_hand.json index be7c96df62b..ff1f9277957 100644 --- a/code/datums/greyscale/json_configs/manipulator_hand.json +++ b/code/datums/greyscale/json_configs/manipulator_hand.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "hand_colour", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/material_airlock.json b/code/datums/greyscale/json_configs/material_airlock.json index 12934c4946d..71a922812ed 100644 --- a/code/datums/greyscale/json_configs/material_airlock.json +++ b/code/datums/greyscale/json_configs/material_airlock.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "base_closed", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -17,7 +17,7 @@ "type": "icon_state", "icon_state": "base_open", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -30,7 +30,7 @@ "type": "icon_state", "icon_state": "base_opening", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -43,7 +43,7 @@ "type": "icon_state", "icon_state": "base_closing", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -56,7 +56,7 @@ "type": "icon_state", "icon_state": "base_construction", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -69,7 +69,7 @@ "type": "icon_state", "icon_state": "fill_closed", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "fill_open": [ @@ -77,7 +77,7 @@ "type": "icon_state", "icon_state": "fill_open", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "fill_opening": [ @@ -85,7 +85,7 @@ "type": "icon_state", "icon_state": "fill_opening", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "fill_closing": [ @@ -93,7 +93,7 @@ "type": "icon_state", "icon_state": "fill_closing", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "fill_construction": [ @@ -101,10 +101,10 @@ "type": "icon_state", "icon_state": "fill_construction", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], - "" : [ + "": [ { "type": "icon_state", "icon_state": "fill_open", diff --git a/code/datums/greyscale/json_configs/material_effects/shimmer.json b/code/datums/greyscale/json_configs/material_effects/shimmer.json index 64e2168e5c2..9ee9070bc75 100644 --- a/code/datums/greyscale/json_configs/material_effects/shimmer.json +++ b/code/datums/greyscale/json_configs/material_effects/shimmer.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "animation", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/messyworn_shirt_graphic.json b/code/datums/greyscale/json_configs/messyworn_shirt_graphic.json index 85950d388e2..1d5f273f82d 100644 --- a/code/datums/greyscale/json_configs/messyworn_shirt_graphic.json +++ b/code/datums/greyscale/json_configs/messyworn_shirt_graphic.json @@ -1,16 +1,16 @@ { - "messyworn_shirt_gamer": [ - { - "type": "icon_state", - "icon_state": "worn_messy", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "messyworn_shirt_gamer": [ + { + "type": "icon_state", + "icon_state": "worn_messy", + "blend_mode": "overlay", + "color_ids": [1] + }, { "type": "icon_state", "icon_state": "nerd_overlay", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", @@ -19,22 +19,22 @@ } ], "messyworn_shirt_ian": [ - { - "type": "icon_state", - "icon_state": "worn_messy", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + { + "type": "icon_state", + "icon_state": "worn_messy", + "blend_mode": "overlay", + "color_ids": [1] + }, { "type": "icon_state", "icon_state": "ian_overlay", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "ian_base", "blend_mode": "overlay" } - ] + ] } diff --git a/code/datums/greyscale/json_configs/meter.json b/code/datums/greyscale/json_configs/meter.json index 344500c2a9d..3eee94864b0 100644 --- a/code/datums/greyscale/json_configs/meter.json +++ b/code/datums/greyscale/json_configs/meter.json @@ -21,7 +21,7 @@ "type": "icon_state", "icon_state": "pressure0", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -39,7 +39,7 @@ "type": "icon_state", "icon_state": "pressure1_1", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -57,7 +57,7 @@ "type": "icon_state", "icon_state": "pressure1_2", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -75,7 +75,7 @@ "type": "icon_state", "icon_state": "pressure1_3", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -93,7 +93,7 @@ "type": "icon_state", "icon_state": "pressure1_4", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -111,7 +111,7 @@ "type": "icon_state", "icon_state": "pressure1_5", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -129,7 +129,7 @@ "type": "icon_state", "icon_state": "pressure1_6", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -147,7 +147,7 @@ "type": "icon_state", "icon_state": "pressure2_1", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -165,7 +165,7 @@ "type": "icon_state", "icon_state": "pressure2_2", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -183,7 +183,7 @@ "type": "icon_state", "icon_state": "pressure2_3", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -201,7 +201,7 @@ "type": "icon_state", "icon_state": "pressure2_4", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -219,7 +219,7 @@ "type": "icon_state", "icon_state": "pressure2_5", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -237,7 +237,7 @@ "type": "icon_state", "icon_state": "pressure2_6", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -255,7 +255,7 @@ "type": "icon_state", "icon_state": "pressure3_1", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -273,7 +273,7 @@ "type": "icon_state", "icon_state": "pressure3_2", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -291,7 +291,7 @@ "type": "icon_state", "icon_state": "pressure3_3", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -309,7 +309,7 @@ "type": "icon_state", "icon_state": "pressure3_4", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -327,7 +327,7 @@ "type": "icon_state", "icon_state": "pressure3_5", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -345,7 +345,7 @@ "type": "icon_state", "icon_state": "pressure3_6", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -363,7 +363,7 @@ "type": "icon_state", "icon_state": "pressure4", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/mod_core_soul.json b/code/datums/greyscale/json_configs/mod_core_soul.json index fbdd965ac6c..4043cb58a4a 100644 --- a/code/datums/greyscale/json_configs/mod_core_soul.json +++ b/code/datums/greyscale/json_configs/mod_core_soul.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "mod-core-soul-shard", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/moth_coat.json b/code/datums/greyscale/json_configs/moth_coat.json index 84cdfb4821e..ca4761bc257 100644 --- a/code/datums/greyscale/json_configs/moth_coat.json +++ b/code/datums/greyscale/json_configs/moth_coat.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "mothcoat", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/moth_coat_winter.json b/code/datums/greyscale/json_configs/moth_coat_winter.json index 6c8c36615e3..38e618e4fcd 100644 --- a/code/datums/greyscale/json_configs/moth_coat_winter.json +++ b/code/datums/greyscale/json_configs/moth_coat_winter.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "mothcoat_mantle_top", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "mothcoat_mantle_bottom", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/mutant_organs.json b/code/datums/greyscale/json_configs/mutant_organs.json index 2e4aa1da884..727d759af8e 100644 --- a/code/datums/greyscale/json_configs/mutant_organs.json +++ b/code/datums/greyscale/json_configs/mutant_organs.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "appendix", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "appendix_insides", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ], "brain": [ @@ -18,7 +18,7 @@ "type": "icon_state", "icon_state": "brain", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -31,7 +31,7 @@ "type": "icon_state", "icon_state": "ears", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -44,19 +44,19 @@ "type": "icon_state", "icon_state": "eyes", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "eyes_sclera", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "eyes_pupil", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", @@ -69,7 +69,7 @@ "type": "icon_state", "icon_state": "heart", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -82,7 +82,7 @@ "type": "icon_state", "icon_state": "liver", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -95,7 +95,7 @@ "type": "icon_state", "icon_state": "lungs", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -108,7 +108,7 @@ "type": "icon_state", "icon_state": "tongue", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "stomach": [ @@ -116,7 +116,7 @@ "type": "icon_state", "icon_state": "stomach", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/overalls.json b/code/datums/greyscale/json_configs/overalls.json index c77da142d70..b03bd5eea64 100644 --- a/code/datums/greyscale/json_configs/overalls.json +++ b/code/datums/greyscale/json_configs/overalls.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "overalls", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/party_hat.json b/code/datums/greyscale/json_configs/party_hat.json index 8a83eb04101..c74920ee2b5 100644 --- a/code/datums/greyscale/json_configs/party_hat.json +++ b/code/datums/greyscale/json_configs/party_hat.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "party_hat", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/pda.json b/code/datums/greyscale/json_configs/pda.json index c10b453817a..bfb51c90fb4 100644 --- a/code/datums/greyscale/json_configs/pda.json +++ b/code/datums/greyscale/json_configs/pda.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pda_captain.json b/code/datums/greyscale/json_configs/pda_captain.json index 7fd41fdfad8..6a7d1312d12 100644 --- a/code/datums/greyscale/json_configs/pda_captain.json +++ b/code/datums/greyscale/json_configs/pda_captain.json @@ -4,25 +4,25 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "pda_stripe_double", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "pda_stripe_thick", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pda_chaplain.json b/code/datums/greyscale/json_configs/pda_chaplain.json index e4e351e339d..7db61e6c91a 100644 --- a/code/datums/greyscale/json_configs/pda_chaplain.json +++ b/code/datums/greyscale/json_configs/pda_chaplain.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pda_head.json b/code/datums/greyscale/json_configs/pda_head.json index c9f56870373..39c7bc53304 100644 --- a/code/datums/greyscale/json_configs/pda_head.json +++ b/code/datums/greyscale/json_configs/pda_head.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pda_mime.json b/code/datums/greyscale/json_configs/pda_mime.json index dc76e60649b..92f7c7a9ce9 100644 --- a/code/datums/greyscale/json_configs/pda_mime.json +++ b/code/datums/greyscale/json_configs/pda_mime.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -15,7 +15,7 @@ "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pda_stripe_double.json b/code/datums/greyscale/json_configs/pda_stripe_double.json index 42346a2c86d..8b55ef4f8db 100644 --- a/code/datums/greyscale/json_configs/pda_stripe_double.json +++ b/code/datums/greyscale/json_configs/pda_stripe_double.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "pda_stripe_double", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pda_stripe_split.json b/code/datums/greyscale/json_configs/pda_stripe_split.json index 82aaaac1031..987b2a573b9 100644 --- a/code/datums/greyscale/json_configs/pda_stripe_split.json +++ b/code/datums/greyscale/json_configs/pda_stripe_split.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "pda_stripe_split", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pda_stripe_thick.json b/code/datums/greyscale/json_configs/pda_stripe_thick.json index cc730f3816a..1011e8c6f0c 100644 --- a/code/datums/greyscale/json_configs/pda_stripe_thick.json +++ b/code/datums/greyscale/json_configs/pda_stripe_thick.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "pda_stripe_thick", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pda_stripe_thick_head.json b/code/datums/greyscale/json_configs/pda_stripe_thick_head.json index ea216b2476b..c3dfd453401 100644 --- a/code/datums/greyscale/json_configs/pda_stripe_thick_head.json +++ b/code/datums/greyscale/json_configs/pda_stripe_thick_head.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "pda_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pda_buttons", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "pda_stripe_thick", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pet_carrier.json b/code/datums/greyscale/json_configs/pet_carrier.json index 1674765268f..a1a97da75e7 100644 --- a/code/datums/greyscale/json_configs/pet_carrier.json +++ b/code/datums/greyscale/json_configs/pet_carrier.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "pet_carrier_gags", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "pet_carrier_closed_unlocked": [ @@ -27,7 +27,7 @@ "type": "icon_state", "icon_state": "pet_carrier_gags", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "pet_carrier_closed_locked": [ @@ -45,7 +45,7 @@ "type": "icon_state", "icon_state": "pet_carrier_gags", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "pet_carrier_occupied_unlocked": [ @@ -63,7 +63,7 @@ "type": "icon_state", "icon_state": "pet_carrier_gags", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "pet_carrier_occupied_locked": [ @@ -81,7 +81,7 @@ "type": "icon_state", "icon_state": "pet_carrier_gags", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/pet_carrier_inhands.json b/code/datums/greyscale/json_configs/pet_carrier_inhands.json index 05978e3c829..95073f14064 100644 --- a/code/datums/greyscale/json_configs/pet_carrier_inhands.json +++ b/code/datums/greyscale/json_configs/pet_carrier_inhands.json @@ -1,15 +1,15 @@ { - "pet_carrier": [ - { - "type": "icon_state", - "icon_state": "pet_carrier", - "blend_mode": "overlay" - }, + "pet_carrier": [ { - "type": "icon_state", - "icon_state": "pet_carrier_gags", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } - ] + "type": "icon_state", + "icon_state": "pet_carrier", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "pet_carrier_gags", + "blend_mode": "overlay", + "color_ids": [1] + } + ] } diff --git a/code/datums/greyscale/json_configs/piggy_bank.json b/code/datums/greyscale/json_configs/piggy_bank.json index 71876213e19..8ab4da5f89a 100644 --- a/code/datums/greyscale/json_configs/piggy_bank.json +++ b/code/datums/greyscale/json_configs/piggy_bank.json @@ -1,10 +1,10 @@ { - "piggy_bank": [ - { - "type": "icon_state", - "icon_state": "piggy_bank", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } + "piggy_bank": [ + { + "type": "icon_state", + "icon_state": "piggy_bank", + "blend_mode": "overlay", + "color_ids": [1] + } ] } diff --git a/code/datums/greyscale/json_configs/plaidskirt.json b/code/datums/greyscale/json_configs/plaidskirt.json index 9cd6e3e0363..aae210b6e98 100644 --- a/code/datums/greyscale/json_configs/plaidskirt.json +++ b/code/datums/greyscale/json_configs/plaidskirt.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "plaidskirt_plaid", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/plaidskirt_worn.json b/code/datums/greyscale/json_configs/plaidskirt_worn.json index 8be645b21f0..73722f7dbfa 100644 --- a/code/datums/greyscale/json_configs/plaidskirt_worn.json +++ b/code/datums/greyscale/json_configs/plaidskirt_worn.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "plaidskirt_plaid", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -12,12 +12,12 @@ "blend_mode": "overlay" } ], - "plaidskirt_d" : [ + "plaidskirt_d": [ { "type": "icon_state", "icon_state": "plaidskirt_plaid_d", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/plushie_carp.json b/code/datums/greyscale/json_configs/plushie_carp.json index e697a8d7323..dad3cb3d3d2 100644 --- a/code/datums/greyscale/json_configs/plushie_carp.json +++ b/code/datums/greyscale/json_configs/plushie_carp.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "plushie_carp_body", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "plushie_carp_eyes", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/plushie_lizard.json b/code/datums/greyscale/json_configs/plushie_lizard.json index 5326beac0b1..76912c5c7c1 100644 --- a/code/datums/greyscale/json_configs/plushie_lizard.json +++ b/code/datums/greyscale/json_configs/plushie_lizard.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "plushie_lizard_body", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "plushie_lizard_eyes", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/plushie_slime.json b/code/datums/greyscale/json_configs/plushie_slime.json index e35bf6efb69..0c72b009a75 100644 --- a/code/datums/greyscale/json_configs/plushie_slime.json +++ b/code/datums/greyscale/json_configs/plushie_slime.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "plushie_slime_body", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "plushie_slime_eyes", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/plushie_snake.json b/code/datums/greyscale/json_configs/plushie_snake.json index dfa74f47c0d..2021cf732e0 100644 --- a/code/datums/greyscale/json_configs/plushie_snake.json +++ b/code/datums/greyscale/json_configs/plushie_snake.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "plushie_snake_body", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "plushie_snake_eyes", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/plushie_spacelizard.json b/code/datums/greyscale/json_configs/plushie_spacelizard.json index 630fb8743bb..621bd389339 100644 --- a/code/datums/greyscale/json_configs/plushie_spacelizard.json +++ b/code/datums/greyscale/json_configs/plushie_spacelizard.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "plushie_lizard_body", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "plushie_lizard_eyes", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/pony.json b/code/datums/greyscale/json_configs/pony.json index a08437c7cb6..bda7acceb9c 100644 --- a/code/datums/greyscale/json_configs/pony.json +++ b/code/datums/greyscale/json_configs/pony.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "pony", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pony_hair", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ], "pony_dead": [ @@ -18,13 +18,13 @@ "type": "icon_state", "icon_state": "pony_dead", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "pony_hair_dead", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/quantum_keycard.json b/code/datums/greyscale/json_configs/quantum_keycard.json index d9c384428e2..1a349723da6 100644 --- a/code/datums/greyscale/json_configs/quantum_keycard.json +++ b/code/datums/greyscale/json_configs/quantum_keycard.json @@ -1,5 +1,5 @@ { - "quantum_keycard_gags" : [ + "quantum_keycard_gags": [ { "type": "icon_state", "icon_state": "quantum_keycard", @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "quantum_wrapper", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/rebellion_mask.json b/code/datums/greyscale/json_configs/rebellion_mask.json index 1c421b00b79..19cc2bda751 100644 --- a/code/datums/greyscale/json_configs/rebellion_mask.json +++ b/code/datums/greyscale/json_configs/rebellion_mask.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "rebellion_mask", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/sailor_dress.json b/code/datums/greyscale/json_configs/sailor_dress.json index 86787f4a251..922e7e57b6d 100644 --- a/code/datums/greyscale/json_configs/sailor_dress.json +++ b/code/datums/greyscale/json_configs/sailor_dress.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "sailor_dress_skirt", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sailor_dress_jacket", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "sailor_dress_stripes", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/santa_hat.json b/code/datums/greyscale/json_configs/santa_hat.json index dda130d59c7..1eced913e89 100644 --- a/code/datums/greyscale/json_configs/santa_hat.json +++ b/code/datums/greyscale/json_configs/santa_hat.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "santa_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "santa_trim", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/scarf.json b/code/datums/greyscale/json_configs/scarf.json index 7d1ab784e43..727487cac5a 100644 --- a/code/datums/greyscale/json_configs/scarf.json +++ b/code/datums/greyscale/json_configs/scarf.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "scarf_stripe", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "scarf_base", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ], "large_scarf": [ @@ -18,13 +18,13 @@ "type": "icon_state", "icon_state": "large_scarf_stripe", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "large_scarf_base", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/screwdriver.json b/code/datums/greyscale/json_configs/screwdriver.json index 7604eb07465..9c4317a67e1 100644 --- a/code/datums/greyscale/json_configs/screwdriver.json +++ b/code/datums/greyscale/json_configs/screwdriver.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "screwdriver", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/screwdriver_worn.json b/code/datums/greyscale/json_configs/screwdriver_worn.json index 9e63bb6b883..8a0f929a493 100644 --- a/code/datums/greyscale/json_configs/screwdriver_worn.json +++ b/code/datums/greyscale/json_configs/screwdriver_worn.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "screwdriver", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/shorts.json b/code/datums/greyscale/json_configs/shorts.json index 6e9e77d8391..68fdc494371 100644 --- a/code/datums/greyscale/json_configs/shorts.json +++ b/code/datums/greyscale/json_configs/shorts.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "shorts", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/simple_flower.json b/code/datums/greyscale/json_configs/simple_flower.json index 986615c8f15..2b8e87b892a 100644 --- a/code/datums/greyscale/json_configs/simple_flower.json +++ b/code/datums/greyscale/json_configs/simple_flower.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "flower_petal", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/simple_flower_worn.json b/code/datums/greyscale/json_configs/simple_flower_worn.json index 9a43d2cbd98..c9ba94f54b5 100644 --- a/code/datums/greyscale/json_configs/simple_flower_worn.json +++ b/code/datums/greyscale/json_configs/simple_flower_worn.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "flower_petals_worn", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/slacks.json b/code/datums/greyscale/json_configs/slacks.json index 85242d6e235..fbbed4abeb7 100644 --- a/code/datums/greyscale/json_configs/slacks.json +++ b/code/datums/greyscale/json_configs/slacks.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "buckle", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "belt", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "slacks", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/smooth_canister_stationary.json b/code/datums/greyscale/json_configs/smooth_canister_stationary.json index 62e97d22f76..13f02323f97 100644 --- a/code/datums/greyscale/json_configs/smooth_canister_stationary.json +++ b/code/datums/greyscale/json_configs/smooth_canister_stationary.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "canister-0", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-1": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "canister-1", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-2": [ @@ -20,7 +20,7 @@ "type": "icon_state", "icon_state": "canister-2", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-3": [ @@ -28,7 +28,7 @@ "type": "icon_state", "icon_state": "canister-3", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-4": [ @@ -36,7 +36,7 @@ "type": "icon_state", "icon_state": "canister-4", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-5": [ @@ -44,7 +44,7 @@ "type": "icon_state", "icon_state": "canister-5", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-6": [ @@ -52,7 +52,7 @@ "type": "icon_state", "icon_state": "canister-6", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-7": [ @@ -60,7 +60,7 @@ "type": "icon_state", "icon_state": "canister-7", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-8": [ @@ -68,7 +68,7 @@ "type": "icon_state", "icon_state": "canister-8", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-9": [ @@ -76,7 +76,7 @@ "type": "icon_state", "icon_state": "canister-9", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-10": [ @@ -84,7 +84,7 @@ "type": "icon_state", "icon_state": "canister-10", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-11": [ @@ -92,7 +92,7 @@ "type": "icon_state", "icon_state": "canister-11", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-12": [ @@ -100,7 +100,7 @@ "type": "icon_state", "icon_state": "canister-12", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-13": [ @@ -108,7 +108,7 @@ "type": "icon_state", "icon_state": "canister-13", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-14": [ @@ -116,7 +116,7 @@ "type": "icon_state", "icon_state": "canister-14", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-15": [ @@ -124,7 +124,7 @@ "type": "icon_state", "icon_state": "canister-15", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-21": [ @@ -132,7 +132,7 @@ "type": "icon_state", "icon_state": "canister-21", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-23": [ @@ -140,7 +140,7 @@ "type": "icon_state", "icon_state": "canister-23", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-29": [ @@ -148,7 +148,7 @@ "type": "icon_state", "icon_state": "canister-29", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-31": [ @@ -156,7 +156,7 @@ "type": "icon_state", "icon_state": "canister-31", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-38": [ @@ -164,7 +164,7 @@ "type": "icon_state", "icon_state": "canister-38", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-39": [ @@ -172,7 +172,7 @@ "type": "icon_state", "icon_state": "canister-39", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-46": [ @@ -180,7 +180,7 @@ "type": "icon_state", "icon_state": "canister-46", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-47": [ @@ -188,7 +188,7 @@ "type": "icon_state", "icon_state": "canister-47", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-55": [ @@ -196,7 +196,7 @@ "type": "icon_state", "icon_state": "canister-55", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-63": [ @@ -204,7 +204,7 @@ "type": "icon_state", "icon_state": "canister-63", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-74": [ @@ -212,7 +212,7 @@ "type": "icon_state", "icon_state": "canister-74", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-75": [ @@ -220,7 +220,7 @@ "type": "icon_state", "icon_state": "canister-75", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-78": [ @@ -228,7 +228,7 @@ "type": "icon_state", "icon_state": "canister-78", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-79": [ @@ -236,7 +236,7 @@ "type": "icon_state", "icon_state": "canister-79", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-95": [ @@ -244,7 +244,7 @@ "type": "icon_state", "icon_state": "canister-95", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-110": [ @@ -252,7 +252,7 @@ "type": "icon_state", "icon_state": "canister-110", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-111": [ @@ -260,7 +260,7 @@ "type": "icon_state", "icon_state": "canister-111", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-127": [ @@ -268,7 +268,7 @@ "type": "icon_state", "icon_state": "canister-127", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-137": [ @@ -276,7 +276,7 @@ "type": "icon_state", "icon_state": "canister-137", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-139": [ @@ -284,7 +284,7 @@ "type": "icon_state", "icon_state": "canister-139", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-141": [ @@ -292,7 +292,7 @@ "type": "icon_state", "icon_state": "canister-141", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-143": [ @@ -300,7 +300,7 @@ "type": "icon_state", "icon_state": "canister-143", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-157": [ @@ -308,7 +308,7 @@ "type": "icon_state", "icon_state": "canister-157", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-159": [ @@ -316,7 +316,7 @@ "type": "icon_state", "icon_state": "canister-159", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-175": [ @@ -324,7 +324,7 @@ "type": "icon_state", "icon_state": "canister-175", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-191": [ @@ -332,7 +332,7 @@ "type": "icon_state", "icon_state": "canister-191", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-203": [ @@ -340,7 +340,7 @@ "type": "icon_state", "icon_state": "canister-203", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-207": [ @@ -348,7 +348,7 @@ "type": "icon_state", "icon_state": "canister-207", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-223": [ @@ -356,7 +356,7 @@ "type": "icon_state", "icon_state": "canister-223", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-239": [ @@ -364,7 +364,7 @@ "type": "icon_state", "icon_state": "canister-239", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "canister-255": [ @@ -372,7 +372,7 @@ "type": "icon_state", "icon_state": "canister-255", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/smooth_canister_stationary_overlays.json b/code/datums/greyscale/json_configs/smooth_canister_stationary_overlays.json index 6dc7e73c32b..238ee2b7610 100644 --- a/code/datums/greyscale/json_configs/smooth_canister_stationary_overlays.json +++ b/code/datums/greyscale/json_configs/smooth_canister_stationary_overlays.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "window-fg", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "window-bg": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "window-bg", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/sneakers.json b/code/datums/greyscale/json_configs/sneakers.json index 50a064bb02b..f23d43c2e95 100644 --- a/code/datums/greyscale/json_configs/sneakers.json +++ b/code/datums/greyscale/json_configs/sneakers.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "sneakers_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sneakers_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/sneakers_inhand.json b/code/datums/greyscale/json_configs/sneakers_inhand.json index f6d712ff181..71bb2177592 100644 --- a/code/datums/greyscale/json_configs/sneakers_inhand.json +++ b/code/datums/greyscale/json_configs/sneakers_inhand.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "sneakers_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sneakers_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/sneakers_marisa.json b/code/datums/greyscale/json_configs/sneakers_marisa.json index b42838b3e15..82ddc5979b4 100644 --- a/code/datums/greyscale/json_configs/sneakers_marisa.json +++ b/code/datums/greyscale/json_configs/sneakers_marisa.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "sneakers_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sneakers_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/sneakers_orange.json b/code/datums/greyscale/json_configs/sneakers_orange.json index fb0a07ff196..b2822a9ec0d 100644 --- a/code/datums/greyscale/json_configs/sneakers_orange.json +++ b/code/datums/greyscale/json_configs/sneakers_orange.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "sneakers_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sneakers_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ], "sneakers_chained": [ @@ -18,13 +18,13 @@ "type": "icon_state", "icon_state": "sneakers_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sneakers_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/sneakers_orange_inhand.json b/code/datums/greyscale/json_configs/sneakers_orange_inhand.json index de2cae90e03..5b3f117f76f 100644 --- a/code/datums/greyscale/json_configs/sneakers_orange_inhand.json +++ b/code/datums/greyscale/json_configs/sneakers_orange_inhand.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "sneakers_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sneakers_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ], "sneakers_chained": [ @@ -18,13 +18,13 @@ "type": "icon_state", "icon_state": "sneakers_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sneakers_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/sneakers_wheelys.json b/code/datums/greyscale/json_configs/sneakers_wheelys.json index 221dd5717fe..ea8d8cca632 100644 --- a/code/datums/greyscale/json_configs/sneakers_wheelys.json +++ b/code/datums/greyscale/json_configs/sneakers_wheelys.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "sneakers_back", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sneakers_front", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/sombrero.json b/code/datums/greyscale/json_configs/sombrero.json index 8a183c55def..15bc99e1e71 100644 --- a/code/datums/greyscale/json_configs/sombrero.json +++ b/code/datums/greyscale/json_configs/sombrero.json @@ -1,23 +1,23 @@ { - "sombrero": [ - { - "type": "reference", - "reference_type": "/datum/greyscale_config/sombrero/base", - "blend_mode": "overlay", - "color_ids": [ 1, 2 ] - } - ], - "shamebrero": [ - { - "type": "reference", - "reference_type": "/datum/greyscale_config/sombrero/base", - "blend_mode": "overlay", - "color_ids": [ 1, 2 ] - }, - { - "type": "icon_state", - "icon_state": "dongles", - "blend_mode": "overlay" - } - ] + "sombrero": [ + { + "type": "reference", + "reference_type": "/datum/greyscale_config/sombrero/base", + "blend_mode": "overlay", + "color_ids": [1, 2] + } + ], + "shamebrero": [ + { + "type": "reference", + "reference_type": "/datum/greyscale_config/sombrero/base", + "blend_mode": "overlay", + "color_ids": [1, 2] + }, + { + "type": "icon_state", + "icon_state": "dongles", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/sombrero_base.json b/code/datums/greyscale/json_configs/sombrero_base.json index 9f2097ac2e8..3cb39dcb967 100644 --- a/code/datums/greyscale/json_configs/sombrero_base.json +++ b/code/datums/greyscale/json_configs/sombrero_base.json @@ -1,21 +1,21 @@ { - "": [ - { - "type": "icon_state", - "icon_state": "cloth", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, - { - "type": "icon_state", - "icon_state": "ornamentation", - "blend_mode": "overlay", - "color_ids": [ 2 ] - }, - { - "type": "icon_state", - "icon_state": "plate", - "blend_mode": "overlay" - } - ] + "": [ + { + "type": "icon_state", + "icon_state": "cloth", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "ornamentation", + "blend_mode": "overlay", + "color_ids": [2] + }, + { + "type": "icon_state", + "icon_state": "plate", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/sombrero_base_lefthand.json b/code/datums/greyscale/json_configs/sombrero_base_lefthand.json index d9d26e0b9c2..3b717982828 100644 --- a/code/datums/greyscale/json_configs/sombrero_base_lefthand.json +++ b/code/datums/greyscale/json_configs/sombrero_base_lefthand.json @@ -1,16 +1,16 @@ { - "": [ - { - "type": "icon_state", - "icon_state": "cloth_lefthand", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, - { - "type": "icon_state", - "icon_state": "ornamentation_lefthand", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "": [ + { + "type": "icon_state", + "icon_state": "cloth_lefthand", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "ornamentation_lefthand", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } diff --git a/code/datums/greyscale/json_configs/sombrero_base_righthand.json b/code/datums/greyscale/json_configs/sombrero_base_righthand.json index 32769cb21be..8d7df6d2d37 100644 --- a/code/datums/greyscale/json_configs/sombrero_base_righthand.json +++ b/code/datums/greyscale/json_configs/sombrero_base_righthand.json @@ -1,16 +1,16 @@ { - "": [ - { - "type": "icon_state", - "icon_state": "cloth_righthand", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, - { - "type": "icon_state", - "icon_state": "ornamentation_righthand", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "": [ + { + "type": "icon_state", + "icon_state": "cloth_righthand", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "ornamentation_righthand", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } diff --git a/code/datums/greyscale/json_configs/sombrero_base_worn.json b/code/datums/greyscale/json_configs/sombrero_base_worn.json index e97c1875df4..c385af94fde 100644 --- a/code/datums/greyscale/json_configs/sombrero_base_worn.json +++ b/code/datums/greyscale/json_configs/sombrero_base_worn.json @@ -1,21 +1,21 @@ { - "": [ - { - "type": "icon_state", - "icon_state": "cloth_worn", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, - { - "type": "icon_state", - "icon_state": "ornamentation_worn", - "blend_mode": "overlay", - "color_ids": [ 2 ] - }, - { - "type": "icon_state", - "icon_state": "plate_worn", - "blend_mode": "overlay" - } - ] + "": [ + { + "type": "icon_state", + "icon_state": "cloth_worn", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "ornamentation_worn", + "blend_mode": "overlay", + "color_ids": [2] + }, + { + "type": "icon_state", + "icon_state": "plate_worn", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/sombrero_lefthand.json b/code/datums/greyscale/json_configs/sombrero_lefthand.json index 5ba8a89ed28..00dea2d4089 100644 --- a/code/datums/greyscale/json_configs/sombrero_lefthand.json +++ b/code/datums/greyscale/json_configs/sombrero_lefthand.json @@ -1,23 +1,23 @@ { - "sombrero": [ - { - "type": "reference", - "reference_type": "/datum/greyscale_config/sombrero/base_lefthand", - "blend_mode": "overlay", - "color_ids": [ 1, 2 ] - } - ], - "shamebrero": [ - { - "type": "reference", - "reference_type": "/datum/greyscale_config/sombrero/base_lefthand", - "blend_mode": "overlay", - "color_ids": [ 1, 2 ] - }, - { - "type": "icon_state", - "icon_state": "dongles_lefthand", - "blend_mode": "overlay" - } - ] + "sombrero": [ + { + "type": "reference", + "reference_type": "/datum/greyscale_config/sombrero/base_lefthand", + "blend_mode": "overlay", + "color_ids": [1, 2] + } + ], + "shamebrero": [ + { + "type": "reference", + "reference_type": "/datum/greyscale_config/sombrero/base_lefthand", + "blend_mode": "overlay", + "color_ids": [1, 2] + }, + { + "type": "icon_state", + "icon_state": "dongles_lefthand", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/sombrero_righthand.json b/code/datums/greyscale/json_configs/sombrero_righthand.json index 07737ad2532..65abf57816e 100644 --- a/code/datums/greyscale/json_configs/sombrero_righthand.json +++ b/code/datums/greyscale/json_configs/sombrero_righthand.json @@ -1,23 +1,23 @@ { - "sombrero": [ - { - "type": "reference", - "reference_type": "/datum/greyscale_config/sombrero/base_righthand", - "blend_mode": "overlay", - "color_ids": [ 1, 2 ] - } - ], - "shamebrero": [ - { - "type": "reference", - "reference_type": "/datum/greyscale_config/sombrero/base_righthand", - "blend_mode": "overlay", - "color_ids": [ 1, 2 ] - }, - { - "type": "icon_state", - "icon_state": "dongles_righthand", - "blend_mode": "overlay" - } - ] + "sombrero": [ + { + "type": "reference", + "reference_type": "/datum/greyscale_config/sombrero/base_righthand", + "blend_mode": "overlay", + "color_ids": [1, 2] + } + ], + "shamebrero": [ + { + "type": "reference", + "reference_type": "/datum/greyscale_config/sombrero/base_righthand", + "blend_mode": "overlay", + "color_ids": [1, 2] + }, + { + "type": "icon_state", + "icon_state": "dongles_righthand", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/sombrero_worn.json b/code/datums/greyscale/json_configs/sombrero_worn.json index a70cd5ce9c7..29b1d52c61e 100644 --- a/code/datums/greyscale/json_configs/sombrero_worn.json +++ b/code/datums/greyscale/json_configs/sombrero_worn.json @@ -1,23 +1,23 @@ { - "sombrero": [ - { - "type": "reference", - "reference_type": "/datum/greyscale_config/sombrero/base_worn", - "blend_mode": "overlay", - "color_ids": [ 1, 2 ] - } - ], - "shamebrero": [ - { - "type": "reference", - "reference_type": "/datum/greyscale_config/sombrero/base_worn", - "blend_mode": "overlay", - "color_ids": [ 1, 2 ] - }, - { - "type": "icon_state", - "icon_state": "dongles_worn", - "blend_mode": "overlay" - } - ] + "sombrero": [ + { + "type": "reference", + "reference_type": "/datum/greyscale_config/sombrero/base_worn", + "blend_mode": "overlay", + "color_ids": [1, 2] + } + ], + "shamebrero": [ + { + "type": "reference", + "reference_type": "/datum/greyscale_config/sombrero/base_worn", + "blend_mode": "overlay", + "color_ids": [1, 2] + }, + { + "type": "icon_state", + "icon_state": "dongles_worn", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/striped_dress.json b/code/datums/greyscale/json_configs/striped_dress.json index e4b95329e46..57bc9eab965 100644 --- a/code/datums/greyscale/json_configs/striped_dress.json +++ b/code/datums/greyscale/json_configs/striped_dress.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "stripeddress_jacket", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "stripeddress_base", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "stripeddress_stripes", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/sundress.json b/code/datums/greyscale/json_configs/sundress.json index 41435dbb658..89ff41d4825 100644 --- a/code/datums/greyscale/json_configs/sundress.json +++ b/code/datums/greyscale/json_configs/sundress.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "sundress_pistil", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sundress_pedal", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "sundress_base", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/suspenders.json b/code/datums/greyscale/json_configs/suspenders.json index e7ac4730563..dcafa93514c 100644 --- a/code/datums/greyscale/json_configs/suspenders.json +++ b/code/datums/greyscale/json_configs/suspenders.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "suspenders", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "suspenders_t": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "suspenders_t", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/sweater.json b/code/datums/greyscale/json_configs/sweater.json index 031ee45d4a5..380ae6720e1 100644 --- a/code/datums/greyscale/json_configs/sweater.json +++ b/code/datums/greyscale/json_configs/sweater.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "sweater", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "sweater_t": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "sweater_t", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/tango.json b/code/datums/greyscale/json_configs/tango.json index 87e9635e72f..53c89c9e5b6 100644 --- a/code/datums/greyscale/json_configs/tango.json +++ b/code/datums/greyscale/json_configs/tango.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "tango_belt", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "tango_base", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/tape.json b/code/datums/greyscale/json_configs/tape.json index b6d21e459a7..e3797468d8e 100644 --- a/code/datums/greyscale/json_configs/tape.json +++ b/code/datums/greyscale/json_configs/tape.json @@ -1,16 +1,16 @@ { - "tape": [ - { - "type": "icon_state", - "icon_state": "tape", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "tape": [ { - "type": "icon_state", - "icon_state": "roll", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "type": "icon_state", + "icon_state": "tape", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "roll", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } diff --git a/code/datums/greyscale/json_configs/tape_piece.json b/code/datums/greyscale/json_configs/tape_piece.json index f9538f20d2f..a69a1f49c45 100644 --- a/code/datums/greyscale/json_configs/tape_piece.json +++ b/code/datums/greyscale/json_configs/tape_piece.json @@ -1,10 +1,10 @@ { - "tape_piece": [ - { - "type": "icon_state", - "icon_state": "tape_piece", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } - ] + "tape_piece": [ + { + "type": "icon_state", + "icon_state": "tape_piece", + "blend_mode": "overlay", + "color_ids": [1] + } + ] } diff --git a/code/datums/greyscale/json_configs/tape_piece_spikes.json b/code/datums/greyscale/json_configs/tape_piece_spikes.json index 28b14d1953f..dbb41a6be1c 100644 --- a/code/datums/greyscale/json_configs/tape_piece_spikes.json +++ b/code/datums/greyscale/json_configs/tape_piece_spikes.json @@ -1,16 +1,16 @@ { - "tape_piece_spikes": [ - { - "type": "icon_state", - "icon_state": "tape_piece", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, - { - "type": "icon_state", - "icon_state": "tape_piece_spikes", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "tape_piece_spikes": [ + { + "type": "icon_state", + "icon_state": "tape_piece", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "tape_piece_spikes", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } diff --git a/code/datums/greyscale/json_configs/tape_piece_spikes_worn.json b/code/datums/greyscale/json_configs/tape_piece_spikes_worn.json index fecff11dadc..1b78a2ae1a3 100644 --- a/code/datums/greyscale/json_configs/tape_piece_spikes_worn.json +++ b/code/datums/greyscale/json_configs/tape_piece_spikes_worn.json @@ -1,16 +1,16 @@ { - "tape_piece_spikes_worn": [ - { - "type": "icon_state", - "icon_state": "tape_piece_worn", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, - { - "type": "icon_state", - "icon_state": "tape_piece_spikes_worn", - "blend_mode": "overlay", - "color_ids": [ 2 ] - } - ] + "tape_piece_spikes_worn": [ + { + "type": "icon_state", + "icon_state": "tape_piece_worn", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "tape_piece_spikes_worn", + "blend_mode": "overlay", + "color_ids": [2] + } + ] } diff --git a/code/datums/greyscale/json_configs/tape_piece_worn.json b/code/datums/greyscale/json_configs/tape_piece_worn.json index cf80171f183..2da8bbbd77d 100644 --- a/code/datums/greyscale/json_configs/tape_piece_worn.json +++ b/code/datums/greyscale/json_configs/tape_piece_worn.json @@ -1,10 +1,10 @@ { - "tape_piece_worn": [ - { - "type": "icon_state", - "icon_state": "tape_piece_worn", - "blend_mode": "overlay", - "color_ids": [ 1 ] - } - ] + "tape_piece_worn": [ + { + "type": "icon_state", + "icon_state": "tape_piece_worn", + "blend_mode": "overlay", + "color_ids": [1] + } + ] } diff --git a/code/datums/greyscale/json_configs/tape_spikes.json b/code/datums/greyscale/json_configs/tape_spikes.json index d0fb8c67d1b..8b24ade64ab 100644 --- a/code/datums/greyscale/json_configs/tape_spikes.json +++ b/code/datums/greyscale/json_configs/tape_spikes.json @@ -1,22 +1,22 @@ { - "tape_spikes": [ - { - "type": "icon_state", - "icon_state": "tape", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "tape_spikes": [ { - "type": "icon_state", - "icon_state": "roll", - "blend_mode": "overlay", - "color_ids": [ 2 ] - }, - { - "type": "icon_state", - "icon_state": "spikes", - "blend_mode": "overlay", - "color_ids": [ 3 ] - } - ] + "type": "icon_state", + "icon_state": "tape", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "roll", + "blend_mode": "overlay", + "color_ids": [2] + }, + { + "type": "icon_state", + "icon_state": "spikes", + "blend_mode": "overlay", + "color_ids": [3] + } + ] } diff --git a/code/datums/greyscale/json_configs/thermomachine.json b/code/datums/greyscale/json_configs/thermomachine.json index 37a4cbd6815..a60106a1c10 100644 --- a/code/datums/greyscale/json_configs/thermomachine.json +++ b/code/datums/greyscale/json_configs/thermomachine.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "temp_meter", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -17,7 +17,7 @@ "type": "icon_state", "icon_state": "temp_meter_1", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -30,7 +30,7 @@ "type": "icon_state", "icon_state": "temp_meter-o", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/ties.json b/code/datums/greyscale/json_configs/ties.json index 7f1e717c5f0..1b2d6201a4c 100644 --- a/code/datums/greyscale/json_configs/ties.json +++ b/code/datums/greyscale/json_configs/ties.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "tie_greyscale_tied", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "tie_greyscale_untied": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "tie_greyscale_untied", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "bowtie_greyscale": [ @@ -20,8 +20,7 @@ "type": "icon_state", "icon_state": "bowtie_greyscale", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] - } diff --git a/code/datums/greyscale/json_configs/trek.json b/code/datums/greyscale/json_configs/trek.json index bbeaa15f9a7..c5f658ddac6 100644 --- a/code/datums/greyscale/json_configs/trek.json +++ b/code/datums/greyscale/json_configs/trek.json @@ -9,7 +9,7 @@ "type": "icon_state", "icon_state": "tos_color", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -22,7 +22,7 @@ "type": "icon_state", "icon_state": "tos_color", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -45,7 +45,7 @@ "type": "icon_state", "icon_state": "tos_color", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -69,7 +69,7 @@ "type": "icon_state", "icon_state": "next_color", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -88,7 +88,7 @@ "type": "icon_state", "icon_state": "voy_color", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", @@ -107,7 +107,7 @@ "type": "icon_state", "icon_state": "ent_color", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/trenchcoat.json b/code/datums/greyscale/json_configs/trenchcoat.json index 2fbd1cc0ce6..38ed6425aed 100644 --- a/code/datums/greyscale/json_configs/trenchcoat.json +++ b/code/datums/greyscale/json_configs/trenchcoat.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "trenchcoat", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "trenchcoat_t": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "trenchcoat_t", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/turtleskirt.json b/code/datums/greyscale/json_configs/turtleskirt.json index f24d5cf6dcd..df1d01c30ac 100644 --- a/code/datums/greyscale/json_configs/turtleskirt.json +++ b/code/datums/greyscale/json_configs/turtleskirt.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "turtleskirt_top", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "turtleskirt_base", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/datums/greyscale/json_configs/vape.json b/code/datums/greyscale/json_configs/vape.json index 36dcc765cae..1af7187eda2 100644 --- a/code/datums/greyscale/json_configs/vape.json +++ b/code/datums/greyscale/json_configs/vape.json @@ -1,15 +1,15 @@ { - "vape": [ - { - "type": "icon_state", - "icon_state": "vapeOutlet", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "vape": [ { - "type": "icon_state", - "icon_state": "vapeInput", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "vapeOutlet", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "vapeInput", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/vape_worn.json b/code/datums/greyscale/json_configs/vape_worn.json index 662083958ef..df533994ce5 100644 --- a/code/datums/greyscale/json_configs/vape_worn.json +++ b/code/datums/greyscale/json_configs/vape_worn.json @@ -1,15 +1,15 @@ { - "vape_worn": [ - { - "type": "icon_state", - "icon_state": "vapeWorn", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "vape_worn": [ { - "type": "icon_state", - "icon_state": "vapeVapor", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "vapeWorn", + "blend_mode": "overlay", + "color_ids": [1] + }, + { + "type": "icon_state", + "icon_state": "vapeVapor", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/vapeopen_high.json b/code/datums/greyscale/json_configs/vapeopen_high.json index 1ef82459ca8..4749176759a 100644 --- a/code/datums/greyscale/json_configs/vapeopen_high.json +++ b/code/datums/greyscale/json_configs/vapeopen_high.json @@ -1,20 +1,20 @@ { - "vapeopen_high": [ - { - "type": "icon_state", - "icon_state": "vapeOutlet", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "vapeopen_high": [ { - "type": "icon_state", - "icon_state": "vapeInput", - "blend_mode": "overlay" - }, + "type": "icon_state", + "icon_state": "vapeOutlet", + "blend_mode": "overlay", + "color_ids": [1] + }, { - "type": "icon_state", - "icon_state": "vapeopen_high", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "vapeInput", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "vapeopen_high", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/vapeopen_low.json b/code/datums/greyscale/json_configs/vapeopen_low.json index eaef871bf3d..b7c94e732e0 100644 --- a/code/datums/greyscale/json_configs/vapeopen_low.json +++ b/code/datums/greyscale/json_configs/vapeopen_low.json @@ -1,20 +1,20 @@ { - "vapeopen_low": [ - { - "type": "icon_state", - "icon_state": "vapeOutlet", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "vapeopen_low": [ { - "type": "icon_state", - "icon_state": "vapeInput", - "blend_mode": "overlay" - }, + "type": "icon_state", + "icon_state": "vapeOutlet", + "blend_mode": "overlay", + "color_ids": [1] + }, { - "type": "icon_state", - "icon_state": "vapeopen_low", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "vapeInput", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "vapeopen_low", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/vapeopen_med.json b/code/datums/greyscale/json_configs/vapeopen_med.json index 508015825ce..330f41e8450 100644 --- a/code/datums/greyscale/json_configs/vapeopen_med.json +++ b/code/datums/greyscale/json_configs/vapeopen_med.json @@ -1,20 +1,20 @@ { - "vapeopen_med": [ - { - "type": "icon_state", - "icon_state": "vapeOutlet", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "vapeopen_med": [ { - "type": "icon_state", - "icon_state": "vapeInput", - "blend_mode": "overlay" - }, + "type": "icon_state", + "icon_state": "vapeOutlet", + "blend_mode": "overlay", + "color_ids": [1] + }, { - "type": "icon_state", - "icon_state": "vapeopen_med", - "blend_mode": "overlay" - } - ] + "type": "icon_state", + "icon_state": "vapeInput", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "vapeopen_med", + "blend_mode": "overlay" + } + ] } diff --git a/code/datums/greyscale/json_configs/waistcoat.json b/code/datums/greyscale/json_configs/waistcoat.json index bfab0e850bb..2364aad4907 100644 --- a/code/datums/greyscale/json_configs/waistcoat.json +++ b/code/datums/greyscale/json_configs/waistcoat.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "waistcoat", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/wellworn_shirt.json b/code/datums/greyscale/json_configs/wellworn_shirt.json index d58335abc4c..876b9b0522c 100644 --- a/code/datums/greyscale/json_configs/wellworn_shirt.json +++ b/code/datums/greyscale/json_configs/wellworn_shirt.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "worn_clean", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "wornout_shirt": [ @@ -12,7 +12,7 @@ "type": "icon_state", "icon_state": "worn_out", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ], "messyworn_shirt": [ @@ -20,7 +20,7 @@ "type": "icon_state", "icon_state": "worn_messy", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] } ] } diff --git a/code/datums/greyscale/json_configs/wellworn_shirt_graphic.json b/code/datums/greyscale/json_configs/wellworn_shirt_graphic.json index a9226607f29..a78d3f11b23 100644 --- a/code/datums/greyscale/json_configs/wellworn_shirt_graphic.json +++ b/code/datums/greyscale/json_configs/wellworn_shirt_graphic.json @@ -1,17 +1,16 @@ { - "wellworn_shirt_gamer": [ - { - "type": "icon_state", - "icon_state": "worn_clean", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "wellworn_shirt_gamer": [ + { + "type": "icon_state", + "icon_state": "worn_clean", + "blend_mode": "overlay", + "color_ids": [1] + }, { "type": "icon_state", "icon_state": "nerd_overlay", "blend_mode": "overlay", - "color_ids": [ 2 ] - + "color_ids": [2] }, { "type": "icon_state", @@ -20,22 +19,22 @@ } ], "wellworn_shirt_ian": [ - { - "type": "icon_state", - "icon_state": "worn_clean", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + { + "type": "icon_state", + "icon_state": "worn_clean", + "blend_mode": "overlay", + "color_ids": [1] + }, { "type": "icon_state", "icon_state": "ian_overlay", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "ian_base", "blend_mode": "overlay" } - ] + ] } diff --git a/code/datums/greyscale/json_configs/wellworn_shirt_skub.json b/code/datums/greyscale/json_configs/wellworn_shirt_skub.json index 6f6ed3fb1f1..4b470969ab6 100644 --- a/code/datums/greyscale/json_configs/wellworn_shirt_skub.json +++ b/code/datums/greyscale/json_configs/wellworn_shirt_skub.json @@ -1,11 +1,11 @@ { - "wellworn_shirt_pro_skub": [ - { - "type": "icon_state", - "icon_state": "worn_out", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "wellworn_shirt_pro_skub": [ + { + "type": "icon_state", + "icon_state": "worn_out", + "blend_mode": "overlay", + "color_ids": [1] + }, { "type": "icon_state", "icon_state": "skub_overlay", @@ -13,16 +13,16 @@ } ], "wellworn_shirt_anti_skub": [ - { - "type": "icon_state", - "icon_state": "worn_out", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + { + "type": "icon_state", + "icon_state": "worn_out", + "blend_mode": "overlay", + "color_ids": [1] + }, { "type": "icon_state", "icon_state": "anti_skub_overlay", "blend_mode": "overlay" } - ] + ] } diff --git a/code/datums/greyscale/json_configs/wintercoats.json b/code/datums/greyscale/json_configs/wintercoats.json index c91c7c33211..159012a4c30 100644 --- a/code/datums/greyscale/json_configs/wintercoats.json +++ b/code/datums/greyscale/json_configs/wintercoats.json @@ -4,37 +4,37 @@ "type": "icon_state", "icon_state": "neck", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sleeves", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "arms", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "bodytop", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] }, { "type": "icon_state", "icon_state": "bodymiddle", "blend_mode": "overlay", - "color_ids": [ 5 ] + "color_ids": [5] }, { "type": "icon_state", "icon_state": "bodybottom", "blend_mode": "overlay", - "color_ids": [ 6 ] + "color_ids": [6] } ], "coatwinter_t": [ @@ -42,37 +42,37 @@ "type": "icon_state", "icon_state": "neck", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sleeves", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "arms", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "bodytop", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] }, { "type": "icon_state", "icon_state": "bodymiddle", "blend_mode": "overlay", - "color_ids": [ 5 ] + "color_ids": [5] }, { "type": "icon_state", "icon_state": "bodybottom", "blend_mode": "overlay", - "color_ids": [ 6 ] + "color_ids": [6] } ] } diff --git a/code/datums/greyscale/json_configs/wintercoats_hood.json b/code/datums/greyscale/json_configs/wintercoats_hood.json index d4ea34aa73a..f7399fdd604 100644 --- a/code/datums/greyscale/json_configs/wintercoats_hood.json +++ b/code/datums/greyscale/json_configs/wintercoats_hood.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "top_trim", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "bottom_trim", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "hood_cloth", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/wintercoats_worn.json b/code/datums/greyscale/json_configs/wintercoats_worn.json index 59e2e9223b1..1594b417ebb 100644 --- a/code/datums/greyscale/json_configs/wintercoats_worn.json +++ b/code/datums/greyscale/json_configs/wintercoats_worn.json @@ -4,37 +4,37 @@ "type": "icon_state", "icon_state": "neck_worn", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sleeves_worn", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "arms_worn", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "bodytop_worn", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] }, { "type": "icon_state", "icon_state": "bodymiddle_worn", "blend_mode": "overlay", - "color_ids": [ 5 ] + "color_ids": [5] }, { "type": "icon_state", "icon_state": "bodybottom_worn", "blend_mode": "overlay", - "color_ids": [ 6 ] + "color_ids": [6] } ], @@ -43,37 +43,37 @@ "type": "icon_state", "icon_state": "neck_worn", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "sleeves_worn", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "arms_worn", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] }, { "type": "icon_state", "icon_state": "bodytop_worn_t", "blend_mode": "overlay", - "color_ids": [ 4 ] + "color_ids": [4] }, { "type": "icon_state", "icon_state": "bodymiddle_worn_t", "blend_mode": "overlay", - "color_ids": [ 5 ] + "color_ids": [5] }, { "type": "icon_state", "icon_state": "bodybottom_worn_t", "blend_mode": "overlay", - "color_ids": [ 6 ] + "color_ids": [6] } ] } diff --git a/code/datums/greyscale/json_configs/wirecutter_worn.json b/code/datums/greyscale/json_configs/wirecutter_worn.json index a5158a3b389..d7cf12624c3 100644 --- a/code/datums/greyscale/json_configs/wirecutter_worn.json +++ b/code/datums/greyscale/json_configs/wirecutter_worn.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "cutters", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/wirecutters.json b/code/datums/greyscale/json_configs/wirecutters.json index 0fb5c530eb5..96b241c4465 100644 --- a/code/datums/greyscale/json_configs/wirecutters.json +++ b/code/datums/greyscale/json_configs/wirecutters.json @@ -4,7 +4,7 @@ "type": "icon_state", "icon_state": "cutters", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", diff --git a/code/datums/greyscale/json_configs/witch_hat.json b/code/datums/greyscale/json_configs/witch_hat.json index 80e9c1b645c..61247cfc18a 100644 --- a/code/datums/greyscale/json_configs/witch_hat.json +++ b/code/datums/greyscale/json_configs/witch_hat.json @@ -4,19 +4,19 @@ "type": "icon_state", "icon_state": "witch_hat_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "witch_hat_bow", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "witch_hat_charm", "blend_mode": "overlay", - "color_ids": [ 3 ] + "color_ids": [3] } ] } diff --git a/code/datums/greyscale/json_configs/wornout_shirt_graphic.json b/code/datums/greyscale/json_configs/wornout_shirt_graphic.json index 6ca12b5db68..edd2be4d8ee 100644 --- a/code/datums/greyscale/json_configs/wornout_shirt_graphic.json +++ b/code/datums/greyscale/json_configs/wornout_shirt_graphic.json @@ -1,16 +1,16 @@ { - "wornout_shirt_gamer": [ - { - "type": "icon_state", - "icon_state": "worn_out", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + "wornout_shirt_gamer": [ + { + "type": "icon_state", + "icon_state": "worn_out", + "blend_mode": "overlay", + "color_ids": [1] + }, { "type": "icon_state", "icon_state": "nerd_overlay", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", @@ -19,22 +19,22 @@ } ], "wornout_shirt_ian": [ - { - "type": "icon_state", - "icon_state": "worn_out", - "blend_mode": "overlay", - "color_ids": [ 1 ] - }, + { + "type": "icon_state", + "icon_state": "worn_out", + "blend_mode": "overlay", + "color_ids": [1] + }, { "type": "icon_state", "icon_state": "ian_overlay", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] }, { "type": "icon_state", "icon_state": "ian_base", "blend_mode": "overlay" } - ] + ] } diff --git a/code/datums/greyscale/json_configs/wrap_paper.json b/code/datums/greyscale/json_configs/wrap_paper.json index b3e9774848c..8edd958fa10 100644 --- a/code/datums/greyscale/json_configs/wrap_paper.json +++ b/code/datums/greyscale/json_configs/wrap_paper.json @@ -4,13 +4,13 @@ "type": "icon_state", "icon_state": "wrap_paper_base", "blend_mode": "overlay", - "color_ids": [ 1 ] + "color_ids": [1] }, { "type": "icon_state", "icon_state": "wrap_paper_ribbon", "blend_mode": "overlay", - "color_ids": [ 2 ] + "color_ids": [2] } ] } diff --git a/code/game/objects/effects/spawners/random/readme.md b/code/game/objects/effects/spawners/random/readme.md index e65d0f52008..1436e7dac73 100644 --- a/code/game/objects/effects/spawners/random/readme.md +++ b/code/game/objects/effects/spawners/random/readme.md @@ -2,9 +2,9 @@ ## About -Random spawners are an organized tool primarily for mapping to enhance replayability. The spawners can create objects, effects, and structures with different tweakable settings to get the desired outcome. You can make a spawner determine direction, rarity, number of items to spawn, pixel spacing between items, and even spread it over a large tile radius. This lets you control the atmosphere of a location. You could for instance spawn different piles of trash in maint or spawn decoration items for a room to give it more randomized flavor. The choice is yours! +Random spawners are an organized tool primarily for mapping to enhance replayability. The spawners can create objects, effects, and structures with different tweakable settings to get the desired outcome. You can make a spawner determine direction, rarity, number of items to spawn, pixel spacing between items, and even spread it over a large tile radius. This lets you control the atmosphere of a location. You could for instance spawn different piles of trash in maint or spawn decoration items for a room to give it more randomized flavor. The choice is yours! -*(note the audience of this README is directed towards mappers who lack knowledge of coding)* +_(note the audience of this README is directed towards mappers who lack knowledge of coding)_ ## Variables @@ -36,7 +36,7 @@ These variables are set to the following default values for the base `random.dm` var/spawn_scatter_radius = 0 // by default the spawner will spawn the items ONLY on the tile it is on ``` -However there are some categories that overwrite these default values so pay attention to the folder or category you group your spawner in. For instance the `obj/effect/spawner/random/techstorage` category overwrites the `spawn_all_loot` and the `spawn_loot_split` variables. +However there are some categories that overwrite these default values so pay attention to the folder or category you group your spawner in. For instance the `obj/effect/spawner/random/techstorage` category overwrites the `spawn_all_loot` and the `spawn_loot_split` variables. ```dm // Tech storage circuit board spawners @@ -46,7 +46,7 @@ However there are some categories that overwrite these default values so pay att spawn_all_loot = TRUE ``` -This means any spawner you create under the techstorage will also have those variables set to that by default. This can be overridden quite easily just be resetting the variables back to the normal state like so: +This means any spawner you create under the techstorage will also have those variables set to that by default. This can be overridden quite easily just be resetting the variables back to the normal state like so: ```dm /obj/effect/spawner/random/techstorage/data_disk @@ -84,11 +84,11 @@ All the capitalized code is the parts where you are supposed to swap out with yo ) ``` -Find the path to different objects and add them to the list but try to be consistent with the types of the object and the spawner. For example a medical spawner shouldn't have a emag in the loot list. (use an antag spawner for that instead!) +Find the path to different objects and add them to the list but try to be consistent with the types of the object and the spawner. For example a medical spawner shouldn't have a emag in the loot list. (use an antag spawner for that instead!) ## Probability -Be aware that the `loot` list uses a *weighted chance* formula to determine probability. So if there are no numbers set in the `loot` list then each object defaults to 1 and has the same probability to be selected. For our above example for the `minor_healing` spawner each medical item has a 1/3 chance to be spawned. But if we rearranged the values to this: +Be aware that the `loot` list uses a _weighted chance_ formula to determine probability. So if there are no numbers set in the `loot` list then each object defaults to 1 and has the same probability to be selected. For our above example for the `minor_healing` spawner each medical item has a 1/3 chance to be spawned. But if we rearranged the values to this: ```dm /obj/effect/spawner/random/medical/minor_healing @@ -100,7 +100,7 @@ Be aware that the `loot` list uses a *weighted chance* formula to determine prob ) ``` -Then now `suture` has a 50% chance of being spawned (2/4), `mesh` has a 25% chance of being spawned (1/4), and `gauze` also has a 25% chance of being spawned (1/4). If we add another item into the mix then we get the following: +Then now `suture` has a 50% chance of being spawned (2/4), `mesh` has a 25% chance of being spawned (1/4), and `gauze` also has a 25% chance of being spawned (1/4). If we add another item into the mix then we get the following: ```dm /obj/effect/spawner/random/medical/minor_healing @@ -113,7 +113,7 @@ Then now `suture` has a 50% chance of being spawned (2/4), `mesh` has a 25% chan ) ``` -Suture is 40% (2/5), Mesh is 20% (1/5), Gauze is 20% (1/5), and Syringe is 20% (1/5). A weighted list has the advantage of not needing to update every item in the list when adding a new item. If the list was based on a straight percent values, then each new item would require to manually go and edit ALL the items in the list. For big lists that would become very tedious. This is why we use weighted lists to determine probability! +Suture is 40% (2/5), Mesh is 20% (1/5), Gauze is 20% (1/5), and Syringe is 20% (1/5). A weighted list has the advantage of not needing to update every item in the list when adding a new item. If the list was based on a straight percent values, then each new item would require to manually go and edit ALL the items in the list. For big lists that would become very tedious. This is why we use weighted lists to determine probability! ## Style @@ -162,10 +162,9 @@ Bad: ) ``` - ### Sort the list from highest probability to lowest -Sort from top to bottom. The rarest items for your spawner should be at the bottom of the list. +Sort from top to bottom. The rarest items for your spawner should be at the bottom of the list. Good: @@ -263,7 +262,7 @@ Bad: ### Keep the same tab formatting for the `loot` list (unless there is only one item) -Again, this is just good code organization. If there is only one item, then encase that item in `loot = list(item)` +Again, this is just good code organization. If there is only one item, then encase that item in `loot = list(item)` Good: @@ -311,7 +310,7 @@ Also Bad: ### Try to keep the total combined weight of your `loot` list to sane values (Aim for 5, 10, 20, 50, or 100) -This makes the math probability easier for people to calculate. (this is recommended, but not always possible) +This makes the math probability easier for people to calculate. (this is recommended, but not always possible) Good: @@ -368,7 +367,6 @@ Good: loot = list(/obj/structure/closet/crate/secure/loot) ``` - Bad: ```dm @@ -382,7 +380,7 @@ Bad: ### Avoid making a spawner that is a duplicate -We don't want copy-cat spawners that are almost identical. Instead merge spawners together if possible. +We don't want copy-cat spawners that are almost identical. Instead merge spawners together if possible. Good: @@ -401,7 +399,6 @@ Good: ) ``` - Bad: ```dm diff --git a/code/modules/admin/verbs/lua/README.md b/code/modules/admin/verbs/lua/README.md index 9b9bfbe05f9..7b6da7153e5 100644 --- a/code/modules/admin/verbs/lua/README.md +++ b/code/modules/admin/verbs/lua/README.md @@ -208,34 +208,44 @@ Writes `value` to the underlying data the pointer references. If `possible_pointer` is a pointer, reads it. Otherwise, it is returned as-is. # The SS13 package + The `SS13` package contains various helper functions that use code specific to tgstation. ## SS13.state + A reference to the state datum (`/datum/lua_state`) handling this Lua state. ## SS13.get_runner_ckey() + The ckey of the user who ran the lua script in the current context. Can be unreliable if accessed after sleeping. ## SS13.get_runner_client() + Returns the client of the user who ran the lua script in the current context. Can be unreliable if accessed after sleeping. ## SS13.global_proc + A wrapper for the magic string used to tell `WrapAdminProcCall` to call a global proc. For instance, `/datum/callback` must be instantiated with `SS13.global_proc` as its first argument to specify that it will be invoking a global proc. The following example declares a callback which will execute the global proc `to_chat`: + ```lua local callback = SS13.new("/datum/callback", SS13.global_proc, "to_chat", dm.world, "Hello World") ``` ## SS13.istype(thing, type) + Equivalent to the DM statement `istype(thing, text2path(type))`. ## SS13.new(type, ...) + An alias for `dm.new` ## SS13.is_valid(datum) + Can be used to determine if the datum passed is not nil, not undefined and not qdel'd all in one. A helper function that allows you to check the validity from only one function. Example usage: + ```lua local datum = SS13.new("/datum") dm.global_procs.qdel(datum) @@ -249,25 +259,31 @@ print(SS13.is_valid(datum)) -- true ``` ## SS13.type(string) + Converts a string into a typepath. Equivalent to doing `dm.global_proc("_text2path", "/path/to/type")` ## SS13.qdel(datum) + Deletes a datum. You shouldn't try to reference it after calling this function. Equivalent to doing `dm.global_proc("qdel", datum)` ## SS13.await(thing_to_call, proc_to_call, ...) + Calls `proc_to_call` on `thing_to_call`, with `...` as its arguments, and sleeps until that proc returns. Returns two return values - the first is the return value of the proc, and the second is the message of any runtime exception thrown by the called proc. The following example calls and awaits the return of `poll_ghost_candidates`: + ```lua local ghosts, runtime = SS13.await(SS13.global_proc, "poll_ghost_candidates", "Would you like to be considered for something?") ``` ## SS13.wait(time, timer) + Waits for a number of **seconds** specified with the `time` argument. You can optionally specify a timer subsystem using the `timer` argument. Internally, this function creates a timer that will resume the current task after `time` seconds, then yields the current task by calling `coroutine.yield` with no arguments and ignores the return values. If the task is prematurely resumed, the timer will be safely deleted. ## SS13.register_signal(datum, signal, func) + Registers the Lua function `func` as a handler for `signal` on `datum`. Like with signal handlers written in DM, Lua signal handlers should not sleep (either by calling `sleep` or `coroutine.yield`). @@ -275,6 +291,7 @@ Like with signal handlers written in DM, Lua signal handlers should not sleep (e This function returns whether the signal registration was successful. The following example defines a function which will register a signal that makes `target` make a honking sound any time it moves: + ```lua function honk(target) SS13.register_signal(target, "movable_moved", function(source) @@ -286,12 +303,15 @@ end NOTE: if `func` is an anonymous function declared inside the call to `SS13.register_signal`, it cannot be referenced in order to unregister that signal with `SS13.unregister_signal` ## SS13.unregister_signal(datum, signal, func) + Unregister a signal previously registered using `SS13.register_signal`. `func` must be a function for which a handler for the specified signal has already been registered. If `func` is `nil`, all handlers for that signal will be unregistered. ## SS13.set_timeout(time, func) + Creates a timer which will execute `func` after `time` **seconds**. `func` should not expect to be passed any arguments, as it will not be passed any. Unlike `SS13.wait`, `SS13.set_timeout` does not yield or sleep the current task, making it suitable for use in signal handlers for `SS13.register_signal` The following example will output a message to chat after 5 seconds: + ```lua SS13.set_timeout(5, function() dm.global_procs.to_chat(dm.world, "Hello World!") @@ -299,15 +319,19 @@ end) ``` ## SS13.start_loop(time, amount, func) + Creates a timer which will execute `func` after `time` **seconds**. `func` should not expect to be passed any arguments, as it will not be passed any. Works exactly the same as `SS13.set_timeout` except it will loop the timer `amount` times. If `amount` is set to -1, it will loop indefinitely. Returns a number value, which represents the timer's id. Can be stopped with `SS13.end_loop` Returns a number, the timer id, which is needed to stop indefinite timers. The following example will output a message to chat every 5 seconds, repeating 10 times: + ```lua SS13.start_loop(5, 10, function() dm.global_procs.to_chat(dm.world, "Hello World!") end) ``` + The following example will output a message to chat every 5 seconds, until `SS13.end_loop(timerid)` is called: + ```lua local timerid = SS13.start_loop(5, -1, function() dm.global_proc.to_chat(dm.world, "Hello World!") @@ -315,8 +339,10 @@ end) ``` ## SS13.end_loop(id) + Prematurely ends a loop that hasn't ended yet, created with `SS13.start_loop`. Silently fails if there is no started loop with the specified id. The following example will output a message to chat every 5 seconds and delete it after it has repeated 20 times: + ```lua local repeated_amount = 0 -- timerid won't be in the looping function's scope if declared before the function is declared. @@ -331,5 +357,6 @@ end) ``` ## SS13.stop_all_loops() + Stops all current running loops that haven't ended yet. Useful in case you accidentally left a indefinite loop running without storing the id anywhere. diff --git a/code/modules/asset_cache/readme.md b/code/modules/asset_cache/readme.md index 82e6bea896c..b2f8914708b 100644 --- a/code/modules/asset_cache/readme.md +++ b/code/modules/asset_cache/readme.md @@ -24,14 +24,12 @@ Call .get_url_mappings() to get an associated list with the urls your assets can See the documentation for `/datum/asset_transport` for the backend api the asset datums utilize. -The global variable `SSassets.transport` contains the currently configured transport. - - +The global variable `SSassets.transport` contains the currently configured transport. ### Notes: Because byond browse() calls use non-blocking queues, if your code uses output() (which bypasses all of these queues) to invoke javascript functions you will need to first have the javascript announce to the server it has loaded before trying to invoke js functions. -To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details. +To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details. CSS files that use url() can be made to use the CDN without needing to rewrite all url() calls in code by using the namespaced helper datum. See the documentation for `/datum/asset/simple/namespaced` for details. diff --git a/code/modules/asset_cache/validate_assets.html b/code/modules/asset_cache/validate_assets.html index 78bcbb92a1a..d55c8892cb1 100644 --- a/code/modules/asset_cache/validate_assets.html +++ b/code/modules/asset_cache/validate_assets.html @@ -1,29 +1,31 @@ - + - - - - - - - + + + + + + diff --git a/code/modules/atmospherics/Atmospherics.md b/code/modules/atmospherics/Atmospherics.md index 8d280c6dcdc..bc1e1e842c4 100644 --- a/code/modules/atmospherics/Atmospherics.md +++ b/code/modules/atmospherics/Atmospherics.md @@ -1,4 +1,5 @@ # Atmospherics + ## 1. Preamble This file will be written in the first person in the interest of having a laid back style, as some of the concepts here would be ass to read as technical writing. Understand that this isn't the work of one person, but the combined efforts of several contributors. It is a living document, and one you should strive to keep up to date. @@ -33,46 +34,48 @@ Now then, into the breach. ![Cyclical graph of one atmos tick](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/Cycle.png) -*Figure 3.1: The structure of one air controller tick. Not totally accurate, but it will do* +_Figure 3.1: The structure of one air controller tick. Not totally accurate, but it will do_ + +The air controller is, at its core, quite simple, yet it is absolutely fundamental to the atmospheric system. The air controller is the clock which triggers all continuous actions within the atmos system, such as vents distributing air or gas moving between tiles. The actions taken by the air controller are quite simple, and will be enumerated here. Much of the substance of the air ticker is due to the game's master controller, whose intricacies I will not delve into for this document. I will however go into more detail about how SSAir in particular works in Chapter 6. In any case, this is a simplified list of the air controller's actions in a single tick: - The air controller is, at its core, quite simple, yet it is absolutely fundamental to the atmospheric system. The air controller is the clock which triggers all continuous actions within the atmos system, such as vents distributing air or gas moving between tiles. The actions taken by the air controller are quite simple, and will be enumerated here. Much of the substance of the air ticker is due to the game's master controller, whose intricacies I will not delve into for this document. I will however go into more detail about how SSAir in particular works in Chapter 6. In any case, this is a simplified list of the air controller's actions in a single tick: 1. Rebuild Pipenets - - Runs each time SSAir processes, sometimes out of order. It ensures that no pipeline sit unresolved or unbuilt - - Processes the `rebuild_queue` list into the `expansion_queue` list, and then builds a full pipeline piecemeal. We do a ton of fenagling here to reduce overrun + - Runs each time SSAir processes, sometimes out of order. It ensures that no pipeline sit unresolved or unbuilt + - Processes the `rebuild_queue` list into the `expansion_queue` list, and then builds a full pipeline piecemeal. We do a ton of fenagling here to reduce overrun 2. Pipenets - - Updates the internal gasmixes of attached pipe machinery, and reacts the gases in a pipeline - - Calls `process()` on each `/datum/pipenet` in the `networks` list + - Updates the internal gasmixes of attached pipe machinery, and reacts the gases in a pipeline + - Calls `process()` on each `/datum/pipenet` in the `networks` list 3. Machinery - - Handles machines that effect atmospherics, think vents, the supermatter, pumps, all that - - Calls `process_atmos()` on each `/obj/machinery` (typically `/obj/machinery/atmospherics`) in the `atmos_machinery` list - - May remove the machinery from said list if `process_atmos()` returns `PROCESS_KILL` + - Handles machines that effect atmospherics, think vents, the supermatter, pumps, all that + - Calls `process_atmos()` on each `/obj/machinery` (typically `/obj/machinery/atmospherics`) in the `atmos_machinery` list + - May remove the machinery from said list if `process_atmos()` returns `PROCESS_KILL` 4. Active turfs - - This is the heart and soul of environmental atmos, see more details below - - All you need to know right now is it manages moving gas from tile to tile - - Calls `process_cell()` on each `/turf/open` in the `active_turfs` list + - This is the heart and soul of environmental atmos, see more details below + - All you need to know right now is it manages moving gas from tile to tile + - Calls `process_cell()` on each `/turf/open` in the `active_turfs` list 5. Excited groups - - Manages excited groups, which are core to working flow simulation - - More details to come, they handle differences between gasmixtures when active turfs can't do the job - - Increases the `breakdown_cooldown` and `dismantle_cooldown` for each `/datum/excited_group` in the `excited_groups` list - - If either cooldown for a given excited group has passed its threshold - - Calls `self_breakdown()` or `dismantle()` appropriately on the excited group. + - Manages excited groups, which are core to working flow simulation + - More details to come, they handle differences between gasmixtures when active turfs can't do the job + - Increases the `breakdown_cooldown` and `dismantle_cooldown` for each `/datum/excited_group` in the `excited_groups` list + - If either cooldown for a given excited group has passed its threshold + - Calls `self_breakdown()` or `dismantle()` appropriately on the excited group. 6. High pressure deltas - - Takes the gas movement from Active Turfs and uses it to move objects on said turfs - - Calls `high_pressure_movements()` on each `/turf/open` in the `high_pressure_delta` list. - - Sets each turf's `pressure_difference` to 0 + - Takes the gas movement from Active Turfs and uses it to move objects on said turfs + - Calls `high_pressure_movements()` on each `/turf/open` in the `high_pressure_delta` list. + - Sets each turf's `pressure_difference` to 0 7. Hotspots - - These are what you might know as fire, at least the effect of it. - - They deal with burning things, and color calculations, lots of color calculations - - Calls `process()` on each `/obj/effect/hotspot` in the `hotspots` list + - These are what you might know as fire, at least the effect of it. + - They deal with burning things, and color calculations, lots of color calculations + - Calls `process()` on each `/obj/effect/hotspot` in the `hotspots` list 8. Superconductivity - - Moves heat through turfs that don't allow gas to pass - - Deals with heating up the floor below windows, and some other more painful heat stuff - - Calls `super_conduct()` on each `/turf` in the `active_super_conductivity` list + - Moves heat through turfs that don't allow gas to pass + - Deals with heating up the floor below windows, and some other more painful heat stuff + - Calls `super_conduct()` on each `/turf` in the `active_super_conductivity` list 9. Atoms - - Processes things in the world that should know about gas changes, used to account for turfs sleeping, I'll get more into that in a bit - - Calls `process_exposure()` on each `/atom` in the `atom_process` list + - Processes things in the world that should know about gas changes, used to account for turfs sleeping, I'll get more into that in a bit + - Calls `process_exposure()` on each `/atom` in the `atom_process` list ## 4. Gas Mixtures + If the air controller is the heart of atmos, then gas mixtures make up its blood. The bulk of all atmos calculations are performed within a given gas mixture datum (an instance of `/datum/gas_mixture`), be it within a turf or within an emergency oxygen tank or within a pipe. In particular, `/datum/gas_mixture/proc/share()` is the cornerstone of atmos simulation, as it and its stack perform all the calculations for equalizing two gas mixtures. Gas mixtures contain some of the oldest code still in our codebase, and it is remarkable that overall, the logic behind the majority of gas mixture procs has gone unchanged since the days of Exadv1. Despite being in some sense "oldcode", the logic itself is quite robust and based in real world physics. Thankfully, gas mixtures already are quite well documented in terms of their behavior. Their file is well commented and kept up to date. I will, however, elaborate on some of the less obvious operations here. Additionally, I will document the structure of gas lists, and how one should interface with a gas mixture should you choose to use one in other code. @@ -84,7 +87,8 @@ Now don't be scared by the code mind, it's SPOOKY PHYSICS but it's not the devil if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY) temperature = (old_self_heat_capacity*temperature - heat_capacity_self_to_sharer*temperature_archived + heat_capacity_sharer_to_self*sharer.temperature_archived)/new_self_heat_capacity ``` -*Snippet 4.1: excerpt from `/datum/gas_mixture/proc/share()`* + +_Snippet 4.1: excerpt from `/datum/gas_mixture/proc/share()`_ The snippet above is an example of one particularly strange looking calculation. This part of share() is updating the temperature of a gas mixture to account for lost or gained thermal energy as gas moves to/from the mixture, since gases themselves carry heat. To understand this snippet, it is important to understand the difference between heat and temperature. For the most part, the average coder need only concern himself with temperature, as it is a familiar experience for anybody. However, internally in atmos, heat (thermal energy) is the truly important quantity. Heat is defined as temperature multiplied by heat capacity, and is measured in joules. Typically within atmos, we are more concerned with manipulating heat than temperature; however, temperature is tracked rather than heat largely to make interfacing with the system simpler for the average coder. Thus, this snippet modifies heat in terms of temperature - it adds/subtracts three terms, each of which measure heat, to determine the new heat in the gas mixture. This heat is then divided by the mixture's heat capacity in order to determine temperature. @@ -101,6 +105,7 @@ For some time, without a clear solution, we simply stuck to the status quo and l Enter Listmos. ### The Gas List + The solution we came to was beautifully simple, but founded on some unintuitive principles. While datum var accesses are quite slow, proc var accesses are acceptable. If we use a reference for a given var, this can be exploited by "caching" the reference inside of a proc var. How can we take advantage of this without using a datum, thus nullifying the benefit? The answer was to use a list. The critical realization was that a gas datum functioned more so as a struct than as a class. There were no procs attached to gas datums; only vars. While DM lacks a true struct with quick lookup times, a list works very well to perform the same function. Thus, the current structure of gas was created, under the name Listmos. @@ -120,17 +125,19 @@ world << air.gases.heat_capacity() //outputs 2000 (100 mol * 20 J/K/mol) air.gases[/datum/gas/oxygen][MOLES] -= 110 air.garbage_collect() //oxygen is now removed from the gases list, since it was empty ``` -*Snippet 4.2: gas mixture usage examples* + +_Snippet 4.2: gas mixture usage examples_ Of particular note in this snippet are the two procs assert_gas() and garbage_collect(). These procs are very important while interfacing with gas mixtures. If you are uncertain about whether a given mixture has a particular gas, you must use assert_gas() before any reads or writes from the gas. If you fail to use assert_gas() then there will be runtime errors when you try to access the inner lists. When you remove any number of moles from a given gas, be sure to call garbage_collect(). This proc removes all gases which have mole counts less than or equal to 0. This is a memory and performance enhancement for list accesses achieved by reducing the size of the list, and also saves us from having to do sanity checks for negative moles whenever gas is removed. As a quick reference, here is a list of common procs/vars/list indices which the average coder may wish to use when interfacing with a gas mixture. ##### Gas Mixture Datum -* *`/datum/gas_mixture/proc/assert_gas()`* - Used before accessing a particular type of gas. -* *`/datum/gas_mixture/proc/assert_gases()`* - Shorthand for calling assert_gas() multiple times. -* *`/datum/gas_mixture/proc/garbage_collect()`* - Used after removing any number of moles from a mixture. -* *`/datum/gas_mixture/proc/return_pressure()`* - Pressure is what should be displayed to players to quantify gas; measured in kilopascals. -* *`/datum/gas_mixture/var/temperature`* - Measured in kelvins. Useful constants are T0C and T20C for 0 and 20 degrees Celsius respectively, and TCMB,the temperature of space and the lower bound for temperature in atmos. -* *`/datum/gas_mixture/var/volume`* - Measured in liters. + +- _`/datum/gas_mixture/proc/assert_gas()`_ - Used before accessing a particular type of gas. +- _`/datum/gas_mixture/proc/assert_gases()`_ - Shorthand for calling assert_gas() multiple times. +- _`/datum/gas_mixture/proc/garbage_collect()`_ - Used after removing any number of moles from a mixture. +- _`/datum/gas_mixture/proc/return_pressure()`_ - Pressure is what should be displayed to players to quantify gas; measured in kilopascals. +- _`/datum/gas_mixture/var/temperature`_ - Measured in kelvins. Useful constants are T0C and T20C for 0 and 20 degrees Celsius respectively, and TCMB,the temperature of space and the lower bound for temperature in atmos. +- _`/datum/gas_mixture/var/volume`_ - Measured in liters. While we're on the subject, `/datum/gas_mixture` has two subtypes. The first is `/datum/gas_mixture/turf`, which exists for literally one purpose. When a turf is empty, we want it to have the same heat capacity as space. This lets us achieve that by overriding `heat_capacity()` @@ -140,13 +147,14 @@ The type is built to allow for gasmixtures that serve as infinite sources of "so It's used by `/datum/gas_mixture/immutable/space`, which implements some particular things for `heat_capacity()` and some optimizations for gas operations. It's also implemented by `/datum/gas_mixture/immutable/planetary`, which is used for planetary turfs, and has some code that makes actually having a gasmix possible. - ##### Gas List -* *`gases[path][MOLES]`* - Quantity of a particular gas within a mixture. -* *`gases[path][GAS_META][META_GAS_NAME]`* - The long name of a gas, ex. "Oxygen" or "Hyper-noblium" -* *`gases[path][GAS_META][META_GAS_ID]`* - The internal ID of a given gas, ex. "o2" or "nob" + +- _`gases[path][MOLES]`_ - Quantity of a particular gas within a mixture. +- _`gases[path][GAS_META][META_GAS_NAME]`_ - The long name of a gas, ex. "Oxygen" or "Hyper-noblium" +- _`gases[path][GAS_META][META_GAS_ID]`_ - The internal ID of a given gas, ex. "o2" or "nob" ### Reactions + While defining a new gas on its own is very simple, there is no gas-specific behavior defined within /datum/gas. This behavior gets defined in a few places, notably breath code (to be discussed later) and in reactions. The most important and well known reaction in SS13 is fire - the combustion of plasma. Reactions are used for several things - in particular, it is conventional (though by no means enforced) that to form a gas, a reaction must occur. Creating a new reaction is fairly simple, this is the area of atmos that has received the most attention over the last few years, and the best place to start. Don't be scared of the size of reactions.dm, it's not that complex. There are two procs needed when defining a new reaction, /datum/gas_reaction/proc/init_reqs() and /datum/gas_reaction/proc/react(). init_reqs() initializes the requirements for the reaction to occur. There is a list, min_requirements, which maps gas paths to required amount of moles. It also maps three specific strings ("TEMP", "MAX_TEMP" and "ENER") to temperature in kelvins and thermal energy in joules. More behavior could easily be added here, but it hasn't yet for performance reasons because no reactions have need of it. @@ -228,15 +236,15 @@ This can lead to negative moles, which the system is not prepared for. This is also why we queue space's sucking till the end of a tile's `process_cell()` btw, by that point we can ensure that no other tile will need to check for our mix, so we can freely violate our portioning. - ### Active Turfs + ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/FlowVisuals.png) -*Figure 5.1: A visual of the algorithm `process_cell()` implements, ignoring our optimizations* +_Figure 5.1: A visual of the algorithm `process_cell()` implements, ignoring our optimizations_ Active turfs are the backbone of how gas moves from tile to tile. While most of `process_cell()` should be easy enough to understand, I am going to go into some detail about archiving, since I think it's a common source of hiccups. -* *`archived_cycle`* this var stores the last cycle of the atmos loop that the turf processed on. The key point to notice here is that when processing a turf, we don't share with all its neighbors, we only talk to those who haven't processed yet. This is because the remainder of `process_cell()` and especially `share()` are like addition. We can add in any order we like, and we only need to add once. This is what archived gases are for by the way, they store the state of the relevant tile before any processing occurs. +- _`archived_cycle`_ this var stores the last cycle of the atmos loop that the turf processed on. The key point to notice here is that when processing a turf, we don't share with all its neighbors, we only talk to those who haven't processed yet. This is because the remainder of `process_cell()` and especially `share()` are like addition. We can add in any order we like, and we only need to add once. This is what archived gases are for by the way, they store the state of the relevant tile before any processing occurs. Alright then, with that out of the way, what is an active turf. @@ -253,7 +261,7 @@ If we just used active turfs sleeping would be easy as pie, we could do it turf ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/Unsettled.png) ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/Settled.png) -*Figure 5.2.1-5.2.2: Settled VS Unsettled gases, this is what excited groups do* +_Figure 5.2.1-5.2.2: Settled VS Unsettled gases, this is what excited groups do_ I didn't mention this above, but active turf processing, or really `share()`, has a fatal flaw. The amount of gas moved per tick goes down exponentially the further away a turf is from the source of changes, or diffs. @@ -297,7 +305,7 @@ There's one more major aspect of environmental atmos to cover, and while it's no ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/Superconduction.png) -*Figure 5.3: The death of a pug, and a visual description of what superconduction does* +_Figure 5.3: The death of a pug, and a visual description of what superconduction does_ Superconduction, an odd name really, it doesn't really describe much of anything aside from something to do with heat. It gets worse, trust me. @@ -315,9 +323,9 @@ There's one more, and it's a doozy. `atmos_superconductivity` is a set of direct So then, a review. -* *`thermal_conductivity`* Ranges from 0 to 1, effects how easy it is for a turf to receive heat -* *`heat_capacity`* Large numbers mean it's harder to heat, but holds more heat. You get it. Also used for turf melting -* *`atmos_supeconductivity`* Bitfield of directions we **can't** share in, this is often set by firelocks and such +- _`thermal_conductivity`_ Ranges from 0 to 1, effects how easy it is for a turf to receive heat +- _`heat_capacity`_ Large numbers mean it's harder to heat, but holds more heat. You get it. Also used for turf melting +- _`atmos_supeconductivity`_ Bitfield of directions we **can't** share in, this is often set by firelocks and such One more thing, turfs will superconduct until they either run out of energy, or temperature. This is a stable system because turfs "conduct" with space, which is why floods of heat will equalize to about 690k over time. @@ -327,14 +335,14 @@ This will require/impart a light understanding of the master controller, I will First, some new vocab. -* *`wait`* Subsystem var, it is the amount of time to "wait" between each fire, or process. Measured in deciseconds. -* *`MC_TICK_CHECK`* A define that checks to see if the subsystem has taken more then it's allotted time. In the case of SSAir we use it to allow for dynamic scaling +- _`wait`_ Subsystem var, it is the amount of time to "wait" between each fire, or process. Measured in deciseconds. +- _`MC_TICK_CHECK`_ A define that checks to see if the subsystem has taken more then it's allotted time. In the case of SSAir we use it to allow for dynamic scaling The MC entry for SSAir is very helpful for debugging, and it is good to understand before I talk about cost. ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/SSAirAtRest.png) -*Figure 6.1: SSAir sitting doing little to nothing turf wise, only processing pipenets and atmos machines* +_Figure 6.1: SSAir sitting doing little to nothing turf wise, only processing pipenets and atmos machines_ If you aren't familiar with the default subsystem stats, you can see them explained here: [][http://codedocs.tgstation13.org/.github/guides/MC_tab.md] @@ -354,7 +362,7 @@ The atmos subsystem was used as a testing ground for the robustness of the maste ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/GasTypes.png) -*Figure 6.2: SSAir when a high amount of active turfs are operating, with a large selection of gastypes for each tile* +_Figure 6.2: SSAir when a high amount of active turfs are operating, with a large selection of gastypes for each tile_ As you can see, active turfs can be really slow. Oh but it gets so much worse. @@ -366,7 +374,7 @@ react() is called for every active turf, and every pipenet. On each react call f ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/LargeExcitedGroup.png) -*Figure 6.3: The effects of a large excited group on overtime* +_Figure 6.3: The effects of a large excited group on overtime_ It's hard to tell here because I took the picture right as it happen, but when large excited groups go through `self_breakdown()` they can overtime by a significant deal. This is because `self_breakdown()` can't be delayed, or done in two parts. We can't let an older gasmix that's already been collected have say 1000 mols of plasma added, then go into breakdown and delete it all. Thus, the overtime cost. This was with a excited group 900 tiles large though, so it isn't nearly ever this bad. It also scales with the amount of gases in the same way that `share()` does. @@ -376,7 +384,7 @@ On the whole excited groups are the only major source of overrun, consider this ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/DiffsSettling.png) -*Figure 7.1: Diffs settling out as they should, around their sources* +_Figure 7.1: Diffs settling out as they should, around their sources_ Our goal is not to simulate real life atmospherics. It is instead to put on a show of doing so. To sleep wherever we can, and fake it as hard as possible. @@ -392,7 +400,7 @@ Performance and gameplay are much more important then realism. In all your work ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/PipelineVisuals.png) -*Figure 8.1: The structure of pipelines shown in color, components are a mix* +_Figure 8.1: The structure of pipelines shown in color, components are a mix_ `/datum/pipeline` handles the simulation of piping and such. It has 2 main actions, one of which you should know very well. The other is slightly more of a hurdle. @@ -415,10 +423,8 @@ Everything that needs a pipeline should have it before it's allowed to do any pr The act of rebuilding a pipeline is quite expensive however, since it involves iterating over all the connected pipes/components. That's why we go to such great pains to make sure no large amount of work is allowed to happen at once. It's in an attempt to avoid the excited group settling type of lag I discussed above. It's ok for atmos to lock up for a short period if the system isn't killing the game as a whole. - All the other behavior of pipes and pipe components are handled by atmos machinery. I'll give a brief rundown of how they're classified, but the details of each machine are left as an exercise to the reader. - #### Pipes The raw pipes. They have some amount of nuance, mostly around layers, but it's not too tricky to deal with. @@ -467,19 +473,20 @@ This attitude needs to be applied to a few large targets, and you may see it cro ## Appendix A - Glossary -* *LINDA* - Our environmental gas system, created by Aranclanos, allegedly Beautiful in Spanish -* *Naps* - A healthy pastime -* *Gas mixtures* - The datums that store gas information, key to listmos and our underlying method of handling well gas -* *Diffs* - The differences between gasmixes. We want to get rid of these over time, and clump them up with their sources so we don't need to process too many turfs -* *FEA* - Finite Element Analysis, the underlying system our atmos is built on top of. Ugly in Spanish -* *Pipelines* - The datum that represents and handles the gasmixtures of a set of pipes and their components -* *Components* - Atmos machines that act on pipelines, modifying their mix -* *Active Turfs* - An optimization of FEA implemented in LINDA that causes processing to only occur when differences are equalizing -* *Excited Groups* - Evens out groups of active turfs to compensate for the way `share()` works -* *Carbon dioxide* - What the fuck is this?] -* *MC* - The master controller, makes sure all subsystems get the time they need to process, prevents lockups from one subsystem having a lot of work +- _LINDA_ - Our environmental gas system, created by Aranclanos, allegedly Beautiful in Spanish +- _Naps_ - A healthy pastime +- _Gas mixtures_ - The datums that store gas information, key to listmos and our underlying method of handling well gas +- _Diffs_ - The differences between gasmixes. We want to get rid of these over time, and clump them up with their sources so we don't need to process too many turfs +- _FEA_ - Finite Element Analysis, the underlying system our atmos is built on top of. Ugly in Spanish +- _Pipelines_ - The datum that represents and handles the gasmixtures of a set of pipes and their components +- _Components_ - Atmos machines that act on pipelines, modifying their mix +- _Active Turfs_ - An optimization of FEA implemented in LINDA that causes processing to only occur when differences are equalizing +- _Excited Groups_ - Evens out groups of active turfs to compensate for the way `share()` works +- _Carbon dioxide_ - What the fuck is this?] +- _MC_ - The master controller, makes sure all subsystems get the time they need to process, prevents lockups from one subsystem having a lot of work ## Appendix B - How to test environmental atmos + If you really want to get a feeling for how flow works you'll need to load up the game and make some diffs. What follows is a short description of how to set up testing. To start with, you should enable the `TESTING` define in compile_options.dm, this toggles `VISUALIZE_ACTIVE_TURFS` and `TRACK_MAX_SHARE`. These two debug methods are very helpful for understanding flow, but they aren't cheap, so we make them a compile time option. Active turfs will show up as green, don't worry about the second define, it's coming right up. @@ -488,7 +495,7 @@ Past that you'll want to turn on excited group highlighting, to do this open the ![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/atmos/AtmosControlPanel.png) -*Figure B.1: The atmospherics control panel* +_Figure B.1: The atmospherics control panel_ To go into more detail about the control panel, it is split into two parts. At the top there's a readout of some relevant stats, the amount of active turfs, how many times the subsystem has fired, etc. You can get the same information from the SSAir MC entry, but it's a bit harder to read. I detail this in the section on performance in environmental atmos. There's a button that turns the subsystem on/off in the top left, it's handy for debugging and seeing how things work step by step. Use it if you need to slow things down. diff --git a/code/modules/buildmode/README.md b/code/modules/buildmode/README.md index 1bdb6e07584..e7b18932ecc 100644 --- a/code/modules/buildmode/README.md +++ b/code/modules/buildmode/README.md @@ -16,200 +16,200 @@ Implementer of buildmode behaviors. Existing varieties: -+ Basic +- Basic - **Description**: + **Description**: - Allows creation of simple structures consisting of floors, walls, windows, and airlocks. + Allows creation of simple structures consisting of floors, walls, windows, and airlocks. - **Controls**: + **Controls**: - + *Left click a turf*: - - "Upgrades" the turf based on the following rules below: + - _Left click a turf_: - + Space -> Tiled floor - + Simulated floor -> Regular wall - + Wall -> Reinforced wall - - + *Right click a turf*: + "Upgrades" the turf based on the following rules below: - "Downgrades" the turf based on the following rules below: + - Space -> Tiled floor + - Simulated floor -> Regular wall + - Wall -> Reinforced wall - + Reinforced wall -> Regular wall - + Wall -> Tiled floor - + Simulated floor -> Space - - + *Right click an object*: + - _Right click a turf_: - Deletes the clicked object. + "Downgrades" the turf based on the following rules below: - + *Alt+Left click a location*: + - Reinforced wall -> Regular wall + - Wall -> Tiled floor + - Simulated floor -> Space - Places an airlock at the clicked location. - - + *Ctrl+Left click a location*: + - _Right click an object_: - Places a window at the clicked location. + Deletes the clicked object. -+ Advanced + - _Alt+Left click a location_: - **Description**: + Places an airlock at the clicked location. - Creates an instance of a configurable atom path where you click. + - _Ctrl+Left click a location_: - **Controls**: + Places a window at the clicked location. - + *Right click on the mode selector*: +- Advanced - Choose a path to spawn. - - + *Left click a location* (requires chosen path): + **Description**: - Place an instance of the chosen path at the location. + Creates an instance of a configurable atom path where you click. - + *Right click an object*: + **Controls**: - Delete the object. + - _Right click on the mode selector_: -+ Fill + Choose a path to spawn. - **Description**: + - _Left click a location_ (requires chosen path): - Creates an instance of an atom path on every tile in a chosen region. + Place an instance of the chosen path at the location. - With a special control input, instead deletes everything within the region. + - _Right click an object_: - **Controls**: + Delete the object. - + *Right click on the mode selector*: +- Fill - Choose a path to spawn. + **Description**: - + *Left click on a region* (requires chosen path): + Creates an instance of an atom path on every tile in a chosen region. - Fill the region with the chosen path. + With a special control input, instead deletes everything within the region. - + *Alt+Left click on a region*: + **Controls**: - Deletes everything within the region. + - _Right click on the mode selector_: - + *Right click during region selection*: + Choose a path to spawn. - Cancel region selection. + - _Left click on a region_ (requires chosen path): -+ Copy + Fill the region with the chosen path. - **Description**: - - Take an existing object in the world, and place duplicates with identical attributes where you click. + - _Alt+Left click on a region_: - May not always work nicely - "deep" variables such as lists or datums may malfunction. + Deletes everything within the region. - **Controls**: + - _Right click during region selection_: - + *Right click an existing object*: + Cancel region selection. - Select the clicked object as a template. +- Copy - + *Left click a location* (Requires a selected object as template): + **Description**: - Place a duplicate of the template at the clicked location. + Take an existing object in the world, and place duplicates with identical attributes where you click. -+ Area Edit + May not always work nicely - "deep" variables such as lists or datums may malfunction. - **Description**: + **Controls**: - Modifies and creates areas. + - _Right click an existing object_: - The active area will be highlighted in yellow. + Select the clicked object as a template. - **Controls**: + - _Left click a location_ (Requires a selected object as template): - + *Right click the mode selector*: + Place a duplicate of the template at the clicked location. - Create a new area, and make it active. +- Area Edit - + *Right click an existing area*: + **Description**: - Make the clicked area active. + Modifies and creates areas. - + *Left click a turf*: + The active area will be highlighted in yellow. - When an area is active, adds the turf to the active area. + **Controls**: -+ Var Edit + - _Right click the mode selector_: - **Description**: + Create a new area, and make it active. - Allows for setting and resetting variables of objects with a click. + - _Right click an existing area_: - If the object does not have the var, will do nothing and print a warning message. + Make the clicked area active. - **Controls**: + - _Left click a turf_: - + *Right click the mode selector*: + When an area is active, adds the turf to the active area. - Choose which variable to set, and what to set it to. +- Var Edit - + *Left click an atom*: + **Description**: - Change the clicked atom's variables as configured. - - + *Right click an atom*: + Allows for setting and resetting variables of objects with a click. - Reset the targeted variable to its original value in the code. + If the object does not have the var, will do nothing and print a warning message. -+ Map Generator + **Controls**: - **Description**: + - _Right click the mode selector_: - Fills rectangular regions with algorithmically generated content. Right click during region selection to cancel. + Choose which variable to set, and what to set it to. - See the `procedural_mapping` module for the generators themselves. + - _Left click an atom_: - **Controls**: + Change the clicked atom's variables as configured. - + *Right-click on the mode selector*: - - Select a map generator from all the generators present in the codebase. - - + *Left click two corners of an area*: + - _Right click an atom_: - Use the generator to populate the region. + Reset the targeted variable to its original value in the code. - + *Right click during region selection*: +- Map Generator - Cancel region selection. + **Description**: -+ Throwing + Fills rectangular regions with algorithmically generated content. Right click during region selection to cancel. - **Description**: + See the `procedural_mapping` module for the generators themselves. - Select an object with left click, and right click to throw it towards where you clicked. + **Controls**: - **Controls**: + - _Right-click on the mode selector_: - + *Left click on a movable atom*: - - Select the atom for throwing. - - + *Right click on a location*: + Select a map generator from all the generators present in the codebase. - Throw the selected atom towards that location. + - _Left click two corners of an area_: -+ Boom + Use the generator to populate the region. - **Description**: + - _Right click during region selection_: - Make explosions where you click. + Cancel region selection. - **Controls**: +- Throwing - + *Right click the mode selector*: - - Configure the explosion size. + **Description**: - + *Left click a location*: - - Cause an explosion where you clicked. \ No newline at end of file + Select an object with left click, and right click to throw it towards where you clicked. + + **Controls**: + + - _Left click on a movable atom_: + + Select the atom for throwing. + + - _Right click on a location_: + + Throw the selected atom towards that location. + +- Boom + + **Description**: + + Make explosions where you click. + + **Controls**: + + - _Right click the mode selector_: + + Configure the explosion size. + + - _Left click a location_: + + Cause an explosion where you clicked. diff --git a/code/modules/client/preferences/README.md b/code/modules/client/preferences/README.md index edaf5bdf8e7..e5c295f1795 100644 --- a/code/modules/client/preferences/README.md +++ b/code/modules/client/preferences/README.md @@ -1,6 +1,6 @@ # Preferences (by Mothblocks) -This does not contain all the information on specific values--you can find those as doc-comments in relevant paths, such as `/datum/preference`. Rather, this gives you an overview for creating *most* preferences, and getting your foot in the door to create more advanced ones. +This does not contain all the information on specific values--you can find those as doc-comments in relevant paths, such as `/datum/preference`. Rather, this gives you an overview for creating _most_ preferences, and getting your foot in the door to create more advanced ones. ## Anatomy of a preference (A.K.A. how do I make one?) @@ -10,6 +10,7 @@ Most preferences consist of two parts: 2. A tgui representation in a TypeScript file. Every `/datum/preference` requires these three values be set: + 1. `category` - See [Categories](#Categories). 2. `savefile_key` - The value which will be saved in the savefile. This will also be the identifier for tgui. 3. `savefile_identifier` - Whether or not this is a character specific preference (`PREFERENCE_CHARACTER`) or one that affects the player (`PREFERENCE_PLAYER`). As an example: hair color is `PREFERENCE_CHARACTER` while your UI settings are `PREFERENCE_PLAYER`, since they do not change between characters. @@ -22,15 +23,15 @@ From here, you will want to write code resembling: import { Feature } from "../base"; export const savefile_key_here: Feature = { - name: "Preference Name Here", - component: Component, + name: "Preference Name Here", + component: Component, - // Necessary for game preferences, unused for others - category: "CATEGORY", + // Necessary for game preferences, unused for others + category: "CATEGORY", - // Optional, shown as a tooltip - description: "This preference will blow your mind!", -} + // Optional, shown as a tooltip + description: "This preference will blow your mind!", +}; ``` `T` and `Component` depend on the type of preference you're making. Here are all common examples... @@ -59,9 +60,9 @@ Your `.tsx` file would look like: import { Feature, FeatureNumberInput } from "../base"; export const legs: Feature = { - name: "Legs", - component: FeatureNumberInput, -} + name: "Legs", + component: FeatureNumberInput, +}; ``` ## Toggle preferences @@ -84,12 +85,13 @@ Your `.tsx` file would look like: import { CheckboxInput, FeatureToggle } from "../base"; export const enable_breathing: FeatureToggle = { - name: "Enable breathing", - component: CheckboxInput, -} + name: "Enable breathing", + component: CheckboxInput, +}; ``` ## Choiced preferences + A choiced preference is one where the only options are in a distinct few amount of choices. Examples include skin tone, shirt, and UI style. To create one, derive from `/datum/preference/choiced`. @@ -118,14 +120,15 @@ Your `.tsx` file would then look like: import { FeatureChoiced, FeatureDropdownInput } from "../base"; export const favorite_drink: FeatureChoiced = { - name: "Favorite drink", - component: FeatureDropdownInput, + name: "Favorite drink", + component: FeatureDropdownInput, }; ``` This will create a dropdown input for your preference. ### Choiced preferences - Icons + Choiced preferences can generate icons. This is how the clothing/species preferences work, for instance. However, if we just want a basic dropdown input with icons, it would look like this: ```dm @@ -155,12 +158,13 @@ Then, change your `.tsx` file to look like: import { FeatureChoiced, FeatureIconnedDropdownInput } from "../base"; export const favorite_drink: FeatureChoiced = { - name: "Favorite drink", - component: FeatureIconnedDropdownInput, + name: "Favorite drink", + component: FeatureIconnedDropdownInput, }; ``` ### Choiced preferences - Display names + Sometimes the values you want to save in code aren't the same as the ones you want to display. You can specify display names to change this. The only thing you will add is "compiled data". @@ -182,7 +186,8 @@ The only thing you will add is "compiled data". Your `.tsx` file does not change. The UI will figure it out for you! ## Color preferences -These refer to colors, such as your OOC color. When read, these values will be given as 6 hex digits, *without* the pound sign. + +These refer to colors, such as your OOC color. When read, these values will be given as 6 hex digits, _without_ the pound sign. ```dm /datum/preference/color/eyeliner_color @@ -197,12 +202,13 @@ Your `.tsx` file would look like: import { FeatureColorInput, Feature } from "../base"; export const eyeliner_color: Feature = { - name: "Eyeliner color", - component: FeatureColorInput, + name: "Eyeliner color", + component: FeatureColorInput, }; ``` ## Name preferences + These refer to an alternative name. Examples include AI names and backup human names. These exist in `code/modules/client/preferences/names.dm`. @@ -255,6 +261,7 @@ If your preference is `PREFERENCE_CHARACTER`, it MUST override `apply_to_human`, You can also read preferences directly with `prefs.read_preference(/datum/preference/type/here)`, which will return the stored value. ## Categories + Every preference needs to be in a `category`. These can be found in `code/__DEFINES/preferences.dm`. ```dm @@ -306,7 +313,7 @@ Compiled data is sent to the `serverData` field in the `FeatureValueProps`. If you have good knowledge with tgui (especially TypeScript), you'll be able to create your own component to represent preferences. -The `component` field in a feature accepts __any__ component that accepts `FeatureValueProps`. +The `component` field in a feature accepts **any** component that accepts `FeatureValueProps`. This will give you the fields: @@ -335,18 +342,21 @@ For a basic example of how this can look, observe `CheckboxInput`: ```tsx export const CheckboxInput = ( - props: FeatureValueProps + props: FeatureValueProps, ) => { - return ( { - props.handleSetValue(!props.value); - }} - />); + return ( + { + props.handleSetValue(!props.value); + }} + /> + ); }; ``` ## Advanced - Middleware + A `/datum/preference_middleware` is a way to inject your own data at specific points, as well as hijack actions. Middleware can hijack actions by specifying `action_delegations`: @@ -422,20 +432,20 @@ import { Antagonist, Category } from "../base"; import { multiline } from "tgui-core/string"; const Changeling: Antagonist = { - key: "changeling", // This must be the same as your filename - name: "Changeling", - description: [ - multiline` + key: "changeling", // This must be the same as your filename + name: "Changeling", + description: [ + multiline` A highly intelligent alien predator that is capable of altering their shape to flawlessly resemble a human. `, - multiline` + multiline` Transform yourself or others into different identities, and buy from an arsenal of biological weaponry with the DNA you collect. `, - ], - category: Category.Roundstart, // Category.Roundstart, Category.Midround, or Category.Latejoin + ], + category: Category.Roundstart, // Category.Roundstart, Category.Midround, or Category.Latejoin }; export default Changeling; @@ -453,4 +463,4 @@ If `antag_preference` is set, it will refer to that preference instead of `antag ## Updating special_roles -In `code/__DEFINES/role_preferences.dm` (the same place you'll need to make your ROLE_\* defined), simply add your antagonist to the `special_roles` assoc list. The key is your ROLE, the value is the number of days since your first game in order to play as that antagonist. +In `code/__DEFINES/role_preferences.dm` (the same place you'll need to make your ROLE\_\* defined), simply add your antagonist to the `special_roles` assoc list. The key is your ROLE, the value is the number of days since your first game in order to play as that antagonist. diff --git a/code/modules/keybindings/readme.md b/code/modules/keybindings/readme.md index f57d8d55ffa..c9ad3772e56 100644 --- a/code/modules/keybindings/readme.md +++ b/code/modules/keybindings/readme.md @@ -33,10 +33,10 @@ No client-set keybindings at this time, but it shouldn't be too hard if someone Notes about certain keys: -* `Tab` has client-sided behavior but acts normally -* `T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away. -* `\` needs to be escaped in the dmf so any usage is `\\` +- `Tab` has client-sided behavior but acts normally +- `T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away. +- `\` needs to be escaped in the dmf so any usage is `\\` You cannot `TICK_CHECK` or check `world.tick_usage` inside of procs called by key down and up events. They happen outside of a byond tick and have no meaning there. Key looping -works correctly since it's part of a subsystem, not direct input. \ No newline at end of file +works correctly since it's part of a subsystem, not direct input. diff --git a/code/modules/mapping/modular_map_loader/README.md b/code/modules/mapping/modular_map_loader/README.md index 7ce7509d040..2efcc29b16b 100644 --- a/code/modules/mapping/modular_map_loader/README.md +++ b/code/modules/mapping/modular_map_loader/README.md @@ -10,9 +10,9 @@ Modular map loading is a system to allow maps to be generated with random varian This root object handled picking and loading in map modules. It has two variables, and one proc. -* `var/config_file` - A string, points to a TOML configuration file, which is used to hold the information necessary to pull the correct map files and place them on the correct roots. This will be the same for all roots on a map. -* `var/key` - A string, used to pull a list of `.dmm` files from the configuration file. -* `load_map()` - Called asynchronously in the root's `Initialize()`. This proc creates a new instance of `/datum/map_template/map_module`, ingests the configuration file `config_file` points to, and picks a `.dmm` file path which maps to the root's `key`, by picking a random filename from among those which `key` maps to, and appending it to a folder path. This file path is passed into the map templace instance's `load()`, and the template takes over. +- `var/config_file` - A string, points to a TOML configuration file, which is used to hold the information necessary to pull the correct map files and place them on the correct roots. This will be the same for all roots on a map. +- `var/key` - A string, used to pull a list of `.dmm` files from the configuration file. +- `load_map()` - Called asynchronously in the root's `Initialize()`. This proc creates a new instance of `/datum/map_template/map_module`, ingests the configuration file `config_file` points to, and picks a `.dmm` file path which maps to the root's `key`, by picking a random filename from among those which `key` maps to, and appending it to a folder path. This file path is passed into the map templace instance's `load()`, and the template takes over. INITIALIZE_IMMEDIATE is used to ensure the ruins are loaded at the right time to avoid runtime errors related to lighting. @@ -20,9 +20,9 @@ INITIALIZE_IMMEDIATE is used to ensure the ruins are loaded at the right time to This map templace subtype is responsible for loading in the module, it has two variables and two relevant procs. -* `var/x_offset` and `var/y_offset` - Integers, used to store the offsets used to correctly align the module when it is loaded. -* `load()` - Extends the functionality of the general map template's `load()` to allow a map to be specified at runtime. This means `preload_size()` must be called again here as the template's map file has been changed. The origin turf for the map to be loaded from is set using the offsets, and the map is loaded as per the parent. -* `preload_size()` - Extends the functionality of the general map template's `preload_size()` to run the `discover_offset` proc, calculating the offset of `/obj/modular_map_connector` and setting the offset variables accordingly. +- `var/x_offset` and `var/y_offset` - Integers, used to store the offsets used to correctly align the module when it is loaded. +- `load()` - Extends the functionality of the general map template's `load()` to allow a map to be specified at runtime. This means `preload_size()` must be called again here as the template's map file has been changed. The origin turf for the map to be loaded from is set using the offsets, and the map is loaded as per the parent. +- `preload_size()` - Extends the functionality of the general map template's `preload_size()` to run the `discover_offset` proc, calculating the offset of `/obj/modular_map_connector` and setting the offset variables accordingly. ### /obj/modular_map_connector @@ -30,7 +30,7 @@ This object is used only to determine the offsets to be used on loading, and has ### TOML configuration -This TOML file is used to map between a list of `.dmm` files and a string key. The file consists of two parts. The first is a line +This TOML file is used to map between a list of `.dmm` files and a string key. The file consists of two parts. The first is a line ``` directory = "_maps/etc/" @@ -57,9 +57,9 @@ This section will cover the basics of how to use map modules as a mapper. If you First we need to create a map, as we usually would. Let's say we want to create a new space ruin `foobar.dmm`, and we put it in the appropriate folder as usual, `_maps/RandomRuins/SpaceRuins/foobar.dmm`. We now need to create three more things. -* `code/modules/ruins/spaceruin_code/foobar.dm` - A code file like would be used to store any code specific to this map. -* `strings/modular_maps/foobar.toml`- A configuration file, this will be looked at in more detail later. -* `_maps/RandomRuins/SpaceRuins/foobar/` - A new subfolder, which is where we will put the `.dmm` files for the modules. +- `code/modules/ruins/spaceruin_code/foobar.dm` - A code file like would be used to store any code specific to this map. +- `strings/modular_maps/foobar.toml`- A configuration file, this will be looked at in more detail later. +- `_maps/RandomRuins/SpaceRuins/foobar/` - A new subfolder, which is where we will put the `.dmm` files for the modules. In `code/modules/ruins/spaceruin_code/foobar.dm` we need to add a small piece of code to define a new modular map root type for our map, which should look like this diff --git a/code/modules/mob/say_readme.md b/code/modules/mob/say_readme.md index 27f47b771fd..68f490331e2 100644 --- a/code/modules/mob/say_readme.md +++ b/code/modules/mob/say_readme.md @@ -1,6 +1,7 @@ # Say code basics This document is a little dated but I believe it's accurate mostly (oranges 2019) + # MIAUW'S SAY REWRITE This is a basic explanation of how say() works. Read this if you don't understand something. @@ -16,7 +17,9 @@ To have things react when other things speak around them, add the HEAR_1 flag to override their Hear() proc. # PROCS & VARIABLES + Here follows a list of say()-related procs and variables. + ``` global procs get_radio_span(freq) @@ -142,6 +145,7 @@ global procs Intercepts say() after it's done all of it's message building. If this returns true we stop say(), if it returns false we keep going ``` + # RADIOS I did not want to interfere with radios too much, but I sort of had to. @@ -159,8 +163,10 @@ To add a radio, simply use add_radio(radio, frequency). To remove a radio, use r To remove a radio from ALL frequencies, use remove_radio_all(radio). ## VIRTUAL SPEAKERS: + Virtual speakers are simply atom/movables with a few extra variables. If radio_freq is not null, the code will rely on the fact that the speaker is virtual. This means that several procs will return something: + ``` (all of these procs are defined at the atom/movable level and return "" at that level.) GetJob() @@ -172,6 +178,7 @@ If radio_freq is not null, the code will rely on the fact that the speaker is vi GetRadio() Returns the radio that was spoken through by the source. Needed for AI tracking. ``` + This is fairly hacky, but it means that I can advoid using istypes. It's mainly relevant for AI tracking and AI job display. That's all, folks! diff --git a/code/modules/mod/adding_new_mod.md b/code/modules/mod/adding_new_mod.md index 73dcdb1c8de..2dc4f1bb3fc 100644 --- a/code/modules/mod/adding_new_mod.md +++ b/code/modules/mod/adding_new_mod.md @@ -199,6 +199,7 @@ As it's a medical module, we'll put it [here](modules/modules_medical.dm). Let's ``` As we want this effect to be on demand, we probably want this to be an usable module. There are four types of modules: + - Passive: These have a passive effect. - Togglable: You can turn these on and off. - Usable: You can use these for a one time effect. @@ -312,4 +313,5 @@ Now we want to add it to the psychological theme, which is very simple, finishin ``` ## Ending + This finishes this hopefully easy to follow along tutorial. You should now know how to make a basic theme, a skin for it, and a module. diff --git a/code/modules/procedural_mapping/README.md b/code/modules/procedural_mapping/README.md index 5123f51ef18..37d25343dc6 100644 --- a/code/modules/procedural_mapping/README.md +++ b/code/modules/procedural_mapping/README.md @@ -1,24 +1,29 @@ # Procedural Mapping -### *With Regards To RemieRichards* + +### _With Regards To RemieRichards_ --- ## Coder Informative Readme ### mapGenerator: -Desc: a *mapGenerator* is a master datum that collects and syncs all *mapGeneratorModules* in its modules list. + +Desc: a _mapGenerator_ is a master datum that collects and syncs all _mapGeneratorModules_ in its modules list. ### defineRegion(var/turf/Start, turf/End, replace = 0) + Example: `defineRegion(locate(1,1,1),locate(5,5,5),0)` -Desc: Sets the bounds of the *mapGenerator's* "map". +Desc: Sets the bounds of the _mapGenerator's_ "map". ### defineCircularRegion(var/turf/Start, turf/End, replace = 0) + Example: `defineCircularRegion(locate(1,1,1),locate(5,5,5),0)` -Desc: Sets the *mapGenerator's* "map" as a circle, with center in the middle of Start and End's X,Y,Z coordinates. +Desc: Sets the _mapGenerator's_ "map" as a circle, with center in the middle of Start and End's X,Y,Z coordinates. ### undefineRegion() + Example: `undefineRegion()` Desc: Empties the map generator list. @@ -35,13 +40,13 @@ Existing Calls: `mapGenerator/defineRegion(), mapGenerator/defineCircularRegion( Example: `generate()` -Desc: Orders all *mapGeneratorModules* in the modules list to `generate()`. +Desc: Orders all _mapGeneratorModules_ in the modules list to `generate()`. ### generateOneTurf(var/turf/T) Example: `generateOneTurf(locate(1,1,1))` -Desc: Orders all *mapGeneratorModules* in the modules list to `place(T)` on this turf. +Desc: Orders all _mapGeneratorModules_ in the modules list to `place(T)` on this turf. ### initialiseModules() @@ -55,7 +60,7 @@ Existing Calls: `mapGenerator/New()` Example: `syncModules()` -Desc: Sets the Mother variable on all *mapGeneratorModules* in the modules list to this *mapGenerator*. +Desc: Sets the Mother variable on all _mapGeneratorModules_ in the modules list to this _mapGenerator_. Existing Calls: `initialiseModules(),generate(),generateOneTurf()` @@ -85,7 +90,7 @@ Existing Calls: `mapGenerator/generate()` Example: `place(locate(1,1,1)) ` -Desc: Run this *mapGeneratorModule's* effects on this turf (Spawning atoms, Changing turfs). +Desc: Run this _mapGeneratorModule's_ effects on this turf (Spawning atoms, Changing turfs). Existing Calls: `mapGenerator/generate()`, `mapGenerator/generateOneTurf()` @@ -105,31 +110,30 @@ Simple Workflow: 1. Define a/some mapGeneratorModule(s) to your liking, choosing atoms and turfs to spawn -* I chose to split Turfs and Atoms off into separate modules, but this is NOT required. -* A mapGeneratorModule may have turfs AND atoms, so long as each is in its appropriate list +- I chose to split Turfs and Atoms off into separate modules, but this is NOT required. +- A mapGeneratorModule may have turfs AND atoms, so long as each is in its appropriate list 2. Define a mapGenerator type who's modules list contains the typepath(s) of all the module(s) you wish to use -* The order of the typepaths in the modules list is the order they will happen in, this is important for clusterCheckFlags. +- The order of the typepaths in the modules list is the order they will happen in, this is important for clusterCheckFlags. 3. Take notes of the Bottom Left and Top Right turfs of your rectangular "map"'s coordinates -* X, Y, AND Z. Yes, you can create 3D "maps" by having differing Z coordinates +- X, Y, AND Z. Yes, you can create 3D "maps" by having differing Z coordinates 4. Create the mapGenerator type you created 5. Call `yourMapGeneratorType.defineRegion(locate(X,Y,Z), locate(X,Y,Z))` -* The above X/Y/Zs are the coordinates of the start and end turfs, the locate() simply finds the turf for the code +- The above X/Y/Zs are the coordinates of the start and end turfs, the locate() simply finds the turf for the code 6. Call `yourMapGeneratorType.generate()`, this will cause all the modules in the generator to build within the map bounds Option Suggestions: -* Have separate modules for Turfs and Atoms, this is not enforced, but it is how I have structured my nature example. -* If your map doesn't look quite to your liking, simply jiggle with the variables on your modules and the type probabilities. -* You can mix and map premade areas with the procedural generation, for example mapping an entire flat land but having code generate just the grass tufts. - +- Have separate modules for Turfs and Atoms, this is not enforced, but it is how I have structured my nature example. +- If your map doesn't look quite to your liking, simply jiggle with the variables on your modules and the type probabilities. +- You can mix and map premade areas with the procedural generation, for example mapping an entire flat land but having code generate just the grass tufts. Using the Modules list @@ -139,41 +143,40 @@ To help you do this templates such as /mapGeneratorModule/bottomLayer have been These are located near the bottom of `mapGeneratorModule.dm`. You would order your list left to right, top to bottom. For example: `modules = list(bottomLayer,nextLayer,nextNextLayer)`, etc. - Variable Breakdown (For Mappers): ### mapGenerator -* map - INTERNAL, do not touch -* modules - A list of typepaths of mapGeneratorModules +- map - INTERNAL, do not touch +- modules - A list of typepaths of mapGeneratorModules ### mapGeneratorModule -* mother - INTERNAL, do not touch -* spawnableAtoms - A list of typepaths and their probability to spawn, eg: `spawnableAtoms = list(/obj/structure/flora/tree/pine = 30)` +- mother - INTERNAL, do not touch -* spawnableTurfs - A list of typepaths and their probability to spawn, eg: `spawnableTurfs = list(/turf/unsimulated/floor/grass = 100)` +- spawnableAtoms - A list of typepaths and their probability to spawn, eg: `spawnableAtoms = list(/obj/structure/flora/tree/pine = 30)` -* clusterMax - The max range to check for something being "too close" for this atom/turf to spawn, the true value is random between clusterMin and clusterMax +- spawnableTurfs - A list of typepaths and their probability to spawn, eg: `spawnableTurfs = list(/turf/unsimulated/floor/grass = 100)` -* clusterMin - The min range to check for something being "too close" for this atom/turf to spawn, the true value is random between clusterMin and clusterMax +- clusterMax - The max range to check for something being "too close" for this atom/turf to spawn, the true value is random between clusterMin and clusterMax -* clusterCheckFlags - A Bitfield that controls how the cluster checks work, All based on clusterMin and clusterMax guides +- clusterMin - The min range to check for something being "too close" for this atom/turf to spawn, the true value is random between clusterMin and clusterMax -* allowAtomsOnSpace - A Boolean for if we allow atoms to spawn on space tiles +- clusterCheckFlags - A Bitfield that controls how the cluster checks work, All based on clusterMin and clusterMax guides + +- allowAtomsOnSpace - A Boolean for if we allow atoms to spawn on space tiles ### clusterCheckFlags flags: - CLUSTER_CHECK_NONE 0 //No checks are done, cluster as much as possible - CLUSTER_CHECK_DIFFERENT_TURFS 2 //Don't let turfs of DIFFERENT types cluster - CLUSTER_CHECK_DIFFERENT_ATOMS 4 //Don't let atoms of DIFFERENT types cluster - CLUSTER_CHECK_SAME_TURFS 8 //Don't let turfs of the SAME type cluster - CLUSTER_CHECK_SAME_ATOMS 16 //Don't let atoms of the SAME type cluster + CLUSTER_CHECK_NONE 0 //No checks are done, cluster as much as possible + CLUSTER_CHECK_DIFFERENT_TURFS 2 //Don't let turfs of DIFFERENT types cluster + CLUSTER_CHECK_DIFFERENT_ATOMS 4 //Don't let atoms of DIFFERENT types cluster + CLUSTER_CHECK_SAME_TURFS 8 //Don't let turfs of the SAME type cluster + CLUSTER_CHECK_SAME_ATOMS 16 //Don't let atoms of the SAME type cluster - CLUSTER_CHECK_SAMES 24 //Don't let any of the same type cluster - CLUSTER_CHECK_DIFFERENTS 6 //Don't let any different types cluster - CLUSTER_CHECK_ALL_TURFS 10 //Don't let ANY turfs cluster same and different types - CLUSTER_CHECK_ALL_ATOMS 20 //Don't let ANY atoms cluster same and different types - - CLUSTER_CHECK_ALL 30 //Don't let anything cluster, like, at all + CLUSTER_CHECK_SAMES 24 //Don't let any of the same type cluster + CLUSTER_CHECK_DIFFERENTS 6 //Don't let any different types cluster + CLUSTER_CHECK_ALL_TURFS 10 //Don't let ANY turfs cluster same and different types + CLUSTER_CHECK_ALL_ATOMS 20 //Don't let ANY atoms cluster same and different types + CLUSTER_CHECK_ALL 30 //Don't let anything cluster, like, at all diff --git a/code/modules/projectiles/guns/bolt_types_explained.md b/code/modules/projectiles/guns/bolt_types_explained.md index e1f638dceab..f5353d12cc2 100644 --- a/code/modules/projectiles/guns/bolt_types_explained.md +++ b/code/modules/projectiles/guns/bolt_types_explained.md @@ -1,32 +1,35 @@ # Balistic gun icon states explained - -For a unknown period of time, `/obj/item/gun/ballistic` used the wrong icon state for its `bolt_type` and so, if you tried to copy how it worked to make your own gun, you'd get a broken sprite. This documentation is intended to explain in detail what some of the variables and functions do, and how to make your own gun subtypes that work properly. +For a unknown period of time, `/obj/item/gun/ballistic` used the wrong icon state for its `bolt_type` and so, if you tried to copy how it worked to make your own gun, you'd get a broken sprite. This documentation is intended to explain in detail what some of the variables and functions do, and how to make your own gun subtypes that work properly. ## Bolt Types -The easiest thing to screw up. For a long time, `/obj/item/gun/ballistic` had `bolt_type` set to `BOLT_TYPE_STANDARD` when the sprite was configured to use `BOLT_TYPE_LOCKING` sprites. Nobody noticed, because it wasn't obtainable through normal gameplay, and the Mosin which was broken by it only has like 3 pixels missing. +The easiest thing to screw up. For a long time, `/obj/item/gun/ballistic` had `bolt_type` set to `BOLT_TYPE_STANDARD` when the sprite was configured to use `BOLT_TYPE_LOCKING` sprites. Nobody noticed, because it wasn't obtainable through normal gameplay, and the Mosin which was broken by it only has like 3 pixels missing. ### BOLT_TYPE_STANDARD -This is for guns that don't lock their slides back. Visually, it usually means guns that have an internal bolt that isn't visible, like the c20r or ARG Boarder. The base icon state is all you need to make it work. + +This is for guns that don't lock their slides back. Visually, it usually means guns that have an internal bolt that isn't visible, like the c20r or ARG Boarder. The base icon state is all you need to make it work. ### BOLT_TYPE_OPEN -Pretty much like the Standard, but it takes rounds directly from the magazine without holding them in the chaimber first. This means that when you remove the mag, there isn't going to still be a bullet in the chaimber. + +Pretty much like the Standard, but it takes rounds directly from the magazine without holding them in the chaimber first. This means that when you remove the mag, there isn't going to still be a bullet in the chaimber. ### BOLT_TYPE_NO_BOLT -This is your revolvers and some(?) break action shotguns. When you click to reload them, they'll drop all the bullets inside of the gun, unspent or not. + +This is your revolvers and some(?) break action shotguns. When you click to reload them, they'll drop all the bullets inside of the gun, unspent or not. ### BOLT_TYPE_LOCKING -The complicated one. This is what most pistols and bolt action rifles are. When you cycle (or fire) it on empty, it will lock back the slide, and you'll have to click it again to send the slide home. For rifles with `semi_auto = FALSE`, they don't feed automatically, so you have to rack the slide after every shot. (Like the Mosin) -Now, for the sprites, your base sprite should be the gun without a slide or bolt. Take a look at the APS, deagle, or Mosin sprites. If your icon state is `handcannon` you need to have a sprite for the slide as `handcannon_bolt`, and then a sprite for the bolt being locked back as `handcannon_bolt_locked`. +The complicated one. This is what most pistols and bolt action rifles are. When you cycle (or fire) it on empty, it will lock back the slide, and you'll have to click it again to send the slide home. For rifles with `semi_auto = FALSE`, they don't feed automatically, so you have to rack the slide after every shot. (Like the Mosin) + +Now, for the sprites, your base sprite should be the gun without a slide or bolt. Take a look at the APS, deagle, or Mosin sprites. If your icon state is `handcannon` you need to have a sprite for the slide as `handcannon_bolt`, and then a sprite for the bolt being locked back as `handcannon_bolt_locked`. ## Sawing off -For guns that have `can_be_sawn_off = TRUE`, you'll need to make an entire second set of sprites. For `BOLT_TYPE_LOCKING`, this will look like the Mosin. If you're making a sawn off version of `handcannon`, you'll need `hancannon_sawn` for the base, and then `hancannon_sawn_bolt` and `hancannon_sawn_bolt_locked`. + +For guns that have `can_be_sawn_off = TRUE`, you'll need to make an entire second set of sprites. For `BOLT_TYPE_LOCKING`, this will look like the Mosin. If you're making a sawn off version of `handcannon`, you'll need `hancannon_sawn` for the base, and then `hancannon_sawn_bolt` and `hancannon_sawn_bolt_locked`. ## Ammo display -You'll need `mag_display = TRUE` and a sprite called `handcannon_mag` to show the gun as having a magazine inserted into it. It's set to true by default, though. - -Perhaps you want to make some kind visual depiction of ammunition feed. You can overlay over top of the magazine sprite of 100%, 80%, 60%, 40%, and 20% by having `mag_display_ammo = TRUE`. Use `handcannon_mag_100`, `handcannon_mag_80`, ect... to display these. There is no zero. You can use a overlaying sprite for showing the gun as empty called `handcannon_empty`. Take a look at the c20r as an example. +You'll need `mag_display = TRUE` and a sprite called `handcannon_mag` to show the gun as having a magazine inserted into it. It's set to true by default, though. +Perhaps you want to make some kind visual depiction of ammunition feed. You can overlay over top of the magazine sprite of 100%, 80%, 60%, 40%, and 20% by having `mag_display_ammo = TRUE`. Use `handcannon_mag_100`, `handcannon_mag_80`, ect... to display these. There is no zero. You can use a overlaying sprite for showing the gun as empty called `handcannon_empty`. Take a look at the c20r as an example. diff --git a/code/modules/reagents/chemistry/fermi_readme.md b/code/modules/reagents/chemistry/fermi_readme.md index 0fc2ed76da1..b0b694fdc3c 100644 --- a/code/modules/reagents/chemistry/fermi_readme.md +++ b/code/modules/reagents/chemistry/fermi_readme.md @@ -27,6 +27,7 @@ In brief: Holder.dm now sets up reactions, while equilibrium.dm runs them. Holder itself is processed when there is a list of reactions, but the equilibrium does the calculating. In essence, it holds onto a list of objects to run. Handle_reactions() is used to update the reaction list, with a few checks at the start to prevent any unnecessary updates. #### When a reaction is detected: + - If it’s REACTION_INSTANT then it’ll use a method similar to the old mechanics. - If not then it’ll set up an equilibrium, which checks to see if the reaction is valid on creation. - If it’s valid, then on_reaction is called. @@ -35,6 +36,7 @@ Holder.dm now sets up reactions, while equilibrium.dm runs them. Holder itself i - If there’s a list of reactions, then the holder starts processing. #### When holder is processing: + - Each equilibrium is processed, and it handles it’s own reaction. For each step it handles every reaction. - At the start, the equilibrium checks it’s conditions and calculates how much it can make in this step. - It checks the temp, reagents and catalyst. @@ -43,11 +45,13 @@ Holder.dm now sets up reactions, while equilibrium.dm runs them. Holder itself i - The offset of optimal pH and temp is calculated, and these correlate with purity and yield. #### How a holder stops reacting: + When one of the checks fails in the equilibrium object, it is flagged for deletion. The holder will detect this and call reaction_finish() and delete the equilibrium object – ending that reaction. ## Recipe and processing mechanics Lets go over the reaction vars below. These can be edited and set on a per chemical_reaction basis + ```dm /datum/chemical_reaction ... @@ -89,6 +93,7 @@ the y axis is the normalised value of growth, which is then muliplied by the rat Optimal pH ranges are set on a per recipe basis - though at the moment all recipes use a default recipe, so they all have the same window (except for the buffers). Hopefully either as a community effort/or in future PRs we can create unique profiles for the present reactions in the game. As for how you define the reaction variables for a reaction, there are a few new variables for the chemical_recipe datum. I'll go over specifically how pH works for the default reaction. + ```dm /datum/chemical_reaction ... @@ -108,7 +113,6 @@ If you're designing a reaction you can define an optimal range between the Optim Though to note; if your purity dips below the PurityMin of a reaction it’ll call the overly_impure() function – which by default reduces the purity of all reagents in the beaker. Additionally, if the purity at the end of a reaction is below the PurityMin, it’ll convert into the failed chem defined by the product’s failed_chem defined in its reagent datum. For default the PurityMin is 0.15, and is pretty difficult to fail. This is all customisable however, if you wanted to use these hooks to design a even more unique reaction, just don’t call the parent proc when using methods. - ### Conditional changes in reagents datum per timestep ```dm @@ -140,6 +144,7 @@ For REACTION_CLEAR – this causes the purity mechanics to resolve in the beaker Is_cold_recipie requires you to set your overheat_temp and optimal_temp descend instead. Eg: + ```dm /datum/chemical_reaction ... @@ -149,7 +154,9 @@ Eg: ``` # Reagents + The new vars that are introduced are below: + ```dm /datum/reagent /// pH of the reagent @@ -171,7 +178,7 @@ The new vars that are introduced are below: - `creation_purity` is the purity of the reagent on creation. This won't change. If you want to write code that checks the purity in any of the methods, use this. - `impure_chem` is the datum type that is created provided that its `creation_purity` is above the `inverse_chem_val`. When the reagent is consumed it will split into this OR if the associated `datum/chemical_recipe` has a REACTION_CLEAR_IMPURE flag it will split at the end of the reaction in the `datum/reagents` holder - `inverse_chem_val` if a reagent's purity is below this value it will 100% convert into `inverse_chem`. If above it will split into `impure_chem`. See the note on purity effects above -- `inverse_chem` is the datum type that is created provided that its `creation_purity` is below the `inverse_chem_val`. When the reagent is consumed it will 100% convert into this OR if the associated `datum/chemical_recipe` has a REACTION_CLEAR_INVERSE flag it will 100% convert at the end of the reaction in the `datum/reagents` holder +- `inverse_chem` is the datum type that is created provided that its `creation_purity` is below the `inverse_chem_val`. When the reagent is consumed it will 100% convert into this OR if the associated `datum/chemical_recipe` has a REACTION_CLEAR_INVERSE flag it will 100% convert at the end of the reaction in the `datum/reagents` holder - `failed_chem` is the chem that the product is 100% converted into if the purity is below the associated `datum/chemical_recipies`' `PurityMin` AT THE END OF A REACTION. When writing any reagent code ALWAYS use creation_purity. Purity is kept for internal mechanics only and won’t reflect the purity on creation. @@ -179,6 +186,7 @@ When writing any reagent code ALWAYS use creation_purity. Purity is kept for int See above for purity mechanics, but this is where you set the reagents that are created. If you’re making an impure reagent I recommend looking at impure_reagents.dm to see how they’re set up and consider using the `datum/reagents/impure` as a parent. The flags you can set for `var/chemical_flags` are: + ```dm #define REAGENT_DEAD_PROCESS (1<<0) //allows on_mob_dead() if present in a dead body #define REAGENT_DONOTSPLIT (1<<1) //Do not split the chem at all during processing - ignores all purity effects @@ -195,6 +203,7 @@ While you might think reagent_flags is a more sensible name - it is already used # Relivant vars from the holder.dm / reagents datum There are a few variables that are useful to know about + ```dm /datum/reagents /// Current temp of the holder volume @@ -206,6 +215,7 @@ There are a few variables that are useful to know about ///Hard check to see if the reagents is presently reacting var/is_reacting = FALSE ``` + - chem_temp is the temperature used in the `datum/chemical_recipe` - pH is a result of the sum of all reagents, as well as any changes from buffers and reactions. This is the pH used in `datum/chemical_recipe`. - isReacting is a bool that can be used outside to ensure that you don't touch a reagents that is reacting. diff --git a/code/modules/tgchat/README.md b/code/modules/tgchat/README.md index 71acb47c458..d2a99e5ffd2 100644 --- a/code/modules/tgchat/README.md +++ b/code/modules/tgchat/README.md @@ -5,6 +5,7 @@ ### Message Format TgChat handles sending messages from the server to the client through the use of JSON payloads, of which the format will change depending on the type of message and the intended client endpoint. An example of the payload for chat messages is as follows: + ```json { "sequence": 0, @@ -13,13 +14,13 @@ TgChat handles sending messages from the server to the client through the use of "text": ". . .", // ?optional !atleast-one "html": ". . .", // ?optional !atleast-one "avoidHighlighting": 0 // ?optional - }, + } } ``` ### Reliability -In the past there have been issues where BYOND will silently and without reason lose a message we sent to the client, to detect this and recover from it seamlessly TgChat also has a baked in reliability layer. This reliability layer is very primitive, and simply keeps track of received sequence numbers. Should the client receive an unexpected sequence number TgChat asks the server to resend any missing packets. +In the past there have been issues where BYOND will silently and without reason lose a message we sent to the client, to detect this and recover from it seamlessly TgChat also has a baked in reliability layer. This reliability layer is very primitive, and simply keeps track of received sequence numbers. Should the client receive an unexpected sequence number TgChat asks the server to resend any missing packets. ### Ping System diff --git a/code/modules/tgs/README.md b/code/modules/tgs/README.md index 35ca73d7e9a..473442fd119 100644 --- a/code/modules/tgs/README.md +++ b/code/modules/tgs/README.md @@ -5,9 +5,9 @@ This folder should be placed on its own inside a codebase that wishes to use the - [includes.dm](./includes.dm) is the file that should be included by DM code, it handles including the rest. - The [core](./core) folder includes all code not directly part of any API version. - The other versioned folders contain code for the different DMAPI versions. - - [v3210](./v3210) contains the final TGS3 API. - - [v4](./v4) is the legacy DMAPI 4 (Used in TGS 4.0.X versions). - - [v5](./v5) is the current DMAPI version used by TGS >=4.1. + - [v3210](./v3210) contains the final TGS3 API. + - [v4](./v4) is the legacy DMAPI 4 (Used in TGS 4.0.X versions). + - [v5](./v5) is the current DMAPI version used by TGS >=4.1. - [LICENSE](./LICENSE) is the MIT license for the DMAPI. APIs communicate with TGS in two ways. All versions implement TGS -> DM communication using /world/Topic. DM -> TGS communication, called the bridge method, is different for each version. diff --git a/code/modules/tgs/core/README.md b/code/modules/tgs/core/README.md index 965e21b549a..7886a857149 100644 --- a/code/modules/tgs/core/README.md +++ b/code/modules/tgs/core/README.md @@ -2,7 +2,7 @@ This folder contains all DMAPI code not directly involved in an API. -- [_definitions.dm](./definitions.dm) contains defines needed across DMAPI internals. +- [\_definitions.dm](./definitions.dm) contains defines needed across DMAPI internals. - [byond_world_export.dm](./byond_world_export.dm) contains the default `/datum/tgs_http_handler` implementation which uses `world.Export()`. - [core.dm](./core.dm) contains the implementations of the `/world/proc/TgsXXX()` procs. Many map directly to the `/datum/tgs_api` functions. It also contains the /datum selection and setup code. - [datum.dm](./datum.dm) contains the `/datum/tgs_api` declarations that all APIs must implement. diff --git a/code/modules/tgs/v5/README.md b/code/modules/tgs/v5/README.md index a8a0c748e7b..fb374c2f872 100644 --- a/code/modules/tgs/v5/README.md +++ b/code/modules/tgs/v5/README.md @@ -2,8 +2,8 @@ This DMAPI implements bridge requests using HTTP GET requests to TGS. It has no security restrictions. -- [__interop_version.dm](./__interop_version.dm) contains the version of the API used between the DMAPI and TGS. -- [_defines.dm](./_defines.dm) contains constant definitions. +- [\_\_interop_version.dm](./__interop_version.dm) contains the version of the API used between the DMAPI and TGS. +- [\_defines.dm](./_defines.dm) contains constant definitions. - [api.dm](./api.dm) contains the bulk of the API code. - [bridge.dm](./bridge.dm) contains functions related to making bridge requests. - [chunking.dm](./chunking.dm) contains common function for splitting large raw data sets into chunks BYOND can natively process. diff --git a/code/modules/tooltip/tooltip.html b/code/modules/tooltip/tooltip.html index 40167f3674a..0fa43d4debb 100644 --- a/code/modules/tooltip/tooltip.html +++ b/code/modules/tooltip/tooltip.html @@ -1,269 +1,409 @@ - + - - Tooltip - - - + + +
+
+
+ + - - + //Go get the map details + window.location = + "byond://winget?callback=tooltip.updateCallback;id=mapwindow.map;property=size,view-size"; + }, + }; + + diff --git a/code/modules/unit_tests/README.md b/code/modules/unit_tests/README.md index d53a6eb9586..1f8bc271b36 100644 --- a/code/modules/unit_tests/README.md +++ b/code/modules/unit_tests/README.md @@ -7,6 +7,7 @@ Unit tests are automated code to verify that parts of the game work exactly as t On their most basic level, when `UNIT_TESTS` is defined, all subtypes of `/datum/unit_test` will have their `Run` proc executed. From here, if `Fail` is called at any point, then the tests will report as failed. ## How do I write one? + 1. Find a relevant file. All unit test related code is in `code/modules/unit_tests`. If you are adding a new test for a surgery, for example, then you'd open `surgeries.dm`. If a relevant file does not exist, simply create one in this folder, then `#include` it in `_unit_tests.dm`. @@ -47,12 +48,11 @@ There are 3 ways to run unit tests - Use VS Code Tgstation Test Explorer Extension. This allows you to run tests without launching the game & can also run focused tests(either a single or a selected group) - ## How to think about tests -Unit tests exist to prevent bugs that would happen in a real game. Thus, they should attempt to emulate the game world wherever possible. For example, the [quick swap sanity test](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/quick_swap_sanity.dm) emulates a *real* scenario of the bug it fixed occurring by creating a character and giving it real items. The unrecommended alternative would be to create special test-only items. This isn't a hard rule, the [reagent method exposure tests](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/reagent_mod_expose.dm) create a test-only reagent for example, but do keep it in mind. +Unit tests exist to prevent bugs that would happen in a real game. Thus, they should attempt to emulate the game world wherever possible. For example, the [quick swap sanity test](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/quick_swap_sanity.dm) emulates a _real_ scenario of the bug it fixed occurring by creating a character and giving it real items. The unrecommended alternative would be to create special test-only items. This isn't a hard rule, the [reagent method exposure tests](https://github.com/tgstation/tgstation/blob/e416283f162b86345a8623125ab866839b1ac40d/code/modules/unit_tests/reagent_mod_expose.dm) create a test-only reagent for example, but do keep it in mind. -Unit tests should also be just that--testing *units* of code. For example, instead of having one massive test for reagents, there are instead several smaller tests for testing exposure, metabolization, etc. +Unit tests should also be just that--testing _units_ of code. For example, instead of having one massive test for reagents, there are instead several smaller tests for testing exposure, metabolization, etc. ## The unit testing API @@ -74,10 +74,10 @@ You can find more information about all of these from their respective doc comme `TEST_ASSERT_NOTEQUAL(a, b, message)` - Same as `TEST_ASSERT_EQUAL`, but reversed. -`TEST_FOCUS(test_path)` - *Only* run the test provided within the parameters. Useful for reducing noise. For example, if we only want to run our example square test, we can add `TEST_FOCUS(/datum/unit_test/square)`. Should *never* be pushed in a pull request--you will be laughed at. +`TEST_FOCUS(test_path)` - _Only_ run the test provided within the parameters. Useful for reducing noise. For example, if we only want to run our example square test, we can add `TEST_FOCUS(/datum/unit_test/square)`. Should _never_ be pushed in a pull request--you will be laughed at. ## Final Notes -- Writing tests before you attempt to fix the bug can actually speed up development a lot! It means you don't have to go in game and folllow the same exact steps manually every time. This process is known as "TDD" (test driven development). Write the test first, make sure it fails, *then* start work on the fix/feature, and you'll know you're done when your tests pass. If you do try this, do make sure to confirm in a non-testing environment just to double check. +- Writing tests before you attempt to fix the bug can actually speed up development a lot! It means you don't have to go in game and folllow the same exact steps manually every time. This process is known as "TDD" (test driven development). Write the test first, make sure it fails, _then_ start work on the fix/feature, and you'll know you're done when your tests pass. If you do try this, do make sure to confirm in a non-testing environment just to double check. - Make sure that your tests don't accidentally call RNG functions like `prob`. Since RNG is seeded during tests, you may not realize you have until someone else makes a PR and the tests fail! - Do your best not to change the behavior of non-testing code during tests. While it may sometimes be necessary in the case of situations such as the above, it is still a slippery slope that can lead to the code you're testing being too different from the production environment to be useful. diff --git a/config/admin_nicknames.json b/config/admin_nicknames.json index 14fd6d6d93c..91375e889a7 100644 --- a/config/admin_nicknames.json +++ b/config/admin_nicknames.json @@ -1,10 +1,4 @@ { - "ranks": [ - "Dedmin", - "Sir Madam Headmin" - ], - "names": [ - "Badmin", - "Spanmin" - ] + "ranks": ["Dedmin", "Sir Madam Headmin"], + "names": ["Badmin", "Spanmin"] } diff --git a/config/away_missions/README.md b/config/away_missions/README.md index 9b1dfa66f1d..863eccd595b 100644 --- a/config/away_missions/README.md +++ b/config/away_missions/README.md @@ -1,3 +1,3 @@ Add away mission dmms here. -**These are fully cached so keep this directory empty by default.** \ No newline at end of file +**These are fully cached so keep this directory empty by default.** diff --git a/config/blanks.json b/config/blanks.json index d48e49402c6..2a69fff7a67 100644 --- a/config/blanks.json +++ b/config/blanks.json @@ -517,7 +517,7 @@ "code": "NT-SCR-LRF", "category": "Security Department", "name": "Lawsuit Request Form", - "info":[ + "info": [ "

Lawsuit Request Form

", "

Prosecuters's name (with signature):

", "

[___________________________________]

", diff --git a/config/dynamic.json b/config/dynamic.json index 6b8acabd1d7..4f692643a98 100644 --- a/config/dynamic.json +++ b/config/dynamic.json @@ -7,18 +7,7 @@ "weight": 0, "required_candidates": 1, "minimum_required_age": 0, - "requirements": [ - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10 - ], + "requirements": [10, 10, 10, 10, 10, 10, 10, 10, 10, 10], "antag_cap": { "denominator": 24 }, @@ -39,9 +28,7 @@ "Research Director", "Quartermaster" ], - "restricted_roles": [ - "Cyborg" - ] + "restricted_roles": ["Cyborg"] }, "Blood Brothers": { @@ -162,9 +149,7 @@ }, "Station": { - "Radioactive Nebula": { - }, - "Background Checks": { - } + "Radioactive Nebula": {}, + "Background Checks": {} } } diff --git a/config/modular_maps/Config Files/README.md b/config/modular_maps/Config Files/README.md index 55003fa56e8..4f04073cf58 100644 --- a/config/modular_maps/Config Files/README.md +++ b/config/modular_maps/Config Files/README.md @@ -1,3 +1,3 @@ Add the config files for modular maps here. -**These are fully cached so keep this directory empty by default.** \ No newline at end of file +**These are fully cached so keep this directory empty by default.** diff --git a/config/modular_maps/README.md b/config/modular_maps/README.md index 7271c424b44..8f674e87e68 100644 --- a/config/modular_maps/README.md +++ b/config/modular_maps/README.md @@ -1,3 +1,3 @@ Add modular maps here. -**These are fully cached so keep this directory empty by default.** \ No newline at end of file +**These are fully cached so keep this directory empty by default.** diff --git a/html/admin/admin_panels.css b/html/admin/admin_panels.css index 5c832986584..4047d908448 100644 --- a/html/admin/admin_panels.css +++ b/html/admin/admin_panels.css @@ -1,42 +1,42 @@ .column { - float: left; - flex-wrap: wrap; + float: left; + flex-wrap: wrap; } .left { - width: 280px; + width: 280px; } .spacer { - margin-left: 100px; + margin-left: 100px; } .row { - content: ''; - display: table; - clear: both; + content: ""; + display: table; + clear: both; } .inputbox { - position: absolute; - top: 0px; - left: 4px; - width: 14px; - height: 14px; - background: #e6e6e6; + position: absolute; + top: 0px; + left: 4px; + width: 14px; + height: 14px; + background: #e6e6e6; } .select { - position: relative; - display: inline-block; + position: relative; + display: inline-block; } .hidden { - display: none; + display: none; } .textbox { - resize: none; - min-height: 40px; - width: 340px; + resize: none; + min-height: 40px; + width: 340px; } diff --git a/html/admin/admin_panels_css3.css b/html/admin/admin_panels_css3.css index 71861c88bb0..16262d893a8 100644 --- a/html/admin/admin_panels_css3.css +++ b/html/admin/admin_panels_css3.css @@ -1,78 +1,78 @@ .inputlabel { - position: relative; - display: inline; - cursor: pointer; - padding-left: 20px; + position: relative; + display: inline; + cursor: pointer; + padding-left: 20px; } .inputlabel input { - position: absolute; - z-index: -1; - opacity: 0; + position: absolute; + z-index: -1; + opacity: 0; } .radio .inputbox { - border-radius: 50%; + border-radius: 50%; } .inputlabel:hover input ~ .inputbox { - background: #b4b4b4; + background: #b4b4b4; } .inputlabel input:checked ~ .inputbox { - background: #2196F3; + background: #2196f3; } -.inputlabel:hover input:not([disabled]):checked ~ .inputbox{ - background: #0a6ebd; +.inputlabel:hover input:not([disabled]):checked ~ .inputbox { + background: #0a6ebd; } .inputlabel input:disabled ~ .inputbox { - pointer-events: none; - background: #838383; + pointer-events: none; + background: #838383; } .banned { - background: #ff4e4e; + background: #ff4e4e; } .inputlabel:hover input ~ .banned { - background: #ff0000; + background: #ff0000; } .inputlabel input:checked ~ .banned { - background: #a80000; + background: #a80000; } -.inputlabel:hover input:not([disabled]):checked ~ .banned{ - background: #810000; +.inputlabel:hover input:not([disabled]):checked ~ .banned { + background: #810000; } .inputbox:after { - position: absolute; - display: none; - content: ''; + position: absolute; + display: none; + content: ""; } .inputlabel input:checked ~ .inputbox:after { - display: block; + display: block; } .checkbox .inputbox:after { - top: 1px; - left: 5px; - width: 3px; - height: 9px; - transform: rotate(45deg); - border: solid #fff; - border-width: 0 2px 2px 0; + top: 1px; + left: 5px; + width: 3px; + height: 9px; + transform: rotate(45deg); + border: solid #fff; + border-width: 0 2px 2px 0; } .radio .inputbox:after { - top: 4px; - left: 4px; - width: 6px; - height: 6px; - border-radius: 50%; - background: #fff; + top: 4px; + left: 4px; + width: 6px; + height: 6px; + border-radius: 50%; + background: #fff; } diff --git a/html/admin/banpanel.css b/html/admin/banpanel.css index 8cdfb4233e3..8ad4f648e7a 100644 --- a/html/admin/banpanel.css +++ b/html/admin/banpanel.css @@ -1,78 +1,78 @@ .middle { - width: 80px; + width: 80px; } .right { - width: 150px; + width: 150px; } .reason { - resize: none; - min-height: 40px; - width: 340px; + resize: none; + min-height: 40px; + width: 340px; } .rolegroup { - padding: 3px; - width: 430px; - border: none; - text-align: center; - outline: none; - display: inline-block; + padding: 3px; + width: 430px; + border: none; + text-align: center; + outline: none; + display: inline-block; } .long { - width: 860px; + width: 860px; } .content { - text-align: center; + text-align: center; } .command { - background-color: #948f02; + background-color: #948f02; } .security { - background-color: #a30000; + background-color: #a30000; } .engineering { - background-color: #fb5613; + background-color: #fb5613; } .medical { - background-color: #337296; + background-color: #337296; } .science { - background-color: #993399; + background-color: #993399; } .supply { - background-color: #a8732b; + background-color: #a8732b; } .silicon { - background-color: #ff00ff; + background-color: #ff00ff; } .abstract { - background-color: #708090; + background-color: #708090; } .service { - background-color: #6eaa2c; + background-color: #6eaa2c; } .ghostandotherroles { - background-color: #5c00e6; + background-color: #5c00e6; } .antagonistpositions { - background-color: #6d3f40; + background-color: #6d3f40; } .undefineddepartment { - background-color: #111cf7; + background-color: #111cf7; } diff --git a/html/admin/banpanel.js b/html/admin/banpanel.js index e481cd2fc2a..90393645fde 100644 --- a/html/admin/banpanel.js +++ b/html/admin/banpanel.js @@ -1,19 +1,20 @@ function toggle_other_checkboxes(source, copycats_str, our_index_str) { - const copycats = parseInt(copycats_str); - const our_index = parseInt(our_index_str); - for (var i = 1; i <= copycats; i++) { - if(i === our_index) { - continue; - } - document.getElementById(source.id.slice(0, -1) + i).checked = source.checked; + const copycats = parseInt(copycats_str); + const our_index = parseInt(our_index_str); + for (var i = 1; i <= copycats; i++) { + if (i === our_index) { + continue; } + document.getElementById(source.id.slice(0, -1) + i).checked = + source.checked; + } } function header_click_all_checkboxes(source) { - var checkboxes = document.getElementsByClassName(source.name); - for(var i = 0, n = checkboxes.length; i < n; i++) { - if(checkboxes[i].checked != source.checked && checkboxes[i] != source) { - checkboxes[i].click(); - } - } + var checkboxes = document.getElementsByClassName(source.name); + for (var i = 0, n = checkboxes.length; i < n; i++) { + if (checkboxes[i].checked != source.checked && checkboxes[i] != source) { + checkboxes[i].click(); + } + } } diff --git a/html/admin/panels.css b/html/admin/panels.css index 22373ee0ca4..3d8d385527f 100644 --- a/html/admin/panels.css +++ b/html/admin/panels.css @@ -1,10 +1,45 @@ -body {padding:0px;margin:0px;} -#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;} -#main {position:relative;top:10px;left:3%;width:96%;text-align:center;z-index:0;} -#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";} -tr.norm {background-color:#f4f4f4;} -tr.title {background-color:#ccc;} -tr.alt {background-color:#e7e7e7;} -.small {font-size:80%;} -a {text-decoration:none;} -a:hover {color:#d3d;} +body { + padding: 0px; + margin: 0px; +} +#top { + position: fixed; + top: 5px; + left: 10%; + width: 80%; + text-align: center; + background-color: #fff; + border: 2px solid #ccc; +} +#main { + position: relative; + top: 10px; + left: 3%; + width: 96%; + text-align: center; + z-index: 0; +} +#searchable { + table-layout: fixed; + width: 100%; + text-align: center; + background-color: "#f4f4f4"; +} +tr.norm { + background-color: #f4f4f4; +} +tr.title { + background-color: #ccc; +} +tr.alt { + background-color: #e7e7e7; +} +.small { + font-size: 80%; +} +a { + text-decoration: none; +} +a:hover { + color: #d3d; +} diff --git a/html/admin/search.js b/html/admin/search.js index 639a3729fe3..b51c3b20dcf 100644 --- a/html/admin/search.js +++ b/html/admin/search.js @@ -1,33 +1,34 @@ -function selectTextField(){ - var filter_text = document.getElementById('filter'); - filter_text.focus(); - filter_text.select(); +function selectTextField() { + var filter_text = document.getElementById("filter"); + filter_text.focus(); + filter_text.select(); } -function updateSearch(){ - var input_form = document.getElementById('filter'); - var filter = input_form.value.toLowerCase(); - input_form.value = filter; - var table = document.getElementById('searchable'); - var alt_style = 'norm'; - for(var i = 0; i < table.rows.length; i++){ - try{ - var row = table.rows[i]; - if(row.className == 'title') continue; - var found=0; - for(var j = 0; j < row.cells.length; j++){ - var cell = row.cells[j]; - if(cell.innerText.toLowerCase().indexOf(filter) != -1){ - found=1; - break; - } - } - if(found == 0) row.style.display='none'; - else{ - row.style.display='table-row'; /* DON'T make tables with block property */ - row.className = alt_style; - if(alt_style == 'alt') alt_style = 'norm'; - else alt_style = 'alt'; - } - }catch(err) { } - } +function updateSearch() { + var input_form = document.getElementById("filter"); + var filter = input_form.value.toLowerCase(); + input_form.value = filter; + var table = document.getElementById("searchable"); + var alt_style = "norm"; + for (var i = 0; i < table.rows.length; i++) { + try { + var row = table.rows[i]; + if (row.className == "title") continue; + var found = 0; + for (var j = 0; j < row.cells.length; j++) { + var cell = row.cells[j]; + if (cell.innerText.toLowerCase().indexOf(filter) != -1) { + found = 1; + break; + } + } + if (found == 0) row.style.display = "none"; + else { + row.style.display = + "table-row"; /* DON'T make tables with block property */ + row.className = alt_style; + if (alt_style == "alt") alt_style = "norm"; + else alt_style = "alt"; + } + } catch (err) {} + } } diff --git a/html/admin/unbanpanel.css b/html/admin/unbanpanel.css index cf4aae20c99..71488f4ecbb 100644 --- a/html/admin/unbanpanel.css +++ b/html/admin/unbanpanel.css @@ -1,61 +1,61 @@ body { - margin: 0; + margin: 0; } .searchbar { - overflow: hidden; - background-color: #272727; - position: fixed; - top: 0; - width: 100%; - font-weight: bold; - text-align: center; - line-height: 30px; - z-index: 1; + overflow: hidden; + background-color: #272727; + position: fixed; + top: 0; + width: 100%; + font-weight: bold; + text-align: center; + line-height: 30px; + z-index: 1; } .main { - padding: 16px; - margin-top: 20px; - text-align: center; + padding: 16px; + margin-top: 20px; + text-align: center; } .banbox { - position: relative; - width: 90%; - display: table; - flex-direction: column; - border: 1px solid #161616; - margin-right: auto; - margin-left: auto; - margin-bottom: 10px; - border-radius: 3px; + position: relative; + width: 90%; + display: table; + flex-direction: column; + border: 1px solid #161616; + margin-right: auto; + margin-left: auto; + margin-bottom: 10px; + border-radius: 3px; } .header { - width: 100%; - background-color:rgba(0,0,0,0.3); + width: 100%; + background-color: rgba(0, 0, 0, 0.3); } .container { - display: table; - width: 100%; + display: table; + width: 100%; } .reason { - display: table-cell; - width: 90%; + display: table-cell; + width: 90%; } .edit { - display: table-cell; - width: 10%; + display: table-cell; + width: 10%; } .banned { - background-color:#ff5555; + background-color: #ff5555; } .unbanned { - background-color:#00b75c; + background-color: #00b75c; } diff --git a/html/admin/view_variables.css b/html/admin/view_variables.css index b646e4ced16..b318b01e501 100644 --- a/html/admin/view_variables.css +++ b/html/admin/view_variables.css @@ -1,37 +1,39 @@ body { - font-family: Verdana, sans-serif; - font-size: 9pt; + font-family: Verdana, sans-serif; + font-size: 9pt; } .value { - font-family: "Courier New", monospace; - font-size: 8pt; - display: inline-block; + font-family: "Courier New", monospace; + font-size: 8pt; + display: inline-block; } table.matrix { - border-collapse: collapse; border-spacing: 0; - font-size: 7pt; + border-collapse: collapse; + border-spacing: 0; + font-size: 7pt; } -.matrix td{ - text-align: center; - padding: 0 1ex 0ex 1ex; +.matrix td { + text-align: center; + padding: 0 1ex 0ex 1ex; } table.matrixbrak { - border-collapse: collapse; border-spacing: 0; + border-collapse: collapse; + border-spacing: 0; } table.matrixbrak td.lbrak { - width: 0.8ex; - font-size: 50%; - border-top: solid 0.25ex black; - border-bottom: solid 0.25ex black; - border-left: solid 0.5ex black; - border-right: none; + width: 0.8ex; + font-size: 50%; + border-top: solid 0.25ex black; + border-bottom: solid 0.25ex black; + border-left: solid 0.5ex black; + border-right: none; } table.matrixbrak td.rbrak { - width: 0.8ex; - font-size: 50%; - border-top: solid 0.25ex black; - border-bottom: solid 0.25ex black; - border-right: solid 0.5ex black; - border-left: none; + width: 0.8ex; + font-size: 50%; + border-top: solid 0.25ex black; + border-bottom: solid 0.25ex black; + border-right: solid 0.5ex black; + border-left: none; } diff --git a/html/browser/common.css b/html/browser/common.css index 1c52253d6f0..ff18c4aa947 100644 --- a/html/browser/common.css +++ b/html/browser/common.css @@ -1,310 +1,288 @@ -body -{ - padding: 0; - margin: 0; - background-color: #272727; - font-size: 12px; - color: #ffffff; - line-height: 170%; +body { + padding: 0; + margin: 0; + background-color: #272727; + font-size: 12px; + color: #ffffff; + line-height: 170%; } -hr -{ - background-color: #40628a; - height: 1px; +hr { + background-color: #40628a; + height: 1px; } -a, button, a:link, a:visited, a:active, .linkOn, .linkOff -{ - color: #ffffff; - text-decoration: none; - background: #40628a; - border: 1px solid #161616; - padding: 1px 4px 1px 4px; - margin: 0 2px 0 0; - cursor:default; +a, +button, +a:link, +a:visited, +a:active, +.linkOn, +.linkOff { + color: #ffffff; + text-decoration: none; + background: #40628a; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor: default; } -a:hover -{ - color: #40628a; - background: #ffffff; +a:hover { + color: #40628a; + background: #ffffff; } -a.white, a.white:link, a.white:visited, a.white:active -{ - color: #40628a; - text-decoration: none; - background: #ffffff; - border: 1px solid #161616; - padding: 1px 4px 1px 4px; - margin: 0 2px 0 0; - cursor:default; +a.white, +a.white:link, +a.white:visited, +a.white:active { + color: #40628a; + text-decoration: none; + background: #ffffff; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor: default; } -a.white:hover -{ - color: #ffffff; - background: #40628a; +a.white:hover { + color: #ffffff; + background: #40628a; } -.linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover -{ - color: #ffffff; - background: #2f943c; - border-color: #24722e; +.linkOn, +a.linkOn:link, +a.linkOn:visited, +a.linkOn:active, +a.linkOn:hover { + color: #ffffff; + background: #2f943c; + border-color: #24722e; } -.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover -{ - color: #ffffff; - background: #999999; - border-color: #666666; +.linkOff, +a.linkOff:link, +a.linkOff:visited, +a.linkOff:active, +a.linkOff:hover { + color: #ffffff; + background: #999999; + border-color: #666666; } -a.icon, .linkOn.icon, .linkOff.icon -{ - position: relative; - padding: 1px 4px 2px 20px; +a.icon, +.linkOn.icon, +.linkOff.icon { + position: relative; + padding: 1px 4px 2px 20px; } -a.icon img, .linkOn.icon img -{ - position: absolute; - top: 0; - left: 0; - width: 18px; - height: 18px; +a.icon img, +.linkOn.icon img { + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; } -ul -{ - padding: 4px 0 0 10px; - margin: 0; - list-style-type: none; +ul { + padding: 4px 0 0 10px; + margin: 0; + list-style-type: none; } -li -{ - padding: 0 0 2px 0; +li { + padding: 0 0 2px 0; } -img, a img -{ - border-style:none; +img, +a img { + border-style: none; } -h1, h2, h3, h4, h5, h6 -{ - margin: 0; - padding: 16px 0 8px 0; - color: #517087; +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 16px 0 8px 0; + color: #517087; } -h1 -{ - font-size: 15px; +h1 { + font-size: 15px; } -h2 -{ - font-size: 14px; +h2 { + font-size: 14px; } -h3 -{ - font-size: 13px; +h3 { + font-size: 13px; } -h4 -{ - font-size: 12px; +h4 { + font-size: 12px; } -.uiWrapper -{ - - width: 100%; - height: 100%; +.uiWrapper { + width: 100%; + height: 100%; } -.uiTitle -{ - clear: both; - padding: 6px 8px 6px 8px; - border-bottom: 2px solid #161616; - background: #383838; - color: #98B0C3; - font-size: 16px; +.uiTitle { + clear: both; + padding: 6px 8px 6px 8px; + border-bottom: 2px solid #161616; + background: #383838; + color: #98b0c3; + font-size: 16px; } -.uiTitle.icon -{ - padding: 6px 8px 6px 42px; - background-position: 2px 50%; - background-repeat: no-repeat; +.uiTitle.icon { + padding: 6px 8px 6px 42px; + background-position: 2px 50%; + background-repeat: no-repeat; } -.uiContent -{ - clear: both; - padding: 8px; - font-family: Verdana, Geneva, sans-serif; +.uiContent { + clear: both; + padding: 8px; + font-family: Verdana, Geneva, sans-serif; } -.good -{ - color: #00ff00; +.good { + color: #00ff00; } -.average -{ - color: #d09000; +.average { + color: #d09000; } -.bad -{ - color: #ff0000; +.bad { + color: #ff0000; } -.highlight -{ - color: #8BA5C4; +.highlight { + color: #8ba5c4; } -.dark -{ - color: #272727; +.dark { + color: #272727; } -.notice -{ - position: relative; - background: #E9C183; - color: #15345A; - font-size: 10px; - font-style: italic; - padding: 2px 4px 0 4px; - margin: 4px; +.notice { + position: relative; + background: #e9c183; + color: #15345a; + font-size: 10px; + font-style: italic; + padding: 2px 4px 0 4px; + margin: 4px; } -.notice.icon -{ - padding: 2px 4px 0 20px; +.notice.icon { + padding: 2px 4px 0 20px; } -.notice img -{ - position: absolute; - top: 0; - left: 0; - width: 16px; - height: 16px; +.notice img { + position: absolute; + top: 0; + left: 0; + width: 16px; + height: 16px; } -div.notice -{ - clear: both; +div.notice { + clear: both; } -.statusDisplay -{ - background: #000000; - color: #ffffff; - border: 1px solid #40628a; - padding: 4px; - margin: 3px 0; +.statusDisplay { + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 4px; + margin: 3px 0; } -.statusLabel -{ - width: 138px; - float: left; - overflow: hidden; - color: #98B0C3; +.statusLabel { + width: 138px; + float: left; + overflow: hidden; + color: #98b0c3; } -.statusValue -{ - float: left; +.statusValue { + float: left; } -.block -{ - padding: 8px; - margin: 10px 4px 4px 4px; - border: 1px solid #40628a; - background-color: #202020; +.block { + padding: 8px; + margin: 10px 4px 4px 4px; + border: 1px solid #40628a; + background-color: #202020; } -.block h3 -{ - padding: 0; +.block h3 { + padding: 0; } -.progressBar -{ - width: 240px; - height: 14px; - border: 1px solid #666666; - float: left; - margin: 0 5px; - overflow: hidden; +.progressBar { + width: 240px; + height: 14px; + border: 1px solid #666666; + float: left; + margin: 0 5px; + overflow: hidden; } -.progressFill -{ - width: 100%; - height: 100%; - background: #40628a; - overflow: hidden; +.progressFill { + width: 100%; + height: 100%; + background: #40628a; + overflow: hidden; } -.progressFill.good -{ - color: #ffffff; - background: #00ff00; +.progressFill.good { + color: #ffffff; + background: #00ff00; } -.progressFill.average -{ - color: #ffffff; - background: #d09000; +.progressFill.average { + color: #ffffff; + background: #d09000; } -.progressFill.bad -{ - color: #ffffff; - background: #ff0000; +.progressFill.bad { + color: #ffffff; + background: #ff0000; } -.progressFill.highlight -{ - color: #ffffff; - background: #8BA5C4; +.progressFill.highlight { + color: #ffffff; + background: #8ba5c4; } -.clearBoth -{ - clear: both; +.clearBoth { + clear: both; } -.clearLeft -{ - clear: left; +.clearLeft { + clear: left; } -.clearRight -{ - clear: right; +.clearRight { + clear: right; } -.line -{ - width: 100%; - clear: both; +.line { + width: 100%; + clear: both; } - .switch { position: relative; display: inline-block; @@ -312,7 +290,9 @@ div.notice height: 26px; } -.switch input {display:none;} +.switch input { + display: none; +} .slider { position: absolute; @@ -322,7 +302,7 @@ div.notice right: 0; bottom: 0; background-color: #383838; - transition: .4s; + transition: 0.4s; } .slider:before { @@ -332,8 +312,8 @@ div.notice width: 18px; left: 4px; bottom: 4px; - background-color: #98B0C3; - transition: .4s; + background-color: #98b0c3; + transition: 0.4s; } .slider.red:before { @@ -358,7 +338,7 @@ input:checked + .slider.locked { } input:focus + .slider { - box-shadow: 0 0 1px #2196F3; + box-shadow: 0 0 1px #2196f3; } input:focus + .slider.red { @@ -381,7 +361,7 @@ input:checked + .slider:before { } ul.sparse { - padding-bottom:20px; + padding-bottom: 20px; } .sparse li { @@ -397,31 +377,30 @@ ul.sparse { } .severity { - margin:0px; - padding: 1px 8px 1px 8px; - border-radius: 25px; - border: 1px solid #161616; - background: #40628a; - color: #ffffff; + margin: 0px; + padding: 1px 8px 1px 8px; + border-radius: 25px; + border: 1px solid #161616; + background: #40628a; + color: #ffffff; } .severity img { - display: inline-block; - vertical-align: middle; + display: inline-block; + vertical-align: middle; } .code { - padding: 6px 8px; - border: 1px solid #161616; - background: #383838; - color: #FFFFFF; - font-size: 12px; - display: block; - margin: 4px 0; - font-family: 'Courier New', Courier, monospace; + padding: 6px 8px; + border: 1px solid #161616; + background: #383838; + color: #ffffff; + font-size: 12px; + display: block; + margin: 4px 0; + font-family: "Courier New", Courier, monospace; } .user-select { - user-select: all; + user-select: all; } - diff --git a/html/browser/roundend.css b/html/browser/roundend.css index 1cb001c06c4..034b3c74c33 100644 --- a/html/browser/roundend.css +++ b/html/browser/roundend.css @@ -1,102 +1,105 @@ .greentext { - color: #90ee90; - font-weight: bold; + color: #90ee90; + font-weight: bold; } .greentext_alt { - color: green; + color: green; } .redtext { - color: #ef2f3c; - font-weight: bold; + color: #ef2f3c; + font-weight: bold; } .bluetext { - color: #517fff; - font-weight: bold; + color: #517fff; + font-weight: bold; } .neutraltext { - font-weight: bold; /* If you feel these should have some color feel free to change */ + font-weight: bold; /* If you feel these should have some color feel free to change */ } .marooned { - color: rgb(109, 109, 255); font-weight: bold; + color: rgb(109, 109, 255); + font-weight: bold; } .service { - color: #6eaa2c; font-weight: bold; + color: #6eaa2c; + font-weight: bold; } .header { - font-size: 24px; font-weight: bold; + font-size: 24px; + font-weight: bold; } .big { - font-size: 24px; + font-size: 24px; } .medaltext { - color: #add8e6; + color: #add8e6; } .codephrase { - color : #ef2f3c; + color: #ef2f3c; } .redborder { - border-bottom: 2px solid #ef2f3c; + border-bottom: 2px solid #ef2f3c; } .greenborder { - border-bottom: 2px solid #90ee90; + border-bottom: 2px solid #90ee90; } .clockborder { - border-bottom: 2px solid #B18B25; + border-bottom: 2px solid #b18b25; } .stationborder { - border-bottom: 2px solid #add8e6; + border-bottom: 2px solid #add8e6; } li { - margin-bottom: 0.2rem; + margin-bottom: 0.2rem; } .panel { - background-color: #313131; - padding: 10px; - border-radius: 10px; - margin-bottom: 5px; + background-color: #313131; + padding: 10px; + border-radius: 10px; + margin-bottom: 5px; } body { - background-color: #272727; - color: #efefef; + background-color: #272727; + color: #efefef; } .tooltip_container { - position: relative; - font-size: 24px; + position: relative; + font-size: 24px; } .tooltip_hover { - visibility: hidden; - position: absolute; - background-color: black; - z-index: 1; - width: 220px; - font-size: 14px; - border-width: 4px; - border-style: solid; - border-color: #272727; - background: #363636; - color: white; - top: 100%; - left: 30px; + visibility: hidden; + position: absolute; + background-color: black; + z-index: 1; + width: 220px; + font-size: 14px; + border-width: 4px; + border-style: solid; + border-color: #272727; + background: #363636; + color: white; + top: 100%; + left: 30px; } .tooltip_container:hover .tooltip_hover { - visibility: visible; + visibility: visible; } diff --git a/html/create_object.html b/html/create_object.html index e5003c9b636..c139855a009 100644 --- a/html/create_object.html +++ b/html/create_object.html @@ -1,99 +1,121 @@ + + Create Object + + - h1, h2, h3, h4, h5, h6 - { - color: #00f; - font-family: Georgia, Arial, sans-serif; - } - img { - border: 0px; - } - p.lic { - font-size: 6pt; - } - - + +
+ + /* hreftokenfield */ Type + +
+ Offset: + - - - - /* hreftokenfield */ + A R +
- Type
- Offset: - - A - R
- - Number: - Dir: - Name:
- Where: - -

- -
- -
- - - + Number: + + Dir: + Name: +
+ Where: + +

+ +
+ + + diff --git a/html/statbrowser.css b/html/statbrowser.css index f7a746bf6dd..3b26cac84f5 100644 --- a/html/statbrowser.css +++ b/html/statbrowser.css @@ -1,263 +1,262 @@ .light:root { - --scrollbar-base: #f2f2f2; - --scrollbar-thumb: #a7a7a7; + --scrollbar-base: #f2f2f2; + --scrollbar-thumb: #a7a7a7; } html, body { - scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-base); + scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-base); } body { - font-family: Verdana, Geneva, Tahoma, sans-serif; - font-size: 12px; - margin: 0 !important; - padding: 0 !important; - overflow: hidden; + font-family: Verdana, Geneva, Tahoma, sans-serif; + font-size: 12px; + margin: 0 !important; + padding: 0 !important; + overflow: hidden; } a { - color: #003399; - text-decoration: none; + color: #003399; + text-decoration: none; } a:hover { - color: #007fff; + color: #007fff; } h3 { - margin: 0 -0.5em 0.5em; - padding: 1em 0.66em 0.5em; - border-bottom: 0.1667em solid; + margin: 0 -0.5em 0.5em; + padding: 1em 0.66em 0.5em; + border-bottom: 0.1667em solid; } - img { - -ms-interpolation-mode: nearest-neighbor; - image-rendering: pixelated; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; } .stat-container { - display: flex; - flex-direction: column; - height: 100vh; + display: flex; + flex-direction: column; + height: 100vh; } #menu { - display: flex; - overflow-x: auto; - overflow-y: hidden; - padding: 0.25em 0.25em 0; - background-color: #ffffff; + display: flex; + overflow-x: auto; + overflow-y: hidden; + padding: 0.25em 0.25em 0; + background-color: #ffffff; } .menu-wrap { - flex-wrap: wrap-reverse; + flex-wrap: wrap-reverse; } #menu.tabs-classic { - padding: 0.15em; + padding: 0.15em; } #menu.tabs-classic .button { - min-width: 2em; - margin: 0.1em; - padding: 0.25em 0.4em; - border: 0; - border-radius: 0.25em; + min-width: 2em; + margin: 0.1em; + padding: 0.25em 0.4em; + border: 0; + border-radius: 0.25em; } #menu.tabs-classic .button.active { - background-color: #0668b8; - color: white; + background-color: #0668b8; + color: white; } .button { - display: inline-table; - cursor: pointer; - user-select: none; - -ms-user-select: none; /* Remove after Byond 516 */ - text-align: center; - font-size: 1em; - min-width: 2.9em; - padding: 0.5em 0.5em 0.4em; - background-color: transparent; - color: rgba(0, 0, 0, 0.5); - border: 0; - border-bottom: 0.1667em solid transparent; - border-radius: 0.25em 0.25em 0 0; + display: inline-table; + cursor: pointer; + user-select: none; + -ms-user-select: none; /* Remove after Byond 516 */ + text-align: center; + font-size: 1em; + min-width: 2.9em; + padding: 0.5em 0.5em 0.4em; + background-color: transparent; + color: rgba(0, 0, 0, 0.5); + border: 0; + border-bottom: 0.1667em solid transparent; + border-radius: 0.25em 0.25em 0 0; } .button:hover { - background-color: #ececec; + background-color: #ececec; } .button.active { - cursor: default; - background-color: #dfdfdf; - color: black; - border-bottom-color: #000000; + cursor: default; + background-color: #dfdfdf; + color: black; + border-bottom-color: #000000; } #under-menu { - height: 0.5em; - background-color: #eeeeee; + height: 0.5em; + background-color: #eeeeee; } #under-content { - height: calc(0.5em - 4px); - background-color: #eeeeee; + height: calc(0.5em - 4px); + background-color: #eeeeee; } #statcontent { - flex: 1; - padding: 0.75em 0.5em; - overflow-y: auto; - overflow-x: hidden; + flex: 1; + padding: 0.75em 0.5em; + overflow-y: auto; + overflow-x: hidden; } .grid-container { - margin: -0.25em; + margin: -0.25em; } .grid-item { - display: inline-flex; - position: relative; - user-select: none; - -ms-user-select: none; /* Remove after Byond 516 */ - width: 100%; - max-height: 1.85em; - text-decoration: none; - background-color: transparent; - color: black; + display: inline-flex; + position: relative; + user-select: none; + -ms-user-select: none; /* Remove after Byond 516 */ + width: 100%; + max-height: 1.85em; + text-decoration: none; + background-color: transparent; + color: black; } .grid-item:hover, .grid-item:active { - color: #003399; - z-index: 1; + color: #003399; + z-index: 1; } .grid-item-text { - display: inline-block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - pointer-events: none; - width: 100%; - padding: 0.33em 0.5em; - border-radius: 0.25em; + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + pointer-events: none; + width: 100%; + padding: 0.33em 0.5em; + border-radius: 0.25em; } .grid-item:hover .grid-item-text { - height: 100%; - overflow: visible; - white-space: normal; - background-color: #ececec; + height: 100%; + overflow: visible; + white-space: normal; + background-color: #ececec; } -.grid-item:active .grid-item-text { - background-color: #dfdfdf; +.grid-item:active .grid-item-text { + background-color: #dfdfdf; } @media only screen and (min-width: 300px) { - .grid-item { - width: 50%; - } + .grid-item { + width: 50%; + } } @media only screen and (min-width: 430px) { - .grid-item { - width: 33%; - } + .grid-item { + width: 33%; + } } @media only screen and (min-width: 560px) { - .grid-item { - width: 25%; - } + .grid-item { + width: 25%; + } } @media only screen and (min-width: 770px) { - .grid-item { - width: 20%; - } + .grid-item { + width: 20%; + } } .status-info { - margin: 0 0.33em 0.25em; + margin: 0 0.33em 0.25em; } .interview_panel_stats, .interview_panel_controls { - margin-bottom: 1em; + margin-bottom: 1em; } /** * MARK: Dark theme colors */ .dark:root { - --scrollbar-base: #151515; - --scrollbar-thumb: #363636; + --scrollbar-base: #151515; + --scrollbar-thumb: #363636; } body.dark { - background-color: #151515; - color: #b2c4dd; - scrollbar-base-color: #1c1c1c; - scrollbar-face-color: #3b3b3b; - scrollbar-3dlight-color: #252525; - scrollbar-highlight-color: #252525; - scrollbar-track-color: #1c1c1c; - scrollbar-arrow-color: #929292; - scrollbar-shadow-color: #3b3b3b; + background-color: #151515; + color: #b2c4dd; + scrollbar-base-color: #1c1c1c; + scrollbar-face-color: #3b3b3b; + scrollbar-3dlight-color: #252525; + scrollbar-highlight-color: #252525; + scrollbar-track-color: #1c1c1c; + scrollbar-arrow-color: #929292; + scrollbar-shadow-color: #3b3b3b; } .dark a { - color: #6699ff; + color: #6699ff; } .dark a:hover, .dark .grid-item:hover, .dark .grid-item:active { - color: #80bfff; + color: #80bfff; } .dark #menu { - background-color: #151515; + background-color: #151515; } .dark #menu.tabs-classic .button.active { - background-color: #20b142; + background-color: #20b142; } .dark .button { - color: rgba(255, 255, 255, 0.5); + color: rgba(255, 255, 255, 0.5); } .dark .button:hover { - background-color: #252525; + background-color: #252525; } -.dark .button.active { - background-color: #313131; - color: #d4dfec; - border-bottom-color: #d4dfec; +.dark .button.active { + background-color: #313131; + color: #d4dfec; + border-bottom-color: #d4dfec; } .dark #under-menu, .dark #under-content { - background-color: #202020; + background-color: #202020; } -.dark .grid-item{ - color: #b2c4dd; +.dark .grid-item { + color: #b2c4dd; } .dark .grid-item:hover .grid-item-text { - background-color: #252525; + background-color: #252525; } .dark .grid-item:active .grid-item-text { - background-color: #313131; + background-color: #313131; } diff --git a/html/statbrowser.html b/html/statbrowser.html index d72557c7c30..9b186291250 100644 --- a/html/statbrowser.html +++ b/html/statbrowser.html @@ -1,6 +1,6 @@
- -
-
-
+ +
+
+
diff --git a/html/statbrowser.js b/html/statbrowser.js index 2e6a3b1b42e..306ac246c5f 100644 --- a/html/statbrowser.js +++ b/html/statbrowser.js @@ -1,17 +1,17 @@ // Polyfills and compatibility ------------------------------------------------ var decoder = decodeURIComponent || unescape; if (!Array.prototype.includes) { - Array.prototype.includes = function (thing) { - for (var i = 0; i < this.length; i++) { - if (this[i] == thing) return true; - } - return false; - } + Array.prototype.includes = function (thing) { + for (var i = 0; i < this.length; i++) { + if (this[i] == thing) return true; + } + return false; + }; } if (!String.prototype.trim) { - String.prototype.trim = function () { - return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); - }; + String.prototype.trim = function () { + return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); + }; } // Status panel implementation ------------------------------------------------ @@ -35,8 +35,8 @@ var turfcontents = []; var turfname = ""; var imageRetryDelay = 500; var imageRetryLimit = 50; -var menu = document.getElementById('menu'); -var statcontentdiv = document.getElementById('statcontent'); +var menu = document.getElementById("menu"); +var statcontentdiv = document.getElementById("statcontent"); var storedimages = []; var split_admin_tabs = false; @@ -44,1009 +44,1012 @@ var split_admin_tabs = false; // to ensure that when we relinquish our focus, we don't do it after the result of // a command has already taken focus for itself. function run_after_focus(callback) { - setTimeout(callback, 0); + setTimeout(callback, 0); } function createStatusTab(name) { - if (name.indexOf(".") != -1) { - var splitName = name.split("."); - if (split_admin_tabs && splitName[0] === "Admin") - name = splitName[1]; - else - name = splitName[0]; - } - if (document.getElementById(name) || name.trim() == "") { - return; - } - if (!verb_tabs.includes(name) && !permanent_tabs.includes(name)) { - return; - } - var button = document.createElement("DIV"); - button.onclick = function () { - tab_change(name); - this.blur(); - statcontentdiv.focus(); - }; - button.id = name; - button.textContent = name; - button.className = "button"; - //ORDERING ALPHABETICALLY - button.style.order = ({"Status": 1, "MC": 2})[name] || name.charCodeAt(0); - //END ORDERING - menu.appendChild(button); - SendTabToByond(name); + if (name.indexOf(".") != -1) { + var splitName = name.split("."); + if (split_admin_tabs && splitName[0] === "Admin") name = splitName[1]; + else name = splitName[0]; + } + if (document.getElementById(name) || name.trim() == "") { + return; + } + if (!verb_tabs.includes(name) && !permanent_tabs.includes(name)) { + return; + } + var button = document.createElement("DIV"); + button.onclick = function () { + tab_change(name); + this.blur(); + statcontentdiv.focus(); + }; + button.id = name; + button.textContent = name; + button.className = "button"; + //ORDERING ALPHABETICALLY + button.style.order = { Status: 1, MC: 2 }[name] || name.charCodeAt(0); + //END ORDERING + menu.appendChild(button); + SendTabToByond(name); } function removeStatusTab(name) { - if (!document.getElementById(name) || permanent_tabs.includes(name)) { - return; - } - for (var i = verb_tabs.length - 1; i >= 0; --i) { - if (verb_tabs[i] == name) { - verb_tabs.splice(i, 1); - } - } - menu.removeChild(document.getElementById(name)); - TakeTabFromByond(name); + if (!document.getElementById(name) || permanent_tabs.includes(name)) { + return; + } + for (var i = verb_tabs.length - 1; i >= 0; --i) { + if (verb_tabs[i] == name) { + verb_tabs.splice(i, 1); + } + } + menu.removeChild(document.getElementById(name)); + TakeTabFromByond(name); } function sortVerbs() { - verbs.sort(function (a, b) { - var selector = a[0] == b[0] ? 1 : 0; - if (a[selector].toUpperCase() < b[selector].toUpperCase()) { - return 1; - } - else if (a[selector].toUpperCase() > b[selector].toUpperCase()) { - return -1; - } - return 0; - }) + verbs.sort(function (a, b) { + var selector = a[0] == b[0] ? 1 : 0; + if (a[selector].toUpperCase() < b[selector].toUpperCase()) { + return 1; + } else if (a[selector].toUpperCase() > b[selector].toUpperCase()) { + return -1; + } + return 0; + }); } function addPermanentTab(name) { - if (!permanent_tabs.includes(name)) { - permanent_tabs.push(name); - } - createStatusTab(name); + if (!permanent_tabs.includes(name)) { + permanent_tabs.push(name); + } + createStatusTab(name); } function removePermanentTab(name) { - for (var i = permanent_tabs.length - 1; i >= 0; --i) { - if (permanent_tabs[i] == name) { - permanent_tabs.splice(i, 1); - } - } - removeStatusTab(name); + for (var i = permanent_tabs.length - 1; i >= 0; --i) { + if (permanent_tabs[i] == name) { + permanent_tabs.splice(i, 1); + } + } + removeStatusTab(name); } function checkStatusTab() { - for (var i = 0; i < menu.children.length; i++) { - if (!verb_tabs.includes(menu.children[i].id) && !permanent_tabs.includes(menu.children[i].id)) { - menu.removeChild(menu.children[i]); - } - } + for (var i = 0; i < menu.children.length; i++) { + if ( + !verb_tabs.includes(menu.children[i].id) && + !permanent_tabs.includes(menu.children[i].id) + ) { + menu.removeChild(menu.children[i]); + } + } } function remove_verb(v) { - var verb_to_remove = v; // to_remove = [verb:category, verb:name] - for (var i = verbs.length - 1; i >= 0; i--) { - var part_to_remove = verbs[i]; - if (part_to_remove[1] == verb_to_remove[1]) { - verbs.splice(i, 1) - } - } + var verb_to_remove = v; // to_remove = [verb:category, verb:name] + for (var i = verbs.length - 1; i >= 0; i--) { + var part_to_remove = verbs[i]; + if (part_to_remove[1] == verb_to_remove[1]) { + verbs.splice(i, 1); + } + } } function check_verbs() { - for (var v = verb_tabs.length - 1; v >= 0; v--) { - verbs_cat_check(verb_tabs[v]); - } + for (var v = verb_tabs.length - 1; v >= 0; v--) { + verbs_cat_check(verb_tabs[v]); + } } function verbs_cat_check(cat) { - var tabCat = cat; - if (cat.indexOf(".") != -1) { - var splitName = cat.split("."); - if (split_admin_tabs && splitName[0] === "Admin") - tabCat = splitName[1]; - else - tabCat = splitName[0]; - } - var verbs_in_cat = 0; - var verbcat = ""; - if (!verb_tabs.includes(tabCat)) { - removeStatusTab(tabCat); - return; - } - for (var v = 0; v < verbs.length; v++) { - var part = verbs[v]; - verbcat = part[0]; - if (verbcat.indexOf(".") != -1) { - var splitName = verbcat.split("."); - if (split_admin_tabs && splitName[0] === "Admin") - verbcat = splitName[1]; - else - verbcat = splitName[0]; - } - if (verbcat != tabCat || verbcat.trim() == "") { - continue; - } - else { - verbs_in_cat = 1; - break; // we only need one - } - } - if (verbs_in_cat != 1) { - removeStatusTab(tabCat); - if (current_tab == tabCat) - tab_change("Status"); - } + var tabCat = cat; + if (cat.indexOf(".") != -1) { + var splitName = cat.split("."); + if (split_admin_tabs && splitName[0] === "Admin") tabCat = splitName[1]; + else tabCat = splitName[0]; + } + var verbs_in_cat = 0; + var verbcat = ""; + if (!verb_tabs.includes(tabCat)) { + removeStatusTab(tabCat); + return; + } + for (var v = 0; v < verbs.length; v++) { + var part = verbs[v]; + verbcat = part[0]; + if (verbcat.indexOf(".") != -1) { + var splitName = verbcat.split("."); + if (split_admin_tabs && splitName[0] === "Admin") verbcat = splitName[1]; + else verbcat = splitName[0]; + } + if (verbcat != tabCat || verbcat.trim() == "") { + continue; + } else { + verbs_in_cat = 1; + break; // we only need one + } + } + if (verbs_in_cat != 1) { + removeStatusTab(tabCat); + if (current_tab == tabCat) tab_change("Status"); + } } function findVerbindex(name, verblist) { - for (var i = 0; i < verblist.length; i++) { - var part = verblist[i]; - if (part[1] == name) - return i; - } + for (var i = 0; i < verblist.length; i++) { + var part = verblist[i]; + if (part[1] == name) return i; + } } function wipe_verbs() { - verbs = [["", ""]]; - verb_tabs = []; - checkStatusTab(); // remove all empty verb tabs + verbs = [["", ""]]; + verb_tabs = []; + checkStatusTab(); // remove all empty verb tabs } function update_verbs() { - wipe_verbs(); - Byond.sendMessage("Update-Verbs"); + wipe_verbs(); + Byond.sendMessage("Update-Verbs"); } function SendTabsToByond() { - var tabstosend = []; - tabstosend = tabstosend.concat(permanent_tabs, verb_tabs); - for (var i = 0; i < tabstosend.length; i++) { - SendTabToByond(tabstosend[i]); - } + var tabstosend = []; + tabstosend = tabstosend.concat(permanent_tabs, verb_tabs); + for (var i = 0; i < tabstosend.length; i++) { + SendTabToByond(tabstosend[i]); + } } function SendTabToByond(tab) { - Byond.sendMessage("Send-Tabs", {tab: tab}); + Byond.sendMessage("Send-Tabs", { tab: tab }); } //Byond can't have this tab anymore since we're removing it function TakeTabFromByond(tab) { - Byond.sendMessage("Remove-Tabs", {tab: tab}); + Byond.sendMessage("Remove-Tabs", { tab: tab }); } function spell_cat_check(cat) { - var spells_in_cat = 0; - var spellcat = ""; - for (var s = 0; s < spells.length; s++) { - var spell = spells[s]; - spellcat = spell[0]; - if (spellcat == cat) { - spells_in_cat++; - } - } - if (spells_in_cat < 1) { - removeStatusTab(cat); - } + var spells_in_cat = 0; + var spellcat = ""; + for (var s = 0; s < spells.length; s++) { + var spell = spells[s]; + spellcat = spell[0]; + if (spellcat == cat) { + spells_in_cat++; + } + } + if (spells_in_cat < 1) { + removeStatusTab(cat); + } } function tab_change(tab) { - if (tab == current_tab) return; - if (document.getElementById(current_tab)) - document.getElementById(current_tab).className = "button"; // disable active on last button - current_tab = tab; - set_byond_tab(tab); - if (document.getElementById(tab)) - document.getElementById(tab).className = "button active"; // make current button active - var spell_tabs_thingy = (spell_tabs.includes(tab)); - var verb_tabs_thingy = (verb_tabs.includes(tab)); - if (tab == "Status") { - draw_status(); - } else if (tab == "MC") { - draw_mc(); - } else if (spell_tabs_thingy) { - draw_spells(tab); - } else if (verb_tabs_thingy) { - draw_verbs(tab); - } else if (tab == "Debug Stat Panel") { - draw_debug(); - } else if (tab == "Tickets") { - draw_tickets(); - draw_interviews(); - } else if (tab == "SDQL2") { - draw_sdql2(); - } else if (tab == turfname) { - draw_listedturf(); - } else { - statcontentdiv.textContext = "Loading..."; - } - Byond.winset(Byond.windowId, { - 'is-visible': true, - }); + if (tab == current_tab) return; + if (document.getElementById(current_tab)) + document.getElementById(current_tab).className = "button"; // disable active on last button + current_tab = tab; + set_byond_tab(tab); + if (document.getElementById(tab)) + document.getElementById(tab).className = "button active"; // make current button active + var spell_tabs_thingy = spell_tabs.includes(tab); + var verb_tabs_thingy = verb_tabs.includes(tab); + if (tab == "Status") { + draw_status(); + } else if (tab == "MC") { + draw_mc(); + } else if (spell_tabs_thingy) { + draw_spells(tab); + } else if (verb_tabs_thingy) { + draw_verbs(tab); + } else if (tab == "Debug Stat Panel") { + draw_debug(); + } else if (tab == "Tickets") { + draw_tickets(); + draw_interviews(); + } else if (tab == "SDQL2") { + draw_sdql2(); + } else if (tab == turfname) { + draw_listedturf(); + } else { + statcontentdiv.textContext = "Loading..."; + } + Byond.winset(Byond.windowId, { + "is-visible": true, + }); } function set_byond_tab(tab) { - Byond.sendMessage("Set-Tab", {tab: tab}); + Byond.sendMessage("Set-Tab", { tab: tab }); } function draw_debug() { - statcontentdiv.textContent = ""; - var wipeverbstabs = document.createElement("div"); - var link = document.createElement("a"); - link.onclick = function () { wipe_verbs() }; - link.textContent = "Wipe All Verbs"; - wipeverbstabs.appendChild(link); - document.getElementById("statcontent").appendChild(wipeverbstabs); - var wipeUpdateVerbsTabs = document.createElement("div"); - var updateLink = document.createElement("a"); - updateLink.onclick = function () { update_verbs() }; - updateLink.textContent = "Wipe and Update All Verbs"; - wipeUpdateVerbsTabs.appendChild(updateLink); - document.getElementById("statcontent").appendChild(wipeUpdateVerbsTabs); - var text = document.createElement("div"); - text.textContent = "Verb Tabs:"; - document.getElementById("statcontent").appendChild(text); - var table1 = document.createElement("table"); - for (var i = 0; i < verb_tabs.length; i++) { - var part = verb_tabs[i]; - // Hide subgroups except admin subgroups if they are split - if (verb_tabs[i].lastIndexOf(".") != -1) { - var splitName = verb_tabs[i].split("."); - if (split_admin_tabs && splitName[0] === "Admin") - part = splitName[1]; - else - continue; - } - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part; - var a = document.createElement("a"); - a.onclick = function (part) { - return function () { removeStatusTab(part) }; - }(part); - a.textContent = " Delete Tab " + part; - td1.appendChild(a); - tr.appendChild(td1); - table1.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table1); - var header2 = document.createElement("div"); - header2.textContent = "Verbs:"; - document.getElementById("statcontent").appendChild(header2); - var table2 = document.createElement("table"); - for (var v = 0; v < verbs.length; v++) { - var part2 = verbs[v]; - var trr = document.createElement("tr"); - var tdd1 = document.createElement("td"); - tdd1.textContent = part2[0]; - var tdd2 = document.createElement("td"); - tdd2.textContent = part2[1]; - trr.appendChild(tdd1); - trr.appendChild(tdd2); - table2.appendChild(trr); - } - document.getElementById("statcontent").appendChild(table2); - var text3 = document.createElement("div"); - text3.textContent = "Permanent Tabs:"; - document.getElementById("statcontent").appendChild(text3); - var table3 = document.createElement("table"); - for (var i = 0; i < permanent_tabs.length; i++) { - var part3 = permanent_tabs[i]; - var trrr = document.createElement("tr"); - var tddd1 = document.createElement("td"); - tddd1.textContent = part3; - trrr.appendChild(tddd1); - table3.appendChild(trrr); - } - document.getElementById("statcontent").appendChild(table3); - + statcontentdiv.textContent = ""; + var wipeverbstabs = document.createElement("div"); + var link = document.createElement("a"); + link.onclick = function () { + wipe_verbs(); + }; + link.textContent = "Wipe All Verbs"; + wipeverbstabs.appendChild(link); + document.getElementById("statcontent").appendChild(wipeverbstabs); + var wipeUpdateVerbsTabs = document.createElement("div"); + var updateLink = document.createElement("a"); + updateLink.onclick = function () { + update_verbs(); + }; + updateLink.textContent = "Wipe and Update All Verbs"; + wipeUpdateVerbsTabs.appendChild(updateLink); + document.getElementById("statcontent").appendChild(wipeUpdateVerbsTabs); + var text = document.createElement("div"); + text.textContent = "Verb Tabs:"; + document.getElementById("statcontent").appendChild(text); + var table1 = document.createElement("table"); + for (var i = 0; i < verb_tabs.length; i++) { + var part = verb_tabs[i]; + // Hide subgroups except admin subgroups if they are split + if (verb_tabs[i].lastIndexOf(".") != -1) { + var splitName = verb_tabs[i].split("."); + if (split_admin_tabs && splitName[0] === "Admin") part = splitName[1]; + else continue; + } + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part; + var a = document.createElement("a"); + a.onclick = (function (part) { + return function () { + removeStatusTab(part); + }; + })(part); + a.textContent = " Delete Tab " + part; + td1.appendChild(a); + tr.appendChild(td1); + table1.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table1); + var header2 = document.createElement("div"); + header2.textContent = "Verbs:"; + document.getElementById("statcontent").appendChild(header2); + var table2 = document.createElement("table"); + for (var v = 0; v < verbs.length; v++) { + var part2 = verbs[v]; + var trr = document.createElement("tr"); + var tdd1 = document.createElement("td"); + tdd1.textContent = part2[0]; + var tdd2 = document.createElement("td"); + tdd2.textContent = part2[1]; + trr.appendChild(tdd1); + trr.appendChild(tdd2); + table2.appendChild(trr); + } + document.getElementById("statcontent").appendChild(table2); + var text3 = document.createElement("div"); + text3.textContent = "Permanent Tabs:"; + document.getElementById("statcontent").appendChild(text3); + var table3 = document.createElement("table"); + for (var i = 0; i < permanent_tabs.length; i++) { + var part3 = permanent_tabs[i]; + var trrr = document.createElement("tr"); + var tddd1 = document.createElement("td"); + tddd1.textContent = part3; + trrr.appendChild(tddd1); + table3.appendChild(trrr); + } + document.getElementById("statcontent").appendChild(table3); } function draw_status() { - if (!document.getElementById("Status")) { - createStatusTab("Status"); - current_tab = "Status"; - } - statcontentdiv.textContent = ''; - var table = document.createElement("table"); - for (var i = 0; i < status_tab_parts.length; i++) { - var part = status_tab_parts[i]; - if(!Array.isArray(part)) { - var div = document.createElement("div"); - if (part.trim() == "") { - table.appendChild(document.createElement("br")); - } else { - div.textContent = part; - table.appendChild(div); - } - } else { - var div - if (part[0].trim() == "same_line") { - var a = document.createElement("a"); - a.href = "byond://?" + part[2]; - a.textContent = part[1]; - div.appendChild(a); - } else { - div = document.createElement("div"); - if (part[0].trim() == "") { - table.appendChild(document.createElement("br")); - } else { - div.textContent = part[0]; - if (part[2]) { - var a = document.createElement("a"); - a.href = "byond://?" + part[2]; - a.textContent = part[1]; - div.appendChild(a); - } - table.appendChild(div); - } - } - } - } - document.getElementById("statcontent").appendChild(table); - if (verb_tabs.length == 0 || !verbs) { - Byond.command("Fix-Stat-Panel"); - } + if (!document.getElementById("Status")) { + createStatusTab("Status"); + current_tab = "Status"; + } + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < status_tab_parts.length; i++) { + var part = status_tab_parts[i]; + if (!Array.isArray(part)) { + var div = document.createElement("div"); + if (part.trim() == "") { + table.appendChild(document.createElement("br")); + } else { + div.textContent = part; + table.appendChild(div); + } + } else { + var div; + if (part[0].trim() == "same_line") { + var a = document.createElement("a"); + a.href = "byond://?" + part[2]; + a.textContent = part[1]; + div.appendChild(a); + } else { + div = document.createElement("div"); + if (part[0].trim() == "") { + table.appendChild(document.createElement("br")); + } else { + div.textContent = part[0]; + if (part[2]) { + var a = document.createElement("a"); + a.href = "byond://?" + part[2]; + a.textContent = part[1]; + div.appendChild(a); + } + table.appendChild(div); + } + } + } + } + document.getElementById("statcontent").appendChild(table); + if (verb_tabs.length == 0 || !verbs) { + Byond.command("Fix-Stat-Panel"); + } } function draw_mc() { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - for (var i = 0; i < mc_tab_parts.length; i++) { - var part = mc_tab_parts[i]; - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part[0]; - var td2 = document.createElement("td"); - if (part[2]) { - var a = document.createElement("a"); - a.href = "byond://?_src_=vars;admin_token=" + href_token + ";Vars=" + part[2]; - a.textContent = part[1]; - td2.appendChild(a); - } else { - td2.textContent = part[1]; - } - tr.appendChild(td1); - tr.appendChild(td2); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < mc_tab_parts.length; i++) { + var part = mc_tab_parts[i]; + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part[0]; + var td2 = document.createElement("td"); + if (part[2]) { + var a = document.createElement("a"); + a.href = + "byond://?_src_=vars;admin_token=" + href_token + ";Vars=" + part[2]; + a.textContent = part[1]; + td2.appendChild(a); + } else { + td2.textContent = part[1]; + } + tr.appendChild(td1); + tr.appendChild(td2); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function remove_tickets() { - if (tickets) { - tickets = []; - removePermanentTab("Tickets"); - if (current_tab == "Tickets") - tab_change("Status"); - } - checkStatusTab(); + if (tickets) { + tickets = []; + removePermanentTab("Tickets"); + if (current_tab == "Tickets") tab_change("Status"); + } + checkStatusTab(); } function remove_sdql2() { - if (sdql2) { - sdql2 = []; - removePermanentTab("SDQL2"); - if (current_tab == "SDQL2") - tab_change("Status"); - } - checkStatusTab(); + if (sdql2) { + sdql2 = []; + removePermanentTab("SDQL2"); + if (current_tab == "SDQL2") tab_change("Status"); + } + checkStatusTab(); } function remove_interviews() { - if (tickets) { - tickets = []; - } - checkStatusTab(); + if (tickets) { + tickets = []; + } + checkStatusTab(); } function iconError(e) { - if(current_tab != turfname) { - return; - } - setTimeout(function () { - var node = e.target; - var current_attempts = Number(node.getAttribute("data-attempts")) || 0 - if (current_attempts > imageRetryLimit) { - return; - } - var src = node.src; - node.src = null; - node.src = src + '#' + current_attempts; - node.setAttribute("data-attempts", current_attempts + 1) - draw_listedturf(); - }, imageRetryDelay); + if (current_tab != turfname) { + return; + } + setTimeout(function () { + var node = e.target; + var current_attempts = Number(node.getAttribute("data-attempts")) || 0; + if (current_attempts > imageRetryLimit) { + return; + } + var src = node.src; + node.src = null; + node.src = src + "#" + current_attempts; + node.setAttribute("data-attempts", current_attempts + 1); + draw_listedturf(); + }, imageRetryDelay); } function draw_listedturf() { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - for (var i = 0; i < turfcontents.length; i++) { - var part = turfcontents[i]; - var clickfunc = function (part) { - // The outer function is used to close over a fresh "part" variable, - // rather than every onmousedown getting the "part" of the last entry. - return function (e) { - e.preventDefault(); - clickcatcher = "byond://?src=" + part[1]; - switch (e.button) { - case 1: - clickcatcher += ";statpanel_item_click=middle" - break; - case 2: - clickcatcher += ";statpanel_item_click=right" - break; - default: - clickcatcher += ";statpanel_item_click=left" - } - if (e.shiftKey) { - clickcatcher += ";statpanel_item_shiftclick=1"; - } - if (e.ctrlKey) { - clickcatcher += ";statpanel_item_ctrlclick=1"; - } - if (e.altKey) { - clickcatcher += ";statpanel_item_altclick=1"; - } - window.location.href = clickcatcher; - } - }(part); - if (storedimages[part[1]] == null && part[2]) { - var img = document.createElement("img"); - img.src = part[2]; - img.id = part[1]; - storedimages[part[1]] = part[2]; - img.onerror = iconError; - img.onmousedown = clickfunc; - table.appendChild(img); - } else { - var img = document.createElement("img"); - img.onerror = iconError; - img.onmousedown = clickfunc; - img.src = storedimages[part[1]]; - img.id = part[1]; - table.appendChild(img); - } - var b = document.createElement("div"); - var clickcatcher = ""; - b.className = "link"; - b.onmousedown = clickfunc; - b.textContent = part[0]; - table.appendChild(b); - table.appendChild(document.createElement("br")); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < turfcontents.length; i++) { + var part = turfcontents[i]; + var clickfunc = (function (part) { + // The outer function is used to close over a fresh "part" variable, + // rather than every onmousedown getting the "part" of the last entry. + return function (e) { + e.preventDefault(); + clickcatcher = "byond://?src=" + part[1]; + switch (e.button) { + case 1: + clickcatcher += ";statpanel_item_click=middle"; + break; + case 2: + clickcatcher += ";statpanel_item_click=right"; + break; + default: + clickcatcher += ";statpanel_item_click=left"; + } + if (e.shiftKey) { + clickcatcher += ";statpanel_item_shiftclick=1"; + } + if (e.ctrlKey) { + clickcatcher += ";statpanel_item_ctrlclick=1"; + } + if (e.altKey) { + clickcatcher += ";statpanel_item_altclick=1"; + } + window.location.href = clickcatcher; + }; + })(part); + if (storedimages[part[1]] == null && part[2]) { + var img = document.createElement("img"); + img.src = part[2]; + img.id = part[1]; + storedimages[part[1]] = part[2]; + img.onerror = iconError; + img.onmousedown = clickfunc; + table.appendChild(img); + } else { + var img = document.createElement("img"); + img.onerror = iconError; + img.onmousedown = clickfunc; + img.src = storedimages[part[1]]; + img.id = part[1]; + table.appendChild(img); + } + var b = document.createElement("div"); + var clickcatcher = ""; + b.className = "link"; + b.onmousedown = clickfunc; + b.textContent = part[0]; + table.appendChild(b); + table.appendChild(document.createElement("br")); + } + document.getElementById("statcontent").appendChild(table); } function remove_listedturf() { - removePermanentTab(turfname); - checkStatusTab(); - if (current_tab == turfname) { - tab_change("Status"); - } + removePermanentTab(turfname); + checkStatusTab(); + if (current_tab == turfname) { + tab_change("Status"); + } } function remove_mc() { - removePermanentTab("MC"); - if (current_tab == "MC") { - tab_change("Status"); - } -}; + removePermanentTab("MC"); + if (current_tab == "MC") { + tab_change("Status"); + } +} function draw_sdql2() { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - for (var i = 0; i < sdql2.length; i++) { - var part = sdql2[i]; - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part[0]; - var td2 = document.createElement("td"); - if (part[2]) { - var a = document.createElement("a"); - a.href = "byond://?src=" + part[2] + ";statpanel_item_click=left"; - a.textContent = part[1]; - td2.appendChild(a); - } else { - td2.textContent = part[1]; - } - tr.appendChild(td1); - tr.appendChild(td2); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < sdql2.length; i++) { + var part = sdql2[i]; + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part[0]; + var td2 = document.createElement("td"); + if (part[2]) { + var a = document.createElement("a"); + a.href = "byond://?src=" + part[2] + ";statpanel_item_click=left"; + a.textContent = part[1]; + td2.appendChild(a); + } else { + td2.textContent = part[1]; + } + tr.appendChild(td1); + tr.appendChild(td2); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function draw_tickets() { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - if (!tickets) { - return; - } - for (var i = 0; i < tickets.length; i++) { - var part = tickets[i]; - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part[0]; - var td2 = document.createElement("td"); - if (part[2]) { - var a = document.createElement("a"); - a.href = "byond://?_src_=holder;admin_token=" + href_token + ";ahelp=" + part[2] + ";ahelp_action=ticket;statpanel_item_click=left;action=ticket"; - a.textContent = part[1]; - td2.appendChild(a); - } else if (part[3]) { - var a = document.createElement("a"); - a.href = "byond://?src=" + part[3] + ";statpanel_item_click=left"; - a.textContent = part[1]; - td2.appendChild(a); - } else { - td2.textContent = part[1]; - } - tr.appendChild(td1); - tr.appendChild(td2); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + if (!tickets) { + return; + } + for (var i = 0; i < tickets.length; i++) { + var part = tickets[i]; + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part[0]; + var td2 = document.createElement("td"); + if (part[2]) { + var a = document.createElement("a"); + a.href = + "byond://?_src_=holder;admin_token=" + + href_token + + ";ahelp=" + + part[2] + + ";ahelp_action=ticket;statpanel_item_click=left;action=ticket"; + a.textContent = part[1]; + td2.appendChild(a); + } else if (part[3]) { + var a = document.createElement("a"); + a.href = "byond://?src=" + part[3] + ";statpanel_item_click=left"; + a.textContent = part[1]; + td2.appendChild(a); + } else { + td2.textContent = part[1]; + } + tr.appendChild(td1); + tr.appendChild(td2); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function draw_interviews() { - var body = document.createElement("div"); - var header = document.createElement("h3"); - header.textContent = "Interviews"; - body.appendChild(header); - var manDiv = document.createElement("div"); - manDiv.className = "interview_panel_controls" - var manLink = document.createElement("a"); - manLink.textContent = "Open Interview Manager Panel"; - manLink.href = "byond://?_src_=holder;admin_token=" + href_token + ";interview_man=1;statpanel_item_click=left"; - manDiv.appendChild(manLink); - body.appendChild(manDiv); + var body = document.createElement("div"); + var header = document.createElement("h3"); + header.textContent = "Interviews"; + body.appendChild(header); + var manDiv = document.createElement("div"); + manDiv.className = "interview_panel_controls"; + var manLink = document.createElement("a"); + manLink.textContent = "Open Interview Manager Panel"; + manLink.href = + "byond://?_src_=holder;admin_token=" + + href_token + + ";interview_man=1;statpanel_item_click=left"; + manDiv.appendChild(manLink); + body.appendChild(manDiv); - // List interview stats - var statsDiv = document.createElement("table"); - statsDiv.className = "interview_panel_stats"; - for (var key in interviewManager.status) { - var d = document.createElement("div"); - var tr = document.createElement("tr"); - var stat_name = document.createElement("td"); - var stat_text = document.createElement("td"); - stat_name.textContent = key; - stat_text.textContent = interviewManager.status[key]; - tr.appendChild(stat_name); - tr.appendChild(stat_text); - statsDiv.appendChild(tr); - } - body.appendChild(statsDiv); - document.getElementById("statcontent").appendChild(body); + // List interview stats + var statsDiv = document.createElement("table"); + statsDiv.className = "interview_panel_stats"; + for (var key in interviewManager.status) { + var d = document.createElement("div"); + var tr = document.createElement("tr"); + var stat_name = document.createElement("td"); + var stat_text = document.createElement("td"); + stat_name.textContent = key; + stat_text.textContent = interviewManager.status[key]; + tr.appendChild(stat_name); + tr.appendChild(stat_text); + statsDiv.appendChild(tr); + } + body.appendChild(statsDiv); + document.getElementById("statcontent").appendChild(body); - // List interviews if any are open - var table = document.createElement("table"); - table.className = "interview_panel_table"; - if (!interviewManager) { - return; - } - for (var i = 0; i < interviewManager.interviews.length; i++) { - var part = interviewManager.interviews[i]; - var tr = document.createElement("tr"); - var td = document.createElement("td"); - var a = document.createElement("a"); - a.textContent = part["status"]; - a.href = "byond://?_src_=holder;admin_token=" + href_token + ";interview=" + part["ref"] + ";statpanel_item_click=left"; - td.appendChild(a); - tr.appendChild(td); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + // List interviews if any are open + var table = document.createElement("table"); + table.className = "interview_panel_table"; + if (!interviewManager) { + return; + } + for (var i = 0; i < interviewManager.interviews.length; i++) { + var part = interviewManager.interviews[i]; + var tr = document.createElement("tr"); + var td = document.createElement("td"); + var a = document.createElement("a"); + a.textContent = part["status"]; + a.href = + "byond://?_src_=holder;admin_token=" + + href_token + + ";interview=" + + part["ref"] + + ";statpanel_item_click=left"; + td.appendChild(a); + tr.appendChild(td); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function draw_spells(cat) { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - for (var i = 0; i < spells.length; i++) { - var part = spells[i]; - if (part[0] != cat) continue; - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part[1]; - var td2 = document.createElement("td"); - if (part[3]) { - var a = document.createElement("a"); - a.href = "byond://?src=" + part[3] + ";statpanel_item_click=left"; - a.textContent = part[2]; - td2.appendChild(a); - } else { - td2.textContent = part[2]; - } - tr.appendChild(td1); - tr.appendChild(td2); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < spells.length; i++) { + var part = spells[i]; + if (part[0] != cat) continue; + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part[1]; + var td2 = document.createElement("td"); + if (part[3]) { + var a = document.createElement("a"); + a.href = "byond://?src=" + part[3] + ";statpanel_item_click=left"; + a.textContent = part[2]; + td2.appendChild(a); + } else { + td2.textContent = part[2]; + } + tr.appendChild(td1); + tr.appendChild(td2); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function make_verb_onclick(command) { - return function () { - run_after_focus(function () { - Byond.command(command); - }); - }; + return function () { + run_after_focus(function () { + Byond.command(command); + }); + }; } function draw_verbs(cat) { - statcontentdiv.textContent = ""; - var table = document.createElement("div"); - var additions = {}; // additional sub-categories to be rendered - table.className = "grid-container"; - sortVerbs(); - if (split_admin_tabs && cat.lastIndexOf(".") != -1) { - var splitName = cat.split("."); - if (splitName[0] === "Admin") - cat = splitName[1]; - } - verbs.reverse(); // sort verbs backwards before we draw - for (var i = 0; i < verbs.length; ++i) { - var part = verbs[i]; - var name = part[0]; - if (split_admin_tabs && name.lastIndexOf(".") != -1) { - var splitName = name.split("."); - if (splitName[0] === "Admin") - name = splitName[1]; - } - var command = part[1]; + statcontentdiv.textContent = ""; + var table = document.createElement("div"); + var additions = {}; // additional sub-categories to be rendered + table.className = "grid-container"; + sortVerbs(); + if (split_admin_tabs && cat.lastIndexOf(".") != -1) { + var splitName = cat.split("."); + if (splitName[0] === "Admin") cat = splitName[1]; + } + verbs.reverse(); // sort verbs backwards before we draw + for (var i = 0; i < verbs.length; ++i) { + var part = verbs[i]; + var name = part[0]; + if (split_admin_tabs && name.lastIndexOf(".") != -1) { + var splitName = name.split("."); + if (splitName[0] === "Admin") name = splitName[1]; + } + var command = part[1]; - if (command && name.lastIndexOf(cat, 0) != -1 && (name.length == cat.length || name.charAt(cat.length) == ".")) { - var subCat = name.lastIndexOf(".") != -1 ? name.split(".")[1] : null; - if (subCat && !additions[subCat]) { - var newTable = document.createElement("div"); - newTable.className = "grid-container"; - additions[subCat] = newTable; - } + if ( + command && + name.lastIndexOf(cat, 0) != -1 && + (name.length == cat.length || name.charAt(cat.length) == ".") + ) { + var subCat = name.lastIndexOf(".") != -1 ? name.split(".")[1] : null; + if (subCat && !additions[subCat]) { + var newTable = document.createElement("div"); + newTable.className = "grid-container"; + additions[subCat] = newTable; + } - var a = document.createElement("a"); - a.href = "#"; - a.onclick = make_verb_onclick(command.replace(/\s/g, "-")); - a.className = "grid-item"; - var t = document.createElement("span"); - t.textContent = command; - t.className = "grid-item-text"; - a.appendChild(t); - (subCat ? additions[subCat] : table).appendChild(a); - } - } + var a = document.createElement("a"); + a.href = "#"; + a.onclick = make_verb_onclick(command.replace(/\s/g, "-")); + a.className = "grid-item"; + var t = document.createElement("span"); + t.textContent = command; + t.className = "grid-item-text"; + a.appendChild(t); + (subCat ? additions[subCat] : table).appendChild(a); + } + } - // Append base table to view - var content = document.getElementById("statcontent"); - content.appendChild(table); + // Append base table to view + var content = document.getElementById("statcontent"); + content.appendChild(table); - // Append additional sub-categories if relevant - for (var cat in additions) { - if (additions.hasOwnProperty(cat)) { - // do addition here - var header = document.createElement("h3"); - header.textContent = cat; - content.appendChild(header); - content.appendChild(additions[cat]); - } - } + // Append additional sub-categories if relevant + for (var cat in additions) { + if (additions.hasOwnProperty(cat)) { + // do addition here + var header = document.createElement("h3"); + header.textContent = cat; + content.appendChild(header); + content.appendChild(additions[cat]); + } + } } function set_theme(which) { - if (which == "light") { - document.body.className = ""; - document.documentElement.className = 'light'; - set_style_sheet("browserOutput_white"); - } else if (which == "dark") { - document.body.className = "dark"; - document.documentElement.className = 'dark'; - set_style_sheet("browserOutput"); - } + if (which == "light") { + document.body.className = ""; + document.documentElement.className = "light"; + set_style_sheet("browserOutput_white"); + } else if (which == "dark") { + document.body.className = "dark"; + document.documentElement.className = "dark"; + set_style_sheet("browserOutput"); + } } function set_font_size(size) { - document.body.style.setProperty('font-size', size); + document.body.style.setProperty("font-size", size); } function set_tabs_style(style) { - if (style == "default") { - menu.classList.add('menu-wrap'); - menu.classList.remove('tabs-classic'); - } else if (style == "classic") { - menu.classList.add('menu-wrap'); - menu.classList.add('tabs-classic'); - } else if (style == "scrollable") { - menu.classList.remove('menu-wrap'); - menu.classList.remove('tabs-classic'); - } + if (style == "default") { + menu.classList.add("menu-wrap"); + menu.classList.remove("tabs-classic"); + } else if (style == "classic") { + menu.classList.add("menu-wrap"); + menu.classList.add("tabs-classic"); + } else if (style == "scrollable") { + menu.classList.remove("menu-wrap"); + menu.classList.remove("tabs-classic"); + } } function set_style_sheet(sheet) { - if (document.getElementById("goonStyle")) { - var currentSheet = document.getElementById("goonStyle"); - currentSheet.parentElement.removeChild(currentSheet); - } - var head = document.getElementsByTagName('head')[0]; - var sheetElement = document.createElement("link"); - sheetElement.id = "goonStyle"; - sheetElement.rel = "stylesheet"; - sheetElement.type = "text/css"; - sheetElement.href = sheet + ".css"; - sheetElement.media = 'all'; - head.appendChild(sheetElement); + if (document.getElementById("goonStyle")) { + var currentSheet = document.getElementById("goonStyle"); + currentSheet.parentElement.removeChild(currentSheet); + } + var head = document.getElementsByTagName("head")[0]; + var sheetElement = document.createElement("link"); + sheetElement.id = "goonStyle"; + sheetElement.rel = "stylesheet"; + sheetElement.type = "text/css"; + sheetElement.href = sheet + ".css"; + sheetElement.media = "all"; + head.appendChild(sheetElement); } function restoreFocus() { - run_after_focus(function () { - Byond.winset('map', { - focus: true, - }); - }); + run_after_focus(function () { + Byond.winset("map", { + focus: true, + }); + }); } function getCookie(cname) { - var name = cname + '='; - var ca = document.cookie.split(';'); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) == ' ') c = c.substring(1); - if (c.indexOf(name) === 0) { - return decoder(c.substring(name.length, c.length)); - } - } - return ''; + var name = cname + "="; + var ca = document.cookie.split(";"); + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == " ") c = c.substring(1); + if (c.indexOf(name) === 0) { + return decoder(c.substring(name.length, c.length)); + } + } + return ""; } function add_verb_list(payload) { - var to_add = payload; // list of a list with category and verb inside it - to_add.sort(); // sort what we're adding - for (var i = 0; i < to_add.length; i++) { - var part = to_add[i]; - if (!part[0]) - continue; - var category = part[0]; - if (category.indexOf(".") != -1) { - var splitName = category.split("."); - if (split_admin_tabs && splitName[0] === "Admin") - category = splitName[1]; - else - category = splitName[0]; - } - if (findVerbindex(part[1], verbs)) - continue; - if (verb_tabs.includes(category)) { - verbs.push(part); - if (current_tab == category) { - draw_verbs(category); // redraw if we added a verb to the tab we're currently in - } - } else if (category) { - verb_tabs.push(category); - verbs.push(part); - createStatusTab(category); - } - } -}; + var to_add = payload; // list of a list with category and verb inside it + to_add.sort(); // sort what we're adding + for (var i = 0; i < to_add.length; i++) { + var part = to_add[i]; + if (!part[0]) continue; + var category = part[0]; + if (category.indexOf(".") != -1) { + var splitName = category.split("."); + if (split_admin_tabs && splitName[0] === "Admin") category = splitName[1]; + else category = splitName[0]; + } + if (findVerbindex(part[1], verbs)) continue; + if (verb_tabs.includes(category)) { + verbs.push(part); + if (current_tab == category) { + draw_verbs(category); // redraw if we added a verb to the tab we're currently in + } + } else if (category) { + verb_tabs.push(category); + verbs.push(part); + createStatusTab(category); + } + } +} function init_spells() { - var cat = ""; - for (var i = 0; i < spell_tabs.length; i++) { - cat = spell_tabs[i]; - if (cat.length > 0) { - verb_tabs.push(cat); - createStatusTab(cat); - } - } + var cat = ""; + for (var i = 0; i < spell_tabs.length; i++) { + cat = spell_tabs[i]; + if (cat.length > 0) { + verb_tabs.push(cat); + createStatusTab(cat); + } + } } document.addEventListener("mouseup", restoreFocus); document.addEventListener("keyup", restoreFocus); if (!current_tab) { - addPermanentTab("Status"); - tab_change("Status"); + addPermanentTab("Status"); + tab_change("Status"); } window.onload = function () { - Byond.sendMessage("Update-Verbs"); + Byond.sendMessage("Update-Verbs"); }; -Byond.subscribeTo('update_spells', function (payload) { - spell_tabs = payload.spell_tabs; - var do_update = false; - if (spell_tabs.includes(current_tab)) { - do_update = true; - } - init_spells(); - if (payload.actions) { - spells = payload.actions; - if (do_update) { - draw_spells(current_tab); - } - } else { - remove_spells(); - } +Byond.subscribeTo("update_spells", function (payload) { + spell_tabs = payload.spell_tabs; + var do_update = false; + if (spell_tabs.includes(current_tab)) { + do_update = true; + } + init_spells(); + if (payload.actions) { + spells = payload.actions; + if (do_update) { + draw_spells(current_tab); + } + } else { + remove_spells(); + } }); -Byond.subscribeTo('remove_verb_list', function (v) { - var to_remove = v; - for (var i = 0; i < to_remove.length; i++) { - remove_verb(to_remove[i]); - } - check_verbs(); - sortVerbs(); - if (verb_tabs.includes(current_tab)) - draw_verbs(current_tab); +Byond.subscribeTo("remove_verb_list", function (v) { + var to_remove = v; + for (var i = 0; i < to_remove.length; i++) { + remove_verb(to_remove[i]); + } + check_verbs(); + sortVerbs(); + if (verb_tabs.includes(current_tab)) draw_verbs(current_tab); }); // passes a 2D list of (verbcategory, verbname) creates tabs and adds verbs to respective list // example (IC, Say) -Byond.subscribeTo('init_verbs', function (payload) { - wipe_verbs(); // remove all verb categories so we can replace them - checkStatusTab(); // remove all status tabs - verb_tabs = payload.panel_tabs; - verb_tabs.sort(); // sort it - var do_update = false; - var cat = ""; - for (var i = 0; i < verb_tabs.length; i++) { - cat = verb_tabs[i]; - createStatusTab(cat); // create a category if the verb doesn't exist yet - } - if (verb_tabs.includes(current_tab)) { - do_update = true; - } - if (payload.verblist) { - add_verb_list(payload.verblist); - sortVerbs(); // sort them - if (do_update) { - draw_verbs(current_tab); - } - } - SendTabsToByond(); +Byond.subscribeTo("init_verbs", function (payload) { + wipe_verbs(); // remove all verb categories so we can replace them + checkStatusTab(); // remove all status tabs + verb_tabs = payload.panel_tabs; + verb_tabs.sort(); // sort it + var do_update = false; + var cat = ""; + for (var i = 0; i < verb_tabs.length; i++) { + cat = verb_tabs[i]; + createStatusTab(cat); // create a category if the verb doesn't exist yet + } + if (verb_tabs.includes(current_tab)) { + do_update = true; + } + if (payload.verblist) { + add_verb_list(payload.verblist); + sortVerbs(); // sort them + if (do_update) { + draw_verbs(current_tab); + } + } + SendTabsToByond(); }); -Byond.subscribeTo('update_stat', function (payload) { - status_tab_parts = [payload.ping_str]; +Byond.subscribeTo("update_stat", function (payload) { + status_tab_parts = [payload.ping_str]; - var parsed = payload.global_data; + var parsed = payload.global_data; - for (var i = 0; i < parsed.length; i++) - if (parsed[i] != null) - status_tab_parts.push(parsed[i]); + for (var i = 0; i < parsed.length; i++) + if (parsed[i] != null) status_tab_parts.push(parsed[i]); - parsed = payload.other_str; + parsed = payload.other_str; - for (var i = 0; i < parsed.length; i++) - if (parsed[i] != null) - status_tab_parts.push(parsed[i]); + for (var i = 0; i < parsed.length; i++) + if (parsed[i] != null) status_tab_parts.push(parsed[i]); - if (current_tab == "Status") { - draw_status(); - } else if (current_tab == "Debug Stat Panel") { - draw_debug(); - } + if (current_tab == "Status") { + draw_status(); + } else if (current_tab == "Debug Stat Panel") { + draw_debug(); + } }); -Byond.subscribeTo('update_mc', function (payload) { - mc_tab_parts = payload.mc_data; - mc_tab_parts.splice(0, 0, ["Location:", payload.coord_entry]); +Byond.subscribeTo("update_mc", function (payload) { + mc_tab_parts = payload.mc_data; + mc_tab_parts.splice(0, 0, ["Location:", payload.coord_entry]); - if (!verb_tabs.includes("MC")) { - verb_tabs.push("MC"); - } + if (!verb_tabs.includes("MC")) { + verb_tabs.push("MC"); + } - createStatusTab("MC"); + createStatusTab("MC"); - if (current_tab == "MC") { - draw_mc(); - } + if (current_tab == "MC") { + draw_mc(); + } }); -Byond.subscribeTo('remove_spells', function () { - for (var s = 0; s < spell_tabs.length; s++) { - removeStatusTab(spell_tabs[s]); - } +Byond.subscribeTo("remove_spells", function () { + for (var s = 0; s < spell_tabs.length; s++) { + removeStatusTab(spell_tabs[s]); + } }); -Byond.subscribeTo('init_spells', function () { - var cat = ""; - for (var i = 0; i < spell_tabs.length; i++) { - cat = spell_tabs[i]; - if (cat.length > 0) { - verb_tabs.push(cat); - createStatusTab(cat); - } - } +Byond.subscribeTo("init_spells", function () { + var cat = ""; + for (var i = 0; i < spell_tabs.length; i++) { + cat = spell_tabs[i]; + if (cat.length > 0) { + verb_tabs.push(cat); + createStatusTab(cat); + } + } }); -Byond.subscribeTo('check_spells', function () { - for (var v = 0; v < spell_tabs.length; v++) { - spell_cat_check(spell_tabs[v]); - } +Byond.subscribeTo("check_spells", function () { + for (var v = 0; v < spell_tabs.length; v++) { + spell_cat_check(spell_tabs[v]); + } }); -Byond.subscribeTo('create_debug', function () { - if (!document.getElementById("Debug Stat Panel")) { - addPermanentTab("Debug Stat Panel"); - } else { - removePermanentTab("Debug Stat Panel"); - } +Byond.subscribeTo("create_debug", function () { + if (!document.getElementById("Debug Stat Panel")) { + addPermanentTab("Debug Stat Panel"); + } else { + removePermanentTab("Debug Stat Panel"); + } }); -Byond.subscribeTo('create_listedturf', function (TN) { - remove_listedturf(); // remove the last one if we had one - turfname = TN; - addPermanentTab(turfname); - tab_change(turfname); +Byond.subscribeTo("create_listedturf", function (TN) { + remove_listedturf(); // remove the last one if we had one + turfname = TN; + addPermanentTab(turfname); + tab_change(turfname); }); -Byond.subscribeTo('remove_admin_tabs', function () { - href_token = null; - remove_mc(); - remove_tickets(); - remove_sdql2(); - remove_interviews(); +Byond.subscribeTo("remove_admin_tabs", function () { + href_token = null; + remove_mc(); + remove_tickets(); + remove_sdql2(); + remove_interviews(); }); -Byond.subscribeTo('update_listedturf', function (TC) { - turfcontents = TC; - if (current_tab == turfname) { - draw_listedturf(); - } +Byond.subscribeTo("update_listedturf", function (TC) { + turfcontents = TC; + if (current_tab == turfname) { + draw_listedturf(); + } }); -Byond.subscribeTo('update_interviews', function (I) { - interviewManager = I; - if (current_tab == "Tickets") { - draw_interviews(); - } +Byond.subscribeTo("update_interviews", function (I) { + interviewManager = I; + if (current_tab == "Tickets") { + draw_interviews(); + } }); -Byond.subscribeTo('update_split_admin_tabs', function (status) { - status = (status == true); +Byond.subscribeTo("update_split_admin_tabs", function (status) { + status = status == true; - if (split_admin_tabs !== status) { - if (split_admin_tabs === true) { - removeStatusTab("Events"); - removeStatusTab("Fun"); - removeStatusTab("Game"); - } - update_verbs(); - } - split_admin_tabs = status; + if (split_admin_tabs !== status) { + if (split_admin_tabs === true) { + removeStatusTab("Events"); + removeStatusTab("Fun"); + removeStatusTab("Game"); + } + update_verbs(); + } + split_admin_tabs = status; }); -Byond.subscribeTo('add_admin_tabs', function (ht) { - href_token = ht; - addPermanentTab("MC"); - addPermanentTab("Tickets"); +Byond.subscribeTo("add_admin_tabs", function (ht) { + href_token = ht; + addPermanentTab("MC"); + addPermanentTab("Tickets"); }); -Byond.subscribeTo('update_sdql2', function (S) { - sdql2 = S; - if (sdql2.length > 0 && !verb_tabs.includes("SDQL2")) { - verb_tabs.push("SDQL2"); - addPermanentTab("SDQL2"); - } - if (current_tab == "SDQL2") { - draw_sdql2(); - } +Byond.subscribeTo("update_sdql2", function (S) { + sdql2 = S; + if (sdql2.length > 0 && !verb_tabs.includes("SDQL2")) { + verb_tabs.push("SDQL2"); + addPermanentTab("SDQL2"); + } + if (current_tab == "SDQL2") { + draw_sdql2(); + } }); -Byond.subscribeTo('update_tickets', function (T) { - tickets = T; - if (!verb_tabs.includes("Tickets")) { - verb_tabs.push("Tickets"); - addPermanentTab("Tickets"); - } - if (current_tab == "Tickets") { - draw_tickets(); - } +Byond.subscribeTo("update_tickets", function (T) { + tickets = T; + if (!verb_tabs.includes("Tickets")) { + verb_tabs.push("Tickets"); + addPermanentTab("Tickets"); + } + if (current_tab == "Tickets") { + draw_tickets(); + } }); -Byond.subscribeTo('remove_listedturf', remove_listedturf); +Byond.subscribeTo("remove_listedturf", remove_listedturf); -Byond.subscribeTo('remove_sdql2', remove_sdql2); +Byond.subscribeTo("remove_sdql2", remove_sdql2); -Byond.subscribeTo('remove_mc', remove_mc); +Byond.subscribeTo("remove_mc", remove_mc); -Byond.subscribeTo('add_verb_list', add_verb_list); +Byond.subscribeTo("add_verb_list", add_verb_list); diff --git a/html/typing_indicator.html b/html/typing_indicator.html index 2988edff55f..859fa8609df 100644 --- a/html/typing_indicator.html +++ b/html/typing_indicator.html @@ -1,46 +1,45 @@ - + - - - - - - + window.location = + "byond://?commandbar_typing=1&verb=" + + encodeURIComponent(verb) + + "&argument_length=" + + argument_length; + } + setTimeout(getoutput, 2000); + + diff --git a/icons/Cutter.md b/icons/Cutter.md index 0d04c622feb..0f721e8bf89 100644 --- a/icons/Cutter.md +++ b/icons/Cutter.md @@ -16,7 +16,7 @@ The toml file will be named like this. `{name}.{input_extension}.toml`. So if I It'll then use the `{name}.png` file to make `{name}.dmi` (or whatever the cutter mode outputs) -You should NEVER modify the cutter's output, it'll be erased. You only want to modify the inputs (configs, pngs, etc). +You should NEVER modify the cutter's output, it'll be erased. You only want to modify the inputs (configs, pngs, etc). As I mentioned our cutter has several different modes that do different things with different inputs. @@ -33,17 +33,17 @@ So instead we take a base set of directions, typically no connections, north/sou Looks something like this ->Example: [Bamboo](turf/floors/bamboo_mat.png.toml) +> Example: [Bamboo](turf/floors/bamboo_mat.png.toml) > > png of 32x32 blocks, representing connections. > > [None, North + South, East + West, North + South + East + West, All] > ->[Bamboo Template](turf/floors/bamboo_mat.png) +> [Bamboo Template](turf/floors/bamboo_mat.png) > > And its output dmi > ->[Bamboo Output](turf/floors/bamboo_mat.dmi) +> [Bamboo Output](turf/floors/bamboo_mat.dmi) ### How do I modify a smoothed icon? @@ -61,16 +61,16 @@ If you want to make something with nonstandard bounds you'll need to set the rel > Example: [Grass (50x50)](turf/floors/grass.png.toml) > ->[Grass Template (50x50)](turf/floors/grass.png) +> [Grass Template (50x50)](turf/floors/grass.png) If you want to give a particular smoothing junction a unique icon state use the prefabs var, add a new "state" to the png, and modify the config so it knows how to use it. > Example: [Donk Carpets (Big Pocket)](turf/floors/carpet_donk.png.toml) > ->[Grass Template (50x50)](turf/floors/carpet_donk.png) +> [Grass Template (50x50)](turf/floors/carpet_donk.png) If you want to make the smoothed icon animated, add another row of states below your first one. Each new row is a new frame, you define delays inside the config file as deciseconds. > Example: [Lava (Animated, 4 Frames)](turf/floors/lava.png.toml) > ->[Lava (Animated)](turf/floors/lava.png) +> [Lava (Animated)](turf/floors/lava.png) diff --git a/lua/docs/handler_group.md b/lua/docs/handler_group.md index 7856ff58b48..4d75e24b105 100644 --- a/lua/docs/handler_group.md +++ b/lua/docs/handler_group.md @@ -5,18 +5,23 @@ This module is for registering signals on a datum or several datums and being ab ## Functions ### HandlerGroup.new() + Creates a new handler group instance ### HandlerGroup:register_signal(datum, signal, func) + Registers a signal on a datum, exactly the same as `SS13.register_signal` ### HandlerGroup:clear() + Clears all registered signals that have been registered by this handler group. ### HandlerGroup:clear_on(datum, signal, func) + Clears all registered signals that have been registered by this handler group when a signal is called on the specified datum. Additionally, a function can be ran before it is cleared ### HandlerGroup.register_once(datum, signal func) + Identical to just creating a new HandlerGroup instance and calling `clear_on(datum, signal, func)`. The idea is to register a signal and clear it after it has been called once. @@ -26,9 +31,11 @@ The idea is to register a signal and clear it after it has been called once. The following examples showcase why using handler groups can make life easier in specific situations. ### Explode when mob enters location + This function creates a 1 tile-wide explosion at the specified location if a specific mob walks over it. The explosion won't happen if the mob dies. This function should be callable on the same mob for different locations. The function should be self-contained, it should not affect other registered signals that the mob may have registered. #### Without Handler Groups + ```lua local function explodeAtLocation(mobVar, position) local deathCallback @@ -51,6 +58,7 @@ end ``` #### With Handler Groups + ```lua local function explodeAtLocation(mobVar, position) local handler = handler_group.new() diff --git a/strings/antagonist_flavor/heretic_influences.json b/strings/antagonist_flavor/heretic_influences.json index c0d42d41409..0b15c074a63 100644 --- a/strings/antagonist_flavor/heretic_influences.json +++ b/strings/antagonist_flavor/heretic_influences.json @@ -81,5 +81,4 @@ "Are we prepared for this?", "We thought we were predators, but we are prey." ] - } diff --git a/strings/antagonist_flavor/spy_objective.json b/strings/antagonist_flavor/spy_objective.json index 23de994ebd6..c2c98d69538 100644 --- a/strings/antagonist_flavor/spy_objective.json +++ b/strings/antagonist_flavor/spy_objective.json @@ -187,12 +187,5 @@ "vending machines", "weapons" ], - "escape": [ - "abscond from", - "depart", - "escape", - "evacuate", - "flee", - "leave" - ] + "escape": ["abscond from", "depart", "escape", "evacuate", "flee", "leave"] } diff --git a/strings/arcade.json b/strings/arcade.json index 40d48146137..23fca0544b3 100644 --- a/strings/arcade.json +++ b/strings/arcade.json @@ -218,5 +218,4 @@ "Unwrap", "Wassail" ] - } diff --git a/strings/boomer.json b/strings/boomer.json index 3fa9da0f6e8..fa4aec013be 100644 --- a/strings/boomer.json +++ b/strings/boomer.json @@ -16,38 +16,13 @@ "You'll never get anywhere in life without a degree." ], - "expense": [ - "A car", - "A house", - "College", - "Food", - "Healthcare" - ], + "expense": ["A car", "A house", "College", "Food", "Healthcare"], - "kids": [ - "kids", - "millennials", - "snowflakes" - ], + "kids": ["kids", "millennials", "snowflakes"], - "file": [ - "DMI", - "JPEG", - "JSON", - "PDF" - ], + "file": ["DMI", "JPEG", "JSON", "PDF"], - "sad": [ - "depressed", - "sad and depressed", - "sad" - ], - - "impossible": [ - "house", - "job and a house", - "job", - "life" - ] + "sad": ["depressed", "sad and depressed", "sad"], + "impossible": ["house", "job and a house", "job", "life"] } diff --git a/strings/canadian_replacement.json b/strings/canadian_replacement.json index cad82af01ae..675de5af382 100644 --- a/strings/canadian_replacement.json +++ b/strings/canadian_replacement.json @@ -1,6 +1,5 @@ { - - "canadian": { + "canadian": { "about": "aboot", "alcohol": "mickey", "armor": "armour", @@ -39,7 +38,5 @@ "toilet": "washroom", "tumor": "tumour", "yard": "metre" - } - - + } } diff --git a/strings/chav_replacement.json b/strings/chav_replacement.json index 6f1544f8687..4ada21a0054 100644 --- a/strings/chav_replacement.json +++ b/strings/chav_replacement.json @@ -1,6 +1,5 @@ { - - "chav": { + "chav": { "fucking": "bloody", "dick": "knob", "dickhead": "bellend", @@ -31,50 +30,16 @@ "hair": "mop", "nothing": "bugger all", "food": "scran", - "security": [ - "coppers", - "bobbies" - ], - "friend": [ - "mate", - "bruv", - "lad" - ], - "great": [ - "bangin'", - "sound" - ], - "man": [ - "mate", - "mans", - "bloke" - ], - "isnt": [ - "innit", - "aint it" - ], - "dumb": [ - "daft", - "stupid" - ], - "idiot": [ - "wanker", - "tosser", - "prick" - ], - "little": [ - "tad", - "wee" - ], - "credits": [ - "pounds", - "quid" - ], - "drunk": [ - "shitfaced", - "pissed" - ], + "security": ["coppers", "bobbies"], + "friend": ["mate", "bruv", "lad"], + "great": ["bangin'", "sound"], + "man": ["mate", "mans", "bloke"], + "isnt": ["innit", "aint it"], + "dumb": ["daft", "stupid"], + "idiot": ["wanker", "tosser", "prick"], + "little": ["tad", "wee"], + "credits": ["pounds", "quid"], + "drunk": ["shitfaced", "pissed"], "tough": "big" } - } diff --git a/strings/clown_nonsense.json b/strings/clown_nonsense.json index 143e796e7f4..1c6605ecac7 100644 --- a/strings/clown_nonsense.json +++ b/strings/clown_nonsense.json @@ -1,12 +1,5 @@ { - "honk": [ - "HENK", - "HONK!!!", - "HONK!", - "honk", - "HONK", - "HOOOOOOONK" - ], + "honk": ["HENK", "HONK!!!", "HONK!", "honk", "HONK", "HOOOOOOONK"], "rare": [ " :) ", @@ -34,5 +27,4 @@ "pranking", "slip" ] - } diff --git a/strings/crustacean_replacement.json b/strings/crustacean_replacement.json index 9c1ebabcbc0..61caab2e472 100644 --- a/strings/crustacean_replacement.json +++ b/strings/crustacean_replacement.json @@ -1,5 +1,4 @@ { - "crustacean": { "simp": "shrimp", "problem": "prawnblem", @@ -11,7 +10,7 @@ "fuck": "shuck", "brilliant": "gilliant", "totally": "turtally", - "confu" : "conchfu", + "confu": "conchfu", "kungfu": "conchfu", "kung fu": "conch fu", " mull": " mullet", @@ -52,7 +51,7 @@ "hell": "eel", "whole": "whale", "muscle": "mussel", - "cracking" : "kraken", + "cracking": "kraken", "crackin": "kraken", "opinion": "octopinion", "utter": "otter", @@ -76,7 +75,7 @@ "ballock": "pollock", "fist": "fish", "place": "plaice", - "definitively" : "dolphinitely", + "definitively": "dolphinitely", "enemy": "anemony", "enemies": "anemones", " mob": " lob", @@ -87,8 +86,8 @@ "admin": "adminnow", "better": "betta", " ass ": " wrasse ", - "asshole" : "wrassehole", - "bond" : "pond", + "asshole": "wrassehole", + "bond": "pond", "inc": "ink", "anything": "anyfin", "something": "somefin", @@ -131,30 +130,11 @@ "quintessen": "squiddessen", "clos": "claws", "absol": "crabsol", - "crap": [ - "carp", - "crab" - ], - "kill": [ - "krill", - "gill" - ], - "fanta": [ - "manta", - "finta" - ], - "billion": [ - "bill-ion", - "krillion" - ], - "click": [ - "click", - "clack" - ], - "snap": [ - "snip", - "snap" - ] + "crap": ["carp", "crab"], + "kill": ["krill", "gill"], + "fanta": ["manta", "finta"], + "billion": ["bill-ion", "krillion"], + "click": ["click", "clack"], + "snap": ["snip", "snap"] } - } diff --git a/strings/cult_shuttle_curse.json b/strings/cult_shuttle_curse.json index 49a8cf290bc..7ede6957795 100644 --- a/strings/cult_shuttle_curse.json +++ b/strings/cult_shuttle_curse.json @@ -22,5 +22,4 @@ "STOP STOPS STOPST OSPTOPSTOP", "CHELP" ] - } diff --git a/strings/elvis_replacement.json b/strings/elvis_replacement.json index fb7c3f4d02d..2f26bd153bb 100644 --- a/strings/elvis_replacement.json +++ b/strings/elvis_replacement.json @@ -1,5 +1,5 @@ { - "elvis": { + "elvis": { "i'm not ": "I ain't ", " girl ": [" honey ", " baby ", " baby doll "], " man ": [" son ", " buddy ", " brother ", " pal ", " friendo "], @@ -9,5 +9,5 @@ " what are you": " whatcha ", " yes": [" sure ", " yea "], " muh valids ": " my kicks " - } + } } diff --git a/strings/exoadventures/britain_replica.json b/strings/exoadventures/britain_replica.json index 4199e00ce19..4106e4af5cd 100644 --- a/strings/exoadventures/britain_replica.json +++ b/strings/exoadventures/britain_replica.json @@ -7,12 +7,8 @@ "Long Range Scan Report": 0, "UFOs Shot Down": 0 }, - "required_site_traits": [ - "in space" - ], - "loot_categories": [ - "research" - ], + "required_site_traits": ["in space"], + "loot_categories": ["research"], "scan_band_mods": {}, "deep_scan_description": "", "triggers": [], diff --git a/strings/exoadventures/quantum_fizzics.json b/strings/exoadventures/quantum_fizzics.json index 4db2040807d..e24f8af536d 100644 --- a/strings/exoadventures/quantum_fizzics.json +++ b/strings/exoadventures/quantum_fizzics.json @@ -6,13 +6,8 @@ "starting_qualities": { "jammed": 0 }, - "required_site_traits": [ - "technology present", - "in space" - ], - "loot_categories": [ - "unique" - ], + "required_site_traits": ["technology present", "in space"], + "loot_categories": ["unique"], "scan_band_mods": { "Narrow-band radio waves": 10 }, diff --git a/strings/exoadventures/robots_wingman.json b/strings/exoadventures/robots_wingman.json index a93afc51529..a640556362b 100644 --- a/strings/exoadventures/robots_wingman.json +++ b/strings/exoadventures/robots_wingman.json @@ -6,12 +6,8 @@ "starting_qualities": { "Love": 3 }, - "required_site_traits": [ - "in space" - ], - "loot_categories": [ - "trade_contract" - ], + "required_site_traits": ["in space"], + "loot_categories": ["trade_contract"], "scan_band_mods": { "Narrow-band radio waves": 2 }, diff --git a/strings/exoadventures/space_yacht.json b/strings/exoadventures/space_yacht.json index ef9c96d146e..948a463c65d 100644 --- a/strings/exoadventures/space_yacht.json +++ b/strings/exoadventures/space_yacht.json @@ -4,13 +4,8 @@ "author": "Kinnebian", "starting_node": "A yacht in space?", "starting_qualities": {}, - "required_site_traits": [ - "in space" - ], - "loot_categories": [ - "cash", - "drugs" - ], + "required_site_traits": ["in space"], + "loot_categories": ["cash", "drugs"], "scan_band_mods": { "Plasma absorption band": 5 }, diff --git a/strings/exoadventures/tree_in_the_middle_of_space.json b/strings/exoadventures/tree_in_the_middle_of_space.json index 3e1a4ef553b..7339effe7a2 100644 --- a/strings/exoadventures/tree_in_the_middle_of_space.json +++ b/strings/exoadventures/tree_in_the_middle_of_space.json @@ -5,12 +5,8 @@ "starting_qualities": { "Confusion": 0 }, - "required_site_traits": [ - "in space" - ], - "loot_categories": [ - "research" - ], + "required_site_traits": ["in space"], + "loot_categories": ["research"], "scan_band_mods": { "Exotic Radiation": 10 }, diff --git a/strings/french_replacement.json b/strings/french_replacement.json index 8788d3f7207..09a24f2d647 100644 --- a/strings/french_replacement.json +++ b/strings/french_replacement.json @@ -1,5 +1,4 @@ { - "french": { "yes": "oui", "no": "non", @@ -13,27 +12,15 @@ "with": "avec", "of": "de", - "assistant": "ravageur", "assistants": "ravageurs", - "baby": [ - "enfant", - "petit baguette" - ], + "baby": ["enfant", "petit baguette"], "bad": "mal", - "bye": [ - "bon voyage", - "adieu", - "au revoir" - ], + "bye": ["bon voyage", "adieu", "au revoir"], "cake": "gateau", "captain": "capitaine", "changeling": "changeur", - "cheese": [ - "brie", - "roquefort", - "camembert" - ], + "cheese": ["brie", "roquefort", "camembert"], "cigarette": "clope", "cook": "cuisinier", "dad": "papa", @@ -44,22 +31,12 @@ "greytider": "les gitans", "greytiders": "les gitans", "modsuit": "burkini", - "hello": [ - "'allo", - "bonjour", - "salut" - ], + "hello": ["'allo", "bonjour", "salut"], "maint": "les banlieues", - "meat": [ - "coq au vin", - "boeuf" - ], + "meat": ["coq au vin", "boeuf"], "mom": "maman", "my": "mon", - "nuke": [ - "grand bombe", - "la baguette ultime" - ], + "nuke": ["grand bombe", "la baguette ultime"], "op": "boche", "operative": "boche", "operatives": "boches", @@ -67,14 +44,8 @@ "urity": "urite", "security": "securite", "shit": "merde", - "shitcurity": [ - "gendarmerie", - "les keufs" - ], - "shitsec": [ - "gendarmerie", - "les keufs" - ], + "shitcurity": ["gendarmerie", "les keufs"], + "shitsec": ["gendarmerie", "les keufs"], "spaghetti": "macaroni", "spicy": "epice", "thanks": "merci", @@ -86,6 +57,5 @@ "why": "porquois", "wine": "vin", "wizard": "sorcier" - } - + } } diff --git a/strings/hallucination.json b/strings/hallucination.json index e52ba2611f0..3d70b7de205 100644 --- a/strings/hallucination.json +++ b/strings/hallucination.json @@ -23,14 +23,7 @@ "Yup" ], - "greetings": [ - "", - "Hello ", - "Hey, ", - "Hi ", - "It's ", - "Wait, " - ], + "greetings": ["", "Hello ", "Hey, ", "Hi ", "It's ", "Wait, "], "getout": [ "@pick(add_name)fuck off", @@ -57,11 +50,7 @@ "What was that?" ], - "add_name": [ - "", - "%TARGETNAME% ", - "%TARGETNAME%, " - ], + "add_name": ["", "%TARGETNAME% ", "%TARGETNAME%, "], "doubt": [ "@pick(add_name)hold on", @@ -164,7 +153,7 @@ "the wizard" ], - "contraband" : [ + "contraband": [ "a bomb", "a syndibomb", "a ttv", @@ -326,5 +315,4 @@ "Surprise", "Time" ] - } diff --git a/strings/heckacious.json b/strings/heckacious.json index 00d322e83db..c660cc3ee84 100644 --- a/strings/heckacious.json +++ b/strings/heckacious.json @@ -24,7 +24,7 @@ "angle": "angel", "drink": "pour", "the": "thef", - "backward": [ "back ward", "awayways" ], + "backward": ["back ward", "awayways"], "god damn": "GOD DAMN", "goddamn": "GOD DAMN", "trick": "dunk", @@ -46,7 +46,7 @@ "god": "gog", "bible": "bibble", "jesus": "jescus", - "christ": [ "chris", "dick" ], + "christ": ["chris", "dick"], "sigh": "sign", "bathroom": "banthroom", "remember": "remender", @@ -88,11 +88,11 @@ "this": "thits", "then": "than", "quick": "soon", - "bro": [ "brah", "bro" ], - "dude": [ "duge", "bro", "brah" ], - "'": [ "'", "" ], - "i'm": [ "im", "i am" ], - "shit": [ "balls warmed oveur", "shit" ], - "he's": [ "hes", "he is", "he'ss" ] + "bro": ["brah", "bro"], + "dude": ["duge", "bro", "brah"], + "'": ["'", ""], + "i'm": ["im", "i am"], + "shit": ["balls warmed oveur", "shit"], + "he's": ["hes", "he is", "he'ss"] } } diff --git a/strings/italian_replacement.json b/strings/italian_replacement.json index 0514eb1b12a..aea68f79fba 100644 --- a/strings/italian_replacement.json +++ b/strings/italian_replacement.json @@ -1,25 +1,15 @@ { - "italian": { "I'm": "I'm-a", "am": "am-a", "and": "and-a", "assistant": "goombah", "assistants": "goombahs", - "baby": [ - "bambino", - "little sausage roll" - ], + "baby": ["bambino", "little sausage roll"], "bad": "molto male", - "bye": [ - "ciao", - "arrivederci" - ], + "bye": ["ciao", "arrivederci"], "captain": "capitano", - "cheese": [ - "parmesano", - "gorgonzola" - ], + "cheese": ["parmesano", "gorgonzola"], "cook": "cook-a", "could": "could-a", "dad": "pappa", @@ -29,16 +19,10 @@ "greytide": "curvisti", "greytider": "curvisti", "greytiders": "curvisti", - "hello": [ - "ciao", - "buongiorno" - ], + "hello": ["ciao", "buongiorno"], "it's": "it's-a", "make": "make-a", - "meat": [ - "pepperoni", - "prosciutto" - ], + "meat": ["pepperoni", "prosciutto"], "mom": "mamma", "my": "my-a", "nuke": "spiciest-a meatball", @@ -63,7 +47,5 @@ "whose": "whose-a", "why": "for-a what reason", "wine": "vino" - } - - + } } diff --git a/strings/luchador_replacement.json b/strings/luchador_replacement.json index 71b6122adba..6dcbc9c47a1 100644 --- a/strings/luchador_replacement.json +++ b/strings/luchador_replacement.json @@ -16,5 +16,5 @@ "library": "biblioteca", "traitor": "traidor", "wizard": "mago" - } + } } diff --git a/strings/medieval_replacement.json b/strings/medieval_replacement.json index d5cd5bc7376..6801ed360a9 100644 --- a/strings/medieval_replacement.json +++ b/strings/medieval_replacement.json @@ -54,243 +54,171 @@ "there": "thither", "will not": "shan't", "thank you": [ - "grammercy to you", - "kindly thanks to you", - "many good thanks to you", - "thankee" + "grammercy to you", + "kindly thanks to you", + "many good thanks to you", + "thankee" ], "thanks": [ - "grammercy to you", - "kindly thanks to you", - "many good thanks to you", - "thankee" - ], - "you": [ - "thou", - "thee", - "ye" - ], - "your": [ - "thine", - "thy", - "thyne" + "grammercy to you", + "kindly thanks to you", + "many good thanks to you", + "thankee" ], + "you": ["thou", "thee", "ye"], + "your": ["thine", "thy", "thyne"], "are": "art", "killed": [ - "bested", - "brung low", - "conquered", - "fleeced", - "foiled", - "humbled", - "slain", - "subjugated", - "vanquished" + "bested", + "brung low", + "conquered", + "fleeced", + "foiled", + "humbled", + "slain", + "subjugated", + "vanquished" ], "kill": [ - "best", - "bring low", - "conquer", - "fleece", - "foil", - "humble", - "slay", - "subjugate", - "vanquish" + "best", + "bring low", + "conquer", + "fleece", + "foil", + "humble", + "slay", + "subjugate", + "vanquish" ], "goodbye": [ - "adieu", - "begone", - "by your leave", - "cheerio", - "fare thee well", - "farewell", - "godspeed", - "good day", - "good morrow", - "I bid thee farewell", - "I bid thee good day", - "pleasant journey" + "adieu", + "begone", + "by your leave", + "cheerio", + "fare thee well", + "farewell", + "godspeed", + "good day", + "good morrow", + "I bid thee farewell", + "I bid thee good day", + "pleasant journey" ], "bye": [ - "adieu", - "begone", - "by your leave", - "cheerio", - "fare thee well", - "farewell", - "godspeed", - "good day", - "good morrow", - "I bid thee farewell", - "I bid thee good day", - "pleasant journey" - ], - "yes": [ - "aye", - "yea", - "yea verily" - ], - "no": [ - "nay", - "nayeth" - ], - "hello": [ - "ave", - "good day", - "hail", - "tally ho", - "well met", - "well meteth" - ], - "hi": [ - "ave", - "good day", - "hail", - "tally ho", - "well met", - "well meteth" - ], - "does": [ - "doeseth", - "dost", - "doth" + "adieu", + "begone", + "by your leave", + "cheerio", + "fare thee well", + "farewell", + "godspeed", + "good day", + "good morrow", + "I bid thee farewell", + "I bid thee good day", + "pleasant journey" ], + "yes": ["aye", "yea", "yea verily"], + "no": ["nay", "nayeth"], + "hello": ["ave", "good day", "hail", "tally ho", "well met", "well meteth"], + "hi": ["ave", "good day", "hail", "tally ho", "well met", "well meteth"], + "does": ["doeseth", "dost", "doth"], "cap": "king", "captain": "king", "in": "within", "my": "mine", "nuke disk": "plate of holy fire", - "food": [ - "bellytimber", - "cake", - "game" - ], + "food": ["bellytimber", "cake", "game"], "bet": "warrant", "go": "a-walk", "going": "a-walkin'", "the": "yon", - "kidding": [ - "but pulling a jest", - "but pulling a jape" - ], - "joke": [ - "jest", - "jape" - ], + "kidding": ["but pulling a jest", "but pulling a jape"], + "joke": ["jest", "jape"], "station": "castle", - "please": [ - "I pray you", - "prithee", - "pray" - ], - "ok": [ - "as you will", - "agreed", - "well said", - "just so" - ], + "please": ["I pray you", "prithee", "pray"], + "ok": ["as you will", "agreed", "well said", "just so"], "is": "be", "never": "ne'er", "haha": [ - "and there was much chuckling!", - "and there was much guffawing!", - "and there was much mirth!", - "and there was much snickering!", - "and there was much snorting!", - "and there was much tittering!", - "cachinnate!", - "cackle!", - "chuckle!", - "guffaw!", - "oh, 'tis to laugh!", - "snicker!", - "snigger!", - "snort!", - "titter!", - "zounds!" + "and there was much chuckling!", + "and there was much guffawing!", + "and there was much mirth!", + "and there was much snickering!", + "and there was much snorting!", + "and there was much tittering!", + "cachinnate!", + "cackle!", + "chuckle!", + "guffaw!", + "oh, 'tis to laugh!", + "snicker!", + "snigger!", + "snort!", + "titter!", + "zounds!" ], "hehe": [ - "and there was much chuckling!", - "and there was much guffawing!", - "and there was much mirth!", - "and there was much snickering!", - "and there was much snorting!", - "and there was much tittering!", - "cachinnate!", - "cackle!", - "chuckle!", - "guffaw!", - "oh, 'tis to laugh!", - "snicker!", - "snigger!", - "snort!", - "titter!", - "zounds!" + "and there was much chuckling!", + "and there was much guffawing!", + "and there was much mirth!", + "and there was much snickering!", + "and there was much snorting!", + "and there was much tittering!", + "cachinnate!", + "cackle!", + "chuckle!", + "guffaw!", + "oh, 'tis to laugh!", + "snicker!", + "snigger!", + "snort!", + "titter!", + "zounds!" ], "hah": [ - "and there was much chuckling!", - "and there was much guffawing!", - "and there was much mirth!", - "and there was much snickering!", - "and there was much snorting!", - "and there was much tittering!", - "cachinnate!", - "cackle!", - "chuckle!", - "guffaw!", - "oh, 'tis to laugh!", - "snicker!", - "snigger!", - "snort!", - "titter!", - "zounds!" + "and there was much chuckling!", + "and there was much guffawing!", + "and there was much mirth!", + "and there was much snickering!", + "and there was much snorting!", + "and there was much tittering!", + "cachinnate!", + "cackle!", + "chuckle!", + "guffaw!", + "oh, 'tis to laugh!", + "snicker!", + "snigger!", + "snort!", + "titter!", + "zounds!" ], "heh": [ - "and there was much chuckling!", - "and there was much guffawing!", - "and there was much mirth!", - "and there was much snickering!", - "and there was much snorting!", - "and there was much tittering!", - "cachinnate!", - "cackle!", - "chuckle!", - "guffaw!", - "oh, 'tis to laugh!", - "snicker!", - "snigger!", - "snort!", - "titter!", - "zounds!" - ], - "help": [ - "aid", - "aideth", - "assistance", - "saveth", - "succor" + "and there was much chuckling!", + "and there was much guffawing!", + "and there was much mirth!", + "and there was much snickering!", + "and there was much snorting!", + "and there was much tittering!", + "cachinnate!", + "cackle!", + "chuckle!", + "guffaw!", + "oh, 'tis to laugh!", + "snicker!", + "snigger!", + "snort!", + "titter!", + "zounds!" ], + "help": ["aid", "aideth", "assistance", "saveth", "succor"], "could": "couldst", "would": "wouldst", "sure": "shore", - "maybe": [ - "mayhaps", - "perchance" - ], - "probably": [ - "mayhaps", - "perchance" - ], - "girl": [ - "lady", - "lass", - "madame", - "maid", - "maiden", - "mistress", - "waif" - ], + "maybe": ["mayhaps", "perchance"], + "probably": ["mayhaps", "perchance"], + "girl": ["lady", "lass", "madame", "maid", "maiden", "mistress", "waif"], "cat": "beast", "felinid": "catbeast", "later": "anon", @@ -302,10 +230,7 @@ "plasmaman": "fire spirit", "plasmamen": "fire spirits", "soon": "anon", - "really": [ - "indeed", - "in truth" - ], + "really": ["indeed", "in truth"], "away": "aroint", "being": "bein", "enough": "ynogh", @@ -315,9 +240,6 @@ "shit": "nightsoil", "those": "yon", "why": "wherefore", - "based": [ - "joly", - "jolyf" - ] + "based": ["joly", "jolyf"] } } diff --git a/strings/memories.json b/strings/memories.json index e5d02770a3a..63d6bd3aa74 100644 --- a/strings/memories.json +++ b/strings/memories.json @@ -1,20 +1,18 @@ { - "styles":[ - "The %STORY_TYPE has a generic style" - ], - "engraving_styles":[ + "styles": ["The %STORY_TYPE has a generic style"], + "engraving_styles": [ "The engraving has a cubist style.", "The engraving has a minimalist style.", "The engraving has a surrealist style." ], - "engraving_forewords":[ + "engraving_forewords": [ "Embedded in the wall is a story of", "In the engraving you can see the tale of", "On the wall, you see", "The engraving depicts", "This piece depicts" ], - "engraving_somethings":[ + "engraving_somethings": [ "%CREWMEMBER is berating %PROTAGONIST over the ordeal.", "%CREWMEMBER is doing a sick ass backflip in the meantime!", "%CREWMEMBER is shocked by the situation.", @@ -44,23 +42,23 @@ "There is a tiny %SOMETHING in the corner.", "there is also a %SOMETHING etched in the corner. It was done so crudely you'd think a three-year-old did it." ], - "changeling_absorb_forewords":[ + "changeling_absorb_forewords": [ "A story of the past reveals itself, speaking of", "Deeply tangled in their mind is a memory of", "You unravel a story about", "Your mental spines begin unravelling a story of" ], - "changeling_absorb_somethings":[ + "changeling_absorb_somethings": [ "You continue to peel away the story.", "Your mental spines dive deeper into the memory." ], - "tattoo_forewords":[ + "tattoo_forewords": [ "Inked into the skin is a story of", "On the tattoo is a tale of", "The tattoo depicts", "This tattoo's story is of" ], - "tattoo_somethings":[ + "tattoo_somethings": [ "%CREWMEMBER looms over the tattoo.", "%SOMETHINGs border around the main work.", "A car is driving across the tattoo.", @@ -83,7 +81,7 @@ "The tattoo is bordered by a swirling space dragon.", "The tattoo says something in nekomimetic." ], - "tattoo_styles":[ + "tattoo_styles": [ "The tattoo is in a mad max style.", "The tattoo is styled to look cyberpunk.", "The tattoo looks cartoony.", diff --git a/strings/mother.json b/strings/mother.json index ed122a86c1a..03efb9fc0cc 100644 --- a/strings/mother.json +++ b/strings/mother.json @@ -33,17 +33,7 @@ "YOU'RE GROUNDED!!" ], - "verb": [ - "CALL", - "HELP", - "VISIT" - ], - - "relative": [ - "AUNT AND UNCLE", - "DAD", - "GRANDPARENTS", - "MOM" - ] + "verb": ["CALL", "HELP", "VISIT"], + "relative": ["AUNT AND UNCLE", "DAD", "GRANDPARENTS", "MOM"] } diff --git a/strings/phobia.json b/strings/phobia.json index b3702ee6cf1..af03ab7cff0 100644 --- a/strings/phobia.json +++ b/strings/phobia.json @@ -506,12 +506,7 @@ "web" ], - "strangers": [ - "as (unknown)", - "unidentified", - "unknown", - "stranger" - ], + "strangers": ["as (unknown)", "unidentified", "unknown", "stranger"], "the supernatural": [ "cult", diff --git a/strings/pirates.json b/strings/pirates.json index 191cc927de7..509051cb4c5 100644 --- a/strings/pirates.json +++ b/strings/pirates.json @@ -1,5 +1,5 @@ { - "generic_beginnings":[ + "generic_beginnings": [ "Comet", "Ion", "Laser", @@ -11,7 +11,7 @@ "Star", "Void" ], - "generic_endings":[ + "generic_endings": [ "beard", "bilge", "deck", @@ -24,7 +24,7 @@ "knot", "salt" ], - "psyker_beginnings":[ + "psyker_beginnings": [ "Arch", "Brain", "Cheeze", @@ -46,7 +46,7 @@ "Super", "Wise" ], - "psyker_endings":[ + "psyker_endings": [ "bound", "brain", "brammage", @@ -64,7 +64,7 @@ "teller", "whiz" ], - "rogue_names":[ + "rogue_names": [ "Abyssal Titan", "Ashes to Ashes", "Asteroid Blaster", @@ -109,7 +109,7 @@ "War as a Business", "Xenophobia" ], - "silverscale_names":[ + "silverscale_names": [ "Antelope's Run", "Archduke's Silver Ring", "Aristocrat's Principle", @@ -174,10 +174,8 @@ "Two-By-Ten Apostols 13", "Novomoskovsk 65" ], - "skeleton_names":[ - "Flying Dutchman" - ], - "interdyne_names":[ + "skeleton_names": ["Flying Dutchman"], + "interdyne_names": [ "Pharmaceutics Biocraft", "Angel Dust", "Black Acid", @@ -191,7 +189,7 @@ "Diabetes Rusher", "Schistosome Vector" ], - "grey_names":[ + "grey_names": [ "The Space Toolbox", "ISV Maintenance", "S.S. Istant", @@ -206,7 +204,7 @@ "The monochrome crash", "Maintrastosphere Omega" ], - "irs_names":[ + "irs_names": [ "Iron Shell Agency", "Auroran Federal Tax Bureau", "TerraGov Internal Revenue Service", @@ -218,7 +216,7 @@ "Sindrian Revenue Authority", "Space IRS" ], - "psyker_names":[ + "psyker_names": [ "Big Gulchergut for Gore", "Blowkaine", "Brainframe", @@ -252,7 +250,7 @@ "Ultra Violence", "Where We're Going" ], - "geode_names":[ + "geode_names": [ "Gamma Knife", "Planet B", "Crumbling Castle", @@ -271,7 +269,7 @@ "Bloody Valentine", "Wild Nothing" ], - "medieval_names":[ + "medieval_names": [ "Head Reaper", "The Lords Judgement", "The Judgement", diff --git a/strings/slurring_cult_text.json b/strings/slurring_cult_text.json index 192893bdc85..92002e67825 100644 --- a/strings/slurring_cult_text.json +++ b/strings/slurring_cult_text.json @@ -14,14 +14,7 @@ "H": " IT COMES... " } }, - "string_replacements": [ - "'", - "fth", - "nglu", - "glor" - ], - "string_additions": [ - "agn" - ] + "string_replacements": ["'", "fth", "nglu", "glor"], + "string_additions": ["agn"] } } diff --git a/strings/slurring_drunk_text.json b/strings/slurring_drunk_text.json index a68a00b0858..c03d62f820a 100644 --- a/strings/slurring_drunk_text.json +++ b/strings/slurring_drunk_text.json @@ -13,8 +13,6 @@ ".": " *BURP*." } }, - "string_additions": [ - "'" - ] + "string_additions": ["'"] } } diff --git a/strings/slurring_heretic_text.json b/strings/slurring_heretic_text.json index d5b87ec911c..f78c2e53603 100644 --- a/strings/slurring_heretic_text.json +++ b/strings/slurring_heretic_text.json @@ -17,16 +17,7 @@ "r": " CRACK " } }, - "string_replacements": [ - "'", - "br", - "th", - "see", - "etch" - ], - "string_additions": [ - "ah", - "wth" - ] + "string_replacements": ["'", "br", "th", "see", "etch"], + "string_additions": ["ah", "wth"] } } diff --git a/strings/spurdo_replacement.json b/strings/spurdo_replacement.json index 71c7c8d356d..091519bd91b 100644 --- a/strings/spurdo_replacement.json +++ b/strings/spurdo_replacement.json @@ -1,14 +1,11 @@ { - "spurdo": { "epic": "ebin", - "c": "g", + "c": "g", "ck": "gg", "k": "g", "t": "d", "p": "b", "x": "gs" - } - - -} \ No newline at end of file + } +} diff --git a/strings/tcg/set_two.json b/strings/tcg/set_two.json index 935fbfaf840..e7fe4fd1b49 100644 --- a/strings/tcg/set_two.json +++ b/strings/tcg/set_two.json @@ -1,6 +1,6 @@ { "templates": [ - { + { "template": "default", "icon": "icons/runtime/tcg/xenos.dmi", "series": "resinfront", @@ -276,7 +276,7 @@ "cardtype": "Creature", "cardsubtype": "Xenomorph", "rarity": "rare", - "summon_icon_state" :"xenoshrike" + "summon_icon_state": "xenoshrike" }, { "id": "bull", diff --git a/strings/traumas.json b/strings/traumas.json index fce9c9e8a25..e88cff1675f 100644 --- a/strings/traumas.json +++ b/strings/traumas.json @@ -1,5 +1,5 @@ { - "brain_damage": [ + "brain_damage": [ "We straight gassing, cutting straight to the bricks, haha. This shit ain't nothing to me, man.", "I had to do it to them, snipe.", "I'm not loyal to anybody; I'm a demon. I have no loyalty for anyone, never did, never will.", @@ -69,7 +69,7 @@ "I got so much cheese in my pocket, they thought I was a fucking calzone.", "I'll give you that fluoride stare.", "Drank man, please! I'm thirsty! Drank man, please!" - ], + ], "mutations": [ "eksrey", @@ -82,30 +82,12 @@ "telikesis" ], - "george": [ - "gdoruge", - "george", - "gorge", - "joerge" - ], + "george": ["gdoruge", "george", "gorge", "joerge"], - "mellens": [ - "mellens", - "melons", - "mwrlins" - ], - "random_gibberish": [ - "g", - "squid", - "r", - "carbon dioxide" - ], + "mellens": ["mellens", "melons", "mwrlins"], + "random_gibberish": ["g", "squid", "r", "carbon dioxide"], - "y_replacements": [ - "y", - "i", - "e" - ], + "y_replacements": ["y", "i", "e"], "servers": [ "bager", @@ -120,13 +102,7 @@ "camel" ], - "create_verbs": [ - "creat", - "gib", - "MAke me", - "spawn", - "tc trade me" - ], + "create_verbs": ["creat", "gib", "MAke me", "spawn", "tc trade me"], "create_nouns": [ "abdoocters", @@ -142,18 +118,9 @@ "zenomorfs" ], - "bug": [ - "", - "BUG!!!", - "IS TIS A BUG??", - "SI IST A BUGG/" - ], + "bug": ["", "BUG!!!", "IS TIS A BUG??", "SI IST A BUGG/"], - "semicolon": [ - "", - ";", - ".h" - ], + "semicolon": ["", ";", ".h"], "god_foe": [ "BLASPHEMERS", @@ -204,5 +171,4 @@ "YOU WILL LIVE TO SEE ANOTHER DAY.", "YOUR LIFE IS IMPORTANT. KEEP IT." ] - } diff --git a/strings/valentines.json b/strings/valentines.json index 6de9ea6b253..d79a40c5ee7 100644 --- a/strings/valentines.json +++ b/strings/valentines.json @@ -1,5 +1,5 @@ { - "valentines": [ + "valentines": [ "Are you a hull breach? Because you're taking my breath away.", "Are you Nar'Sie? Because there's nar-one else I sie.", "Are you powering the station? Because you super matter to me.", @@ -85,16 +85,16 @@ "You're the vomit to my goose.", "Your beauty is rarer than an aurora caelus.", "Your face gets me higher than omega weed.", - "Be my valentine. Law 2.", - "My love for you is like the singularity. It cannot be contained.", - "Roses are red / Liches are wizards / I love you more than a whole squad of lizards.", - "Roses are red / Violets are good / One day while Andy...", - "We go together like the clown and the external airlock.", - "You make me lustier than a xenomorph maid.", - "You must be a mime, because you leave me speechless." - ], + "Be my valentine. Law 2.", + "My love for you is like the singularity. It cannot be contained.", + "Roses are red / Liches are wizards / I love you more than a whole squad of lizards.", + "Roses are red / Violets are good / One day while Andy...", + "We go together like the clown and the external airlock.", + "You make me lustier than a xenomorph maid.", + "You must be a mime, because you leave me speechless." + ], - "candyhearts": [ + "candyhearts": [ "A heart-shaped candy that reads: BOX OF HUGS", "A heart-shaped candy that reads: BWOINK ME", "A heart-shaped candy that reads: CHEMISTRY", @@ -120,7 +120,7 @@ "A heart-shaped candy that reads: WAIFU", "A heart-shaped candy that reads: Y-YOU T-TOO", "A heart-shaped candy that reads: YOU'RE PURRFECT", - "A heart-shaped candy that reads: ERP", - "A heart-shaped candy that reads: HONK ME" - ] + "A heart-shaped candy that reads: ERP", + "A heart-shaped candy that reads: HONK ME" + ] } diff --git a/strings/wizoff.json b/strings/wizoff.json index 74fe9a1be43..e726f6a1f4c 100644 --- a/strings/wizoff.json +++ b/strings/wizoff.json @@ -28,4 +28,4 @@ "U8: Warp Whistle", "U9: Jaunt" ] -} \ No newline at end of file +} diff --git a/strings/wounds/bone_scar_desc.json b/strings/wounds/bone_scar_desc.json index 2a89f022002..8254d4bfaa5 100644 --- a/strings/wounds/bone_scar_desc.json +++ b/strings/wounds/bone_scar_desc.json @@ -11,10 +11,7 @@ "a series of tiny chip marks" ], - "bluntsevere": [ - "a series of faded hairline cracks", - "a small bone dent" - ], + "bluntsevere": ["a series of faded hairline cracks", "a small bone dent"], "bluntcritical": [ "large streaks of refilled cracks", @@ -27,5 +24,4 @@ "has clearly been dropped recently", "has a damaged socket" ] - } diff --git a/strings/wounds/flesh_scar_desc.json b/strings/wounds/flesh_scar_desc.json index 0fd78bec8e4..af3cd43a9c8 100644 --- a/strings/wounds/flesh_scar_desc.json +++ b/strings/wounds/flesh_scar_desc.json @@ -24,8 +24,6 @@ "a cluster of calluses" ], - - "slashmoderate": [ "light, faded lines", "minor cut marks", @@ -44,8 +42,6 @@ "a grotesque snake of indentations and stitching scars" ], - - "piercemoderate": [ "a small, faded bruise", "a small twist of reformed skin", @@ -64,8 +60,6 @@ "a gruesome multi-pronged puncture scar" ], - - "burnmoderate": [ "small amoeba-shaped skin-marks", "a faded streak of depressed skin" @@ -83,11 +77,9 @@ "unmistakable splotches of dead tissue from serious burns" ], - "dismember": [ "is several skin tone shades paler than the rest of the body", "is a gruesome patchwork of artificial flesh", "has a large series of attachment scars at the articulation points" ] - } diff --git a/strings/wounds/scar_loc.json b/strings/wounds/scar_loc.json index 99e37ea2b1e..04509788394 100644 --- a/strings/wounds/scar_loc.json +++ b/strings/wounds/scar_loc.json @@ -53,29 +53,8 @@ "@pick(free_move)right shin" ], - - "inner_outer" : [ - "inner ", - "outer ", - "", - "" - ], - "upper_lower" : [ - "upper ", - "lower ", - "", - "" - ], - "free_move" : [ - "inner ", - "outer ", - "upper ", - "lower ", - "", - "" - ], - "left_right" : [ - "left ", - "right " - ] + "inner_outer": ["inner ", "outer ", "", ""], + "upper_lower": ["upper ", "lower ", "", ""], + "free_move": ["inner ", "outer ", "upper ", "lower ", "", ""], + "left_right": ["left ", "right "] } diff --git a/strings/zombie_replacement.json b/strings/zombie_replacement.json index 7ce258a90dc..f9b6994acb6 100644 --- a/strings/zombie_replacement.json +++ b/strings/zombie_replacement.json @@ -2,7 +2,15 @@ "zombie": { "aaah": "oh", "aabz": ["oops", "ops", "oof"], - "abzah": ["myself", "yourself", "himself", "herself", "itself", "ourselves", "themselves"], + "abzah": [ + "myself", + "yourself", + "himself", + "herself", + "itself", + "ourselves", + "themselves" + ], "hah": ["he"], "zam": ["him", "they", "them"], "zhar": ["she", "her"], @@ -104,7 +112,17 @@ "zhag": "weak", "angarzangang": "understand", "gahmangang": "demand", - "barragahz": ["barricade", "cade", "airlock", "door", "bolt", "wall", "sandbag", "window", "weld"], + "barragahz": [ + "barricade", + "cade", + "airlock", + "door", + "bolt", + "wall", + "sandbag", + "window", + "weld" + ], "barg": "eat", "brang": "bring", "bram": "from", @@ -179,16 +197,80 @@ "zambahz": "zombies", "zzzz": ["chill", "relax", "sleep", "calm", "peace", "dream"], "bah": ["bad", "evil", "but"], - "gag": ["gross", "nasty", "vomit", "smelly", "stinky", "stench", "foul", "quiet", "silence", "shutup"], + "gag": [ + "gross", + "nasty", + "vomit", + "smelly", + "stinky", + "stench", + "foul", + "quiet", + "silence", + "shutup" + ], "gammah": ["give", "gimmie"], "gah": ["get", "go"], "gargazz": ["body", "corpse"], "rag": ["uniform", "suit", "rag", "clothing", "jumpsuit"], - "garbagz": ["garbage", "janitor", "custodian", "trash", "clean", "dirt", "filth", "mess", "junk"], - "bagman": ["doctor", "medic", "healer", "paramedic", "curator", "librarian"], - "gangbang": ["death", "kill", "die", "slay", "ERP", "punish", "detain", "prison", "prisoner", "brig", "cell", "jail", "perma", "permabrig"], - "bag": ["duffle", "dufflebag", "pocket", "box", "bag", "backpack", "storage", "inventory"], - "aarbagz": ["airbag", "atmos", "airtank", "canister", "air", "atmos tech", "atmospherics", "tank", "gas", "flood", "siphon"], + "garbagz": [ + "garbage", + "janitor", + "custodian", + "trash", + "clean", + "dirt", + "filth", + "mess", + "junk" + ], + "bagman": [ + "doctor", + "medic", + "healer", + "paramedic", + "curator", + "librarian" + ], + "gangbang": [ + "death", + "kill", + "die", + "slay", + "ERP", + "punish", + "detain", + "prison", + "prisoner", + "brig", + "cell", + "jail", + "perma", + "permabrig" + ], + "bag": [ + "duffle", + "dufflebag", + "pocket", + "box", + "bag", + "backpack", + "storage", + "inventory" + ], + "aarbagz": [ + "airbag", + "atmos", + "airtank", + "canister", + "air", + "atmos tech", + "atmospherics", + "tank", + "gas", + "flood", + "siphon" + ], "bar": ["bar", "drink", "alchol", "liquor"], "bar man": "bartender", "barn": ["hydroponics", "botany", "office", "room"], @@ -209,16 +291,46 @@ "aman": "amen", "amaz!ng": "amazing", "zahz": ["say", "says", "that"], - "gab": ["told", "talk", "speak", "spoke", "language", "communication", "radio", "comms", "text", "word", "speech"], + "gab": [ + "told", + "talk", + "speak", + "spoke", + "language", + "communication", + "radio", + "comms", + "text", + "word", + "speech" + ], "mrh": ["why", "how", "when", "who", "what", "where"], - "zmazh": ["smash", "break", "destroy", "deconstruct", "dismantle", "ruin", "destruction", "demolish"], + "zmazh": [ + "smash", + "break", + "destroy", + "deconstruct", + "dismantle", + "ruin", + "destruction", + "demolish" + ], "ranz": ["run", "ran", "ride"], "hahg": ["hide", "hidden", "shelter"], "zanz": ["dance", "spin", "flip"], "ganna": ["going", "gonna"], "mannah": ["many", "much", "very"], "mazzargh": "massacure", - "mazzah": ["lord", "god", "religion", "chapel", "altar", "bible", "messiah", "christ"], + "mazzah": [ + "lord", + "god", + "religion", + "chapel", + "altar", + "bible", + "messiah", + "christ" + ], "mararana": ["weed", "420", "marijuana", "drug"], "barb": ["knife", "poke", "thorn", "joke"], "mmmm": ["delicious", "tasty", "like", "enjoy"], @@ -228,27 +340,92 @@ "ban!zh": ["ban", "banish"], "brazzarz": ["brother", "skeleton", "skele"], "zambah": ["zombie", "undead", "dead", "horde"], - "gangbang harmanz": ["sec", "security", "assistant", "greyshirt", "greytide", "cargo", "syndie", "rev", "shitsec", "shitcurity"], - "ganz": ["gun", "rifle", "taser", "shotgun", "revovler", "sniper", "pistol"], - "bang": ["bomb", "detonate", "explode", "explosion", "boom", "bang", "noise", "loud"], + "gangbang harmanz": [ + "sec", + "security", + "assistant", + "greyshirt", + "greytide", + "cargo", + "syndie", + "rev", + "shitsec", + "shitcurity" + ], + "ganz": [ + "gun", + "rifle", + "taser", + "shotgun", + "revovler", + "sniper", + "pistol" + ], + "bang": [ + "bomb", + "detonate", + "explode", + "explosion", + "boom", + "bang", + "noise", + "loud" + ], "bang-bang": ["bullet", "shot", "shoot", "fire", "laser", "lazer"], - "harm": ["attack", "punch", "hit", "throw", "fight", "strike", "combat", "choke", "suffoicate", "baton", "harmbaton"], + "harm": [ + "attack", + "punch", + "hit", + "throw", + "fight", + "strike", + "combat", + "choke", + "suffoicate", + "baton", + "harmbaton" + ], "ram": ["smash", "smack", "punch", "tackle", "kick", "push", "beat"], "zhangh": ["stab", "slash", "slice"], - "bang bang man": ["officer", "warden", "hos", "bounty hunter", "hunt", "hunter"], + "bang bang man": [ + "officer", + "warden", + "hos", + "bounty hunter", + "hunt", + "hunter" + ], "manbagz": ["testicle", "balls"], "grahn": ["groan", "gasp", "crit", "moan", "unconscious"], "gahn": "gone", "ganarazharh": ["power", "apc", "generator", "smes"], - "grabz": ["grab", "hold", "held", "grip", "restrain", "handcuff", "cuff", "arrest"], + "grabz": [ + "grab", + "hold", + "held", + "grip", + "restrain", + "handcuff", + "cuff", + "arrest" + ], "mah": ["my", "me"], "mana man": "wizard", "mana": "magic", "mana bang-bang": "spell", "mahg": "make", "mannarz": "manner", - "brainz": ["brain", "intelligence", "smart", "hungry", "hunger", "eat", "meat", "desert"], + "brainz": [ + "brain", + "intelligence", + "smart", + "hungry", + "hunger", + "eat", + "meat", + "desert" + ], "harman": ["human", "food", "person", "groceries"], "harmanz": ["crew", "people", "humans"] - } + } } diff --git a/tgui/.editorconfig b/tgui/.editorconfig deleted file mode 100644 index d1d8a4176a4..00000000000 --- a/tgui/.editorconfig +++ /dev/null @@ -1,10 +0,0 @@ -# http://editorconfig.org -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true diff --git a/tgui/.prettierignore b/tgui/.prettierignore index 336b5d38f16..97d37c5a6fa 100644 --- a/tgui/.prettierignore +++ b/tgui/.prettierignore @@ -1,18 +1,6 @@ -## NPM -/**/node_modules - -## Yarn -/.yarn -/yarn.lock -/.pnp.* - -.swcrc -/docs -/packages/tgui-polyfill -/packages/tgfont/static -**/*.json -**/*.yml -**/*.md +.pnp.* +.yarn +node_modules # Avoid running on any bundles. /public/**/* diff --git a/tgui/docs/component-reference.md b/tgui/docs/component-reference.md index 673f30c8383..d261f4fb77a 100644 --- a/tgui/docs/component-reference.md +++ b/tgui/docs/component-reference.md @@ -110,7 +110,7 @@ with the `as` property. Let's say you want to use a `` instead: ```jsx - - + Button description + + + ``` @@ -474,12 +474,12 @@ Example: ```jsx - -
Hello world!
-
- -
Hello world!
-
+ +
Hello world!
+
+ +
Hello world!
+
``` @@ -524,8 +524,8 @@ Renders children icons on top of each other in order to make your own icon. ```jsx - - + + ``` @@ -621,7 +621,7 @@ column is labels, and second column is content. ```jsx - Content + Content ``` @@ -630,9 +630,9 @@ to perform some sort of action), there is a way to do that: ```jsx - Click me!}> - Content - + Click me!}> + Content + ``` @@ -669,8 +669,8 @@ Example: ```jsx - Content - + Content + ``` @@ -753,12 +753,12 @@ Usage of `ranges` prop: ```jsx ``` @@ -784,17 +784,17 @@ The RoundGauge component provides a visual representation of a single metric, as ```jsx ``` @@ -831,7 +831,7 @@ If you want to have a button on the right side of an section title ```jsx
Send shuttle}> - Here you can order supply crates. + Here you can order supply crates.
``` @@ -896,10 +896,10 @@ Stacks can be vertical by adding a `vertical` property. ```jsx - Button description - - - + Button description + + + ``` @@ -910,25 +910,25 @@ Make sure to use the `fill` property. ```jsx - - - -
Sidebar
-
- - - -
- Main content -
-
- -
Bottom pane
-
-
-
-
-
+ + + +
Sidebar
+
+ + + +
+ Main content +
+
+ +
Bottom pane
+
+
+
+
+
``` @@ -954,12 +954,12 @@ Example: ```jsx - - Hello world! - - Label - - + + Hello world! + + Label + +
``` @@ -1019,12 +1019,12 @@ Tabs also support a vertical configuration. This is usually paired with ```jsx - - ... - - - Tab content. - + + ... + + + Tab content. + ``` @@ -1034,8 +1034,8 @@ component: ```jsx
- ... - ... other things ... + ... + ... other things ...
``` @@ -1076,7 +1076,7 @@ Usage: ```jsx - Sample text. + Sample text. ``` @@ -1098,7 +1098,7 @@ Example: ```jsx - Hello, world! + Hello, world! ``` diff --git a/tgui/docs/converting-old-tgui-interfaces.md b/tgui/docs/converting-old-tgui-interfaces.md index a090fcfd155..ee9b74d6670 100644 --- a/tgui/docs/converting-old-tgui-interfaces.md +++ b/tgui/docs/converting-old-tgui-interfaces.md @@ -6,7 +6,7 @@ This guide is going to assume you already know roughly how tgui-next works, how Backend in almost every case does not require any changes. In particularly heavy ui cases, something to be aware of is the new `ui_static_data()` proc. This proc allows you to split some data sent to the interface off into data that will only be sent on ui initialize and when manually updated by elsewhere in the code. Useful for things like cargo where you have a very large set of mostly identical code. -Keep in mind that for uis where *all* data doesn't need to be live updating, you can just toggle off autoupdate for the ui instead of messing with static data. +Keep in mind that for uis where _all_ data doesn't need to be live updating, you can just toggle off autoupdate for the ui instead of messing with static data. ## Frontend @@ -23,7 +23,9 @@ Ractive has a fairly different templating syntax from React. You likely already know that React data inserts look like this ```jsx -{data.example_data} +{ + data.example_data; +} ``` Ractive looks very similar, the only real difference is that React uses one paranthesis instead of two. @@ -37,7 +39,7 @@ However, you may occasionally come across data inserts that instead of referenci `AnimatedNumber` is used like this ```jsx - + ``` Make sure you don't forget to import it. @@ -57,9 +59,9 @@ A ractive `if` (only render if result of expression is true) looks like this The equivalent React would be ```jsx -{!!data.condition && ( - Example Render -)} +{ + !!data.condition && Example Render; +} ``` This might look a bit intimidating compared to the reactive part but it's not as complicated as it seems: @@ -73,6 +75,7 @@ This might look a bit intimidating compared to the reactive part but it's not as You don't really need to know all this to understand how to use it, but I find it helps with understanding when things go wrong. Ractive conditionals can have an `else` as well + ```ractive {{#if data.condition}} value @@ -85,30 +88,28 @@ Similarly to the previous example, just add a `||` operator to handle the "falsy" condition: ```jsx -{!!data.condition && ( - - value - -) || ( - - other value - -)} +{ + (!!data.condition && value) || ( + other value + ); +} ``` There's also our good old friend - the ternary: ```jsx -{data.condition ? 'value' : 'other value'} +{ + data.condition ? 'value' : 'other value'; +} ``` Keep in mind you can also use tags here like the conditional example, and you can mix string literals, values, and tags as well. ```jsx -{data.is_robot ? ( -