Files
Yogstation/code/modules/mob/living/carbon/human/species.dm
Skrem_7 029bca0eaf Skrem is Less Dumb Edition: Modern Medievalism: Bows, Arrows, and Cloaks, oh my! (#17982)
* first bow powercreep edition

* first patch

* description updates

* added the stuff

* follow-up edits

* very mild voicebox updates

* all the stuff

* some value/wording changes + shifts shadow cloak to nukies

* halve bow slowdown

* aaaa

* uhoh

* cloak charge rate changes

* remove redundant line

* upgrades break bow damage to middle finger

* spellbook adjustments

* tribal armor tweaks (I'm looking at you pathfinder cloak and you're gonna get slapped soon)

* aaa

* more stuff

* agh

* done?

* minor tweaks + craftable gloves

* adds bone crossbow crafting recipe

* maybe fix cornflakes

* Squashed commit of the following:

commit 414af05928
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 18 22:05:17 2023 -0500

    Automatic changelog generation #17965 [ci skip]

commit 4dbd995239
Author: adamsong <adamsong@users.noreply.github.com>
Date:   Sat Feb 18 22:05:15 2023 -0500

    Fix apply_innate_effects not getting mob refs like its supposed to, fixes veil health not being modified (#17965)

commit 8f9f915f69
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 18 22:04:08 2023 -0500

    Automatic changelog generation #17970 [ci skip]

commit 50ed5323a5
Author: ynot01 <ynot000001@gmail.com>
Date:   Sat Feb 18 22:04:06 2023 -0500

    Easier wounds on unclosed surgery sites (#17970)

    * Update _bodyparts.dm

    * Update code/modules/surgery/bodyparts/_bodyparts.dm

commit 9c4d0652db
Author: Changelogs <action@github.com>
Date:   Sat Feb 18 14:07:01 2023 +0000

    Automatic changelog compile [ci skip]

commit 03aae8b4cf
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 18 01:58:51 2023 -0500

    Automatic changelog generation #17934 [ci skip]

commit 2761924c1b
Author: ynot01 <ynot000001@gmail.com>
Date:   Sat Feb 18 01:58:49 2023 -0500

    pvp enabled (#17934)

commit cfe754a9a5
Author: Changelogs <action@github.com>
Date:   Sat Feb 18 06:10:32 2023 +0000

    Automatic changelog compile [ci skip]

commit 491ba04913
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 17 18:08:00 2023 -0500

    Automatic changelog generation #17949 [ci skip]

commit a65d885b53
Author: ynot01 <ynot000001@gmail.com>
Date:   Fri Feb 17 18:07:57 2023 -0500

    Fixes energy sword dupe exploit (#17949)

    * Update SuperBeepsky.dm

    * Update code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm

    Co-authored-by: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com>

    * Update SuperBeepsky.dm

    ---------

    Co-authored-by: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com>

commit 7a8a6689b6
Author: Changelogs <action@github.com>
Date:   Fri Feb 17 22:17:32 2023 +0000

    Automatic changelog compile [ci skip]

commit e43f06f61c
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 17 15:41:43 2023 -0500

    Automatic changelog generation #17924 [ci skip]

commit a4229d8acb
Author: ynot01 <ynot000001@gmail.com>
Date:   Fri Feb 17 15:41:40 2023 -0500

    [BOUNTY] Holy Light sect, dedicated to healing (#17924)

    * you defy the light

    * revive and be less bad flavor

    * Update code/modules/religion/religion_sects.dm

    Co-authored-by: Molti <108117184+Moltijoe@users.noreply.github.com>

    ---------

    Co-authored-by: Molti <108117184+Moltijoe@users.noreply.github.com>

commit ad64a89f0a
Author: ktlwjec <122807629+ktlwjec0@users.noreply.github.com>
Date:   Fri Feb 17 18:04:42 2023 +0000

    removes plate from greeneggsandham (#17883)

commit b0c3ca40a8
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 17 10:59:34 2023 -0500

    Automatic changelog generation #17969 [ci skip]

commit eefceef5ed
Author: wejengin2 <48154165+wejengin2@users.noreply.github.com>
Date:   Fri Feb 17 16:59:31 2023 +0100

    [box] fixes opacity on psych doors (#17969)

    * windows

    * opac

commit 4b75b528ee
Author: Changelogs <action@github.com>
Date:   Fri Feb 17 14:07:57 2023 +0000

    Automatic changelog compile [ci skip]

commit 0a5d72beaf
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 17 01:56:41 2023 -0500

    Automatic changelog generation #17880 [ci skip]

commit f6ed8e4b0b
Author: adamsong <adamsong@users.noreply.github.com>
Date:   Fri Feb 17 01:56:39 2023 -0500

    Makes vote weight and preferred map actually work (#17880)

commit 22657a9023
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 17 01:50:20 2023 -0500

    Automatic changelog generation #17901 [ci skip]

commit 783f444541
Author: Aquizit <70451213+Aquizit@users.noreply.github.com>
Date:   Fri Feb 17 00:50:17 2023 -0600

    Adds new access define for Secure Tech Storage (#17901)

    * creates secure tech storage define, gives it to CE and adds it to appropriate lists

    * sets new access to secure tech storage doors

    * added secure tech storage to ID modification access

    * reverting map changes, will be changed in another pr per wej

commit b306a6f4c3
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 17 01:33:16 2023 -0500

    Automatic changelog generation #17935 [ci skip]

commit 32cdd383e4
Author: SapphicOverload <93578146+SapphicOverload@users.noreply.github.com>
Date:   Fri Feb 17 01:33:14 2023 -0500

    Malfunctioning AIs no longer need to kill androids or synthetics (#17935)

    * Update objective.dm

    * Update Malf_Modules.dm

commit d83cc04e94
Author: Changelogs <action@github.com>
Date:   Fri Feb 17 06:11:59 2023 +0000

    Automatic changelog compile [ci skip]

commit b89713fa7c
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 22:40:04 2023 -0500

    Automatic changelog generation #17861 [ci skip]

commit 818973e1e9
Author: wejengin2 <48154165+wejengin2@users.noreply.github.com>
Date:   Fri Feb 17 04:40:02 2023 +0100

    fixes some issues in infiltrator base (#17861)

    * huh

    * man

    * adds griddle

    * that's really funny but fuck you

    ---------

    Co-authored-by: Byemoh <baiomurang@gmail.com>

commit af417335c1
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 22:32:01 2023 -0500

    Automatic changelog generation #17942 [ci skip]

commit 4e6037ec58
Author: wejengin2 <48154165+wejengin2@users.noreply.github.com>
Date:   Fri Feb 17 04:31:58 2023 +0100

    [box] Fixes some map issues (#17942)

    * eo

    * more

    * more fixes

    * damn

    * cargo double lights

    * rogue cable and wrong id on ai core door

    * derwalls a random rwall

    * tile

commit 2e52265500
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 20:08:21 2023 -0500

    Automatic changelog generation #17917 [ci skip]

commit 6ebf0318d9
Author: Theos <theubernyan@gmail.com>
Date:   Thu Feb 16 20:08:18 2023 -0500

    Removes the knockout from high level bloodsucker mesmerize since it makes the ability weaker (#17917)

    * Removes the knockout from high level bloodsucker mesmerize since it makes the ability weaker

    * Update mesmerize.dm

    * killing you

commit 7d664d3af5
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 20:06:53 2023 -0500

    Automatic changelog generation #17918 [ci skip]

commit dc8148dcb1
Author: ynot01 <ynot000001@gmail.com>
Date:   Thu Feb 16 20:06:51 2023 -0500

    Update roundend.dm (#17918)

commit a46d618224
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 20:06:21 2023 -0500

    Automatic changelog generation #17928 [ci skip]

commit f04bc81f0c
Author: LazennG <58535870+LazennG@users.noreply.github.com>
Date:   Thu Feb 16 17:06:18 2023 -0800

    Update kinetic_crusher.dm (#17928)

commit 18fa2ae7af
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 20:05:51 2023 -0500

    Automatic changelog generation #17946 [ci skip]

commit 6857bacb76
Author: SapphicOverload <93578146+SapphicOverload@users.noreply.github.com>
Date:   Thu Feb 16 20:05:48 2023 -0500

    Update mousetrap.dm (#17946)

commit 1751af026c
Author: Changelogs <action@github.com>
Date:   Thu Feb 16 22:17:07 2023 +0000

    Automatic changelog compile [ci skip]

commit e005525535
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 12:19:45 2023 -0500

    Automatic changelog generation #17922 [ci skip]

commit bc8ae716ab
Author: Ling <lingbleed@gmail.com>
Date:   Thu Feb 16 18:19:42 2023 +0100

    Fixes Atmos fire fighting backpack (#17922)

commit e04fc1b6a8
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 12:18:03 2023 -0500

    Automatic changelog generation #17939 [ci skip]

commit 93daa6c361
Author: ynot01 <ynot000001@gmail.com>
Date:   Thu Feb 16 12:18:00 2023 -0500

    Bloodsucker Brawn knockdown patch (#17939)

    * Update brawn.dm

    * Update brawn.dm

    * Update brawn.dm

commit 1ef9484767
Author: Changelogs <action@github.com>
Date:   Thu Feb 16 14:09:56 2023 +0000

    Automatic changelog compile [ci skip]

commit eaff1fdb1b
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 05:52:39 2023 -0500

    Automatic changelog generation #17936 [ci skip]

commit 3d42d664bc
Author: adamsong <adamsong@users.noreply.github.com>
Date:   Thu Feb 16 05:52:36 2023 -0500

    Fixes editing bans in game (#17936)

    * Fixes editing bans in game

    * Fixes other error

commit 69ea8d6ca9
Author: Changelogs <action@github.com>
Date:   Thu Feb 16 06:11:47 2023 +0000

    Automatic changelog compile [ci skip]

commit 4e6a16b426
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 16 00:37:02 2023 -0500

    Automatic changelog generation #17923 [ci skip]

commit 2a7da8c107
Author: ynot01 <ynot000001@gmail.com>
Date:   Thu Feb 16 00:37:00 2023 -0500

    fixes clown sect not healing (#17923)

commit 890bc91805
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 20:56:34 2023 -0500

    Automatic changelog generation #17945 [ci skip]

commit b2b39d3ed8
Author: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com>
Date:   Wed Feb 15 20:56:32 2023 -0500

    Update revolution.dm (#17945)

commit ec2cbd2c89
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 20:48:13 2023 -0500

    Automatic changelog generation #17864 [ci skip]

commit cd14d86ed6
Author: Theos <theubernyan@gmail.com>
Date:   Wed Feb 15 20:48:10 2023 -0500

    Buffs the ebow to be faster (#17864)

    * ebow buff??

    * obliterate ebow polonium

    * reduced cooldown

commit df7f9bc020
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 20:47:28 2023 -0500

    Automatic changelog generation #17870 [ci skip]

commit 232aa3fa55
Author: ynot01 <ynot000001@gmail.com>
Date:   Wed Feb 15 20:47:26 2023 -0500

    Update bloodsuckers.dm (#17870)

commit d679caad3c
Author: Changelogs <action@github.com>
Date:   Wed Feb 15 22:17:39 2023 +0000

    Automatic changelog compile [ci skip]

commit 9678f1f65a
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 14:58:11 2023 -0500

    Automatic changelog generation #17930 [ci skip]

commit 039792ea37
Author: Byemoh <baiomurang@gmail.com>
Date:   Wed Feb 15 13:58:09 2023 -0600

    NVS Gax Incinerator Expansion (#17930)

commit a0fe3e174c
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 11:04:14 2023 -0500

    Automatic changelog generation #17941 [ci skip]

commit a263586d88
Author: wejengin2 <48154165+wejengin2@users.noreply.github.com>
Date:   Wed Feb 15 17:04:08 2023 +0100

    eee (#17941)

commit f8b90faa17
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 10:11:12 2023 -0500

    Automatic changelog generation #17721 [ci skip]

commit 1d22d7da18
Author: ynot01 <ynot000001@gmail.com>
Date:   Wed Feb 15 10:11:07 2023 -0500

    Long Awaited Psychiatrist Rework (#17721)

    * PART FIVE

    * Update brain_trauma.dm

    * Update examine.dm

    * Update mild.dm

    * Update brain_trauma.dm

    * Update brain_trauma.dm

    * anomalous floating lightswitch

    * undo unintended map changes

    I am sorry I don't know what happened to asteroid station I don't know what changed on the AI satellite I am sorry mapper man

    * can no longer cure things u shouldnt

    wound traumas
    traumas that require the aheal staff
    traumas that come from quirks

    * wej

    * wej 2

    * Update YogStation.dmm

    * Update brain_trauma.dm

    * Update brain_trauma.dm

    * Update brain_trauma.dm

commit 85de433d2d
Author: Changelogs <action@github.com>
Date:   Wed Feb 15 14:08:21 2023 +0000

    Automatic changelog compile [ci skip]

commit a8bd8c2280
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 07:32:49 2023 -0500

    Automatic changelog generation #17916 [ci skip]

commit 3b587559a5
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Wed Feb 15 06:32:46 2023 -0600

    Who approved this (#17916)

commit 6828c4758d
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 06:58:56 2023 -0500

    Automatic changelog generation #17914 [ci skip]

commit 3e3ab2b4d6
Author: ktlwjec <122807629+ktlwjec0@users.noreply.github.com>
Date:   Wed Feb 15 11:58:53 2023 +0000

    fixes processor recipes (#17914)

commit 601ce3f675
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 06:41:26 2023 -0500

    Automatic changelog generation #17888 [ci skip]

commit bf8867a331
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Wed Feb 15 05:41:24 2023 -0600

    no hardcritdamage (#17888)

commit e1a500ec62
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 05:28:58 2023 -0500

    Automatic changelog generation #17781 [ci skip]

commit 874db73a73
Author: ynot01 <ynot000001@gmail.com>
Date:   Wed Feb 15 05:28:55 2023 -0500

    Revert commit 64a6c3a (#17781)

    This reverts 64a6c3ac21

commit 734d6ec0fc
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 15 05:28:03 2023 -0500

    Automatic changelog generation #17772 [ci skip]

commit 30d564c8dc
Author: Manatee <74586965+MajManatee@users.noreply.github.com>
Date:   Wed Feb 15 04:28:00 2023 -0600

    A vain attempt to make the minigun more viable (#17772)

    * mmm minigun

    * Update minigun.dm

commit e7542e1f55
Author: Changelogs <action@github.com>
Date:   Wed Feb 15 06:11:58 2023 +0000

    Automatic changelog compile [ci skip]

commit b5ed98fe7c
Author: Ling <lingbleed@gmail.com>
Date:   Wed Feb 15 02:18:53 2023 +0100

    Fix crew monitor runtime (#17921)

commit 4c7b5535b6
Author: Changelogs <action@github.com>
Date:   Tue Feb 14 14:08:13 2023 +0000

    Automatic changelog compile [ci skip]

commit cfb81a4b91
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 14 04:06:15 2023 -0500

    Automatic changelog generation #17919 [ci skip]

commit 5268119ca6
Author: ynot01 <ynot000001@gmail.com>
Date:   Tue Feb 14 04:06:12 2023 -0500

    Update recharger.dm (#17919)

commit 06acbae28d
Author: Changelogs <action@github.com>
Date:   Tue Feb 14 06:12:20 2023 +0000

    Automatic changelog compile [ci skip]

commit 369dba9990
Author: Changelogs <action@github.com>
Date:   Mon Feb 13 22:17:26 2023 +0000

    Automatic changelog compile [ci skip]

commit a8b8df1868
Author: Yogbot-13 <admin@yogstation.net>
Date:   Mon Feb 13 16:51:13 2023 -0500

    Automatic changelog generation #17887 [ci skip]

commit 991c54d7e3
Author: wejengin2 <48154165+wejengin2@users.noreply.github.com>
Date:   Mon Feb 13 22:51:10 2023 +0100

    yeah (#17887)

commit d9aec4444d
Author: Changelogs <action@github.com>
Date:   Mon Feb 13 06:12:20 2023 +0000

    Automatic changelog compile [ci skip]

commit bad039c45f
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sun Feb 12 17:52:39 2023 -0500

    Automatic changelog generation #17897 [ci skip]

commit f251ff8187
Author: Skrem_7 <98909416+Skrem7@users.noreply.github.com>
Date:   Sun Feb 12 17:52:36 2023 -0500

    better metashield (#17897)

commit 1c7d28f658
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sun Feb 12 17:51:22 2023 -0500

    Automatic changelog generation #17889 [ci skip]

commit 4f4d2d8bbb
Author: LazennG <58535870+LazennG@users.noreply.github.com>
Date:   Sun Feb 12 14:51:19 2023 -0800

    cooldown actions isavailable now calls parent pro (#17889)

commit 5e3f4b08a7
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sun Feb 12 17:50:40 2023 -0500

    Automatic changelog generation #17894 [ci skip]

commit 062f0a2fd5
Author: Manatee <74586965+MajManatee@users.noreply.github.com>
Date:   Sun Feb 12 16:50:37 2023 -0600

    augh (#17894)

commit 494bbd1982
Author: ynot01 <ynot000001@gmail.com>
Date:   Sun Feb 12 07:41:24 2023 -0500

    Update yogstation.dme (#17903)

commit 596b836652
Author: Changelogs <action@github.com>
Date:   Sun Feb 12 06:10:28 2023 +0000

    Automatic changelog compile [ci skip]

commit dc689f3715
Author: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com>
Date:   Sun Feb 12 01:30:21 2023 +0100

    Moves some config settings around which should make debug builds from github run faster (#17900)

          * config update

    * opos

commit 80284d7ca0
Author: Changelogs <action@github.com>
Date:   Sat Feb 11 22:15:52 2023 +0000

    Automatic changelog compile [ci skip]

commit 56e85c55c3
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 13:38:04 2023 -0500

    Automatic changelog generation #17833 [ci skip]

commit 80afe50f46
Author: ynot01 <ynot000001@gmail.com>
Date:   Sat Feb 11 13:38:01 2023 -0500

    Darkspawn is now a midround instead of a gamemode (#17833)

    * dspawn midround

    * disable

    * performance

    * move sec counting down

    * disable nightmare

    * changes S to H

    * runtime safety

    * H and D to var names

commit 435823b827
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 12:49:50 2023 -0500

    Automatic changelog generation #17878 [ci skip]

commit fa4b2b98a3
Author: ynot01 <ynot000001@gmail.com>
Date:   Sat Feb 11 12:49:47 2023 -0500

    You can no longer change directions while dead (#17878)

    * Update bindings_atom.dm

    * Update bindings_atom.dm

    * Update bindings_atom.dm

commit 75cfed640f
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 12:17:44 2023 -0500

    Automatic changelog generation #17842 [ci skip]

commit 291a70fb8f
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Sat Feb 11 11:17:42 2023 -0600

    Removes appendix from darkspawn (#17842)

    * no appendix please

    * just uses nohunger

    * thing

    * might as well remove it from shadowpeople

    they have enough going against them as is

commit 1cc076d57a
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 12:14:44 2023 -0500

    Automatic changelog generation #17828 [ci skip]

commit fef1aed09b
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Sat Feb 11 11:14:42 2023 -0600

    IPC martial buffs (#17828)

    * IPC martial tweak

    * update the movespeed

    * it's the mob that does it

    * bit more uplink stuff

    * no other guns

commit bf62a065f5
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 12:01:19 2023 -0500

    Automatic changelog generation #17824 [ci skip]

commit 20c67e451b
Author: ynot01 <ynot000001@gmail.com>
Date:   Sat Feb 11 12:01:16 2023 -0500

    Antag Reputation Redux (#17824)

    * antag repwork

    * check centcom specifically

    * GLOB.player_list

    * Update antag_rep.txt

    * Update antag_rep.txt

    * better loop

    * set miner to 6

    * set AI to 6

    * cook 5

    * psyfch 5

commit 866c4f0e97
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 11:39:29 2023 -0500

    Automatic changelog generation #17814 [ci skip]

commit 64726b0798
Author: Redd <36747151+ReddicusDragon@users.noreply.github.com>
Date:   Sat Feb 11 11:39:26 2023 -0500

    Changes lizard hiss and increases staff, mentor, and donor retention by allowing felinids to hiss. (#17814)

    * adds sound

    * felinids can hiss

    * felinids can purr

    * You can no longer purr at people

    NanoTrasen has noticed an increase in harassment complaints from stations that employ felinids. The reports indicate that felinids would purr at people. NanoTrasen has since banned workplace purring at people.

    * removes purring

    * update lizard hiss

commit b956f2caae
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 11:36:59 2023 -0500

    Automatic changelog generation #17809 [ci skip]

commit 00769859a2
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Sat Feb 11 10:36:57 2023 -0600

    Nanite heart buff (#17809)

commit 87bd1794db
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 11:36:15 2023 -0500

    Automatic changelog generation #17805 [ci skip]

commit f286bdb997
Author: SapphicOverload <93578146+SapphicOverload@users.noreply.github.com>
Date:   Sat Feb 11 11:36:12 2023 -0500

    you are a good (#17805)

commit a737b7291e
Author: Ling <lingbleed@gmail.com>
Date:   Sat Feb 11 17:35:33 2023 +0100

    Fix a ton of harddels (#17803)

    * Fix a ton of harddels

    * Out of scope

    * Stupid

commit f77eb885d9
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 11:34:47 2023 -0500

    Automatic changelog generation #17724 [ci skip]

commit 8f4993ae0b
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Sat Feb 11 10:34:45 2023 -0600

    Miners wormhole jaunter location shuffle (#17724)

    * Gives mining medic a jaunter

    * in the outfit rather than the locker

    ---------

    Co-authored-by: Jamie D <993128+JamieD1@users.noreply.github.com>

commit a6779b3a77
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 11:27:41 2023 -0500

    Automatic changelog generation #17778 [ci skip]

commit 402e2d775a
Author: Xander3359 <66163761+Xander3359@users.noreply.github.com>
Date:   Sat Feb 11 11:27:38 2023 -0500

    One handed crusher (With new sprites) (#17778)

    * 1-Handed Crusher

    The crusher can now be held in 1 hand, wield it to use it.

    * one-handed crusher

    one-handed crusher

    * Update dynamic.json

commit fa67c930d0
Author: Jamie D <993128+JamieD1@users.noreply.github.com>
Date:   Sat Feb 11 16:23:06 2023 +0000

    Update dynamic_rulesets_roundstart.dm

commit 0e05a643a6
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 11:20:01 2023 -0500

    Automatic changelog generation #17720 [ci skip]

commit 738aac2d74
Author: Manatee <74586965+MajManatee@users.noreply.github.com>
Date:   Sat Feb 11 10:19:59 2023 -0600

    Revert "replaces chasm spawn from tendrils with lava (#17340)" (#17720)

    This reverts commit d0abdd2d33.

commit 0679f56ea6
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 11:19:12 2023 -0500

    Automatic changelog generation #17609 [ci skip]

commit a5660a07e6
Author: Theos <theubernyan@gmail.com>
Date:   Sat Feb 11 11:19:10 2023 -0500

    Increase wizard playercount from 27 to 34 so its not syndicate station 2 (the second one) (#17609)

    * Increase wizard playercount from 27 to 37 so its not syndicate station 2 (the second one)

    * Update wizard.dm

    * Update dynamic_rulesets_roundstart.dm

commit d1ec159cf3
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 10:50:38 2023 -0500

    Automatic changelog generation #17610 [ci skip]

commit f49b009b1d
Author: BurgerLUA <8602857+BurgerLUA@users.noreply.github.com>
Date:   Sat Feb 11 07:50:35 2023 -0800

    Increase nuke op from 27 to 37 so its not syndicate station 3 (the third one) (#17610)

commit 75b0447f82
Author: Changelogs <action@github.com>
Date:   Sat Feb 11 14:07:34 2023 +0000

    Automatic changelog compile [ci skip]

commit ab07a0c5ca
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 04:18:21 2023 -0500

    Automatic changelog generation #17739 [ci skip]

commit ed09aa658d
Author: Manatee <74586965+MajManatee@users.noreply.github.com>
Date:   Sat Feb 11 03:18:18 2023 -0600

    Removes mod disks from loot pool, and makes them orderable from cargo. Also adds a KA crate. (#17739)

    * fug

    * no more disks

commit f6cd327077
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 04:07:17 2023 -0500

    Automatic changelog generation #17873 [ci skip]

commit 09a038e850
Author: LazennG <58535870+LazennG@users.noreply.github.com>
Date:   Sat Feb 11 01:07:15 2023 -0800

    no more curveballs (#17873)

commit 186fedce46
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 04:05:05 2023 -0500

    Automatic changelog generation #17865 [ci skip]

commit 422a595d6c
Author: Skrem_7 <98909416+Skrem7@users.noreply.github.com>
Date:   Sat Feb 11 04:05:02 2023 -0500

    makes darkspawn mindshield text a little less cringe (#17865)

    * makes this text a little less cringe

    * i love repetition of sound

commit c4217e2080
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sat Feb 11 04:04:45 2023 -0500

    Automatic changelog generation #17867 [ci skip]

commit 20fc9d7f33
Author: Theos <theubernyan@gmail.com>
Date:   Sat Feb 11 04:04:42 2023 -0500

    Reduces drakeling attack cooldowns slightly to match the mining equipment they are meant to upgrade (#17867)

commit fdf31d11a7
Author: Changelogs <action@github.com>
Date:   Sat Feb 11 06:10:17 2023 +0000

    Automatic changelog compile [ci skip]

commit 6b0ddaf194
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 20:45:30 2023 -0500

    Automatic changelog generation #17863 [ci skip]

commit 484a70bdc6
Author: Skrem_7 <98909416+Skrem7@users.noreply.github.com>
Date:   Fri Feb 10 20:45:27 2023 -0500

    hammer fix (#17863)

commit c3f4bee6a9
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 20:43:51 2023 -0500

    Automatic changelog generation #17866 [ci skip]

commit 44d935e116
Author: Mqiib <43766432+Mqiib@users.noreply.github.com>
Date:   Fri Feb 10 20:43:49 2023 -0500

    Unfucks darkspawn veils but they're still weaker (#17866)

    * brtuh

    * Update yogstation/code/game/gamemodes/darkspawn/veil.dm

    whoops

    Co-authored-by: Molti <108117184+Moltijoe@users.noreply.github.com>

    ---------

    Co-authored-by: Molti <108117184+Moltijoe@users.noreply.github.com>

commit 80045a2877
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 19:56:54 2023 -0500

    Automatic changelog generation #17770 [ci skip]

commit 40564ae7f4
Author: githubuser4141 <61243846+githubuser4141@users.noreply.github.com>
Date:   Sat Feb 11 13:56:51 2023 +1300

    Buffs the MK-II Ripley's speed (#17770)

    * dir

    * Update mecha_defense.dm

    * Update uplink_items.dm

    * Update uplink_items.dm

    * Update uplink_items.dm

    * Update ripley.dm

    * Update ripley.dm

    * Update uplink_items.dm

commit bece519a8b
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 18:45:30 2023 -0500

    Automatic changelog generation #17784 [ci skip]

commit 4a499be90f
Author: Skrem_7 <98909416+Skrem7@users.noreply.github.com>
Date:   Fri Feb 10 18:45:27 2023 -0500

    True semi-auto shotguns + racking medium/heavy ballistics requires both hands + removes outdated stechkin animations (#17784)

    * shotguns actually semi-auto now

    * updates desc

    * removes stechkin animations

    * fixes rack sound

    * Update code/modules/projectiles/guns/ballistic.dm

    Co-authored-by: tattax <71668564+tattax@users.noreply.github.com>

    * slight fixes

    ---------

    Co-authored-by: tattax <71668564+tattax@users.noreply.github.com>

commit 24ad52b6bd
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 18:22:35 2023 -0500

    Automatic changelog generation #17835 [ci skip]

commit 053f8bf856
Author: Redd <36747151+ReddicusDragon@users.noreply.github.com>
Date:   Fri Feb 10 18:22:32 2023 -0500

    Typo fix (#17835)

    * Update swarmer.dm

    * Update scripture_scripts.dm

    * Update golems.dm

    * Update pen.dm

    * Update touch_attacks.dm

    * Update uplink_items.dm

    * Update explosive_fist.dm

    * Update garden_warfare.dm

    * Update stealth.dm

    * Update uplink_item.dm

    * Update code/modules/mob/living/carbon/human/species_types/golems.dm

    Co-authored-by: ynot01 <ynot000001@gmail.com>

    * Update scripture_scripts.dm

    ---------

    Co-authored-by: ynot01 <ynot000001@gmail.com>

commit d0e1c6f1f9
Author: Ling <lingbleed@gmail.com>
Date:   Sat Feb 11 00:09:14 2023 +0100

    Actually fixes gas mixer sprite for real this time (#17840)

commit 66545d3bee
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 18:07:46 2023 -0500

    Automatic changelog generation #17847 [ci skip]

commit b04412e57e
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Fri Feb 10 17:07:42 2023 -0600

    Removes #1 cause of suicide in Lizards (#17847)

    * CarkFetishContent

    * 20 minutes and chat message

    * no dead lizards

    * optimization

commit c6ab8818ff
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 18:01:32 2023 -0500

    Automatic changelog generation #17854 [ci skip]

commit 0c13569569
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Fri Feb 10 17:01:20 2023 -0600

    Gives mining medic a laptop to keep track of bodycams (#17854)

    * Gives mining medic a laptop

    * upgraded network card

commit 9a3512a44b
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:59:29 2023 -0500

    Automatic changelog generation #17836 [ci skip]

commit 606c9ced8f
Author: Aquizit <70451213+Aquizit@users.noreply.github.com>
Date:   Fri Feb 10 16:59:27 2023 -0600

    Adds Personnel HUD Type, gives HoP and Cap a pair of sunglasses with it (#17836)

    * adds personnel hud type, sunglasses for HoP and Cap with it

    * renames CMO shades for HoP/Cap, made new shades for CMO

    * forgot to make the sunglasses tint blue

commit fc4a64ed52
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:58:53 2023 -0500

    Automatic changelog generation #17871 [ci skip]

commit ab089cfae7
Author: ynot01 <ynot000001@gmail.com>
Date:   Fri Feb 10 17:58:51 2023 -0500

    Cult tiles now block atmos like everyone though it did (#17871)

    * Update reinf_floor.dm

    * Update cult_structures.dm

    * Update cult_structures.dm

commit 20af730457
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:58:27 2023 -0500

    Automatic changelog generation #17819 [ci skip]

commit 3e918a5658
Author: Mqiib <43766432+Mqiib@users.noreply.github.com>
Date:   Fri Feb 10 17:58:25 2023 -0500

    Unstupidify (#17819)

commit 411c213dcd
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:58:11 2023 -0500

    Automatic changelog generation #17818 [ci skip]

commit 919a2686b6
Author: Ling <lingbleed@gmail.com>
Date:   Fri Feb 10 23:58:08 2023 +0100

    Prevents wormholes from spawning in syndicate shuttles (#17818)

commit b66d0720bb
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:56:47 2023 -0500

    Automatic changelog generation #17811 [ci skip]

commit b9eb469042
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Fri Feb 10 16:56:44 2023 -0600

    Reduces body temp increase from being on fire (#17811)

    * Greatly reduces heat from being on fire

    * even less

commit cdb38b84fd
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:49:43 2023 -0500

    Automatic changelog generation #17804 [ci skip]

commit 1f02d82d27
Author: ynot01 <ynot000001@gmail.com>
Date:   Fri Feb 10 17:49:41 2023 -0500

    from fortnite (#17804)

    do the thing

commit 0c64a222c8
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:47:18 2023 -0500

    Automatic changelog generation #17801 [ci skip]

commit f6bf19009f
Author: Ezhan <39889035+Ethan4303@users.noreply.github.com>
Date:   Fri Feb 10 17:47:15 2023 -0500

    rotates the gas simulator in yogstation turbine (#17801)

commit 7c9b4054a0
Author: ynot01 <ynot000001@gmail.com>
Date:   Fri Feb 10 17:46:46 2023 -0500

    Protects events from being faked random by admins (#17790)

    * Update _event.dm

    * Update _event.dm

commit cf793830ec
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:46:06 2023 -0500

    Automatic changelog generation #17785 [ci skip]

commit 15bb9f53b7
Author: Skrem_7 <98909416+Skrem7@users.noreply.github.com>
Date:   Fri Feb 10 17:46:03 2023 -0500

    adds a spare mag to oddjob kit (#17785)

commit c69563273b
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:45:23 2023 -0500

    Automatic changelog generation #17769 [ci skip]

commit 367cf38f16
Author: ynot01 <ynot000001@gmail.com>
Date:   Fri Feb 10 17:45:20 2023 -0500

    Purchasable autosurgeon for 5TC (#17769)

    * syndi cat

    * Update uplink_items.dm

commit 247a50bc9f
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:43:58 2023 -0500

    Automatic changelog generation #17735 [ci skip]

commit 167ab6af2b
Author: SapphicOverload <93578146+SapphicOverload@users.noreply.github.com>
Date:   Fri Feb 10 17:43:55 2023 -0500

    Multilingual quirk can no longer give you centcom encrypted language and costs 2 points instead of 3 (#17735)

    * guh

    * Update good.dm

commit bb77f2d6a3
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 17:22:33 2023 -0500

    Automatic changelog generation #17856 [ci skip]

commit f13f241426
Author: Redd <36747151+ReddicusDragon@users.noreply.github.com>
Date:   Fri Feb 10 17:22:31 2023 -0500

    Revert "Removes felinid language (#17825)" (#17856)

    This reverts commit e75cb0ad00.

commit c53b3bc784
Author: Changelogs <action@github.com>
Date:   Fri Feb 10 22:17:13 2023 +0000

    Automatic changelog compile [ci skip]

commit bf214dad30
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 15:57:59 2023 -0500

    Automatic changelog generation #17832 [ci skip]

commit 0144098f5c
Author: Addust <80979251+Addust@users.noreply.github.com>
Date:   Fri Feb 10 20:57:56 2023 +0000

    Gives onehalf a blue oxygen tank instead of a red one inside the safe (#17832)

    yes

commit 84c1ff3331
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 13:08:39 2023 -0500

    Automatic changelog generation #17881 [ci skip]

commit e2ce0336ff
Author: wejengin2 <48154165+wejengin2@users.noreply.github.com>
Date:   Fri Feb 10 19:08:36 2023 +0100

    ye (#17881)

commit 596ac490f7
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 12:29:57 2023 -0500

    Automatic changelog generation #17812 [ci skip]

commit 2047871e5b
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Fri Feb 10 11:29:53 2023 -0600

    Adds a chemical that purges nanites (#17812)

    * NaniteRemovalChemical

    * rename

    * Update code/modules/reagents/chemistry/reagents/medicine_reagents.dm

    Co-authored-by: Ling <lingbleed@gmail.com>

    ---------

    Co-authored-by: Ling <lingbleed@gmail.com>

commit bb0d420b09
Author: wejengin2 <48154165+wejengin2@users.noreply.github.com>
Date:   Fri Feb 10 16:04:20 2023 +0100

    Massacres the unused maps. (#17764)

    * someone has to do it

    * camels

    * order

    * ok no

commit 0424f5f5e4
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 09:40:37 2023 -0500

    Automatic changelog generation #17823 [ci skip]

commit 611fc49e0b
Author: Jamie D <993128+JamieD1@users.noreply.github.com>
Date:   Fri Feb 10 14:40:33 2023 +0000

    e (#17823)

commit adda8bc9a0
Author: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com>
Date:   Fri Feb 10 15:17:47 2023 +0100

    Update unique_donator_items.dm (#17874)

commit 3a8ad081f9
Author: Changelogs <action@github.com>
Date:   Fri Feb 10 14:08:30 2023 +0000

    Automatic changelog compile [ci skip]

commit ff2f15a395
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 05:01:24 2023 -0500

    Automatic changelog generation #17848 [ci skip]

commit 58a00ef32d
Author: Waterpig <49160555+Majkl-J@users.noreply.github.com>
Date:   Fri Feb 10 11:01:21 2023 +0100

    Adds barricading of airlocks and doors (#17848)

    * I like wood 😩

    * Makes them faster to remove

    * 😩

    * I hate molti

    Co-authored-by: Molti <108117184+Moltijoe@users.noreply.github.com>

    ---------

    Co-authored-by: Molti <108117184+Moltijoe@users.noreply.github.com>

commit 726c31fd2f
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 04:29:51 2023 -0500

    Automatic changelog generation #17807 [ci skip]

commit 9d4d28edd3
Author: Redd <36747151+ReddicusDragon@users.noreply.github.com>
Date:   Fri Feb 10 04:29:48 2023 -0500

    Removes corn syrup from catsip (#17807)

commit a995a0e6fd
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 04:28:25 2023 -0500

    Automatic changelog generation #17831 [ci skip]

commit d35292c3d4
Author: Ling <lingbleed@gmail.com>
Date:   Fri Feb 10 10:28:20 2023 +0100

    RPD now builds even when clicked on another pipe (#17831)

commit 51fd6de808
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 03:53:48 2023 -0500

    Automatic changelog generation #17852 [ci skip]

commit 9f91e2edf7
Author: Manatee <74586965+MajManatee@users.noreply.github.com>
Date:   Fri Feb 10 02:53:45 2023 -0600

    les go (#17852)

commit a55a6d4297
Author: Changelogs <action@github.com>
Date:   Fri Feb 10 06:11:39 2023 +0000

    Automatic changelog compile [ci skip]

commit 380e400cb3
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 01:04:58 2023 -0500

    Automatic changelog generation #17837 [ci skip]

commit 861567f4db
Author: Byemoh <baiomurang@gmail.com>
Date:   Fri Feb 10 00:04:56 2023 -0600

    Update airlock.dm (#17837)

commit 08cec4a012
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 01:01:14 2023 -0500

    Automatic changelog generation #17813 [ci skip]

commit 5cf47b2580
Author: ynot01 <ynot000001@gmail.com>
Date:   Fri Feb 10 01:01:12 2023 -0500

    Update hologram.dm (#17813)

commit ef783cb856
Author: Yogbot-13 <admin@yogstation.net>
Date:   Fri Feb 10 00:58:35 2023 -0500

    Automatic changelog generation #17834 [ci skip]

commit a00b6ce757
Author: ynot01 <ynot000001@gmail.com>
Date:   Fri Feb 10 00:58:33 2023 -0500

    Update medbeam.dm (#17834)

commit d5b72b2259
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 9 20:22:06 2023 -0500

    Automatic changelog generation #17723 [ci skip]

commit 4a6973a465
Author: Byemoh <baiomurang@gmail.com>
Date:   Thu Feb 9 19:22:03 2023 -0600

    Falling into a chasm doesn't delete your body and someone can fish you up (#17723)

    * eeeee

    * e

    * map

    * break

    * eeeee

    * cope

    * Update chasm.dm

commit 229d6664ef
Author: Changelogs <action@github.com>
Date:   Thu Feb 9 22:17:48 2023 +0000

    Automatic changelog compile [ci skip]

commit f606eaac8e
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 9 10:41:20 2023 -0500

    Automatic changelog generation #17670 [ci skip]

commit 26ad93fd58
Author: ynot01 <ynot000001@gmail.com>
Date:   Thu Feb 9 10:41:17 2023 -0500

    Big Heretic revamp (finally) (#17670)

    * heresy

    * Update eldritch_book.dm

    * heat resistant lizards

    * 5 tile range only!

    * delete the shield dummy!

    * Update eldritch_items.dm

    * new sounds

    * Update eldritch_antag.dm

    * Update eldritch_items.dm

    * sanity

    * Update code/modules/antagonists/eldritch_cult/eldritch_book.dm

    Co-authored-by: Ling <lingbleed@gmail.com>

    ---------

    Co-authored-by: Ling <lingbleed@gmail.com>

commit 2264d7e6bc
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 9 10:36:18 2023 -0500

    Automatic changelog generation #17795 [ci skip]

commit 6e401075bd
Author: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com>
Date:   Thu Feb 9 16:36:15 2023 +0100

    It now takes 6 seconds to cremate someone, and 3 seconds to break out if they're conscious (#17795)

    * Update morgue.dm

    * Update morgue.dm

    * Update code/game/objects/structures/morgue.dm

    * Update code/game/objects/structures/morgue.dm

commit c28d359784
Author: Yogbot-13 <admin@yogstation.net>
Date:   Thu Feb 9 10:27:17 2023 -0500

    Automatic changelog generation #17766 [ci skip]

commit a0c31d2aee
Author: Skrem_7 <98909416+Skrem7@users.noreply.github.com>
Date:   Thu Feb 9 10:27:13 2023 -0500

    brrrt (#17766)

commit 9ff2bc445a
Author: Changelogs <action@github.com>
Date:   Thu Feb 9 06:11:19 2023 +0000

    Automatic changelog compile [ci skip]

commit d268cadeda
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 8 18:44:13 2023 -0500

    Automatic changelog generation #17806 [ci skip]

commit c223e28c9d
Author: Ling <lingbleed@gmail.com>
Date:   Thu Feb 9 00:44:11 2023 +0100

    Fix 'id in pda' pref (#17806)

commit 44decca884
Author: Changelogs <action@github.com>
Date:   Wed Feb 8 22:16:57 2023 +0000

    Automatic changelog compile [ci skip]

commit d750b905dd
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 8 13:17:57 2023 -0500

    Automatic changelog generation #17777 [ci skip]

commit 00a527192b
Author: Manatee <74586965+MajManatee@users.noreply.github.com>
Date:   Wed Feb 8 12:17:54 2023 -0600

    More snowflake items - Boxta (#17777)

    * all non spritework

    * Quirky first hat

    * mmm sprites

commit f028dd3418
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 8 12:31:26 2023 -0500

    Automatic changelog generation #17825 [ci skip]

commit e75cb0ad00
Author: Redd <36747151+ReddicusDragon@users.noreply.github.com>
Date:   Wed Feb 8 12:31:23 2023 -0500

    Removes felinid language (#17825)

    * Removes felinid language from silicons

    * Removes multilingual (felinid) trait

    * Removes felinid from being granted upon using cat ears

    * Redd moment

    * removes felinid from tongue's possible language base.

    * removes felinid from telecomms

    * removes felinid from language holders

    * removes the felinid language as it provides a material benefit to donors

    * gives felinids the english language holder

    * removes felinid language icon

commit 060c415b04
Author: Changelogs <action@github.com>
Date:   Wed Feb 8 14:08:15 2023 +0000

    Automatic changelog compile [ci skip]

commit 7345f0e82d
Author: Yogbot-13 <admin@yogstation.net>
Date:   Wed Feb 8 05:39:07 2023 -0500

    Automatic changelog generation #17846 [ci skip]

commit 3e51ef4f8b
Author: Molti <108117184+Moltijoe@users.noreply.github.com>
Date:   Wed Feb 8 04:39:03 2023 -0600

    Update lavaland_surface_maze.dmm (#17846)

commit e7823cfc39
Author: Changelogs <action@github.com>
Date:   Wed Feb 8 06:11:43 2023 +0000

    Automatic changelog compile [ci skip]

commit d927ebc03d
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 20:39:04 2023 -0500

    Automatic changelog generation #17802 [ci skip]

commit 0fd7dcfc9d
Author: cuackles <68789204+cuackles@users.noreply.github.com>
Date:   Tue Feb 7 22:39:01 2023 -0300

    monkey energy no longer becomes invisible when crushed (#17802)

    * Update janitor.dmi

    * Update janitor.dmi

    * Update janitor.dmi

commit 61601d937e
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 19:57:01 2023 -0500

    Automatic changelog generation #17791 [ci skip]

commit 902e743274
Author: BurgerLUA <8602857+BurgerLUA@users.noreply.github.com>
Date:   Tue Feb 7 16:56:58 2023 -0800

    MALF is no longer continuous (#17791)

commit 81c0963f74
Author: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com>
Date:   Wed Feb 8 01:56:07 2023 +0100

    Update adminhelp.dm (#17783)

commit 95947d2fe2
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 19:53:00 2023 -0500

    Automatic changelog generation #17742 [ci skip]

commit f83723c389
Author: Ling <lingbleed@gmail.com>
Date:   Wed Feb 8 01:52:57 2023 +0100

    Ports SSfoam and SSsmoke (#17742)

    * Ports SSfoam and SSsmoke

    * Remove dupe define

commit 9bb63a7577
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 19:52:22 2023 -0500

    Automatic changelog generation #17738 [ci skip]

commit 0cf7ecf050
Author: Ling <lingbleed@gmail.com>
Date:   Wed Feb 8 01:52:19 2023 +0100

    Actually adds passive vent to RPD (#17738)

    * Actually adds passive vent to RPD

    * Fixed and re-added passive vents

commit 5b9d198f6f
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 18:37:58 2023 -0500

    Automatic changelog generation #17816 [ci skip]

commit 148e80f8ec
Author: ynot01 <ynot000001@gmail.com>
Date:   Tue Feb 7 18:37:55 2023 -0500

    Fixes foam darts not doing any stamina damage (#17816)

    * Update foam_dart.dm

    * Update foam_dart.dm

commit 42165a9806
Author: Changelogs <action@github.com>
Date:   Tue Feb 7 22:17:04 2023 +0000

    Automatic changelog compile [ci skip]

commit b9f7613d59
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 14:59:58 2023 -0500

    Automatic changelog generation #17748 [ci skip]

commit 1cfbe0fd48
Author: Byemoh <baiomurang@gmail.com>
Date:   Tue Feb 7 13:59:54 2023 -0600

    adds det's sunglasses and shit on his desk on gax and other misc stuff (#17748)

    * eeeeeeeeee

    * shudders

    * readds stuff

commit 3947b4ac5a
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 11:46:17 2023 -0500

    Automatic changelog generation #17799 [ci skip]

commit c3cfad4913
Author: ynot01 <ynot000001@gmail.com>
Date:   Tue Feb 7 11:46:14 2023 -0500

    weird (#17799)

commit 8de1275a99
Author: Changelogs <action@github.com>
Date:   Tue Feb 7 14:08:44 2023 +0000

    Automatic changelog compile [ci skip]

commit 198c9f89aa
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 06:52:05 2023 -0500

    Automatic changelog generation #17822 [ci skip]

commit 63928e7f87
Author: Jamie D <993128+JamieD1@users.noreply.github.com>
Date:   Tue Feb 7 11:52:02 2023 +0000

    Update game_options.txt (#17822)

commit 7daad46a71
Author: Yogbot-13 <admin@yogstation.net>
Date:   Tue Feb 7 05:15:44 2023 -0500

    Automatic changelog generation #17776 [ci skip]

commit b01613407a
Author: Byemoh <baiomurang@gmail.com>
Date:   Tue Feb 7 04:15:40 2023 -0600

    Alternate Gax Arrivals design for free miner ship (#17776)

    * Update GaxStation.dmm

    * Update GaxStation.dmm

    * e

commit 23abc5abd2
Author: Changelogs <action@github.com>
Date:   Tue Feb 7 06:11:41 2023 +0000

    Automatic changelog compile [ci skip]

commit d170eab0aa
Author: Yogbot-13 <admin@yogstation.net>
Date:   Mon Feb 6 19:03:32 2023 -0500

    Automatic changelog generation #17797 [ci skip]

commit 1aac303800
Author: Redd <36747151+ReddicusDragon@users.noreply.github.com>
Date:   Mon Feb 6 19:03:29 2023 -0500

    Updates inventory procs to allow silent pickup (#17797)

    * adds make_sound parameter to put_in_hands, first step to making items able to be picked up with or without sound

    * adds make_sound parameter to put_in_active_hand, second step in allowing items to be picked up with or without sound

    * adds make_sound parameter to put_in_hand, third step

    * redd moment

    * weeeeeeee

    * NukeOps nuke code papers spawning are now silent

commit 57283fa900
Author: Yogbot-13 <admin@yogstation.net>
Date:   Mon Feb 6 18:17:08 2023 -0500

    Automatic changelog generation #17712 [ci skip]

commit b2c06b0866
Author: Byemoh <baiomurang@gmail.com>
Date:   Mon Feb 6 17:17:05 2023 -0600

    Lavaland Corn Maze Ruin (#17712)

    * eeee

    * yep

    * Update lavaruinblacklist.txt

    ---------

    Co-authored-by: wejengin2 <48154165+wejengin2@users.noreply.github.com>

commit 0d00d7457c
Author: Changelogs <action@github.com>
Date:   Mon Feb 6 22:16:37 2023 +0000

    Automatic changelog compile [ci skip]

commit 7955f64f79
Author: Yogbot-13 <admin@yogstation.net>
Date:   Mon Feb 6 10:52:52 2023 -0500

    Automatic changelog generation #17582 [ci skip]

commit 8df29b5392
Author: 00ze-cyclone <96987868+00ze-cyclone@users.noreply.github.com>
Date:   Mon Feb 6 16:52:48 2023 +0100

    Uranium eating aegun, second try (#17582)

    * new aegun

    * it just work

    * Update code/modules/projectiles/guns/energy/energy_gun.dm

    Co-authored-by: Molti <108117184+Moltijoe@users.noreply.github.com>

    * Add files via upload

    * dfuisqbdusq

    ---------

    Co-authored-by: Molti <108117184+Moltijoe@users.noreply.github.com>

commit 498e4e6ae4
Author: Changelogs <action@github.com>
Date:   Mon Feb 6 14:09:30 2023 +0000

    Automatic changelog compile [ci skip]

commit e37654707e
Author: Yogbot-13 <admin@yogstation.net>
Date:   Mon Feb 6 07:43:42 2023 -0500

    Automatic changelog generation #17768 [ci skip]

commit 5725a33174
Author: ynot01 <ynot000001@gmail.com>
Date:   Mon Feb 6 07:43:39 2023 -0500

    Foam darts now deal stamina damage if you're holding a toy foam gun (#17768)

    * Update foam_dart.dm

    * Update foam_dart.dm

commit d7f3ee4734
Author: Yogbot-13 <admin@yogstation.net>
Date:   Mon Feb 6 06:38:11 2023 -0500

    Automatic changelog generation #17707 [ci skip]

commit a6c0573423
Author: Mqiib <43766432+Mqiib@users.noreply.github.com>
Date:   Mon Feb 6 06:38:08 2023 -0500

    Shimmyjimmies ion bolts to be less "why are they like that" and more "hey that kinda makes sense" (#17707)

    * NEW IONS

    * forgor

    * hos gun shooty

commit cc868113c1
Author: Changelogs <action@github.com>
Date:   Sun Feb 5 22:15:50 2023 +0000

    Automatic changelog compile [ci skip]

commit 0343eb61c8
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sun Feb 5 14:37:43 2023 -0500

    Automatic changelog generation #17749 [ci skip]

commit e9bb5b6679
Author: ynot01 <ynot000001@gmail.com>
Date:   Sun Feb 5 14:37:41 2023 -0500

    Adds the rest of the roundstart race languages to multilingual quirks (#17749)

    * Update good.dm

    * Update code/datums/traits/good.dm

    Co-authored-by: 00ze-cyclone <96987868+00ze-cyclone@users.noreply.github.com>

    ---------

    Co-authored-by: 00ze-cyclone <96987868+00ze-cyclone@users.noreply.github.com>

commit 00d55013b1
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sun Feb 5 12:14:21 2023 -0500

    Automatic changelog generation #17779 [ci skip]

commit 85661c5d71
Author: LazennG <58535870+LazennG@users.noreply.github.com>
Date:   Sun Feb 5 09:14:18 2023 -0800

    buster arm patch (#17779)

commit 20b3adaae3
Author: Changelogs <action@github.com>
Date:   Sun Feb 5 14:07:35 2023 +0000

    Automatic changelog compile [ci skip]

commit 123638a50e
Author: Yogbot-13 <admin@yogstation.net>
Date:   Sun Feb 5 01:21:47 2023 -0500

    Automatic changelog generation #17774 [ci skip]

commit 707b8379f9
Author: ktlwjec <122807629+ktlwjec0@users.noreply.github.com>
Date:   Sun Feb 5 06:21:45 2023 +0000

    blue burger uses patty (#17774)

commit 6ba5dd3f5f
Author: Changelogs <action@github.com>
Date:   Sun Feb 5 06:10:13 2023 +0000

    Automatic changelog compile [ci skip]

* Revert "Squashed commit of the following:"

This reverts commit 294dc43cff.

* makes anomaly quiver printable

* running it back

* DIE ICON CORNFLAKES DIE

* Revert "DIE ICON CORNFLAKES DIE"

This reverts commit a5294ffab4.

* if this does not work I will scream

* i forgor lazenn redid this

* linter fixes?

* weh

* adds returning variable to break bow

* fixes quiver/hardlight outlines

* resets dmi files

* hello?

* indentation my beloathed

* icons? please don't github

* fixes gumballs/lollipops

* fixes foam force shotguns

* Revert "fixes foam force shotguns"

This reverts commit 37d079dc91.

* fixes foam force for real

* tidies up some sprites

* agh

* fixes bone-tipped nocked sprite

* makes it so beanbag "slugs" don't look like syringes

* fixes in-hand bone-tipped

* removes message_admins from debugging (oops)

* fixes an oversight with bone crossbow crafting

* aaa

* agh

* Agh x2

* should fix icon cornflakes

* killing

* holy shit i think i learned something today

* a g h

---------

Co-authored-by: nmajask <nmajask@gmail.com>
2023-05-06 23:11:36 -05:00

2809 lines
110 KiB
Plaintext

// This code handles different species in the game.
GLOBAL_LIST_EMPTY(roundstart_races)
GLOBAL_LIST_EMPTY(mentor_races)
/// An assoc list of species types to their features (from get_features())
GLOBAL_LIST_EMPTY(features_by_species)
/datum/species
/// if the game needs to manually check your race to do something not included in a proc here, it will use this
var/id
///this is used if you want to use a different species limb sprites. Mainly used for angels as they look like humans.
var/limbs_id
/// this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever
var/name
/// The formatting of the name of the species in plural context. Defaults to "[name]\s" if unset.
/// Ex "[Plasmamen] are weak", "[Mothmen] are strong", "[Lizardpeople] don't like", "[Golems] hate"
var/plural_form
/// if alien colors are disabled, this is the color that will be used by that race
var/default_color = "#FFF"
/// whether or not the race has sexual characteristics. at the moment this is only FALSE for skeletons and shadows
var/sexes = TRUE
///A list that contains pixel offsets for various clothing features, if your species is a different shape
var/list/offset_features = list(OFFSET_UNIFORM = list(0,0), OFFSET_ID = list(0,0), OFFSET_GLOVES = list(0,0), OFFSET_GLASSES = list(0,0), OFFSET_EARS = list(0,0), OFFSET_SHOES = list(0,0), OFFSET_S_STORE = list(0,0), OFFSET_FACEMASK = list(0,0), OFFSET_HEAD = list(0,0), OFFSET_FACE = list(0,0), OFFSET_BELT = list(0,0), OFFSET_BACK = list(0,0), OFFSET_SUIT = list(0,0), OFFSET_NECK = list(0,0))
/// this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color
var/hair_color
/// the alpha used by the hair. 255 is completely solid, 0 is transparent.
var/hair_alpha = 255
///The gradient style used for the mob's hair.
var/grad_style
///The gradient color used to color the gradient.
var/grad_color
/// does it use skintones or not? (spoiler alert this is only used by humans)
var/use_skintones = FALSE
/// If your race wants to bleed something other than bog standard blood, change this to reagent id.
var/datum/reagent/exotic_blood
///If your race uses a non standard bloodtype (A+, O-, AB-, etc)
var/exotic_bloodtype = ""
///What the species drops on gibbing
var/meat = /obj/item/reagent_containers/food/snacks/meat/slab/human
///What, if any, leather will be dropped
var/skinned_type
///What kind of foods the species loves
var/liked_food = NONE
///What kind of foods the species dislikes!
var/disliked_food = GROSS
///What kind of foods cause harm to the species
var/toxic_food = TOXIC
/// slots the race can't equip stuff to
var/list/no_equip = list()
/// slots the race can't equip stuff to that have been added externally that should be inherited on species change
var/list/extra_no_equip = list()
/// this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids
var/nojumpsuit = FALSE
/// affects the speech message
var/say_mod = "says"
/// Weighted list. NOTE: Picks one of the list component and then does a prob() on it, since we can't do a proper weighted pick, since we need to take into account the regular say_mod.
//TL;DR "meows" = 75 and "rawr" = 25 isn't actually 75% and 25%. It's 75% * 50% = 37.5% and 25% * 50% = 12.5%. Chance is divided by number of elements
var/list/rare_say_mod = list()
///Used if you want to give your species thier own language
var/species_language_holder = /datum/language_holder
/// Default mutant bodyparts for this species. Don't forget to set one for every mutant bodypart you allow this species to have.
var/list/default_features = list()
/// Visible CURRENT bodyparts that are unique to a species. DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK SHIT UP! Changes to this list for non-species specific bodyparts (ie cat ears and tails) should be assigned at organ level if possible. Layer hiding is handled by handle_mutant_bodyparts() below.
var/list/mutant_bodyparts = list()
///Internal organs that are unique to this race.
var/list/mutant_organs = list()
/// this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster
var/speedmod = 0
///overall defense for the race... or less defense, if it's negative.
var/armor = 0
/// multiplier for brute damage
var/brutemod = 1
/// multiplier for burn damage
var/burnmod = 1
/// multiplier for cold damage
var/coldmod = 1
/// multiplier for heat damage
var/heatmod = 1
/// multiplier for temperature adjustment
var/tempmod = 1
/// multiplier for acid damage // yogs - Old Plant People
var/acidmod = 1
/// multiplier for stun duration
var/stunmod = 1
/// multiplier for oxyloss
var/oxymod = 1
/// multiplier for cloneloss
var/clonemod = 1
/// multiplier for toxloss
var/toxmod = 1
/// multiplier for stun duration
var/staminamod = 1
/// multiplier for money paid at payday, species dependent
var/payday_modifier = 1
///Type of damage attack does
var/attack_type = BRUTE
///lowest possible punch damage. if this is set to 0, punches will always miss
var/punchdamagelow = 1
///highest possible punch damage
var/punchdamagehigh = 10
///damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical
var/punchstunthreshold = 10
///values of inaccuracy that adds to the spread of any ranged weapon
var/aiminginaccuracy = 0
///base electrocution coefficient
var/siemens_coeff = 1
///base action speed coefficient
var/action_speed_coefficient = 1
///what kind of damage overlays (if any) appear on our species when wounded?
var/damage_overlay_type = "human"
///to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"]
var/fixed_mut_color = ""
///special mutation that can be found in the genepool. Dont leave empty or changing species will be a headache
var/inert_mutation = DWARFISM
///used to set the mobs deathsound on species change
var/deathsound
///Sounds to override barefeet walkng
var/list/special_step_sounds
///Sounds to play while walking regardless of wearing shoes
var/list/special_walk_sounds
///Special sound for grabbing
var/grab_sound
///yogs - audio of a species' scream
var/screamsound
///is a flying species, just a check for some things
var/flying_species = FALSE
///the actual flying ability given to flying species
var/datum/action/innate/flight/fly
///the icon used for the wings + details icon of a different source colour
var/wings_icon = "Angel"
var/wings_detail
/// Used for metabolizing reagents. We're going to assume you're a meatbag unless you say otherwise.
var/reagent_tag = PROCESS_ORGANIC
/// What kind of gibs to spawn
var/species_gibs = "human"
/// Can this species use numbers in its name?
var/allow_numbers_in_name = FALSE
/// species-only traits. Can be found in DNA.dm
var/list/species_traits = list()
/// generic traits tied to having the species
var/list/inherent_traits = list()
///biotypes, used for viruses and the like
var/list/inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
/// punch-specific attack verb
var/attack_verb = "punch"
///the melee attack sound
var/sound/attack_sound = 'sound/weapons/punch1.ogg'
///the swing and miss sound
var/sound/miss_sound = 'sound/weapons/punchmiss.ogg'
/// list of mobs that will ignore this species
var/list/mob/living/ignored_by = list()
//Breathing!
///what type of gas is breathed
var/breathid = "o2"
//Do NOT remove by setting to null. use OR make a RESPECTIVE TRAIT (removing stomach? add the NOSTOMACH trait to your species)
//why does it work this way? because traits also disable the downsides of not having an organ, removing organs but not having the trait will make your species die
///Replaces default brain with a different organ
var/obj/item/organ/brain/mutantbrain = /obj/item/organ/brain
///Replaces default heart with a different organ
var/obj/item/organ/heart/mutantheart = /obj/item/organ/heart
///Replaces default lungs with a different organ
var/obj/item/organ/lungs/mutantlungs = /obj/item/organ/lungs
///Replaces default eyes with a different organ
var/obj/item/organ/eyes/mutanteyes = /obj/item/organ/eyes
///Replaces default ears with a different organ
var/obj/item/organ/ears/mutantears = /obj/item/organ/ears
///Replaces default tongue with a different organ
var/obj/item/organ/tongue/mutanttongue = /obj/item/organ/tongue
///Replaces default liver with a different organ
var/obj/item/organ/liver/mutantliver = /obj/item/organ/liver
///Replaces default stomach with a different organ
var/obj/item/organ/stomach/mutantstomach = /obj/item/organ/stomach
///Replaces default appendix with a different organ.
var/obj/item/organ/appendix/mutantappendix = /obj/item/organ/appendix
///Forces a species tail
var/obj/item/organ/tail/mutanttail = /obj/item/organ/tail
///Forces an item into this species' hands. Only an honorary mutantthing because this is not an organ and not loaded in the same way, you've been warned to do your research.
var/obj/item/mutanthands
var/override_float = FALSE
///Bitflag that controls what in game ways can select this species as a spawnable source. Think magic mirror and pride mirror, slime extract, ERT etc, see defines in __DEFINES/mobs.dm, defaults to NONE, so people actually have to think about it
var/changesource_flags = NONE
//The component to add when swimming
var/swimming_component = /datum/component/swimming
var/smells_like = "something alien"
//Should we preload this species's organs?
var/preload = TRUE
///////////
// PROCS //
///////////
/datum/species/New()
if(!limbs_id) //if we havent set a limbs id to use, just use our own id
limbs_id = id
if(!plural_form)
plural_form = "[name]\s"
return ..()
/// Gets a list of all species available to choose in roundstart.
/proc/get_selectable_species()
RETURN_TYPE(/list)
if (!GLOB.roundstart_races.len)
GLOB.roundstart_races = generate_selectable_species()
return GLOB.roundstart_races
/**
* Generates species available to choose in character setup at roundstart
*
* This proc generates which species are available to pick from in character setup.
* If there are no available roundstart species, defaults to human.
*/
/proc/generate_selectable_species()
var/list/selectable_species = list()
for(var/species_type in subtypesof(/datum/species))
var/datum/species/species = new species_type
if(species.check_roundstart_eligible())
selectable_species += species.id
qdel(species)
if(!selectable_species.len)
selectable_species += "human"
return selectable_species
/**
* Checks if a species is eligible to be picked at roundstart.
*
* Checks the config to see if this species is allowed to be picked in the character setup menu.
* Used by [/proc/generate_selectable_species].
*/
/datum/species/proc/check_roundstart_eligible()
if(id in (CONFIG_GET(keyed_list/roundstart_races)))
return TRUE
return FALSE
/datum/species/proc/check_mentor()
if(id in (CONFIG_GET(keyed_list/mentor_races)))
return TRUE
return FALSE
/datum/species/proc/random_name(gender,unique,lastname)
if(unique)
return random_unique_name(gender)
var/randname
if(gender == MALE)
randname = pick(GLOB.first_names_male)
else
randname = pick(GLOB.first_names_female)
if(lastname)
randname += " [lastname]"
else
randname += " [pick(GLOB.last_names)]"
return randname
//used to add things to the no_equip list that'll get inherited on species changes
/datum/species/proc/add_no_equip_slot(mob/living/carbon/C, slot)
extra_no_equip.Add(slot)
var/obj/item/thing = C.get_item_by_slot(slot)
if(thing && (!thing.species_exception || !is_type_in_list(src,thing.species_exception)))
C.dropItemToGround(thing)
//removes something from the extra_no_equip list as well as the normal no_equip list
/datum/species/proc/remove_no_equip_slot(mob/living/carbon/C, slot)
extra_no_equip.Remove(slot)
//Called when cloning, copies some vars that should be kept
/datum/species/proc/copy_properties_from(datum/species/old_species)
return
//Please override this locally if you want to define when what species qualifies for what rank if human authority is enforced.
/datum/species/proc/qualifies_for_rank(rank, list/features)
if(rank in GLOB.command_positions)
return 0
return 1
/datum/species/proc/has_toes()
return FALSE
/**
* Corrects organs in a carbon, removing ones it doesn't need and adding ones it does.
*
* Takes all organ slots, removes organs a species should not have, adds organs a species should have.
* can use replace_current to refresh all organs, creating an entirely new set.
*
* Arguments:
* * C - carbon, the owner of the species datum AKA whoever we're regenerating organs in
* * old_species - datum, used when regenerate organs is called in a switching species to remove old mutant organs.
* * replace_current - boolean, forces all old organs to get deleted whether or not they pass the species' ability to keep that organ
* * visual_only - boolean, only load organs that change how the species looks. Do not use for normal gameplay stuff
*/
/datum/species/proc/regenerate_organs(mob/living/carbon/C, datum/species/old_species, replace_current = TRUE, visual_only = FALSE)
//what should be put in if there is no mutantorgan (brains handled separately)
var/list/slot_mutantorgans = list(ORGAN_SLOT_BRAIN = mutantbrain, ORGAN_SLOT_HEART = mutantheart, ORGAN_SLOT_LUNGS = mutantlungs, ORGAN_SLOT_APPENDIX = mutantappendix, \
ORGAN_SLOT_EYES = mutanteyes, ORGAN_SLOT_EARS = mutantears, ORGAN_SLOT_TONGUE = mutanttongue, ORGAN_SLOT_LIVER = mutantliver, ORGAN_SLOT_STOMACH = mutantstomach, ORGAN_SLOT_TAIL = mutanttail)
for(var/slot in list(ORGAN_SLOT_BRAIN, ORGAN_SLOT_HEART, ORGAN_SLOT_LUNGS, ORGAN_SLOT_APPENDIX, \
ORGAN_SLOT_EYES, ORGAN_SLOT_EARS, ORGAN_SLOT_TONGUE, ORGAN_SLOT_LIVER, ORGAN_SLOT_STOMACH, ORGAN_SLOT_TAIL))
var/obj/item/organ/oldorgan = C.getorganslot(slot) //used in removing
var/obj/item/organ/neworgan = slot_mutantorgans[slot] //used in adding
if(visual_only && !initial(neworgan.visual))
continue
var/used_neworgan = FALSE
neworgan = SSwardrobe.provide_type(neworgan)
var/should_have = neworgan.get_availability(src) //organ proc that points back to a species trait (so if the species is supposed to have this organ)
if(oldorgan && (!should_have || replace_current))
if(slot == ORGAN_SLOT_BRAIN)
var/obj/item/organ/brain/brain = oldorgan
if(!brain.decoy_override)//"Just keep it if it's fake" - confucius, probably
brain.Remove(C,TRUE, TRUE) //brain argument used so it doesn't cause any... sudden death.
QDEL_NULL(brain)
oldorgan = null //now deleted
else
oldorgan.Remove(C,TRUE)
QDEL_NULL(oldorgan) //we cannot just tab this out because we need to skip the deleting if it is a decoy brain.
if(oldorgan)
oldorgan.setOrganDamage(0)
else if(should_have)
if(slot == ORGAN_SLOT_TAIL)
// Special snowflake code to handle tail appearances
var/obj/item/organ/tail/new_tail = neworgan
if(iscatperson(C))
new_tail.tail_type = C.dna.features["tail_human"]
if(ispolysmorph(C))
new_tail.tail_type = C.dna.features["tail_polysmorph"]
if(islizard(C))
var/obj/item/organ/tail/lizard/new_lizard_tail = neworgan
new_lizard_tail.tail_type = C.dna.features["tail_lizard"]
new_lizard_tail.spines = C.dna.features["spines"]
used_neworgan = TRUE
neworgan.Insert(C, TRUE, FALSE)
if(!used_neworgan)
qdel(neworgan)
if(old_species)
for(var/mutantorgan in old_species.mutant_organs)
// Snowflake check. If our species share this mutant organ, let's not remove it
// just yet as we'll be properly replacing it later.
if(mutantorgan in mutant_organs)
continue
var/obj/item/organ/I = C.getorgan(mutantorgan)
if(I)
I.Remove(C)
QDEL_NULL(I)
for(var/organ_path in mutant_organs)
var/obj/item/organ/current_organ = C.getorgan(organ_path)
if(!current_organ || replace_current)
var/obj/item/organ/replacement = SSwardrobe.provide_type(organ_path)
// If there's an existing mutant organ, we're technically replacing it.
// Let's abuse the snowflake proc that skillchips added. Basically retains
// feature parity with every other organ too.
//if(current_organ)
// current_organ.before_organ_replacement(replacement)
// organ.Insert will qdel any current organs in that slot, so we don't need to.
replacement.Insert(C, TRUE, FALSE)
/datum/species/proc/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
// Drop the items the new species can't wear
if((AGENDER in species_traits))
C.gender = PLURAL
if((FGENDER in species_traits))
C.gender = FEMALE
if((MGENDER in species_traits))
C.gender = MALE
extra_no_equip.Add(old_species.extra_no_equip)
for(var/slot_id in no_equip)
var/obj/item/thing = C.get_item_by_slot(slot_id)
if(thing && (!thing.species_exception || !is_type_in_list(src,thing.species_exception)))
C.dropItemToGround(thing)
if(C.hud_used)
C.hud_used.update_locked_slots()
// this needs to be FIRST because qdel calls update_body which checks if we have DIGITIGRADE legs or not and if not then removes DIGITIGRADE from species_traits
if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs")
species_traits += DIGITIGRADE
if(DIGITIGRADE in species_traits)
C.Digitigrade_Leg_Swap(FALSE)
C.mob_biotypes = inherent_biotypes
regenerate_organs(C,old_species)
if(exotic_bloodtype && C.dna.blood_type != exotic_bloodtype)
C.dna.blood_type = exotic_bloodtype
if(old_species.mutanthands)
for(var/obj/item/I in C.held_items)
if(istype(I, old_species.mutanthands))
qdel(I)
if(mutanthands)
// Drop items in hands
// If you're lucky enough to have a TRAIT_NODROP item, then it stays.
for(var/V in C.held_items)
var/obj/item/I = V
if(istype(I))
C.dropItemToGround(I)
else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
C.put_in_hands(new mutanthands())
if(ROBOTIC_LIMBS in species_traits)
for(var/obj/item/bodypart/B in C.bodyparts)
B.change_bodypart_status(BODYPART_ROBOTIC) // Makes all Bodyparts robotic.
B.render_like_organic = TRUE
if(NOMOUTH in species_traits)
for(var/obj/item/bodypart/head/head in C.bodyparts)
head.mouth = FALSE
for(var/X in inherent_traits)
ADD_TRAIT(C, X, SPECIES_TRAIT)
if(TRAIT_VIRUSIMMUNE in inherent_traits)
for(var/datum/disease/A in C.diseases)
A.cure(FALSE)
if(flying_species && isnull(fly))
fly = new
fly.Grant(C)
C.add_movespeed_modifier(MOVESPEED_ID_SPECIES, TRUE, 100, override=TRUE, multiplicative_slowdown=speedmod, movetypes=(~FLYING))
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
/datum/species/proc/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
if(C.dna.species.exotic_bloodtype)
C.dna.blood_type = random_blood_type()
if(DIGITIGRADE in species_traits)
C.Digitigrade_Leg_Swap(TRUE)
if(ROBOTIC_LIMBS in species_traits)
for(var/obj/item/bodypart/B in C.bodyparts)
B.change_bodypart_status(BODYPART_ORGANIC, FALSE, TRUE)
B.render_like_organic = FALSE
if(NOMOUTH in species_traits)
for(var/obj/item/bodypart/head/head in C.bodyparts)
head.mouth = TRUE
for(var/X in inherent_traits)
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
//If their inert mutation is not the same, swap it out
if((inert_mutation != new_species.inert_mutation) && LAZYLEN(C.dna.mutation_index) && (inert_mutation in C.dna.mutation_index))
C.dna.remove_mutation(inert_mutation)
//keep it at the right spot, so we can't have people taking shortcuts
var/location = C.dna.mutation_index.Find(inert_mutation)
C.dna.mutation_index[location] = new_species.inert_mutation
C.dna.default_mutation_genes[location] = C.dna.mutation_index[location]
C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation)
C.dna.default_mutation_genes[new_species.inert_mutation] = C.dna.mutation_index[new_species.inert_mutation]
if(flying_species)
fly.Remove(C)
QDEL_NULL(fly)
if(C.movement_type & FLYING)
ToggleFlight(C)
if(C?.dna?.species && (C.dna.features["wings"] == wings_icon))
if("wings" in C.dna.species.mutant_bodyparts)
C.dna.species.mutant_bodyparts -= "wings"
C.dna.features["wings"] = "None"
if(wings_detail && C.dna.features["wingsdetail"] == wings_detail)
if("wingsdetail" in C.dna.species.mutant_bodyparts)
C.dna.species.mutant_bodyparts -= "wingsdetail"
C.dna.features["wingsdetail"] = "None"
C.update_body()
C.remove_movespeed_modifier(MOVESPEED_ID_SPECIES)
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
H.remove_overlay(HAIR_LAYER)
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
if(!HD) //Decapitated
return
if(HAS_TRAIT(H, TRAIT_HUSK))
return
var/datum/sprite_accessory/S
var/list/standing = list()
var/hair_hidden = FALSE //ignored if the matching dynamic_X_suffix is non-empty
var/facialhair_hidden = FALSE // ^
var/dynamic_hair_suffix = "" //if this is non-null, and hair+suffix matches an iconstate, then we render that hair instead
var/dynamic_fhair_suffix = ""
//for augmented heads
if(HD.status == BODYPART_ROBOTIC && !yogs_draw_robot_hair) //yogs - allow for robot head hair
return
//we check if our hat or helmet hides our facial hair.
if(H.head)
var/obj/item/I = H.head
if(istype(I, /obj/item/clothing))
var/obj/item/clothing/C = I
dynamic_fhair_suffix = C.dynamic_fhair_suffix
if(I.flags_inv & HIDEFACIALHAIR)
facialhair_hidden = TRUE
if(H.wear_mask)
var/obj/item/clothing/mask/M = H.wear_mask
dynamic_fhair_suffix = M.dynamic_fhair_suffix //mask > head in terms of facial hair
if(M.flags_inv & HIDEFACIALHAIR)
facialhair_hidden = TRUE
if(H.facial_hair_style && (FACEHAIR in species_traits) && (!facialhair_hidden || dynamic_fhair_suffix))
S = GLOB.facial_hair_styles_list[H.facial_hair_style]
if(S)
//List of all valid dynamic_fhair_suffixes
var/static/list/fextensions
if(!fextensions)
var/icon/fhair_extensions = icon('icons/mob/facialhair_extensions.dmi')
fextensions = list()
for(var/s in fhair_extensions.IconStates(1))
fextensions[s] = TRUE
qdel(fhair_extensions)
//Is hair+dynamic_fhair_suffix a valid iconstate?
var/fhair_state = S.icon_state
var/fhair_file = S.icon
if(fextensions[fhair_state+dynamic_fhair_suffix])
fhair_state += dynamic_fhair_suffix
fhair_file = 'icons/mob/facialhair_extensions.dmi'
var/mutable_appearance/facial_overlay = mutable_appearance(fhair_file, fhair_state, -HAIR_LAYER)
if(!forced_colour)
if(hair_color)
if(hair_color == "mutcolor")
facial_overlay.color = "#" + H.dna.features["mcolor"]
else if(hair_color == "fixedmutcolor")
facial_overlay.color = "#[fixed_mut_color]"
else
facial_overlay.color = "#" + hair_color
else
facial_overlay.color = "#" + H.facial_hair_color
else
facial_overlay.color = forced_colour
facial_overlay.alpha = hair_alpha
standing += facial_overlay
if(H.head)
var/obj/item/I = H.head
if(istype(I, /obj/item/clothing))
var/obj/item/clothing/C = I
dynamic_hair_suffix = C.dynamic_hair_suffix
if(I.flags_inv & HIDEHAIR)
hair_hidden = TRUE
if(H.wear_mask)
var/obj/item/clothing/mask/M = H.wear_mask
if(!dynamic_hair_suffix) //head > mask in terms of head hair
dynamic_hair_suffix = M.dynamic_hair_suffix
if(M.flags_inv & HIDEHAIR)
hair_hidden = TRUE
if(!hair_hidden || dynamic_hair_suffix)
var/mutable_appearance/hair_overlay = mutable_appearance(layer = -HAIR_LAYER)
var/mutable_appearance/gradient_overlay = mutable_appearance(layer = -HAIR_LAYER)
if(!hair_hidden && !H.getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain
if(!(NOBLOOD in species_traits))
hair_overlay.icon = 'icons/mob/human_face.dmi'
hair_overlay.icon_state = "debrained"
else if(H.hair_style && (HAIR in species_traits))
S = GLOB.hair_styles_list[H.hair_style]
if(S)
//List of all valid dynamic_hair_suffixes
var/static/list/extensions
if(!extensions)
var/icon/hair_extensions = icon('icons/mob/hair_extensions.dmi') //hehe
extensions = list()
for(var/s in hair_extensions.IconStates(1))
extensions[s] = TRUE
qdel(hair_extensions)
//Is hair+dynamic_hair_suffix a valid iconstate?
var/hair_state = S.icon_state
var/hair_file = S.icon
if(extensions[hair_state+dynamic_hair_suffix])
hair_state += dynamic_hair_suffix
hair_file = 'icons/mob/hair_extensions.dmi'
hair_overlay.icon = hair_file
hair_overlay.icon_state = hair_state
if(!forced_colour)
if(hair_color)
if(hair_color == "mutcolor")
hair_overlay.color = "#" + H.dna.features["mcolor"]
else if(hair_color == "fixedmutcolor")
hair_overlay.color = "#[fixed_mut_color]"
else
hair_overlay.color = "#" + hair_color
else
hair_overlay.color = "#" + H.hair_color
//Gradients
grad_style = H.grad_style
grad_color = H.grad_color
if(grad_style)
var/datum/sprite_accessory/gradient = GLOB.hair_gradients_list[grad_style]
var/icon/temp = icon(gradient.icon, gradient.icon_state)
var/icon/temp_hair = icon(hair_file, hair_state)
temp.Blend(temp_hair, ICON_ADD)
gradient_overlay.icon = temp
gradient_overlay.color = "#" + grad_color
else
hair_overlay.color = forced_colour
hair_overlay.alpha = hair_alpha
if(OFFSET_FACE in H.dna.species.offset_features)
hair_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1]
hair_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2]
if(hair_overlay.icon)
standing += hair_overlay
standing += gradient_overlay
if("pod_hair" in H.dna.species.mutant_bodyparts)
//alright bear with me for a second while i explain this awful code since it was literally 3 days of me bumbling through blind
//for hair code to work, you need to start by removing the layer, as in the beginning with remove_overlay(head), then you need to use a mutable appearance variable
//the mutable appearance will store the sprite file dmi, the name of the sprite (icon_state), and the layer this will go on (in this case HAIR_LAYER)
//those are the basic variables, then you color the sprite with whatever source color you're using and set the alpha. from there it's added to the "standing" list
//which is storing all the individual mutable_appearance variables (each one is a sprite), and then standing is loaded into the H.overlays_standing and finalized
//with apply_overlays.
//if you're working with sprite code i hope this helps because i wish i was dead now.
S = GLOB.pod_hair_list[H.dna.features["pod_hair"]]
if(S)
if(ReadHSV(RGBtoHSV(H.hair_color))[3] <= ReadHSV("#7F7F7F")[3])
H.hair_color = H.dna.species.default_color
var/hair_state = S.icon_state
var/hair_file = S.icon
hair_overlay.icon = hair_file
hair_overlay.icon_state = hair_state
if(!forced_colour)
if(hair_color)
if(hair_color == "mutcolor")
hair_overlay.color = "#" + H.dna.features["mcolor"]
else if(hair_color == "fixedmutcolor")
hair_overlay.color = "#[fixed_mut_color]"
else
hair_overlay.color = "#" + hair_color
else
hair_overlay.color = "#" + H.hair_color
hair_overlay.alpha = hair_alpha
standing+=hair_overlay
//var/mutable_appearance/pod_flower = mutable_appearance(GLOB.pod_flower_list[H.dna.features["pod_flower"]].icon, GLOB.pod_flower_list[H.dna.features["pod_flower"]].icon_state, -HAIR_LAYER)
S = GLOB.pod_flower_list[H.dna.features["pod_flower"]]
if(S)
var/flower_state = S.icon_state
var/flower_file = S.icon
// flower_overlay.icon = flower_file
// flower_overlay.icon_state = flower_state
var/mutable_appearance/flower_overlay = mutable_appearance(flower_file, flower_state, -HAIR_LAYER)
if(!forced_colour)
if(hair_color)
if(hair_color == "mutcolor")
flower_overlay.color = "#" + H.dna.features["mcolor"]
else if(hair_color == "fixedmutcolor")
flower_overlay.color = "#[fixed_mut_color]"
else
flower_overlay.color = "#" + hair_color
else
flower_overlay.color = "#" + H.facial_hair_color
flower_overlay.alpha = hair_alpha
standing += flower_overlay
if(standing.len)
H.overlays_standing[HAIR_LAYER] = standing
H.apply_overlay(HAIR_LAYER)
/datum/species/proc/handle_body(mob/living/carbon/human/H)
H.remove_overlay(BODY_LAYER)
var/list/standing = list()
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
if(HD && !(HAS_TRAIT(H, TRAIT_HUSK)))
// lipstick
if(H.lip_style && (LIPS in species_traits))
var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER)
lip_overlay.color = H.lip_color
if(OFFSET_FACE in H.dna.species.offset_features)
lip_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1]
lip_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2]
standing += lip_overlay
#define OFFSET_X 1
#define OFFSET_Y 2
// eyes
if(!(NOEYESPRITES in species_traits))
var/obj/item/organ/eyes/parent_eyes = H.getorganslot(ORGAN_SLOT_EYES)
var/mutable_appearance/eye_overlay
if(parent_eyes)
eye_overlay += parent_eyes.generate_body_overlay(H)
else
var/mutable_appearance/missing_eyes = mutable_appearance('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER)
if(OFFSET_FACE in offset_features)
missing_eyes.pixel_x += offset_features[OFFSET_FACE][1]
missing_eyes.pixel_y += offset_features[OFFSET_FACE][2]
eye_overlay += missing_eyes
standing += eye_overlay
#undef OFFSET_X
#undef OFFSET_Y
//Underwear, Undershirts & Socks
if(!(NO_UNDERWEAR in species_traits))
if(H.underwear)
var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[H.underwear]
if(underwear)
if(HAS_TRAIT(H, TRAIT_SKINNY))
standing += wear_skinny_version(underwear.icon_state, underwear.icon, BODY_LAYER) //Neat, this works
else
standing += mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER)
if(H.undershirt)
var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[H.undershirt]
if(undershirt)
if(HAS_TRAIT(H, TRAIT_SKINNY)) //Check for skinny first
standing += wear_skinny_version(undershirt.icon_state, undershirt.icon, BODY_LAYER)
else if(H.dna.species.sexes && H.gender == FEMALE)
standing += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER)
else
standing += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER)
if(H.socks && H.get_num_legs(FALSE) >= 2 && !(DIGITIGRADE in species_traits))
var/datum/sprite_accessory/socks/socks = GLOB.socks_list[H.socks]
if(socks)
standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER)
if(standing.len)
H.overlays_standing[BODY_LAYER] = standing
H.apply_overlay(BODY_LAYER)
handle_mutant_bodyparts(H)
/datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
var/list/bodyparts_to_add = mutant_bodyparts.Copy()
var/list/relevent_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
var/list/standing = list()
H.remove_overlay(BODY_BEHIND_LAYER)
H.remove_overlay(BODY_ADJ_LAYER)
H.remove_overlay(BODY_FRONT_LAYER)
if(!mutant_bodyparts)
return
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
if("tail_lizard" in mutant_bodyparts)
if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
bodyparts_to_add -= "tail_lizard"
if("waggingtail_lizard" in mutant_bodyparts)
if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
bodyparts_to_add -= "waggingtail_lizard"
else if ("tail_lizard" in mutant_bodyparts)
bodyparts_to_add -= "waggingtail_lizard"
if("tail_human" in mutant_bodyparts)
if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
bodyparts_to_add -= "tail_human"
if("waggingtail_human" in mutant_bodyparts)
if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
bodyparts_to_add -= "waggingtail_human"
else if ("tail_human" in mutant_bodyparts)
bodyparts_to_add -= "waggingtail_human"
if("tail_polysmorph" in mutant_bodyparts)
if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
bodyparts_to_add -= "tail_polysmorph"
if("spines" in mutant_bodyparts)
if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
bodyparts_to_add -= "spines"
if("waggingspines" in mutant_bodyparts)
if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
bodyparts_to_add -= "waggingspines"
else if ("tail" in mutant_bodyparts)
bodyparts_to_add -= "waggingspines"
if("snout" in mutant_bodyparts) //Take a closer look at that snout!
if((H.wear_mask && H.wear_mask.mutantrace_variation == NO_MUTANTRACE_VARIATION && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "snout"
if("frills" in mutant_bodyparts)
if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "frills"
if("horns" in mutant_bodyparts)
if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "horns"
if("ears" in mutant_bodyparts)
if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "ears"
if("wings" in mutant_bodyparts)
if(!H.dna.features["wings"] || H.dna.features["wings"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception))))
bodyparts_to_add -= "wings"
if("wings_open" in mutant_bodyparts)
if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))
bodyparts_to_add -= "wings_open"
else if ("wings" in mutant_bodyparts)
bodyparts_to_add -= "wings_open"
if("wingsdetail" in mutant_bodyparts)
if(!H.dna.features["wingsdetail"] || H.dna.features["wingsdetail"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception))))
bodyparts_to_add -= "wingsdetail"
if("wingsdetail_open" in mutant_bodyparts)
if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))
bodyparts_to_add -= "wingsdetail_open"
else if ("wingsdetail" in mutant_bodyparts)
bodyparts_to_add -= "wingsdetail_open"
if("ipc_screen" in mutant_bodyparts)
if(!H.dna.features["ipc_screen"] || H.dna.features["ipc_screen"] == "None" || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEYES)) || !HD)
bodyparts_to_add -= "ipc_screen"
if("ipc_antenna" in mutant_bodyparts)
if(!H.dna.features["ipc_antenna"] || H.dna.features["ipc_antenna"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD)
bodyparts_to_add -= "ipc_antenna"
if("teeth" in mutant_bodyparts)
if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "teeth"
if("dome" in mutant_bodyparts)
if(!H.dna.features["dome"] || H.dna.features["dome"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "dome"
if("ethereal_mark" in mutant_bodyparts)
if((H.wear_mask && (H.wear_mask.flags_inv & HIDEEYES)) || (H.head && (H.head.flags_inv & HIDEEYES)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "ethereal_mark"
if("pod_hair" in mutant_bodyparts)
if((H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || (H.head && (H.head.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "pod_hair"
if("pod_flower" in mutant_bodyparts)
if((H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || (H.head && (H.head.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "pod_flower"
if(H.dna.features["pod_flower"] != H.dna.features["pod_hair"])
H.dna.features["pod_flower"] = H.dna.features["pod_hair"]
//Digitigrade legs are stuck in the phantom zone between true limbs and mutant bodyparts. Mainly it just needs more agressive updating than most limbs.
var/update_needed = FALSE
var/not_digitigrade = TRUE
for(var/X in H.bodyparts)
var/obj/item/bodypart/O = X
if(!O.use_digitigrade)
continue
not_digitigrade = FALSE
if(!(DIGITIGRADE in species_traits)) //Someone cut off a digitigrade leg and tacked it on
species_traits += DIGITIGRADE
var/should_be_squished = FALSE
if(H.wear_suit && ((H.wear_suit.flags_inv & HIDEJUMPSUIT) || (H.wear_suit.body_parts_covered & LEGS))) //Check for snowflake suit
var/obj/item/clothing/suit/A = H.wear_suit
if(A.mutantrace_variation != MUTANTRACE_VARIATION)
should_be_squished = TRUE
if(H.w_uniform && (H.w_uniform.body_parts_covered & LEGS)) //Check for snowflake jumpsuit
var/obj/item/clothing/under/U = H.w_uniform
if(U.mutantrace_variation != MUTANTRACE_VARIATION)
should_be_squished = TRUE
if(H.shoes)
var/obj/item/clothing/shoes/S = H.shoes
if(S.mutantrace_variation != MUTANTRACE_VARIATION)
should_be_squished = TRUE
if(should_be_squished)
S.adjusted = NORMAL_STYLE
else
S.adjusted = DIGITIGRADE_STYLE
H.update_inv_shoes()
if(O.use_digitigrade == FULL_DIGITIGRADE && should_be_squished)
O.use_digitigrade = SQUISHED_DIGITIGRADE
update_needed = TRUE
else if(O.use_digitigrade == SQUISHED_DIGITIGRADE && !should_be_squished)
O.use_digitigrade = FULL_DIGITIGRADE
update_needed = TRUE
if(update_needed)
H.update_body_parts()
if(not_digitigrade && (DIGITIGRADE in species_traits)) //Curse is lifted
species_traits -= DIGITIGRADE
if(!bodyparts_to_add)
return
var/g = (H.gender == FEMALE) ? "f" : "m"
for(var/layer in relevent_layers)
var/layertext = mutant_bodyparts_layertext(layer)
for(var/bodypart in bodyparts_to_add)
var/datum/sprite_accessory/S
switch(bodypart)
if("tail_lizard")
S = GLOB.tails_list_lizard[H.dna.features["tail_lizard"]]
if("waggingtail_lizard")
S = GLOB.animated_tails_list_lizard[H.dna.features["tail_lizard"]]
if("tail_human")
S = GLOB.tails_list_human[H.dna.features["tail_human"]]
if("tail_polysmorph")
S = GLOB.tails_list_polysmorph[H.dna.features["tail_polysmorph"]]
if("waggingtail_human")
S = GLOB.animated_tails_list_human[H.dna.features["tail_human"]]
if("spines")
S = GLOB.spines_list[H.dna.features["spines"]]
if("waggingspines")
S = GLOB.animated_spines_list[H.dna.features["spines"]]
if("snout")
S = GLOB.snouts_list[H.dna.features["snout"]]
if("frills")
S = GLOB.frills_list[H.dna.features["frills"]]
if("horns")
S = GLOB.horns_list[H.dna.features["horns"]]
if("ears")
S = GLOB.ears_list[H.dna.features["ears"]]
if("body_markings")
S = GLOB.body_markings_list[H.dna.features["body_markings"]]
if("wings")
S = GLOB.wings_list[H.dna.features["wings"]]
if("wingsopen")
S = GLOB.wings_open_list[H.dna.features["wings"]]
if("wingsdetail")
S = GLOB.wings_list[H.dna.features["wingsdetail"]]
if("wingsdetailopen")
S = GLOB.wings_open_list[H.dna.features["wingsdetail"]]
if("legs")
S = GLOB.legs_list[H.dna.features["legs"]]
if("moth_wings")
S = GLOB.moth_wings_list[H.dna.features["moth_wings"]]
if("moth_wingsopen")
S = GLOB.moth_wingsopen_list[H.dna.features["moth_wings"]]
if("caps")
S = GLOB.caps_list[H.dna.features["caps"]]
if("teeth")
S = GLOB.teeth_list[H.dna.features["teeth"]]
if("dome")
S = GLOB.dome_list[H.dna.features["dome"]]
if("dorsal_tubes")
S = GLOB.dorsal_tubes_list[H.dna.features["dorsal_tubes"]]
if("ethereal_mark")
S = GLOB.ethereal_mark_list[H.dna.features["ethereal_mark"]]
if("ipc_screen")
S = GLOB.ipc_screens_list[H.dna.features["ipc_screen"]]
if("ipc_antenna")
S = GLOB.ipc_antennas_list[H.dna.features["ipc_antenna"]]
if("ipc_chassis")
S = GLOB.ipc_chassis_list[H.dna.features["ipc_chassis"]]
if(!S || S.icon_state == "none")
continue
var/mutable_appearance/accessory_overlay = mutable_appearance(S.icon, layer = -layer)
//A little rename so we don't have to use tail_lizard or tail_human when naming the sprites.
if(bodypart == "tail_lizard" || bodypart == "tail_human" || bodypart == "tail_polysmorph")
bodypart = "tail"
else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human")
bodypart = "waggingtail"
if(S.gender_specific)
accessory_overlay.icon_state = "[g]_[bodypart]_[S.icon_state]_[layertext]"
else
accessory_overlay.icon_state = "m_[bodypart]_[S.icon_state]_[layertext]"
if(S.center)
accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y)
if(!(HAS_TRAIT(H, TRAIT_HUSK)))
if(!forced_colour)
switch(S.color_src)
if(MUTCOLORS)
if(H.dna.check_mutation(HULK) || H.dna.check_mutation(ACTIVE_HULK)) //HULK GO FIRST
accessory_overlay.color = "#00aa00"
else if(fixed_mut_color) //Then fixed color if applicable
accessory_overlay.color = "#[fixed_mut_color]"
else //Then snowflake color
accessory_overlay.color = "#[H.dna.features["mcolor"]]"
if(HAIR)
if(hair_color == "mutcolor")
accessory_overlay.color = "#[H.dna.features["mcolor"]]"
else if(hair_color == "fixedmutcolor")
accessory_overlay.color = "#[fixed_mut_color]"
else
accessory_overlay.color = "#[H.hair_color]"
if(FACEHAIR)
accessory_overlay.color = "#[H.facial_hair_color]"
if(EYECOLOR)
accessory_overlay.color = "#[H.eye_color]"
else
accessory_overlay.color = forced_colour
standing += accessory_overlay
if(S.hasinner)
var/mutable_appearance/inner_accessory_overlay = mutable_appearance(S.icon, layer = -layer)
if(S.gender_specific)
inner_accessory_overlay.icon_state = "[g]_[bodypart]inner_[S.icon_state]_[layertext]"
else
inner_accessory_overlay.icon_state = "m_[bodypart]inner_[S.icon_state]_[layertext]"
if(S.center)
inner_accessory_overlay = center_image(inner_accessory_overlay, S.dimension_x, S.dimension_y)
standing += inner_accessory_overlay
H.overlays_standing[layer] = standing.Copy()
standing = list()
H.apply_overlay(BODY_BEHIND_LAYER)
H.apply_overlay(BODY_ADJ_LAYER)
H.apply_overlay(BODY_FRONT_LAYER)
//This exists so sprite accessories can still be per-layer without having to include that layer's
//number in their sprite name, which causes issues when those numbers change.
/datum/species/proc/mutant_bodyparts_layertext(layer)
switch(layer)
if(BODY_BEHIND_LAYER)
return "BEHIND"
if(BODY_ADJ_LAYER)
return "ADJ"
if(BODY_FRONT_LAYER)
return "FRONT"
/datum/species/proc/spec_life(mob/living/carbon/human/H)
if(HAS_TRAIT(H, TRAIT_NOBREATH))
H.setOxyLoss(0)
H.losebreath = 0
var/takes_crit_damage = (!HAS_TRAIT(H, TRAIT_NOCRITDAMAGE))
if((H.health < H.crit_threshold) && takes_crit_damage)
H.adjustBruteLoss(1)
if(flying_species)
HandleFlight(H)
//I wag in death
/datum/species/proc/spec_death(gibbed, mob/living/carbon/human/H)
stop_wagging_tail(H)
return
//Now checks if the item is already equipped to that slot before instantly returning false because of it being there, so you can now check if an item is able to remain in a slot
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE)
if((slot in no_equip) || (slot in extra_no_equip))
if(!I.species_exception || !is_type_in_list(src, I.species_exception))
return FALSE
var/num_arms = H.get_num_arms(FALSE)
var/num_legs = H.get_num_legs(FALSE)
switch(slot)
if(SLOT_HANDS)
if(H.get_empty_held_indexes())
return TRUE
return FALSE
if(SLOT_WEAR_MASK)
if(H.wear_mask && H.wear_mask != I)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_MASK))
return FALSE
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_NECK)
if(H.wear_neck && H.wear_neck != I)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_NECK) )
return FALSE
return TRUE
if(SLOT_BACK)
if(H.back && H.back != I)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_BACK) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_WEAR_SUIT)
if(H.wear_suit && H.wear_suit != I)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_OCLOTHING) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_GLOVES)
if(H.gloves && H.gloves != I)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_GLOVES) )
return FALSE
if(num_arms < 2)
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_SHOES)
if(H.shoes && H.shoes != I)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_FEET) )
return FALSE
if(num_legs < 2)
return FALSE
var/obj/item/clothing/shoes/S = I
if(istype(S) && ((!S && (DIGITIGRADE in species_traits)) || ((DIGITIGRADE in species_traits) ? S.xenoshoe == NO_DIGIT : S.xenoshoe == YES_DIGIT))) // Checks leg compatibilty with shoe digitigrade or not flag
if(!disable_warning)
to_chat(H, span_warning("This footwear isn't compatible with your feet!"))
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_BELT)
if(H.belt && H.belt != I)
return FALSE
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!"))
return FALSE
if(!(I.slot_flags & ITEM_SLOT_BELT))
return
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_GLASSES)
if(H.glasses && H.glasses != I)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_EYES))
return FALSE
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES)
if(E?.no_glasses)
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_HEAD)
if(H.head && H.head != I)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_HEAD))
return FALSE
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_EARS)
if(H.ears && H.ears != I)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_EARS))
return FALSE
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_W_UNIFORM)
if(H.w_uniform && H.w_uniform != I)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_ICLOTHING) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_WEAR_ID)
if(H.wear_id && H.wear_id != I)
return FALSE
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!"))
return FALSE
if( !(I.slot_flags & ITEM_SLOT_ID) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(SLOT_L_STORE)
if(HAS_TRAIT(I, TRAIT_NODROP)) //Pockets aren't visible, so you can't move TRAIT_NODROP items into them.
return FALSE
if(H.l_store && H.l_store != I)
return FALSE
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_L_LEG)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!"))
return FALSE
if(I.slot_flags & ITEM_SLOT_DENYPOCKET)
return FALSE
if( I.w_class <= WEIGHT_CLASS_SMALL || (I.slot_flags & ITEM_SLOT_POCKET) )
return TRUE
if(SLOT_R_STORE)
if(HAS_TRAIT(I, TRAIT_NODROP))
return FALSE
if(H.r_store && H.r_store != I)
return FALSE
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_R_LEG)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!"))
return FALSE
if(I.slot_flags & ITEM_SLOT_DENYPOCKET)
return FALSE
if( I.w_class <= WEIGHT_CLASS_SMALL || (I.slot_flags & ITEM_SLOT_POCKET) )
return TRUE
return FALSE
if(SLOT_S_STORE)
if(HAS_TRAIT(I, TRAIT_NODROP))
return FALSE
if(H.s_store && H.s_store != I)
return FALSE
if(!H.wear_suit)
if(!disable_warning)
to_chat(H, span_warning("You need a suit before you can attach this [I.name]!"))
return FALSE
if(!H.wear_suit.allowed)
if(!disable_warning)
to_chat(H, "You somehow have a suit with no defined allowed items for suit storage, stop that.")
return FALSE
if(I.slot_flags & ITEM_SLOT_DENY_S_STORE)
return FALSE
if(I.w_class > WEIGHT_CLASS_BULKY)
if(!disable_warning)
to_chat(H, "The [I.name] is too big to attach.") //should be src?
return FALSE
if( istype(I, /obj/item/pda) || istype(I, /obj/item/pen) || is_type_in_list(I, H.wear_suit.allowed) )
return TRUE
return FALSE
if(SLOT_HANDCUFFED)
if(H.handcuffed && H.handcuffed != I)
return FALSE
if(!istype(I, /obj/item/restraints/handcuffs))
return FALSE
if(num_arms < 2)
return FALSE
return TRUE
if(SLOT_LEGCUFFED)
if(H.legcuffed && H.legcuffed != I)
return FALSE
if(!istype(I, /obj/item/restraints/legcuffs))
return FALSE
if(num_legs < 2)
return FALSE
return TRUE
if(SLOT_IN_BACKPACK)
if(H.back && H.back != I)
if(SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_CAN_INSERT, I, H, TRUE))
return TRUE
return FALSE
return FALSE //Unsupported slot
/datum/species/proc/equip_delay_self_check(obj/item/I, mob/living/carbon/human/H, bypass_equip_delay_self)
if(!I.equip_delay_self || bypass_equip_delay_self)
return TRUE
H.visible_message(span_notice("[H] start putting on [I]..."), span_notice("You start putting on [I]..."))
return do_after(H, I.equip_delay_self, H)
/datum/species/proc/before_equip_job(datum/job/J, mob/living/carbon/human/H)
return
/datum/species/proc/after_equip_job(datum/job/J, mob/living/carbon/human/H)
H.update_mutant_bodyparts()
// Do species-specific reagent handling here
// Return 1 if it should do normal processing too
// Return 0 if it shouldn't deplete and do its normal effect
// Other return values will cause weird badness
/datum/species/proc/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
if(chem.type == exotic_blood)
H.blood_volume = min(H.blood_volume + round(chem.volume, 0.1), BLOOD_VOLUME_MAXIMUM(H))
H.reagents.del_reagent(chem.type)
return TRUE
//This handles dumping unprocessable reagents.
var/dump_reagent = TRUE
if((chem.process_flags & SYNTHETIC) && (H.dna.species.reagent_tag & PROCESS_SYNTHETIC)) //SYNTHETIC-oriented reagents require PROCESS_SYNTHETIC
dump_reagent = FALSE
if((chem.process_flags & ORGANIC) && (H.dna.species.reagent_tag & PROCESS_ORGANIC)) //ORGANIC-oriented reagents require PROCESS_ORGANIC
dump_reagent = FALSE
if(dump_reagent)
chem.holder.remove_reagent(chem.type, chem.metabolization_rate)
return TRUE
return FALSE
/datum/species/proc/check_species_weakness(obj/item, mob/living/attacker)
return 0 //This is not a boolean, it's the multiplier for the damage that the user takes from the item.It is added onto the check_weakness value of the mob, and then the force of the item is multiplied by this value
////////
//LIFE//
////////
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
return //hunger is for BABIES
//The fucking TRAIT_FAT mutation is the dumbest shit ever. It makes the code so difficult to work with
if(HAS_TRAIT(H, TRAIT_FAT))//I share your pain, past coder.
if(H.overeatduration < 100)
to_chat(H, span_notice("You feel fit again!"))
REMOVE_TRAIT(H, TRAIT_FAT, OBESITY)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
else
if(H.overeatduration >= 100)
to_chat(H, span_danger("You suddenly feel blubbery!"))
ADD_TRAIT(H, TRAIT_FAT, OBESITY)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
// nutrition decrease and satiety
if (H.nutrition > 0 && H.stat != DEAD && !HAS_TRAIT(H, TRAIT_NOHUNGER))
// THEY HUNGER
var/hunger_rate = HUNGER_FACTOR
var/datum/component/mood/mood = H.GetComponent(/datum/component/mood)
if(mood && mood.sanity > SANITY_DISTURBED)
hunger_rate *= max(0.5, 1 - 0.002 * mood.sanity) //0.85 to 0.75
if(HAS_TRAIT(H, TRAIT_EAT_LESS))
hunger_rate *= 0.75 //hunger rate reduced by about 25%
if(HAS_TRAIT(H, TRAIT_EAT_MORE))
hunger_rate *= 3 //hunger rate tripled
if(HAS_TRAIT(H, TRAIT_BOTTOMLESS_STOMACH))
H.nutrition = min(H.nutrition, NUTRITION_LEVEL_MOSTLY_FULL) //capped, can never be truly full
// Whether we cap off our satiety or move it towards 0
if(H.satiety > MAX_SATIETY)
H.satiety = MAX_SATIETY
else if(H.satiety > 0)
H.satiety--
else if(H.satiety < -MAX_SATIETY)
H.satiety = -MAX_SATIETY
else if(H.satiety < 0)
H.satiety++
if(prob(round(-H.satiety/40)))
H.Jitter(5)
hunger_rate = 3 * HUNGER_FACTOR
hunger_rate *= H.physiology.hunger_mod
H.adjust_nutrition(-hunger_rate)
if (H.nutrition > NUTRITION_LEVEL_FULL)
if(H.overeatduration < 600) //capped so people don't take forever to unfat
H.overeatduration++
else
if(H.overeatduration > 1)
H.overeatduration -= 2 //doubled the unfat rate
//metabolism change
if(H.nutrition > NUTRITION_LEVEL_FAT)
H.metabolism_efficiency = 1
else if(H.nutrition > NUTRITION_LEVEL_FED && H.satiety > 80)
if(H.metabolism_efficiency != 1.25 && !HAS_TRAIT(H, TRAIT_NOHUNGER))
to_chat(H, span_notice("You feel vigorous."))
H.metabolism_efficiency = 1.25
else if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
if(H.metabolism_efficiency != 0.8)
to_chat(H, span_notice("You feel sluggish."))
H.metabolism_efficiency = 0.8
else
if(H.metabolism_efficiency == 1.25)
to_chat(H, span_notice("You no longer feel vigorous."))
H.metabolism_efficiency = 1
get_hunger_alert(H)
/datum/species/proc/get_hunger_alert(mob/living/carbon/human/H)
switch(H.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
H.throw_alert("nutrition", /atom/movable/screen/alert/fat)
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL)
H.clear_alert("nutrition")
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
H.throw_alert("nutrition", /atom/movable/screen/alert/hungry)
if(0 to NUTRITION_LEVEL_STARVING)
H.throw_alert("nutrition", /atom/movable/screen/alert/starving)
/datum/species/proc/update_health_hud(mob/living/carbon/human/H)
return 0
/datum/species/proc/handle_mutations_and_radiation(mob/living/carbon/human/H)
if(HAS_TRAIT(H, TRAIT_RADIMMUNE))
H.radiation = 0
return TRUE
. = FALSE
var/radiation = H.radiation
if(radiation > RAD_MOB_KNOCKDOWN && prob(RAD_MOB_KNOCKDOWN_PROB))
if(!H.IsParalyzed())
H.emote("collapse")
H.Paralyze(RAD_MOB_KNOCKDOWN_AMOUNT)
to_chat(H, span_danger("You feel weak."))
if(radiation > RAD_MOB_VOMIT && prob(RAD_MOB_VOMIT_PROB))
H.vomit(10, TRUE)
if(radiation > RAD_MOB_MUTATE)
if(prob(1))
to_chat(H, span_danger("You mutate!"))
H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
H.emote("gasp")
H.domutcheck()
if(radiation > RAD_MOB_HAIRLOSS)
if(prob(15) && !(H.hair_style == "Bald") && (HAIR in species_traits))
to_chat(H, span_danger("Your hair starts to fall out in clumps..."))
addtimer(CALLBACK(src, .proc/go_bald, H), 50)
/datum/species/proc/go_bald(mob/living/carbon/human/H)
if(QDELETED(H)) //may be called from a timer
return
H.facial_hair_style = "Shaved"
H.hair_style = "Bald"
H.update_hair()
////////////////
// MOVE SPEED //
////////////////
/datum/species/proc/movement_delay(mob/living/carbon/human/H)
. = 0 //We start at 0.
var/flight = 0 //Check for flight and flying items
var/gravity = 0
if(H.movement_type & FLYING)
flight = 1
gravity = H.has_gravity()
if(!HAS_TRAIT(H, TRAIT_IGNORESLOWDOWN) && gravity)
// Clothing slowdown
if(H.wear_suit)
. += H.wear_suit.slowdown
if(H.shoes)
. += H.shoes.slowdown
if(H.back)
. += H.back.slowdown
if(H.head)
. += H.head.slowdown
for(var/obj/item/I in H.held_items)
if(I.item_flags & SLOWS_WHILE_IN_HAND)
. += I.slowdown
if(!HAS_TRAIT(H, TRAIT_IGNOREDAMAGESLOWDOWN))
var/health_deficiency = max(H.maxHealth - H.health, min(H.staminaloss, H.maxHealth))
if(HAS_TRAIT(H, TRAIT_REDUCED_DAMAGE_SLOWDOWN))
health_deficiency -= H.maxHealth * 0.2 //20% more damage required for slowdown
if(health_deficiency >= H.maxHealth * 0.4)
if(HAS_TRAIT(H, TRAIT_RESISTDAMAGESLOWDOWN))
health_deficiency *= 0.5
if(flight)
health_deficiency *= 0.333
if(health_deficiency < 100) // https://i.imgur.com/W4nusN8.png https://www.desmos.com/calculator/qsf6iakqgp
. += (health_deficiency / 50) ** 2.58
else
. += (health_deficiency / 100) + 5
if(CONFIG_GET(flag/disable_human_mood) && !H.mood_enabled) // Yogs -- Mood as preference
if(!HAS_TRAIT(H, TRAIT_NOHUNGER))
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
if((hungry >= 70) && !flight) //Being hungry will still allow you to use a flightsuit/wings.
. += hungry / 50
else if(isethereal(H))
var/datum/species/ethereal/E = H.dna.species
var/charge = E.get_charge(H)
if(charge <= ETHEREAL_CHARGE_NORMAL)
. += 1.5 * (1 - charge / 100)
//Moving in high gravity is very slow (Flying too)
if(gravity > STANDARD_GRAVITY)
var/grav_force = min(gravity - STANDARD_GRAVITY,3)
. += 1 + grav_force
if(HAS_TRAIT(H, TRAIT_FAT))
. += (1.5 - flight)
if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTCOLD))
. += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR
return .
//////////////////
// ATTACK PROCS //
//////////////////
/datum/species/proc/spec_updatehealth(mob/living/carbon/human/H)
return
/datum/species/proc/spec_fully_heal(mob/living/carbon/human/H)
return
/datum/species/proc/spec_emp_act(mob/living/carbon/human/H, severity)
return
/datum/species/proc/spec_emag_act(mob/living/carbon/human/H, mob/user)
return
/datum/species/proc/spec_electrocute_act(mob/living/carbon/human/H, shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
return
/datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(!((target.health < 0 || HAS_TRAIT(target, TRAIT_FAKEDEATH)) && !(target.mobility_flags & MOBILITY_STAND)))
target.help_shake_act(user)
if(target != user)
log_combat(user, target, "shaken")
return 1
else
var/we_breathe = !HAS_TRAIT_FROM(user, TRAIT_NOBREATH, SPECIES_TRAIT)
var/we_lung = user.getorganslot(ORGAN_SLOT_LUNGS)
if(we_breathe && we_lung)
user.do_cpr(target)
else if(we_breathe && !we_lung)
to_chat(user, span_warning("You have no lungs to breathe with, so you cannot perform CPR."))
else
to_chat(user, span_notice("You do not breathe, so you cannot perform CPR."))
/datum/species/proc/grab(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
var/datum/martial_art/M = target.check_block()
if(user.pulledby && user.pulledby.grab_state >= GRAB_AGGRESSIVE)
return FALSE
if(M)
M.handle_counter(target, user)
return FALSE
if(attacker_style && attacker_style.grab_act(user,target))
return TRUE
else
target.grabbedby(user)
return TRUE
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(!attacker_style?.nonlethal && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, span_warning("You don't want to harm [target]!"))
return FALSE
var/datum/martial_art/M = target.check_block()
if(M)
M.handle_counter(target, user)
return FALSE
if(attacker_style && attacker_style.harm_act(user,target))
return TRUE
else
var/atk_verb = user.dna.species.attack_verb
if(!(target.mobility_flags & MOBILITY_STAND))
atk_verb = ATTACK_EFFECT_KICK
switch(atk_verb)//this code is really stupid but some genius apparently made "claw" and "slash" two attack types but also the same one so it's needed i guess
if(ATTACK_EFFECT_KICK)
user.do_attack_animation(target, ATTACK_EFFECT_KICK)
if(ATTACK_EFFECT_SLASH, ATTACK_EFFECT_CLAW)//smh
user.do_attack_animation(target, ATTACK_EFFECT_CLAW)
if(ATTACK_EFFECT_SMASH)
user.do_attack_animation(target, ATTACK_EFFECT_SMASH)
else
user.do_attack_animation(target, ATTACK_EFFECT_PUNCH)
var/damage = rand(user.get_punchdamagelow(), user.get_punchdamagehigh())
var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
if(user.get_punchdamagelow())
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
miss_chance = 0
else
miss_chance = min((user.get_punchdamagelow()/user.get_punchdamagehigh()) + user.getStaminaLoss() + (user.getBruteLoss()*0.5), 100) //old base chance for a miss + various damage. capped at 100 to prevent weirdness in prob()
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
playsound(target.loc, user.dna.species.miss_sound, 25, 1, -1)
target.visible_message(span_danger("[user] has attempted to [atk_verb] [target]!"),\
span_userdanger("[user] has attempted to [atk_verb] [target]!"), null, COMBAT_MESSAGE_RANGE)
log_combat(user, target, "attempted to punch")
return FALSE
var/armor_block = target.run_armor_check(affecting, MELEE)
playsound(target.loc, user.dna.species.attack_sound, 25, 1, -1)
target.visible_message(span_danger("[user] has [atk_verb]ed [target]!"), \
span_userdanger("[user] has [atk_verb]ed [target]!"), null, COMBAT_MESSAGE_RANGE)
target.lastattacker = user.real_name
target.lastattackerckey = user.ckey
user.dna.species.spec_unarmedattacked(user, target)
if(user.limb_destroyer)
target.dismembering_strike(user, affecting.body_zone)
var/attack_direction = get_dir(user, target)
if(atk_verb == ATTACK_EFFECT_KICK)//kicks deal 1.5x raw damage
target.apply_damage(damage*1.5, user.dna.species.attack_type, affecting, armor_block, attack_direction = attack_direction)
log_combat(user, target, "kicked")
else//other attacks deal full raw damage + 1.5x in stamina damage
target.apply_damage(damage, user.dna.species.attack_type, affecting, armor_block, attack_direction = attack_direction)
target.apply_damage(damage*1.5, STAMINA, affecting, armor_block)
log_combat(user, target, "punched")
if((target.stat != DEAD) && damage >= user.get_punchstunthreshold())
target.visible_message(span_danger("[user] has knocked [target] down!"), \
span_userdanger("[user] has knocked [target] down!"), null, COMBAT_MESSAGE_RANGE)
var/knockdown_duration = 40 + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 40 base stun + 40 stun modifier = 80 stun duration, which is the old base duration
target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block)
target.forcesay(GLOB.hit_appends)
log_combat(user, target, "got a stun punch with their previous punch")
else if(!(target.mobility_flags & MOBILITY_STAND))
target.forcesay(GLOB.hit_appends)
/datum/species/proc/spec_unarmedattacked(mob/living/carbon/human/user, mob/living/carbon/human/target)
return
/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(target.check_block())
target.visible_message(span_warning("[target] blocks [user]'s shoving attempt!"))
return FALSE
if(attacker_style && attacker_style.disarm_act(user,target))
return TRUE
if(user.resting || user.IsKnockdown())
return FALSE
if(user == target)
return FALSE
if(user.loc == target.loc)
return FALSE
if(user.pulledby && user.pulledby.grab_state >= GRAB_AGGRESSIVE)
return FALSE
else
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
if(target.w_uniform)
target.w_uniform.add_fingerprint(user)
var/randomized_zone = ran_zone(user.zone_selected)
SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone)
var/shove_dir = get_dir(user.loc, target.loc)
var/turf/target_shove_turf = get_step(target.loc, shove_dir)
var/mob/living/carbon/human/target_collateral_human
var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied
//Thank you based whoneedsspace
target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents
var/bothstanding = target_collateral_human && (target.mobility_flags & MOBILITY_STAND) && (target_collateral_human.mobility_flags & MOBILITY_STAND)
if(target_collateral_human && bothstanding)
shove_blocked = TRUE
else
target.Move(target_shove_turf, shove_dir)
if(get_turf(target) != target_shove_turf)
shove_blocked = TRUE
if(target.IsKnockdown() && !target.IsParalyzed())
var/armor_block = target.run_armor_check(affecting, MELEE, "Your armor prevents your fall!", "Your armor softens your fall!")
target.apply_effect(SHOVE_CHAIN_PARALYZE, EFFECT_PARALYZE, armor_block)
target.visible_message(span_danger("[user.name] kicks [target.name] onto their side!"),
span_danger("[user.name] kicks you onto your side!"), null, COMBAT_MESSAGE_RANGE)
var/reset_timer = SHOVE_CHAIN_PARALYZE * (100-armor_block)/100
addtimer(CALLBACK(target, /mob/living/proc/SetKnockdown, 0), reset_timer)
log_combat(user, target, "kicks", "onto their side (paralyzing)")
if(shove_blocked && !target.is_shove_knockdown_blocked() && !target.buckled)
var/directional_blocked = FALSE
if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that
var/target_turf = get_turf(target)
for(var/obj/O in target_turf)
if(O.flags_1 & ON_BORDER_1 && O.dir == shove_dir && O.density)
directional_blocked = TRUE
break
if(target_turf != target_shove_turf) //Make sure that we don't run the exact same check twice on the same tile
for(var/obj/O in target_shove_turf)
if(O.flags_1 & ON_BORDER_1 && O.dir == turn(shove_dir, 180) && O.density)
directional_blocked = TRUE
break
if(!bothstanding || directional_blocked)
var/obj/item/I = target.get_active_held_item()
if(target.dropItemToGround(I))
user.visible_message(span_danger("[user.name] shoves [target.name], disarming them!"),
span_danger("You shove [target.name], disarming them!"), null, COMBAT_MESSAGE_RANGE)
log_combat(user, target, "shoved", "disarming them")
else if(bothstanding)
target.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
if(!target_collateral_human.is_shove_knockdown_blocked())
target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
user.visible_message(span_danger("[user.name] shoves [target.name] into [target_collateral_human.name]!"),
span_danger("You shove [target.name] into [target_collateral_human.name]!"), null, COMBAT_MESSAGE_RANGE)
log_combat(user, target, "shoved", "into [target_collateral_human.name]")
else
user.visible_message(span_danger("[user.name] shoves [target.name]!"),
span_danger("You shove [target.name]!"), null, COMBAT_MESSAGE_RANGE)
var/target_held_item = target.get_active_held_item()
var/knocked_item = FALSE
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
target_held_item = null
if(!target.has_movespeed_modifier(MOVESPEED_ID_SHOVE))
target.add_movespeed_modifier(MOVESPEED_ID_SHOVE, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
if(target_held_item)
target.visible_message(span_danger("[target.name]'s grip on \the [target_held_item] loosens!"),
span_danger("Your grip on \the [target_held_item] loosens!"), null, COMBAT_MESSAGE_RANGE)
addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
else if(target_held_item)
target.dropItemToGround(target_held_item)
knocked_item = TRUE
target.visible_message(span_danger("[target.name] drops \the [target_held_item]!!"),
span_danger("You drop \the [target_held_item]!!"), null, COMBAT_MESSAGE_RANGE)
var/append_message = ""
if(target_held_item)
if(knocked_item)
append_message = "causing them to drop [target_held_item]"
else
append_message = "loosening their grip on [target_held_item]"
log_combat(user, target, "shoved", append_message)
/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
return
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
if(!istype(M))
return
CHECK_DNA_AND_SPECIES(M)
CHECK_DNA_AND_SPECIES(H)
if(!istype(M)) //sanity check for drones.
return
if(M.mind)
attacker_style = M.mind.martial_art
if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
if((M.dna.check_mutation(ACTIVE_HULK) || M.dna.check_mutation(HULK)) && M.a_intent == "disarm")
H.check_shields(0, M.name) // We check their shields twice since we are a hulk. Also triggers hitreactions for HULK_ATTACK
M.visible_message(span_danger("[M]'s punch knocks the shield out of [H]'s hand."), \
span_userdanger("[M]'s punch knocks the shield out of [H]'s hand."))
if(M.dna)
playsound(H.loc, M.dna.species.attack_sound, 25, 1, -1)
else
playsound(H.loc, 'sound/weapons/punch1.ogg', 25, 1, -1)
log_combat(M, H, "hulk punched a shield held by")
return FALSE
if(istype(attacker_style, /datum/martial_art/flyingfang) && M.a_intent == INTENT_DISARM)
disarm(M, H, attacker_style)
log_combat(M, H, "attempted to touch")
H.visible_message(span_warning("[M] attempted to touch [H]!"))
return 0
SEND_SIGNAL(M, COMSIG_MOB_ATTACK_HAND, M, H, attacker_style)
switch(M.a_intent)
if(INTENT_HELP)
help(M, H, attacker_style)
if(INTENT_GRAB)
grab(M, H, attacker_style)
if(INTENT_HARM)
harm(M, H, attacker_style)
if(INTENT_DISARM)
disarm(M, H, attacker_style)
/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
// Allows you to put in item-specific reactions based on species
if(user != H)
if(H.check_shields(I, I.force, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
return FALSE
var/datum/martial_art/M = H.check_block()
if(M)
M.handle_counter(H, user)
return FALSE
var/hit_area
if(!affecting) //Something went wrong. Maybe the limb is missing?
affecting = H.bodyparts[1]
hit_area = affecting.name
var/def_zone = affecting.body_zone
var/armor_block = H.run_armor_check(affecting, MELEE, span_notice("Your armor has protected your [hit_area]."), span_notice("Your armor has softened a hit to your [hit_area]."),I.armour_penetration)
armor_block = min(90,armor_block) //cap damage reduction at 90%
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
var/Iwound_bonus = I.wound_bonus
// this way, you can't wound with a surgical tool on help intent if they have a surgery active and are laying down, so a misclick with a circular saw on the wrong limb doesn't bleed them dry (they still get hit tho)
if((I.item_flags & SURGICAL_TOOL) && user.a_intent == INTENT_HELP && (H.mobility_flags & ~MOBILITY_STAND) && (LAZYLEN(H.surgeries) > 0))
Iwound_bonus = CANT_WOUND
var/weakness = H.check_weakness(I, user)
H.send_item_attack_message(I, user, hit_area, affecting)
var/attack_direction = get_dir(user, H)
apply_damage(I.force * weakness, I.damtype, def_zone, armor_block, H, wound_bonus = Iwound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.sharpness, attack_direction = attack_direction)
if(!I.force)
return FALSE //item force is zero
var/bloody = 0
if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2))))
if(affecting.status == BODYPART_ORGANIC)
I.add_mob_blood(H) //Make the weapon bloody, not the person.
if(prob(I.force * 2)) //blood spatter!
bloody = 1
var/turf/location = H.loc
if(istype(location))
H.add_splatter_floor(location)
if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood
user.add_mob_blood(H)
switch(hit_area)
if(BODY_ZONE_HEAD)
if(!I.is_sharp() && armor_block < 50)
if(prob(I.force))
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20)
if(H.stat == CONSCIOUS)
H.visible_message(span_danger("[H] has been knocked senseless!"), \
span_userdanger("[H] has been knocked senseless!"))
H.confused = max(H.confused, 20)
H.adjust_blurriness(10)
if(prob(10))
H.gain_trauma(/datum/brain_trauma/mild/concussion)
else
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, I.force * 0.2)
if(H.mind && H.stat == CONSCIOUS && H != user && prob(I.force + ((100 - H.health) * 0.5))) // rev deconversion through blunt trauma.
var/datum/antagonist/rev/rev = H.mind.has_antag_datum(/datum/antagonist/rev)
if(rev)
rev.remove_revolutionary(FALSE, user)
if(bloody) //Apply blood
if(H.wear_mask)
H.wear_mask.add_mob_blood(H)
H.update_inv_wear_mask()
if(H.head)
H.head.add_mob_blood(H)
H.update_inv_head()
if(H.glasses && prob(33))
H.glasses.add_mob_blood(H)
H.update_inv_glasses()
if(BODY_ZONE_CHEST)
if(H.stat == CONSCIOUS && !I.is_sharp() && armor_block < 50)
if(prob(I.force))
H.visible_message(span_danger("[H] has been knocked down!"), \
span_userdanger("[H] has been knocked down!"))
H.apply_effect(60, EFFECT_KNOCKDOWN, armor_block)
if(bloody)
if(H.wear_suit)
H.wear_suit.add_mob_blood(H)
H.update_inv_wear_suit()
if(H.w_uniform)
H.w_uniform.add_mob_blood(H)
H.update_inv_w_uniform()
if(Iforce > 10 || Iforce >= 5 && prob(33))
H.forcesay(GLOB.hit_appends) //forcesay checks stat already.
return TRUE
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE, attack_direction = null)
SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness, attack_direction) // make sure putting wound_bonus here doesn't screw up other signals or uses for this signal)
var/hit_percent = (100-(blocked+armor))/100
hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100
if(!damage || hit_percent <= 0)
return 0
var/obj/item/bodypart/BP = null
if(isbodypart(def_zone))
BP = def_zone
else
if(!def_zone)
def_zone = ran_zone(def_zone)
BP = H.get_bodypart(check_zone(def_zone))
if(!BP)
BP = H.bodyparts[1]
switch(damagetype)
if(BRUTE)
H.damageoverlaytemp = 20
if(BP)
if(BP.receive_damage(damage * hit_percent * brutemod * H.physiology.brute_mod, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction))
H.update_damage_overlays()
else//no bodypart, we deal damage with a more general method.
H.adjustBruteLoss(damage * hit_percent * brutemod * H.physiology.brute_mod)
if(BURN)
H.damageoverlaytemp = 20
if(BP)
if(BP.receive_damage(0, damage * hit_percent * burnmod * H.physiology.burn_mod, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction))
H.update_damage_overlays()
else
H.adjustFireLoss(damage * hit_percent * burnmod * H.physiology.burn_mod)
if(TOX)
H.adjustToxLoss(damage * hit_percent * toxmod * H.physiology.tox_mod)
if(OXY)
H.adjustOxyLoss(damage * hit_percent * oxymod * H.physiology.oxy_mod)
if(CLONE)
H.adjustCloneLoss(damage * hit_percent * clonemod * H.physiology.clone_mod)
if(STAMINA)
if(BP)
if(BP.receive_damage(0, 0, damage * staminamod * hit_percent * H.physiology.stamina_mod))
H.update_stamina()
else
H.adjustStaminaLoss(damage * hit_percent * H.physiology.stamina_mod)
if(BRAIN)
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage * hit_percent * H.physiology.brain_mod)
if(H.stat == DEAD && (H.mobility_flags & MOBILITY_STAND))
if(H.buckled && istype(H.buckled, /obj/structure))//prevent buckling corpses to chairs to make indestructible projectile walls
var/obj/structure/sitter = H.buckled
sitter.take_damage(damage, damagetype)
return 1
/datum/species/proc/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
// called when hit by a projectile
switch(P.type)
if(/obj/item/projectile/energy/floramut) // overwritten by plants/pods
H.show_message(span_notice("The radiation beam dissipates harmlessly through your body."))
if(/obj/item/projectile/energy/florayield)
H.show_message(span_notice("The radiation beam dissipates harmlessly through your body."))
/datum/species/proc/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
// called before a projectile hit
return 0
/////////////
//BREATHING//
/////////////
/datum/species/proc/breathe(mob/living/carbon/human/H)
if(HAS_TRAIT(H, TRAIT_NOBREATH))
return TRUE
/datum/species/proc/handle_environment(datum/gas_mixture/environment, mob/living/carbon/human/H)
if(!environment)
return
var/human_loc = H.loc
if(istype(human_loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
return
if(environment.get_moles(/datum/gas/water_vapor) > 10)//water vapour above a certain amount makes you wet
if(environment.get_moles(/datum/gas/water_vapor) > 40)//if there's a lot of water vapour, preterni ded
H.adjust_fire_stacks(-3)
else
H.adjust_fire_stacks(-2)
var/loc_temp = H.get_temperature(environment)
var/heat_capacity_factor = min(1, environment.heat_capacity() / environment.return_volume())
//Body temperature is adjusted in two parts: first there your body tries to naturally preserve homeostasis (shivering/sweating), then it reacts to the surrounding environment
//Thermal protection (insulation) has mixed benefits in two situations (hot in hot places, cold in hot places)
if(!H.on_fire) //If you're on fire, you do not heat up or cool down based on surrounding gases
var/natural = 0
if(H.stat != DEAD)
natural = H.natural_bodytemperature_stabilization()
var/thermal_protection = 1
if(loc_temp < H.bodytemperature) //Place is colder than we are
thermal_protection -= H.get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
thermal_protection *= heat_capacity_factor
if(ismovable(human_loc))
var/atom/movable/occupied_space = human_loc
thermal_protection *= (1 - occupied_space.contents_thermal_insulation)
if(!HAS_TRAIT(H, TRAIT_NO_PASSIVE_COOLING))
if(H.bodytemperature < BODYTEMP_NORMAL) //we're cold, insulation helps us retain body heat and will reduce the heat we lose to the environment
H.adjust_bodytemperature((thermal_protection+1)*natural + max(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX))
else //we're sweating, insulation hinders our ability to reduce heat - and it will reduce the amount of cooling you get from the environment
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + max((thermal_protection * (loc_temp - H.bodytemperature) + BODYTEMP_NORMAL - H.bodytemperature) / BODYTEMP_COLD_DIVISOR , BODYTEMP_COOLING_MAX)) //Extra calculation for hardsuits to bleed off heat
if (loc_temp > H.bodytemperature) //Place is hotter than we are
var/natural = 0
if(H.stat != DEAD)
natural = H.natural_bodytemperature_stabilization()
var/thermal_protection = 1
thermal_protection -= H.get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
thermal_protection *= heat_capacity_factor
if(ismovable(human_loc))
var/atom/movable/occupied_space = human_loc
thermal_protection *= (1 - occupied_space.contents_thermal_insulation)
if(!HAS_TRAIT(H, TRAIT_NO_PASSIVE_HEATING))
if(H.bodytemperature < BODYTEMP_NORMAL) //and we're cold, insulation enhances our ability to retain body heat but reduces the heat we get from the environment
H.adjust_bodytemperature((thermal_protection+1)*natural + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
else //we're sweating, insulation hinders out ability to reduce heat - but will reduce the amount of heat we get from the environment
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
// +/- 50 degrees from 310K is the 'safe' zone, where no damage is dealt.
if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTHEAT))
//Body temperature is too hot.
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "hot", /datum/mood_event/hot)
var/burn_damage
var/firemodifier = H.fire_stacks / 50
if (H.on_fire)
burn_damage = max(log(2-firemodifier,(H.bodytemperature-BODYTEMP_NORMAL))-5,0)
else
firemodifier = min(firemodifier, 0)
burn_damage = max(log(2-firemodifier,(H.bodytemperature-BODYTEMP_NORMAL))-5,0) // this can go below 5 at log 2.5
if (burn_damage)
switch(burn_damage)
if(0 to 2)
H.throw_alert("temp", /atom/movable/screen/alert/hot, 1)
if(2 to 4)
H.throw_alert("temp", /atom/movable/screen/alert/hot, 2)
else
H.throw_alert("temp", /atom/movable/screen/alert/hot, 3)
burn_damage = burn_damage * heatmod * H.physiology.heat_mod
if (H.stat < UNCONSCIOUS && (prob(burn_damage) * 10) / 4) //40% for level 3 damage on humans
H.emote("scream")
H.apply_damage(burn_damage, BURN)
else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTCOLD))
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold)
switch(H.bodytemperature)
if(200 to BODYTEMP_COLD_DAMAGE_LIMIT)
H.throw_alert("temp", /atom/movable/screen/alert/cold, 1)
H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod*H.physiology.cold_mod, BURN)
if(120 to 200)
H.throw_alert("temp", /atom/movable/screen/alert/cold, 2)
H.apply_damage(COLD_DAMAGE_LEVEL_2*coldmod*H.physiology.cold_mod, BURN)
else
H.throw_alert("temp", /atom/movable/screen/alert/cold, 3)
H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod*H.physiology.cold_mod, BURN)
else
H.clear_alert("temp")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
// Infrared luminosity, how far away can you pick up someone's heat with infrared (NOT THERMAL) vision
// 37C has 12 range (11 tiles)
// 20C has 7 range (6 tiles)
// 10C has 3 range (2 tiles)
// 0C has 0 range (0 tiles)
H.infra_luminosity = round(max((H.bodytemperature - T0C)/3, 0))
var/pressure = environment.return_pressure()
var/adjusted_pressure = H.calculate_affecting_pressure(pressure) //Returns how much pressure actually affects the mob.
switch(adjusted_pressure)
if(HAZARD_HIGH_PRESSURE to INFINITY)
if(!HAS_TRAIT(H, TRAIT_RESISTHIGHPRESSURE))
H.adjustBruteLoss(min(((adjusted_pressure / HAZARD_HIGH_PRESSURE) -1 ) * PRESSURE_DAMAGE_COEFFICIENT, MAX_HIGH_PRESSURE_DAMAGE) * H.physiology.pressure_mod)
H.throw_alert("pressure", /atom/movable/screen/alert/highpressure, 2)
else
H.clear_alert("pressure")
if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE)
H.throw_alert("pressure", /atom/movable/screen/alert/highpressure, 1)
if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE)
H.clear_alert("pressure")
if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE)
H.throw_alert("pressure", /atom/movable/screen/alert/lowpressure, 1)
else
if(HAS_TRAIT(H, TRAIT_RESISTLOWPRESSURE))
H.clear_alert("pressure")
else
H.adjustBruteLoss(LOW_PRESSURE_DAMAGE * H.physiology.pressure_mod)
H.throw_alert("pressure", /atom/movable/screen/alert/lowpressure, 2)
//////////
// FIRE //
//////////
/datum/species/proc/handle_fire(mob/living/carbon/human/H, no_protection = FALSE)
if(!CanIgniteMob(H))
return TRUE
if(H.on_fire)
//the fire tries to damage the exposed clothes and items
var/list/burning_items = list()
var/list/obscured = H.check_obscured_slots(TRUE)
//HEAD//
if(H.glasses && !(SLOT_GLASSES in obscured))
burning_items += H.glasses
if(H.wear_mask && !(SLOT_WEAR_MASK in obscured))
burning_items += H.wear_mask
if(H.wear_neck && !(SLOT_NECK in obscured))
burning_items += H.wear_neck
if(H.ears && !(SLOT_EARS in obscured))
burning_items += H.ears
if(H.head)
burning_items += H.head
//CHEST//
if(H.w_uniform && !(SLOT_W_UNIFORM in obscured))
burning_items += H.w_uniform
if(H.wear_suit)
burning_items += H.wear_suit
//ARMS & HANDS//
var/obj/item/clothing/arm_clothes = null
if(H.gloves && !(SLOT_GLOVES in obscured))
arm_clothes = H.gloves
else if(H.wear_suit && ((H.wear_suit.body_parts_covered & HANDS) || (H.wear_suit.body_parts_covered & ARMS)))
arm_clothes = H.wear_suit
else if(H.w_uniform && ((H.w_uniform.body_parts_covered & HANDS) || (H.w_uniform.body_parts_covered & ARMS)))
arm_clothes = H.w_uniform
if(arm_clothes)
burning_items |= arm_clothes
//LEGS & FEET//
var/obj/item/clothing/leg_clothes = null
if(H.shoes && !(SLOT_SHOES in obscured))
leg_clothes = H.shoes
else if(H.wear_suit && ((H.wear_suit.body_parts_covered & FEET) || (H.wear_suit.body_parts_covered & LEGS)))
leg_clothes = H.wear_suit
else if(H.w_uniform && ((H.w_uniform.body_parts_covered & FEET) || (H.w_uniform.body_parts_covered & LEGS)))
leg_clothes = H.w_uniform
if(leg_clothes)
burning_items |= leg_clothes
for(var/X in burning_items)
var/obj/item/I = X
I.fire_act((H.fire_stacks * 50)) //damage taken is reduced to 2% of this value by fire_act()
var/thermal_protection = H.get_thermal_protection()
if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT && !no_protection)
return
if(thermal_protection >= FIRE_SUIT_MAX_TEMP_PROTECT && !no_protection)
H.adjust_bodytemperature(11)
else
H.adjust_bodytemperature(BODYTEMP_HEATING_MAX + (H.fire_stacks * 2))
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "on_fire", /datum/mood_event/on_fire)
/datum/species/proc/CanIgniteMob(mob/living/carbon/human/H)
if(HAS_TRAIT(H, TRAIT_NOFIRE))
return FALSE
return TRUE
/datum/species/proc/ExtinguishMob(mob/living/carbon/human/H)
return
/datum/species/proc/spec_revival(mob/living/carbon/human/H, admin_revive = FALSE)
return
////////////
// Stun //
////////////
/datum/species/proc/spec_stun(mob/living/carbon/human/H,amount)
if(!HAS_TRAIT(H, TRAIT_STUNIMMUNE))
if(flying_species && H.movement_type & FLYING)
ToggleFlight(H)
flyslip(H)
stop_wagging_tail(H)
return stunmod * H.physiology.stun_mod * amount
//////////////
//Space Move//
//////////////
/datum/species/proc/space_move(mob/living/carbon/human/H)
if(H.movement_type & FLYING)
return TRUE
return FALSE
/datum/species/proc/negates_gravity(mob/living/carbon/human/H)
if(H.movement_type & FLYING)
return TRUE
return FALSE
/datum/species/proc/has_heavy_gravity(mob/living/carbon/human/H)
return FALSE
////////////////
//Tail Wagging//
////////////////
/datum/species/proc/can_wag_tail(mob/living/carbon/human/H)
if(H.IsParalyzed() || H.IsStun())
return FALSE
// var/obj/item/organ/tail = H.getorganslot(ORGAN_SLOT_TAIL)
return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts) || ("tail_lizard" in mutant_bodyparts) || ("waggingtail_lizard" in mutant_bodyparts)
/datum/species/proc/is_wagging_tail(mob/living/carbon/human/H)
return ("waggingtail_human" in mutant_bodyparts) || ("waggingtail_lizard" in mutant_bodyparts)
/datum/species/proc/start_wagging_tail(mob/living/carbon/human/H)
if("tail_human" in mutant_bodyparts)
mutant_bodyparts -= "tail_human"
mutant_bodyparts |= "waggingtail_human"
if("tail_lizard" in mutant_bodyparts)
mutant_bodyparts -= "tail_lizard"
mutant_bodyparts -= "spines"
mutant_bodyparts |= "waggingtail_lizard"
mutant_bodyparts |= "waggingspines"
H.update_body()
/datum/species/proc/stop_wagging_tail(mob/living/carbon/human/H)
if("waggingtail_human" in mutant_bodyparts)
mutant_bodyparts -= "waggingtail_human"
mutant_bodyparts |= "tail_human"
if("waggingtail_lizard" in mutant_bodyparts)
mutant_bodyparts -= "waggingtail_lizard"
mutant_bodyparts -= "waggingspines"
mutant_bodyparts |= "tail_lizard"
mutant_bodyparts |= "spines"
H.update_body()
///////////////
//FLIGHT SHIT//
///////////////
/datum/species/proc/GiveSpeciesFlight(mob/living/carbon/human/H)
if(flying_species) //species that already have flying traits should not work with this proc
return
flying_species = TRUE
if(isnull(fly))
fly = new
fly.Grant(H)
if(ismoth(H)) //mothpeople don't grow new wings, they already have theirs
return
if(H.dna.features["wings"] != wings_icon)
mutant_bodyparts |= "wings"
H.dna.features["wings"] = wings_icon
if(wings_detail && H.dna.features["wingsdetail"] != wings_detail)
mutant_bodyparts |= "wingsdetail"
H.dna.features["wingsdetail"] = wings_detail
H.update_body()
/datum/species/proc/HandleFlight(mob/living/carbon/human/H)
if(H.movement_type & FLYING)
if(!CanFly(H))
ToggleFlight(H)
return FALSE
return TRUE
else
return FALSE
/datum/species/proc/CanFly(mob/living/carbon/human/H)
if(H.stat || !(H.mobility_flags & MOBILITY_STAND))
return FALSE
if(ismoth(H) && H.dna.features["moth_wings"] == "Burnt Off") //this is so tragic can we get an "F" in the chat
to_chat(H, "<span>Your crispy wings won't work anymore!</span>")
return FALSE
if(H.wear_suit && ((H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))) //Jumpsuits have tail holes, so it makes sense they have wing holes too
to_chat(H, "Your suit blocks your wings from extending!")
return FALSE
if(isskeleton(H))
to_chat(H, "Your wings are just bones; You can't actually fly!")
return FALSE
var/turf/T = get_turf(H)
if(!T)
return FALSE
var/datum/gas_mixture/environment = T.return_air()
if(environment && !(environment.return_pressure() > 30))
to_chat(H, span_warning("The atmosphere is too thin for you to fly!"))
return FALSE
else
return TRUE
/datum/species/proc/flyslip(mob/living/carbon/human/H)
var/obj/buckled_obj
if(H.buckled)
buckled_obj = H.buckled
to_chat(H, span_notice("Your wings spazz out and launch you!"))
playsound(H.loc, 'sound/misc/slip.ogg', 50, TRUE, -3)
for(var/obj/item/I in H.held_items)
H.accident(I)
var/olddir = H.dir
H.stop_pulling()
if(buckled_obj)
buckled_obj.unbuckle_mob(H)
step(buckled_obj, olddir)
else
new /datum/forced_movement(H, get_ranged_target_turf(H, olddir, 4), 1, FALSE, CALLBACK(H, /mob/living/carbon/.proc/spin, 1, 1))
return TRUE
//UNSAFE PROC, should only be called through the Activate or other sources that check for CanFly
/datum/species/proc/ToggleFlight(mob/living/carbon/human/H)
if(!(H.movement_type & FLYING))
stunmod *= 2
speedmod -= 0.35
H.setMovetype(H.movement_type | FLYING)
override_float = TRUE
H.pass_flags |= PASSTABLE
H.OpenWings()
H.update_mobility()
else
stunmod *= 0.5
speedmod += 0.35
H.setMovetype(H.movement_type & ~FLYING)
override_float = FALSE
H.pass_flags &= ~PASSTABLE
H.CloseWings()
/datum/action/innate/flight
name = "Toggle Flight"
check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_STUN
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "flight"
/datum/action/innate/flight/Activate()
var/mob/living/carbon/human/H = owner
var/datum/species/S = H.dna.species
if(S.CanFly(H))
S.ToggleFlight(H)
if(!(H.movement_type & FLYING))
to_chat(H, span_notice("You settle gently back onto the ground..."))
else
to_chat(H, span_notice("You beat your wings and begin to hover gently above the ground..."))
H.set_resting(FALSE, TRUE)
/**
* The human species version of [/mob/living/carbon/proc/get_biological_state]. Depends on the HAS_FLESH and HAS_BONE species traits, having bones lets you have bone wounds, having flesh lets you have burn, slash, and piercing wounds
*/
/datum/species/proc/get_biological_state(mob/living/carbon/human/H)
. = BIO_INORGANIC
if(HAS_FLESH in species_traits)
. |= BIO_JUST_FLESH
if(HAS_BONE in species_traits)
. |= BIO_JUST_BONE
/datum/species/proc/get_scream_sound(mob/living/carbon/human/H)
if(islist(screamsound))
return pick(screamsound)
return screamsound
/datum/species/proc/eat_text(fullness, eatverb, obj/O, mob/living/carbon/C, mob/user)
. = TRUE
if(C == user)
if(fullness <= 50)
user.visible_message(span_notice("[user] frantically [eatverb]s \the [O], scarfing it down!"), span_notice("You frantically [eatverb] \the [O], scarfing it down!"))
else if((fullness > 50 && fullness < 150) || HAS_TRAIT(C, TRAIT_BOTTOMLESS_STOMACH))
user.visible_message(span_notice("[user] hungrily [eatverb]s \the [O]."), span_notice("You hungrily [eatverb] \the [O]."))
else if(fullness > 150 && fullness < 500)
user.visible_message(span_notice("[user] [eatverb]s \the [O]."), span_notice("You [eatverb] \the [O]."))
else if(fullness > 500 && fullness < 600)
user.visible_message(span_notice("[user] unwillingly [eatverb]s a bit of \the [O]."), span_notice("You unwillingly [eatverb] a bit of \the [O]."))
else if(fullness > (600 * (1 + C.overeatduration / 2000))) // The more you eat - the more you can eat
user.visible_message(span_warning("[user] cannot force any more of \the [O] to go down [user.p_their()] throat!"), span_warning("You cannot force any more of \the [O] to go down your throat!"))
return FALSE
else
C.visible_message(span_danger("[user] forces [C] to eat [O]."), \
span_userdanger("[user] forces [C] to eat [O]."))
/datum/species/proc/force_eat_text(fullness, obj/O, mob/living/carbon/C, mob/user)
. = TRUE
if(fullness <= (600 * (1 + C.overeatduration / 1000)))
C.visible_message(span_danger("[user] attempts to feed [C] [O]."), \
span_userdanger("[user] attempts to feed [C] [O]."))
else
C.visible_message(span_warning("[user] cannot force any more of [O] down [C]'s throat!"), \
span_warning("[user] cannot force any more of [O] down [C]'s throat!"))
return FALSE
/datum/species/proc/drink_text(obj/O, mob/living/carbon/C, mob/user)
. = TRUE
if(C == user)
user.visible_message(span_notice("[user] swallows a gulp of [O]."), span_notice("You swallow a gulp of [O]."))
else
C.visible_message(span_danger("[user] feeds the contents of [O] to [C]."), span_userdanger("[user] feeds the contents of [O] to [C]."))
/datum/species/proc/force_drink_text(obj/O, mob/living/carbon/C, mob/user)
. = TRUE
C.visible_message(span_danger("[user] attempts to feed the contents of [O] to [C]."), span_userdanger("[user] attempts to feed the contents of [O] to [C]."))
/datum/species/proc/get_types_to_preload()
var/list/to_store = list()
to_store += mutant_organs
//Don't preload brains, cause reuse becomes a horrible headache
to_store += mutantheart
to_store += mutantlungs
to_store += mutanteyes
to_store += mutantears
to_store += mutanttongue
to_store += mutantliver
to_store += mutantstomach
to_store += mutantappendix
to_store += mutanttail
//We don't cache mutant hands because it's not constrained enough, too high a potential for failure
return to_store
/// Returns a list of strings representing features this species has.
/// Used by the preferences UI to know what buttons to show.
/datum/species/proc/get_features()
var/cached_features = GLOB.features_by_species[type]
if (!isnull(cached_features))
return cached_features
var/list/features = list()
for (var/preference_type in GLOB.preference_entries)
var/datum/preference/preference = GLOB.preference_entries[preference_type]
if ( \
(preference.relevant_mutant_bodypart in mutant_bodyparts) \
|| (preference.relevant_species_trait in species_traits) \
)
features += preference.savefile_key
/*for (var/obj/item/organ/external/organ_type as anything in external_organs)
var/preference = initial(organ_type.preference)
if (!isnull(preference))
features += preference*/
GLOB.features_by_species[type] = features
return features
/// Given a human, will adjust it before taking a picture for the preferences UI.
/// This should create a CONSISTENT result, so the icons don't randomly change.
/datum/species/proc/prepare_human_for_preview(mob/living/carbon/human/human)
return
/**
* Gets a short description for the specices. Should be relatively succinct.
* Used in the preference menu.
*
* Returns a string.
*/
/datum/species/proc/get_species_description()
SHOULD_CALL_PARENT(FALSE)
stack_trace("Species [name] ([type]) did not have a description set, and is a selectable roundstart race! Override get_species_description.")
return "No species description set, file a bug report!"
/**
* Gets the lore behind the type of species. Can be long.
* Used in the preference menu.
*
* Returns a list of strings.
* Between each entry in the list, a newline will be inserted, for formatting.
*/
/datum/species/proc/get_species_lore()
SHOULD_CALL_PARENT(FALSE)
RETURN_TYPE(/list)
stack_trace("Species [name] ([type]) did not have lore set, and is a selectable roundstart race! Override get_species_lore.")
return list("No species lore set, file a bug report!")
/**
* Translate the species liked foods from bitfields into strings
* and returns it in the form of an associated list.
*
* Returns a list, or null if they have no diet.
*/
/datum/species/proc/get_species_diet()
if(TRAIT_NOHUNGER in inherent_traits)
return null
var/list/food_flags = FOOD_FLAGS
return list(
"liked_food" = bitfield_to_list(liked_food, food_flags),
"disliked_food" = bitfield_to_list(disliked_food, food_flags),
"toxic_food" = bitfield_to_list(toxic_food, food_flags),
)
/**
* Generates a list of "perks" related to this species
* (Postives, neutrals, and negatives)
* in the format of a list of lists.
* Used in the preference menu.
*
* "Perk" format is as followed:
* list(
* SPECIES_PERK_TYPE = type of perk (postiive, negative, neutral - use the defines)
* SPECIES_PERK_ICON = icon shown within the UI
* SPECIES_PERK_NAME = name of the perk on hover
* SPECIES_PERK_DESC = description of the perk on hover
* )
*
* Returns a list of lists.
* The outer list is an assoc list of [perk type]s to a list of perks.
* The innter list is a list of perks. Can be empty, but won't be null.
*/
/datum/species/proc/get_species_perks()
var/list/species_perks = list()
// Let us get every perk we can concieve of in one big list.
// The order these are called (kind of) matters.
// Species unique perks first, as they're more important than genetic perks,
// and language perk last, as it comes at the end of the perks list
species_perks += create_pref_unique_perks()
species_perks += create_pref_blood_perks()
species_perks += create_pref_combat_perks()
species_perks += create_pref_damage_perks()
species_perks += create_pref_temperature_perks()
species_perks += create_pref_traits_perks()
species_perks += create_pref_biotypes_perks()
species_perks += create_pref_language_perk()
// Some overrides may return `null`, prevent those from jamming up the list.
listclearnulls(species_perks)
// Now let's sort them out for cleanliness and sanity
var/list/perks_to_return = list(
SPECIES_POSITIVE_PERK = list(),
SPECIES_NEUTRAL_PERK = list(),
SPECIES_NEGATIVE_PERK = list(),
)
for(var/list/perk as anything in species_perks)
var/perk_type = perk[SPECIES_PERK_TYPE]
// If we find a perk that isn't postiive, negative, or neutral,
// it's a bad entry - don't add it to our list. Throw a stack trace and skip it instead.
if(isnull(perks_to_return[perk_type]))
stack_trace("Invalid species perk ([perk[SPECIES_PERK_NAME]]) found for species [name]. \
The type should be positive, negative, or neutral. (Got: [perk_type])")
continue
perks_to_return[perk_type] += list(perk)
return perks_to_return
/**
* Used to add any species specific perks to the perk list.
*
* Returns null by default. When overriding, return a list of perks.
*/
/datum/species/proc/create_pref_unique_perks()
return null
/**
* Adds adds any perks related to combat.
* For example, the damage type of their punches.
*
* Returns a list containing perks, or an empty list.
*/
/datum/species/proc/create_pref_combat_perks()
var/list/to_add = list()
if(attack_type != BRUTE)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK,
SPECIES_PERK_ICON = "fist-raised",
SPECIES_PERK_NAME = "Elemental Attacker",
SPECIES_PERK_DESC = "[plural_form] deal [attack_type] damage with their punches instead of brute.",
))
return to_add
/**
* Adds adds any perks related to sustaining damage.
* For example, brute damage vulnerability, or fire damage resistance.
*
* Returns a list containing perks, or an empty list.
*/
/datum/species/proc/create_pref_damage_perks()
var/list/to_add = list()
// Brute related
if(brutemod > 1)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
SPECIES_PERK_ICON = "band-aid",
SPECIES_PERK_NAME = "Brutal Weakness",
SPECIES_PERK_DESC = "[plural_form] are weak to brute damage.",
))
if(brutemod < 1)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "shield-alt",
SPECIES_PERK_NAME = "Brutal Resilience",
SPECIES_PERK_DESC = "[plural_form] are resilient to bruising and brute damage.",
))
// Burn related
if(burnmod > 1)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
SPECIES_PERK_ICON = "burn",
SPECIES_PERK_NAME = "Fire Weakness",
SPECIES_PERK_DESC = "[plural_form] are weak to fire and burn damage.",
))
if(burnmod < 1)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "shield-alt",
SPECIES_PERK_NAME = "Fire Resilience",
SPECIES_PERK_DESC = "[plural_form] are resilient to flames, and burn damage.",
))
// Shock damage
if(siemens_coeff > 1)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
SPECIES_PERK_ICON = "bolt",
SPECIES_PERK_NAME = "Shock Vulnerability",
SPECIES_PERK_DESC = "[plural_form] are vulnerable to being shocked.",
))
if(siemens_coeff < 1)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "shield-alt",
SPECIES_PERK_NAME = "Shock Resilience",
SPECIES_PERK_DESC = "[plural_form] are resilient to being shocked.",
))
return to_add
/**
* Adds adds any perks related to how the species deals with temperature.
*
* Returns a list containing perks, or an empty list.
*/
/datum/species/proc/create_pref_temperature_perks()
var/list/to_add = list()
// Hot temperature tolerance
if(heatmod > 1/* || bodytemp_heat_damage_limit < BODYTEMP_HEAT_DAMAGE_LIMIT*/)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
SPECIES_PERK_ICON = "temperature-high",
SPECIES_PERK_NAME = "Heat Vulnerability",
SPECIES_PERK_DESC = "[plural_form] are vulnerable to high temperatures.",
))
if(heatmod < 1/* || bodytemp_heat_damage_limit > BODYTEMP_HEAT_DAMAGE_LIMIT*/)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "thermometer-empty",
SPECIES_PERK_NAME = "Heat Resilience",
SPECIES_PERK_DESC = "[plural_form] are resilient to hotter environments.",
))
// Cold temperature tolerance
if(coldmod > 1/* || bodytemp_cold_damage_limit > BODYTEMP_COLD_DAMAGE_LIMIT*/)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
SPECIES_PERK_ICON = "temperature-low",
SPECIES_PERK_NAME = "Cold Vulnerability",
SPECIES_PERK_DESC = "[plural_form] are vulnerable to cold temperatures.",
))
if(coldmod < 1/* || bodytemp_cold_damage_limit < BODYTEMP_COLD_DAMAGE_LIMIT*/)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "thermometer-empty",
SPECIES_PERK_NAME = "Cold Resilience",
SPECIES_PERK_DESC = "[plural_form] are resilient to colder environments.",
))
return to_add
/**
* Adds adds any perks related to the species' blood (or lack thereof).
*
* Returns a list containing perks, or an empty list.
*/
/datum/species/proc/create_pref_blood_perks()
var/list/to_add = list()
// NOBLOOD takes priority by default
if(NOBLOOD in species_traits)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "tint-slash",
SPECIES_PERK_NAME = "Bloodletted",
SPECIES_PERK_DESC = "[plural_form] do not have blood.",
))
// Otherwise, check if their exotic blood is a valid typepath
else if(ispath(exotic_blood))
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK,
SPECIES_PERK_ICON = "tint",
SPECIES_PERK_NAME = initial(exotic_blood.name),
SPECIES_PERK_DESC = "[name] blood is [initial(exotic_blood.name)], which can make recieving medical treatment harder.",
))
// Otherwise otherwise, see if they have an exotic bloodtype set
else if(exotic_bloodtype)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK,
SPECIES_PERK_ICON = "tint",
SPECIES_PERK_NAME = "Exotic Blood",
SPECIES_PERK_DESC = "[plural_form] have \"[exotic_bloodtype]\" type blood, which can make recieving medical treatment harder.",
))
return to_add
/**
* Adds adds any perks related to the species' inherent_traits list.
*
* Returns a list containing perks, or an empty list.
*/
/datum/species/proc/create_pref_traits_perks()
var/list/to_add = list()
if(TRAIT_RADIMMUNE in inherent_traits)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "radiation",
SPECIES_PERK_NAME = "Radiation Immunity",
SPECIES_PERK_DESC = "[plural_form] are completely unaffected by radiation. However, this doesn't mean they can't be irradiated.",
))
if(TRAIT_LIMBATTACHMENT in inherent_traits)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "user-plus",
SPECIES_PERK_NAME = "Limbs Easily Reattached",
SPECIES_PERK_DESC = "[plural_form] limbs are easily readded, and as such do not \
require surgery to restore. Simply pick it up and pop it back in, champ!",
))
if(TRAIT_EASYDISMEMBER in inherent_traits)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
SPECIES_PERK_ICON = "user-times",
SPECIES_PERK_NAME = "Limbs Easily Dismembered",
SPECIES_PERK_DESC = "[plural_form] limbs are not secured well, and as such they are easily dismembered.",
))
if(TRAIT_EASILY_WOUNDED in inherent_traits)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
SPECIES_PERK_ICON = "user-times",
SPECIES_PERK_NAME = "Easily Wounded",
SPECIES_PERK_DESC = "[plural_form] skin is very weak and fragile. They are much easier to apply serious wounds to.",
))
if(TRAIT_TOXINLOVER in inherent_traits)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK,
SPECIES_PERK_ICON = "syringe",
SPECIES_PERK_NAME = "Toxins Lover",
SPECIES_PERK_DESC = "Toxins damage dealt to [plural_form] are reversed - healing toxins will instead cause harm, and \
causing toxins will instead cause healing. Be careful around purging chemicals!",
))
if(ROBOTIC_LIMBS in species_traits)//species traits is basically inherent traits
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK,
SPECIES_PERK_ICON = "fa-solid fa-gear",
SPECIES_PERK_NAME = "Robotic limbs",
SPECIES_PERK_DESC = "[plural_form] have limbs comprised entirely of metal and circuitry, this will make standard surgery ineffective. \
However, this gives [plural_form] the ability to do self-maintenance with just simple tools.",
))
return to_add
/**
* Adds adds any perks related to the species' inherent_biotypes flags.
*
* Returns a list containing perks, or an empty list.
*/
/datum/species/proc/create_pref_biotypes_perks()
var/list/to_add = list()
if(MOB_UNDEAD in inherent_biotypes)
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "skull",
SPECIES_PERK_NAME = "Undead",
SPECIES_PERK_DESC = "[plural_form] are of the undead! The undead do not have the need to eat or breathe, and \
most viruses will not be able to infect a walking corpse. Their worries mostly stop at remaining in one piece, really.",
))
return to_add
/**
* Adds in a language perk based on all the languages the species
* can speak by default (according to their language holder).
*
* Returns a list containing perks, or an empty list.
*/
/datum/species/proc/create_pref_language_perk()
var/list/to_add = list()
// Grab galactic common as a path, for comparisons
var/datum/language/common_language = /datum/language/common
// Now let's find all the languages they can speak that aren't common
var/list/bonus_languages = list()
var/datum/language_holder/temp_holder = new species_language_holder()
for(var/datum/language/language_type as anything in temp_holder.spoken_languages)
if(ispath(language_type, common_language))
continue
bonus_languages += initial(language_type.name)
// If we have any languages we can speak: create a perk for them all
if(length(bonus_languages))
to_add += list(list(
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "comment",
SPECIES_PERK_NAME = "Native Speaker",
SPECIES_PERK_DESC = "Alongside [initial(common_language.name)], [plural_form] gain the ability to speak [english_list(bonus_languages)].",
))
qdel(temp_holder)
return to_add