From 7cab049dd195cdec3701523337b9d0d0ae79f7d4 Mon Sep 17 00:00:00 2001 From: Mothblocks <35135081+Mothblocks@users.noreply.github.com> Date: Fri, 10 Jun 2022 15:02:30 -0700 Subject: [PATCH] Screenshot tests (#67679) Adds screenshot visual testing workflow and scripts. --- .github/CODEOWNERS | 1 + .github/workflows/ci_suite.yml | 42 ++++ .../show_screenshot_test_results.yml | 43 ++++ .gitignore | 7 +- .../client/preferences/middleware/antags.dm | 12 +- code/modules/mob/living/carbon/human/dummy.dm | 3 +- code/modules/unit_tests/_unit_tests.dm | 3 + .../unit_tests/screenshot_antag_icons.dm | 12 + code/modules/unit_tests/screenshot_basic.dm | 8 + .../unit_tests/screenshot_humanoids.dm | 44 ++++ code/modules/unit_tests/screenshots/README.md | 18 ++ .../screenshot_antag_icons_abductor.png | Bin 0 -> 907 bytes .../screenshot_antag_icons_blob.png | Bin 0 -> 4696 bytes .../screenshot_antag_icons_blobinfection.png | Bin 0 -> 6287 bytes .../screenshot_antag_icons_bloodbrother.png | Bin 0 -> 2402 bytes .../screenshot_antag_icons_changeling.png | Bin 0 -> 898 bytes .../screenshot_antag_icons_clownoperative.png | Bin 0 -> 2004 bytes .../screenshot_antag_icons_cultist.png | Bin 0 -> 672 bytes ...eenshot_antag_icons_familyheadaspirant.png | Bin 0 -> 627 bytes .../screenshot_antag_icons_fugitive.png | Bin 0 -> 1988 bytes .../screenshot_antag_icons_gangster.png | Bin 0 -> 627 bytes ...reenshot_antag_icons_headrevolutionary.png | Bin 0 -> 2361 bytes .../screenshot_antag_icons_heretic.png | Bin 0 -> 624 bytes ...screenshot_antag_icons_hereticsmuggler.png | Bin 0 -> 624 bytes .../screenshot_antag_icons_loneoperative.png | Bin 0 -> 619 bytes .../screenshot_antag_icons_malfai.png | Bin 0 -> 528 bytes .../screenshot_antag_icons_malfaimidround.png | Bin 0 -> 528 bytes .../screenshot_antag_icons_nightmare.png | Bin 0 -> 617 bytes .../screenshot_antag_icons_obsessed.png | Bin 0 -> 3687 bytes .../screenshot_antag_icons_operative.png | Bin 0 -> 1895 bytes ...reenshot_antag_icons_operativemidround.png | Bin 0 -> 1895 bytes .../screenshot_antag_icons_opportunist.png | Bin 0 -> 741 bytes .../screenshot_antag_icons_provocateur.png | Bin 0 -> 2361 bytes .../screenshot_antag_icons_revenant.png | Bin 0 -> 923 bytes ...screenshot_antag_icons_sentientdisease.png | Bin 0 -> 389 bytes .../screenshot_antag_icons_spacedragon.png | Bin 0 -> 1226 bytes .../screenshot_antag_icons_spaceninja.png | Bin 0 -> 572 bytes ...nshot_antag_icons_syndicateinfiltrator.png | Bin 0 -> 821 bytes ...shot_antag_icons_syndicatesleeperagent.png | Bin 0 -> 821 bytes .../screenshot_antag_icons_thief.png | Bin 0 -> 741 bytes .../screenshot_antag_icons_traitor.png | Bin 0 -> 821 bytes .../screenshot_antag_icons_wizard.png | Bin 0 -> 800 bytes .../screenshot_antag_icons_wizardmidround.png | Bin 0 -> 800 bytes .../screenshot_antag_icons_xenomorph.png | Bin 0 -> 592 bytes .../screenshots/screenshot_basic_red.png | Bin 0 -> 218 bytes ...shot_humanoids__datum_species_abductor.png | Bin 0 -> 1125 bytes ...nshot_humanoids__datum_species_android.png | Bin 0 -> 1095 bytes ...shot_humanoids__datum_species_dullahan.png | Bin 0 -> 913 bytes ...shot_humanoids__datum_species_ethereal.png | Bin 0 -> 2670 bytes ...creenshot_humanoids__datum_species_fly.png | Bin 0 -> 1080 bytes ...eenshot_humanoids__datum_species_golem.png | Bin 0 -> 1886 bytes ...anoids__datum_species_golem_adamantine.png | Bin 0 -> 2175 bytes ...t_humanoids__datum_species_golem_alloy.png | Bin 0 -> 1447 bytes ...umanoids__datum_species_golem_bananium.png | Bin 0 -> 2175 bytes ...manoids__datum_species_golem_bluespace.png | Bin 0 -> 2175 bytes ...ot_humanoids__datum_species_golem_bone.png | Bin 0 -> 927 bytes ..._humanoids__datum_species_golem_bronze.png | Bin 0 -> 2175 bytes ...manoids__datum_species_golem_cardboard.png | Bin 0 -> 1011 bytes ...t_humanoids__datum_species_golem_cloth.png | Bin 0 -> 918 bytes ...humanoids__datum_species_golem_diamond.png | Bin 0 -> 2175 bytes ...anoids__datum_species_golem_durathread.png | Bin 0 -> 1002 bytes ...t_humanoids__datum_species_golem_glass.png | Bin 0 -> 4087 bytes ...ot_humanoids__datum_species_golem_gold.png | Bin 0 -> 2043 bytes ...humanoids__datum_species_golem_leather.png | Bin 0 -> 1917 bytes ...manoids__datum_species_golem_mhydrogen.png | Bin 0 -> 2020 bytes ..._humanoids__datum_species_golem_plasma.png | Bin 0 -> 2175 bytes ...umanoids__datum_species_golem_plasteel.png | Bin 0 -> 1927 bytes ...humanoids__datum_species_golem_plastic.png | Bin 0 -> 2098 bytes ...oids__datum_species_golem_plastitanium.png | Bin 0 -> 1794 bytes ...t_humanoids__datum_species_golem_runic.png | Bin 0 -> 948 bytes ...ot_humanoids__datum_species_golem_sand.png | Bin 0 -> 2175 bytes ..._humanoids__datum_species_golem_silver.png | Bin 0 -> 2020 bytes ...ot_humanoids__datum_species_golem_snow.png | Bin 0 -> 1908 bytes ...umanoids__datum_species_golem_titanium.png | Bin 0 -> 2098 bytes ...humanoids__datum_species_golem_uranium.png | Bin 0 -> 2175 bytes ...ot_humanoids__datum_species_golem_wood.png | Bin 0 -> 2039 bytes ...eenshot_humanoids__datum_species_human.png | Bin 0 -> 1075 bytes ...humanoids__datum_species_human_felinid.png | Bin 0 -> 1129 bytes ...s__datum_species_human_krokodil_addict.png | Bin 0 -> 1146 bytes ...eenshot_humanoids__datum_species_jelly.png | Bin 0 -> 2444 bytes ...noids__datum_species_jelly_luminescent.png | Bin 0 -> 2484 bytes ...t_humanoids__datum_species_jelly_slime.png | Bin 0 -> 2206 bytes ...manoids__datum_species_jelly_stargazer.png | Bin 0 -> 2444 bytes ...enshot_humanoids__datum_species_lizard.png | Bin 0 -> 1419 bytes ...anoids__datum_species_lizard_ashwalker.png | Bin 0 -> 1079 bytes ...oids__datum_species_lizard_silverscale.png | Bin 0 -> 1153 bytes ...enshot_humanoids__datum_species_monkey.png | Bin 0 -> 806 bytes ...reenshot_humanoids__datum_species_moth.png | Bin 0 -> 1743 bytes ...reenshot_humanoids__datum_species_mush.png | Bin 0 -> 853 bytes ...hot_humanoids__datum_species_plasmaman.png | Bin 0 -> 2468 bytes ...creenshot_humanoids__datum_species_pod.png | Bin 0 -> 1253 bytes ...enshot_humanoids__datum_species_shadow.png | Bin 0 -> 1066 bytes ...anoids__datum_species_shadow_nightmare.png | Bin 0 -> 1111 bytes ...shot_humanoids__datum_species_skeleton.png | Bin 0 -> 2529 bytes ...eenshot_humanoids__datum_species_snail.png | Bin 0 -> 2674 bytes ...nshot_humanoids__datum_species_vampire.png | Bin 0 -> 1075 bytes ...enshot_humanoids__datum_species_zombie.png | Bin 0 -> 1142 bytes ...noids__datum_species_zombie_infectious.png | Bin 0 -> 1142 bytes code/modules/unit_tests/unit_test.dm | 24 ++ tools/ci/run_server.sh | 5 + tools/ci/show_screenshot_test_results.js | 236 ++++++++++++++++++ tools/screenshot-test-comparison/index.js | 103 ++++++++ .../package-lock.json | 51 ++++ tools/screenshot-test-comparison/package.json | 12 + 104 files changed, 616 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/show_screenshot_test_results.yml create mode 100644 code/modules/unit_tests/screenshot_antag_icons.dm create mode 100644 code/modules/unit_tests/screenshot_basic.dm create mode 100644 code/modules/unit_tests/screenshot_humanoids.dm create mode 100644 code/modules/unit_tests/screenshots/README.md create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_abductor.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_blob.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_blobinfection.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_changeling.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_clownoperative.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_cultist.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_familyheadaspirant.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_fugitive.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_gangster.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_heretic.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_hereticsmuggler.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_loneoperative.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_malfai.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_malfaimidround.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_nightmare.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_operative.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_operativemidround.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_opportunist.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_provocateur.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_revenant.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_sentientdisease.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_spacedragon.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_spaceninja.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_syndicateinfiltrator.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_syndicatesleeperagent.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_thief.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_traitor.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_wizard.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_wizardmidround.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_xenomorph.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_basic_red.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_abductor.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_android.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_dullahan.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_ethereal.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_fly.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_adamantine.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_alloy.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_bananium.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_bluespace.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_bone.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_bronze.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_cardboard.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_cloth.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_diamond.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_durathread.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_glass.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_gold.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_leather.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_mhydrogen.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_plasma.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_plasteel.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_plastic.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_plastitanium.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_runic.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_sand.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_silver.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_snow.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_titanium.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_uranium.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_wood.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_felinid.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_krokodil_addict.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_luminescent.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_slime.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_stargazer.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_silverscale.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_moth.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_mush.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_plasmaman.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_pod.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_shadow.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_shadow_nightmare.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_skeleton.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_snail.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vampire.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_zombie.png create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_zombie_infectious.png create mode 100644 tools/ci/show_screenshot_test_results.js create mode 100644 tools/screenshot-test-comparison/index.js create mode 100644 tools/screenshot-test-comparison/package-lock.json create mode 100644 tools/screenshot-test-comparison/package.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0ef110cffd6..e678497f5e6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -45,6 +45,7 @@ /code/modules/preferences_menu.dm @Mothblocks /code/modules/preferences_savefile.dm @Mothblocks /tgui/packages/tgui/interfaces/PreferencesMenu/ @Mothblocks +/tools/screenshot-test-comparison/ @Mothblocks # MrMelbert diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index edc81edcb13..86baaafacbd 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -132,6 +132,48 @@ jobs: run: | source $HOME/BYOND/byond/bin/byondsetup bash tools/ci/run_server.sh ${{ matrix.map }} + - name: Upload screenshot tests + if: always() + uses: actions/upload-artifact@v3 + with: + name: test_artifacts_${{ matrix.map }} + path: data/screenshots_new/ + retention-days: 1 + + compare_screenshots: + if: "!contains(github.event.head_commit.message, '[ci skip]') && always()" + needs: [run_all_tests] + name: Compare Screenshot Tests + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + # If we ever add more artifacts, this is going to break, but it'll be obvious. + - name: Download screenshot tests + uses: actions/download-artifact@v3 + with: + path: artifacts + - name: ls -R + run: ls -R artifacts + - name: Setup screenshot comparison + run: npm i + working-directory: tools/screenshot-test-comparison + - name: Run screenshot comparison + run: node tools/screenshot-test-comparison/index.js artifacts code/modules/unit_tests/screenshots artifacts/screenshot_comparisons + # workflow_run does not give you the PR it ran on, + # even through the thing literally named "matching pull requests". + # However, in GraphQL, you can check if the check suite was ran + # by a specific PR, so trusting the (user controlled) action here is okay, + # as long as we check it later in show_screenshot_test_results + - name: Save PR ID + if: failure() && github.event.pull_request + run: | + echo ${{ github.event.pull_request.number }} > artifacts/screenshot_comparisons/pull_request_number.txt + - name: Upload bad screenshots + if: failure() + uses: actions/upload-artifact@v3 + with: + name: bad-screenshots + path: artifacts/screenshot_comparisons test_windows: if: "!contains(github.event.head_commit.message, '[ci skip]')" diff --git a/.github/workflows/show_screenshot_test_results.yml b/.github/workflows/show_screenshot_test_results.yml new file mode 100644 index 00000000000..3e9125510b7 --- /dev/null +++ b/.github/workflows/show_screenshot_test_results.yml @@ -0,0 +1,43 @@ +# This is a separate workflow so that it can access secrets, which are necessary +# because we need to be able to upload the images and post a comment. +# In the event this workflow fails, the screenshot test results are still +# available as an artifact of the screenshot test comparison workflow itself. +# This simply provides necessary quality of life. +name: Show Screenshot Test Results +on: + workflow_run: + workflows: [CI Suite] + types: + - completed +jobs: + show_screenshot_test_results: + if: "!contains(github.event.head_commit.message, '[ci skip]')" + name: Show Screenshot Test Results + runs-on: ubuntu-20.04 + steps: + - name: "Check for ARTIFACTS_FILE_HOUSE_KEY" + id: secrets_set + env: + ENABLER_SECRET: ${{ secrets.ARTIFACTS_FILE_HOUSE_KEY }} + run: | + unset SECRET_EXISTS + if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi + echo "::set-output name=SECRETS_ENABLED::$SECRET_EXISTS" + - name: Checkout + if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: actions/checkout@v3 + - name: Prepare module + if: steps.secrets_set.outputs.SECRETS_ENABLED + 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: Show screenshot test results + if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: actions/github-script@v6 + env: + FILE_HOUSE_KEY: ${{ secrets.ARTIFACTS_FILE_HOUSE_KEY }} + with: + script: | + const { showScreenshotTestResults } = await import('${{ github.workspace }}/tools/ci/show_screenshot_test_results.js') + await showScreenshotTestResults({ github, context, exec }) diff --git a/.gitignore b/.gitignore index 44537f0a6b7..10cdcfb1349 100644 --- a/.gitignore +++ b/.gitignore @@ -197,5 +197,8 @@ Temporary Items /tools/LinuxOneShot/TGS_Instances /tools/LinuxOneShot/TGS_Logs -# Autowiki -/tools/autowiki/node_modules +# JavaScript tools +**/node_modules + +# Screenshot tests +/artifacts diff --git a/code/modules/client/preferences/middleware/antags.dm b/code/modules/client/preferences/middleware/antags.dm index b782397fd5b..08936bcd23e 100644 --- a/code/modules/client/preferences/middleware/antags.dm +++ b/code/modules/client/preferences/middleware/antags.dm @@ -110,6 +110,9 @@ early = TRUE cross_round_cachable = TRUE + /// Mapping of spritesheet keys -> icons + var/list/antag_icons = list() + /datum/asset/spritesheet/antagonists/create_spritesheets() // Antagonists that don't have a dynamic ruleset, but do have a preference var/static/list/non_ruleset_antagonists = list( @@ -128,7 +131,6 @@ antagonists[initial(ruleset.antag_flag)] = antagonist_type var/list/generated_icons = list() - var/list/to_insert = list() for (var/antag_flag in antagonists) var/datum/antagonist/antagonist_type = antagonists[antag_flag] @@ -137,7 +139,7 @@ var/spritesheet_key = serialize_antag_name(antag_flag) if (!isnull(generated_icons[antagonist_type])) - to_insert[spritesheet_key] = generated_icons[antagonist_type] + antag_icons[spritesheet_key] = generated_icons[antagonist_type] continue var/datum/antagonist/antagonist = new antagonist_type @@ -152,10 +154,10 @@ // If an icon is not prepared to be scaled to that size, it looks really ugly, and this // makes it harder to figure out what size it *actually* is. generated_icons[antagonist_type] = preview_icon - to_insert[spritesheet_key] = preview_icon + antag_icons[spritesheet_key] = preview_icon - for (var/spritesheet_key in to_insert) - Insert(spritesheet_key, to_insert[spritesheet_key]) + for (var/spritesheet_key in antag_icons) + Insert(spritesheet_key, antag_icons[spritesheet_key]) /// Serializes an antag name to be used for preferences UI /proc/serialize_antag_name(antag_name) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index c8cc678f10d..ae1dd2b4c84 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -102,7 +102,8 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) dna.features["snout"] = "Round" dna.features["spines"] = "None" dna.features["tail_cat"] = "None" - dna.features["tail_lizard"] = "Light" + dna.features["tail_lizard"] = "Smooth" + dna.features["pod_hair"] = "Ivy" //Inefficient pooling/caching way. GLOBAL_LIST_EMPTY(human_dummy_list) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 2b3918a9531..699f215d0e0 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -129,6 +129,9 @@ #include "reagent_recipe_collisions.dm" #include "resist.dm" #include "say.dm" +#include "screenshot_antag_icons.dm" +#include "screenshot_basic.dm" +#include "screenshot_humanoids.dm" #include "security_officer_distribution.dm" #include "serving_tray.dm" #include "siunit.dm" diff --git a/code/modules/unit_tests/screenshot_antag_icons.dm b/code/modules/unit_tests/screenshot_antag_icons.dm new file mode 100644 index 00000000000..0a210ae31ed --- /dev/null +++ b/code/modules/unit_tests/screenshot_antag_icons.dm @@ -0,0 +1,12 @@ +/// A screenshot test to make sure every antag icon in the preferences menu is consistent +/datum/unit_test/screenshot_antag_icons + +/datum/unit_test/screenshot_antag_icons/Run() + var/datum/asset/spritesheet/antagonists/antagonists = get_asset_datum(/datum/asset/spritesheet/antagonists) + + for (var/antag_icon_key in antagonists.antag_icons) + var/icon/reference_icon = antagonists.antag_icons[antag_icon_key] + + var/icon/icon = new() + icon.Insert(reference_icon, null, SOUTH, 1) + test_screenshot(antag_icon_key, icon) diff --git a/code/modules/unit_tests/screenshot_basic.dm b/code/modules/unit_tests/screenshot_basic.dm new file mode 100644 index 00000000000..350514f007f --- /dev/null +++ b/code/modules/unit_tests/screenshot_basic.dm @@ -0,0 +1,8 @@ +/// This is an example for screenshot tests, and a meta-test to make sure they work in the success case. +/// It creates a picture that is red on the left side, green on the other. +/datum/unit_test/screenshot_basic + +/datum/unit_test/screenshot_basic/Run() + var/icon/red = icon('icons/blanks/32x32.dmi', "nothing") + red.Blend(COLOR_RED, ICON_OVERLAY) + test_screenshot("red", red) diff --git a/code/modules/unit_tests/screenshot_humanoids.dm b/code/modules/unit_tests/screenshot_humanoids.dm new file mode 100644 index 00000000000..196d946cb12 --- /dev/null +++ b/code/modules/unit_tests/screenshot_humanoids.dm @@ -0,0 +1,44 @@ +/// A screenshot test for every humanoid species with a handful of jobs. +/datum/unit_test/screenshot_humanoids + +/datum/unit_test/screenshot_humanoids/Run() + // Test lizards as their own thing so we can get more coverage on their features + var/mob/living/carbon/human/lizard = allocate(/mob/living/carbon/human/dummy/consistent) + lizard.dna.features["mcolor"] = "#099" + lizard.dna.features["tail_lizard"] = "Light Tiger" + lizard.dna.features["snout"] = "Sharp + Light" + lizard.dna.features["horns"] = "Simple" + lizard.dna.features["frills"] = "Aquatic" + lizard.dna.features["legs"] = "Normal Legs" + lizard.set_species(/datum/species/lizard) + lizard.equipOutfit(/datum/outfit/job/engineer) + test_screenshot("[/datum/species/lizard]", get_flat_icon_for_all_directions(lizard)) + + // let me have this + var/mob/living/carbon/human/moth = allocate(/mob/living/carbon/human/dummy/consistent) + moth.dna.features["moth_antennae"] = "Firewatch" + moth.dna.features["moth_markings"] = "None" + moth.dna.features["moth_wings"] = "Firewatch" + moth.set_species(/datum/species/moth) + moth.equipOutfit(/datum/outfit/job/cmo, visualsOnly = TRUE) + test_screenshot("[/datum/species/moth]", get_flat_icon_for_all_directions(moth)) + + // The rest of the species + for (var/datum/species/species_type as anything in subtypesof(/datum/species) - /datum/species/moth - /datum/species/lizard) + test_screenshot("[species_type]", get_flat_icon_for_all_directions(make_dummy(species_type, /datum/outfit/job/assistant/consistent))) + +/datum/unit_test/screenshot_humanoids/proc/get_flat_icon_for_all_directions(atom/thing) + var/icon/output = icon('icons/effects/effects.dmi', "nothing") + COMPILE_OVERLAYS(thing) + + for (var/direction in GLOB.cardinals) + var/icon/partial = getFlatIcon(thing, defdir = direction, no_anim = TRUE) + output.Insert(partial, dir = direction) + + return output + +/datum/unit_test/screenshot_humanoids/proc/make_dummy(species, job_outfit) + var/mob/living/carbon/human/dummy/consistent/dummy = allocate(/mob/living/carbon/human/dummy/consistent) + dummy.set_species(species) + dummy.equipOutfit(job_outfit, visualsOnly = TRUE) + return dummy diff --git a/code/modules/unit_tests/screenshots/README.md b/code/modules/unit_tests/screenshots/README.md new file mode 100644 index 00000000000..1d50a4e5612 --- /dev/null +++ b/code/modules/unit_tests/screenshots/README.md @@ -0,0 +1,18 @@ +This folder contains the results for screenshot tests. Screenshot tests make sure an icon looks the same as it did before a change to prevent regressions. + +You can create one by simply using the `test_screenshot` proc. + +This example test screenshots a red image and keeps it. + +```dm +/// This is an example for screenshot tests, and a meta-test to make sure they work in the success case. +/// It creates a picture that is red on the left side, green on the other. +/datum/unit_test/screenshot_basic + +/datum/unit_test/screenshot_basic/Run() + var/icon/red = icon('icons/blanks/32x32.dmi', "nothing") + red.Blend(COLOR_RED, ICON_OVERLAY) + test_screenshot("red", red) +``` + +Unfortunately, screenshot tests are sanest to test through a pull request directly, due to limitations with both DM and GitHub. diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_abductor.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_abductor.png new file mode 100644 index 0000000000000000000000000000000000000000..c0503326ddb194e9c30b1889ff7f93966e89c330 GIT binary patch literal 907 zcmV;619bd}P)mBPAFY8MGfCW-|avN=jyBVNg#? zLP10@Ffav(c&GpX00DGTPE!Ct=GbNc003lqR9JLGWpiV4X>fFDZ*Bkpc$`yKaB_9` z^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGEX}w$Gg33tGfE(w;*!LYR3KAHiHkEO zv#1!zH00t;D@x2wg|L+sT>V_YCISGS$rvAshC*oo00LJ@L_t(&f$f-WZ`&{ogp;+Y zS9hMXyx2{Xt!cRk60DFL_& z@Bks*7pQ`eTwNmjOQJNPh6~JLp320`>S|PV4!|hjD^%CDe3f_6t3NC>Cpf3-vN#GS zdJ_OFmrG99I-rnMy}@;Wz@;(XAYGOI^8+vn&{Sg-wQDGO2B~@wC9gWu{&T=LXti3^ z{_s@_46f*WH#u{`$8?M=FG?1i+A0Dt3_!DnHk-{B%8CpNgBv>g3`@>Py%|dnOz%-(xEa}z-3xmztl5ivgz~Wl6z$Ps(f0rtf%WX1%wr%;`9$m07*a|Q=h>~wL zVu5XTmeV;;k-UZkU=)DaD)PLiRAgoB0=5>}3`H_xG62<}t5gH63=~GqqefH%P3HpW zMh4(205n=;Rd%=AsoC}SBAs4zvd;FR0Q@Py6SUv&3D{ek0d%L)%YfFT060Voko}GI zuTB8nPO|T9x}6A+&eJAZisT7B0HXj*rG+zGx}h8n2laTeqtnjXwHW-Eq=Pto-=QB6 znrG<6Wq}g_;4$%!t*6N+j-5bNd4=fo+aUpL!C=8Yrwm<$bc&Hr?VzjcZB&q~Y= zg8XS7Aqb?uF3QjO;XNP!d)^PIsDiO@OP_}UCx>t!($NsSii)kwP*)ofjNP`o=fm3~^vwq+KTQ`xdcm9Hg|eyVNq=u1y@5mMkK4)b&pSB12?;p}S9h zh1+rQC>%XE&N!}(*k~?0M~hMUQ?((*PY>S}-740+&FlsgxjV6WY&dkU@B;#8W3*@^ zb%`a65xTj7`}B0SE)v|4Pq7$w2I#vzoGS2ytE}3GtErFRjv@i`10efn!F}x7dQK0L zbxRHu8^bkm*_px9+e^(n_0^@lCq6sBkU2P114Lw<;GmJPTljh$*61Bd^^3Q-8vcaI zH0w3(WtqS93=s4^3?p^6Upity*m!Ho^?dGrR$MN%ono~=+tR09LCV6}ZMJofr7_FE zuHP2PNL}O=X8Y*5{Rn`WDUref!Jpuanwv7b)C5NuKU)J`7eu+V3hP!SRtur8D*VGi zK~cT0rChY>TyGG-9id7AD{8CD_hYQ}{{R5}1t1j!Bu9Q*F)zJ+mLF>_q~KFYuo9=U zf|OqxW$B#F6G zw13Sg6IkzBT{9%lvR=`38cWf*pv`h*Jzt(S$(0WVr9y!HlTWkY#BMo>kQGMI2RXks z+q+{e|1KxQYu78Evf^VS$qfIvm7f~CAz$aC0o8cn!@)X=cPV(>M7Hh>pqHpRAsoA+ zzgA2r0K7d?Qoky^C`zmy^Gh6cd1yMHX&$$i^DN7~&-=pk)XYS2_k7kh+?|^AMmKgm z22wT*;8!2zrbC7RD+;nI9cS1zlF8TdBqpAQ?0N00pm)ib^7ah!UakTQJin9UW)GGs zR`0%@nc+801vZ}N!8!46P&vi!dWov)6CpyOL}GOCh3UBV#?)qxoyX^hY$eOazL!I3 zO1sLtxFzKVOVYc%^`P}^?_5?&So{c79c1R%+q zv5xwbEP%z-^5girD3YRaKGKwQe}Jq#gJTPqqQ&|#u{rs%0D=kOQ2&8wPQ5eDkT{>n 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 anTC`Qq)9g|`OjAom7yL?w@Sw$=6?Xd*Wx|^ literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_blobinfection.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_blobinfection.png new file mode 100644 index 0000000000000000000000000000000000000000..e3d7acbf5d891f24b1c97f51d6b646d419f1038c GIT binary patch literal 6287 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 Y--O^W2KT+z8UO$Q07*qoM6N<$g8htvUjP6A literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_clownoperative.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_clownoperative.png new file mode 100644 index 0000000000000000000000000000000000000000..d61c10e74871c60a24a3573afb470553fdf7996a GIT binary patch literal 2004 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 N002ovPDHLkV1mkI5>)^I literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_fugitive.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_fugitive.png new file mode 100644 index 0000000000000000000000000000000000000000..d1187a14d8491f36b021cd52a262e9e1a074e147 GIT binary patch literal 1988 zcmY*adpr|t8=j=G9Ls4c#P^03uPmoBIcMguW~^R5hrAS-(>5g0fhIY`YY~$}Xj2X; zljZbMG-;UAYsi_z#5=ZW==0_K^?l#(_uS9@{Bu9Q`?;>`zMgwX=W|jZ6%YUbkb>LW zpmws)ze9ZA&OVhBWwMikV$c`xHvTxjh`=y>U}y*c5KVS<4~ro1*IdI^*JmIIT?n(Q z+qK$FzZW_&b)wr*hk>kit3EY7)n)(Dv0M9ASTf=O0;LeFkd^h?#MR(_^3GAR-lQ-2 z0M7Mju)i4Qtdf|Lw~HR&F+*9+5f88j0DuZ`8%uOFnM1xBjJB2UxXdZjwY^eg>vgMX zNkt+#VHvXLBuf9!oWgw~hw@}kiAW9>4k#zpxWVn!kGiK8!>v&i5hrnpc1r&_hx0Tn z`)&tO41^F3p+3}0w1St$vFqo_Jn5H+*_Fvn^L$^`s7}V_d{;dVqhl$%_y3k)d^OBv z!s{}U>NCm%TrYVYS^|_mV12kH#pEW~<(=R3?bTM^;0H^7nWkv$r?Hp-jRdQrLhOiz zy3g34)J2i5B+;DJxtRPtBqH+_8as5DV?#LBsalZ4c3x_xVg(I05*UmWo3>t|R|k4Q zoe^xsEpD_lF*-Az0|MUemfP(kTd_+{QX<;5&s9?^^R(Z?J7nODp2(Tl^z|9a+&oif zFfwTFN$h z-rigq)sswQWstll*l7;ZV!Tq6ySzBM9V;y48p-Osv~>qSr+&0isE=Rke?h64#CO&D zJ(u|^@d%vux(@GYOW1BWf$h_O)yxrR&D-PtfX)e4DOmP%ty)-grPRQ+zXN*1YsYZ3 zBLic>XKGAC;=itATImP#>yRT+FY{{izkT*Z*L^SH##;zEo;ivMvxa)1eZPz8YfArU z`83ex`@7*!*JJ{M@|J-}t`2TL^!znI3Zh#C$t9s6SkJV@*J!>IVTEkbkRFt#-m z$7B>w#4~8m%E$Q?G$rh?B_9kU7GEMiFyj1jZwY#zwj>VOzl+4ae1zsqDaI&T$E6K< zP;|z|sUvaeViD3$&GBaBR}1VD4)1G~f#rBRK>(iY3mcWvKIGtk_u)}wWbiLUjpH}L z;XimZdm~K-weMG$eTJN!lhCSlBADS~6d`#b=IF?eJv=R!Q^9u$=9?^pf=hToFekjj ztAVFpF5LJqkF3X+2~C{Tso>>y0v9vr4nf%Yn}*72nWYwtD}#z^Mr?I=(Uk-0PlJ~l zWmA+Q<}rnx?Z;R3*#b>0G zu?ffpdz;P)=mOU<6HUkXni??DI+ii&KUI`s%nJXr)Afr4*jAQF&7Pc{*WF>h ze9}I#9@RM1yB}hTrWYH2Abbu4ad?@F`2{2&3H`+9vMNm>9tTvLiVTPk@#gY^y8gpT~(U?2U|S^XU~*|wIfJ^kUO)pK!}yTa6d(+S6m5%Yjts|y8p zTs2ohZ^aW)4kQ&6b4^-pb6`xi+W*INwckfcdZZtNAs2_3#^=kfuWe-)Yj=6L&o|9{ zwNw65wGH_AloZPf`ljau`(CpM4O9ljGwo1veA!(`h(7y0DEsQ{CPQespgV1`m7O1E zFbEs09ov9jKEL6nCT)G$1s5DM46^Ebe;qN}hKw05FKxSFZu>4;CW&w+e{!6XW$-Ds z(D%w~I)qXn!2|ziJhgmJm^OQyw@F220O9cX@`AI*L znT$#2-s8yDJE$LunQbw4ZoZUJczxfl(tA|H1XW6zs+5^V&{hC7WHA!oKs+t%oArtr zSFNp;vJNcE3NUkOflZQr4eE)FtU7MZy+!}-djlHuMy^CY4)HY`M08IAI!@ld+e+~bN02DIRX zDnD4D3=z6#1E-A~5xY*D!k;82<3-|R!nAVQZ*{vmP_?&<#|63~j>bJ}w-;WzP3Om3 s4V60c9aVhAo zkXJ}+Bdm>et`o#&EX5|*S+Bi?X~e=p_8FX=>|HLKfQ4|m!~Bc8*)YE&7xp7bvdJd@ zDQT~$w&rCUfKqC^sJpN$_i&SRxS>{{6e1oJqzirRQvz<@;f4xn9O(FV6yk@ekJfVQ z6;GQbJhDdMzh;`k{%|-1;L9cKrIq&90RH(aps(8p5P1$A1Hfp+7eA#C*AAGRnw!j+ zEHl^o1X~KUKFfT#SQl7Wg+%nAL(X|nZI8B@h618I&z}o$!Gj8E1sG@n1(A}dTobhd zAp`CSpb`&cN-dqD8}K_wk}w?>$%MkkM{#>2fvilWV&IP$UaNOY{fz{Ee-SXDkjDVH zTnpe+WNfUB-@#fwTgK+91wbkLI(;+F#lSgZrtkJ8o=bHA_hk&fgY-Q?o&!kf-@)9v zkH!Ppy${{DMTA-WpEwDkweEAp-rY!09_&Q-Km;J=sw1&xkVpA5_yHYiUY%uW>@NTS N002ovPDHLkV1mkI5>)^I literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png new file mode 100644 index 0000000000000000000000000000000000000000..7a1b6f6913d1d97d26e26ed73c9ede48148178ed GIT binary patch literal 2361 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 Mp(UzP|MIQ>0wFwWjQ{`u literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_heretic.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_heretic.png new file mode 100644 index 0000000000000000000000000000000000000000..73bc5e02dd39ca40d4bba1713c6d82ff2ef08201 GIT binary patch literal 624 zcmV-$0+0QPP)C2t+NS^i z$98wPWIklv=?J%fTa0x9WOfc>aU|H$|U0xWeYKymVL zP5;cG;Ftgf9&n{zrH8>oCnp8f^wlLLRMlDdu^Y^53swO*AoK3(lJT5_f@(VA;%}_;^r4lB{|zSeE5m2#(9<&5nXy0!f8HiG>bXef}uT zk8l-&W06{`VDlf&X#`WKgHPUtTkx1Ge}!uRyT!x*$rS7o$QOMeMp{!AStC^C2t+NS^i z$98wPWIklv=?J%fTa0x9WOfc>aU|H$|U0xWeYKymVL zP5;cG;Ftgf9&n{zrH8>oCnp8f^wlLLRMlDdu^Y^53swO*AoK3(lJT5_f@(VA;%}_;^r4lB{|zSeE5m2#(9<&5nXy0!f8HiG>bXef}uT zk8l-&W06{`VDlf&X#`WKgHPUtTkx1Ge}!uRyT!x*$rS7o$QOMeMp{!AStC^Mg2;B@Uc{%=b6Db2FSxRiF|4^On|BHIb+2>wwrIp&rnEEI&i+sTYiBZK2BxW-m z4ARtWgaHuQGyH$pjoGpziV?7uCv-Sa(J^1yAOQC;d&<%@%Vv-6E=oXzr}FA+N!}60 z2oT9fmGrZ`wJE-313-q@qAJs;{TBZ40Beg+ASya3zSlFjV)^bMuG#@ z9WwxRd7UFS1S5trh9DAfY0=}{X4H4=LmUcPXyy2~KF_tRB?ODk zrQm?MQ2QfaKKMCmx(ECRfV;iJm44(ugT26@@p94x`~b{F1a6JqB-H=_002ovPDHLk FV1oNb{;~i7 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_malfai.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_malfai.png new file mode 100644 index 0000000000000000000000000000000000000000..993fbc0b308a1e0214d0e4345194be5cc2295544 GIT binary patch literal 528 zcmV+r0`L8aP)PUYz!1k6rzu8}5JWg;{STEk2-NQk5srW$MbA`M z021~++QtAa18T0SjSstI5CD>rT13Cbs8LEx-7qMSUVe&lh3fBXG zfKy1ReF|J(Ot5YnK!{H@PQy6!QdqYP=#;)ylvVyKu6G6){Kb9=F!;~ORp1RyFzs-H SIzm|h0000PUYz!1k6rzu8}5JWg;{STEk2-NQk5srW$MbA`M z021~++QtAa18T0SjSstI5CD>rT13Cbs8LEx-7qMSUVe&lh3fBXG zfKy1ReF|J(Ot5YnK!{H@PQy6!QdqYP=#;)ylvVyKu6G6){Kb9=F!;~ORp1RyFzs-H SIzm|h0000fFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM z;w;ZhDainGEX}w$Gg33tGfE(w;*!LYR3KAHiHkEOv#1!zH00t;D@x2wg|L+sT>V_Y zCISGS$rvAshC*oo00DhTL_t(oh3%FxPQySDMUBD*oFi;F0I;Ty;<13*EXoN|(`}K4 zjxFiXas)#`?*mYfo(A8AKjWpcfk-G}EqR*VVxFR}dFxD)j5XF+WBt7j(lk|S$iPIO zpj|0_91EZ`$~6}e%?AmfuQ1muqSXqQQV$lmB4dbff{ZN2IiAbbo!6g}p_f@1NsaN{9l+(zmQU&D({hF>2A9}5F?Puw;Edp z10i&-S#WpP8#+FK7V3zS1gU31DgX<`&(`}soAv~xsp#EGB^l}(dOucA^$-BG<1Huv zELCtx1F)7Z{X=&Wy9Z!In?ZIB0on}CRnMEZZiWZ}tn^dG`%?J6$iXgI+k9+ZdjyXV zXiIj!QisqCG)?nv*FB;41uzmew{U41OyTAG{$GGky2bkq%_Ck200000NkvXXu0mjf D){y#i literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png new file mode 100644 index 0000000000000000000000000000000000000000..1d5f88bd8407fcffff9fff9779712981cdf15bc9 GIT binary patch literal 3687 zcmaJ^XH*kP(+*WY=|u$u6hx%=-lZ6+5-9h^SQQNEafVfDn)t z0-+-kBoHA6-`xA%-`}3I`|OW7yEC(MW}he3+|-bfftvvU05AgY>sgS|>7PkQOJ3LW z!<5P39r?&6SkEo!NuXCiu$TW+03f^=WEBt?LcoIpj!rg2jU+@T$C020OX+Dj%(^(z z`0j{#gJpv}c76Q*gfUViAt23&&B%h&moq1)T^S^so<`nY=}?|YV+#V^^mU`L*1Ae_ z)zM56P%?6j-#8d>pX^OLP*3Mkc=16|RDeAyW=Jc{aq;nicO{A_0j^ho@oP)B`nufF z7HFhT_~of9=bk}XUb`>dOa+oHe>-*aOz_3f)LpvD0w$=}zAk^O?~|(;^n<@s8+^fy zHK+j}VD$>>Nm$EaH)&wY8+q%xl3?T0AT7DVvywBk#`ZF4_s?X=u{*qD=KRWDkJMVuHDqti+Pnds1{oY%9gubgKAuGbU**A4P^ zne;wuvcU>Jj1A$7OIsTCr++!+VSox^Gy9go=e(~L-RDMO8Izax=!T`e0kRonAD~Ak zxQhe|XQubF`<#!lJgjvltFi68AMDtlpFZg4NkwqPjJ>|S$BRq(KWmPh$%`t!A|oKP zAA8p<-qqNyA{o@mr)@0Pb<~Ji`L%r6dLpJ;P+;Ia#lLrqTS6~yW0UTsytwV{6LH2F z*E+Llfq&vNXWv5jK#mW3G|^st0}NAm{5a(>X0y_x1W?>3i8(mUnjAsA*E+s;{PSv( ze9#J}o+IYnZ_TxD+a>651WNN{oI+pi>tB6b*1T_lSXT?FaaBj0i+I{k2dYQw3ai_wX=EPC@3*&d--m7gF38a_xJOLBAn1mRJ7- zk%rP%k8{HOfc2nDB)Ypbd{;wP3-$`XJ{E>XY{TQu=Pz-2V+s86&BcFbe%?qVAz?X2 z1HGJGt!{Clh>1V9v~C|lstO#>Oud2XII&6kBC`;FcwHS|W@yhF8%9}L*9CyK$wA8w zzN5LOmj?Q9JD~FpFBXf1^qw+nY2a{zX3>5ZGD@^(y8A9_49tgK2rt2W!&gk+>*MCOikzU5&^EnL606@fCk4jq+<`e zCz?I30AF7VIR!XLgXuB}AP2C%mkIl8p_^mwug2w7o(_J(M+&)6Q-YN6r>Dy}BE7aZ z`s%S1vIKY8EpA!SI{%^)qo8%(T+#XW;(CA7pQ3fSffaa6nyJB!#IVzo`K?9b#lUWN zF2x1OH~-F!Q{?7FxOm#}taGI1vOds3Qh(03uEU*XD2x9VZ|d4f#C7$Md^4t>gD^+q zP*aD|s*vGErt5<2eEefD32V@l?sq}b_v1Ppc)=J62zD2~Hpref(^#InRVW(yW}uk+ z=-X`j6?jYhR7TPB-iSO<%IS3Qiixq?4J?on+eXg#SgVb7jHvDnVDYD!&TUJdmJSAkX}?n5g*w3VOnMf&%TsDL`MrjVy|1 z$k@C;SWWIA=}MHR1rwv}=vptdE0#gOJ_f7OzZC1yW`0pM+M%+Bvi9dv_lxSRC~}N7 z!lCUttwgTA`&05`^^}*b>x8QJAzq8AMbs8=<> z7LKU~J}!ZQY`v?HfweyD5r#mdPZ=N|TQMy{3s0R+y{-x=bysER=@Ul-rBZEPBv!B) zBww2Ll$Tdj{5CZeFFrOtY5Hsnf3v;ajZxeM(7KGzi_)Ay8ftQORr&36XxO>1byd+q z7&bK`csNKuAaUa13P{cBolE@Z*%(s9(>in0=9atXXFcuT-A|nL59#Wx@EVmdt{&Uc za=U_<(*8q&940tXTuxCjdBIn>!1xxB?X{4zbfL-~uWo%d{dv{Y9)4Cy;>qU6{o#?3 zwdHu|yLaT`l;h5%tw!DV_h)`ftsTSCsn-&lm}#Q;c0q*ukY@Y{yo`NPe6T;@Doaj0 zU6O82ULG9fO;1bZ33O_@Mu#*7J+?FR!^*-G>nq;YB))EBsId|Qfk1;UGOtI3hGou) z#IH+gs%Eisb=>hrkM>p`Sy`1gfk!5h?%>CFf#9!B(&qN|#tsgAmMGN5_O@U)rmG2Z zfrbuZfucS)IP$DPHa2?FEPeY&0zkHYCziIQOsi^r7<+g(Ruhvu8;VlFu+@cA)Lmwm zmk-zZmff(48y+CAF%7+%4q6|KP>em`%8JEnLfPT>g@(my1cqQnmLZH}zLSxeDMQZH z{63=ijfp%r;%S@XGOLNfj#gA82MbzO!WN*IAqG!d-9z{#)bDLGG5%N}B{#@fo}ExS zFRk+-CH46iLi5a#Q_q=2&o7z>I#!s~1#&JQ_Bu|R30u+eq3)i4<7p^rYqf>&WA9wb z3MMt&vNj7bVVoF)Sy);onfmm(&&{9hSjlEpjnq+lbw07E)dl2^rxuvDz&xBbm0B2{y|?Ebt;r9E!-b&0FKf~& zbF%0KqGQ*^*SevZB}*!4W*P8MhbR4Z#qE6PO|<$C58*S(F`hB7tz)VNa5ZfAk z7**UWJv#fA-0MR@?DXawZE|}z5ZgyAsd}%3aFOKyqsybGbrxVxaVO@io$2>oB1Z6| z#8YlD-&qvup`)WA5O`NVsl~H}wy{eGuWbanZ5f!aZ7KsB4LpxD>qD@Ils=iJ#O;6S zXfs_h9Gtn*y_HC#rDRdZIht@2QsEJc|Af)7je9U1w;8R6tI+Bc$nl^INoyT`o*33a zrPjtA+fdear#AsY>d0S_`52jOQ%YEiqb&0F@oCA-WUK*qvVvjKLN&8nT+R)7vPE=_ z9&PQXX8JcMda0V|H9RQKiX(_EY7~pDt&(|eXGBX&OTxmz8N#-fuXaIOe(N^dk({i$ zJPJLnqU`wC8^D!7rg~66J3Gg4(#ff&Q|7>$h?JPvijBFsw#W8U8%!@h*HOUFp1hn(E3!M-on~fc z5|w0S+bAznQ{~kTv4)C9h9S86i2|DHwZDd?%y1^{pz|}?jo2duF)PPyr{s&p s(fV+%$EEa~LibUwF3FjHLjS|O%0h$qxS^IoR*nFmzNucFu2bUw0NeOP8~^|S literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_operative.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_operative.png new file mode 100644 index 0000000000000000000000000000000000000000..450f465ee8060460b9e1db83266ab205e0e66297 GIT binary patch literal 1895 zcmYL~2{hZ;7sr396;;GAMr*09Q%h~7ifV!qWyDgus;wzSEFq{RTJ7I3wxG6@*aj1w zs3n%#_ae5aB}&xVR_$sHDgJ8a?|;sF@4oZSdH1~gz4!BOl!?(@4mN%^0021j^>j>+ zt>cf$%5uEU;-07;8~0#yYd;-lG{V;n<>%(@1pt9~GfR}O|L&F<>f81wX#-j5{$7e% zsfEIOrRiB23S5e8Qfg6pV{W!ruMbX+5Kl2jW*U9Xyg@T+M{7@%zOMJ08W!f(53F zxz@y#obyr-0~0>9Ye-qp++)EkdROkvC4s}|$aKfyv)qVSu+I7P@r$h6;HdMtsas4f z5r5!4XTlAx&Y$Xs*M$g!{04g0+*Hb^-cC*Uxe&@3ADJYh|2!SN0&0Wc z()wEg9J>qln3|ZC-g)(6ihg|?vqv?9oE-LZg@3$m zE_j7xQkt+eG{;jd&?%Hg#Ky-bK2@+@t_&KtvA-MuDNZr(hDw0d*{U^c6d$MV{psZ#BTH+O3D7a=1p!|%ki|-b0QD!EKBW*m zC2WB<`lXU*N?454VdrvBkFdc1X|SyX3zTnHfSJ^Qr`wAW9&N?sxrbr z?tvI7H_XO;9RmPqV@FK1ejJ^>&Q+*}$5p=tCSG&%&LjF!*h|j+A~{GI7BDw15^wf^ zwD`*X>su{XQw#GKTBQfCn-Qx{z55zmGdO^dl5X>QnrNvm0)brW3>_7f&LY)Lt9#-| zu3gf$!wMwkT{|~PYEmQ#9^9XEn(8aobK3xrBSJ~ON_S)8!_2d$VZ;rHRftRRBXiie zw>d|5QImw~iSHjrAilzhnL?^}_tPkLV#qTrOXQyMDjenBiH>m2NjNmcn3#LcsstBs zIi+TL^^Z2A(1YK^mKGO9L-FploSx2S9C}LH6tiCbk~UC=$a7iVOOoQomS!bg*dY5~ zD;}Wa@X2+~2ODjlluIE~xahC-%A;RbO;oT*GplC#+avXfPwEuPtYwHx#fUHMYcW33 z#IyvcvG#S0XPZyZOzjh;N@Kh9#D_0q^q&tHtHSHC$pc49~4;lHSCMK zQNft#^;=&zod|4d^kFAt^$qBd*K{F zK!Wz9Rkip=1($0SZ=@g)hI*}r|Akhaonc~Ri|Mr{AEey6wSBPO6*&IMJIqsA2LsY)mn?$J{TU?Z;n)m?7nt7Ksu;y8D+eK? z{sE^8i|dJ_GZ1)=N*FDZS?0TS12m)OP^A#`!|!ngvrEC&htKznE4I_Wq{Hk(oL2Iv zK6OoF#`^*ef$yi1CZA&tM$+svmfmMqtQ85Z?U9kh)4O9oA&K&39YKO~OcOrPVfssp zsuXg7m%Hde%o|$$4$&}<%6K$8w6Yt#BHOpMwmcVrelb%i)btnvVkrRufI;d=!ePx& zDB7OzFOsQ|1`VZXaiPD%W{trqVzHxrZixDqSv3sykIklMQ0NT{*yECYJI?VBcUWHGfNsD0I-cMfQw>M#a2a*e<1qd zL6|LUj+UMDbe0{^mu#=uU$(6s?Is@7nD zk^XuRLY^#in}fB2)n(_$7`=XlKf?bO`S$F@)>q2q27G|=>aDyP#6oL z;6ybQ+con0Bj!W#A1p+o?J_pLqr40yrxXYK(l76GYsee^%ptfwt}TJ3H?E<|8wzcy zMneN{LiLwEWGY)U&SM-8(DoVLwVUo=!#_jL9&>egj*b*gNMD`!`?zxg`Yj>+ zt>cf$%5uEU;-07;8~0#yYd;-lG{V;n<>%(@1pt9~GfR}O|L&F<>f81wX#-j5{$7e% zsfEIOrRiB23S5e8Qfg6pV{W!ruMbX+5Kl2jW*U9Xyg@T+M{7@%zOMJ08W!f(53F zxz@y#obyr-0~0>9Ye-qp++)EkdROkvC4s}|$aKfyv)qVSu+I7P@r$h6;HdMtsas4f z5r5!4XTlAx&Y$Xs*M$g!{04g0+*Hb^-cC*Uxe&@3ADJYh|2!SN0&0Wc z()wEg9J>qln3|ZC-g)(6ihg|?vqv?9oE-LZg@3$m zE_j7xQkt+eG{;jd&?%Hg#Ky-bK2@+@t_&KtvA-MuDNZr(hDw0d*{U^c6d$MV{psZ#BTH+O3D7a=1p!|%ki|-b0QD!EKBW*m zC2WB<`lXU*N?454VdrvBkFdc1X|SyX3zTnHfSJ^Qr`wAW9&N?sxrbr z?tvI7H_XO;9RmPqV@FK1ejJ^>&Q+*}$5p=tCSG&%&LjF!*h|j+A~{GI7BDw15^wf^ zwD`*X>su{XQw#GKTBQfCn-Qx{z55zmGdO^dl5X>QnrNvm0)brW3>_7f&LY)Lt9#-| zu3gf$!wMwkT{|~PYEmQ#9^9XEn(8aobK3xrBSJ~ON_S)8!_2d$VZ;rHRftRRBXiie zw>d|5QImw~iSHjrAilzhnL?^}_tPkLV#qTrOXQyMDjenBiH>m2NjNmcn3#LcsstBs zIi+TL^^Z2A(1YK^mKGO9L-FploSx2S9C}LH6tiCbk~UC=$a7iVOOoQomS!bg*dY5~ zD;}Wa@X2+~2ODjlluIE~xahC-%A;RbO;oT*GplC#+avXfPwEuPtYwHx#fUHMYcW33 z#IyvcvG#S0XPZyZOzjh;N@Kh9#D_0q^q&tHtHSHC$pc49~4;lHSCMK zQNft#^;=&zod|4d^kFAt^$qBd*K{F zK!Wz9Rkip=1($0SZ=@g)hI*}r|Akhaonc~Ri|Mr{AEey6wSBPO6*&IMJIqsA2LsY)mn?$J{TU?Z;n)m?7nt7Ksu;y8D+eK? z{sE^8i|dJ_GZ1)=N*FDZS?0TS12m)OP^A#`!|!ngvrEC&htKznE4I_Wq{Hk(oL2Iv zK6OoF#`^*ef$yi1CZA&tM$+svmfmMqtQ85Z?U9kh)4O9oA&K&39YKO~OcOrPVfssp zsuXg7m%Hde%o|$$4$&}<%6K$8w6Yt#BHOpMwmcVrelb%i)btnvVkrRufI;d=!ePx& zDB7OzFOsQ|1`VZXaiPD%W{trqVzHxrZixDqSv3sykIklMQ0NT{*yECYJI?VBcUWHGfNsD0I-cMfQw>M#a2a*e<1qd zL6|LUj+UMDbe0{^mu#=uU$(6s?Is@7nD zk^XuRLY^#in}fB2)n(_$7`=XlKf?bO`S$F@)>q2q27G|=>aDyP#6oL z;6ybQ+con0Bj!W#A1p+o?J_pLqr40yrxXYK(l76GYsee^%ptfwt}TJ3H?E<|8wzcy zMneN{LiLwEWGY)U&SM-8(DoVLwVUo=!#_jL9&>egj*b*gNMD`!`?zxg`YV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r z;NmRLOex6#axBfbI5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j)$TZ~QOe;#vO@*+P66=?buu*f?u;!9W4Q;quF$c z+E}vR0?tDTxDJVyxXEeJl8B&h0S9Kl2xw&08zW_Y$nglwgQav_4t^cjY(4nQNV>ib zBIqKp4z~45m|CwKe%>R3-UM7(e5?qx!){BQkq<-0A%`!>^ZW@EMez*yoSXjK-ZKcS z(H?9q5P`s41ic6l@dC=Sd<9%UrD;3QbP4Uj))EoqIu1cqRd0Z6@DA#_{s2wWe1b24 z5hiP_wKYHl0xJ>pBG8VCE9Mrt?bGJk@(oDRJ-GlCfkd zG)9=DWi&D|mhAgB!l&|G*Z0TsoafK`Ip^Hxz7wo1jgNAPZ~*{t6m5dC-N(zn4=4Nn zJ(?2++lPN5?3{2Y&)_RTJ^?r%|LXv71CMbC2nyL)#RM#^jmeoQ%Jub7FxB=d{g5A{ z3KVl$vURn6HIy;hW72C*Id?N4(Tv~BRuC(gnOP6RoKH&JfATcI1`_#$F;ZAhHb)&H zHX%1FB_NM{QoY#B`TE5!5uVgsMK- z5%#2GeX=1K<6L^k)GxM=EAZJkHMmOaYAA)XYO90`jQrx=6ZY6x7bzVRt&}jro_*~K*1=foVF`k4 zsIa3D+Lr}{1(tX3$ot)j=Q~U3DM|Wz4s995Dz^j9MU3D+S4*Or8z6UX;S3^K@mB?K z?GFqTXFR@bt(841^AjfgOZ<|fqxaQ1qKBykF|_z8F3P+r#XfTC9?x5*6z>O~z&J0I zHv4R3So|@c?-he9(v_k|1Io#oPfH3CqLpUF-pusmiie*NAhRltq0DO}cRu8?U8=h; z&Hc7@zVxBI+*cYL7_fYo^P(fvlmEezj@BU@wsD1#vhP1T}97u?0Oeu7k1w=Q-VYCFNuBO&Rxc>dU59`{m4V z3crhK6)$*Oi}I1N8q5N;P53@6tC_|7j(Fq;y1&@hFnJ8AiP2E1JgGQtV+&U4@aegs@H?(UViz)|~aF*+Mo zFk}2!wfOd@2hX8ArO-xkmvbf%{I2+#X+m#J9+MWYLu4#Y{_vrfL0k(XTj)N6p&wMT z(`m7Ob+v(T9hu?|-MDoQvF0~ip->^3ay-=zb>}83&gA!TgI$PO)^3&I^8LNo0-; zhi+~!ei!#ntwQDUt=`$0BDOIxRj}K+t@z0W$;|d+Qz1sCnqvGcxd+CBadC4$$WPCT ze&X3VC45*K`IDqbQt&I9tdjPjzYEV$oXOKN+*o6%-XuP*D}4C#h636=nW)X-uYqNF z&{SF4=e0J}c2TR#%R#5@5DCD(nf??k*3i&kWGyQvS5vY1SwjaD-Txg|GW5}^cl;~* zI0;0%d(=f>AsA_CQay1krLK;ih0o3P@Zt6(-l7>bl^B6Q#+!MHXU<72`AgD+FB4J9c-34J4iRjKKFyNnVG2#d@45LL#t(MpFO8}vFplo z*ZcRU>q2Ibw&zQfVul_;794{@LeyTkH*y^R~mK1yhYz~?7Zw#%cPNoctFzMU{$ zh=O@?9}`i2QCb($@t3O_<*vC<7l)20p+48vraUShIY7a$&}gY3gv`5&_YE{9&vEsk z^{!)$&N+D*E&e_I;a{Rs2j@>MMow;Qb-|og+YqKoE=~621M>CtPNm*E88}UDUzqu} za6biOh2)ODPE!X{PNo@QqnSs&`(Np-95!2sp39reA7iS;_<`6 z!F(s%@?f1VF&uz00>Dj1!$tjl;|mK(Cb8Y!!%{neO_xmH$;tw4eRK5k#>n+qsk+rw zT+l_N7rWH4eBsf*O3!IaiVQJ_vrU!6WAdnrR9gn!45lvh6GIpqYcYLi)(s#u_!hUP zf;icSZN7eX$0#>sAmV*BTDwF!S+QXl>`?7H&hAHp*TH6gjUF+pNaoMpTADpM@l|Bc z6->9=5qLGOc$&F0Ov~&kJDm#^Ag)DNU8s}K*@hK#z=RN%Ud3CThQDYhq_$*RtOFhZW06SR(k)pOmtEEiAv_${ZG?C&%B!$fh`)*loC7<+$99#_g3o zd(=YsCbsc19ZvZ$IJYX2p>)cZYK&bNyLxPA9QV@C-w3in|B9uEczjT9&0c+I# zC$y|=^{G6M*p008fsYj$7V$KEQvWy8Fr*j~8)LsgePM7_aHS(q`BJVf!#K2$(^iNs zk^SDV&xUwghDytBDZPp|P(FQ-R4G0i2ya%wmI0Pl+?zLH=G0!{#rI-SyP#mhxB#Vz z=%(I!{7O+-66ubMjAeCndVCe+qc7{vm?xVFCtV+=asC-zFx9z$?iaM2&UV$I?ZXb< z!&cb>Dp}P2WRd|zCjz?DrheVm*lL97N7U1l!=5+%#iw}Y5R~EHyFM)?3{r{M--Q6Q Mp(UzP|MIQ>0wFwWjQ{`u literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_revenant.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_revenant.png new file mode 100644 index 0000000000000000000000000000000000000000..eccedaabc01a35dc1eb75ab7ebac75d4bb3cc4cc GIT binary patch literal 923 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoSydqsB`&GO$wiq3C7Jno3=9=> zg2M`mO22;zF8KKMiI%sn*10q1gExd4Tr__0Nawtd=E;B!p&LvdKRV-a*5|xNV?md< zkav)1j_8yrJ1l~Yy1Rf(o}Ct#yM&5^6?0Nq!|lac#pC_;80MXnkoPHJ@L*tIdgJNh z7*a9k?Ht>@+YSP5D-XEMlGv7L%5-U&Q4PayhL<%=n1i!#|HcYkj*BZ+?Hf>H4K2 z@2`k|*x$^MB;eq4-SEKYpZw+h@rT|{-u!rd@bPal{2LeyITY9!kCccrC;k1m{Oa+G z`@WVL-?}$_MgwbyBZFa)_>@UmQQIF2?piYMuAmr5sY1gH=C7;~dqRv`KkR<}R&7_# zMJXKz9;S}WcTGXNqI5T0zig#@lnJO#f<-{t-#Pdc@Am!k7oFd2V>8Ppea5s^!9if< zK+``-JV>nl_xEk`pXt*N9#@e2!Und%q|kBaQ})+Ihe|$u`g=6v{`u*%FP7a9j9&LB zHsJLo7MLrZWxmjx%y;d5_3vwk(;l7Jw<|RQWaZ_r_KByrKbOy+zurE^_uXxEm>)%? z&-Ln>-!QpSw997Ro#{cmXKnqxq@ou2G=ja#p`d2XwnS$Qho`1(MXTHdq-#c?RMhG_0jrp& zPMY>?*}QL2#nX2j+b0LH2pH`pmQ{MSIf3)u@xGsV#Eu^v_Jy$ldG4#O-S*sbWs~dC z&2H^{U}phUPc1#v#n~ElWuG`KlJeYhHcF^nuX;MID?YwGFg+vhZb5F&@>9Fhy-%^U z?|r{Nff1Ox&Ny1Aq}-jDp0u=W*|(Wf92+KYu0L)xlB literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_sentientdisease.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_sentientdisease.png new file mode 100644 index 0000000000000000000000000000000000000000..e7e1cbd661fcb609b7d24bf84ba5fbc003c8882f GIT binary patch literal 389 zcmV;00eb$4P)fFDZ*Bkpc$`yKaB_9`^iy#0 z_2eo`Eh^5;&r`5fFwryM;w;ZhDainGEX}w$Gg33tGfE(w;*!LYR3KAHiHkEOv#1!z zH00t;D@x2wg|L+sT>V_YCISGS$rvAshC*oo006y7L_t(Ijjhu$4#OY}1yDx}9l1ay zuF=gm3+c@`N{_(EVDW2`wCWO@p%y}V1CW>x(R{_0>IBw(cnG>678hwFTAB+Cz=e#7 zJ=_kw{sxvAM4ULFW20pA{6fzgRF#D*S^mUOBnGS2E20zPX{EOe4wLTAbrGzDBzAidT_7RSM_AvT5+G*juub-!Ri3Q_rxR}{( j{d~b{VlqgRv7D+m(szW4NCKsN00000NkvXXu0mjfD!H94 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_spacedragon.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_spacedragon.png new file mode 100644 index 0000000000000000000000000000000000000000..f81dadfcf56f00434d321158cfee87f91cc0c250 GIT binary patch literal 1226 zcmV;*1U37KP)v6QXZPhw^=s;0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRL zOex6#axBfbI5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j)$TZ~QOe;#vO@*+P6;s%_8mg{qJa&FG@I)Si$qWG#C=*OM%DY9Nk<7%r_PXo$K4d_J05VMqz0 zq)N`Sbj!|JYXwQpyj~Ty50H-x{E{2YL~dIpRqD3PR?WF}!b|-|YmG78foOP+V1dCy z0FLXTE>;hKweugomB5Hx!rBuMBQ{Jn9~JfF-DZXh`!6G}>H!Gh3&9x50ZdOP@2)br zGDc%7b`mP3A5am!*05S=^0(H0GaARn`tNXVgBx#yTPTe~0MS=ddpedxI}qOEcxoNe zj`B1mi1~IYV&uy70?=YdBO{fBn22{LukGB)wPc4<09VJzipeQo^Z|yerl_=5g}@@` z_*v_vr1p5_fyDyJ_C47dsNURS?||Y?h`Au>fjj9A0niOtHKZu7s0YAj!`i&RPM!J$ z0=79x^s^Y(C1R?8x6S}*2jkb^;oTkUcC`HtpL~7t#dWf@Gwu)UZpzJkyK0Q#oFGFf zxTXMr7z(hvF~xFLmyY`arbPM90I;NvJl)8V3sTwez=m`?QWSbc0a8tJeFA_grSh@&VbHYzPRN;+~5E4+x>_2 ztEdgkU1N5pHxL*Pko)oH-{DXIFl3A=x8fzY^xc66!$yZe`=H-RbFbvqv+_d#Q8b{v zJkp(~9>=Bo7_~0}w7erdB0>Mg#QiYNMxbIy|5aF!1tRQ;<ps{=&%UA~5Dn5R)km7IaSOmRAtriC z?+Hk=rOjjyguu332n6*8ByTDHzzA#fi*5r-92Ag0I9h;@(i6a#)+@RKlIREEX_P?3 zF9amfpIh{cfk7+Nku<>LMZXvrUjEqvbgyhzYtX+0@c$~=U(2yF)1Ici$8sgxe}6y& o>-IMWv3E*0Ch|MT6MYBZA8ohCuT2qjLjV8(07*qoM6N<$f`h>{qyPW_ literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_spaceninja.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_spaceninja.png new file mode 100644 index 0000000000000000000000000000000000000000..a54028e1be992751de449f732d257bec93754230 GIT binary patch literal 572 zcmV-C0>k}@P)Tv;Y)dBg<5WAsT@>c4~A0 z0JQb)9A>mE6sYmqB3g@!LIKM4#66++i0*;XRsaCd)-NOnN~Sp^X@!845KAtD0~BQh z*;$kb$meH~(JYDsrWDhimslmYDBl?j;91CFy8~s8J=0MokPFCMh2_@0MFRn}UoHgi z;Viu6(rDn+^Go(mM}gw)S49?34i{-0e%3SQym+ymo#Jm0000< KMNUMnLSTXhT5J9&C&n=|BUPZba8?J1qLW6D5a^kZGeO?E-nC>03aYB_wkQTOiaan2Q@V{ zcXxOH;%V=-6f7((jEagXDJefcKYdCc82|tP0d!JMQvg8b*k%9#0AzYpSad{Xb7OL8 zaCB*JZU6vyoKseCa&`CgQ*iP19%!{}1e(*+Za-GDSK#_xS?L%6S~_?uEg?Fbu;m z3}fG%RG8oZ0;Zl;bnoc7K;fR}odFy?=jcpgf?eTEKL@_=UjQ6@jJm3|30eujB?y9m zr#J){b=8%QL*N!ZpE&n{s>1DHg1rbNVe)V|^wf{!=_I}Pf-8qsy-GneVS@h^Fks{u z1GH)i*s?Lw#8ycdh9>xf05?uV6h$!@S73yTk>;mhWBP11J5~W7?0h~i1$fkq!^LaB zIE+*S&i~vJp-W#Z7AE+mfF+$&Anpbr;}%eW5tTSAe}g+#!&M(rf+T)CTJs2Wy^YNA4q^hqJ5yssx4KEpWzMZCTJ;m0P69oHr{ZQUbvn z$nzYItZGM$E8hq1T`k!m0b zOR+iK1Z@Ng=PANjYuv~YH$YJoY&QtzQl}ClTr4ohR7o1cO|Vl?Hle}yo~vEa`+#u} z@avia7anh`>QM>Scywq~YuD;U`j*qz^}z*S_80TfB_yzf00000NkvXXu0mjf5}#)j literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_syndicatesleeperagent.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_syndicatesleeperagent.png new file mode 100644 index 0000000000000000000000000000000000000000..62e23dad5c7f005c87e98c8fe75c71ee56526e07 GIT binary patch literal 821 zcmV-51Iqk~P)5J9&C&n=|BUPZba8?J1qLW6D5a^kZGeO?E-nC>03aYB_wkQTOiaan2Q@V{ zcXxOH;%V=-6f7((jEagXDJefcKYdCc82|tP0d!JMQvg8b*k%9#0AzYpSad{Xb7OL8 zaCB*JZU6vyoKseCa&`CgQ*iP19%!{}1e(*+Za-GDSK#_xS?L%6S~_?uEg?Fbu;m z3}fG%RG8oZ0;Zl;bnoc7K;fR}odFy?=jcpgf?eTEKL@_=UjQ6@jJm3|30eujB?y9m zr#J){b=8%QL*N!ZpE&n{s>1DHg1rbNVe)V|^wf{!=_I}Pf-8qsy-GneVS@h^Fks{u z1GH)i*s?Lw#8ycdh9>xf05?uV6h$!@S73yTk>;mhWBP11J5~W7?0h~i1$fkq!^LaB zIE+*S&i~vJp-W#Z7AE+mfF+$&Anpbr;}%eW5tTSAe}g+#!&M(rf+T)CTJs2Wy^YNA4q^hqJ5yssx4KEpWzMZCTJ;m0P69oHr{ZQUbvn z$nzYItZGM$E8hq1T`k!m0b zOR+iK1Z@Ng=PANjYuv~YH$YJoY&QtzQl}ClTr4ohR7o1cO|Vl?Hle}yo~vEa`+#u} z@avia7anh`>QM>Scywq~YuD;U`j*qz^}z*S_80TfB_yzf00000NkvXXu0mjf5}#)j literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_thief.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_thief.png new file mode 100644 index 0000000000000000000000000000000000000000..63668193247ddb7412486a43cb232b04f7c499f0 GIT binary patch literal 741 zcmVV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r z;NmRLOex6#axBfbI5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j)$TZ~QOe;#vO@*+P66=?buu*f?u;!9W4Q;quF$c z+E}vR0?tDTxDJVyxXEeJl8B&h0S9Kl2xw&08zW_Y$nglwgQav_4t^cjY(4nQNV>ib zBIqKp4z~45m|CwKe%>R3-UM7(e5?qx!){BQkq<-0A%`!>^ZW@EMez*yoSXjK-ZKcS z(H?9q5P`s41ic6l@dC=Sd<9%UrD;3QbP4Uj))EoqIu1cqRd0Z6@DA#_{s2wWe1b24 z5hiP_wKYHl0xJ>pBG8VCE9Mrt?bGJk@(oDRJ-G5J9&C&n=|BUPZba8?J1qLW6D5a^kZGeO?E-nC>03aYB_wkQTOiaan2Q@V{ zcXxOH;%V=-6f7((jEagXDJefcKYdCc82|tP0d!JMQvg8b*k%9#0AzYpSad{Xb7OL8 zaCB*JZU6vyoKseCa&`CgQ*iP19%!{}1e(*+Za-GDSK#_xS?L%6S~_?uEg?Fbu;m z3}fG%RG8oZ0;Zl;bnoc7K;fR}odFy?=jcpgf?eTEKL@_=UjQ6@jJm3|30eujB?y9m zr#J){b=8%QL*N!ZpE&n{s>1DHg1rbNVe)V|^wf{!=_I}Pf-8qsy-GneVS@h^Fks{u z1GH)i*s?Lw#8ycdh9>xf05?uV6h$!@S73yTk>;mhWBP11J5~W7?0h~i1$fkq!^LaB zIE+*S&i~vJp-W#Z7AE+mfF+$&Anpbr;}%eW5tTSAe}g+#!&M(rf+T)CTJs2Wy^YNA4q^hqJ5yssx4KEpWzMZCTJ;m0P69oHr{ZQUbvn z$nzYItZGM$E8hq1T`k!m0b zOR+iK1Z@Ng=PANjYuv~YH$YJoY&QtzQl}ClTr4ohR7o1cO|Vl?Hle}yo~vEa`+#u} z@avia7anh`>QM>Scywq~YuD;U`j*qz^}z*S_80TfB_yzf00000NkvXXu0mjf5}#)j literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_wizard.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_wizard.png new file mode 100644 index 0000000000000000000000000000000000000000..350266c89793edaf4d21714a5ca8649c8771fefe GIT binary patch literal 800 zcmV+*1K<3KP)XQNa1p#sB~S|KQOYgLsLFiQ%uN+MbeUR&SpRbDk>^pj@I$&9#2nC+SN1@IB`l!O7e4hM*si-0d!JMQvg8b z*k%9#0AzYpSad{Xb7OL8aCB*JZU6vyoKseCa&`CgQ*iP1cj81{e$Q0wqa8z{U$b z1d}vPe@ut*4tj-pG9DZ72C>buEO8JuY!S=?^R3KxPS+R)xC&@NXt(wX%&8peCK-Vz z0PG=Df_EtKLXY(UVKHG>8 zj;4nvX9L^_aEweDJA2{xuOhYdLDiwWzqtX1hy}j&-AP|RXzPRJfOq9Y0ovrXJ`kxE e4cyM%4e$jo*1-8?fn%ot0000XQNa1p#sB~S|KQOYgLsLFiQ%uN+MbeUR&SpRbDk>^pj@I$&9#2nC+SN1@IB`l!O7e4hM*si-0d!JMQvg8b z*k%9#0AzYpSad{Xb7OL8aCB*JZU6vyoKseCa&`CgQ*iP1cj81{e$Q0wqa8z{U$b z1d}vPe@ut*4tj-pG9DZ72C>buEO8JuY!S=?^R3KxPS+R)xC&@NXt(wX%&8peCK-Vz z0PG=Df_EtKLXY(UVKHG>8 zj;4nvX9L^_aEweDJA2{xuOhYdLDiwWzqtX1hy}j&-AP|RXzPRJfOq9Y0ovrXJ`kxE e4cyM%4e$jo*1-8?fn%ot0000V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#axBfbI5Sc+ z(=$pSoZ^zil2jm5Nr{UyC9|j)$TZ~QOe;#vO@*+P6znK8m>z(?1R`^3S1y`pKsX`%JJIO@n9R}>5Y*wmJsjE=Nzicr6<*l1 zfy;)3)>{Rjz8>yOcxDHjgNmg-9?!3E!~(nk_?Al?C?JW58Rdx9*gNj6aR57-6To{P zSf1`*;rHkg_XNaRW{6oR5QjKX0CA0W4GukP)Pppf54~-ZB+w}vijMiH>`3(V0Kcn> zYYpnz^Kq;pIY5@!0K9bNp3&YRz`JMfnE|YWw6`umtpicQ zfHC1iy$W=}20j7(LOx9mj++nw0000k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h7I;J!GcfQS24TkI`72U@f|4b!5hcO-X(i=}MX3x0iJ5sNdU>fO3MP66 zdPasH6*8v+6?u8OIEHw5Z#}+|m%%`QS@He;FU$AO@-TVxE&Tk~7~)ZXF2B*?KY9Ys S3r_+~W$<+Mb6Mw<&;$VF-csTK literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_abductor.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_abductor.png new file mode 100644 index 0000000000000000000000000000000000000000..d4742750320cd285b1a571a364be04fe05d15e8d GIT binary patch literal 1125 zcmV-r1e*JaP) zK1oSQv$L~wcYthcY$_@$k&%&4Pft-#TcoF~5fl{E*WXG?N};5wo1UYttgJaXIZaGV zKR!N7N=lfNllhK7bz zR8+CCv1)2+TUb_ufq`&sZCqSj9$SmD00001bW%=J06^y0W&i*HWqMRtbVOxyV{&P5 zbZKvH004NLQ&wYE62mqS@7!En1VMG7`0`5sf zK~z|U?Urd%+b|G@B})nkV2EVNG9o<^hoi*?LerMx|NpPEG!^QRFg)bjC#?I7`=$Kp&+Edwe_*;|Wh?(ES4;#KHbv3UF9XCis_X zfgP2jgHd^On9z@52)yK(Auw8&C1sGABtSyC9tlU8dNP%gb1vmHtt+K6dZo1~jn-8> zW2&^O>l&VM-N?#nX{5H5G;v+kP1DpWrR(ZMYpL}~r6U=j`+6kAbYe7gAhpvHI?xe- zh6!kt|0HyW9T@Dug&C-;+Rs6)B06+v2+RQjY~{a&`fdmjojBuu1K_t%e*uI#>{HHm z0LFt|OT{U(TYzP!BG@lfl-wFAos`DHf(`+cT3cgS3vUYnrC_tlRv#++aRw_o0F<9l z#{m6vpyM)!kx8kc14n4MA-1|q=@_t9a3Mw4*;{n{tqr^-vPzx-Ue5v?i7k>H0J?XP zHSiAs1`-AV4r258Gkrc^v@L1d#eAO7m+cujYnKWAe0*`a0Knq%VtgLem#qi1%cxGi z_;~&o)4xIxd_?tk6Li1;4C+PR01WGJee)uDJFs=I<_K61$Fl0{CLpM;>)|wmD;OXt02ceCzUy8SaA2T0)yW({cFN&f z!f8--j~y6nG1q}qc=YytFbg<^c(J|#AaMu*z%~GYkV628S$)^o*8uDQ%r*kpb-e!i z210@x#|~Zth_xQTp+kBb2i)GQRyW)OY*3Gg8F*!OclRyX!Fsh?W6msAPS6K|o6cR| z>+e6-V75bp^g_s9|KukGT7YB%5VBjrFXmkRe*glUG50yZy)j99fZ@%-Lt1~>c!&(Z rn}f%c{J8ZH>DZWqrd00000NkvXXu0mjfuk!#V literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_android.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_android.png new file mode 100644 index 0000000000000000000000000000000000000000..413fe56c47faeefaf780890b753d5195af3eb607 GIT binary patch literal 1095 zcmV-N1i1T&P)Zt0mS$#vQ&VVFQ&T!RI+VY*va+)O|Nki|DFCOriHV7ahljARuxe^*XlQ7Tkdr<> zK1oSQv$L~wcYthcY$_@$k&%&4Pft-#TbY@e5fl{E*WXG?O0KM|IXO8^OiVvMK1)hU zn3R<2=;+JI$$ox*baZrDT3Sv{PMDaO)z#G^CMKtfFDZ*Bkpc$`yKaB_9`^iy#0 z_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LYR3KAHiHkEOv#1!P zo{KZBC^0t`#5UwoR&e!m0hp)f*Ij^z;4uT_sA2U(SX0wW_$0-OY zU<$_>LzSrq0|@APcA}J&QmGS~YppZ9HpX&mOr6d+(MCJx;F;!D)!rzpjIWhVbM2a@ zahl?$J~c)eb6T532JoRC4Jpp7fe|PZjDiuEguuW8G3Pbrx+mQAz2oQb8%} zrHuCDz`eupDb57^ZBhIBy!KxgkR1tj93#mgL%__GGBARGF9cT<$AGK zZQ)ZAyX09g@T?%P)F#;rVDure2mT?!NW!QfK-K+Y5Hlt_glQ zzq($5V0C>pzfAIVI|$l!lCy6^JpW4Z?+^?hN&abKz$L_s^&J9*Q-}n<0Re;> z6DZ8;yT-p2;0PpaQ%sWSdU*o@*R;eDycIC-`v8#R-A4*Gn;ZNtgx*K>s8|Tj#qI5n zb4sw?Y_^!QNR>0}gM`Rl-`k(Rwn~V&L3%M{>lt*?5?cT=0Sv%%M;3MunfkvZ$Z+-_ z2!geDIl-N^WP5c6yXY-}njDv^eGwhK5vBRI#zKYHDg*SXP69fpBeYTwGjb`BIJm0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0* zI5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j)q@Ig2ttc@!6~s2=QdV&Fa{-$O0Gj_84mqJ= zL;wH+M@d9MR9J=WmfLdMAP|P}g213qaB9mrwZcx^Hi!3rzV4#L>6is)dgTlKGnPm5 z?fzb2#I6vtW?h;V08&bTMV%|98oblmEREJ3AF)tcS!?mia|4~zU_iSL49}JA``)S= z*WH!Yp!HR!nF!=LpBy+YjK&H;dkt8DW(+hgK(F$r!aY@Br~+R`5LY&@fmIC03XQ-u zAOqLsyOJLtf#Jd%|BnIPmHgA7uHehy-VGeXMOez{41fnPF3M#ncnr>2 zl5-&zTtq3us&n0S=f1Ckl#%BomSaS~Cj-z}ffu35p~gwLS7;-#`|K;6{%eE3!t9a{ zgUp)-UT~Y_Xn@swW)EDD!I^-w1|BtC{*SNMn_&>cuvxDwd^_BTn_*kww|Dms8#LHF z+~3`@d^===VasyyBkSXf<3CY?E-arl>r#Y$PZ@k!`2#a6A~qDq=G!qLYMhxCa|S?BY3$vp0abu)KT=R-C&V2pVh~ku zY9O3T9*2ZLy{~BglfrJl-vyiwp?*R=```~87pR$RKEIVgr^`#${o zeSi?l0qN7BnJ@mJXauMRphNRj$eX#9KO2yNH|Duz@N7(VJRs%a;HA!ArWvAPkcWfU n8h(ABA?lijgSQ%fV}^&nIkqU5VF)?V00000NkvXXu0mjf7lovZ literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_ethereal.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_ethereal.png new file mode 100644 index 0000000000000000000000000000000000000000..b38c363378c364eec344fdadd7169b3c66986194 GIT binary patch literal 2670 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 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_fly.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_fly.png new file mode 100644 index 0000000000000000000000000000000000000000..205d91bcef3aaab803bf7cdb7e66f2d650ee2368 GIT binary patch literal 1080 zcmV-81jqY{P)N=izutgJaXIZaGVKR!N7N=lfNl>h(# z>gedp$;p0xespwnT3T98PEH#e8lhK7bzR8+CCv1)2+TUb_u zfq`&sZCqSjP{c|Z00001bW%=J06^y0W&i*HWqMRtbVOxyV{&P5bZKvH004NLQ&wYE62mqS@7!En1VMG7`0?kQ8K~z|U-Ifba+b|G- z?YcF6V8F5C;IcO5wI!jjZsYO)|Jm+bULw9L8bX>lsjbj=_xWOy_=NasA*K8nA1K9T z$iaZ;Lp4w%Izwt$K+}A0I3B9ect~Z)3Dhe!*`oy0*>I-dLkl#UTA!p{mkoAv- ziG)nrFk|Y$aHtRIdU0f}F~-^>nnMQ+FP!r;?_813IMPm+WeMMT?rjmA_11;L`aIWV zRaK>?xGRpGv(6nCE|UQ~)uSQDg?G?_b??6M}i#*I|UJ9`}J>pu~^o%sO#loLGV?5Do*Pa!OzYwE|(x!US6D^ zW%;U3f_jzZ;(LmxpB(=IA@D29zf8y-1Hevh_yItw!N73b!1+C*Pe(Z$Da9G2+2iH| z7(m8g-~@82)R3HVWP*m-1-UPA1UaDi0aD3s!aihhd!V>0!12Yy!^$lH*kfL{zHC}R z%sX>?L~GqPWyYYZveod)c zm#^=xAgoj!cJNjJhd&66l6dw}&%)JueI=CvLFm<^Vt(Bjd2{pggz8|kUT>u7uIIUO zkHvl;`0U3`&&+M>peLhV5H&T yj^=mU8G;d{;ozRa_m49K9oymHfx-`&;o&c>c2I^>lKb}n00007qkB^TI5;FEBrPp1A0HnZ z8yg%P9334UcXxL^Jv~xVQd3h?85tRXfPfkr8Wj~47#J7_2L~=LE)Wn9A|fInARreP z7ZDK=LqkIk4-Z*cSril$6B82*3=AnLDI+5zl9G~4OiWlX$5)u*!2nYoQ1p)#B1Ox=J&<8#M0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0* zI5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j)q@Ig2ttc@!6~s2=QdV&Fa{-$O0Gj_84mqJ= zL;wH;+(|@1R9J=Gmwj6jSr~`UK#2@HBV%LkP}nw52%^b}nPW5L3%Y{o+AdmRB{_-$ z5lG@%zNhB)=DJyZ;GJ>Ty*6f^`2hW{i+{M!xj8(CGv@)J?=6(WY0I4s%6|TZi%kw2 z?r>dfwllbC&kr6K19FCK@p7~qE8bQ}aMj;&?aEKrFN**d z1Hp^Dhre+Z;5SjIz0>Pw!{8Fbk*;WWdq^J%8F~V@0`Pp@z~2&j!1<`Vm*<5GEwOHh z$67GPd@smpK6*QPBOaiwM|9%=mLv)D*qSpkO}cpgMjxT?C>C6~Lt{x*RSDCw)jo-d zyR_UN5C&M8?ie)xTByN}v-yVMZo*=thLR#pBK^Z7KNFf7wGfO_7_0c~B_@YVJmpIa z(ehw`r<-LueSIw5z|&*b(^xvIfrN(=zLZH2lo3ttjZgeCNoYjECPA2>|GomcA2bOR zAEOI8e*Fz!(*>C+(!j}7=6?dlXDYK(op#dX!NZ5)2ZYYdB(n`Xo1Dpze+9%jt(s1K zCYhWik7DA`W2T8Dr=OSvPo|TENJa>mO(rvqg1OnLbe1NxLX#ZDJRLU)#-B12O^oES z>8aVdMgf}F&|IozVKLt_%Ah4vjZkU{F{6$=wct+8A#L8ojV#|TETW>KE?H89mQv^)=d$C4TtlVil@cVV$vvy6?(Bz(wA}BkqtzbW06f|HvtFAe77F|h*vR7({x7S9iY9L@E$%C0wU&|yMi+Z&hc>N7u$&Z8V% zWqn@OwPKA|T&&l}{&8e=@%}Gp2J9$-;nDiNkseh2?S3z>LdhLpVt_ z8E_=RIfL)aAGRaPcMT=BdQI=M)s(O`Trw_FY3NNyDDRUM9pCqxdxP^N-u;z0*0jO_ zG(dYi=J(8ihXp;-;~#shfdkNTlq%T%<#80KDA-@@W0e zj==%ECFP~5Mx4wDv YZ@tR literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_adamantine.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_adamantine.png new file mode 100644 index 0000000000000000000000000000000000000000..78d706f1326a6db3cd06b68a8fc82011e73cd5d5 GIT binary patch literal 2175 zcmV-_2!QvAP)OC)}ED2#$Aje{zZhZ_5k zHodSNXI~ONIWeuEG`6Wa%DXwqx*TCzGO(l(J2xtmh%cm>G`Ff5S5Xl>H!-W9I?KE` z#kVbp(>P$ESireihw!BxH!bN4>mFnGcXlM zLrO|YJI}xmH8Bu4G!HZ}8e3HjFDn^YQX_eB7EVbML_ZEPFDa3R5 z9UBTF9|H;s5$)rN+K5jr+hR8+CCv1)2+Bz<%aF)j%q9tRi~2N@R( zDJBC83IYcQ0Rsa91_h7{PhS8400DGTPE!Ct=GbNc003orR9JLGWpiV4X>fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KAHiHkEOv#1!Po{KZBC^0t`#5UwoR&e!m0h?S`b$3N{q*EbPI7|K+ZI`nT$0O!WYYET ztavv_f(He!2$3=4CU#S53st?GB)e+=}kbxjS`dIzR8r3RDuy$SK z`Zb?!SRDoMsEwM>$WU_AT7Yjx+UOWntWpO~Q5P4V@OiYB9|;)}H*VPo*Yk#?E$T$D z9&Jq~N%a@u`mGSxhhvP%WRO#2!k1rdN=c=}M{LEZn5Jn=VsTCwC?=jv+LXpn+tNjN z`ZfyFMx&9<Jt|nKHIhnOUjo?3_$0a) z1%(1$SRljLh?jq+yj%e{7iHv9nY&WS-65HjWkazgfLn?;STMcZ0~+UM6qyAAjR8^2 zo|13AEoCTFrV|KsW$3?CKzlU;L3$Cv3nIV!e&2dtP+n0Mz{@Ji|0f`d1Z|e@KOm== zAAbBv_cKFP9<OXjvfo($BrJcG7Rkx z!&K#2D+2|`t12uuilOWjb3#U(ED_A0MW@W+HMMoW77(aj z&?987M?^tGovcP-K84t70r#iz^qD5qY;UO-r3lrx*qc$)nbVB`M@^2nX4I-B+W_81 zYFklroTCX6v|E&CQOCJ>Ex@($=Q_|?rKKGbbg*nIYVCB2+~~_OIXijIvK^41t2?9% zx!mWW=W@__w+nTJbaz1lk2|pkU65x%O=`@NUqC&HZVxyEL!AqGUA?~n+}rE&B3GXQ zn!!cSrTzglIMnGC{|k?|b7&9^I4*fEit-NUuue9Ds&__TKHM+D`ww4^-dT-CWV&Ie zXdBzxM@O!VpMiQ^uqC8y@1FQR6AYyFiYPr>!ys--v(~6Ea2I2sQ+#370Rcb&KQfFr}&}=l2OaDA>38rkb2E?1uPm!vv|mIk^uMp!&_~TN9cb2@1&gTm>_)kpXcD7;PWI+QYXegNU z;WnpRA<_m+bDTZ@t{$tx?g@7nuTpp~OojD#^X(ib=z_n6(;6j#@7KgQAb}&M<~}Br znrV?XGDaUqC|iihq0;1XNKl?!Iy6bNC<)GIWC8{L84xK}c}&|m2XL?2AMlY|QwaYI z0tJX+xODTw+2lW?BIPP^f$G8B+=JxVhvsyS5!Cw?eGSF2wrSHnJ2Zp&xw&~;Y;i-M zSUH~s2g}axT_@Zdyw3bzf6vddtYZNhz#b}&ojM3E7W5CF*y2MhH~=*!6gnh7d4e2; z3E=*MPp#$AlwN}C^;3^5wGspR%d!(BzZY}~*=1tyz1Qi;Zftf-aJRd;F&o@p@M-OK z_RL7|nVBAEH~dgW$hElWmFO{IS?}VaOJcy|e5L0Jc$Lw@!V`}&|FMMNY1g>o+0s*p zK3#gI81I6xKZ9dS&tJUk18860%NNg=#s=Rw_%F&)r3@UeW^Vuh002ovPDHLkV1m%C BvUdOg literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_alloy.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_alloy.png new file mode 100644 index 0000000000000000000000000000000000000000..e9199bfc305fe3ba43b64ebc75bfa722921cf194 GIT binary patch literal 1447 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 KgFDAg(f1O=P!|_-8XAKb7L3NZ-@E-WnC z4GlvG2q_X0SP2O)2nZ?(2`eNdvl0?p85w&B2q+mDd?CI|>81_mGo z1|J6pBmx2p4h}^H1sDnnGYSeY2L~br1sN0+WD^r!1qBxy8-)f29tH*+1OyTc3_S`8 zG!qkH5fN4_EZY|savBfFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KAHiHkEOv#1!Po{KZBC^0t`#5UwoR&e!m0h?S`b$3N{q*EbPI7|K+ZI`nT$0O!WYYET ztavv_f(He!2$3=4CU#S53st?GB)e+=}kbxjS`dIzR8r3RDuy$SK z`Zb?!SRDoMsEwM>$WU_AT7Yjx+UOWntWpO~Q5P4V@OiYB9|;)}H*VPo*Yk#?E$T$D z9&Jq~N%a@u`mGSxhhvP%WRO#2!k1rdN=c=}M{LEZn5Jn=VsTCwC?=jv+LXpn+tNjN z`ZfyFMx&9<Jt|nKHIhnOUjo?3_$0a) z1%(1$SRljLh?jq+yj%e{7iHv9nY&WS-65HjWkazgfLn?;STMcZ0~+UM6qyAAjR8^2 zo|13AEoCTFrV|KsW$3?CKzlU;L3$Cv3nIV!e&2dtP+n0Mz{@Ji|0f`d1Z|e@KOm== zAAbBv_cKFP9<OXjvfo($BrJcG7Rkx z!&K#2D+2|`t12uuilOWjb3#U(ED_A0MW@W+HMMoW77(aj z&?987M?^tGovcP-K84t70r#iz^qD5qY;UO-r3lrx*qc$)nbVB`M@^2nX4I-B+W_81 zYFklroTCX6v|E&CQOCJ>Ex@($=Q_|?rKKGbbg*nIYVCB2+~~_OIXijIvK^41t2?9% zx!mWW=W@__w+nTJbaz1lk2|pkU65x%O=`@NUqC&HZVxyEL!AqGUA?~n+}rE&B3GXQ zn!!cSrTzglIMnGC{|k?|b7&9^I4*fEit-NUuue9Ds&__TKHM+D`ww4^-dT-CWV&Ie zXdBzxM@O!VpMiQ^uqC8y@1FQR6AYyFiYPr>!ys--v(~6Ea2I2sQ+#370Rcb&KQfFr}&}=l2OaDA>38rkb2E?1uPm!vv|mIk^uMp!&_~TN9cb2@1&gTm>_)kpXcD7;PWI+QYXegNU z;WnpRA<_m+bDTZ@t{$tx?g@7nuTpp~OojD#^X(ib=z_n6(;6j#@7KgQAb}&M<~}Br znrV?XGDaUqC|iihq0;1XNKl?!Iy6bNC<)GIWC8{L84xK}c}&|m2XL?2AMlY|QwaYI z0tJX+xODTw+2lW?BIPP^f$G8B+=JxVhvsyS5!Cw?eGSF2wrSHnJ2Zp&xw&~;Y;i-M zSUH~s2g}axT_@Zdyw3bzf6vddtYZNhz#b}&ojM3E7W5CF*y2MhH~=*!6gnh7d4e2; z3E=*MPp#$AlwN}C^;3^5wGspR%d!(BzZY}~*=1tyz1Qi;Zftf-aJRd;F&o@p@M-OK z_RL7|nVBAEH~dgW$hElWmFO{IS?}VaOJcy|e5L0Jc$Lw@!V`}&|FMMNY1g>o+0s*p zK3#gI81I6xKZ9dS&tJUk18860%NNg=#s=Rw_%F&)r3@UeW^Vuh002ovPDHLkV1kz+ Bb%6i? literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_bone.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_bone.png new file mode 100644 index 0000000000000000000000000000000000000000..11ffef30da3aae2fac2404b53318c65d26e5d43e GIT binary patch literal 927 zcmV;Q17Q4#P)KAp_8`9`e$GU*WOe@B8b4t2NIK10e;! z%(o}mcHpBLA9{G;loE$7J{?<#$I13MBu?`@J;Xg~EqZCJ<1b;B4V3EvdaM96gQ*BvKSa5H>BZc$!-c5WyBllTny5c2PJ_ z?Y}L4Pr<SCd9~kXs}5WO;<&#!i3u4DtIDY>yGH)b#o1|M8z< zqXdUI`xk&Q9%Cte58_h%3xw=Sq0%P+SbW8Jky1Q@QVczPuvch~1H)WF3hjze917`2 z2gBS;wxHgvDX;pO>*uv9#h?%1QrFpFNXuLkLQMWXC#0C_ylfcKx>jtnkUjiA)=MHm zqttbMX3)fnl$cgy^4pogVn2i~p@I zTyLx{KCZ!Fu#6{@|IM>7dyg35K?CqbRYUmaqrX>%7hIa!TC)HE002ovPDHLkV1kkw BsA~WK literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_bronze.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_bronze.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb6bfa0597a4496ae0709b049c4f3ce245ca7e6 GIT binary patch literal 2175 zcmV-_2!QvAP)}|caz`AybS-#F9ac3JQZp1hB@b9O6?I4)bVwXkH5EW85L`JIX+aucJQ!X& z7nHxYflwd0b1nb>|AkW_flwf3KN-JwFSl|nS~wQMcrS^GiHcStl3OH^S|f>7B8OBV zLn#opaV@lPEW30rZbTcfu&_uh5obUdmR%)_Rw70#5p6>nc}pF6OCEhrA5Ab5drTg< zaxG|RXhLHx_Y59A!TlT3T98PEK`69Y7}!x^pc`E)uM3DyL{E zq*NhSHWiqdn3`WDn_wo6SR>Wd)rN+KG9L_7R8+CCv1)2+Y(p9=8VVc{2Newk77Ya> z76}Rl0tN&E0s#R90|9SKbRz%&00DGTPE!Ct=GbNc003orR9JLGWpiV4X>fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KAHiHkEOv#1!Po{KZBC^0t`#5UwoR&e!m0h?S`b$3N{q*EbPI7|K+ZI`nT$0O!WYYET ztavv_f(He!2$3=4CU#S53st?GB)e+=}kbxjS`dIzR8r3RDuy$SK z`Zb?!SRDoMsEwM>$WU_AT7Yjx+UOWntWpO~Q5P4V@OiYB9|;)}H*VPo*Yk#?E$T$D z9&Jq~N%a@u`mGSxhhvP%WRO#2!k1rdN=c=}M{LEZn5Jn=VsTCwC?=jv+LXpn+tNjN z`ZfyFMx&9<Jt|nKHIhnOUjo?3_$0a) z1%(1$SRljLh?jq+yj%e{7iHv9nY&WS-65HjWkazgfLn?;STMcZ0~+UM6qyAAjR8^2 zo|13AEoCTFrV|KsW$3?CKzlU;L3$Cv3nIV!e&2dtP+n0Mz{@Ji|0f`d1Z|e@KOm== zAAbBv_cKFP9<OXjvfo($BrJcG7Rkx z!&K#2D+2|`t12uuilOWjb3#U(ED_A0MW@W+HMMoW77(aj z&?987M?^tGovcP-K84t70r#iz^qD5qY;UO-r3lrx*qc$)nbVB`M@^2nX4I-B+W_81 zYFklroTCX6v|E&CQOCJ>Ex@($=Q_|?rKKGbbg*nIYVCB2+~~_OIXijIvK^41t2?9% zx!mWW=W@__w+nTJbaz1lk2|pkU65x%O=`@NUqC&HZVxyEL!AqGUA?~n+}rE&B3GXQ zn!!cSrTzglIMnGC{|k?|b7&9^I4*fEit-NUuue9Ds&__TKHM+D`ww4^-dT-CWV&Ie zXdBzxM@O!VpMiQ^uqC8y@1FQR6AYyFiYPr>!ys--v(~6Ea2I2sQ+#370Rcb&KQfFr}&}=l2OaDA>38rkb2E?1uPm!vv|mIk^uMp!&_~TN9cb2@1&gTm>_)kpXcD7;PWI+QYXegNU z;WnpRA<_m+bDTZ@t{$tx?g@7nuTpp~OojD#^X(ib=z_n6(;6j#@7KgQAb}&M<~}Br znrV?XGDaUqC|iihq0;1XNKl?!Iy6bNC<)GIWC8{L84xK}c}&|m2XL?2AMlY|QwaYI z0tJX+xODTw+2lW?BIPP^f$G8B+=JxVhvsyS5!Cw?eGSF2wrSHnJ2Zp&xw&~;Y;i-M zSUH~s2g}axT_@Zdyw3bzf6vddtYZNhz#b}&ojM3E7W5CF*y2MhH~=*!6gnh7d4e2; z3E=*MPp#$AlwN}C^;3^5wGspR%d!(BzZY}~*=1tyz1Qi;Zftf-aJRd;F&o@p@M-OK z_RL7|nVBAEH~dgW$hElWmFO{IS?}VaOJcy|e5L0Jc$Lw@!V`}&|FMMNY1g>o+0s*p zK3#gI81I6xKZ9dS&tJUk18860%NNg=#s=Rw_%F&)r3@UeW^Vuh002ovPDHLkV1hHG BepCPe literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_cardboard.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_cardboard.png new file mode 100644 index 0000000000000000000000000000000000000000..cfc30dee8bdd3ca219b43f060c8ae29448ce1fa2 GIT binary patch literal 1011 zcmVV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ> zRWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j)q@Ig2ttc@!6~s2= zQdV&Fa{-$O0Gj_84mqJ=L;wH+%}GQ-R9J=Wm+e*}F${)VhE@ojkB(KRE3A9}SGjK@ zutJ*-=eR%3QIPW{4{17WqA@>qYnJUh`ljo;jqb6gZ*AwC>ly$L-P^6EKiO{QcI$vA zMcx~d3`hr%_ns^~6#_Y|(dht^B9azQ2SaS;P)D#HLQr*c=xG?oaiIR-%Q{$p2o$Di z!t0?DJsR?T^lY(rz93jXx;{+vJWrwbwG;+8JUh1M9;Lo_;oKyi38j1nM0~YF22=$M zAzAMLY;ebpEmITr)Xra@^{+rps2@$`;=0l^wV`aBWac8msb% zSS!WSGXQ{}Sw$DA32+YqlnOqw1i!X~3qaF90cr-g?XW}qQs1XlU3Tg6R?{Wa%6t6_ zq;FZReXZ#~_TQ{sxb_p}Sj01ecnD|}@pL?%czB>%xZxoqC7BOY!0(TfOG$ND?f-vZ%>hE1N^0Cl zDM{OD{6~StSQ&4w2EbU(S2qA!0W`Y*V;OuKKyGX=VI9z}0e5hnkkaRj&;sx-X#~V; h!^0II)&P{P=`YW8DpRa1W{Lm+002ovPDHLkV1h3yzoq~H literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_cloth.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_cloth.png new file mode 100644 index 0000000000000000000000000000000000000000..86eb0a04904f0cc0741d90bdfc9136353bffe26e GIT binary patch literal 918 zcmV;H18Mw;P)P)t-sz`($+ zuCD3n>BGarl)twB|Nn`JiLkJ+XlQ6YK0ZlFNo;IvDk>_Gk&#bNPfAKkT3T98PEM4R zl$e;9)z#I8hK5vBRI#zKYHDiiq9YXm0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pS zoZ^zil2jm5Nr{UyC9|j)q@Ig2ttc@!6~s2=QdV&Fa{-$O0Gj_84mqJ=L;wH+h)G02 zR9J=GR_&78APfX4Ul@F~Y0~!npR`&zm!`2KGIRfq8Il>VSgnLWr1afJ&iQLN5k(e5 zoH2Zh5q@Ag@{!mzV8Y;oho9~SBZ89ypWhDQ>@jQ}0)kC}w?17q2Xygp%B2)$7oT*O zC{MPu6{A@=46qH8%pY)I5I`b^iNhkX`bUP@r~|$qMpDZi zzQrlo4UVH?(Q#!Ym;DO?wUDeDc=C|9p8)6JysPuTK%EB;J{4qgaHJ>-@vdNBh5r=f zcNDLCy#t#pvuZ%0#_*RY3P$u+xYdQ-$8WtJE3Y&yI40f1fdU0F2%TqX)p~ zeK6{-qvk8Mb`Tdwzt)d&`xlE-Xfb*}puvANg!5Q|d)AWly+YQN|I8pK5_abLx~xhO zZ6o7}u`bnMD05wZ%HgUOT=57>I&(mj$Fy6;P~zRDqGkHfs*LzVloH-1%K|Ft=9%Q6P}O;-%Z` z`%f8aBnn;$Qfq6MO6$10U4rXX2#EXIcI!c*?BC_6)&msrMIY-Y2)i}6N&~%&(Zle#{5?XIe5a#GD1<@|Oqab*H sd@2}pCLSq>G;|*J1swr_j{m;>1;~pPf$QP;R{#J207*qoM6N<$f^GJp2mk;8 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_diamond.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..8701d58ca5eb1d57b738eb099a745ca9e1795007 GIT binary patch literal 2175 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 Y0kQNWFb5?@7ytkO07*qoM6N<$g3hAHlK=n! literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_glass.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_glass.png new file mode 100644 index 0000000000000000000000000000000000000000..b49db9e679d97f61dcb35dc1b7201cf73478f74e GIT binary patch literal 4087 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 aV_Srr(B6AryISBR4?=3_saL7mMg9+=;q?>% literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_gold.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_gold.png new file mode 100644 index 0000000000000000000000000000000000000000..e1353ea196848f1020329c2406dad973891fa3f4 GIT binary patch literal 2043 zcmWkuc{CJ?7ruC@h!*RJOgv%i`x?epV;ResK~wf&2G5?T$x_A`ONp_sl`LsA_N5o5 zl!{V3(ytUML==VcEN^~)+&x1c zzXI?oI6Ju6^!D}|8G(rj7#l-W6m)gLxpP1ufU7H*nu5DK#Kb^!G~n@IVF9O41BC*< zzTo8r%$~NSBwI^^U)b~YD7YARS-LUS{O zg#nw*K5+u_^TE~@LPH@g4&vkC;ze+Dg!AX2y&cG8^2w86Z4G8-W*7|S!Ud?Qf!0=T zaVQFfs;-9Hx8eA4xOVN@_3O~m0!~g&;o%Sz1ZU2`jT?YQLuDoS_&|9%HwA`<+&SRk z0eX7CWI|~vuvl>C4&ZQ5PypK6kdOdbSx{C6c6Okn0}TyOR|j-DT)qsKE^n}PrAd$GcIEBSx z&z=QybLi}Z`g*uY=V~b|DuOFlV03geH8s`E&8@MqF*rClBm|_TK}-zfCb`64H4$j~HuGw0{&OB8Czk1`t<@BSb`jhybULRm#|??YFfw!$nrkJi$}@CW zN?HbDefpnV2@$K&JSBUect=v$=(?{pz%CJtHQLRCHc_xe93hDIhckpx^0&@%8r_IN z0=Ie(e0h#k7L5-&kRJLEYtoBNLIwY^o1o-M=4dkwc+h=%lW%=WG-?w+9I7^Je)?2) zay@>--h7=J9ToQC`Cd!el6{mEb;aR*8_WN$CFWE=92s5@nlqBzACOR7WOJ!hmsFy* zI}>UC3y~MCMBk8(Le{<0ATRj-KtGvGd!F#~dqKaj76g&|6HvL&OnARjKMksBzI9O7 zv~l-!S$6Nl#w&bswv?@zihFbYr{Nji$2UbtqBh?KVk?q5Ob+`y^beDJ^07B=-DzIb-(%`=pc7yhZ=i-pyw!dCL42<~DItBzHn+_quahoaNty4#hzsMyWix!?|0aGHpmV-8Nj*h-XQ)>u7YY1}`EreR_`+BIA;x zYmCFp4MPD$rc*%XO%LiJ89swl{vib7kJfeibD5%T8zv?bv?^UI^j_v*5? zlLJj;YBo4t*WR*rm^Y)vXXJ$hKZj&)_F7RhJypEPVAM5dM8@&fsg@pb z-+zl|Yj@1_(cky!U$S%g?JM^gy*R+SGm<%*ljAp)T%&7!o*AM1lw#2ul$u;pqIT?qJAe5kG~M5-3SFslR#?6r_sB1m+)isN?B`{2UaYNQpNwG# z$+UqLx=rLti%?iwS#5~m-<@R)y`M-GrD4BF zdng?!Ovm=pn>P8q&p6KgBgyddJ1bVI5pX)gM+DRHLN$F*vQ)6f0KfU&_^H(2^y`VTJ} Bacuwq literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_leather.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_leather.png new file mode 100644 index 0000000000000000000000000000000000000000..547484abd056e49b245f8e6268f8e7491afb85b3 GIT binary patch literal 1917 zcmV-@2ZH#CP)gM@up$}|NH!uN84xrl7&Zokxe=zRzWFGPfs!>7fw4Q9~ciVBNj|KBqkja8x##57Y

Zi#IU`d)CsRHrC>|3@HzF7k3p_3yL^B{H8xc`GCOZl+J|-3s3Kb9v9u^KtN=j8gC>9V3CL9tI4+%0R7a9}{6AlRy4G2^}CmItB5DW(r z4hRqo2oVejFC-QZ3KAp_z&V%uN5;x{+5p~(yscd}2jv4(^mY6FJ*{4~CFBrr-EhJ2 zssnq24S?~eH^?yTm8MWH#6wLOV1V{T990g#|&t4A$o)&5M49_4JGU zO}&w_+~lzk4u=KI(|Y5?MQ-r}9v3@E5Ae?0+Sy{d?YxMuI^2rr4AfAB?u58UtSvedz+a>(&@p?4)Yoyf>C=R}Ca*vW6#}(*F!dyQa)Ue4OCLj)~uV zzl*$-NXs=`PA4Ss(m*7}wP6sqf($)0yCfk1ynAq{R!~$TA_>z>okTnj^-Q4+lP{ImE#u`JnY-ZDlZ_YfcUFctFJK-J+fNMovZhXoON|_vZ8-F1IIAd{DpX4tb5kUK zJKdFo402u5Z!t-^V>)FN!xe?3=E;L-BB(ieKT8TGq6g$WMJkoBSZh$tfb2^XUEcN_ zFjuqhR1xVuvYJ7y0TM;U5=*QG?{QATrf*<-cYORVxSEJr6j2jjwOA)c9de92%0d~O z93P*^j!|M=FI-hJC(EmM9pF4dCx8EQvMS5D+6&Yd$rGavYXV*i|Eh9~P8e)z8UIMm z@Rx_kjrigH1fdye*BUb5p^$Y~nlWgwl^paN{xA6agGs$}@3WQ$Gjl})UM$XK2EqG< zs)dz&>Ck{59+vVe@TQDV;qEySuu&x>{OV zq@<)bH#dlgh?$w0s;a6{QBj|tpS--hx3{;Bj*g9ujgym;I5;?^rKK}7GohiOii(Pl zkB@+WfVjB0wzjr1GBPkQFhfH_z`(#UF)=hWG*wkqD=RBfQc`hoaX&vlFE1~KhK4&k zJ18h9y}i9UIyxjIBuq?9DJdx>B_*4in`>)pBO@aqARuRFXQrm6At50mA|f0d92*-O zA0HnI3JN?tJQWocEG#S?9UT@H7FSnS6ciM5b8{LR8WYE62mqS@7!En1VMG7`1qDe&K~z|U z-IwcI6Gs%rXQ+ih*%0Vr+pUTPQV9^Cm~FPO86d#~ArK7GfHr7b2o;scf(3+x%aRZb zpj<>0!6I^NMZElj-KEw(X7}uue)D~veA(a3yJybKoSa4IV-rro|Brui?9(I-o|Jqn zMaw~#n)X>*It6k{pJB*M)qyJe70$#5cLe^8lWg zZ~T@{qtBcKcmXmM78#25W-vr^Nom=4g(hhvLV<;67xKdX{^pE8%IiM=1djgs%unuO*MykyWP%X&Zf3c zj@oma(^bjTWjeW>^UBkL&*vP?mmSX4I+O$m^&b2QW| zxTm?co^uvd(ic*koHw_{o4~y-xn9g4<$%Zawap%dfzgIIaLl+B z2)=qnk>yTzLpS-&>Zrd)^$_><8#fd9%^TO27d$CK~j1cX$IF;es5oV(M0_ zB7)XiloX;YYrxyl-J58D`UKSH$><-r{d=R74MmQSheK53;BDNm^YkI1Pr+pk4c{SX zBsj{cQiQnC;0PjjhKB%-NT_54g-!Grz{hA)7>$&K2xKts)rZl?~!(FmGK5vL%7ShRcw-Nh~_NkcAt z7tNGMV_*cf+YuCx%+3KkJ{yUn$h-}T;9l%LSwM?R&baz3VsYovB3cODkKI${6QbXY zmr3KlBcsiUc~|1 zc@{I9G>*0^Yx+BRTBDfWWH8Iy6%N=Zz2EpOZ3{b8+lwRBR6Foi+B2gRgD=rRUYIT_ zj$z+M;~-=(*tp@tV`5aNk_ODPY|!%DiVf-8%I@Nwnzqvo*!tWOWLZTP

_0dJ3oZ z7lj~$P*Hy>ru0USN*amX$5Q%HYGbL5P3#TctDS9I+Mq`D6zj7mUO6I1KvlSL(b!}N zIIF=ON!VRM$q^{-EFo--XL^^toR@IR0Ly}ccFciL0K64kOhKiE75B~$u&6!y zWt6|RYaol6F311>|8F6XYaonO8E&62&X_L7OBP|FFwu#LiE|>Ac_f~AB%E?0lyD-F zHxWpeEya~B!kaJ3TN`(ikW*>!_ zF2-nRXgm^5Umbio5lTKjK1oSQXCH-S9)yc3wU;f#Y;0^#7-lLeDvBwyjw`t{4?>ZV zkv9-WhA6I`XwQWx}8WRQ>3D(9nl8va5>SsTxr-{a zh$4|l7G9W`n13dwfhVVSBbn9J)rN+KDGWALR8+CCv1)2+SsQdC3oaK29uWl>5(O6> z2_^^v3IzfO0s#XA0R@U?iL?L!00DGTPE!Ct=GbNc003orR9JLGWpiV4X>fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KAHiHkEOv#1!Po{KZBC^0t`#5UwoR&e!m0h?S`b$3N{q*EbPI7|K+ZI`nT$0O!WYYET ztavv_f(He!2$3=4CU#S53st?GB)e+=}kbxjS`dIzR8r3RDuy$SK z`Zb?!SRDoMsEwM>$WU_AT7Yjx+UOWntWpO~Q5P4V@OiYB9|;)}H*VPo*Yk#?E$T$D z9&Jq~N%a@u`mGSxhhvP%WRO#2!k1rdN=c=}M{LEZn5Jn=VsTCwC?=jv+LXpn+tNjN z`ZfyFMx&9<Jt|nKHIhnOUjo?3_$0a) z1%(1$SRljLh?jq+yj%e{7iHv9nY&WS-65HjWkazgfLn?;STMcZ0~+UM6qyAAjR8^2 zo|13AEoCTFrV|KsW$3?CKzlU;L3$Cv3nIV!e&2dtP+n0Mz{@Ji|0f`d1Z|e@KOm== zAAbBv_cKFP9<OXjvfo($BrJcG7Rkx z!&K#2D+2|`t12uuilOWjb3#U(ED_A0MW@W+HMMoW77(aj z&?987M?^tGovcP-K84t70r#iz^qD5qY;UO-r3lrx*qc$)nbVB`M@^2nX4I-B+W_81 zYFklroTCX6v|E&CQOCJ>Ex@($=Q_|?rKKGbbg*nIYVCB2+~~_OIXijIvK^41t2?9% zx!mWW=W@__w+nTJbaz1lk2|pkU65x%O=`@NUqC&HZVxyEL!AqGUA?~n+}rE&B3GXQ zn!!cSrTzglIMnGC{|k?|b7&9^I4*fEit-NUuue9Ds&__TKHM+D`ww4^-dT-CWV&Ie zXdBzxM@O!VpMiQ^uqC8y@1FQR6AYyFiYPr>!ys--v(~6Ea2I2sQ+#370Rcb&KQfFr}&}=l2OaDA>38rkb2E?1uPm!vv|mIk^uMp!&_~TN9cb2@1&gTm>_)kpXcD7;PWI+QYXegNU z;WnpRA<_m+bDTZ@t{$tx?g@7nuTpp~OojD#^X(ib=z_n6(;6j#@7KgQAb}&M<~}Br znrV?XGDaUqC|iihq0;1XNKl?!Iy6bNC<)GIWC8{L84xK}c}&|m2XL?2AMlY|QwaYI z0tJX+xODTw+2lW?BIPP^f$G8B+=JxVhvsyS5!Cw?eGSF2wrSHnJ2Zp&xw&~;Y;i-M zSUH~s2g}axT_@Zdyw3bzf6vddtYZNhz#b}&ojM3E7W5CF*y2MhH~=*!6gnh7d4e2; z3E=*MPp#$AlwN}C^;3^5wGspR%d!(BzZY}~*=1tyz1Qi;Zftf-aJRd;F&o@p@M-OK z_RL7|nVBAEH~dgW$hElWmFO{IS?}VaOJcy|e5L0Jc$Lw@!V`}&|FMMNY1g>o+0s*p zK3#gI81I6xKZ9dS&tJUk18860%NNg=#s=Rw_%F&)r3@UeW^Vuh002ovPDHLkV1f;d Bl*s@9 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_plasteel.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_plasteel.png new file mode 100644 index 0000000000000000000000000000000000000000..da26728fe39fd3c8382d23e6109f03737362d979 GIT binary patch literal 1927 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 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_plastitanium.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_plastitanium.png new file mode 100644 index 0000000000000000000000000000000000000000..32e9549dc5ba626267005f0b19a911952313ebd2 GIT binary patch literal 1794 zcmV+d2mSboP)d3Ser zNl8htu&^&LFJxq7E-o%eNJvmnP*G7)Q&UqjGc!_BQfO#sFfcGJEiG?vZ)|LAKR-Vz zDk^SnZgO&RDJdzDk&$a_Yj}8gN=iyaMMXeBKx%4gH8nLQB_%sMJ0l|_V`F1;b8|O0 zH)UmIA|fJGR8(GGUTJA*GBPq^Vq$c3ba8QUS65dbA0Jp)Sa5J~9UUEZc6J^f9v~nf zG&D3D8yh4fBpMnT85tQC78Vy57hhjrF)=YhLP8Z46%-T{W@cs)5fKv;69xtb4Gj$v z5)upy3`a*t5D*X#4-X0o3LzmO92^{Vb#+5SLrY6bPEJm3T3MKwm}h5a)z#I8hK8}R zu?`Ln1Ox;E0s;dA1F9NA_y7O^0d!JMQvg8b*k%9#0A+eqSad{Xb7OL8aCB*JZU6vy zoKseCa&`CgQ*iP1KApfgRex5qt_ z3}5z}&pCYIckh$QOzva?@T-aOF#nI=y6yFh;2z)Yu~82G@rj8EAB%F9n+%X~Kg#di z<)`jV@xNgXEI<9b5WF9_gBd&s&HQoyp?EKh@Ngu0o1fsN2MB)zvFX`Bh>N2k#^>e} zkEdhSO3Wb{c@n|*TMoh#A&KsXg+-nhZcU~ZFrJzugz$?fm-xh!gp`g*?kg5Zgvhc? zc;e1kMWXY(AT3epsp`VjrxKAfnT$*%#jQ@^>@&%miwMiaE6vExr-hMcuJ_vx&$2Fs zVzXh1&gF6|c`7l5qJtL;3?UhE{R?NEA<$r!mArC7W)M^ryREg#o_U)>}VD&9)g=i~R(_WVA!v?Ua!zP{FY9yBnETkMc0-6H0;7KxD ze!2!>uqRv4YVT}U5o2_2Q%myV?F3AJ6K=#>?nQcjTt@6psyr*Fko_6 zlIl5T0KKH;f<>St`!MM5?jd}z+aEx`s9+K7_Z!;>uwUp7+%M4|bPM}%&}{VgU3tf- z#+gId%uOG8-3qnsJ(|vK!XXo{8m?(HrYH_O*f-`^j2ID11$0*R z6iOnA8H(Q}4Ma9gbtRo50pDlmbaA8NXJ3G%(krTIIQ-u6^prz28vd+e5nNteT-HKmPZ4=iPMf-Z z{yc;}M{xQ4@5^&tZ=PZc^w;H(SwRmA3mP#PZsRrVE|rdP^C>6{S^QM&}DlZNunwNAPa9XBc=>w%*`p zXM+(r23;SVouTuErQH>-e}z^VPEW7;+{*3@~ literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_runic.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_runic.png new file mode 100644 index 0000000000000000000000000000000000000000..e3a43f47b16e75603074ff4b20a930f813988d15 GIT binary patch literal 948 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 B)8GIA literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_silver.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_silver.png new file mode 100644 index 0000000000000000000000000000000000000000..b7ba888b71a1e32d1c3129540a08a383e0023fea GIT binary patch literal 2020 zcmVEySuu&x>{OV zq@<)bH#dlgh?$w0s;a6{QBj|tpS--hx3{;Bj*g9ujgym;I5;?^rKK}7GohiOii(Pl zkB@+WfVjB0wzjr1GBPkQFhfH_z`(#UF)=hWG*wkqD=RBfQc`hoaX&vlFE1~KhK4&k zJ18h9y}i9UIyxjIBuq?9DJdx>B_*4in`>)pBO@aqARuRFXQrm6At50mA|f0d92*-O zA0HnI3JN?tJQWocEG#S?9UT@H7FSnS6ciM5b8{LR8WYE62mqS@7!En1VMG7`1qDe&K~z|U z-IwcI6Gs%rXQ+ih*%0Vr+pUTPQV9^Cm~FPO86d#~ArK7GfHr7b2o;scf(3+x%aRZb zpj<>0!6I^NMZElj-KEw(X7}uue)D~veA(a3yJybKoSa4IV-rro|Brui?9(I-o|Jqn zMaw~#n)X>*It6k{pJB*M)qyJe70$#5cLe^8lWg zZ~T@{qtBcKcmXmM78#25W-vr^Nom=4g(hhvLV<;67xKdX{^pE8%IiM=1djgs%unuO*MykyWP%X&Zf3c zj@oma(^bjTWjeW>^UBkL&*vP?mmSX4I+O$m^&b2QW| zxTm?co^uvd(ic*koHw_{o4~y-xn9g4<$%Zawap%dfzgIIaLl+B z2)=qnk>yTzLpS-&>Zrd)^$_><8#fd9%^TO27d$CK~j1cX$IF;es5oV(M0_ zB7)XiloX;YYrxyl-J58D`UKSH$><-r{d=R74MmQSheK53;BDNm^YkI1Pr+pk4c{SX zBsj{cQiQnC;0PjjhKB%-NT_54g-!Grz{hA)7>$&K2xKts)rZl?~!(FmGK5vL%7ShRcw-Nh~_NkcAt z7tNGMV_*cf+YuCx%+3KkJ{yUn$h-}T;9l%LSwM?R&baz3VsYovB3cODkKI${6QbXY zmr3KlBcsiUc~|1 zc@{I9G>*0^Yx+BRTBDfWWH8Iy6%N=Zz2EpOZ3{b8+lwRBR6Foi+B2gRgD=rRUYIT_ zj$z+M;~-=(*tp@tV`5aNk_ODPY|!%DiVf-8%I@Nwnzqvo*!tWOWLZTP

_0dJ3oZ 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 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_uranium.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_uranium.png new file mode 100644 index 0000000000000000000000000000000000000000..7db2eb454fe50092f909c72a55d0c9148eb96436 GIT binary patch literal 2175 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 IY~RWH54x;-h5!Hn literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_wood.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_golem_wood.png new file mode 100644 index 0000000000000000000000000000000000000000..868ad85331cdc5254ccec7cf5c797326dcbbfb68 GIT binary patch literal 2039 zcmV;EJ80IKP?_aFd$k$D_K7(G9wsAGa^wsCrdRXNHZdozqVsW zFOOwJ|NsAINik$cFHblnlW9hcWJ5(UA(d)JiHV78Ofzv%HgHchYD+R`N-;Ae7>i;; zkY+_yJSecRus0_fPdFxYQa3gx8dN(dT|z8gLM&lLE;}k5Uqda9WkYCaXgDYuH6#@mT|Q|_GG<6HWk@h-OEM@O6LwQLdsjOp8WD3+H)cpNf?Pf% z84)5F5K2l)ief<{84)EK5+fN99~KW$IVLnE86g-DU_>q|9uyuH4jmK@hhRV|9TXW7 z3>_5?8WIc}6Af=qH8?06Og1D3u3I|d;Cld_`5ex_m2n8k^5+D~3JS!bFCK-reKu0nnO*bW1 zJ}FK&C0bfqPEJlSBNsU+8-ZIreo8SzFCdthn08b+cvU%WPBhik)rN+KR8&;4v9W4u zYEwHWAr}x94+;D0RaR90;xH<6#xJL0d!JMQvg8b*k%9#0A+eqSad{X zb7OL8aCB*JZU6vyoKseCa&`CgQ*iP1KAp(M&oah z@fN=ZV=vzMS(+MUoNKLXWa`hcsO*SoBbeQiLRh**LR1Sdf5F=OXEc{hYfXIx}3!?U+N06tV;@(?P&^i zXA7?Mm;+&kWjKbtsv)lhWitp~BQ*>w#no`Y+;b&cfO>g!oy+(4Iezn#s9#ni#PuW6 zPdGGwEq5L9y)rJvz>S-OXowr`SELB_4|79k@aByHfTO`k*$|4_C>y{<5=BF0kwHi> z5-{9CvD@XKp!{|W-7*A5AVG}hqbNEW2T!EfTzb3X_T07Lo=96-J6<5lQW}fHsmNpTS-WNq_4-Qg=S(T^shs;IzFst^vCqa8%Q!MJKew=m#?$lj^GXXf zBL1HqM~e${^CRFwehLv@>U*HZAM`C{Z}g91y4`yAA-Gq>?e_4jwS5}q(KEBv%a&2_ zQH_pTmaAvafE-<^-RIUlDugx@vJ^hjxplSj(`Yxil|u!sMuTol8IS1<#@2%SEAr!N zH_jh@Oj9fFJc#GHS19^%(RomS`j662R;&dOF0igVq5ptRJS4vNFdeqhUqSSUf0z9kS3o(dLH7U&?TYy+r@Nh5JtNyf@38S*W_+n$@Mb-LC z&Lgn0d`U4uw3))ImS-F^gUyYN&9JGBm{3X=V=2P(>&Hy+X50Mh@6C0dk1Rn0_={~O z{RMEdpnt?LwO!=F0cfD2C8GMtqm8swfc=FSeSuecrwVsE^{)bbDg&lE8Y)!37wi=c z9ZK)L-H0^|3?)@~GC4HR0QMJ1YBA!eH5IUN;+3 zZ@^VXOG|H3hUV8Qf`#a^HnzP0(S_}pb~y@RDJB=U-@bc40nmww_wU|rFMiyg{0kEx VTxm?WzGnac002ovPDHLkV1fcVOBw(G literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human.png new file mode 100644 index 0000000000000000000000000000000000000000..767a2ec704d1559ab7ec4c9fe4f433a8bb45bdd6 GIT binary patch literal 1075 zcmV-31kC%1P)c6yN=izutgJaXIZaGVKR!N7N=lfNl>h(#>gedp$;p0xespwn zT3T98PEMGZnAO$QA|@uMsfFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5f zFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LYR3KAHiHkEOv#1!Po{KZBC^0t`#5Uwo zR&e!m0h8 z5+uWsV1*KnIDr!_aR#ZmDL_jKeZugCFk0fDVM{cmfPBF#U;;lL6{M24y~#qiB=Aufgu!#`hMU9VAKeSLNLxyU!eEHG?} zTzr}1`Co~D#Sru;@(&YmzyKWNvTgv#AJh!QJig&?N3-V@1JNAe{eR3Rz_F~CXyBxw z6s82z5LL`^G-oV8smctv1WMuY$_fZrD5Yv^fSC74c<;G@o3%25K^!QrIKCSvM3pmh ze?>btja@;(_1)y~$gL^Rcs!Qf)b*Ky8^;MxGrWRPgcG2_bJ8@9Zx!gpkR>e7T#yek zP`$o)-+$~ZnA{+}DpbddpBQ8T*aTFlZiTs-Yvcb5kU$FIt|o970&5Q_W^-`Q^ZUJr ts0hsF;DN&rPacAgy*YT~@MFO|`~s-XL-hQLJa(dxgnl)tu#iHYH_rm(QEynAtIXlRa*lRiE^Nl8hwv$J$} zfNX4RDk>_Gk&#bNPf<@>5fl{E*WXG?O0KM|IXO8^OiVvMK1)hUn3RlhK7bzR8+CCv1)2+TUb_ufq`&sZCqSj8@|Jj z00001bW%=J06^y0W&i*HWqMRtbVOxyV{&P5bZKvH004NLQ&wYE62mqS@7!En1VMG7`0}4q*K~z|U?Urj-+b|43?Wm3+4R-9fq+6Tv z+8WBbjmQ80Z)}H6l zH7U60LTX&(xo;PX1sVh%n)47`2)gl z9aRvif^M2Y+_#5&pc#%8Muqo)1gRPSn)2~2;Cjz+)y3`)0sS@QB*68pXSl*02(JR% zv(; z&|w^2{*A9z>%Lcgzh12bzUeR2MZXdF<<<4g8U^c{>#IwaZ~9TtZ&vmKCS&dfuL_I}v5ykPKnt9*<=|FaoSaY_5vCeN@ zPT;n_qpL82_R#jJ#9Rf=)6qM&XinhXBXF!BVdJLr(!C{cl!Z+`9Shp6)-G5|&Z09yb6hX4R#0001B2}A$@d;kEHzqSAX0FwX!iHV7@u&^5& z8%O{E8X6jCXlRa*lRiE^Nl8hwv$J$}fNX4Rk&%&4Pft-#TWkOTBO@ab6cp6g-%3hK zuB@y%IXO*COg}z8OG-+Zl$8Jf|LW-I%gM=petvXxbXreG9 z004%DhE!Bkv9YmgYHC|pR)c|oaBXc|TwDag0^k4u00DGTPE!Ct=GbNc003orR9JLG zWpiV4X>fFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TB zGg33tGfE(w;*!LYR3KAHiHkEOv#1!Po{KZBC^0t`#5UwoR&e!m0hNxb4l3 zo9;+2_mlosjBJUq_hw0&{1xY!$apMX#(BDxXZbemkxDiBkf$Wy5!rNinrBp&sZdHu zDRwAReLIv^%0bYp1(TPi>65MI+wRT)gCPyOy;JilTTqrp@aH$Z* zamA}o75{u(h|z(1;AlY(9w~g8))q4G_(E_^aWtqEETmway@lid+QBM;DtQzbcvQf% zP?0u2Vg{l-qBEFb|5h29K`x=aM>1f=ESlmVKo20$_l$$X zN>3;(1?t>{2x~_-Y3|cUVPy!e{ zIQ3okQUN~3Fdp_pUw{{>LM zJ9iTkxN(jg5736;;FjjMn;9Y^FboHG6ux_yA!yqS2lo`d4-5~#0ErG|v2`~v^#A|> M07*qoM6N<$f_6spV*mgE literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly.png new file mode 100644 index 0000000000000000000000000000000000000000..8951c16232efb8c5281737832cf930f25914d02f GIT binary patch literal 2444 zcmV;733K*|P)V=-0C=1w$2$&yAP@z>nmxq}_Qqekje!^nxPytSP^bwIy}pIhO@rAkF2Hz4 zkK~f>3yi7lNWE#R5sYyl6(t?9{wZ~>0*2P4wv-DP6RAC~rxY-HYG8wb@s2*4{}>LN zJdk?;00`VkL_t(|ob8)`Y!l}h$3HGmK|(TbDVYLRu;d=gVDm%^1h!i@=leY0_s6~WK5tBZzn{-Do?2`N78_3lF!CdZ z=#Wy~XB(O1H|d=N9HK*_5|K7sYGLf&@A8|BI&OAUFk6sShz9iS3eZpeypDEv_cQ_tYA5E1QM_tu~(Yb&96&< zsqWjb1aJaZ5y_8z9{@hpOKlM57}q~2=5G`eq?j)O`7!@=LbCwTXjCdKEj95rE@psl z;^JGe?sJHASOQUA;ipBp8iGC9~OVQYWHZ zSg7FR;Se1XKSkuP6eBRid6{4FPme8K0(iY%Xe^ahk)1Xl|rEqg3XFxvr>1n0hU7D`wePYC=|l$^=4%v^m@Hg ze}6xM%}QI#1?+aa`e|#qfMB!I-`}sBUy}eGm;9>oM~@x_V0BReb^mH$bx}b=`MQz~ zbX@XhR0M@TH#ZlL$AjH&M-T+{W4GJ!cs%6h=IZ88D?rC3zqGoj0KsMjKoA7^+h!$I zd8R~&=bxIIQiG3&BEr!AE23ly@%*=L z-2$Mwxmo?hm+R$EDL}_1zw|=c^8|u}YOsPJs06l>N3E{3%9YL=1cHOSQ1<-1dqFaO zyWLK6b92HRpxhhbPul|m!9hmCV;nwGYXa1keym=s{P2-l(@1zsZL#@cHa~#V=}edd zoKB}&UoU@30fGYoM#5tR2a*S!>EA5|f6AAk*1U624txb##dFe5cBVDx5FHXf1PXy+ zI83cZx98yB2-sx)^^x@{>qjCHng9DhzBc~!Z-XPimw_q>{XE2rFIB7ED>x8PAA>Kx zRL#Zqcc2#eePJZ6Wo?)SY{&uK1fS2Bw3=F80jvT-+RUdH;2B^BXo2wPD1EoOxY!O1TZxcR-%!Ll_L!xC_WM%Q=J+Kk3CjD6PRr;8Gow!sbF|lI5-gC z@R3^6d>?g2paie*E5aMWlWpdCDBtPGgkKBB zuXzZJMJ*WaBh8>8{mDay*q*yVIG(A%3)5fuK@ zjg92z=O?X`pP$d^#zx)znl?p!K3`IU+qZ8wrTUvzC$#cUPfsV5S5#D(IyyQM_;Ye{ zbn)xX4gSC3bN?93hyV+n9?vAFVF45eV&7R$j3(h0XZc_V#t%qT#T?j&$bO^r^T2*! zU(AOp;|-u&0ELhhzHB4fVY6NaVIvi zjkCCTE5`ja@R@N_#sp}=HPw9^dMM^I;2>}wku3KDwe`;Jc7QpZFn=0R}q-|Rp z{GDQofCs?)u~x}84#v1107b|?R3h>RW8!OG3A)|xgs#11+jc|N=L?Q@+Kv!3nS{6U;RI5E*nW4i+YE8U>WGfLk@#h9MZrunhT<{>TO9~4M zxqSID0PSCIC-7jjZBR)`*R5&b_}b%Y@F#{F^qMk+>gsA!)5lHZr*NtFZZN zl=N*d?1WzYQuqZMHpqOQ*I(zE0^|D-hKIoHGXbj#3TSI?ma@Gq-qzeKttu!W)p-Ry zFw_G!KKC2|?eD#pP#&3>Fzkp{L?$K}86D-=v14l4jvYG;+xs6*NuF5K{X0tl0000< KMNUMnLSTX{2#b9H literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_luminescent.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_luminescent.png new file mode 100644 index 0000000000000000000000000000000000000000..690344a8ab5a1ee646231b82f5d99e6a42c8c404 GIT binary patch literal 2484 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 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_stargazer.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_stargazer.png new file mode 100644 index 0000000000000000000000000000000000000000..8951c16232efb8c5281737832cf930f25914d02f GIT binary patch literal 2444 zcmV;733K*|P)V=-0C=1w$2$&yAP@z>nmxq}_Qqekje!^nxPytSP^bwIy}pIhO@rAkF2Hz4 zkK~f>3yi7lNWE#R5sYyl6(t?9{wZ~>0*2P4wv-DP6RAC~rxY-HYG8wb@s2*4{}>LN zJdk?;00`VkL_t(|ob8)`Y!l}h$3HGmK|(TbDVYLRu;d=gVDm%^1h!i@=leY0_s6~WK5tBZzn{-Do?2`N78_3lF!CdZ z=#Wy~XB(O1H|d=N9HK*_5|K7sYGLf&@A8|BI&OAUFk6sShz9iS3eZpeypDEv_cQ_tYA5E1QM_tu~(Yb&96&< zsqWjb1aJaZ5y_8z9{@hpOKlM57}q~2=5G`eq?j)O`7!@=LbCwTXjCdKEj95rE@psl z;^JGe?sJHASOQUA;ipBp8iGC9~OVQYWHZ zSg7FR;Se1XKSkuP6eBRid6{4FPme8K0(iY%Xe^ahk)1Xl|rEqg3XFxvr>1n0hU7D`wePYC=|l$^=4%v^m@Hg ze}6xM%}QI#1?+aa`e|#qfMB!I-`}sBUy}eGm;9>oM~@x_V0BReb^mH$bx}b=`MQz~ zbX@XhR0M@TH#ZlL$AjH&M-T+{W4GJ!cs%6h=IZ88D?rC3zqGoj0KsMjKoA7^+h!$I zd8R~&=bxIIQiG3&BEr!AE23ly@%*=L z-2$Mwxmo?hm+R$EDL}_1zw|=c^8|u}YOsPJs06l>N3E{3%9YL=1cHOSQ1<-1dqFaO zyWLK6b92HRpxhhbPul|m!9hmCV;nwGYXa1keym=s{P2-l(@1zsZL#@cHa~#V=}edd zoKB}&UoU@30fGYoM#5tR2a*S!>EA5|f6AAk*1U624txb##dFe5cBVDx5FHXf1PXy+ zI83cZx98yB2-sx)^^x@{>qjCHng9DhzBc~!Z-XPimw_q>{XE2rFIB7ED>x8PAA>Kx zRL#Zqcc2#eePJZ6Wo?)SY{&uK1fS2Bw3=F80jvT-+RUdH;2B^BXo2wPD1EoOxY!O1TZxcR-%!Ll_L!xC_WM%Q=J+Kk3CjD6PRr;8Gow!sbF|lI5-gC z@R3^6d>?g2paie*E5aMWlWpdCDBtPGgkKBB zuXzZJMJ*WaBh8>8{mDay*q*yVIG(A%3)5fuK@ zjg92z=O?X`pP$d^#zx)znl?p!K3`IU+qZ8wrTUvzC$#cUPfsV5S5#D(IyyQM_;Ye{ zbn)xX4gSC3bN?93hyV+n9?vAFVF45eV&7R$j3(h0XZc_V#t%qT#T?j&$bO^r^T2*! zU(AOp;|-u&0ELhhzHB4fVY6NaVIvi zjkCCTE5`ja@R@N_#sp}=HPw9^dMM^I;2>}wku3KDwe`;Jc7QpZFn=0R}q-|Rp z{GDQofCs?)u~x}84#v1107b|?R3h>RW8!OG3A)|xgs#11+jc|N=L?Q@+Kv!3nS{6U;RI5E*nW4i+YE8U>WGfLk@#h9MZrunhT<{>TO9~4M zxqSID0PSCIC-7jjZBR)`*R5&b_}b%Y@F#{F^qMk+>gsA!)5lHZr*NtFZZN zl=N*d?1WzYQuqZMHpqOQ*I(zE0^|D-hKIoHGXbj#3TSI?ma@Gq-qzeKttu!W)p-Ry zFw_G!KKC2|?eD#pP#&3>Fzkp{L?$K}86D-=v14l4jvYG;+xs6*NuF5K{X0tl0000< KMNUMnLSTX{2#b9H literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard.png new file mode 100644 index 0000000000000000000000000000000000000000..955d413d50e2cfab4f2cd58bb25b544dc936bc2d GIT binary patch literal 1419 zcmV;61$6p}P)GbSP%SnuA7MNtWV=-0C=2JR&a84_w-Y6@%7{? zOD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j)q@Ig2 zttc@!6~s2=QdV&Fa{-$O0Gj_84mqJ=L;wH;DM>^@R9Jod3~gZ-ifR$#p&Lm_s!pG@qG^-oHuXK#&*zqYf9_gH{6 z8J1x`z~PWM`||qs_V)a0T@oO$HoKU$0RqJ2@A=Pvf9C(a8fy3fUf9gHA6pD@+N@E2 z$Pb4D2xj#m()xU~)8WVy`INO_(I(I`r-D_vRIl)=a9-OK?>Cvfp&U~ zKp0BlZwR^+7~Bv+IZmKWf*isOWn6!Jd_=fvhMY=U-MQoG)H%>iDE@Tp@ndC5aF{L)b1?vy41y_8 zf*p>#%2bB_28$uM!PuJ~*9WaYkRuFQj_C(u5Ra2zPNrdp>4Z?YFnfuPEpnJoZ^HP^ zbgo(#UV%sn{h{Yv26G4iC0TvYs{jkXQX?%pusw`kQpoCon3dTpaJ>fjRZ+h(T;c@5FrqOmSDX#|dd#DkWk18BTm zL1(|pyvE!ooijoJc>|%KeYW!F&q(15B0vv9rFc$6MSyIIek1~fTvf2z?LZ&}jd=dt zr`eAUqx}wR_PGYUfh^l=7~;nWz(8K)ef1)!gjJy%j86HaWD|~Wq;(Uq!Re}(}`3})KPQ_p=qs`8>DYwECDHmjsO&0 ZU002ovPDHLkV1mZRdW8T0 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png new file mode 100644 index 0000000000000000000000000000000000000000..24b9dc784bbbc2ea37c516cf9154f39b92495045 GIT binary patch literal 1079 zcmV-71jze|P)_Gk&#bN zPf<@>5fl{E*WXG?N&rOw06zc#DgatqT24+*0Av7|n3&bo)gmS)r>eGwhK5vBRI#zK zYHDgN#dVti0004WQchCV=-0C=2JR&a84_w-Y6 z@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j) zq@Ig2ttc@!6~s2=QdV&Fa{-$O0Gj_84mqJ=L;wH-1xZ9fR9J=GmVI;EAPmNlY3l?G z#wA@=o2JXQ@BbP12)t~K1<76i+LViPxkvh0ya_4wzZnsIPVc&|<#Air_|!c(zD0QG zx<`Df9wol(9%_K6KI?rIu6*0W?$E>wGDl6 z&iCHALH5{NXUB2GQ`Ws1f-~N@Fc>fEcATbZv^Cug&(0a=o(Cs*K+o|^kaXo8GB7SW zgAAMiaF~F}=5IxhoPp;I;?{$8JLWkUt)L@AuP_G;2t)q2)h|O3bQOL43&8)j`X9hn z=W|3C0Buhc>tO{1L5D-HgEuA`^PKO~3FGKippzVQLbv9AwT7!`p zK1_4Q)_`hSlb9w`5{};xiISMb>#4#2w%mIN{XbjPS*(HaHMtY zkJ$mg5`n(zF6$iJgR$0My4Wi|aLB)60=Z<!GkUjf} z@#DNes@GIiu4rqQc@zkC8W)R_+#+y1%C=p`X+yB{yr7!l3I?PG;Na}E%=0yY2L>(L z*|Y#=wvpemod!EDoPp;QTNxP3rFU62v%pix7wa7W!$a5r!UO=!+yWT(TIMNS12}`k zHy@mm9G~7`XcQ7>a1Br)WPnD7UdsUeb~?T33<#TeMjR4q^ZWa^ms$qr)9FlFr-Kx( zxDQIyy580K`;W7sv~7@zk&eC@uYSU~1*n`S9M|ZZMqM-zrF4l013@?3a%OzOHpjg;Uu@#Zrk(NaE5)l=dK{ xk_hbhS_^+YvYz7@Q96WFY<&S+3vlh5(l1*@G?&ojQ8xep002ovPDHLkV1kVf>3;wK literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_silverscale.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_silverscale.png new file mode 100644 index 0000000000000000000000000000000000000000..12ee5dc1c7ef1294ea3ff112aa52c43a03fc4a8f GIT binary patch literal 1153 zcmV-{1b+L8P)_Gk&#bN zPf<@>5fl{E*WXG?O0KM|IXO8^OiVvMK1)hUn3ReGwhK5vBRI#zKYHDg*SXP69fpBeYTwGjNqv?zQ0004WQchC< zK<3zH0001GdQ@0+L}hbha%pgMX>V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r z;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5Nr{UyC9|j)q@Ig2ttc@!6~s2=QdV&F za{-$O0Gj_84mqJ=L;wH-D@jB_R9J=GmThy}APmRBq;&!YTkWvUCur3!kZwW*EP4ehZ|TD5Hp z-?VOIW3@C=+eR8%S8dmIt;*@Txzbu{ebs2f1N0D&1WIQ{Lk3biEg=I<05ohsr@~)G zcbI{}3|#7gx@yB7w2IInL&IPX5MZ0|E7cE6Aav%8`vAaSss0y`>UfU$0l?D}g}R*p zme9eW7S>4Vq%>C41ORl~qFGAEGUv<2HrI{)w&dx7nshW$$6f;~lTt$lju8hU>ew!5 z9Sv#)3yG|=sE2-&)$v^$cnVP^?*Lc`rceMlK^4gXV0bO+F9HfplOuqa0S*b7p2aJ4 zz^yI;@O=tF5IDSB2gbq|ZBfU@D30GFhS#gry6;)vuU9KFezm&kZ`p0nj}aWhg}A$a zcw7Tu{rGTyN5tRV-}C{{-v9y_Q~%}fwh6|jf2nOY-@zDuZ8nFf%xeE-JGHEnx+o6- zc(qYg^eMjJaY_e=85HV8E(cy+2q?HBAdU#MOMHGAFrQ`+8Ze2)O_*22Njaz?hkQKT zd&*$bC_DgUgMMUuJB%RZdn$`pv{K{H5(L$?qk@)PB49kUZ8f%CLQumnLN|je7$7+S z1_!5c7>)_JFwmSDWCN+{@B{(k;r+q{V9av~@N5js2v9Gd33y!#59Jev zgO_~#OPnE?ha~Fv))~hGAF3}72d}yK*J*}e5fLW@A1!*s;ovO?c>6d!Oo4v@8p%Ks TGtQnl00000NkvXXu0mjf+Uo%h literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png new file mode 100644 index 0000000000000000000000000000000000000000..6e2d1a6114cc051cbcd435251c835ea8e1eb79f3 GIT binary patch literal 806 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 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_plasmaman.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_plasmaman.png new file mode 100644 index 0000000000000000000000000000000000000000..94b05c68a8f782d59db0334a6f745fb1ce476631 GIT binary patch literal 2468 zcmV;V30wAwP)V=-0C=1w$2$&yAP@z>nmxq}_Qqekje!^nxPytSP^bwIy}pIhO@rAkF2Hz4 zkK~f>3yi7lNWE#R5sYyl6(t?9{wZ~>0*2P4wv-DP6RAC~rxY-HYG8wb@s2*4{}>LN zJdk?;00{I+L_t(|ob8%_OjB7F$3JD*NI)AFf?3=qHo;nVbqkJD873GVqq8u>Y!rrS zmf@e7(LXR5N`y%4+>42f5LP5rz&AesCsxr<d{J9+3F^glXB4 zAZrbn>bXm=rxyT+(av@Eb<9RH0KJ}GN+^-bFB>9%GMvmj1Ofq}xVTs~ zUOTP|UJHh--~R3Se+Dt{+e=ApNm{BG!{_~{b)N1Fsh6nH=jd_zojm^eF(tJnX~o6G zLLd+jva_=jjzn2&fY`Y>4@Jz^{1*{z(L40rA(dR?L8b#58ykhyYt{nbee^Ibcr6%8 z-ghZL!?WVD@F(uQWv9VF;@9#%fpym9zvlt8p={kSzEV=?M{r&y2`4e(L%jI^- z^9K(e1YkveF8b;XtjN!ekgr~|mX^!yNp*tApOuw`)oR6HFrd@vq|0D1V6|Gw%F2?> zAJ+jbm)nIE`MKx{v;gRIx|zQPT4KqQ<%Dqlsi`T+_;83$n3|fB&7V*N=nAyB28RG} zxm?nHM_bp7Y;Xvd%O%~5PDvKR`S0Ah13+_gvvh^a1gZ1H8{lP(hYNtf@u5(gMsGe=7=>w{H=sPZUndnhZymUvH!px6(EiD zOYNS^_aE4!8u5%tBQ{se<_D;%s)|?xs;a7__Hy}SI$&_X#fWE&!GY*TC;PdD;E(Bm z;N8b?eUi#2#@<};dpPYGq4w%jF^Z8=7_xXIX`QvVd3-gL_jM^!56ooFh zFYx|{CMmoI2VBx?@cj=>T)NoAAE^mBM(q^l72)(d6EHJAf0OeJCU%7`aDmp=)~M}7 z`C7-iP?PfvCjG92_+vUipQA@K=G2{&cz*VB?@l+DF1lH{awXPpPGJ619d5T9tyYW2 z>*dtMNj@{|!7*w_pQBe`awNZKjAPV}$Lr;7qcN%zv|25lJv}%w?U?ktXmXxOh(GRD zxaG?hLEP&fKYCIqSfi6hJ^b|~&bj>u_DJ6f6<=4(d0X7_Ws3k%@pZ*Z{NV`a4}T_J z|FXUXW^anZ-?`#yT~WRzW#0m+;For1K=ME>Iq4XD-XsBP40 zHOCtoWb-Gq5o&F1joRVXty@*G{+Fl{iSkcRPe;frDk@YhEiDoJnVFfg_+_WY{@<|Z zUxSO@0ZFM3fcdWxNEW}M2(Z~~s?O7$p@pgum|Y*xdAc*CG&3zb0z~6KGwg|~SgLb` z(dq*V^NKii`eX=@ouE||0mghI6JO;-$gI6q!V{*cf-&ESwbvR|t^|r4;PgA0>bZ+! z)DFy4Xoz(JsVtHZ`!*ZR5!{YZyW;alMT_94-+ao^eMhC=y`Em$&;1*K8~?qKvbCVB ztW4Ov^A7-Qsa!8{1C-R3C>l)J50#ab30+-XX$QVN06_Y-^fdJnHRgSLC8bh{EtTsr z@7s%diJJ6n>1pu7cqMOwgm;1#izTA-jU`)wnJn>$XN+{!Pbseu5n;30R6!vlByt1v zbVi;OA3l6Ip{bZq1XwH{xwpy5NdkcYX0sWy+02g0YOGdk(o^EG5PmXjwOZLxSuN=k z2n3j%oCId_hlw~LrUNV%i=feH=IEHNua@;YBtWW=dt= zP%UG4c$n_)ZZsNATqneR3p{x6K)TQU<+2FkvGMz8G@6vu1jK`Da0rb?!-EI+>1ZQ@ zKM)8I2m})9C+-w57z|`*XG?QmgjgH!*2a=~Hy&mTersb%gf1dPeZ`uASV(9QT)K2= z#P4L~{*#H>I?dMkRfstSd_EsKosRDAZb=qC@5S|CA+e*fnvS-vsE4IGo$i&{WD#-K zfY}uxo8EmpX8R+b91*_w`xhzM4j=jCi15KzAMo(uLjW=}e!=ulPa|{+AD~xNvxFn2 z15TVcp{lE^6987NS_ME`!&US-dMR(OuihZFAMuRMIVBzoV&9uKZ33X9ql31Ft5W*h z>35R;yO~2%yWK9?5UbC)5g>L@S63%^yk1JxGYgOSF>>yo{{Y~xe>ui`zpvoWXFsQc z3I*oHhtuyQ$N%Ch)bIC4=mOAw^9uRPm&Y|+gsekRF+cA-`!4|A{rtUoO^*ZIx^+vq zefu`GwYA*4caMzBWwbS11wdcDK}wn?+Mn!G;qW4b`8FP)si`SqV^dyU9+57WV>~GM z8l0Vyo=@WeOeT}cWHPBTmn~=2>fZn;HXdG|3cq&1YX>Z}0t*eriIMQFr^nq7Y)OJT ziDQQIw{tGZRTKeYO~B0`uJDd=9aSHh=(urX-V!4nH*N@3ADMW^xQ?4YT#2YxkPF3A zV0KMFUT!Yuo10Vag!9eKLSAkzvFa7%K+zOf|K^(jT>Sp~2)S>3T(KgF!Z$w7h}TPf ieZ3^xzJ0sm{{9E|$}xBYSWFcF0000fFDZ*Bkp zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LY zR3KAHiHkEOv#1!Po{KZBC^0t`#5UwoR&e!m0hnf8!UQ4Yx^hIm5`DP0>g>>}YofQiZJ2EVk2l)fY7 z?qoMnDC9q6kG~zQSqHhNC;Rx(DZ)@6lzGqadz_ltKFrJww}234P6!3Ul-2PFB@t#u zu_gOiS$tfC&s#{L;VJzyRl9HG62T9XckTL z3TSY*t*_c9J_BOYuC{f7&z3P*TU#6A65iW-vslGglEt{fYTJNzxonS$SbQqt=Oelq zWw;`p4Ek!6AqXvYX01mCHQgk1o6^Z}R_GwH=kOysJ?nr~m{als81yWl7Th6u1t9yH zIRpO?;2no|0X1xM`8)mi_+-5n>-EX;aY8>`pNX^eX+l50xV$<6;NsP&{7Ct}m+*!F64aw;5V6ASnO^4^Dm8 zZ4;;f&}!G&9Kd!C6GTn*+6I(8We_OETn5(BtCz-v5rDQ}KLS7pR%!%@6#y{%9>9`U z-&JuNfDGCeZJnI>)+yR+80LVs#e>`ih!}fFi-vmNiU+K&Z*H!e1>E{LiYEm6{<68f z{r)MH!QIWxU4!Z4hzl1q2er*I*S_z5{JdK>?RY?XBV^mZ_ywa8An5=?_Ny=)=3M-L z00HU{?sI_q5R&5o*)SYDr1gi*43Pm0!@*-pete!G(zY26o>KA?Gd%nTDBD>2hZgr3 P00000NkvXXu0mjf<^eRD literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_shadow.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..0d232158466ff3ff4dc1cdded30dd48be2b8d43a GIT binary patch literal 1066 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 literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vampire.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vampire.png new file mode 100644 index 0000000000000000000000000000000000000000..a29c38b292c85d7c0348322a90acac9d43c726a6 GIT binary patch literal 1075 zcmV-31kC%1P)d?lNzqSAX0Evl-;l8)9u&}&_d}wHBj*yc+K0ZlFNwc%Fba#MkY-}nj zDv^N=izutgJaXIZaGVKR!N7N=lfNl>h(#>gedp$;p0xespwn zT3T98PEMGZnAO$QA|@uMsfFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5f zFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LYR3KAHiHkEOv#1!Po{KZBC^0t`#5Uwo zR&e!m0h8 z5+uWsV1*KnIDr!_aR#ZmDL_jKeZugCFk0fDVM{cmfPBF#U;;lL6{M24y~#qiB=Aufgu!#`hMU9VAKeSLNLxyU!eEHG?} zTzr}1`Co~D#Sru;@(&YmzyKWNvTgv#AJh!QJig&?N3-V@1JNAe{eR3Rz_F~CXyBxw z6s82z5LL`^G-oV8smctv1WMuY$_fZrD5Yv^fSC74c<;G@o3%25K^!QrIKCSvM3pmh ze?>btja@;(_1)y~$gL^Rcs!Qf)b*Ky8^;MxGrWRPgcG2_bJ8@9Zx!gpkR>e7T#yek zP`$o)-+$~ZnA{+}DpbddpBQ8T*aTFlZiTs-Yvcb5kU$FIt|o970&5Q_W^-`Q^ZUJr ts0hsF;DN&rPacAgy*YT~@MFO|`~s-XL-hQLG5|&Z09yb6hX4R#0001B2}A$@d;kEHzqbGX|C0a!iHV7@u&^5& z8%O{E8X6jCXlRa*lRiE^Nl8hwv$J$}fNX4Rk&%&4Pft-#TWkOTBO@ab6cp6g-%3hK zuB@y%IXO*COg}z8OG-+Zl$7e|=*!8;etv#*baYx;T24+*n3$N=)zu;lRR92n zhK5vBRI#zKYHDg*SXP69fpBeYTwGjHo0+iy0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5Nr{UyC9|j)q@Ig2ttc@!6~s2=QdV&Fa{-$O0Gj_84mqJ=L;wH+ z{7FPXR9J=WmVZ;*FbsxWJ2t@`g=WEyonT;V(*avT8QsQ@@Bg_brNDN?GTiphj+^dC zFZW2V6(d_>?5){^PyULFOlBe#uhN|FDY-`p z97vVtnUd5JgMilZfZ%ghNcCRJf=sbM1>kd1q101dlJN|<22RDZLu0_fm_wRdYZJV3 z&TH>n756x_&enAe&p7v{63%$zL}h%O+q!9*+EUzAN6s1Njw%=N06xT{LX0!-AOquq zGmwFc2sqe)#twf3514_+48qt0xvhsisBMHphMvJ5pn#}`w=sYEga~KBhu;M7ZOnfO zj5!m>vUn1JihEwp94b&e2#7)+k51e~X(_xh!5A;(bb2xp04{1YA*5EL1IMK-PAgG; zsKm$9LXHm914oN;@Zj)e#yH3z;0wVG#nGTvu#lp4_8N}=YY(eLs^n2%;7NhNVny;K z0NIB~4g5m_FF3p?5Wu#NKjVwVvTa%0E*A@eui8)SQ@bMg+3fsc2?EQD^VwOHui8PN zT}3(jJlNw;jDG=R_=xg1V|ZLsoKMnRs-v^o4U7f<)#!c9#M7+KPE4AVi$Y69}ga83uLM0hWKwYlamoQI*YxGtSFie+MS65#Z zA#lA}uQ%oOE_vyMvP`${&A0CxQ}7AZS+H%T;@J-{905oNP)Htyp_o(g{{>JWcz=@; zxbdDG5736;;FjjM+ZiGuFboHG6ux_yA!yqU2lo`dj|>k#0r>u8o0XsdRR91007*qo IM6N<$f_K6DFaQ7m literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_zombie_infectious.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_zombie_infectious.png new file mode 100644 index 0000000000000000000000000000000000000000..7b0d5c736d5236d4c8cc89bafb5646c515a35afe GIT binary patch literal 1142 zcmV-+1d02JP)G5|&Z09yb6hX4R#0001B2}A$@d;kEHzqbGX|C0a!iHV7@u&^5& z8%O{E8X6jCXlRa*lRiE^Nl8hwv$J$}fNX4Rk&%&4Pft-#TWkOTBO@ab6cp6g-%3hK zuB@y%IXO*COg}z8OG-+Zl$7e|=*!8;etv#*baYx;T24+*n3$N=)zu;lRR92n zhK5vBRI#zKYHDg*SXP69fpBeYTwGjHo0+iy0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5Nr{UyC9|j)q@Ig2ttc@!6~s2=QdV&Fa{-$O0Gj_84mqJ=L;wH+ z{7FPXR9J=WmVZ;*FbsxWJ2t@`g=WEyonT;V(*avT8QsQ@@Bg_brNDN?GTiphj+^dC zFZW2V6(d_>?5){^PyULFOlBe#uhN|FDY-`p z97vVtnUd5JgMilZfZ%ghNcCRJf=sbM1>kd1q101dlJN|<22RDZLu0_fm_wRdYZJV3 z&TH>n756x_&enAe&p7v{63%$zL}h%O+q!9*+EUzAN6s1Njw%=N06xT{LX0!-AOquq zGmwFc2sqe)#twf3514_+48qt0xvhsisBMHphMvJ5pn#}`w=sYEga~KBhu;M7ZOnfO zj5!m>vUn1JihEwp94b&e2#7)+k51e~X(_xh!5A;(bb2xp04{1YA*5EL1IMK-PAgG; zsKm$9LXHm914oN;@Zj)e#yH3z;0wVG#nGTvu#lp4_8N}=YY(eLs^n2%;7NhNVny;K z0NIB~4g5m_FF3p?5Wu#NKjVwVvTa%0E*A@eui8)SQ@bMg+3fsc2?EQD^VwOHui8PN zT}3(jJlNw;jDG=R_=xg1V|ZLsoKMnRs-v^o4U7f<)#!c9#M7+KPE4AVi$Y69}ga83uLM0hWKwYlamoQI*YxGtSFie+MS65#Z zA#lA}uQ%oOE_vyMvP`${&A0CxQ}7AZS+H%T;@J-{905oNP)Htyp_o(g{{>JWcz=@; zxbdDG5736;;FjjM+ZiGuFboHG6ux_yA!yqU2lo`dj|>k#0r>u8o0XsdRR91007*qo IM6N<$f_K6DFaQ7m literal 0 HcmV?d00001 diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 4359d2f1de0..ea8e75c9e4a 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -84,6 +84,30 @@ GLOBAL_LIST_EMPTY(unit_test_mapping_logs) allocated += instance return instance +/datum/unit_test/proc/test_screenshot(name, icon/icon) + if (!istype(icon)) + TEST_FAIL("[icon] is not an icon.") + return + + var/path_prefix = replacetext(replacetext("[type]", "/datum/unit_test/", ""), "/", "_") + name = replacetext(name, "/", "_") + + var/filename = "code/modules/unit_tests/screenshots/[path_prefix]_[name].png" + + if (fexists(filename)) + var/data_filename = "data/screenshots/[path_prefix]_[name].png" + fcopy(icon, data_filename) + log_test("[path_prefix]_[name] was found, putting in data/screenshots") + else if (fexists("code")) + // We are probably running in a local build + fcopy(icon, filename) + TEST_FAIL("Screenshot for [name] did not exist. One has been created.") + else + // We are probably running in real CI, so just pretend it worked and move on + fcopy(icon, "data/screenshots_new/[path_prefix]_[name].png") + + log_test("[path_prefix]_[name] was put in data/screenshots_new") + /proc/RunUnitTest(test_path, list/test_results) var/datum/unit_test/test = new test_path diff --git a/tools/ci/run_server.sh b/tools/ci/run_server.sh index f9eaa31e566..baf172d8ec3 100644 --- a/tools/ci/run_server.sh +++ b/tools/ci/run_server.sh @@ -17,5 +17,10 @@ cp _maps/$MAP.json ci_test/data/next_map.json cd ci_test DreamDaemon tgstation.dmb -close -trusted -verbose -params "log-directory=ci" + cd .. + +mkdir -p data/screenshots_new +cp -r ci_test/data/screenshots_new data/screenshots_new + cat ci_test/data/logs/ci/clean_run.lk diff --git a/tools/ci/show_screenshot_test_results.js b/tools/ci/show_screenshot_test_results.js new file mode 100644 index 00000000000..607ad9854d6 --- /dev/null +++ b/tools/ci/show_screenshot_test_results.js @@ -0,0 +1,236 @@ +import fetch, { FormData, fileFrom } from "node-fetch"; +import fs from "fs"; +import path from "path"; +import process from "process"; + +const createComment = (screenshotFailures, zipFileUrl) => { + const formatScreenshotFailure = ({ directory, diffUrl, newUrl, oldUrl }) => { + const img = (url) => { + if (url) { + return `![](${url})`; + } else { + return "None produced."; + } + }; + + return `| ${directory} | ${img(oldUrl)} | ${img(newUrl)} | ${img(diffUrl)} |`; + }; + + return ` + Screenshot tests failed! + + ${zipFileUrl ? `[Download zip file of new screenshots.](${zipFileUrl})` : "No zip file could be produced, this is a bug!"} + + ## Diffs +

