mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
* 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: commit414af05928Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 18 22:05:17 2023 -0500 Automatic changelog generation #17965 [ci skip] commit4dbd995239Author: 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) commit8f9f915f69Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 18 22:04:08 2023 -0500 Automatic changelog generation #17970 [ci skip] commit50ed5323a5Author: 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 commit9c4d0652dbAuthor: Changelogs <action@github.com> Date: Sat Feb 18 14:07:01 2023 +0000 Automatic changelog compile [ci skip] commit03aae8b4cfAuthor: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 18 01:58:51 2023 -0500 Automatic changelog generation #17934 [ci skip] commit2761924c1bAuthor: ynot01 <ynot000001@gmail.com> Date: Sat Feb 18 01:58:49 2023 -0500 pvp enabled (#17934) commitcfe754a9a5Author: Changelogs <action@github.com> Date: Sat Feb 18 06:10:32 2023 +0000 Automatic changelog compile [ci skip] commit491ba04913Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 17 18:08:00 2023 -0500 Automatic changelog generation #17949 [ci skip] commita65d885b53Author: 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> commit7a8a6689b6Author: Changelogs <action@github.com> Date: Fri Feb 17 22:17:32 2023 +0000 Automatic changelog compile [ci skip] commite43f06f61cAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 17 15:41:43 2023 -0500 Automatic changelog generation #17924 [ci skip] commita4229d8acbAuthor: 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> commitad64a89f0aAuthor: ktlwjec <122807629+ktlwjec0@users.noreply.github.com> Date: Fri Feb 17 18:04:42 2023 +0000 removes plate from greeneggsandham (#17883) commitb0c3ca40a8Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 17 10:59:34 2023 -0500 Automatic changelog generation #17969 [ci skip] commiteefceef5edAuthor: 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 commit4b75b528eeAuthor: Changelogs <action@github.com> Date: Fri Feb 17 14:07:57 2023 +0000 Automatic changelog compile [ci skip] commit0a5d72beafAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 17 01:56:41 2023 -0500 Automatic changelog generation #17880 [ci skip] commitf6ed8e4b0bAuthor: adamsong <adamsong@users.noreply.github.com> Date: Fri Feb 17 01:56:39 2023 -0500 Makes vote weight and preferred map actually work (#17880) commit22657a9023Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 17 01:50:20 2023 -0500 Automatic changelog generation #17901 [ci skip] commit783f444541Author: 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 commitb306a6f4c3Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 17 01:33:16 2023 -0500 Automatic changelog generation #17935 [ci skip] commit32cdd383e4Author: 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 commitd83cc04e94Author: Changelogs <action@github.com> Date: Fri Feb 17 06:11:59 2023 +0000 Automatic changelog compile [ci skip] commitb89713fa7cAuthor: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 22:40:04 2023 -0500 Automatic changelog generation #17861 [ci skip] commit818973e1e9Author: 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> commitaf417335c1Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 22:32:01 2023 -0500 Automatic changelog generation #17942 [ci skip] commit4e6037ec58Author: 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 commit2e52265500Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 20:08:21 2023 -0500 Automatic changelog generation #17917 [ci skip] commit6ebf0318d9Author: 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 commit7d664d3af5Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 20:06:53 2023 -0500 Automatic changelog generation #17918 [ci skip] commitdc8148dcb1Author: ynot01 <ynot000001@gmail.com> Date: Thu Feb 16 20:06:51 2023 -0500 Update roundend.dm (#17918) commita46d618224Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 20:06:21 2023 -0500 Automatic changelog generation #17928 [ci skip] commitf04bc81f0cAuthor: LazennG <58535870+LazennG@users.noreply.github.com> Date: Thu Feb 16 17:06:18 2023 -0800 Update kinetic_crusher.dm (#17928) commit18fa2ae7afAuthor: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 20:05:51 2023 -0500 Automatic changelog generation #17946 [ci skip] commit6857bacb76Author: SapphicOverload <93578146+SapphicOverload@users.noreply.github.com> Date: Thu Feb 16 20:05:48 2023 -0500 Update mousetrap.dm (#17946) commit1751af026cAuthor: Changelogs <action@github.com> Date: Thu Feb 16 22:17:07 2023 +0000 Automatic changelog compile [ci skip] commite005525535Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 12:19:45 2023 -0500 Automatic changelog generation #17922 [ci skip] commitbc8ae716abAuthor: Ling <lingbleed@gmail.com> Date: Thu Feb 16 18:19:42 2023 +0100 Fixes Atmos fire fighting backpack (#17922) commite04fc1b6a8Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 12:18:03 2023 -0500 Automatic changelog generation #17939 [ci skip] commit93daa6c361Author: 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 commit1ef9484767Author: Changelogs <action@github.com> Date: Thu Feb 16 14:09:56 2023 +0000 Automatic changelog compile [ci skip] commiteaff1fdb1bAuthor: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 05:52:39 2023 -0500 Automatic changelog generation #17936 [ci skip] commit3d42d664bcAuthor: 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 commit69ea8d6ca9Author: Changelogs <action@github.com> Date: Thu Feb 16 06:11:47 2023 +0000 Automatic changelog compile [ci skip] commit4e6a16b426Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 16 00:37:02 2023 -0500 Automatic changelog generation #17923 [ci skip] commit2a7da8c107Author: ynot01 <ynot000001@gmail.com> Date: Thu Feb 16 00:37:00 2023 -0500 fixes clown sect not healing (#17923) commit890bc91805Author: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 20:56:34 2023 -0500 Automatic changelog generation #17945 [ci skip] commitb2b39d3ed8Author: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com> Date: Wed Feb 15 20:56:32 2023 -0500 Update revolution.dm (#17945) commitec2cbd2c89Author: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 20:48:13 2023 -0500 Automatic changelog generation #17864 [ci skip] commitcd14d86ed6Author: 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 commitdf7f9bc020Author: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 20:47:28 2023 -0500 Automatic changelog generation #17870 [ci skip] commit232aa3fa55Author: ynot01 <ynot000001@gmail.com> Date: Wed Feb 15 20:47:26 2023 -0500 Update bloodsuckers.dm (#17870) commitd679caad3cAuthor: Changelogs <action@github.com> Date: Wed Feb 15 22:17:39 2023 +0000 Automatic changelog compile [ci skip] commit9678f1f65aAuthor: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 14:58:11 2023 -0500 Automatic changelog generation #17930 [ci skip] commit039792ea37Author: Byemoh <baiomurang@gmail.com> Date: Wed Feb 15 13:58:09 2023 -0600 NVS Gax Incinerator Expansion (#17930) commita0fe3e174cAuthor: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 11:04:14 2023 -0500 Automatic changelog generation #17941 [ci skip] commita263586d88Author: wejengin2 <48154165+wejengin2@users.noreply.github.com> Date: Wed Feb 15 17:04:08 2023 +0100 eee (#17941) commitf8b90faa17Author: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 10:11:12 2023 -0500 Automatic changelog generation #17721 [ci skip] commit1d22d7da18Author: 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 commit85de433d2dAuthor: Changelogs <action@github.com> Date: Wed Feb 15 14:08:21 2023 +0000 Automatic changelog compile [ci skip] commita8bd8c2280Author: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 07:32:49 2023 -0500 Automatic changelog generation #17916 [ci skip] commit3b587559a5Author: Molti <108117184+Moltijoe@users.noreply.github.com> Date: Wed Feb 15 06:32:46 2023 -0600 Who approved this (#17916) commit6828c4758dAuthor: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 06:58:56 2023 -0500 Automatic changelog generation #17914 [ci skip] commit3e3ab2b4d6Author: ktlwjec <122807629+ktlwjec0@users.noreply.github.com> Date: Wed Feb 15 11:58:53 2023 +0000 fixes processor recipes (#17914) commit601ce3f675Author: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 06:41:26 2023 -0500 Automatic changelog generation #17888 [ci skip] commitbf8867a331Author: Molti <108117184+Moltijoe@users.noreply.github.com> Date: Wed Feb 15 05:41:24 2023 -0600 no hardcritdamage (#17888) commite1a500ec62Author: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 05:28:58 2023 -0500 Automatic changelog generation #17781 [ci skip] commit874db73a73Author: ynot01 <ynot000001@gmail.com> Date: Wed Feb 15 05:28:55 2023 -0500 Revert commit64a6c3a(#17781) This reverts64a6c3ac21commit734d6ec0fcAuthor: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 15 05:28:03 2023 -0500 Automatic changelog generation #17772 [ci skip] commit30d564c8dcAuthor: 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 commite7542e1f55Author: Changelogs <action@github.com> Date: Wed Feb 15 06:11:58 2023 +0000 Automatic changelog compile [ci skip] commitb5ed98fe7cAuthor: Ling <lingbleed@gmail.com> Date: Wed Feb 15 02:18:53 2023 +0100 Fix crew monitor runtime (#17921) commit4c7b5535b6Author: Changelogs <action@github.com> Date: Tue Feb 14 14:08:13 2023 +0000 Automatic changelog compile [ci skip] commitcfb81a4b91Author: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 14 04:06:15 2023 -0500 Automatic changelog generation #17919 [ci skip] commit5268119ca6Author: ynot01 <ynot000001@gmail.com> Date: Tue Feb 14 04:06:12 2023 -0500 Update recharger.dm (#17919) commit06acbae28dAuthor: Changelogs <action@github.com> Date: Tue Feb 14 06:12:20 2023 +0000 Automatic changelog compile [ci skip] commit369dba9990Author: Changelogs <action@github.com> Date: Mon Feb 13 22:17:26 2023 +0000 Automatic changelog compile [ci skip] commita8b8df1868Author: Yogbot-13 <admin@yogstation.net> Date: Mon Feb 13 16:51:13 2023 -0500 Automatic changelog generation #17887 [ci skip] commit991c54d7e3Author: wejengin2 <48154165+wejengin2@users.noreply.github.com> Date: Mon Feb 13 22:51:10 2023 +0100 yeah (#17887) commitd9aec4444dAuthor: Changelogs <action@github.com> Date: Mon Feb 13 06:12:20 2023 +0000 Automatic changelog compile [ci skip] commitbad039c45fAuthor: Yogbot-13 <admin@yogstation.net> Date: Sun Feb 12 17:52:39 2023 -0500 Automatic changelog generation #17897 [ci skip] commitf251ff8187Author: Skrem_7 <98909416+Skrem7@users.noreply.github.com> Date: Sun Feb 12 17:52:36 2023 -0500 better metashield (#17897) commit1c7d28f658Author: Yogbot-13 <admin@yogstation.net> Date: Sun Feb 12 17:51:22 2023 -0500 Automatic changelog generation #17889 [ci skip] commit4f4d2d8bbbAuthor: LazennG <58535870+LazennG@users.noreply.github.com> Date: Sun Feb 12 14:51:19 2023 -0800 cooldown actions isavailable now calls parent pro (#17889) commit5e3f4b08a7Author: Yogbot-13 <admin@yogstation.net> Date: Sun Feb 12 17:50:40 2023 -0500 Automatic changelog generation #17894 [ci skip] commit062f0a2fd5Author: Manatee <74586965+MajManatee@users.noreply.github.com> Date: Sun Feb 12 16:50:37 2023 -0600 augh (#17894) commit494bbd1982Author: ynot01 <ynot000001@gmail.com> Date: Sun Feb 12 07:41:24 2023 -0500 Update yogstation.dme (#17903) commit596b836652Author: Changelogs <action@github.com> Date: Sun Feb 12 06:10:28 2023 +0000 Automatic changelog compile [ci skip] commitdc689f3715Author: 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 commit80284d7ca0Author: Changelogs <action@github.com> Date: Sat Feb 11 22:15:52 2023 +0000 Automatic changelog compile [ci skip] commit56e85c55c3Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 13:38:04 2023 -0500 Automatic changelog generation #17833 [ci skip] commit80afe50f46Author: 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 commit435823b827Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 12:49:50 2023 -0500 Automatic changelog generation #17878 [ci skip] commitfa4b2b98a3Author: 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 commit75cfed640fAuthor: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 12:17:44 2023 -0500 Automatic changelog generation #17842 [ci skip] commit291a70fb8fAuthor: 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 commit1cc076d57aAuthor: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 12:14:44 2023 -0500 Automatic changelog generation #17828 [ci skip] commitfef1aed09bAuthor: 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 commitbf62a065f5Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 12:01:19 2023 -0500 Automatic changelog generation #17824 [ci skip] commit20c67e451bAuthor: 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 commit866c4f0e97Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 11:39:29 2023 -0500 Automatic changelog generation #17814 [ci skip] commit64726b0798Author: 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 commitb956f2caaeAuthor: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 11:36:59 2023 -0500 Automatic changelog generation #17809 [ci skip] commit00769859a2Author: Molti <108117184+Moltijoe@users.noreply.github.com> Date: Sat Feb 11 10:36:57 2023 -0600 Nanite heart buff (#17809) commit87bd1794dbAuthor: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 11:36:15 2023 -0500 Automatic changelog generation #17805 [ci skip] commitf286bdb997Author: SapphicOverload <93578146+SapphicOverload@users.noreply.github.com> Date: Sat Feb 11 11:36:12 2023 -0500 you are a good (#17805) commita737b7291eAuthor: 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 commitf77eb885d9Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 11:34:47 2023 -0500 Automatic changelog generation #17724 [ci skip] commit8f4993ae0bAuthor: 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> commita6779b3a77Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 11:27:41 2023 -0500 Automatic changelog generation #17778 [ci skip] commit402e2d775aAuthor: 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 commitfa67c930d0Author: Jamie D <993128+JamieD1@users.noreply.github.com> Date: Sat Feb 11 16:23:06 2023 +0000 Update dynamic_rulesets_roundstart.dm commit0e05a643a6Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 11:20:01 2023 -0500 Automatic changelog generation #17720 [ci skip] commit738aac2d74Author: 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 commitd0abdd2d33. commit0679f56ea6Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 11:19:12 2023 -0500 Automatic changelog generation #17609 [ci skip] commita5660a07e6Author: 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 commitd1ec159cf3Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 10:50:38 2023 -0500 Automatic changelog generation #17610 [ci skip] commitf49b009b1dAuthor: 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) commit75b0447f82Author: Changelogs <action@github.com> Date: Sat Feb 11 14:07:34 2023 +0000 Automatic changelog compile [ci skip] commitab07a0c5caAuthor: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 04:18:21 2023 -0500 Automatic changelog generation #17739 [ci skip] commited09aa658dAuthor: 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 commitf6cd327077Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 04:07:17 2023 -0500 Automatic changelog generation #17873 [ci skip] commit09a038e850Author: LazennG <58535870+LazennG@users.noreply.github.com> Date: Sat Feb 11 01:07:15 2023 -0800 no more curveballs (#17873) commit186fedce46Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 04:05:05 2023 -0500 Automatic changelog generation #17865 [ci skip] commit422a595d6cAuthor: 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 commitc4217e2080Author: Yogbot-13 <admin@yogstation.net> Date: Sat Feb 11 04:04:45 2023 -0500 Automatic changelog generation #17867 [ci skip] commit20fc9d7f33Author: 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) commitfdf31d11a7Author: Changelogs <action@github.com> Date: Sat Feb 11 06:10:17 2023 +0000 Automatic changelog compile [ci skip] commit6b0ddaf194Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 20:45:30 2023 -0500 Automatic changelog generation #17863 [ci skip] commit484a70bdc6Author: Skrem_7 <98909416+Skrem7@users.noreply.github.com> Date: Fri Feb 10 20:45:27 2023 -0500 hammer fix (#17863) commitc3f4bee6a9Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 20:43:51 2023 -0500 Automatic changelog generation #17866 [ci skip] commit44d935e116Author: 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> commit80045a2877Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 19:56:54 2023 -0500 Automatic changelog generation #17770 [ci skip] commit40564ae7f4Author: 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 commitbece519a8bAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 18:45:30 2023 -0500 Automatic changelog generation #17784 [ci skip] commit4a499be90fAuthor: 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> commit24ad52b6bdAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 18:22:35 2023 -0500 Automatic changelog generation #17835 [ci skip] commit053f8bf856Author: 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> commitd0e1c6f1f9Author: Ling <lingbleed@gmail.com> Date: Sat Feb 11 00:09:14 2023 +0100 Actually fixes gas mixer sprite for real this time (#17840) commit66545d3beeAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 18:07:46 2023 -0500 Automatic changelog generation #17847 [ci skip] commitb04412e57eAuthor: 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 commitc6ab8818ffAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 18:01:32 2023 -0500 Automatic changelog generation #17854 [ci skip] commit0c13569569Author: 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 commit9a3512a44bAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:59:29 2023 -0500 Automatic changelog generation #17836 [ci skip] commit606c9ced8fAuthor: 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 commitfc4a64ed52Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:58:53 2023 -0500 Automatic changelog generation #17871 [ci skip] commitab089cfae7Author: 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 commit20af730457Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:58:27 2023 -0500 Automatic changelog generation #17819 [ci skip] commit3e918a5658Author: Mqiib <43766432+Mqiib@users.noreply.github.com> Date: Fri Feb 10 17:58:25 2023 -0500 Unstupidify (#17819) commit411c213dcdAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:58:11 2023 -0500 Automatic changelog generation #17818 [ci skip] commit919a2686b6Author: Ling <lingbleed@gmail.com> Date: Fri Feb 10 23:58:08 2023 +0100 Prevents wormholes from spawning in syndicate shuttles (#17818) commitb66d0720bbAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:56:47 2023 -0500 Automatic changelog generation #17811 [ci skip] commitb9eb469042Author: 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 commitcdb38b84fdAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:49:43 2023 -0500 Automatic changelog generation #17804 [ci skip] commit1f02d82d27Author: ynot01 <ynot000001@gmail.com> Date: Fri Feb 10 17:49:41 2023 -0500 from fortnite (#17804) do the thing commit0c64a222c8Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:47:18 2023 -0500 Automatic changelog generation #17801 [ci skip] commitf6bf19009fAuthor: Ezhan <39889035+Ethan4303@users.noreply.github.com> Date: Fri Feb 10 17:47:15 2023 -0500 rotates the gas simulator in yogstation turbine (#17801) commit7c9b4054a0Author: 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 commitcf793830ecAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:46:06 2023 -0500 Automatic changelog generation #17785 [ci skip] commit15bb9f53b7Author: 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) commitc69563273bAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:45:23 2023 -0500 Automatic changelog generation #17769 [ci skip] commit367cf38f16Author: ynot01 <ynot000001@gmail.com> Date: Fri Feb 10 17:45:20 2023 -0500 Purchasable autosurgeon for 5TC (#17769) * syndi cat * Update uplink_items.dm commit247a50bc9fAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:43:58 2023 -0500 Automatic changelog generation #17735 [ci skip] commit167ab6af2bAuthor: 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 commitbb77f2d6a3Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 17:22:33 2023 -0500 Automatic changelog generation #17856 [ci skip] commitf13f241426Author: Redd <36747151+ReddicusDragon@users.noreply.github.com> Date: Fri Feb 10 17:22:31 2023 -0500 Revert "Removes felinid language (#17825)" (#17856) This reverts commite75cb0ad00. commitc53b3bc784Author: Changelogs <action@github.com> Date: Fri Feb 10 22:17:13 2023 +0000 Automatic changelog compile [ci skip] commitbf214dad30Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 15:57:59 2023 -0500 Automatic changelog generation #17832 [ci skip] commit0144098f5cAuthor: 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 commit84c1ff3331Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 13:08:39 2023 -0500 Automatic changelog generation #17881 [ci skip] commite2ce0336ffAuthor: wejengin2 <48154165+wejengin2@users.noreply.github.com> Date: Fri Feb 10 19:08:36 2023 +0100 ye (#17881) commit596ac490f7Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 12:29:57 2023 -0500 Automatic changelog generation #17812 [ci skip] commit2047871e5bAuthor: 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> commitbb0d420b09Author: 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 commit0424f5f5e4Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 09:40:37 2023 -0500 Automatic changelog generation #17823 [ci skip] commit611fc49e0bAuthor: Jamie D <993128+JamieD1@users.noreply.github.com> Date: Fri Feb 10 14:40:33 2023 +0000 e (#17823) commitadda8bc9a0Author: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com> Date: Fri Feb 10 15:17:47 2023 +0100 Update unique_donator_items.dm (#17874) commit3a8ad081f9Author: Changelogs <action@github.com> Date: Fri Feb 10 14:08:30 2023 +0000 Automatic changelog compile [ci skip] commitff2f15a395Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 05:01:24 2023 -0500 Automatic changelog generation #17848 [ci skip] commit58a00ef32dAuthor: 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> commit726c31fd2fAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 04:29:51 2023 -0500 Automatic changelog generation #17807 [ci skip] commit9d4d28edd3Author: Redd <36747151+ReddicusDragon@users.noreply.github.com> Date: Fri Feb 10 04:29:48 2023 -0500 Removes corn syrup from catsip (#17807) commita995a0e6fdAuthor: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 04:28:25 2023 -0500 Automatic changelog generation #17831 [ci skip] commitd35292c3d4Author: Ling <lingbleed@gmail.com> Date: Fri Feb 10 10:28:20 2023 +0100 RPD now builds even when clicked on another pipe (#17831) commit51fd6de808Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 03:53:48 2023 -0500 Automatic changelog generation #17852 [ci skip] commit9f91e2edf7Author: Manatee <74586965+MajManatee@users.noreply.github.com> Date: Fri Feb 10 02:53:45 2023 -0600 les go (#17852) commita55a6d4297Author: Changelogs <action@github.com> Date: Fri Feb 10 06:11:39 2023 +0000 Automatic changelog compile [ci skip] commit380e400cb3Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 01:04:58 2023 -0500 Automatic changelog generation #17837 [ci skip] commit861567f4dbAuthor: Byemoh <baiomurang@gmail.com> Date: Fri Feb 10 00:04:56 2023 -0600 Update airlock.dm (#17837) commit08cec4a012Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 01:01:14 2023 -0500 Automatic changelog generation #17813 [ci skip] commit5cf47b2580Author: ynot01 <ynot000001@gmail.com> Date: Fri Feb 10 01:01:12 2023 -0500 Update hologram.dm (#17813) commitef783cb856Author: Yogbot-13 <admin@yogstation.net> Date: Fri Feb 10 00:58:35 2023 -0500 Automatic changelog generation #17834 [ci skip] commita00b6ce757Author: ynot01 <ynot000001@gmail.com> Date: Fri Feb 10 00:58:33 2023 -0500 Update medbeam.dm (#17834) commitd5b72b2259Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 9 20:22:06 2023 -0500 Automatic changelog generation #17723 [ci skip] commit4a6973a465Author: 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 commit229d6664efAuthor: Changelogs <action@github.com> Date: Thu Feb 9 22:17:48 2023 +0000 Automatic changelog compile [ci skip] commitf606eaac8eAuthor: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 9 10:41:20 2023 -0500 Automatic changelog generation #17670 [ci skip] commit26ad93fd58Author: 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> commit2264d7e6bcAuthor: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 9 10:36:18 2023 -0500 Automatic changelog generation #17795 [ci skip] commit6e401075bdAuthor: 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 commitc28d359784Author: Yogbot-13 <admin@yogstation.net> Date: Thu Feb 9 10:27:17 2023 -0500 Automatic changelog generation #17766 [ci skip] commita0c31d2aeeAuthor: Skrem_7 <98909416+Skrem7@users.noreply.github.com> Date: Thu Feb 9 10:27:13 2023 -0500 brrrt (#17766) commit9ff2bc445aAuthor: Changelogs <action@github.com> Date: Thu Feb 9 06:11:19 2023 +0000 Automatic changelog compile [ci skip] commitd268cadedaAuthor: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 8 18:44:13 2023 -0500 Automatic changelog generation #17806 [ci skip] commitc223e28c9dAuthor: Ling <lingbleed@gmail.com> Date: Thu Feb 9 00:44:11 2023 +0100 Fix 'id in pda' pref (#17806) commit44decca884Author: Changelogs <action@github.com> Date: Wed Feb 8 22:16:57 2023 +0000 Automatic changelog compile [ci skip] commitd750b905ddAuthor: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 8 13:17:57 2023 -0500 Automatic changelog generation #17777 [ci skip] commit00a527192bAuthor: 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 commitf028dd3418Author: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 8 12:31:26 2023 -0500 Automatic changelog generation #17825 [ci skip] commite75cb0ad00Author: 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 commit060c415b04Author: Changelogs <action@github.com> Date: Wed Feb 8 14:08:15 2023 +0000 Automatic changelog compile [ci skip] commit7345f0e82dAuthor: Yogbot-13 <admin@yogstation.net> Date: Wed Feb 8 05:39:07 2023 -0500 Automatic changelog generation #17846 [ci skip] commit3e51ef4f8bAuthor: Molti <108117184+Moltijoe@users.noreply.github.com> Date: Wed Feb 8 04:39:03 2023 -0600 Update lavaland_surface_maze.dmm (#17846) commite7823cfc39Author: Changelogs <action@github.com> Date: Wed Feb 8 06:11:43 2023 +0000 Automatic changelog compile [ci skip] commitd927ebc03dAuthor: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 20:39:04 2023 -0500 Automatic changelog generation #17802 [ci skip] commit0fd7dcfc9dAuthor: 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 commit61601d937eAuthor: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 19:57:01 2023 -0500 Automatic changelog generation #17791 [ci skip] commit902e743274Author: BurgerLUA <8602857+BurgerLUA@users.noreply.github.com> Date: Tue Feb 7 16:56:58 2023 -0800 MALF is no longer continuous (#17791) commit81c0963f74Author: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com> Date: Wed Feb 8 01:56:07 2023 +0100 Update adminhelp.dm (#17783) commit95947d2fe2Author: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 19:53:00 2023 -0500 Automatic changelog generation #17742 [ci skip] commitf83723c389Author: 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 commit9bb63a7577Author: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 19:52:22 2023 -0500 Automatic changelog generation #17738 [ci skip] commit0cf7ecf050Author: 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 commit5b9d198f6fAuthor: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 18:37:58 2023 -0500 Automatic changelog generation #17816 [ci skip] commit148e80f8ecAuthor: 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 commit42165a9806Author: Changelogs <action@github.com> Date: Tue Feb 7 22:17:04 2023 +0000 Automatic changelog compile [ci skip] commitb9f7613d59Author: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 14:59:58 2023 -0500 Automatic changelog generation #17748 [ci skip] commit1cfbe0fd48Author: 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 commit3947b4ac5aAuthor: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 11:46:17 2023 -0500 Automatic changelog generation #17799 [ci skip] commitc3cfad4913Author: ynot01 <ynot000001@gmail.com> Date: Tue Feb 7 11:46:14 2023 -0500 weird (#17799) commit8de1275a99Author: Changelogs <action@github.com> Date: Tue Feb 7 14:08:44 2023 +0000 Automatic changelog compile [ci skip] commit198c9f89aaAuthor: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 06:52:05 2023 -0500 Automatic changelog generation #17822 [ci skip] commit63928e7f87Author: Jamie D <993128+JamieD1@users.noreply.github.com> Date: Tue Feb 7 11:52:02 2023 +0000 Update game_options.txt (#17822) commit7daad46a71Author: Yogbot-13 <admin@yogstation.net> Date: Tue Feb 7 05:15:44 2023 -0500 Automatic changelog generation #17776 [ci skip] commitb01613407aAuthor: 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 commit23abc5abd2Author: Changelogs <action@github.com> Date: Tue Feb 7 06:11:41 2023 +0000 Automatic changelog compile [ci skip] commitd170eab0aaAuthor: Yogbot-13 <admin@yogstation.net> Date: Mon Feb 6 19:03:32 2023 -0500 Automatic changelog generation #17797 [ci skip] commit1aac303800Author: 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 commit57283fa900Author: Yogbot-13 <admin@yogstation.net> Date: Mon Feb 6 18:17:08 2023 -0500 Automatic changelog generation #17712 [ci skip] commitb2c06b0866Author: 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> commit0d00d7457cAuthor: Changelogs <action@github.com> Date: Mon Feb 6 22:16:37 2023 +0000 Automatic changelog compile [ci skip] commit7955f64f79Author: Yogbot-13 <admin@yogstation.net> Date: Mon Feb 6 10:52:52 2023 -0500 Automatic changelog generation #17582 [ci skip] commit8df29b5392Author: 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> commit498e4e6ae4Author: Changelogs <action@github.com> Date: Mon Feb 6 14:09:30 2023 +0000 Automatic changelog compile [ci skip] commite37654707eAuthor: Yogbot-13 <admin@yogstation.net> Date: Mon Feb 6 07:43:42 2023 -0500 Automatic changelog generation #17768 [ci skip] commit5725a33174Author: 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 commitd7f3ee4734Author: Yogbot-13 <admin@yogstation.net> Date: Mon Feb 6 06:38:11 2023 -0500 Automatic changelog generation #17707 [ci skip] commita6c0573423Author: 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 commitcc868113c1Author: Changelogs <action@github.com> Date: Sun Feb 5 22:15:50 2023 +0000 Automatic changelog compile [ci skip] commit0343eb61c8Author: Yogbot-13 <admin@yogstation.net> Date: Sun Feb 5 14:37:43 2023 -0500 Automatic changelog generation #17749 [ci skip] commite9bb5b6679Author: 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> commit00d55013b1Author: Yogbot-13 <admin@yogstation.net> Date: Sun Feb 5 12:14:21 2023 -0500 Automatic changelog generation #17779 [ci skip] commit85661c5d71Author: LazennG <58535870+LazennG@users.noreply.github.com> Date: Sun Feb 5 09:14:18 2023 -0800 buster arm patch (#17779) commit20b3adaae3Author: Changelogs <action@github.com> Date: Sun Feb 5 14:07:35 2023 +0000 Automatic changelog compile [ci skip] commit123638a50eAuthor: Yogbot-13 <admin@yogstation.net> Date: Sun Feb 5 01:21:47 2023 -0500 Automatic changelog generation #17774 [ci skip] commit707b8379f9Author: ktlwjec <122807629+ktlwjec0@users.noreply.github.com> Date: Sun Feb 5 06:21:45 2023 +0000 blue burger uses patty (#17774) commit6ba5dd3f5fAuthor: 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 commit294dc43cff. * makes anomaly quiver printable * running it back * DIE ICON CORNFLAKES DIE * Revert "DIE ICON CORNFLAKES DIE" This reverts commita5294ffab4. * 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 commit37d079dc91. * 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>
2809 lines
110 KiB
Plaintext
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
|