diff --git a/.editorconfig b/.editorconfig
index d6adf33378..471170c449 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -4,7 +4,7 @@ indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
-# end_of_line = lf
+end_of_line = lf
[*.yml]
indent_style = space
diff --git a/.github/AUTODOC_GUIDE.md b/.github/AUTODOC_GUIDE.md
new file mode 100644
index 0000000000..3433c1cc53
--- /dev/null
+++ b/.github/AUTODOC_GUIDE.md
@@ -0,0 +1,108 @@
+# dmdoc
+[DOCUMENTATION]: http://codedocs.tgstation13.org
+
+[BYOND]: https://secure.byond.com/
+
+[DMDOC]: https://github.com/SpaceManiac/SpacemanDMM/tree/master/src/dmdoc
+
+[DMDOC] is a documentation generator for DreamMaker, the scripting language
+of the [BYOND] game engine. It produces simple static HTML files based on
+documented files, macros, types, procs, and vars.
+
+We use **dmdoc** to generate [DOCUMENTATION] for our code, and that documentation
+is automatically generated and built on every new commit to the master branch
+
+This gives new developers a clickable reference [DOCUMENTATION] they can browse to better help
+gain understanding of the /tg/station codebase structure and api reference.
+
+## Documenting code on /tg/station
+We use block comments to document procs and classes, and we use `///` line comments
+when documenting individual variables.
+
+It is required that all new code be covered with DMdoc code, according to the [Requirements](#Required)
+
+We also require that when you touch older code, you must document the functions that you
+have touched in the process of updating that code
+
+### Required
+A class *must* always be autodocumented, and all public functions *must* be documented
+
+All class level defined variables *must* be documented
+
+Internal functions *should* be documented, but may not be
+
+A public function is any function that a developer might reasonably call while using
+or interacting with your object. Internal functions are helper functions that your
+public functions rely on to implement logic
+
+
+### Documenting a proc
+When documenting a proc, we give a short one line description (as this is shown
+next to the proc definition in the list of all procs for a type or global
+namespace), then a longer paragraph which will be shown when the user clicks on
+the proc to jump to it's definition
+```
+/**
+ * Short description of the proc
+ *
+ * Longer detailed paragraph about the proc
+ * including any relevant detail
+ * Arguments:
+ * * arg1 - Relevance of this argument
+ * * arg2 - Relevance of this argument
+ */
+```
+
+### Documenting a class
+We first give the name of the class as a header, this can be omitted if the name is
+just going to be the typepath of the class, as dmdoc uses that by default
+
+Then we give a short oneline description of the class
+
+Finally we give a longer multi paragraph description of the class and it's details
+```
+/**
+ * # Classname (Can be omitted if it's just going to be the typepath)
+ *
+ * The short overview
+ *
+ * A longer
+ * paragraph of functionality about the class
+ * including any assumptions/special cases
+ *
+ */
+```
+
+### Documenting a variable/define
+Give a short explanation of what the variable, in the context of the class, or define is.
+```
+/// Type path of item to go in suit slot
+var/suit = null
+```
+
+## Module level description of code
+Modules are the best way to describe the structure/intent of a package of code
+where you don't want to be tied to the formal layout of the class structure.
+
+On /tg/station we do this by adding markdown files inside the `code` directory
+that will also be rendered and added to the modules tree. The structure for
+these is deliberately not defined, so you can be as freeform and as wheeling as
+you would like.
+
+[Here is a representative example of what you might write](http://codedocs.tgstation13.org/code/modules/keybindings/readme.html)
+
+## Special variables
+You can use certain special template variables in DM DOC comments and they will be expanded
+```
+ [DEFINE_NAME] - Expands to a link to the define definition if documented
+ [/mob] - Expands to a link to the docs for the /mob class
+ [/mob/proc/Dizzy] - Expands to a link that will take you to the /mob class and anchor you to the dizzy proc docs
+ [/mob/var/stat] - Expands to a link that will take you to the /mob class and anchor you to the stat var docs
+```
+
+You can customise the link name by using `[link name][link shorthand].`
+
+eg. `[see more about dizzy here] [/mob/proc/Dizzy]`
+
+This is very useful to quickly link to other parts of the autodoc code to expand
+upon a comment made, or reasoning about code
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 643b4d6e64..d10a2d79f6 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -1,8 +1,29 @@
# CONTRIBUTING
-## Reporting Issues
+1. [Reporting Issues](#reporting-issues)
+2. [Introduction](#introduction)
+3. [Getting Started](#getting-started)
+4. [Meet the Team](#meet-the-team)
+ 1. [Headcoder](#headcoder)
+ 2. [Maintainers](#maintainers)
+ 3. [Issue Managers](#issue-managers)
+5. [Specifications](#specifications)
+6. [Pull Request Process](#pull-request-process)
+7. [Porting features/sprites/sounds/tools from other codebases](#porting-featuresspritessoundstools-from-other-codebases)
+8. [Banned content](#banned-content)
+9. [A word on Git](#a-word-on-git)
-See [this page](http://tgstation13.org/wiki/Reporting_Issues) for a guide and format to issue reports.
+## Reporting Issues
+If you ever encounter a bug in-game, the best way to let a coder know about it is with our GitHub Issue Tracker. Please make sure you use the supplied issue template, and include the round ID for the server.
+
+(If you don't have an account, making a new one takes only one minute.)
+
+If you have difficulty, ask for help in the #coding-general channel on our discord.
+
+## Citadel Station 13
+Notice: We are currently using a near-copy of /tg/station's CONTRIBUTING.md file. Keep in mind which codebase you are on.
+Any questions regarding help for development/spriting/coding/etc should go on #development-discussion-main on our discord.
+https://discord.gg/fkVVfVH48n
## Introduction
@@ -15,35 +36,63 @@ First things first, we want to make it clear how you can contribute (if you've n
/tg/station doesn't have a list of goals and features to add; we instead allow freedom for contributors to suggest and create their ideas for the game. That doesn't mean we aren't determined to squash bugs, which unfortunately pop up a lot due to the deep complexity of the game. Here are some useful starting guides, if you want to contribute or if you want to know what challenges you can tackle with zero knowledge about the game's code structure.
If you want to contribute the first thing you'll need to do is [set up Git](http://tgstation13.org/wiki/Setting_up_git) so you can download the source code.
+After setting it up, optionally navigate your git commandline to the project folder and run the command: `git config blame.ignoreRevsFile .git-blame-ignore-revs`.
-We have a [list of guides on the wiki](http://www.tgstation13.org/wiki/index.php/Guides#Development_and_Contribution_Guides) that will help you get started contributing to /tg/station with Git and Dream Maker. For beginners, it is recommended you work on small projects like bugfixes at first. If you need help learning to program in BYOND, check out this [repository of resources](http://www.byond.com/developer/articles/resources).
+We have a [list of guides on the wiki](http://www.tgstation13.org/wiki/Guides#Development_and_Contribution_Guides) that will help you get started contributing to /tg/station with Git and Dream Maker. For beginners, it is recommended you work on small projects like bugfixes at first. If you need help learning to program in BYOND, check out this [repository of resources](http://www.byond.com/developer/articles/resources).
-There is an open list of approachable issues for [your inspiration here](https://github.com/tgstation/-tg-station/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+First+Issue%22).
+There is an open list of approachable issues for [your inspiration here](https://github.com/Citadel-Station-13/Citadel-Station-13/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+First+Issue%22).
-You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/coderbus) on irc.rizon.net. We're just here to have fun and help out, so please don't expect professional support.
+You can of course, as always, ask for help on the Discord channels or the forums. We're just here to have fun and help out, so please don't expect professional support.
## Meet the Team
-**Design Lead**
-
-The Design Lead has the final say on what gameplay changes get into and out of the game. He or she has full veto power on any feature or balance additions, changes, or removals, and establishes a general, personally-preferred direction for the game.
-
-**Headcoder**
+### Headcoder
The Headcoder is responsible for controlling, adding, and removing maintainers from the project. In addition to filling the role of a normal maintainer, they have sole authority on who becomes a maintainer, as well as who remains a maintainer and who does not.
-**Art Director**
-
-The Art Director controls sprites and aesthetic that get into the game. While sprites for brand-new additions are generally accepted regardless of quality, modified current art assets fall to the Art Director, who can decide whether or not a sprite tweak is both merited and a suitable replacement.
-
-They also control the general "perspective" of the game - how sprites should generally look, especially the angle from which they're viewed. An example of this is the [3/4 perspective](http://static.tvtropes.org/pmwiki/pub/images/kakarikovillage.gif), which is a bird's eye view from above the object being viewed.
-
-**Maintainers**
+### Maintainers
Maintainers are quality control. If a proposed pull request doesn't meet the following specifications, they can request you to change it, or simply just close the pull request. Maintainers are required to give a reason for closing the pull request.
Maintainers can revert your changes if they feel they are not worth maintaining or if they did not live up to the quality specifications.
+Maintainer Guidelines
+
+These are the few directives we have for project maintainers.
+
+- Do not merge PRs you create.
+- Do not merge PRs until 24 hours have passed since it was opened. Exceptions include:
+ - Emergency fixes.
+ - Try to get secondary maintainer approval before merging if you are able to.
+ - PRs with empty commits intended to generate a changelog.
+- Do not merge PRs that contain content from the [banned content list](./CONTRIBUTING.md#banned-content).
+
+These are not steadfast rules as maintainers are expected to use their best judgement when operating.
+
+Our team is entirely voluntary, as such we extend our thanks to maintainers, issue managers, and contributors alike for helping keep the project alive.
+
+What You Can and Can't Do as an Issue Manager
+
+This should help you understand what you can and can't do with your newfound github permissions.
+
+Things you **CAN** do:
+* Label issues appropriately
+* Close issues when appropriate
+* Label PRs when appropriate
+
+Things you **CAN'T** do:
+* [Close PRs](https://imgur.com/w2RqpX8.png): Only maintainers are allowed to close PRs. Do not hit that button.
+
+
" : ""
for(var/line in testmerge)
var/datum/tgs_revision_information/test_merge/tm = line
- var/cm = tm.pull_request_commit
+ var/cm = tm.head_commit
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext_char(cm, 1, 11))
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
continue
diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm
index 9cfec43013..bf910b3944 100644
--- a/code/datums/status_effects/buffs.dm
+++ b/code/datums/status_effects/buffs.dm
@@ -642,7 +642,7 @@
O.Remove()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
- C.vomit(0, toxic = TRUE)
+ C.vomit(0)
O.forceMove(get_turf(owner))
if(isliving(owner))
var/mob/living/L = owner
diff --git a/code/game/objects/effects/glowshroom.dm b/code/game/objects/effects/glowshroom.dm
index 2d28d3a041..22dd772ebe 100644
--- a/code/game/objects/effects/glowshroom.dm
+++ b/code/game/objects/effects/glowshroom.dm
@@ -73,6 +73,8 @@
myseed.adjust_yield(rand(-3,2))
myseed.adjust_production(rand(-3,3))
myseed.endurance = clamp(myseed.endurance + rand(-3,2), 0, 100) // adjust_endurance has a min value of 10, need to edit directly
+ // Scale health to endurance
+ max_integrity = obj_integrity = 10 + myseed.endurance / 2
delay_spread = delay_spread - myseed.production * 100 //So the delay goes DOWN with better stats instead of up. :I
var/datum/plant_gene/trait/glow/G = myseed.get_gene(/datum/plant_gene/trait/glow)
if(ispath(G)) // Seeds were ported to initialize so their genes are still typepaths here, luckily their initializer is smart enough to handle us doing this
@@ -193,8 +195,14 @@
/obj/structure/glowshroom/proc/Decay(spread, amount)
if (spread) // Decay due to spread
myseed.endurance -= amount
+ max_integrity = min(max_integrity, 10 + myseed.endurance / 2)
+ if(obj_integrity > max_integrity)
+ obj_integrity = max_integrity
else // Timed decay
myseed.endurance -= 1
+ max_integrity = min(max_integrity, 10 + myseed.endurance / 2)
+ if(obj_integrity > max_integrity)
+ obj_integrity = max_integrity
if (myseed.endurance > 0)
addtimer(CALLBACK(src, .proc/Decay), delay_decay, FALSE) // Recall decay timer
return
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index f2afaf2826..0172f1c150 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -399,7 +399,7 @@
on_sound = 'sound/weapons/batonextend.ogg'
on_icon_state = "telebaton_1"
off_icon_state = "telebaton_0"
- on_item_state = "nullrod"
+ on_item_state = "telebaton_1"
force_on = 10
force_off = 0
weight_class_on = WEIGHT_CLASS_BULKY
@@ -472,7 +472,7 @@
on_stun_sound = 'sound/effects/contractorbatonhit.ogg'
on_icon_state = "contractor_baton_1"
off_icon_state = "contractor_baton_0"
- on_item_state = "contractor_baton"
+ on_item_state = "contractor_baton_1"
force_on = 16
force_off = 5
weight_class_on = WEIGHT_CLASS_NORMAL
diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm
index e47b2bb0d8..22ffc33516 100644
--- a/code/game/objects/items/pinpointer.dm
+++ b/code/game/objects/items/pinpointer.dm
@@ -4,10 +4,10 @@
desc = "A handheld tracking device that locks onto certain signals."
icon = 'icons/obj/device.dmi'
icon_state = "pinpointer"
+ item_state = "pinpointer"
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
- item_state = "electronic"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
throw_speed = 3
@@ -97,6 +97,7 @@
name = "crew pinpointer"
desc = "A handheld tracking device that points to crew suit sensors."
icon_state = "pinpointer_crew"
+ item_state = "pinpointer_crew"
custom_price = PRICE_ABOVE_EXPENSIVE
var/has_owner = FALSE
var/pinpointer_owner = null
@@ -208,6 +209,7 @@
name = "fugitive pinpointer"
desc = "A handheld tracking device that locates the bounty hunter shuttle for quick escapes."
icon_state = "pinpointer_hunter"
+ item_state = "pinpointer_black"
var/obj/shuttleport
/obj/item/pinpointer/shuttle/Initialize(mapload)
@@ -231,4 +233,4 @@
/obj/item/pinpointer/custom
resets_target = FALSE
-
+
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index 9e3cbad19b..b526b5b886 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -277,7 +277,7 @@
if(lube & NO_SLIP_WHEN_WALKING)
if(C.m_intent == MOVE_INTENT_WALK)
return FALSE
- if(ishuman(C) && !(lube & SLIP_WHEN_JOGGING))
+ if(ishuman(C) && !(lube & SLIP_WHEN_JOGGING) && CONFIG_GET(flag/sprint_enabled))
var/mob/living/carbon/human/H = C
if(!(H.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && H.getStaminaLoss() <= 20)
return FALSE
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 6ac9c4c427..50d18c1b40 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -589,7 +589,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
/turf/AllowDrop()
return TRUE
-/turf/proc/add_vomit_floor(mob/living/M, toxvomit = NONE)
+/turf/proc/add_vomit_floor(mob/living/M, toxvomit = NONE, purge_ratio = 0.1)
var/obj/effect/decal/cleanable/vomit/V = new /obj/effect/decal/cleanable/vomit(src, M.get_static_viruses())
//if the vomit combined, apply toxicity and reagents to the old vomit
@@ -597,21 +597,24 @@ GLOBAL_LIST_EMPTY(station_turfs)
V = locate() in src
if(!V) //the decal was spawned on a wall or groundless turf and promptly qdeleted.
return
- // Make toxins and blazaam vomit look different
+ // Apply the proper icon set based on vomit type
if(toxvomit == VOMIT_PURPLE)
V.icon_state = "vomitpurp_[pick(1,4)]"
else if (toxvomit == VOMIT_TOXIC)
V.icon_state = "vomittox_[pick(1,4)]"
- if (iscarbon(M))
- var/mob/living/carbon/C = M
- if(C.reagents)
- clear_reagents_to_vomit_pool(C,V)
+ else if (toxvomit == VOMIT_NANITE)
+ V.name = "metallic slurry"
+ V.desc = "A puddle of metallic slurry that looks vaguely like very fine sand. It almost seems like it's moving..."
+ V.icon_state = "vomitnanite_[pick(1,4)]"
+ if (purge_ratio && iscarbon(M))
+ clear_reagents_to_vomit_pool(M, V, purge_ratio)
-/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V)
+/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V, purge_ratio = 0.1)
for(var/datum/reagent/consumable/R in M.reagents.reagent_list) //clears the stomach of anything that might be digested as food
if(R.nutriment_factor > 0)
M.reagents.del_reagent(R.type)
- M.reagents.trans_to(V, M.reagents.total_volume / 10)
+ var/chemicals_lost = M.reagents.total_volume * purge_ratio
+ M.reagents.trans_to(V, chemicals_lost)
//Whatever happens after high temperature fire dies out or thermite reaction works.
//Should return new turf
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index b7aeb23e6f..3857d1206c 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -684,6 +684,7 @@
if(HAS_TRAIT(user, TRAIT_NOPUGILIST))
to_chat(user, "We would gain nothing by forming our fists into brute-force weapons when we are trained in precision martial arts!")
return
+ return ..()
/obj/item/clothing/gloves/fingerless/pugilist/cling // switches between lesser GotNS and Big Punchy Rib Breaky Hands
name = "hewn bone gauntlets"
diff --git a/code/modules/antagonists/nukeop/equipment/pinpointer.dm b/code/modules/antagonists/nukeop/equipment/pinpointer.dm
index db9ff4e609..d3fe235f49 100644
--- a/code/modules/antagonists/nukeop/equipment/pinpointer.dm
+++ b/code/modules/antagonists/nukeop/equipment/pinpointer.dm
@@ -61,6 +61,7 @@
name = "syndicate pinpointer"
desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device."
icon_state = "pinpointer_syndicate"
+ item_state = "pinpointer_black"
/obj/item/pinpointer/syndicate_cyborg // Cyborg pinpointers just look for a random operative.
name = "cyborg syndicate pinpointer"
diff --git a/code/modules/antagonists/space_dragon/space_dragon.dm b/code/modules/antagonists/space_dragon/space_dragon.dm
new file mode 100644
index 0000000000..d085d80bbb
--- /dev/null
+++ b/code/modules/antagonists/space_dragon/space_dragon.dm
@@ -0,0 +1,79 @@
+/datum/antagonist/space_dragon
+ name = "Space Dragon"
+ roundend_category = "space dragons"
+ antagpanel_category = "Space Dragon"
+ job_rank = ROLE_SPACE_DRAGON
+ show_in_antagpanel = TRUE
+ show_name_in_check_antagonists = TRUE
+ var/list/datum/mind/carp = list()
+
+/datum/antagonist/space_dragon/greet()
+ to_chat(owner, "Endless time and space we have moved through. We do not remember from where we came, we do not know where we will go. All space belongs to us.\n\
+ Space is an empty void, of which our kind is the apex predator, and there was little to rival our claim to this title.\n\
+ But now, we find intruders spread out amongst our claim, willing to fight our teeth with magics unimaginable, their dens like lights flicking in the depths of space.\n\
+ Today, we will snuff out one of those lights.")
+ to_chat(owner, "You have five minutes to find a safe location to place down the first rift. If you take longer than five minutes to place a rift, you will be returned from whence you came.\n\
+ Alt click to cause a gust around you!")
+ owner.announce_objectives()
+ SEND_SOUND(owner.current, sound('sound/magic/demon_attack1.ogg'))
+
+/datum/antagonist/space_dragon/proc/forge_objectives()
+ var/datum/objective/summon_carp/summon = new()
+ summon.dragon = src
+ objectives += summon
+
+/datum/antagonist/space_dragon/on_gain()
+ forge_objectives()
+ . = ..()
+
+/datum/objective/summon_carp
+ var/datum/antagonist/space_dragon/dragon
+ explanation_text = "Summon and protect the rifts to flood the station with carp."
+
+/datum/antagonist/space_dragon/roundend_report()
+ var/list/parts = list()
+ var/datum/objective/summon_carp/S = locate() in objectives
+ if(S.check_completion())
+ parts += "The [name] has succeeded! Station space has been reclaimed by the space carp!"
+ parts += printplayer(owner)
+ var/objectives_complete = TRUE
+ if(objectives.len)
+ parts += printobjectives(objectives)
+ for(var/datum/objective/objective in objectives)
+ if(!objective.check_completion())
+ objectives_complete = FALSE
+ break
+ if(objectives_complete)
+ parts += "The [name] was successful!"
+ else
+ parts += "The [name] has failed!"
+ parts += "The [name] was assisted by:"
+ parts += printplayerlist(carp)
+ return "