+ See snapshot diffs + + | Name | Expected image | Produced image | Diff | + | :--: | :------------: | :------------: | :--: | + ${screenshotFailures.map(formatScreenshotFailure).join("\n")} +
+ + ## Help +
+ What is this? + + Screenshot tests make sure that specific icons look the same as they did before. + This is important for elements that often mistakenly change, such as alien species. + + If the produced image looks broken, then it is possible your code caused a bug. + Make sure to test in game to see if you can fix it. +
+ +
+ I am changing sprites, it's supposed to look different. + + If the newly produced sprites are correct, then the tests should be updated. + + You can either: + + 1. Right-click the "produced image", and save it in \`code/modules/unit_tests/screenshots/NAME.png\`. + 2. Download and extract [this zip file](${zipFileUrl}) in the root of your repository, and commit. + + If you need help, you can ask maintainers either on Discord or on this pull request. +
+ +
+ This is a false positive. + + If you are sure your code did not cause this failure, especially if it's inconsistent, + then you may have found a false positive. + + Ask maintainers to rerun the test. + + If you need help, you can ask maintainers either on Discord or on this pull request. +
+ `.replace(/\t/g, ''); // If we keep tabs, it'll become a code block. +}; + +export async function showScreenshotTestResults({ github, context, exec }) { + const { FILE_HOUSE_KEY } = process.env; + + // Check if bad-screenshots is in the artifacts + const { data: { artifacts } } = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + + const badScreenshots = artifacts.find(({ name }) => name === 'bad-screenshots'); + if (!badScreenshots) { + console.log("No bad screenshots found"); + return; + } + + // Download the screenshots from the artifacts + const download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: badScreenshots.id, + archive_format: "zip", + }); + + fs.writeFileSync("bad-screenshots.zip", Buffer.from(download.data)); + + await exec.exec("unzip bad-screenshots.zip -d bad-screenshots"); + + const prNumberFile = path.join("bad-screenshots", "pull_request_number.txt"); + + if (!fs.existsSync(prNumberFile)) { + console.log("No PR number found"); + return; + } + + const prNumber = parseInt(fs.readFileSync(prNumberFile, "utf8"), 10); + if (!prNumber) { + console.log("No PR number found"); + return; + } + + fs.rmSync(prNumberFile); + + // Validate the PR + const result = await github.graphql(`query($owner:String!, $repo:String!, $prNumber:Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $prNumber) { + commits(last: 1) { + nodes { + commit { + checkSuites(first: 10) { + nodes { + id + } + } + } + } + } + } + } + }`, { + owner: context.repo.owner, + repo: context.repo.repo, + prNumber, + }); + + const validPr = result + .repository + .pullRequest + .commits + .nodes[0] + .commit + .checkSuites + .nodes + .some(({ id }) => id === context.payload.workflow_run.check_suite_node_id); + + if (!validPr) { + console.log(`PR #${prNumber} is not valid (expected check suite ID ${context.payload.workflow_run.check_suite_node_id})`); + return; + } + + // Upload the screenshots + // 1. Loop over the bad-screenshots directory + // 2. Upload the screenshot + // 3. Save the URL + const uploadFile = async (filename) => { + if (!fs.existsSync(filename)) { + return; + } + + const formData = new FormData(); + + formData.set("key", FILE_HOUSE_KEY); + + formData.set("file", await fileFrom(filename), path.basename(filename)); + + return fetch("https://file.house/api/upload", { + method: "POST", + body: formData, + }) + .then(response => response.json()) + .then(response => { + console.log(response); + return response; + }) + .then(({ url }) => url); + }; + + const screenshotFailures = []; + + for (const directory of fs.readdirSync("bad-screenshots")) { + console.log(`Uploading screenshots for ${directory}`); + + let diffUrl; + let newUrl; + let oldUrl; + + await Promise.all([ + uploadFile(path.join("bad-screenshots", directory, "new.png")).then(url => newUrl = url), + uploadFile(path.join("bad-screenshots", directory, "old.png")).then(url => oldUrl = url), + uploadFile(path.join("bad-screenshots", directory, "diff.png")).then(url => diffUrl = url), + ]); + + console.log(`New URL (${directory}): ${newUrl}`); + console.log(`Old URL (${directory}): ${oldUrl}`); + console.log(`Diff URL (${directory}): ${diffUrl}`); + + screenshotFailures.push({ directory, diffUrl, newUrl, oldUrl }); + } + + if (screenshotFailures.length === 0) { + console.log("No screenshot failures found"); + return; + } + + // Upload zip file for quick fixes + const zipFilePath = path.join("data", "screenshot-update"); + const finalDestination = path.join( + zipFilePath, + "code", "modules", "unit_tests", "screenshots", + ) + + fs.mkdirSync(finalDestination, { recursive: true }); + + for (const { directory } of screenshotFailures) { + fs.copyFileSync( + path.join("bad-screenshots", directory, "new.png"), + path.join(finalDestination, `${directory}.png`), + ) + } + + await exec.exec("zip", ["-r", `../screenshot-update.zip`, "."], { + cwd: zipFilePath, + }); + + const zipUrl = await uploadFile(`${zipFilePath}.zip`); + + // Post the comment + const comment = createComment(screenshotFailures, zipUrl); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: comment, + }); +} diff --git a/tools/screenshot-test-comparison/index.js b/tools/screenshot-test-comparison/index.js new file mode 100644 index 00000000000..0a0f5fa4545 --- /dev/null +++ b/tools/screenshot-test-comparison/index.js @@ -0,0 +1,103 @@ +const fs = require("fs") +const path = require("path") +const pixelmatch = require("pixelmatch") +const process = require("process") +const PNG = require("pngjs").PNG + +const artifactsDirectory = process.argv[2] +if (!artifactsDirectory) { + console.error("Artifacts directory was not passed in") + process.exit(1) +} + +const screenshotsDirectory = process.argv[3] +if (!screenshotsDirectory) { + console.error("Screenshots directory was not passed in") + process.exit(1) +} + +const outputDirectory = process.argv[4] +if (!outputDirectory) { + console.error("Output directory was not passed in") + process.exit(1) +} + +const knownFailures = new Set() + +const fail = (screenshotName, newScreenshot, oldScreenshot, diff) => { + knownFailures.add(screenshotName) + + const outputPath = path.join(outputDirectory, path.parse(screenshotName).name) + fs.mkdirSync(outputPath, { + recursive: true + }) + + fs.copyFileSync(newScreenshot, path.join(outputPath, "new.png")) + + if (oldScreenshot) { + fs.copyFileSync(oldScreenshot, path.join(outputPath, "old.png")) + } + + if (diff) { + fs.writeFileSync(path.join(outputPath, "diff.png"), PNG.sync.write(diff)) + } +} + +for (const filename of fs.readdirSync(artifactsDirectory)) { + if (!filename.startsWith("test_artifacts")) { + continue + } + + const fullPath = path.join(artifactsDirectory, filename, "screenshots_new") + + const fullPathStat = fs.statSync(fullPath) + if (!fullPathStat.isDirectory()) { + continue + } + + for (const screenshotName of fs.readdirSync(fullPath)) { + if (knownFailures.has(screenshotName)) { + continue + } + + const fullPathScreenshotName = path.join(fullPath, screenshotName) + + const fullPathCompareScreenshot = path.join(screenshotsDirectory, screenshotName) + if (!fs.existsSync(fullPathCompareScreenshot)) { + fail(screenshotName, fullPathScreenshotName) + continue + } + + const screenshotNew = PNG.sync.read(fs.readFileSync(fullPathScreenshotName)) + const screenshotCompare = PNG.sync.read(fs.readFileSync(fullPathCompareScreenshot)) + + if ( + screenshotNew.width !== screenshotCompare.width + || screenshotNew.height !== screenshotCompare.height + ) { + console.error(`${screenshotName} has different dimensions from the known screenshot`) + fail(screenshotName, fullPathScreenshotName, fullPathCompareScreenshot) + continue + } + + const diff = new PNG({ width: screenshotNew.width, height: screenshotNew.height }) + const diffResult = pixelmatch( + screenshotNew.data, + screenshotCompare.data, + diff.data, + screenshotNew.width, + screenshotNew.height, + { threshold: 0.1 } + ) + + if (diffResult) { + console.error(`${screenshotName} differs from the known screenshot`) + fail(screenshotName, fullPathScreenshotName, fullPathCompareScreenshot, diff) + } + } +} + +if (knownFailures.size > 0) { + console.error(`${knownFailures.size} screenshots failed`) + process.exit(1) +} diff --git a/tools/screenshot-test-comparison/package-lock.json b/tools/screenshot-test-comparison/package-lock.json new file mode 100644 index 00000000000..4b24f319a79 --- /dev/null +++ b/tools/screenshot-test-comparison/package-lock.json @@ -0,0 +1,51 @@ +{ + "name": "screenshot-test-comparison", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "screenshot-test-comparison", + "version": "1.0.0", + "license": "AGPL-3.0-or-later", + "dependencies": { + "pixelmatch": "^5.3.0", + "pngjs": "^6.0.0" + } + }, + "node_modules/pixelmatch": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", + "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", + "dependencies": { + "pngjs": "^6.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "engines": { + "node": ">=12.13.0" + } + } + }, + "dependencies": { + "pixelmatch": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", + "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", + "requires": { + "pngjs": "^6.0.0" + } + }, + "pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==" + } + } +} diff --git a/tools/screenshot-test-comparison/package.json b/tools/screenshot-test-comparison/package.json new file mode 100644 index 00000000000..8496bddb085 --- /dev/null +++ b/tools/screenshot-test-comparison/package.json @@ -0,0 +1,12 @@ +{ + "name": "screenshot-test-comparison", + "version": "1.0.0", + "description": "", + "keywords": [], + "author": "", + "license": "AGPL-3.0-or-later", + "dependencies": { + "pixelmatch": "^5.3.0", + "pngjs": "^6.0.0" + } +}