diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 2d17e96659c2..c1650b616028 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,11 +1,11 @@
#DOCS
#https://docs.github.com/en/github-ae@latest/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
#
-blank_issues_enabled: false
+blank_issues_enabled: true
contact_links:
- name: Feature Request
- url: https://www.paradisestation.org/forum/60-suggestions/
- about: Please place all feature requests at the following link. (Paradise Station Forums)
+ url: https://discord.com/channels/1097181193939730453/1181261198096875670
+ about: Запросы новых фич следует оставлять на форуме ss13-трекер в дискорде.
- name: Exploit Reports
- url: https://www.paradisestation.org/forum/179-exploit-reports/
- about: If your issue is an ingame exploit that allows players to gain an unfair advantage, or an issue which could affect server stability or security, please file it here so that it is safe from prying eyes. (Paradise Station Forums)
+ url: https://github.com/ss220club/Paradise-SS220/security
+ about: Критические баги, которые могут быть использованы со злыми намерениями, следует оставлять по ссылке.
diff --git a/.github/ISSUE_TEMPLATE/issue_report.yml b/.github/ISSUE_TEMPLATE/issue_report.yml
index e4397dc9b01d..4b3cdb5b5412 100644
--- a/.github/ISSUE_TEMPLATE/issue_report.yml
+++ b/.github/ISSUE_TEMPLATE/issue_report.yml
@@ -10,90 +10,82 @@
# label: | Box title |
# description: | Box small text - Description |
#
-name: "Issue Report"
+name: 'Issue Report'
#title: "[Bug]: " | if you want to have a have it automatically say [Bug] when they start the form
-description: "File an issue report to make us aware of a bug or issue."
-#labels: [Bug] | Auto labels the post, as we do not use this, commenting out, purely as reference
+description: 'Доложите о проблемах или багах, что бы мы могли их исправить.'
+#labels: "Баг"
body:
- type: markdown
attributes:
- value: Thanks for taking the time to fill out this issue report! Don't forget to give it a meaningful title so users can find the report easily.
- - type: checkboxes
- id: not_an_exploit
- attributes:
- label: Exploit Reports
- description: "[If your issue is an ingame exploit that allows players to gain an unfair advantage, or an issue which could affect server stability or security, please file it at this link so that it is safe from prying eyes.](https://www.paradisestation.org/forum/179-exploit-reports/)"
- options:
- - label: I confirm this issue is not an exploit. (Required)
- required: true
+ value: Спасибо за оставленный отчёт! Не забудьте дать ему соответствующее проблеме название для упрощения работы другим.
- type: input
id: version
attributes:
label: BYOND Version
- description: "What BYOND version were you using when the issue occurred? (Find this by pressing the cog in the top-right of the main BYOND menu, then 'About BYOND...') (Required)"
+ description: 'На какой версии BYOND встретился баг. (Если уверены, что не связано, можно пропустить)'
validations:
required: true
- type: textarea
id: description
attributes:
- label: Issue Description
- description: What is the problem? (Required)
- placeholder: I tried buckling myself to a chair but ended up on lavaland!
+ label: Описание проблемы
+ description: В чем состоит суть проблемы? (Обязательное поле)
+ placeholder: Я сел на стул, от чего взорвался, а мой мозг оказался в душе на ЦК!
validations:
required: true
- type: textarea
id: what-expected
attributes:
- label: What did you expect to happen?
- description: Why do you think this is an issue?
- placeholder: I expected to be strapped to a chair.
+ label: Что должно было произойти?
+ description: Почему вы считаете это проблемой?
+ placeholder: Я ожидал, что я просто сяду на стул и буду сидеть.
- type: textarea
id: what-happened
attributes:
- label: What happened instead?
- description: How is what happened different from what you expected?
- placeholder: I got sent to lavaland and died.
+ label: Что случилось вместо этого?
+ description: Как произошедшее отличается от ваших ожиданий?
+ placeholder: Я умер и оказался на ЦК.
- type: textarea
id: why-bad
attributes:
- label: Why is this bad/What are the consequences?
- description: Why do you think this is an important issue?
- placeholder: People sitting in chairs on the station should not end up being devoured by drakes.
+ label: Почему это плохо/Какие последствия?
+ description: Почему вы считаете эту проблему значительной?
+ placeholder: Игроки должны иметь возможность сидеть на стульях, не взрываясь.
- type: textarea
id: how-to-reproduce
attributes:
- label: Steps to reproduce the issue.
- description: The most important section. Review everything you did leading up to causing the issue. (Required)
- placeholder: Find a chair, buckle yourself into it, be eaten by dragon.
+ label: Шаги для повторения проблемы.
+ description: Самая важная часть. Опишите ВСЁ, что вы делали, что бы встретиться с проблемой. (Обязательное поле)
+ placeholder: Нашел стул, сел, взорвался.
validations:
required: true
- type: textarea
id: when-problem-start
attributes:
- label: When did the problem start happening?
- description: If your report is about something that used to work but no longer does, when was the last time you remember it working? (Required)
- placeholder: I could sit fine last week, so sometime around then.
+ label: Когда проблема началась?
+ description: Если отчет связан с тем, что раньше работало иначе, опишите последний раз, когда механика работала корректно. (Обязательное поле)
+ placeholder: Я мог садиться на стулья без проблем неделю назад, так что примерно тогда.
validations:
required: true
- type: textarea
id: extra-information
attributes:
- label: Extra information
- description: Anything else you can tell us.
- placeholder: "I think this issue was introduced in the following PR https://github.com/ParadiseSS13/Paradise/pull/18477"
+ label: Дополнительная информация
+ description: Всё, что вы считаете важным/относящимся к проблеме.
+ placeholder: Я думаю, что проблема начала появляться после этого PR https://github.com/ss220club/Paradise-SS220/pull/583
- type: textarea
id: logs
attributes:
- label: Relevant log output/runtime error
- description: Please copy and paste any relevant log output or runtime if you have access to this. Please censor any ckeys or IP addresses.
+ label: Связанные логи
+ description: Пожалуйста, предоставьте связанные логи или рантаймы, если имеете к ним доступ. (Лучше цензурить IP-адреса)
render: DM
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 5a0d21b14aac..fc3abcbeb510 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,51 +1,40 @@
-
+
+
-
-
+## Что этот PR делает
-## What Does This PR Do
+
+
+
-
-
-
+## Почему это хорошо для игры
-## Why It's Good For The Game
+
-
+## Изображения изменений
-## Images of changes
+
-
+## Тестирование
-## Testing
-
-
-
-
Welcome to The Twin-Nexus Hotel, \[insert name here]! The loyal staff strive to their best effort to cater for the best possible experience for all space(wo)men! If you have any questions or comments, please ask one of our on-board staff for more information.
Welcome to The Twin-Nexus Hotel, \[insert name here]! The loyal staff strive to their best effort to cater for the best possible experience for all space(wo)men! If you have any questions or comments, please ask one of our on-board staff for more information.
Welcome to The Twin-Nexus Hotel, \[insert name here]! The loyal staff strive to their best effort to cater for the best possible experience for all space(wo)men! If you have any questions or comments, please ask one of our on-board staff for more information.
Welcome to The Twin-Nexus Hotel, \[insert name here]! The loyal staff strive to their best effort to cater for the best possible experience for all space(wo)men! If you have any questions or comments, please ask one of our on-board staff for more information.
Всего заработано Кикиридитов: [trader.all_values_sum]"
+
+ var/precious_count = 0
+ var/biggest_index
+ for(var/I in trader.precious_collected_dict)
+ var/value = trader.precious_collected_dict[I]["value"]
+ var/count = trader.precious_collected_dict[I]["count"]
+ precious_count += count
+ if(!biggest_index || trader.precious_collected_dict[biggest_index]["value"] <= value)
+ biggest_index = I
+ text += " Самый дорогой проданный товар: \
+ [biggest_index] ([trader.precious_collected_dict[biggest_index]["value"]]), \
+ всего продано [trader.precious_collected_dict[biggest_index]["count"]] штук."
+
+ text += "
Собраны доступы: "
+ var/list/checked_accesses = list()
+ var/list/region_codes = list(
+ REGION_GENERAL, REGION_SECURITY, REGION_MEDBAY, REGION_RESEARCH,
+ REGION_ENGINEERING, REGION_SUPPLY, REGION_COMMAND, REGION_CENTCOMM
+ )
+ for(var/code in region_codes)
+ var/list/region_accesses
+ if(code != REGION_CENTCOMM)
+ region_accesses = get_region_accesses(code)
+ else
+ region_accesses = list(ACCESS_CENT_GENERAL)
+ for(var/access in trader.collected_access_list)
+ if(access in region_accesses)
+ region_accesses.Remove(access)
+ checked_accesses["[code]"] = region_accesses
+ var/access_count = 0
+ for(var/code in region_codes)
+ if(length(checked_accesses["[code]"]) > 0)
+ continue
+ switch(code)
+ if(REGION_GENERAL)
+ text += "Собраны все общественные и сервисные доступы!"
+ if(REGION_SECURITY)
+ text += " Собраны все доступы службы безопасности!"
+ if(REGION_MEDBAY)
+ text += " Собраны все доступы медицинского отдела!"
+ if(REGION_RESEARCH)
+ text += " Собраны все доступы научного отдела!"
+ if(REGION_ENGINEERING)
+ text += " Собраны все инженерные доступы!"
+ if(REGION_SUPPLY)
+ text += " Собраны все доступы отдела снабжения!"
+ if(REGION_COMMAND)
+ text += " Собраны все командные доступы!"
+ if(REGION_CENTCOMM)
+ text += " Получен особый доступ к Центральному Командованию!"
+ access_count++
+ if(!access_count)
+ text += " Ни одного полного отдела доступов!"
+
+ text += "
Собраны технологии:"
+ for(var/i in trader.collected_tech_dict)
+ text += " [i]: [trader.collected_tech_dict[i]]"
+
+ text += " "
+ return text.Join("")
diff --git a/modular_ss220/antagonists/code/configuration/antag_mix_configuration.dm b/modular_ss220/antagonists/code/configuration/antag_mix_configuration.dm
new file mode 100644
index 000000000000..ac8fddc37435
--- /dev/null
+++ b/modular_ss220/antagonists/code/configuration/antag_mix_configuration.dm
@@ -0,0 +1,29 @@
+/datum/server_configuration
+ var/datum/configuration_section/antag_mix_gamemode_configuration/antag_mix_gamemode
+
+/datum/configuration_section/antag_mix_gamemode_configuration
+ protection_state = PROTECTION_READONLY
+ /// Antag mix budget multiplied. By default it's 1 - so budged is calculated without any modifications
+ var/budget_multiplier = 1
+ /// Max antag fraction defines the percent of antags relatively to ready players. Must be value between 0 and 1.
+ /// 0 means that no antags can be present, 1 - all players can be antags.
+ var/max_antag_fraction = 0.1
+ /// Assoc list of antag scenario config tag -> list of parameters of this scenarios
+ var/list/params_by_scenario = list()
+
+/datum/server_configuration/load_all_sections()
+ . = ..()
+ antag_mix_gamemode = new()
+ safe_load(antag_mix_gamemode, "antag_mix_gamemode_configuration")
+
+/datum/configuration_section/antag_mix_gamemode_configuration/load_data(list/data)
+ CONFIG_LOAD_NUM(budget_multiplier, data["budget_multiplier"])
+ CONFIG_LOAD_NUM(max_antag_fraction, data["max_antag_fraction"])
+
+ for(var/list/scenario_params in data["antag_scenarios_configuration"])
+ var/tag = scenario_params["tag"]
+ if(!tag)
+ error("`tag` missing in `antag_scenarios_configuration`.")
+ continue
+
+ params_by_scenario[tag] = scenario_params["params"]
diff --git a/modular_ss220/antagonists/code/guns/biogun.dm b/modular_ss220/antagonists/code/guns/biogun.dm
new file mode 100644
index 000000000000..1521d515338b
--- /dev/null
+++ b/modular_ss220/antagonists/code/guns/biogun.dm
@@ -0,0 +1,167 @@
+/obj/item/gun/throw/biogun
+ name = "biogun"
+ desc = "Метатель живых био-ядер."
+ icon = 'modular_ss220/antagonists/icons/guns/vox_guns.dmi'
+ lefthand_file = 'modular_ss220/antagonists/icons/guns/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/antagonists/icons/guns/inhands/guns_righthand.dmi'
+ icon_state = "biogun"
+ item_state = "spike_long"
+ var/inhand_charge_sections = 3
+ w_class = WEIGHT_CLASS_HUGE
+ max_capacity = 3
+ projectile_speed = 2
+ projectile_range = 30
+ valid_projectile_type = /obj/item/biocore
+ var/is_vox_private = FALSE
+
+/obj/item/gun/throw/biogun/pickup(mob/user)
+ . = ..()
+ if(!is_vox_private)
+ is_vox_private = TRUE
+ to_chat(user, span_notice("Оружие инициализировало вас, более никто кроме Воксов не сможет им воспользоваться."))
+
+/obj/item/gun/throw/biogun/afterattack__legacy__attackchain(atom/target, mob/living/user, flag, params)
+ if(is_vox_private && !isvox(user))
+ if(prob(20))
+ to_chat(user, span_notice("Оружие отказывается с вами работать и не активируется."))
+ return FALSE
+ . = ..()
+
+/obj/item/gun/throw/biogun/Initialize(mapload)
+ . = ..()
+ update_icon()
+
+/obj/item/gun/throw/biogun/process_chamber()
+ . = ..()
+ update_icon()
+
+/obj/item/gun/throw/biogun/update_icon_state()
+ . = ..()
+ var/num = length(loaded_projectiles) + (to_launch ? 1 : 0)
+ var/inhand_ratio = CEILING((num / max_capacity) * inhand_charge_sections, 1)
+ var/new_item_state = "[initial(item_state)][inhand_ratio]"
+ item_state = new_item_state
+
+/obj/item/gun/throw/biogun/update_overlays()
+ . = ..()
+ var/num = length(loaded_projectiles) + (to_launch ? 1 : 0)
+ if(num)
+ num = min(num, max_capacity)
+ . += "[icon_state]_charge[num]"
+
+/obj/item/gun/throw/biogun/notify_ammo_count()
+ update_icon()
+ var/amount = get_ammocount()
+ if(get_ammocount() >= 1)
+ return span_notice("[src] заряжен [amount]/[max_capacity].")
+ return span_notice("[src] разряжен.")
+
+
+// ============== Существа ==============
+
+/mob/living/simple_animal/hostile/viscerator/vox
+ name = "vox viscerator"
+ icon = 'modular_ss220/antagonists/icons/objects/critter.dmi'
+ faction = list("Vox")
+ mob_biotypes = MOB_ROBOTIC
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ damage_coeff = list(BRUTE = 1, BURN = 0.5, TOX = -1, CLONE = -1, STAMINA = 0, OXY = 0)
+ can_be_on_fire = FALSE
+ fire_damage = 1
+ unsuitable_atmos_damage = 0
+ mob_size = MOB_SIZE_TINY
+ initial_traits = list(TRAIT_FLYING)
+ melee_damage_lower = 10
+ melee_damage_upper = 15
+
+/mob/living/simple_animal/hostile/viscerator/vox/Process_Spacemove(movement_dir)
+ return TRUE
+
+/mob/living/simple_animal/hostile/viscerator/vox/stamina
+ name = "stakikamka"
+ desc = "Небольшое биомеханическое проворное существо на высоких ножках, мешающее и изматывающее тех, кому оно не понравилось."
+ icon_state = "stamina"
+ icon_living = "stamina"
+ density = FALSE
+ obj_damage = 0
+ speed = 0.25
+ melee_damage_type = STAMINA
+ melee_damage_lower = 5
+ melee_damage_upper = 20
+ attacktext = "утомляет"
+
+/mob/living/simple_animal/hostile/viscerator/vox/stamina/death(gibbed)
+ if(prob(30))
+ xgibs(loc)
+ . = ..()
+
+/mob/living/simple_animal/hostile/viscerator/vox/acid
+ name = "acikikid"
+ desc = "Небольшое биомеханическое крабоподобное существо из пасти которого стекает кислота, которую тот наматывает на свои маленькие острые клешни."
+ icon_state = "acid"
+ icon_living = "acid"
+ health = 50
+ maxHealth = 50
+ obj_damage = 20
+ melee_damage_type = BURN
+ melee_damage_lower = 10
+ melee_damage_upper = 30
+ attacktext = "выжигает"
+ mob_size = MOB_SIZE_SMALL
+
+/mob/living/simple_animal/hostile/viscerator/vox/acid/death(gibbed)
+ xgibs(loc)
+ . = ..()
+
+/mob/living/simple_animal/hostile/viscerator/vox/kusaka
+ name = "kusakika"
+ desc = "Маленькое биомеханическое существо с острыми клыкам с половину его тела."
+ icon_state = "kusaka"
+ icon_living = "kusaka"
+ density = FALSE
+ speed = 0.5
+ obj_damage = 0
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ armour_penetration_flat = 30
+ attacktext = "кусает"
+
+/mob/living/simple_animal/hostile/viscerator/vox/kusaka/death(gibbed)
+ if(prob(20))
+ robogibs(loc)
+ . = ..()
+
+/mob/living/simple_animal/hostile/viscerator/vox/taran
+ name = "tarakikan"
+ desc = "Весомое пластинчатое биомеханическое существо."
+ icon_state = "taran"
+ icon_living = "taran"
+ speed = 2
+ health = 100
+ maxHealth = 100
+ obj_damage = 50
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+ armour_penetration_flat = 20
+ attacktext = "таранит"
+ mob_size = MOB_SIZE_HUMAN
+
+/mob/living/simple_animal/hostile/viscerator/vox/taran/death(gibbed)
+ robogibs(loc)
+ . = ..()
+
+/mob/living/simple_animal/hostile/viscerator/vox/tox
+ name = "toxikikic"
+ desc = "Маленькое биомеханическое иглоподобное существо."
+ icon_state = "tox"
+ icon_living = "tox"
+ density = FALSE
+ melee_damage_type = TOX
+ melee_damage_lower = 5
+ melee_damage_upper = 15
+ armour_penetration_flat = 80
+ attacktext = "вонзается"
+
+/mob/living/simple_animal/hostile/viscerator/vox/tox/death(gibbed)
+ xgibs(loc)
+ . = ..()
diff --git a/modular_ss220/antagonists/code/guns/biogun_ammo.dm b/modular_ss220/antagonists/code/guns/biogun_ammo.dm
new file mode 100644
index 000000000000..6610a3d229bc
--- /dev/null
+++ b/modular_ss220/antagonists/code/guns/biogun_ammo.dm
@@ -0,0 +1,87 @@
+/obj/item/biocore
+ name = "biocore"
+ desc = "Острое биоядро с живым организмом внутри. Оно пульсирует и ответно реагирует толчками на каждые взаимодействия."
+ icon = 'modular_ss220/antagonists/icons/guns/vox_guns.dmi'
+ icon_state = "biocore"
+ item_state = "cottoncandy_purple"
+
+ var/mob/living/mob_spawner_type = /mob/living/simple_animal/hostile/creature
+ var/spawn_amount = 1 // сколько в одном ядре
+ var/is_spin = TRUE
+
+ // Дополнительные эффекты при втыкании в гуманоида
+ var/stun = 0
+ var/weaken = 5 SECONDS
+ var/knockdown = 2 SECONDS
+ var/paralyze = 0
+ var/irradiate = 0
+ var/stutter = 5 SECONDS
+ var/slur = 0
+ var/eyeblur = 0
+ var/drowsy = 0
+ var/stamina = 30
+ var/jitter = 10 SECONDS
+ throwforce = 20
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/biocore/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
+ playsound(loc,'sound/weapons/bolathrow.ogg', 50, TRUE)
+ . = ..()
+
+/obj/item/biocore/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ . = ..()
+ spawn_mobs()
+ hurt_impact(hit_atom)
+
+/obj/item/biocore/AltClick(mob/user)
+ . = ..()
+ spawn_mobs()
+
+/obj/item/biocore/proc/spawn_mobs()
+ var/turf/T = get_turf(src)
+ for(var/i in 1 to spawn_amount)
+ var/atom/movable/x = new mob_spawner_type(T)
+ x.admin_spawned = admin_spawned
+ if(prob(50))
+ for(var/j = 1, j <= rand(1, 3), j++)
+ step(x, pick(NORTH,SOUTH,EAST,WEST))
+ do_sparks(5, TRUE, T)
+ qdel(src)
+
+/obj/item/biocore/proc/hurt_impact(atom/hit_atom)
+ if(isliving(hit_atom))
+ var/mob/living/L = hit_atom
+ L.apply_effects(stun, weaken, knockdown, paralyze, irradiate, slur, stutter, eyeblur, drowsy, 0, stamina, jitter)
+
+
+// ============== Ядра ==============
+
+/obj/item/biocore/viscerator
+ name = "biocore (viscerator)"
+ spawn_amount = 3
+ mob_spawner_type = /mob/living/simple_animal/hostile/viscerator/vox
+
+/obj/item/biocore/stamina
+ name = "biocore (stakikamka)"
+ spawn_amount = 3
+ mob_spawner_type = /mob/living/simple_animal/hostile/viscerator/vox/stamina
+
+/obj/item/biocore/acid
+ name = "biocore (acikikid)"
+ spawn_amount = 1
+ mob_spawner_type = /mob/living/simple_animal/hostile/viscerator/vox/acid
+
+/obj/item/biocore/kusaka
+ name = "biocore (kusakika)"
+ spawn_amount = 4
+ mob_spawner_type = /mob/living/simple_animal/hostile/viscerator/vox/kusaka
+
+/obj/item/biocore/taran
+ name = "biocore (tarakikan)"
+ spawn_amount = 1
+ mob_spawner_type = /mob/living/simple_animal/hostile/viscerator/vox/taran
+
+/obj/item/biocore/tox
+ name = "biocore (toxikikic)"
+ spawn_amount = 3
+ mob_spawner_type = /mob/living/simple_animal/hostile/viscerator/vox/tox
diff --git a/modular_ss220/antagonists/code/guns/dartgun.dm b/modular_ss220/antagonists/code/guns/dartgun.dm
new file mode 100644
index 000000000000..ccf46228475e
--- /dev/null
+++ b/modular_ss220/antagonists/code/guns/dartgun.dm
@@ -0,0 +1,164 @@
+/obj/item/gun/syringe/dart_gun
+ name = "dart gun"
+ desc = "Компактный метатель дротиков для доставки химических коктейлей."
+ icon = 'modular_ss220/antagonists/icons/guns/vox_guns.dmi'
+ lefthand_file = 'modular_ss220/antagonists/icons/guns/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/antagonists/icons/guns/inhands/guns_righthand.dmi'
+ icon_state = "dartgun"
+ item_state = "dartgun"
+ var/cartridge_overlay = "dartgun_cartridge_overlay"
+ max_syringes = 5
+ var/list/valid_cartridge_types = list(
+ /obj/item/storage/dart_cartridge,
+ /obj/item/storage/dart_cartridge/combat,
+ /obj/item/storage/dart_cartridge/drugs,
+ /obj/item/storage/dart_cartridge/medical,
+ /obj/item/storage/dart_cartridge/pain,
+ )
+ var/valid_dart_type = /obj/item/reagent_containers/syringe/dart
+ var/obj/item/storage/dart_cartridge/cartridge_loaded
+ var/pixel_y_overlay_div = 5 // сколько у нас делений для спрайта оверлея ("Позиций")
+ var/pixel_y_overlay_offset = 2 // на сколько пикселей смещаем оверлей при полном делении
+ var/is_vox_private = FALSE
+
+/obj/item/gun/syringe/dart_gun/pickup(mob/user)
+ . = ..()
+ if(!is_vox_private)
+ is_vox_private = TRUE
+ to_chat(user, span_notice("Оружие инициализировало вас, более никто кроме Воксов не сможет им воспользоваться."))
+
+/obj/item/gun/syringe/dart_gun/afterattack__legacy__attackchain(atom/target, mob/living/user, flag, params)
+ if(is_vox_private && !isvox(user))
+ if(prob(20))
+ to_chat(user, span_notice("Оружие отказывается с вами работать и не активируется."))
+ return FALSE
+ . = ..()
+
+/obj/item/gun/syringe/dart_gun/Destroy()
+ qdel(cartridge_loaded)
+ . = ..()
+
+/obj/item/gun/syringe/dart_gun/update_overlays()
+ . = ..()
+ if(cartridge_loaded)
+ var/pixel_y_offset = 0
+ var/num = length(syringes)
+ if(num)
+ pixel_y_offset = -(pixel_y_overlay_div - pixel_y_overlay_div * num / max_syringes) * pixel_y_overlay_offset
+ . += image(icon = icon, icon_state = cartridge_overlay, pixel_y = pixel_y_offset)
+ if(cartridge_loaded.overlay_state_color)
+ . += image(icon = icon, icon_state = "[cartridge_overlay]_[cartridge_loaded.overlay_state_color]", pixel_y = pixel_y_offset)
+ . += icon_state
+
+/obj/item/gun/syringe/dart_gun/attackby__legacy__attackchain(obj/item/A, mob/user, params, show_msg)
+ if(cartridge_loaded)
+ for(var/hold_type in cartridge_loaded.can_hold)
+ if(!istype(A, hold_type))
+ continue
+ if(insert_syringe_to_cartridge(A) && user && user.unEquip(A))
+ to_chat(user, span_notice("Вы загрузили [A] в [cartridge_loaded] в [src]!"))
+ return ..()
+ to_chat(user, "Картридж [src] полон!")
+ return FALSE
+ else
+ for(var/cartridge_type in valid_cartridge_types)
+ if(istype(A, cartridge_type))
+ if("[A.type]" != "[cartridge_type]") // Исключаем сабтипы
+ continue
+ if(user && !user.unEquip(A))
+ return TRUE
+ to_chat(user, span_notice("Вы вставили [A] в [src]!"))
+ cartridge_load(A)
+ return ..()
+ if(!chambered.BB && istype(A, valid_dart_type) && length(syringes) < max_syringes)
+ return ..()
+ if(user)
+ to_chat(user, "[A] не вмещается в [src]!")
+ return TRUE
+
+/obj/item/gun/syringe/dart_gun/proc/insert_syringe_to_cartridge(obj/item/syringe)
+ if(length(syringes) >= max_syringes)
+ return FALSE
+ syringe.forceMove(cartridge_loaded)
+ syringes.Add(syringe)
+ process_chamber()
+ return TRUE
+
+/obj/item/gun/syringe/dart_gun/proc/cartridge_load(obj/item/A, mob/user)
+ A.forceMove(src)
+ cartridge_loaded = A
+ for(var/obj/item/I in A.contents)
+ syringes.Add(I)
+ process_chamber()
+
+/obj/item/gun/syringe/dart_gun/proc/cartridge_unload(mob/user)
+ if(!cartridge_loaded)
+ return FALSE
+ user.put_in_hands(cartridge_loaded)
+ //user.unEquip(cartridge_loaded)
+ syringes.Cut()
+ cartridge_loaded.update_icon()
+ cartridge_loaded = null
+ update_icon()
+
+/obj/item/gun/syringe/dart_gun/attack_self__legacy__attackchain(mob/living/user)
+ if(cartridge_loaded)
+ playsound(src, 'modular_ss220/antagonists/sound/guns/m79_unload.ogg', 50, 1)
+ to_chat(user, span_notice("Вы выгрузили [cartridge_loaded] с [src]."))
+ cartridge_unload(user)
+ process_chamber()
+ return TRUE
+ return ..()
+
+/obj/item/gun/syringe/dart_gun/process_chamber()
+ . = ..()
+ if(!cartridge_loaded)
+ update_icon()
+ return
+
+ // Вышвыриваем картридж
+ if(!length(syringes))
+ var/turf/current_turf = get_turf(src)
+ cartridge_loaded.forceMove(current_turf)
+ cartridge_loaded.throw_at(target = current_turf, range = 3, speed = 1)
+ cartridge_loaded.pixel_x = rand(-10, 10)
+ cartridge_loaded.pixel_y = rand(-4, 16)
+ cartridge_loaded.update_icon()
+ cartridge_loaded = null
+ update_icon()
+ playsound(src, 'modular_ss220/antagonists/sound/guns/m79_break_open.ogg', 50, 1)
+ return
+
+ playsound(src, 'modular_ss220/antagonists/sound/guns/m79_reload.ogg', 50, 1)
+ update_icon()
+
+
+// ============== Шприцеметы ==============
+
+/obj/item/gun/syringe/dart_gun/extended
+ name = "extended dart gun"
+ desc = "Расширенный метатель дротиков и шприцов для доставки химических коктейлей."
+ icon_state = "dartgun_ext"
+ valid_cartridge_types = list(
+ /obj/item/storage/dart_cartridge,
+ /obj/item/storage/dart_cartridge/combat,
+ /obj/item/storage/dart_cartridge/drugs,
+ /obj/item/storage/dart_cartridge/medical,
+ /obj/item/storage/dart_cartridge/pain,
+ /obj/item/storage/dart_cartridge/extended
+ )
+
+/obj/item/gun/syringe/dart_gun/big
+ name = "capacious dart gun"
+ desc = "Вместительный метатель дротиков для доставки химических коктейлей."
+ icon_state = "dartgun_big"
+ max_syringes = 10
+ valid_cartridge_types = list(
+ /obj/item/storage/dart_cartridge,
+ /obj/item/storage/dart_cartridge/combat,
+ /obj/item/storage/dart_cartridge/drugs,
+ /obj/item/storage/dart_cartridge/medical,
+ /obj/item/storage/dart_cartridge/pain,
+ /obj/item/storage/dart_cartridge/big,
+ /obj/item/storage/dart_cartridge/big/random
+ )
diff --git a/modular_ss220/antagonists/code/guns/dartgun_ammo.dm b/modular_ss220/antagonists/code/guns/dartgun_ammo.dm
new file mode 100644
index 000000000000..f7b13c210da6
--- /dev/null
+++ b/modular_ss220/antagonists/code/guns/dartgun_ammo.dm
@@ -0,0 +1,217 @@
+/obj/item/storage/dart_cartridge
+ name = "dart cartridge"
+ desc = "Подставка для дротиков."
+ icon = 'modular_ss220/antagonists/icons/guns/ammo.dmi'
+ icon_state = "darts-0"
+ var/icon_state_base = "darts"
+ var/overlay_state = "darts_overlay"
+ var/overlay_state_color
+ item_state = "rcdammo"
+ origin_tech = "materials=2"
+ storage_slots = 5
+ can_hold = list(
+ /obj/item/reagent_containers/syringe/dart
+ )
+ var/list/dart_fill_types = list() // Каким дротиком заполним?
+ var/dart_fill_num = 5 // Сколько дротиков заполним
+ var/dart_overlay_num = 5 // Максимальное отображение дротиков на оверлее
+
+/obj/item/storage/dart_cartridge/update_icon()
+ . = ..()
+ var/num = length(contents)
+ if(!num)
+ icon_state = "[icon_state_base]-0"
+ else if(num > dart_overlay_num)
+ icon_state = "[icon_state_base]-[dart_overlay_num]"
+ else
+ icon_state = "[icon_state_base]-[num]"
+ return TRUE
+
+/obj/item/storage/dart_cartridge/update_overlays()
+ . = ..()
+ if(overlay_state_color)
+ . += "[overlay_state]_[overlay_state_color]"
+
+/obj/item/storage/dart_cartridge/populate_contents()
+ if(length(dart_fill_types))
+ for(var/i in 1 to dart_fill_num+1) //На один больше чтобы фулл заряжался + 1 внутрь
+ var/dart_type = length(dart_fill_types) == 1? dart_fill_types[1] : pick(dart_fill_types)
+ new dart_type(src)
+ update_icon()
+
+
+/obj/item/reagent_containers/syringe/dart
+ name = "dart"
+ desc = "Дротик содержащий химические коктейли."
+ icon = 'modular_ss220/antagonists/icons/objects/dart.dmi'
+ amount_per_transfer_from_this = 15
+ volume = 15
+
+
+// ============= Картриджи =============
+
+/obj/item/storage/dart_cartridge/extended
+ name = "extended dart cartridge"
+ desc = "Расширенная подставка для дротиков и шприцов."
+ overlay_state_color = "ext"
+ can_hold = list(
+ /obj/item/reagent_containers/syringe,
+ /obj/item/reagent_containers/syringe/dart
+ )
+
+/obj/item/storage/dart_cartridge/big
+ name = "capacious dart cartridge"
+ desc = "Увеличенная подставка для дротиков."
+ overlay_state_color = "big"
+ storage_slots = 10
+ dart_fill_num = 10
+
+/obj/item/storage/dart_cartridge/combat
+ name = "combat dart cartridge"
+ desc = "Подставка для боевых дротиков для нанесения повреждений."
+ overlay_state_color = "red"
+ dart_fill_types = list(/obj/item/reagent_containers/syringe/dart/combat)
+
+/obj/item/storage/dart_cartridge/medical
+ name = "medical dart cartridge"
+ overlay_state_color = "teal"
+ desc = "Подставка для полезных дротиков для восстановления."
+ dart_fill_types = list(
+ /obj/item/reagent_containers/syringe/dart/medical,
+ /obj/item/reagent_containers/syringe/dart/medical,
+ /obj/item/reagent_containers/syringe/dart/medical,
+ /obj/item/reagent_containers/syringe/dart/medical/tainted,
+ /obj/item/reagent_containers/syringe/dart/medical/tainted,
+ /obj/item/reagent_containers/syringe/dart/medical/heal,
+ )
+
+/obj/item/storage/dart_cartridge/pain
+ name = "pain dart cartridge"
+ overlay_state_color = "yellow"
+ desc = "Подставка для вредных дротиков, приносящих боль и страдания."
+ dart_fill_types = list(/obj/item/reagent_containers/syringe/dart/pain)
+
+/obj/item/storage/dart_cartridge/drugs
+ name = "drugs dart cartridge"
+ overlay_state_color = "purple"
+ desc = "Подставка для вредных дротиков-наркотиков."
+ dart_fill_types = list(/obj/item/reagent_containers/syringe/dart/drugs)
+
+/obj/item/storage/dart_cartridge/big/random
+ name = "big random dart cartridge"
+ desc = "Случайный набор дротиков с химикатами."
+ dart_fill_types = list(
+ /obj/item/reagent_containers/syringe/dart/combat,
+ /obj/item/reagent_containers/syringe/dart/medical,
+ /obj/item/reagent_containers/syringe/dart/pain,
+ /obj/item/reagent_containers/syringe/dart/drugs,
+ /obj/item/reagent_containers/syringe/dart/pancuronium,
+ /obj/item/reagent_containers/syringe/dart/sarin,
+ /obj/item/reagent_containers/syringe/dart/capulettium,
+ /obj/item/reagent_containers/syringe/dart/bioterror,
+ /obj/item/reagent_containers/syringe/dart/heparin,
+ /obj/item/reagent_containers/syringe/dart/calomel,
+ /obj/item/reagent_containers/syringe/dart/epinephrine,
+ /obj/item/reagent_containers/syringe/dart/charcoal,
+ /obj/item/reagent_containers/syringe/dart/antiviral
+ )
+
+// ============= Шприцы =============
+
+/obj/item/reagent_containers/syringe/dart/combat
+ name = "combat dart"
+ desc = "Боевой дротик, заставляющий цель потерять равновесие и впоследствии обездвижиться."
+ list_reagents = list("space_drugs" = 5, "ether" = 5, "haloperidol" = 5)
+
+/obj/item/reagent_containers/syringe/dart/pain
+ name = "pain dart"
+ desc = "Зудящий порошок с примесью гистамина для страданий."
+ list_reagents = list("itching_powder" = 10, "histamine" = 5)
+
+/obj/item/reagent_containers/syringe/dart/drugs
+ name = "pain dart"
+ desc = "Отвратительная смесь наркотиков, вызывающая галлюцинации, потерю координации и рассудка."
+ list_reagents = list(
+ "space_drugs" = 5, "lsd" = 5, "fliptonium" = 2, "jenkem" = 2, "happiness" = 1)
+
+/obj/item/reagent_containers/syringe/dart/antiviral
+ name = "dart (spaceacillin)"
+ desc = "Содержит противовирусные вещества."
+ list_reagents = list("spaceacillin" = 15)
+
+/obj/item/reagent_containers/syringe/dart/charcoal
+ name = "dart (charcoal)"
+ desc = "Содержит древесный уголь для лечения токсинов и повреждений от них."
+ list_reagents = list("charcoal" = 15)
+
+/obj/item/reagent_containers/syringe/dart/epinephrine
+ name = "dart (Epinephrine)"
+ desc = "Содержит адреналин для стабилизации пациентов."
+ list_reagents = list("epinephrine" = 15)
+
+/obj/item/reagent_containers/syringe/dart/calomel
+ name = "dart (calomel)"
+ desc = "Содержит токсичный каломель для очистки от других веществ в организме."
+ list_reagents = list("calomel" = 15)
+
+/obj/item/reagent_containers/syringe/dart/heparin
+ name = "dart (heparin)"
+ desc = "Содержит гепарин, антикоагулянт крови."
+ list_reagents = list("heparin" = 15)
+
+/obj/item/reagent_containers/syringe/dart/bioterror
+ name = "bioterror dart"
+ desc = "Содержит несколько парализующих реагентов."
+ list_reagents = list("neurotoxin" = 5, "capulettium" = 5, "sodium_thiopental" = 5)
+
+/obj/item/reagent_containers/syringe/dart/capulettium
+ name = "capulettium dart"
+ desc = "Для упокоения целей."
+ list_reagents = list("capulettium" = 15)
+
+/obj/item/reagent_containers/syringe/dart/sarin
+ name = "toxin dart"
+ desc = "Смертельный нейротоксин в малых дозах."
+ list_reagents = list("sarin" = 15)
+
+/obj/item/reagent_containers/syringe/dart/pancuronium
+ name = "pancuronium dart"
+ desc = "Мощный парализующий яд"
+ list_reagents = list("pancuronium" = 15)
+
+
+// ============= Шприцы - Медицинские =============
+
+/obj/item/reagent_containers/syringe/dart/medical
+ name = "medical dart"
+ desc = "Медицинский дротик для восстановления большинства повреждений."
+ list_reagents = list("silver_sulfadiazine" = 5, "styptic_powder" = 5, "charcoal" = 5)
+
+// 1 уровень
+/obj/item/reagent_containers/syringe/dart/medical/tainted
+ name = "tainted medical dart"
+ desc = "На вид будто этой капсулой зачерпнули из первичного бульона. Непонятно кто это сделал, но кажется оно должно лечить. Пахнет мерзко."
+ list_reagents = list("menthol" = 3, "doctorsdelight" = 3, "synthnsoda" = 3, "tomatojuice" = 3, "milk" = 3)
+
+// 2 уровень
+/obj/item/reagent_containers/syringe/dart/medical/heal
+ name = "heal medical dart"
+ desc = "Медицинский дротик для лечения тяжелых травм."
+ list_reagents = list("silver_sulfadiazine" = 5, "styptic_powder" = 5, "synthflesh" = 5)
+
+/obj/item/reagent_containers/syringe/dart/medical/stabilizing
+ name = "stabilizing medical dart"
+ desc = "Медицинский дротик для стабилизации пациента."
+ list_reagents = list("epinephrine" = 5, "salglu_solution" = 5, "weak_omnizine" = 5)
+
+// 3 уровень (1 час)
+/obj/item/reagent_containers/syringe/dart/medical/advanced
+ name = "advanced medical dart"
+ desc = "Медицинский дротик стимулирующий быструю регенерацию."
+ list_reagents = list("bicaridine" = 5, "kelotane" = 5, "omnizine" = 5)
+
+// 4 уровень (2 час)
+/obj/item/reagent_containers/syringe/dart/medical/combat
+ name = "combat medical dart"
+ desc = "передовой дротик с эксперементальными стимулянтами."
+ list_reagents = list("surge_plus" = 5, "syndicate_nanites" = 5)
diff --git a/modular_ss220/antagonists/code/guns/spikegun.dm b/modular_ss220/antagonists/code/guns/spikegun.dm
new file mode 100644
index 000000000000..5f3652be0379
--- /dev/null
+++ b/modular_ss220/antagonists/code/guns/spikegun.dm
@@ -0,0 +1,115 @@
+/// Шипомет перезаряжаемый через "вокс батарейки"
+/obj/item/gun/energy/spike
+ name = "\improper Vox spike gun"
+ desc = "Оружие причудливой формы с яркими пурпурными энергетическими светочами. Рукоять предназначена для когтистой руки. Выстреливает энергетическими кристаллами."
+ icon = 'modular_ss220/antagonists/icons/guns/vox_guns.dmi'
+ lefthand_file = 'modular_ss220/antagonists/icons/guns/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/antagonists/icons/guns/inhands/guns_righthand.dmi'
+ icon_state = "spike"
+ item_state = "spike"
+ charge_sections = 4
+ inhand_charge_sections = 4
+ w_class = WEIGHT_CLASS_NORMAL
+ fire_sound_text = "air gap"
+ can_suppress = FALSE
+ burst_size = 3 // выстреливает всегда очередью
+ shaded_charge = TRUE
+ can_charge = FALSE
+ charge_delay = 4
+ cell_type = /obj/item/stock_parts/cell/vox_spike
+ ammo_type = list(/obj/item/ammo_casing/energy/vox_spike)
+ var/can_reload = TRUE
+ var/is_vox_private = FALSE
+
+/obj/item/gun/energy/spike/pickup(mob/user)
+ . = ..()
+ if(!is_vox_private)
+ is_vox_private = TRUE
+ to_chat(user, span_notice("Оружие инициализировало вас, более никто кроме Воксов не сможет им воспользоваться."))
+
+/obj/item/gun/energy/spike/afterattack__legacy__attackchain(atom/target, mob/living/user, flag, params)
+ if(is_vox_private && !isvox(user))
+ if(prob(20))
+ to_chat(user, span_notice("Оружие отказывается с вами работать и не активируется."))
+ return FALSE
+ . = ..()
+
+/obj/item/gun/energy/spike/emp_act()
+ return
+
+// Перезарядка батареями
+/obj/item/gun/energy/spike/attackby__legacy__attackchain(obj/item/I, mob/user, params)
+ if(can_reload && istype(I, cell_type) && user && user.unEquip(I))
+ to_chat(user, span_notice("Вы заменили [I] в [src]!"))
+ if(cell)
+ user.put_in_hands(cell)
+ I.forceMove(src)
+ cell = I
+ on_recharge()
+ update_icon()
+ playsound(src, 'modular_ss220/antagonists/sound/guns/m79_break_open.ogg', 50, 1)
+ return TRUE
+ . = ..()
+
+/obj/item/gun/energy/spike/update_icon_state()
+ . = ..()
+ var/inhand_ratio = CEILING((cell.charge / cell.maxcharge) * inhand_charge_sections, 1)
+ var/new_item_state = "[initial(item_state)][inhand_ratio]"
+ item_state = new_item_state
+
+
+/// Самозаряжаемый шипомет, шипы чуть-чуть слабее, но зато самовосстанавливаются и лучше проходят через броню.
+/obj/item/gun/energy/spike/long
+ name = "\improper Vox spike longgun"
+ desc = "Оружие причудливой формы с яркими пурпурными энергетическими светочами. Рукоять предназначена для когтистой руки. Выстреливает длинными энергетическими самовосстановимыми кристаллами с увеличенной проникающей способностью."
+ icon_state = "spike_long"
+ item_state = "spike_long"
+ charge_sections = 6
+ inhand_charge_sections = 6
+ selfcharge = TRUE
+ charge_delay = 4
+ ammo_type = list(/obj/item/ammo_casing/energy/vox_spike/long)
+
+/obj/item/gun/energy/spike/long/process()
+ if(selfcharge)
+ if(charge_tick < charge_delay)
+ return ..()
+ playsound(src, 'modular_ss220/antagonists/sound/guns/m79_reload.ogg', 25, 1)
+ . = ..()
+
+
+/// Шипомет заряжаемый за счет нутриентов ВОКСа или крови и мяса гуманоида другой расы. Сильные и болезненные шипы, но всего 4.
+/// Батарея несъемная.
+/obj/item/gun/energy/spike/bio
+ name = "\improper Vox spike biogun"
+ desc = "Оружие причудливой формы с шипами-трубками для нанизывания на руку. Рукоять предназначена для когтистой руки и имеет заостренные полые шипы. Выстреливает большими энергетическими распадающимися заостренными кристаллами, выматывающие цель и рикошетящую о поверхность."
+ icon_state = "spike_bio"
+ item_state = "spike_bio"
+ w_class = WEIGHT_CLASS_HUGE
+ charge_sections = 4
+ inhand_charge_sections = 4
+ ammo_type = list(/obj/item/ammo_casing/energy/vox_spike/big)
+ selfcharge = TRUE
+ can_reload = FALSE
+ charge_delay = 8
+ var/nutrition_cost = 20 // Сколько нутриентов тратится за 1 тик
+ var/brute_cost = 5 // Цена за то что ты не вокс
+ var/stamine_cost = 20 // Цена за то что ты не вокс
+
+/obj/item/gun/energy/spike/bio/process()
+ if(selfcharge)
+ if(!ishuman(loc))
+ return FALSE
+ if(charge_tick < charge_delay)
+ return ..()
+ var/mob/living/carbon/human/user = loc
+ if(user.nutrition <= NUTRITION_LEVEL_HYPOGLYCEMIA)
+ return ..()
+ user.adjust_nutrition(-nutrition_cost)
+ if(!isvox(user))
+ user.adjustBruteLoss(brute_cost)
+ user.adjustStaminaLoss(stamine_cost)
+ playsound(src, 'modular_ss220/antagonists/sound/guns/m79_reload.ogg', 25, 1)
+
+ . = ..()
+
diff --git a/modular_ss220/antagonists/code/guns/spikegun_ammo.dm b/modular_ss220/antagonists/code/guns/spikegun_ammo.dm
new file mode 100644
index 000000000000..1a66e3165386
--- /dev/null
+++ b/modular_ss220/antagonists/code/guns/spikegun_ammo.dm
@@ -0,0 +1,64 @@
+/obj/item/stock_parts/cell/vox_spike
+ name = "\improper vox spike power cell"
+ desc = "Зарядная пурпурная светящаяся стандартная ячейка для шипометов."
+ icon = 'modular_ss220/antagonists/icons/guns/ammo.dmi'
+ icon_state = "spike_cell"
+ maxcharge = 1000
+
+
+/obj/item/ammo_casing/energy/vox_spike
+ name = "шип"
+ desc = "Маленький самозаряжающийся кристаллический шип испускающий энергетический вайб."
+ muzzle_flash_effect = null
+ e_cost = 100
+ delay = 3 //and delay has to be stored here on energy guns
+ select_name = "spike"
+ fire_sound = 'modular_ss220/antagonists/sound/guns/gun_es4.ogg'
+ projectile_type = /obj/item/projectile/bullet/vox_spike
+ e_cost = 25 // 1000 / (50*3) = ~13 выстрелов
+
+/obj/item/projectile/bullet/vox_spike
+ name = "шип"
+ desc = "Маленький самозаряжающийся кристаллический шип испускающий энергетический вайб."
+ icon_state = "magspear"
+ armour_penetration_flat = 20
+ damage = 7
+ knockdown = 0
+ var/bleed_loss = 5
+
+/obj/item/projectile/bullet/vox_spike/on_hit(atom/target, blocked = 0)
+ if((blocked < 100) && ishuman(target))
+ var/mob/living/carbon/human/H = target
+ H.bleed(bleed_loss)
+ . = ..()
+
+
+/obj/item/ammo_casing/energy/vox_spike/long
+ projectile_type = /obj/item/projectile/bullet/vox_spike/long
+ e_cost = 50 // 1000 / (50*3) = 6 выстрелов
+
+/obj/item/projectile/bullet/vox_spike/long
+ damage = 5
+ armour_penetration_flat = 60
+ jitter = 1 SECONDS
+ forcedodge = 3
+ bleed_loss = 3
+
+
+/obj/item/ammo_casing/energy/vox_spike/big
+ projectile_type = /obj/item/projectile/bullet/vox_spike/big
+ e_cost = 80 // 1000 / (80*3) = 4 выстрела
+
+/obj/item/projectile/bullet/vox_spike/big
+ damage = 15
+ stamina = 50
+ stutter = 2 SECONDS
+ jitter = 4 SECONDS
+ speed = 2
+ bleed_loss = 10
+
+ tile_dropoff = 1 //how much damage should be decremented as the bullet moves
+ tile_dropoff_s = 2.5 //same as above but for stamina
+
+ ricochets_max = 3
+ ricochet_chance = 50
diff --git a/modular_ss220/antagonists/code/landmarks.dm b/modular_ss220/antagonists/code/landmarks.dm
new file mode 100644
index 000000000000..b0626d724dc9
--- /dev/null
+++ b/modular_ss220/antagonists/code/landmarks.dm
@@ -0,0 +1,8 @@
+/obj/effect/landmark/spawner/vox_raider
+ name = "Vox Raider"
+ icon = 'modular_ss220/antagonists/icons/landmark.dmi'
+ icon_state = "vox_raider"
+
+/obj/effect/landmark/spawner/vox_raider/Initialize(mapload)
+ . = ..()
+ GLOB.raider_spawn += src
diff --git a/modular_ss220/antagonists/code/mind/memory_edit.dm b/modular_ss220/antagonists/code/mind/memory_edit.dm
new file mode 100644
index 000000000000..0b4c90df1250
--- /dev/null
+++ b/modular_ss220/antagonists/code/mind/memory_edit.dm
@@ -0,0 +1,147 @@
+/datum/mind/proc/clear_antag_datum(datum/antagonist/antag_datum_to_clear)
+ if(!has_antag_datum(antag_datum_to_clear))
+ return
+
+ remove_antag_datum(antag_datum_to_clear)
+ var/antag_name = initial(antag_datum_to_clear.name)
+ log_admin("[key_name(usr)] has removed [antag_name] from [key_name(current)]")
+ message_admins("[key_name_admin(usr)] has removed [antag_name] from [key_name_admin(current)]")
+
+
+/datum/mind/Topic(href, href_list)
+ if(!check_rights(R_ADMIN))
+ return
+
+ if(href_list["blood_brother"])
+ switch(href_list["blood_brother"])
+ if("clear")
+ clear_antag_datum(/datum/antagonist/blood_brother)
+ if("make")
+ var/datum/antagonist/blood_brother/antag_datum = new
+ if(!antag_datum.admin_add(usr, src))
+ qdel(antag_datum)
+
+ if(href_list["vox_raider"])
+ switch(href_list["vox_raider"])
+ if("clear")
+ clear_antag_datum(/datum/antagonist/vox_raider)
+ if("make")
+ var/datum/antagonist/vox_raider/antag_datum = new
+ if(!antag_datum.admin_add(usr, src))
+ qdel(antag_datum)
+ if("landmark")
+ var/picked_landmark = pick(GLOB.raider_spawn)
+ var/turf/loc_spawn = get_turf(picked_landmark)
+ current.forceMove(loc_spawn)
+
+ . = ..()
+
+/datum/mind/proc/memory_edit_blood_brother()
+ . = _memory_edit_header("blood brother")
+ if(has_antag_datum(/datum/antagonist/blood_brother))
+ . += "BLOOD BROTHER|Remove"
+ else
+ . += "Make Blood Brother"
+
+ . += _memory_edit_role_enabled(ROLE_BLOOD_BROTHER)
+
+/datum/mind/proc/memory_edit_vox_raider()
+ . = _memory_edit_header("vox raider")
+ if(has_antag_datum(/datum/antagonist/vox_raider))
+ . += "VOX RAIDER|Remove"
+ . += " To Vox Base."
+ else
+ . += "Make Vox Raider"
+
+ . += _memory_edit_role_enabled(ROLE_VOX_RAIDER)
+
+// Если ОФФы добавят нового антагониста с разумом, то потребуется смещение (кто-нибудь дайте мне разума)
+// Используется в /datum/admins/proc/one_click_antag()
+/datum/admins/Topic(href, href_list)
+ . = ..()
+ if(href_list["makeAntag"])
+ switch(href_list["makeAntag"])
+ if("8")
+ log_admin("[key_name(usr)] has spawned a blood brothers.")
+ if(!makeBloodBrothersTeam())
+ to_chat(usr, "К сожалению, недостаточно кандидатов.")
+ if("9")
+ log_admin("[key_name(usr)] has spawned a vox raiders.")
+ if(!makeVoxRaidersTeam())
+ to_chat(usr, "К сожалению, недостаточно кандидатов.")
+
+
+/datum/admins/proc/makeBloodBrothersTeam()
+ var/confirm = alert("Создать новую команду?", "Подтверждение", "Да", "Нет")
+ if(confirm != "Да")
+ return FALSE
+
+ var/amount = input("Размер команды (1-20)?", "Подтверждение")
+ if(!amount || amount > 20 || amount <= 0)
+ return FALSE
+
+ var/datum/game_mode/antag_mix/temp = new
+ if(GLOB.configuration.gamemode.prevent_mindshield_antags)
+ temp.restricted_jobs += temp.protected_jobs
+ var/datum/antagonist/blood_brother/antag_datum = new
+ var/list/mob/living/carbon/human/candidates = list()
+ for(var/mob/living/carbon/human/applicant in GLOB.player_list)
+ if(CandCheck(ROLE_BLOOD_BROTHER, applicant, temp))
+ candidates += applicant
+ if(!length(candidates))
+ return FALSE
+ qdel(antag_datum)
+
+ var/num = min(length(candidates), amount)
+ var/list/assigned = list()
+ for(var/i = 0, i < num, i++)
+ if(i >= amount)
+ break
+ var/H = pick(candidates)
+ assigned.Add(H)
+ candidates.Remove(H)
+
+ new /datum/team/blood_brothers_team(assigned, TRUE)
+
+ log_admin("[key_name(owner)] tried making Blood Brothers with One-Click-Antag")
+ message_admins("[key_name_admin(owner)] tried making Blood Brothers with One-Click-Antag")
+
+
+/datum/admins/proc/makeVoxRaidersTeam()
+ var/confirm = alert("Создать новую команду?", "Подтверждение", "Да", "Нет")
+ if(confirm != "Да")
+ return FALSE
+
+ var/amount = input("Размер команды (1-20)?", "Подтверждение")
+ if(!amount || amount > 20 || amount <= 0)
+ return FALSE
+
+ var/datum/game_mode/antag_mix/temp = new
+ if(GLOB.configuration.gamemode.prevent_mindshield_antags)
+ temp.restricted_jobs += temp.protected_jobs
+
+ var/datum/antagonist/vox_raider/antag_datum = new
+ var/list/mob/living/carbon/human/candidates = list()
+ for(var/mob/living/carbon/human/applicant in GLOB.player_list)
+ if(CandCheck(ROLE_VOX_RAIDER, applicant, temp))
+ candidates += applicant
+ if(!length(candidates))
+ return FALSE
+
+ var/num = min(length(candidates), amount)
+ var/list/assigned = list()
+ for(var/i = 0, i < num, i++)
+ if(i >= amount)
+ break
+ var/H = pick(candidates)
+ assigned.Add(H)
+ candidates.Remove(H)
+
+ antag_datum.offer_to_equip(owner, assigned)
+ qdel(antag_datum)
+
+ new /datum/team/vox_raiders(assigned, TRUE)
+
+ log_admin("[key_name(owner)] tried making Vox Raiders with One-Click-Antag")
+ message_admins("[key_name_admin(owner)] tried making Vox Raiders with One-Click-Antag")
+ return TRUE
diff --git a/modular_ss220/antagonists/code/morph/morph.dm b/modular_ss220/antagonists/code/morph/morph.dm
new file mode 100644
index 000000000000..9b241bbf3faa
--- /dev/null
+++ b/modular_ss220/antagonists/code/morph/morph.dm
@@ -0,0 +1,18 @@
+#define MORPHS_ANNOUNCE_THRESHOLD 7
+
+GLOBAL_VAR_INIT(MORPHS_NUMBER, 0)
+GLOBAL_VAR_INIT(MORPHS_ANNOUNCED, FALSE)
+
+/mob/living/simple_animal/hostile/morph/Initialize(mapload)
+ . = ..()
+ GLOB.MORPHS_NUMBER++
+ if((GLOB.MORPHS_NUMBER > MORPHS_ANNOUNCE_THRESHOLD) && !GLOB.MORPHS_ANNOUNCED)
+ GLOB.major_announcement.Announce("На борту [station_name()] обнаружены множественные биологические сигнатуры морфов. Всему персоналу надлежит немедленно приступить к сдерживанию.", "ВНИМАНИЕ: Обнаружена биоугроза.", 'sound/effects/siren-spooky.ogg', new_sound2 = 'sound/AI/outbreak_xeno.ogg')
+ GLOB.MORPHS_ANNOUNCED = TRUE
+
+
+/mob/living/simple_animal/hostile/morph/death(gibbed)
+ . = ..()
+
+ if(.)
+ GLOB.MORPHS_NUMBER--
diff --git a/modular_ss220/antagonists/code/objectives.dm b/modular_ss220/antagonists/code/objectives.dm
new file mode 100644
index 000000000000..ef8d445429dc
--- /dev/null
+++ b/modular_ss220/antagonists/code/objectives.dm
@@ -0,0 +1,128 @@
+/datum/objective/is_invalid_target(datum/mind/possible_target)
+ . = ..()
+ if(.)
+ return
+ if(team)
+ for(var/datum/antagonist/target_datum in possible_target.antag_datums)
+ if(team == target_datum.get_team())
+ return TARGET_INVALID_SAME_TEAM
+
+/datum/objective/raider_steal
+ name = "Raider theft"
+ needs_target = FALSE
+ /// Сколько ценностей надо украсть
+ var/precious_amount = 30
+ /// На сколько ценность должна быть "цена" чтобы её засчитать
+ var/precious_value = 200
+ /// Сколько нужно украсть дополнительных ценностей в зависимости от количества людей в игре
+ var/dynamic_amount = 10
+ /// Каждый X игроков добавляем доп. число ценностей
+ var/dynamic_player = 15
+
+/datum/objective/raider_steal/update_explanation_text()
+ explanation_text = "Соберите [precious_amount] ценностей, у каждой из которых цена минимум на [precious_value] кикиридитов. Все ценности должны быть приняты Расчичетчикиком."
+
+/datum/objective/raider_steal/New(text, datum/team/team_to_join)
+ . = ..()
+ generate_amount_goal()
+
+/datum/objective/raider_steal/proc/generate_amount_goal()
+ var/num = 1
+ for(var/mob/new_player/P in GLOB.player_list)
+ if(P.client && P.ready)
+ num++
+ precious_amount += round((num / dynamic_player) * dynamic_amount)
+ update_explanation_text()
+ return precious_amount
+
+/datum/objective/raider_steal/check_completion()
+ var/list_count = 0
+ var/obj/machinery/vox_trader/trader = locate() in GLOB.machines
+ if(!trader)
+ return
+ trader.synchronize_traders_stats()
+ for(var/I in trader.precious_collected_dict)
+ list_count += trader.precious_collected_dict[I]["count"]
+ if(list_count >= precious_amount)
+ return TRUE
+ return FALSE
+
+/datum/objective/raider_entirety_steal
+ name = "Raider entirety theft"
+ needs_target = FALSE
+ /// Общая сумма ценностей
+ var/precious_value = 50000
+ /// Сколько нужно украсть дополнительных ценностей на каждого игрока
+ var/dynamic_value = 750
+
+/datum/objective/raider_entirety_steal/update_explanation_text()
+ explanation_text = "Соберите ценностей на сумму [precious_value]. Все ценности должны быть приняты Расчичетчикиком."
+
+/datum/objective/raider_entirety_steal/New(text, datum/team/team_to_join)
+ . = ..()
+ generate_value_goal()
+
+/datum/objective/raider_entirety_steal/proc/generate_value_goal()
+ var/num = 1
+ var/precious_amount
+ for(var/mob/new_player/P in GLOB.player_list)
+ if(P.client && P.ready)
+ num++
+ precious_amount += num * dynamic_value
+ update_explanation_text()
+ return precious_amount
+
+/datum/objective/raider_entirety_steal/check_completion()
+ var/value_sum = 0
+ for(var/obj/machinery/vox_trader/trader in GLOB.machines)
+ value_sum += trader.all_values_sum
+ if(value_sum >= precious_value)
+ return TRUE
+ return FALSE
+
+
+/datum/objective/raider_collection_access
+ name = "Raider access collect"
+ needs_target = FALSE
+ /// Сколько доступов надо украсть
+ var/access_amount
+
+/datum/objective/raider_collection_access/update_explanation_text()
+ explanation_text = "Соберите [access_amount] уникальных доступов. Все доступы должны быть приняты Расчичетчикиком."
+
+/datum/objective/raider_collection_access/New(text, datum/team/team_to_join)
+ . = ..()
+ access_amount = length(get_all_accesses())
+ update_explanation_text()
+
+/datum/objective/raider_collection_access/check_completion()
+ for(var/obj/machinery/vox_trader/trader in GLOB.machines)
+ if(length(trader.collected_access_list) >= access_amount)
+ return TRUE
+ return FALSE
+
+
+/datum/objective/raider_collection_tech
+ name = "Raider technology collect"
+ needs_target = FALSE
+ var/tech_amount = 9 // Всего в игре технологий (12): 9 обычных, 1 комбат, 1 нелегал, 1 абдуктор.
+ var/tech_min_level = 7 // 7-8 - максимум для обычных технологий, не считая гейтов и т.п.
+
+/datum/objective/raider_collection_tech/update_explanation_text()
+ explanation_text = "Соберите [tech_amount] уникальных технологий [tech_min_level] или больше уровня. Все технологии должны быть приняты Расчичетчикиком."
+
+/datum/objective/raider_collection_tech/New(text, datum/team/team_to_join)
+ . = ..()
+ update_explanation_text()
+
+/datum/objective/raider_collection_tech/check_completion()
+ for(var/obj/machinery/vox_trader/trader in GLOB.machines)
+ if(length(trader.collected_tech_dict))
+ var/count = 0
+ for(var/tech in trader.collected_tech_dict)
+ if(trader.collected_tech_dict[tech] >= tech_min_level)
+ count++
+ if(count >= tech_amount)
+ return TRUE
+ return FALSE
+
diff --git a/modular_ss220/antagonists/code/radio.dm b/modular_ss220/antagonists/code/radio.dm
new file mode 100644
index 000000000000..a87c28d54dfd
--- /dev/null
+++ b/modular_ss220/antagonists/code/radio.dm
@@ -0,0 +1,40 @@
+// =============== FREQUENCE ===============
+// Часть модуля кода частот в /datum/modpack/antagonists/initialize()
+
+
+/datum/controller/subsystem/blackbox/LogBroadcast(freq)
+ if(sealed)
+ return
+ switch(freq)
+ if(VOX_RAID_FREQ)
+ record_feedback("tally", "radio_usage", 1, "voxcom")
+ . = ..()
+
+
+// =============== HEADSETS ===============
+
+/obj/item/radio/headset/vox
+ name = "vox headset"
+ desc = "Наушник дальней связи для поддержания связи со стаей."
+ origin_tech = "syndicate=3"
+ ks1type = /obj/item/encryptionkey/vox
+ requires_tcomms = FALSE
+ instant = TRUE // Work instantly if there are no comms
+ freqlock = TRUE
+ frequency = VOX_RAID_FREQ
+
+/obj/item/radio/headset/vox/alt
+ name = "vox protect headset"
+ desc = "Наушник дальней связи для поддержания связи со стаей. Защищает ушные раковины от громких звуков"
+ icon_state = "com_headset_alt"
+ item_state = "com_headset_alt"
+ origin_tech = "syndicate=3"
+ flags = EARBANGPROTECT
+
+/obj/item/encryptionkey/vox
+ name = "syndicate encryption key"
+ icon = 'modular_ss220/antagonists/icons/trader_machine.dmi'
+ icon_state = "vox_key"
+ channels = list("VoxCom" = 1, "Syndicate" = 1)
+ origin_tech = "syndicate=3"
+ syndie = TRUE
diff --git a/modular_ss220/antagonists/code/vox_raider/clothing/vox_backpack.dm b/modular_ss220/antagonists/code/vox_raider/clothing/vox_backpack.dm
new file mode 100644
index 000000000000..c4ce076ac509
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/clothing/vox_backpack.dm
@@ -0,0 +1,105 @@
+/obj/item/storage/backpack/vox
+ name = "vox backpack"
+ desc = "Рюкзак воксов из плотно переплетенного синтетического волокна. Хорошо защищает спину носителя при побегах и вмещает достаточно добра."
+ icon_state = "backpack_vox"
+ item_color = "backpack_vox"
+ item_state = "backpack_vox"
+ //var/list/species_restricted = list("Vox")
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_storage.dmi'
+ icon_override = 'modular_ss220/antagonists/icons/clothing/mob/back.dmi'
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/back.dmi'
+ )
+ lefthand_file = 'modular_ss220/antagonists/icons/clothing/inhands/clothing_lefthand.dmi'
+ righthand_file = 'modular_ss220/antagonists/icons/clothing/inhands/clothing_righthand.dmi'
+ armor = list(MELEE = 5, BULLET = 5, LASER = 15, ENERGY = 10, BOMB = 10, RAD = 30, FIRE = 60, ACID = 50)
+ resistance_flags = FIRE_PROOF
+ origin_tech = "syndicate=1"
+ max_combined_w_class = 35
+
+/obj/item/storage/backpack/satchel_flat/vox
+ name = "vox satchel"
+ desc = "Ранец воксов из синтетического волокна. Компактный, из-за чего его можно отлично прятать."
+ icon_state = "satchel_vox"
+ item_color = "satchel_vox"
+ item_state = "satchel_vox"
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_storage.dmi'
+ icon_override = 'modular_ss220/antagonists/icons/clothing/mob/back.dmi'
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/back.dmi'
+ )
+ lefthand_file = 'modular_ss220/antagonists/icons/clothing/inhands/clothing_lefthand.dmi'
+ righthand_file = 'modular_ss220/antagonists/icons/clothing/inhands/clothing_righthand.dmi'
+ resistance_flags = FIRE_PROOF
+ origin_tech = "syndicate=1"
+ max_combined_w_class = 25
+
+/obj/item/storage/backpack/duffel/vox
+ name = "vox duffelbag"
+ desc = "Сумка воксов из синтетического волокна. Емкий, вмещает много добра."
+ icon_state = "duffel_vox"
+ item_color = "duffel_vox"
+ item_state = "duffel_vox"
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_storage.dmi'
+ icon_override = 'modular_ss220/antagonists/icons/clothing/mob/back.dmi'
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/back.dmi'
+ )
+ lefthand_file = 'modular_ss220/antagonists/icons/clothing/inhands/clothing_lefthand.dmi'
+ righthand_file = 'modular_ss220/antagonists/icons/clothing/inhands/clothing_righthand.dmi'
+ silent = TRUE
+ zip_time = 2
+ resistance_flags = FIRE_PROOF
+ origin_tech = "syndicate=1"
+ max_combined_w_class = 45
+ allow_same_size = TRUE
+ cant_hold = list(/obj/item/storage/backpack)
+
+// Belts
+
+/obj/item/storage/belt/vox
+ name = "vox belt"
+ desc = "Удобный пояс с петельками для ношения всячины."
+ icon_state = "securitybelt"
+ item_state = "security"
+ origin_tech = "syndicate=1"
+ max_w_class = WEIGHT_CLASS_NORMAL
+ resistance_flags = FIRE_PROOF
+ use_item_overlays = TRUE // Will show the tools on the sprite
+ storage_slots = 7
+ max_combined_w_class = 25
+ can_hold = list(
+ /obj/item/crowbar,
+ /obj/item/screwdriver,
+ /obj/item/weldingtool,
+ /obj/item/wirecutters,
+ /obj/item/wrench,
+ /obj/item/multitool,
+ /obj/item/grenade,
+ /obj/item/flash,
+ /obj/item/kitchen/knife/combat,
+ /obj/item/melee/baton,
+ /obj/item/melee/classic_baton,
+ /obj/item/flashlight,
+ /obj/item/restraints/legcuffs/bola,
+ /obj/item/restraints/handcuffs,
+ /obj/item/biocore,
+ /obj/item/stock_parts/cell/vox_spike,
+ /obj/item/jammer
+ )
+
+/obj/item/storage/belt/vox/bio
+ name = "bio-vox belt"
+ desc = "Удобный пояс с плетенными кармашками для ношения ядер, взрывчатки и шприцов."
+ icon_state = "assaultbelt"
+ item_state = "assault"
+ storage_slots = 21
+ max_combined_w_class = 45
+ can_hold = list(
+ /obj/item/grenade,
+ /obj/item/flash,
+ /obj/item/storage/dart_cartridge,
+ /obj/item/biocore,
+ /obj/item/reagent_containers/iv_bag/blood,
+ /obj/item/reagent_containers/syringe
+ )
diff --git a/modular_ss220/antagonists/code/vox_raider/clothing/vox_clothing.dm b/modular_ss220/antagonists/code/vox_raider/clothing/vox_clothing.dm
new file mode 100644
index 000000000000..b0bcdb329659
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/clothing/vox_clothing.dm
@@ -0,0 +1,43 @@
+/obj/item/clothing/under/vox/jumpsuit
+ name = "vox jumpsuit"
+ desc = "Рабочая одежда вокса."
+ icon_state = "vox-jumpsuit"
+ item_color = "vox-jumpsuit"
+ item_state = "syndicate-black"
+ species_restricted = list("Vox")
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_under.dmi'
+ icon_override = 'modular_ss220/antagonists/icons/clothing/mob/vox/uniform.dmi'
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/uniform.dmi'
+ )
+ body_parts_covered = LEGS
+
+/obj/item/clothing/under/vox/jumpsuit/red
+ name = "vox work jumpsuit"
+ icon_state = "vox-jumpsuit_red"
+ item_color = "vox-jumpsuit_red"
+
+/obj/item/clothing/under/vox/jumpsuit/teal
+ name = "vox teal jumpsuit"
+ icon_state = "vox-jumpsuit_teal"
+ item_color = "vox-jumpsuit_teal"
+
+/obj/item/clothing/under/vox/jumpsuit/blue
+ name = "vox blue jumpsuit"
+ icon_state = "vox-jumpsuit_blue"
+ item_color = "vox-jumpsuit_blue"
+
+/obj/item/clothing/under/vox/jumpsuit/green
+ name = "vox green jumpsuit"
+ icon_state = "vox-jumpsuit_green"
+ item_color = "vox-jumpsuit_green"
+
+/obj/item/clothing/under/vox/jumpsuit/yellow
+ name = "vox yellow jumpsuit"
+ icon_state = "vox-jumpsuit_yellow"
+ item_color = "vox-jumpsuit_yellow"
+
+/obj/item/clothing/under/vox/jumpsuit/purple
+ name = "vox purple jumpsuit"
+ icon_state = "vox-jumpsuit_purple"
+ item_color = "vox-jumpsuit_purple"
diff --git a/modular_ss220/antagonists/code/vox_raider/clothing/vox_gloves.dm b/modular_ss220/antagonists/code/vox_raider/clothing/vox_gloves.dm
new file mode 100644
index 000000000000..57b937b979a3
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/clothing/vox_gloves.dm
@@ -0,0 +1,46 @@
+/obj/item/clothing/gloves/vox
+ name = "vox gauntlets"
+ desc = "Плотные рукавицы причудливой формы с когтями."
+ icon_state = "gloves-vox"
+ item_state = "gloves-vox"
+ item_color = "gloves-vox"
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_gloves.dmi'
+ species_restricted = list("Vox")
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/gloves.dmi')
+ strip_delay = 8 SECONDS
+ cold_protection = HANDS
+ min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
+ heat_protection = HANDS
+ max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
+ resistance_flags = NONE
+ armor = list(MELEE = 30, BULLET = 0, LASER = 10, ENERGY = 10, BOMB = 0, RAD = 0, FIRE = 200, ACID = 50)
+
+/obj/item/clothing/gloves/vox/light
+ name = "light vox gauntlets"
+ desc = "Легкие рукавицы причудливой формы с когтями."
+ strip_delay = 2 SECONDS
+ cold_protection = 0
+ min_cold_protection_temperature = NONE
+ max_heat_protection_temperature = NONE
+ armor = NONE
+
+/obj/item/clothing/gloves/color/yellow/vox
+ name = "insulated vox gauntlets"
+ desc = "Плотные изоляционные рукавицы причудливой формы с когтями."
+ icon_state = "gloves-vox-insulated"
+ item_state = "gloves-vox"
+ item_color = "gloves-vox-insulated"
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_gloves.dmi'
+ species_restricted = list("Vox")
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/gloves.dmi')
+ strip_delay = 8 SECONDS
+ cold_protection = HANDS
+ min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
+ heat_protection = HANDS
+ max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
+ resistance_flags = NONE
+ siemens_coefficient = 0
+ permeability_coefficient = 0.05
+ armor = list(MELEE = 30, BULLET = 0, LASER = 25, ENERGY = 25, BOMB = 0, RAD = 0, FIRE = 200, ACID = 50)
diff --git a/modular_ss220/antagonists/code/vox_raider/clothing/vox_outfit.dm b/modular_ss220/antagonists/code/vox_raider/clothing/vox_outfit.dm
new file mode 100644
index 000000000000..813b55e7ea97
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/clothing/vox_outfit.dm
@@ -0,0 +1,156 @@
+// Outfit
+/datum/outfit/vox
+ name = "Vox Crew"
+ uniform = /obj/item/clothing/under/vox/jumpsuit
+ gloves = /obj/item/clothing/gloves/vox
+ shoes = /obj/item/clothing/shoes/roman/vox
+ l_ear = /obj/item/radio/headset/vox
+ id = /obj/item/card/id/syndicate/vox
+ l_pocket = /obj/item/melee/classic_baton/telescopic
+
+ back = /obj/item/storage/backpack/vox
+ backpack_contents = list(
+ /obj/item/clothing/mask/breath/vox/respirator = 1,
+ /obj/item/tank/internals/emergency_oxygen/double/vox = 1,
+ /obj/item/flashlight = 1,
+ /obj/item/flash = 1,
+ /obj/item/clothing/suit/space/vox/pressure = 1,
+ /obj/item/clothing/head/helmet/space/vox/pressure = 1,
+ )
+
+/datum/outfit/vox/pre_equip(mob/living/carbon/human/H, visualsOnly)
+ . = ..()
+ var/choosen = rand(1, 8)
+ switch(choosen)
+ if(1)
+ uniform = /obj/item/clothing/under/vox/jumpsuit/red
+ if(2)
+ uniform = /obj/item/clothing/under/vox/jumpsuit/teal
+ if(3)
+ uniform = /obj/item/clothing/under/vox/jumpsuit/blue
+ if(4)
+ uniform = /obj/item/clothing/under/vox/jumpsuit/green
+ if(5)
+ uniform = /obj/item/clothing/under/vox/jumpsuit/yellow
+ if(6)
+ uniform = /obj/item/clothing/under/vox/jumpsuit/purple
+ else
+ uniform = /obj/item/clothing/under/vox/jumpsuit
+
+ if(prob(5))
+ uniform = /obj/item/clothing/suit/hooded/vox_robes
+
+ if(prob(50))
+ back = /obj/item/storage/backpack/satchel_flat/vox
+ if(prob(25))
+ back = /obj/item/storage/backpack/duffel/vox
+
+/datum/outfit/vox/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ if(visualsOnly)
+ return
+
+ var/obj/item/card/id/I = H.wear_id
+ if(istype(I))
+ apply_to_card(I, H, list(ACCESS_MAINT_TUNNELS, ACCESS_VOX, ACCESS_EXTERNAL_AIRLOCKS), "Vox Skipjack Crew", "data")
+
+ if(internals_slot)
+ H.internal = H.get_item_by_slot(internals_slot)
+ H.update_action_buttons_icon()
+
+/obj/item/card/id/syndicate/vox
+ name = "vox data card"
+ icon_state = "data"
+
+// ==================== Raiders ====================
+/datum/outfit/vox/raider
+ name = "vox raider"
+ suit = /obj/item/clothing/suit/space/hardsuit/vox
+ suit_store = /obj/item/tank/internals/emergency_oxygen/double/vox
+ gloves = /obj/item/clothing/gloves/color/yellow/vox
+ shoes = /obj/item/clothing/shoes/magboots/vox
+ l_ear = /obj/item/radio/headset/vox/alt
+
+/datum/outfit/vox/raider/trooper
+ name = "vox raider trooper"
+ suit = /obj/item/clothing/suit/space/hardsuit/vox/trooper
+ shoes = /obj/item/clothing/shoes/magboots/vox/combat
+
+/datum/outfit/vox/raider/scout
+ name = "vox raider scout"
+ suit = /obj/item/clothing/suit/space/hardsuit/vox/scout
+ shoes = /obj/item/clothing/shoes/magboots/vox/scout
+
+/datum/outfit/vox/raider/medic
+ name = "vox raider medic"
+ suit = /obj/item/clothing/suit/space/hardsuit/vox/medic
+
+/datum/outfit/vox/raider/mechanic
+ name = "vox raider mechanic"
+ suit = /obj/item/clothing/suit/space/hardsuit/vox/mechanic
+ shoes = /obj/item/clothing/shoes/magboots/vox/heavy
+
+/datum/outfit/vox/raider/heavy
+ name = "vox raider heavy"
+ suit = /obj/item/clothing/suit/space/hardsuit/vox/heavy
+ shoes = /obj/item/clothing/shoes/magboots/vox/heavy
+
+
+// ==================== Mercenaries ====================
+/datum/outfit/vox/merc
+ name = "vox mercenary"
+ suit = /obj/item/clothing/suit/armor/vox_merc
+ head = /obj/item/clothing/head/helmet/vox_merc
+ gloves = /obj/item/clothing/gloves/color/yellow/vox
+ shoes = /obj/item/clothing/shoes/magboots/vox
+ l_ear = /obj/item/radio/headset/vox/alt
+
+/datum/outfit/vox/merc/storm
+ name = "vox mercenary stormtrooper"
+ suit = /obj/item/clothing/suit/armor/vox_merc/stormtrooper
+ head = /obj/item/clothing/head/helmet/vox_merc/stormtrooper
+ shoes = /obj/item/clothing/shoes/magboots/vox/combat
+
+/datum/outfit/vox/merc/fieldmedic
+ name = "vox mercenary field medic"
+ suit = /obj/item/clothing/suit/armor/vox_merc/fieldmedic
+ head = /obj/item/clothing/head/helmet/vox_merc/fieldmedic
+
+/datum/outfit/vox/merc/bomber
+ name = "vox mercenary bomber"
+ suit = /obj/item/clothing/suit/armor/vox_merc/bomber
+ head = /obj/item/clothing/head/helmet/vox_merc/bomber
+ shoes = /obj/item/clothing/shoes/magboots/vox/heavy
+
+/datum/outfit/vox/merc/laminar
+ name = "vox mercenary laminar"
+ suit = /obj/item/clothing/suit/armor/vox_merc/laminar
+ head = /obj/item/clothing/head/helmet/vox_merc/laminar
+
+/datum/outfit/vox/merc/laminar/scout
+ name = "vox mercenary laminar scout"
+ suit = /obj/item/clothing/suit/armor/vox_merc/laminar/scout
+ shoes = /obj/item/clothing/shoes/magboots/vox/scout
+
+/datum/outfit/vox/merc/stealth
+ name = "vox mercenary stealth"
+ suit = /obj/item/clothing/suit/armor/vox_merc/stealth
+ head = /obj/item/clothing/head/helmet/vox_merc/stealth
+
+
+// ==================== Other ====================
+/datum/outfit/vox/carapace
+ name = "Vox Carapace"
+ uniform = /obj/item/clothing/suit/hooded/vox_robes
+ suit = /obj/item/clothing/suit/space/vox/carapace
+ gloves = /obj/item/clothing/gloves/color/yellow/vox
+ shoes = /obj/item/clothing/shoes/magboots/vox
+ head = /obj/item/clothing/head/helmet/space/vox/carapace
+ mask = /obj/item/clothing/mask/gas/syndicate
+ glasses = /obj/item/clothing/glasses/thermal/monocle
+ l_ear = /obj/item/radio/headset/vox/alt
+
+/datum/outfit/vox/carapace/pre_equip(mob/living/carbon/human/H, visualsOnly)
+ . = ..()
+ uniform = /obj/item/clothing/suit/hooded/vox_robes
+ back = /obj/item/storage/backpack/vox
diff --git a/modular_ss220/antagonists/code/vox_raider/clothing/vox_shoes.dm b/modular_ss220/antagonists/code/vox_raider/clothing/vox_shoes.dm
new file mode 100644
index 000000000000..3e0c44608138
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/clothing/vox_shoes.dm
@@ -0,0 +1,50 @@
+/obj/item/clothing/shoes/roman/vox
+ name = "vox sandals"
+ desc = "Синтетические обертки подходящие для большинства типов ног."
+
+/obj/item/clothing/shoes/magboots/vox
+ name = "vox magclaws"
+ desc = "Тяжелые бронированные налапочники для когтистых лап причудливой формы."
+ item_state = "boots-vox"
+ icon_state = "boots-vox"
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_shoes.dmi'
+ species_restricted = list("Vox")
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/feet.dmi')
+ w_class = WEIGHT_CLASS_NORMAL
+ armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 50, RAD = 0, FIRE = 115, ACID = 50)
+ strip_delay = 7 SECONDS
+ resistance_flags = NONE
+ slowdown = 0
+ slowdown_passive = 0
+ slowdown_active = 1
+
+/obj/item/clothing/shoes/magboots/vox/combat
+ name = "vox combat magclaws"
+ desc = "Боевые бронированные налапочники для когтистых лап причудливой формы с улучшенным сцеплением с поверхностью."
+ item_state = "boots-vox-combat"
+ icon_state = "boots-vox-combat"
+ permeability_coefficient = 0.01
+ armor = list(MELEE = 50, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 80, RAD = 50, FIRE = 450, ACID = 50)
+ strip_delay = 10 SECONDS
+ slowdown_active = SHOES_SLOWDOWN+0.5
+
+/obj/item/clothing/shoes/magboots/vox/heavy
+ name = "vox heavy magclaws"
+ desc = "Тяжелые бронированные налапочники для когтистых лап причудливой формы для ведения боевых действий и защит нижних конечностей от всевозможных угроз."
+ item_state = "boots-vox-heavy"
+ icon_state = "boots-vox-heavy"
+ body_parts_covered = FEET|LEGS
+ permeability_coefficient = 0.01
+ armor = list(MELEE = 115, BULLET = 50, LASER = 75, ENERGY = 50, BOMB = 200, RAD = 200, FIRE = 450, ACID = 200)
+ strip_delay = 14 SECONDS
+ slowdown_passive = SHOES_SLOWDOWN+1
+ slowdown_active = SHOES_SLOWDOWN+3
+
+/obj/item/clothing/shoes/magboots/vox/scout
+ name = "vox scout magclaws"
+ desc = "Легкие налапочники для когтистых лап причудливой формы с продвинутым сцеплением с поверхностью для ускорение передвижения."
+ item_state = "boots-vox-combat"
+ icon_state = "boots-vox-combat"
+ slowdown_passive = -0.25
+ slowdown_active = 0
diff --git a/modular_ss220/antagonists/code/vox_raider/clothing/vox_suit_armor.dm b/modular_ss220/antagonists/code/vox_raider/clothing/vox_suit_armor.dm
new file mode 100644
index 000000000000..fd8e612a16c8
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/clothing/vox_suit_armor.dm
@@ -0,0 +1,223 @@
+// Броня ВОКСов.
+// Дает хорошие защитные свойства, но не позволяет держать давление космоса.
+
+/obj/item/clothing/suit/armor/vox_merc
+ name = "vox mercenary vest"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением."
+ icon_state = "vox-merc"
+ item_color = "vox-merc"
+ item_state = "armor"
+ blood_overlay_type = "armor"
+ species_restricted = list("Vox")
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_suit.dmi'
+ icon_override = 'modular_ss220/antagonists/icons/clothing/mob/vox/suit.dmi'
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/suit.dmi'
+ )
+ allowed = list(/obj/item/gun, /obj/item/ammo_box,/obj/item/ammo_casing, /obj/item/melee/baton,
+ /obj/item/melee/energy/sword, /obj/item/shield/energy,
+ /obj/item/restraints/handcuffs, /obj/item/tank/internals)
+ body_parts_covered = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
+ cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
+ heat_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ armor = list(MELEE = 35, BULLET = 50, LASER = 20, ENERGY = 20, BOMB = 25, RAD = 80, FIRE = 50, ACID = 50)
+ strip_delay = 8 SECONDS
+ put_on_delay = 6 SECONDS
+
+/obj/item/clothing/head/helmet/vox_merc
+ name = "vox mercenary helmet"
+ desc = "Специализированный шлем воксов-наемников."
+ icon_state = "vox-merc"
+ item_color = "vox-merc"
+ species_restricted = list("Vox")
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_head.dmi'
+ icon_override = 'modular_ss220/antagonists/icons/clothing/mob/vox/head.dmi'
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/head.dmi'
+ )
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ armor = list(MELEE = 35, BULLET = 50, LASER = 20, ENERGY = 20, BOMB = 25, RAD = 80, FIRE = 50, ACID = 50)
+ flags = HEADBANGPROTECT | BLOCKHEADHAIR
+ flags_inv = HIDEMASK | HIDEEARS
+ flags_cover = HEADCOVERSEYES
+ cold_protection = HEAD
+ heat_protection = HEAD
+ dog_fashion = null
+
+
+// Storm Trooper
+
+/obj/item/clothing/suit/armor/vox_merc/stormtrooper
+ name = "vox mercenary storm vest"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ \nШтурмовой бронекостюм воксов разработан под их структуру тела и прикрывает наиболее уязвимые места, превосходно защищает носителя от огнестрельного вооружения и ближних атак."
+ icon_state = "vox-merc-stormtrooper"
+ item_color = "vox-merc-stormtrooper"
+ w_class = WEIGHT_CLASS_BULKY
+ armor = list(MELEE = 115, BULLET = 115, LASER = 50, ENERGY = 30, BOMB = 15, RAD = 80, FIRE = 50, ACID = 50)
+ strip_delay = 12 SECONDS
+ put_on_delay = 8 SECONDS
+ slowdown = 1
+
+/obj/item/clothing/head/helmet/vox_merc/stormtrooper
+ name = "vox mercenary helmet"
+ icon_state = "vox-merc-stormtrooper"
+ item_color = "vox-merc-stormtrooper"
+ armor = list(MELEE = 115, BULLET = 115, LASER = 50, ENERGY = 30, BOMB = 15, RAD = 80, FIRE = 50, ACID = 50)
+
+
+// Field Medic
+
+/obj/item/clothing/suit/armor/vox_merc/fieldmedic
+ name = "vox mercenary field medic vest"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ \nМедицинский полевой костюм предназначен для защиты владельца от биологических угроз, радиации и кислотной атмосферы. Дает слабую защиту от внешне поступаемых энергетических снарядов, равномерно рассеивая остаточную энергию. Костюм абсолютно не предназначен для защиты в ближнем бою или от взрывчатых веществ за счет свое внутреннего строения, повреждающий носителя от осколков костюма при нарушении целостности. Имеет хранилище для ношения аптечек и контейнеров с химикатами."
+ icon_state = "vox-merc-fieldmedic"
+ item_color = "vox-merc-fieldmedic"
+ armor = list(MELEE = -15, BULLET = 20, LASER = 50, ENERGY = 40, BOMB = -15, RAD = INFINITY, FIRE = 80, ACID = INFINITY)
+ strip_delay = 6 SECONDS
+ put_on_delay = 4 SECONDS
+ allowed = list(/obj/item/flashlight, /obj/item/storage/firstaid,
+ /obj/item/gun, /obj/item/ammo_box,/obj/item/ammo_casing, /obj/item/melee/baton,
+ /obj/item/melee/energy/sword, /obj/item/shield/energy,
+ /obj/item/restraints/handcuffs, /obj/item/tank/internals,
+ /obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper,
+ /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray,
+ /obj/item/reagent_containers/applicator, /obj/item/healthanalyzer, /obj/item/flashlight/pen,
+ /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker,
+ /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/robotanalyzer)
+
+/obj/item/clothing/head/helmet/vox_merc/fieldmedic
+ name = "vox mercenary field medic helmet"
+ icon_state = "vox-merc-fieldmedic"
+ item_color = "vox-merc-fieldmedic"
+ armor = list(MELEE = -15, BULLET = 20, LASER = 50, ENERGY = 40, BOMB = -15, RAD = INFINITY, FIRE = 80, ACID = INFINITY)
+ flags_inv = HIDEMASK
+ flags = HEADBANGPROTECT
+
+// Bomber
+
+/obj/item/clothing/suit/armor/vox_merc/bomber
+ name = "vox mercenary bomber vest"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ \nОсобый разработанный штурмовой тяжелый костюм для действий в условиях крайне взрывоопасной атмосферы. Абсолютная жаростойкость, повышенная стойкость к кислотным жидкостям и лазерному воздействию делают эту броню основной для воксов действующих внутри активно разрушающихся комплексов и кораблей."
+ icon_state = "vox-merc-bomber"
+ item_color = "vox-merc-bomber"
+ armor = list(MELEE = 80, BULLET = 20, LASER = 115, ENERGY = 75, BOMB = 200, RAD = 115, FIRE = INFINITY, ACID = 150)
+ max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
+ strip_delay = 12 SECONDS
+ put_on_delay = 8 SECONDS
+ slowdown = 1.5
+
+/obj/item/clothing/head/helmet/vox_merc/bomber
+ name = "vox mercenary bomber helmet"
+ icon_state = "vox-merc-bomber"
+ item_color = "vox-merc-bomber"
+ armor = list(MELEE = 80, BULLET = 20, LASER = 115, ENERGY = 75, BOMB = 200, RAD = 115, FIRE = INFINITY, ACID = 150)
+ max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
+
+
+// Laminar
+
+/obj/item/clothing/suit/armor/vox_merc/laminar
+ name = "vox mercenary laminar vest"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ \nКомпактный и мобильный костюм отлично помещается в рюкзаке, сформирован из легких пластин позволяющий получить хорошие защитные свойства в совокупности с удобством для носителя, не мешающий его передвижению. Но, в отличии от других моделей, не дает приемлимых защитных параметров от воздействий внешней агрессивной среды и не защищает руки."
+ icon_state = "vox-merc-laminar"
+ item_color = "vox-merc-laminar"
+ w_class = WEIGHT_CLASS_SMALL
+ body_parts_covered = UPPER_TORSO | LOWER_TORSO | LEGS | FEET // Руки уязвимые зоны.
+ cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET
+ heat_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET
+ armor = list(MELEE = 20, BULLET = 20, LASER = 40, ENERGY = 40, BOMB = 15, RAD = 20, FIRE = 20, ACID = 20)
+ strip_delay = 2 SECONDS
+ put_on_delay = 1 SECONDS
+
+/obj/item/clothing/head/helmet/vox_merc/laminar
+ name = "vox mercenary laminar helmet"
+ icon_state = "vox-merc-laminar"
+ item_color = "vox-merc-laminar"
+ w_class = WEIGHT_CLASS_SMALL
+ armor = list(MELEE = 20, BULLET = 20, LASER = 40, ENERGY = 40, BOMB = 15, RAD = 20, FIRE = 20, ACID = 20)
+ flags_inv = HIDEEARS|HIDEEYES
+
+/obj/item/clothing/suit/armor/vox_merc/laminar/scout
+ name = "vox mercenary laminar scout vest"
+ desc = "Компактный и мобильный костюм сформированный из лёгких пластин и за счет их особого размещения, увеличивает погашение импульсов перенаправляя их в ускорение носителя, но взамен теряя значимые защитные свойства. "
+ armor = list(MELEE = 20, BULLET = 20, LASER = 10, ENERGY = 40, BOMB = 40, RAD = 20, FIRE = 20, ACID = 20)
+ slowdown = -0.35
+
+
+// Stealth
+
+// Crew Steath Suit
+/obj/item/clothing/suit/armor/vox_merc/stealth
+ name = "vox mercenary stealth suit"
+ desc = "Специализированный маскировочный костюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ Костюм с маскировочной системой, напрямую связанная с телом носителя. При снимании костюма возможно ощущение легкого недомогания."
+ icon_state = "vox-merc-stealth"
+ item_color = "vox-merc-stealth"
+ blood_overlay_type = "suit"
+ armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 15, RAD = INFINITY, FIRE = INFINITY, ACID = 80)
+ strip_delay = 6 SECONDS
+ put_on_delay = 4 SECONDS
+ var/datum/spell/disguise_self/vox/disguise_spell
+
+/datum/spell/disguise_self/vox
+ name = "Маскировка"
+ desc = "Замаскируйтесь под члена экипажа с его голосом в текущей зоне. \
+ Внимательный осмотр выдаст вас. Если повредить маскировку - она сбросится."
+ invocation = "none"
+ invocation_type = "none"
+
+/obj/item/clothing/suit/armor/vox_merc/stealth/equipped(mob/living/user, slot)
+ ..()
+ if(isvox(user) && slot == ITEM_SLOT_OUTER_SUIT)
+ disguise_spell = new(null)
+ user.AddSpell(disguise_spell)
+
+/obj/item/clothing/suit/armor/vox_merc/stealth/dropped(mob/user)
+ . = ..()
+ if(user && disguise_spell)
+ user.RemoveSpell(disguise_spell)
+ QDEL_NULL(disguise_spell)
+ // сбрасываем спел нанеся чутка урон
+ SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, 5, BRUTE)
+
+/obj/item/clothing/suit/armor/vox_merc/stealth/Destroy()
+ . = ..()
+ if(disguise_spell)
+ QDEL_NULL(disguise_spell)
+
+// Smoke Helmet
+/obj/item/clothing/head/helmet/vox_merc/stealth
+ name = "vox mercenary stealth helmet"
+ desc = "Специализированный шлем воксов-наемников со встроенной системой дымогенератора."
+ icon_state = "vox-merc-stealth"
+ item_color = "vox-merc-stealth"
+ armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 15, RAD = INFINITY, FIRE = INFINITY, ACID = 80)
+ flags = HEADBANGPROTECT
+ flags_inv = HIDEMASK|HIDEEARS|HIDEEYES
+ var/datum/spell/smoke/smoke_spell
+
+/datum/spell/smoke
+ name = "Дымовой занавес"
+ desc = "Выпустить дымовую занавесу скрывающее поле зрение всех находящихся в нём в ближайшей зоне."
+
+/obj/item/clothing/head/helmet/vox_merc/stealth/equipped(mob/living/user, slot)
+ ..()
+ if(isvox(user) && slot == ITEM_SLOT_HEAD)
+ smoke_spell = new(null)
+ user.AddSpell(smoke_spell)
+
+/obj/item/clothing/head/helmet/vox_merc/stealth/dropped(mob/user)
+ . = ..()
+ if(user && smoke_spell)
+ user.RemoveSpell(smoke_spell)
+ QDEL_NULL(smoke_spell)
+
+/obj/item/clothing/head/helmet/vox_merc/stealth/Destroy()
+ . = ..()
+ if(smoke_spell)
+ QDEL_NULL(smoke_spell)
diff --git a/modular_ss220/antagonists/code/vox_raider/clothing/vox_suit_rig.dm b/modular_ss220/antagonists/code/vox_raider/clothing/vox_suit_rig.dm
new file mode 100644
index 000000000000..f15518d75707
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/clothing/vox_suit_rig.dm
@@ -0,0 +1,174 @@
+// РИГи ВОКСов.
+// Дают приемлимые защитные свойства, позволяют держать давление космоса.
+
+/obj/item/clothing/suit/space/hardsuit/vox
+ name = "vox raider hardsuit"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников."
+ icon_state = "vox-raider"
+ item_color = "vox-raider"
+ item_state = "rig_suit"
+ species_restricted = list("Vox")
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_suit.dmi'
+ icon_override = 'modular_ss220/antagonists/icons/clothing/mob/vox/suit.dmi'
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/suit.dmi'
+ )
+ allowed = list(/obj/item/flashlight, /obj/item/tank/internals,
+ /obj/item/gun, /obj/item/ammo_box,/obj/item/ammo_casing, /obj/item/melee/baton,
+ /obj/item/melee/energy/sword, /obj/item/shield/energy,
+ /obj/item/restraints/handcuffs)
+ body_parts_covered = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
+ cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
+ heat_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ armor = list(MELEE = 75, BULLET = 50, LASER = 30, ENERGY = 20, BOMB = 25, RAD = 115, FIRE = 80, ACID = 200)
+ strip_delay = 8 SECONDS
+ put_on_delay = 6 SECONDS
+ slowdown = 0
+ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/vox
+
+/obj/item/clothing/head/helmet/space/hardsuit/vox
+ name = "vox raider helmet"
+ desc = "Специализированный космический шлем воксов-рейдеров."
+ icon_state = "vox-raider"
+ item_color = "vox-raider"
+ species_restricted = list("Vox")
+ icon = 'modular_ss220/antagonists/icons/clothing/obj_head.dmi'
+ icon_override = 'modular_ss220/antagonists/icons/clothing/mob/vox/head.dmi'
+ sprite_sheets = list(
+ "Vox" = 'modular_ss220/antagonists/icons/clothing/mob/vox/head.dmi'
+ )
+ flags = HEADBANGPROTECT | BLOCKHAIR | STOPSPRESSUREDMAGE | THICKMATERIAL
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ armor = list(MELEE = 75, BULLET = 50, LASER = 30, ENERGY = 20, BOMB = 25, RAD = 115, FIRE = 80, ACID = 200)
+
+/obj/item/clothing/head/helmet/space/hardsuit/vox/toggle_light(mob/user)
+ on = !on
+ icon_state = "[initial(icon_state)][on ? "_light" : ""]"
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_head()
+
+ if(on)
+ set_light(brightness_on)
+ else
+ set_light(0)
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtons()
+
+// Space Trooper
+
+/obj/item/clothing/suit/space/hardsuit/vox/trooper
+ name = "vox raider trooper hardsuit"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nКостюм космического штурмовика рейдеров с защитой от огнестрела и колюще-режущего."
+ icon_state = "vox-raider-trooper"
+ item_color = "vox-raider-trooper"
+ armor = list(MELEE = 75, BULLET = 50, LASER = 30, ENERGY = 20, BOMB = 25, RAD = 115, FIRE = 80, ACID = 200)
+ strip_delay = 12 SECONDS
+ put_on_delay = 8 SECONDS
+ slowdown = 1
+ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/vox/trooper
+
+/obj/item/clothing/head/helmet/space/hardsuit/vox/trooper
+ name = "vox raider trooper helmet"
+ icon_state = "vox-raider-trooper"
+ item_color = "vox-raider-trooper"
+ armor = list(MELEE = 75, BULLET = 50, LASER = 30, ENERGY = 20, BOMB = 25, RAD = 115, FIRE = 80, ACID = 200)
+
+
+/obj/item/clothing/suit/space/hardsuit/vox/scout
+ name = "vox raider scout hardsuit"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nКостюм разведчика не сковывает движение и помогает владельцу удобней двигаться в условиях невесомости."
+ icon_state = "vox-raider-scout"
+ item_color = "vox-raider-scout"
+ armor = list(MELEE = 10, BULLET = 20, LASER = 30, ENERGY = 30, BOMB = 15, RAD = 115, FIRE = 80, ACID = 200)
+ strip_delay = 6 SECONDS
+ put_on_delay = 4 SECONDS
+ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/vox/scout
+ slowdown = -0.25
+
+/obj/item/clothing/head/helmet/space/hardsuit/vox/scout
+ name = "vox raider scout helmet"
+ icon_state = "vox-raider-scout"
+ item_color = "vox-raider-scout"
+ armor = list(MELEE = 10, BULLET = 20, LASER = 30, ENERGY = 30, BOMB = 15, RAD = 115, FIRE = 80, ACID = 200)
+
+
+// Medic
+
+/obj/item/clothing/suit/space/hardsuit/vox/medic
+ name = "vox raider medic hardsuit"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nКостюм для работы в условиях отдаленности от опасностей. Более подвижен и обладает приемлимыми свойствами защиты от воздействий различного рода снарядов, но из-за своей структуры способен нанести вред носителю при взрывных воздействиях или колющих атак. Костюм отлично выдерживает радиационный фон и кислотное воздействие и биологическими угрозами. Имеет хранилище для ношения аптечек контейнеров с химикатами."
+ icon_state = "vox-raider-medic"
+ item_color = "vox-raider-medic"
+ armor = list(MELEE = -30, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = -30, RAD = INFINITY, FIRE = 120, ACID = INFINITY)
+ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/vox/medic
+ allowed = list(/obj/item/flashlight, /obj/item/storage/firstaid,
+ /obj/item/gun, /obj/item/ammo_box,/obj/item/ammo_casing, /obj/item/melee/baton,
+ /obj/item/melee/energy/sword, /obj/item/shield/energy,
+ /obj/item/restraints/handcuffs, /obj/item/tank/internals,
+ /obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper,
+ /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray,
+ /obj/item/reagent_containers/applicator, /obj/item/healthanalyzer, /obj/item/flashlight/pen,
+ /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker,
+ /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/robotanalyzer)
+
+/obj/item/clothing/head/helmet/space/hardsuit/vox/medic
+ name = "vox raider medic helmet"
+ icon_state = "vox-raider-medic"
+ item_color = "vox-raider-medic"
+ armor = list(MELEE = -30, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = -30, RAD = INFINITY, FIRE = 120, ACID = INFINITY)
+
+
+// Mechanic
+
+/obj/item/clothing/suit/space/hardsuit/vox/mechanic
+ name = "vox raider mechanic hardsuit"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nКостюм для работы в условиях крайне опасных и недружелюбных атмосфер. За счет своей структуры и технологии рассеивания тепла, костюм обладает хорошей защитой от энергетического оружия."
+ icon_state = "vox-raider-mechanic"
+ item_color = "vox-raider-mechanic"
+ max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
+ armor = list(MELEE = 20, BULLET = 20, LASER = 75, ENERGY = 50, BOMB = 150, RAD = INFINITY, FIRE = INFINITY, ACID = INFINITY)
+ slowdown = 2
+ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/vox/mechanic
+ allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/t_scanner, /obj/item/rcd, /obj/item/rpd,
+ /obj/item/gun, /obj/item/ammo_box,/obj/item/ammo_casing, /obj/item/melee/baton,
+ /obj/item/melee/energy/sword, /obj/item/shield/energy,
+ /obj/item/restraints/handcuffs, /obj/item/tank/internals)
+
+/obj/item/clothing/head/helmet/space/hardsuit/vox/mechanic
+ name = "vox raider mechanic helmet"
+ icon_state = "vox-raider-mechanic"
+ item_color = "vox-raider-mechanic"
+ max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
+ armor = list(MELEE = 20, BULLET = 20, LASER = 75, ENERGY = 50, BOMB = 150, RAD = INFINITY, FIRE = INFINITY, ACID = INFINITY)
+
+
+// Heavy - Воксомех
+
+/obj/item/clothing/suit/space/hardsuit/vox/heavy
+ name = "vox raider heavy hardsuit"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nТяжелый огнеупорный и взрывостойкий костюм рейдеров с превосходной защитой от энергетического оружия и колюще-режущих и приемлимой от огнестрела. Костюм был разработан для противостояния механизированным силам в условиях космического пространства. К сожалению, его вес и ресиверы не настолько совершены, из-за чего он уступает в скорости."
+ icon_state = "vox-raider-heavy"
+ item_color = "vox-raider-heavy"
+ w_class = WEIGHT_CLASS_HUGE
+ armor = list(MELEE = 115, BULLET = 80, LASER = 150, ENERGY = 80, BOMB = 200, RAD = INFINITY, FIRE = INFINITY, ACID = INFINITY)
+ max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
+ slowdown = 3 // Даже черепаха быстрее чем это ведро.
+ strip_delay = 20 SECONDS
+ put_on_delay = 10 SECONDS
+ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/vox/heavy
+
+/obj/item/clothing/head/helmet/space/hardsuit/vox/heavy
+ name = "vox raider heavy helmet"
+ icon_state = "vox-raider-heavy"
+ item_color = "vox-raider-heavy"
+ armor = list(MELEE = 115, BULLET = 80, LASER = 115, ENERGY = 80, BOMB = 200, RAD = INFINITY, FIRE = INFINITY, ACID = INFINITY)
+ max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_defines.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_defines.dm
new file mode 100644
index 000000000000..1c1beff53cc4
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_defines.dm
@@ -0,0 +1,16 @@
+// CATEGORY
+#define VOX_PACK_CLOTHES "Одежда"
+#define VOX_PACK_EQUIPMENT "Снаряжение"
+#define VOX_PACK_RAIDER "Наборы Рейдера"
+#define VOX_PACK_MERCENARIES "Наборы Наемника"
+#define VOX_PACK_CONSUMABLES "Расходники"
+#define VOX_PACK_GOODS "Товары"
+#define VOX_PACK_MEDICINE "Медицина"
+#define VOX_PACK_MISC "Разное"
+#define VOX_PACK_KIT "Полные Наборы"
+
+// Weapons
+#define VOX_PACK_SPIKE "Шипометы"
+#define VOX_PACK_DART "Дротики"
+#define VOX_PACK_BIO "Биооружие"
+#define VOX_PACK_MELEE "Ближний Контакт"
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack.dm
new file mode 100644
index 000000000000..9135cf5f724a
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack.dm
@@ -0,0 +1,57 @@
+/datum/vox_pack
+ var/name = "DEBUG Vox Pack"
+ var/desc = "Описание отсутствует. Сообщите разработчику."
+ var/reference = null
+ var/cost = -1 // -1 = hide
+ var/is_need_trader_cost = TRUE // Is need an additional cost on top of the cost from the “trader machine”
+ var/time_until_available = 0 // How long does it take from the start of the round? In MINUTES
+ var/limited_stock = -1 // Can you only buy so many? -1 allows for infinite purchases
+ var/purchased = 0 // How much have you already bought?
+ var/discount_div = 0 // Процент скидки на паки за покупку набора
+ var/amount = 1
+ var/category = VOX_PACK_MISC
+ var/list/contains = list()
+
+/datum/vox_pack/New()
+ . = ..()
+ update_pack()
+
+/datum/vox_pack/proc/update_pack()
+ if(discount_div <= 0)
+ return
+ cost = round(initial(cost) * discount_div)
+
+/datum/vox_pack/proc/get_items_list()
+ var/list/items_list = list()
+ for(var/typepath in contains)
+ if(!typepath)
+ continue
+ for(var/i in 1 to amount)
+ items_list.Add(typepath)
+ return items_list
+
+/datum/vox_pack/proc/check_possible_buy(amount)
+ if(limited_stock >= 0 && (purchased + amount > limited_stock))
+ return FALSE
+ return TRUE
+
+/datum/vox_pack/proc/check_time_available()
+ var/round_time_minutes = ROUND_TIME
+ if(round_time_minutes < time_until_available MINUTES)
+ return FALSE
+ return TRUE
+
+/datum/vox_pack/proc/get_time_available()
+ var/t = SSticker.time_game_started + time_until_available MINUTES
+ return "[round(t / 36000)]:[add_zero(num2text(t / 600 % 60), 2)]"
+
+/datum/vox_pack/proc/get_time_left()
+ var/t = SSticker.time_game_started + time_until_available MINUTES - ROUND_TIME
+ return "[round(t / 36000)]:[add_zero(num2text(t / 600 % 60), 2)]:[add_zero(num2text(t / 10 % 60), 2)]"
+
+/datum/vox_pack/proc/description()
+ if(!desc)
+ desc = replacetext(desc, "\n", " ")
+ if(!check_time_available())
+ desc += " \[Заказ возможен после [get_time_available()] от начала рейда.\]"
+ return desc
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_bio.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_bio.dm
new file mode 100644
index 000000000000..aec2c8e8bd02
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_bio.dm
@@ -0,0 +1,56 @@
+/datum/vox_pack/bio
+ name = "DEBUG Bio Vox Pack"
+ category = VOX_PACK_BIO
+ time_until_available = 45
+
+// ============== GUNS ==============
+/datum/vox_pack/bio/gun
+ name = "Биомёт"
+ desc = "Компактный метатель биоядер-снарядов. Вмещает в себя 3 острых биоядра одновременно, выстреливая их поочереди, вонзая в плоть цели, а после вылупляя, выпуская биомеханическую тварь для последующей помощи Воксам."
+ reference = "B_G"
+ cost = 2000
+ contains = list(/obj/item/gun/throw/biogun)
+
+// ============== AMMO ==============
+
+/datum/vox_pack/bio/core
+ name = "Биоядро (Потрошитель х3)"
+ desc = "Переписанная машина синдиката на служении Воксам."
+ reference = "B_B_VISC"
+ cost = 400
+ contains = list(/obj/item/biocore/viscerator)
+
+/datum/vox_pack/bio/core/stamine
+ name = "Биоядро (Стакикамка х3)"
+ desc = "Биомеханизм изматывающий своих жертв."
+ reference = "B_B_STAM"
+ cost = 300
+ contains = list(/obj/item/biocore/stamina)
+
+/datum/vox_pack/bio/core/acid
+ name = "Биоядро (Асикикид х1)"
+ desc = "Кислотный жгущий биомеханизм."
+ reference = "B_B_ACID"
+ cost = 200
+ contains = list(/obj/item/biocore/acid)
+
+/datum/vox_pack/bio/core/kusaka
+ name = "Биоядро (Кусакика х4)"
+ desc = "Кусачий маленький биомеханизм."
+ reference = "B_B_KUS"
+ cost = 300
+ contains = list(/obj/item/biocore/kusaka)
+
+/datum/vox_pack/bio/core/taran
+ name = "Биоядро (Таракикан х1)"
+ desc = "Броневой биомеханизм, приспособленный для вышибания дверей."
+ reference = "B_B_TAT"
+ cost = 400
+ contains = list(/obj/item/biocore/taran)
+
+/datum/vox_pack/bio/core/tox
+ name = "Биоядро (Токсикикик х3)"
+ desc = "Иглоподобный биомеханизм для впрыскивания токсин."
+ reference = "B_B_TOX"
+ cost = 300
+ contains = list(/obj/item/biocore/tox)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_clothes.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_clothes.dm
new file mode 100644
index 000000000000..fcbbd103c624
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_clothes.dm
@@ -0,0 +1,213 @@
+/datum/vox_pack/clothes
+ name = "DEBUG Clothes Vox Pack"
+ category = VOX_PACK_CLOTHES
+
+
+// ============== JUMSUIT ==============
+
+/datum/vox_pack/clothes/jumpsuit
+ name = "Рабочая одежда"
+ desc = "Одежда воксов предназначенная только для них."
+ reference = "C_J"
+ cost = 15
+ contains = list(/obj/item/clothing/under/vox/jumpsuit)
+
+/datum/vox_pack/clothes/jumpsuit/red
+ name = "Рабочая одежда - Красная"
+ reference = "C_JR"
+ contains = list(/obj/item/clothing/under/vox/jumpsuit/red)
+
+/datum/vox_pack/clothes/jumpsuit/teal
+ name = "Рабочая одежда - Бирюза"
+ reference = "C_JT"
+ contains = list(/obj/item/clothing/under/vox/jumpsuit/teal)
+
+/datum/vox_pack/clothes/jumpsuit/blue
+ name = "Рабочая одежда - Синий"
+ reference = "C_JB"
+ contains = list(/obj/item/clothing/under/vox/jumpsuit/blue)
+
+/datum/vox_pack/clothes/jumpsuit/green
+ name = "Рабочая одежда - Зеленый"
+ reference = "C_JG"
+ contains = list(/obj/item/clothing/under/vox/jumpsuit/green)
+
+/datum/vox_pack/clothes/jumpsuit/yellow
+ name = "Рабочая одежда - Желтый"
+ reference = "C_JY"
+ contains = list(/obj/item/clothing/under/vox/jumpsuit/yellow)
+
+/datum/vox_pack/clothes/jumpsuit/purple
+ name = "Рабочая одежда - Фиолетовый"
+ reference = "C_JP"
+ contains = list(/obj/item/clothing/under/vox/jumpsuit/purple)
+
+
+// ============== SHOES ==============
+
+/datum/vox_pack/clothes/shoes
+ name = "Обувка"
+ desc = "Синтетические обертки подходящие для большинства типов ног."
+ reference = "C_SH"
+ cost = 15
+ contains = list(/obj/item/clothing/shoes/roman/vox)
+
+
+// ============== MAGBOOTS ==============
+/datum/vox_pack/clothes/magboots
+ name = "Магнитные Налапочники"
+ desc = "Когтистые плотные налапочники с небольшой защитой для лап."
+ reference = "C_SH_M"
+ cost = 200
+ contains = list(/obj/item/clothing/shoes/magboots/vox)
+
+/datum/vox_pack/clothes/magboots/scout
+ name = "Магнитные Налапочники Разведки"
+ desc = "Легкие когтистые налапочники с продвинутым сцеплением с поверхностью для ускорение передвижения."
+ reference = "C_SH_MS"
+ cost = 1000
+ contains = list(/obj/item/clothing/shoes/magboots/vox/scout)
+
+/datum/vox_pack/clothes/magboots/combat
+ name = "Боевые Магнитные Налапочники"
+ desc = "Боевые бронированные когтистые налапочники с улучшенным сцеплением с поверхностью."
+ reference = "C_SH_MC"
+ cost = 2000
+ time_until_available = 45
+ contains = list(/obj/item/clothing/shoes/magboots/vox/combat)
+
+/datum/vox_pack/clothes/magboots/heavy
+ name = "Тяжелые Магнитные Налапочники"
+ desc = "Тяжелые бронированные когтистые налапочники для ведения боевых действий и защит нижних конечностей от всевозможных угроз."
+ reference = "C_SH_MH"
+ cost = 4000
+ time_until_available = 60
+ contains = list(/obj/item/clothing/shoes/magboots/vox/heavy)
+
+
+// ============== GLOVES ==============
+/datum/vox_pack/clothes/gloves
+ name = "Рукавицы"
+ desc = "Плотные рукавицы с когтями с защитой кистей."
+ reference = "C_GL"
+ cost = 400
+ contains = list(/obj/item/clothing/gloves/vox)
+
+/datum/vox_pack/clothes/gloves/insulated
+ name = "Изоляционные Рукавицы"
+ desc = "Плотные изоляционные рукавицы с когтями."
+ reference = "C_GL_I"
+ cost = 2000
+ contains = list(/obj/item/clothing/gloves/color/yellow/vox)
+
+
+// ============== GLASSES ==============
+
+/datum/vox_pack/clothes/eye_night
+ name = "Очки Ночного Видения"
+ desc = "Очки позволяющие видеть в кромешной темноте."
+ reference = "C_EYE_NI"
+ cost = 300
+ contains = list(/obj/item/clothing/glasses/night)
+
+/datum/vox_pack/clothes/eye_meson
+ name = "Мезонный Глаз"
+ desc = "Мезонный кибернетический глаз с системой вставки в глазной разъем. Полностью заменяет функционирующий глаз или его полость. \
+ ВНИМАНИЕ! Глаз возможно удалить только хирургическим путем. Из-за своего размера - не позволяет надевать прочие приблуды на глаза, заменяя очки."
+ reference = "C_EYE_ME"
+ cost = 1000
+ contains = list(/obj/item/clothing/glasses/meson/cyber/vox)
+
+/datum/vox_pack/clothes/eye_thermal
+ name = "Термальный Глаз"
+ desc = "Термальный кибернетический глаз с системой вставки в глазной разъем. Полностью заменяет функционирующий глаз или его полость. \
+ ВНИМАНИЕ! Глаз возможно удалить только хирургическим путем. Из-за своего размера - не позволяет надевать прочие приблуды на глаза, заменяя очки."
+ reference = "C_EYE_TH"
+ cost = 4500
+ time_until_available = 45
+ contains = list(/obj/item/clothing/glasses/thermal/cyber/vox)
+
+/datum/vox_pack/clothes/sechud
+ name = "Дисплей Службы Безопасности"
+ desc = "Очки с защитой для глаз и с доступом в системы базы данных службы безопасности."
+ reference = "C_EYE_SEC"
+ cost = 3500
+ time_until_available = 45
+ contains = list(/obj/item/clothing/glasses/hud/security/sunglasses/fluff/voxxyhud)
+
+/datum/vox_pack/clothes/healthhud
+ name = "Медицинский Дисплей"
+ desc = "Очки для контроля жизненных показателей."
+ reference = "C_EYE_HEALTH"
+ cost = 1000
+ time_until_available = 45
+ contains = list(/obj/item/clothing/glasses/hud/health)
+
+
+// ============== EARS ==============
+
+/datum/vox_pack/clothes/radio
+ name = "Наушники"
+ desc = "Наушник дальней связи для поддержания связи со стаей."
+ reference = "C_RAD"
+ cost = 100
+ contains = list(/obj/item/radio/headset/vox)
+
+/datum/vox_pack/clothes/radio/alt
+ name = "Защитные наушники"
+ desc = "Наушник дальней связи для поддержания связи со стаей. Защищает ушные раковины от громких звуков"
+ reference = "C_RAD_ALT"
+ cost = 500
+ time_until_available = 60
+ contains = list(/obj/item/radio/headset/vox/alt)
+
+
+// ============== Space Suits ==============
+/datum/vox_pack/clothes/pressure
+ name = "Скафандр"
+ desc = "Защитный костюм для работы во враждебной атмосфере с приемлимыми защитными свойствами и полной защитой от давления."
+ reference = "C_PR"
+ cost = 100
+ contains = list(
+ /obj/item/clothing/suit/space/vox/pressure,
+ /obj/item/clothing/head/helmet/space/vox/pressure
+ )
+
+
+// ============== STORAGE ==============
+
+/datum/vox_pack/clothes/backpack
+ name = "Рюкзак"
+ desc = "Рюкзак из плотно переплетенного синтетического волокна. Хорошо защищает спину носителя при побегах и вмещает достаточно добра."
+ reference = "C_BP"
+ cost = 200
+ contains = list(/obj/item/storage/backpack/vox)
+
+/datum/vox_pack/clothes/backpack/duffel
+ name = "Сумка"
+ desc = "Сумка из синтетического волокна. Емкий, вмещает много добра."
+ reference = "C_BPD"
+ cost = 300
+ contains = list(/obj/item/storage/backpack/duffel/vox)
+
+/datum/vox_pack/clothes/backpack/satchel
+ name = "Ранец"
+ desc = "Ранец из синтетического волокна. Компактный, из-за чего его можно отлично прятать."
+ reference = "C_BPS"
+ cost = 150
+ contains = list(/obj/item/storage/backpack/satchel_flat/vox)
+
+
+/datum/vox_pack/clothes/belt
+ name = "Пояс Рейдера"
+ desc = "Пояс вмещающий в себя инструменты и запасные батареи. Вмещает 7 предметов."
+ reference = "C_BELT"
+ cost = 1000
+ contains = list(/obj/item/storage/belt/vox)
+
+/datum/vox_pack/clothes/belt/bio
+ name = "Пояс Био-Рейдера"
+ desc = "Пояс вмещающий в себя биоядра, дротики и взрывчатку. Вмещает 21 тяжелых предметов."
+ reference = "C_BELT_BIO"
+ cost = 1300
+ contains = list(/obj/item/storage/belt/vox/bio)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_consumables.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_consumables.dm
new file mode 100644
index 000000000000..9f6a5ad25f4c
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_consumables.dm
@@ -0,0 +1,51 @@
+/datum/vox_pack/consumables
+ name = "DEBUG Consumables Vox Pack"
+ category = VOX_PACK_CONSUMABLES
+
+
+// MISC
+
+/datum/vox_pack/consumables/food
+ name = "Варево"
+ desc = "Лучше чем ничего."
+ reference = "CO_FOOD"
+ cost = 5
+ contains = list(/obj/item/food/soup/stew)
+
+/datum/vox_pack/consumables/flare
+ name = "Фальшфейер"
+ desc = "Пиротехнический огонь."
+ reference = "CO_FLARE"
+ cost = 15
+ contains = list(/obj/item/flashlight/flare)
+
+
+// EXPLOSIVES
+
+/datum/vox_pack/consumables/smoke
+ name = "Дымовая граната"
+ desc = "Для создания плотных дымовых завес."
+ reference = "CO_SMOKE"
+ cost = 40
+ contains = list(/obj/item/grenade/smokebomb)
+
+/datum/vox_pack/consumables/c4
+ name = "C4"
+ desc = "Взрывчатка для создания аккуратных дыр."
+ reference = "CO_C4"
+ cost = 250
+ contains = list(/obj/item/grenade/plastic/c4)
+
+/datum/vox_pack/consumables/x4
+ name = "X4"
+ desc = "Осколочно-фугасный заряд. Безопасен для подрывника."
+ reference = "CO_X4"
+ cost = 450
+ contains = list(/obj/item/grenade/plastic/c4/x4)
+
+/datum/vox_pack/consumables/t4
+ name = "T4"
+ desc = "Заряд термита, пробивающий стены. Неэффективен против шлюзов."
+ reference = "CO_T4"
+ cost = 700
+ contains = list(/obj/item/grenade/plastic/c4/thermite)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_dart.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_dart.dm
new file mode 100644
index 000000000000..bb7a9a42c3d3
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_dart.dm
@@ -0,0 +1,89 @@
+/datum/vox_pack/dart
+ name = "DEBUG Dart Vox Pack"
+ category = VOX_PACK_DART
+
+// ============== GUNS ==============
+
+/datum/vox_pack/dart/gun
+ name = "Дротикомет"
+ desc = "Компактный метатель дротиков для доставки химических коктейлей. Вмещает 5(+1) дротиков. Никто кроме Воксов не сможет взять его в руки."
+ reference = "D_G"
+ cost = 500
+ contains = list(/obj/item/gun/syringe/dart_gun)
+
+/datum/vox_pack/dart/gun/ext
+ name = "Расширенный Дротикомет"
+ desc = "Расширенный метатель дротиков и шприцов для доставки химических коктейлей. Вмещает 5(+1) дротиков и шприцов. Никто кроме Воксов не сможет взять его в руки."
+ reference = "D_GE"
+ cost = 2000
+ contains = list(/obj/item/gun/syringe/dart_gun/extended)
+
+/datum/vox_pack/dart/gun/big
+ name = "Вместительный Дротикомет"
+ desc = "Вместительный метатель дротиков для доставки химических коктейлей. Вмещает 10(+1) дротиков. Никто кроме Воксов не сможет взять его в руки."
+ reference = "D_GB"
+ cost = 3000
+ contains = list(/obj/item/gun/syringe/dart_gun/big)
+
+
+// ============== AMMO ==============
+
+/datum/vox_pack/dart/cartridge
+ name = "Картридж (5+1)"
+ desc = "Подставка для дротиков. Пустая."
+ reference = "D_C"
+ cost = 25
+ contains = list(/obj/item/storage/dart_cartridge)
+
+/datum/vox_pack/dart/cartridge/extended
+ name = "Картридж (5+1)"
+ desc = "Расширенная подставка для дротиков и шприцов. Пустая."
+ reference = "D_C_EXT"
+ cost = 50
+ contains = list(/obj/item/storage/dart_cartridge/extended)
+
+/datum/vox_pack/dart/cartridge/big
+ name = "Картридж (10+1)"
+ desc = "Увеличенная подставка для дротиков. Пустая."
+ reference = "D_C_BIG"
+ cost = 100
+ contains = list(/obj/item/storage/dart_cartridge/big)
+
+/datum/vox_pack/dart/cartridge/combat
+ name = "Картридж (5+1) - Боевой"
+ desc = "Подставка с боевыми дротиками для нанесения повреждений."
+ reference = "D_C_COM"
+ cost = 400
+ time_until_available = 45
+ contains = list(/obj/item/storage/dart_cartridge/combat)
+
+/datum/vox_pack/dart/cartridge/medical
+ name = "Картридж (5+1) - Медицинский"
+ desc = "Подставка с полезными дротиками для восстановления телесных повреждений."
+ reference = "D_C_MED"
+ cost = 300
+ contains = list(/obj/item/storage/dart_cartridge/medical)
+
+/datum/vox_pack/dart/cartridge/pain
+ name = "Картридж (5+1) - Болевой"
+ desc = "Подставка с вредными дротиками, приносящие боль и страдания."
+ reference = "D_C_PAIN"
+ cost = 400
+ time_until_available = 30
+ contains = list(/obj/item/storage/dart_cartridge/pain)
+
+/datum/vox_pack/dart/cartridge/drugs
+ name = "Картридж (5+1) - Наркотический"
+ desc = "Подставка для вредных дротиков-наркотиков."
+ reference = "D_C_DRUG"
+ cost = 300
+ time_until_available = 30
+ contains = list(/obj/item/storage/dart_cartridge/drugs)
+
+/datum/vox_pack/dart/cartridge/random
+ name = "Картридж (10+1) - ???"
+ desc = "Случайный набор дротиков с химикатами."
+ reference = "D_C_RAND"
+ cost = 1000
+ time_until_available = 60
+ contains = list(/obj/item/storage/dart_cartridge/big/random)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_equipment.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_equipment.dm
new file mode 100644
index 000000000000..7c7ef328d21d
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_equipment.dm
@@ -0,0 +1,77 @@
+/datum/vox_pack/equipment
+ name = "DEBUG Equipment Vox Pack"
+ category = VOX_PACK_EQUIPMENT
+
+
+// ============== Misc ==============
+/datum/vox_pack/equipment/card
+ name = "Идентификационная Карта"
+ desc = "Карта для идентификации, смены образов и воровства доступов."
+ reference = "E_CARD"
+ cost = 150
+ contains = list(/obj/item/card/id/syndicate/vox)
+
+/datum/vox_pack/equipment/hand_valuer
+ name = "Оценщик"
+ desc = "Позволяет узнать ценность товаров. Не забудьте его активировать о Расчичетчикик."
+ reference = "E_VALUER"
+ cost = 100
+ contains = list(/obj/item/hand_valuer)
+
+/datum/vox_pack/equipment/mask
+ name = "Дыхательная Маска"
+ desc = "С встроенной трубкой для дыхания"
+ reference = "E_MASK"
+ cost = 25
+ contains = list(/obj/item/clothing/mask/breath/vox)
+
+/datum/vox_pack/equipment/nitrogen
+ name = "Дыхательный Балон"
+ desc = "Сдвоенный дыхательный балон наполненный нитрогеном."
+ reference = "E_NITR"
+ cost = 50
+ contains = list(/obj/item/tank/internals/emergency_oxygen/double/vox)
+
+/datum/vox_pack/equipment/flag
+ name = "Флаг"
+ desc = "С ним ценности еще ценнее."
+ reference = "E_FLAG"
+ cost = 100
+ contains = list(/obj/item/flag/vox_raider)
+
+// TECH
+
+/datum/vox_pack/equipment/jammer
+ name = "Глушилка"
+ desc = "Глушитель связи."
+ reference = "E_JAM"
+ cost = 500
+ contains = list(/obj/item/jammer)
+
+/datum/vox_pack/equipment/jammer
+ name = "Глушилка"
+ desc = "Глушитель связи."
+ reference = "E_JAM"
+ cost = 500
+ contains = list(/obj/item/jammer)
+
+/datum/vox_pack/equipment/ai_detector
+ name = "Детектор"
+ desc = "Детектор искусственного интеллекта замаскированного под мультиметр."
+ reference = "E_AI"
+ cost = 250
+ contains = list(/obj/item/multitool/ai_detect)
+
+/datum/vox_pack/equipment/stealth
+ name = "Имплантер Маскировки"
+ desc = "Имплантер для скрытых операций и краж."
+ reference = "E_BCI_S"
+ cost = 2000
+ contains = list(/obj/item/bio_chip_implanter/stealth)
+
+/datum/vox_pack/equipment/freedom
+ name = "Имплантер Свободы"
+ desc = "Имплантер скоротечно изменяющий структуру костей для освобождения от сдерживающих факторов."
+ reference = "E_BCI_F"
+ cost = 1500
+ contains = list(/obj/item/bio_chip_implanter/freedom)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_goods.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_goods.dm
new file mode 100644
index 000000000000..945555700e68
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_goods.dm
@@ -0,0 +1,275 @@
+/datum/vox_pack/goods
+ name = "DEBUG Goods Vox Pack"
+ category = VOX_PACK_GOODS
+ is_need_trader_cost = FALSE
+ var/obj/random_subtype
+
+/datum/vox_pack/goods/New()
+ . = ..()
+ if(!random_subtype)
+ return
+ var/list/possible_types = list(random_subtype) + subtypesof(random_subtype)
+ var/choosen_type = pick(possible_types)
+ contains.Add(choosen_type)
+
+/datum/vox_pack/goods/figure
+ name = "Фигурка"
+ desc = "Случайный товар для продажи."
+ reference = "G_FIG"
+ cost = 25
+ random_subtype = /obj/item/toy/figure
+
+/datum/vox_pack/goods/mech
+ name = "Механоид"
+ desc = "Случайный товар для продажи."
+ reference = "G_MECH"
+ cost = 25
+ random_subtype = /obj/item/toy/figure/mech
+
+/datum/vox_pack/goods/plushie
+ name = "Плюшка"
+ desc = "Случайный товар для продажи."
+ reference = "G_PLUSH"
+ cost = 25
+ random_subtype = /obj/item/toy/plushie
+
+/datum/vox_pack/goods/therapy
+ name = "Плюшка-Обнимашка"
+ desc = "Случайный товар для продажи."
+ reference = "G_THER"
+ cost = 25
+ random_subtype = /obj/item/toy/therapy
+
+/datum/vox_pack/goods/carp_plushie
+ name = "Плюшка-Карпушка"
+ desc = "Случайный товар для продажи."
+ reference = "G_CARP"
+ cost = 25
+ random_subtype = /obj/item/toy/plushie/carpplushie
+
+/datum/vox_pack/goods/food
+ name = "Еда"
+ desc = "Случайный товар для продажи."
+ reference = "G_CARP"
+ cost = 50
+ random_subtype = /obj/item/food
+
+/datum/vox_pack/goods/toy
+ name = "Игрушка"
+ desc = "Случайный товар для продажи."
+ reference = "G_TOY"
+ cost = 100
+ random_subtype = /obj/item/toy
+
+/datum/vox_pack/goods/bikehorn
+ name = "Гудок"
+ desc = "Случайный товар для продажи."
+ reference = "G_HORN"
+ cost = 100
+ random_subtype = /obj/item/bikehorn
+
+/datum/vox_pack/goods/beach_ball
+ name = "Мяч"
+ desc = "Случайный товар для продажи."
+ reference = "G_BALL"
+ cost = 100
+ random_subtype = /obj/item/beach_ball
+
+/datum/vox_pack/goods/instrument
+ name = "Музыкальный Инструмент"
+ desc = "Случайный товар для продажи."
+ reference = "G_MINS"
+ cost = 100
+ random_subtype = /obj/item/instrument
+
+/datum/vox_pack/goods/soap
+ name = "Мыло"
+ desc = "Случайный товар для продажи."
+ reference = "G_SOAP"
+ cost = 25
+ random_subtype = /obj/item/soap
+
+/datum/vox_pack/goods/lighter
+ name = "Зажигалка"
+ desc = "Случайный товар для продажи."
+ reference = "G_LIGH"
+ cost = 75
+ random_subtype = /obj/item/lighter
+
+/datum/vox_pack/goods/flag
+ name = "Флаг"
+ desc = "Случайный товар для продажи."
+ reference = "G_FLAG"
+ cost = 50
+ random_subtype = /obj/item/flag
+
+/datum/vox_pack/goods/id_skin
+ name = "Наклейка на карту"
+ desc = "Случайный товар для продажи."
+ reference = "G_IDS"
+ cost = 50
+ random_subtype = /obj/item/id_skin
+
+/datum/vox_pack/goods/drugs
+ name = "Наркотики"
+ desc = "Мясу понравится этот товар."
+ reference = "G_DRUG"
+ cost = 200
+ contains = list(/obj/item/storage/pill_bottle/random_drug_bottle)
+
+/datum/vox_pack/goods/enforser
+ name = "Пистолет Энфорсер (резина)"
+ desc = "Мясу понравится этот товар."
+ reference = "G_ENF"
+ cost = 1000
+ contains = list(/obj/item/gun/projectile/automatic/pistol/enforcer,
+ /obj/item/ammo_box/magazine/enforcer,
+ /obj/item/ammo_box/magazine/enforcer,
+ /obj/item/ammo_box/magazine/enforcer,
+ )
+
+/datum/vox_pack/goods/space
+ name = "Космический Старый Костюм \"NasaVoid\" - Красный"
+ desc = "Мясу понравится этот товар."
+ reference = "G_SP"
+ cost = 200
+ contains = list(
+ /obj/item/clothing/head/helmet/space/nasavoid,
+ /obj/item/clothing/suit/space/nasavoid,
+ )
+
+/datum/vox_pack/goods/space/green
+ name = "Космический Старый Костюм \"NasaVoid\" - Зеленый"
+ desc = "Мясу понравится этот товар."
+ reference = "G_SP_G"
+ cost = 200
+ contains = list(
+ /obj/item/clothing/head/helmet/space/nasavoid/green,
+ /obj/item/clothing/suit/space/nasavoid/green,
+ )
+
+/datum/vox_pack/goods/space/ntblue
+ name = "Космический Старый Костюм \"NasaVoid\" - NT Синий"
+ desc = "Мясу понравится этот товар."
+ reference = "G_SP_NTB"
+ cost = 250
+ contains = list(
+ /obj/item/clothing/head/helmet/space/nasavoid/ntblue,
+ /obj/item/clothing/suit/space/nasavoid/ntblue,
+ )
+
+/datum/vox_pack/goods/space/purple
+ name = "Космический Старый Костюм \"NasaVoid\" - Фиолетовый"
+ desc = "Мясу понравится этот товар."
+ reference = "G_SP_P"
+ cost = 200
+ contains = list(
+ /obj/item/clothing/head/helmet/space/nasavoid/purple,
+ /obj/item/clothing/suit/space/nasavoid/purple,
+ )
+
+/datum/vox_pack/goods/space/yellow
+ name = "Космический Старый Костюм \"NasaVoid\" - Желтый"
+ desc = "Мясу понравится этот товар."
+ reference = "G_SP_Y"
+ cost = 200
+ contains = list(
+ /obj/item/clothing/head/helmet/space/nasavoid/yellow,
+ /obj/item/clothing/suit/space/nasavoid/yellow,
+ )
+
+/datum/vox_pack/goods/space/ltblue
+ name = "Космический Старый Костюм \"NasaVoid\" - Светло-синий"
+ desc = "Мясу понравится этот товар."
+ reference = "G_SP_LTB"
+ cost = 200
+ contains = list(
+ /obj/item/clothing/head/helmet/space/nasavoid/ltblue,
+ /obj/item/clothing/suit/space/nasavoid/ltblue,
+ )
+
+/datum/vox_pack/goods/telescopic
+ name = "Телескопическая дубинка"
+ desc = "Мясу понравится этот товар."
+ reference = "G_TEL"
+ cost = 300
+ contains = list(/obj/item/melee/classic_baton/telescopic)
+
+/datum/vox_pack/goods/clown_gun
+ name = "Клоунская Хлопушка"
+ desc = "Мясу понравится этот товар."
+ reference = "G_CL_GUN"
+ cost = 100
+ contains = list(/obj/item/gun/energy/clown)
+
+/datum/vox_pack/goods/clown
+ name = "Клоунское Снаряжение"
+ desc = "Мясу повеселится от этого товара."
+ reference = "G_CL_EQ"
+ cost = 500
+ contains = list(
+ /obj/item/clothing/mask/gas/clown_hat,
+ /obj/item/clothing/shoes/clown_shoes,
+ /obj/item/clothing/under/rank/civilian/clown,
+ /obj/item/pda/clown,
+ /obj/item/flag/clown,
+ /obj/item/id_skin/clown,
+ /obj/item/bikehorn,
+ /obj/item/storage/backpack/clown,
+ /obj/item/food/grown/banana,
+ /obj/item/stamp/clown,
+ /obj/item/toy/crayon/rainbow,
+ /obj/item/storage/fancy/crayons,
+ /obj/item/reagent_containers/spray/waterflower,
+ /obj/item/reagent_containers/drinks/bottle/bottleofbanana,
+ )
+
+/datum/vox_pack/goods/clown/sec
+ name = "Клоунское Снаряжение Безопасности"
+ desc = "Мясо будет унижено этим товаром."
+ reference = "G_CL_EQS"
+ cost = 1000
+ contains = list(
+ /obj/item/clothing/under/rank/security/officer/clown,
+ /obj/item/clothing/suit/armor/vest/security,
+ /obj/item/clothing/shoes/clown_shoes,
+ /obj/item/clothing/head/helmet,
+ /obj/item/clothing/mask/gas/clown_hat,
+ /obj/item/clothing/gloves/color/red,
+ /obj/item/flag/clown,
+ /obj/item/id_skin/clown,
+ /obj/item/pda/clown,
+ /obj/item/bikehorn,
+ /obj/item/gun/energy/clown/security,
+ /obj/item/food/grown/banana,
+ /obj/item/stamp/clown,
+ /obj/item/toy/crayon/rainbow,
+ /obj/item/storage/fancy/crayons,
+ /obj/item/reagent_containers/spray/waterflower,
+ /obj/item/reagent_containers/drinks/bottle/bottleofbanana,
+ /obj/item/instrument/bikehorn,
+ /obj/item/restraints/handcuffs/toy,
+ /obj/item/restraints/handcuffs/toy,
+ /obj/item/storage/backpack/clown,
+ )
+
+/datum/vox_pack/goods/clown_grenade
+ name = "Клоунская Граната"
+ desc = "Мясу понравится этот товар."
+ reference = "G_CL_GR"
+ cost = 200
+ contains = list(/obj/item/grenade/clusterbuster/honk)
+
+/datum/vox_pack/goods/clown_grenade/evil
+ name = "Клоунская Злая Граната"
+ desc = "Мясу НЕ понравится этот товар."
+ reference = "G_CL_GRE"
+ cost = 500
+ contains = list(/obj/item/grenade/clown_grenade)
+
+/datum/vox_pack/goods/clown_bomba
+ name = "Клоунская Бомба"
+ desc = "Мясу НЕ понравится этот товар."
+ reference = "G_CL_BOMBA"
+ cost = 80000
+ contains = list(/obj/item/grenade/clusterbuster/honk)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_kit.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_kit.dm
new file mode 100644
index 000000000000..dde4e9c5d6f5
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_kit.dm
@@ -0,0 +1,385 @@
+// Цельные наборы
+/datum/vox_pack/kit
+ name = "DEBUG Kit Vox Pack"
+ category = VOX_PACK_KIT
+ is_need_trader_cost = FALSE
+ discount_div = 0.85 // Процент скидки на паки за покупку набора
+ var/list/packs_list = list() // Паки которые мы используем для инициализации текущего пака и его цены
+ var/list/contains_addition = list() // Дополнительные предметы в наборе
+
+/datum/vox_pack/kit/update_pack()
+ if(discount_div <= 0)
+ return FALSE
+ var/temp_cost = initial(cost)
+ contains.Cut()
+ if(length(contains_addition))
+ contains |= contains_addition
+
+ for(var/i in packs_list)
+ var/datum/vox_pack/pack = new i
+ temp_cost += pack.cost
+ contains |= pack.contains.Copy()
+ if(pack.limited_stock >= 0)
+ limited_stock = min(limited_stock, pack.limited_stock)
+ if(!time_until_available && pack.time_until_available)
+ time_until_available = max(time_until_available, pack.time_until_available)
+
+ cost = round(temp_cost * discount_div)
+ return TRUE
+
+// ============== Дешевые Наборы ==============
+
+/datum/vox_pack/kit/lamilar
+ name = "Лёгкий Набор"
+ desc = "Дешевый и лёгкий набор снаряжения, производящийся в промышленных масштабах и рекомендуемый каждому начинающему и опытному воксу при отсутствии средств."
+ reference = "K_LAM"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/lamilar,
+ /datum/vox_pack/clothes/magboots,
+ /datum/vox_pack/clothes/gloves,
+ )
+ discount_div = 0.65
+
+ // !!!!!!!!! TEST
+ contains_addition = list(
+ /obj/item/roller/holo,
+ /obj/item/roller/holo,
+ /obj/item/roller/holo,
+ )
+
+/datum/vox_pack/kit/pressure
+ name = "Космический Набор"
+ desc = "Дешевый набор для перемещения в космосе. Отличное дополнение к полевым наборам."
+ reference = "K_PRES"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/clothes/pressure,
+ /datum/vox_pack/equipment/mask,
+ /datum/vox_pack/equipment/nitrogen,
+ )
+
+// ============== Наборы Наемников ==============
+
+/datum/vox_pack/kit/stormtrooper
+ name = "Штурмовой Набор"
+ desc = "Набор штурмовика для сражения при нормальной атмосфере."
+ reference = "K_STR"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/stormtrooper,
+ /datum/vox_pack/clothes/magboots/combat,
+ /datum/vox_pack/clothes/gloves,
+ /datum/vox_pack/clothes/sechud,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/clothes/belt,
+ /datum/vox_pack/spike/gun,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/bio/core/taran,
+ )
+
+/datum/vox_pack/kit/fieldmedic
+ name = "Набор Полевого Медика"
+ desc = "Всё для оказания первой помощи, хирургического вмешательства и защиты самого медика."
+ reference = "K_FM"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/fieldmedic,
+ /datum/vox_pack/clothes/magboots,
+ /datum/vox_pack/clothes/gloves,
+ /datum/vox_pack/clothes/healthhud,
+ /datum/vox_pack/medicine/blood,
+ /datum/vox_pack/medicine/blood,
+ /datum/vox_pack/medicine/blood,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/stabilizing,
+ /datum/vox_pack/medicine/dart/stabilizing,
+ )
+ contains_addition = list(
+ /obj/item/storage/firstaid/adv,
+ /obj/item/storage/firstaid/toxin,
+ /obj/item/storage/firstaid/surgery,
+ /obj/item/roller/holo,
+ )
+ discount_div = 0.65
+
+/datum/vox_pack/kit/field_scout
+ name = "Набор Полевого Разведчика"
+ desc = "Набор для разведывательных действий в благоприятных условиях."
+ reference = "K_FSCT"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/lamilar/scout,
+ /datum/vox_pack/clothes/magboots/scout,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/equipment/ai_detector,
+ /datum/vox_pack/equipment/stealth,
+ /datum/vox_pack/consumables/t4,
+ /datum/vox_pack/consumables/t4,
+ )
+ discount_div = 0.65
+
+/datum/vox_pack/kit/bomber
+ name = "Набор Подрывника"
+ desc = "Набор медвежатника для собственной защиты и вскрытия защищенного."
+ reference = "K_BOM"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/bomber,
+ /datum/vox_pack/clothes/magboots/heavy,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/clothes/belt/bio,
+ /datum/vox_pack/consumables/c4,
+ /datum/vox_pack/consumables/c4,
+ /datum/vox_pack/consumables/c4,
+ /datum/vox_pack/consumables/c4,
+ /datum/vox_pack/consumables/c4,
+ /datum/vox_pack/consumables/c4,
+ /datum/vox_pack/consumables/x4,
+ /datum/vox_pack/consumables/x4,
+ /datum/vox_pack/consumables/t4,
+ /datum/vox_pack/consumables/t4,
+ /datum/vox_pack/melee/inflatable,
+ /datum/vox_pack/melee/inflatable,
+ /datum/vox_pack/melee/inflatable,
+ )
+ contains_addition = list(
+ /obj/item/clothing/glasses/hud/diagnostic/sunglasses,
+ )
+ discount_div = 0.5
+
+
+// ============== Наборы Рейдеров ==============
+
+/datum/vox_pack/kit/trooper
+ name = "Набор Космического Штурмовика"
+ desc = "Набор для штурма космических кораблей и станций."
+ reference = "K_TROOP"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/raider/trooper,
+ /datum/vox_pack/clothes/magboots/combat,
+ /datum/vox_pack/clothes/gloves,
+ /datum/vox_pack/clothes/sechud,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/spike/gun/long,
+ /datum/vox_pack/clothes/belt,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/consumables/c4,
+ /datum/vox_pack/consumables/c4,
+ /datum/vox_pack/consumables/c4,
+ )
+ contains_addition = list(
+ /obj/item/clothing/mask/breath/vox/respirator,
+ /obj/item/tank/internals/emergency_oxygen/double/vox,
+ )
+
+/datum/vox_pack/kit/scout
+ name = "Набор Космического Разведчика"
+ desc = "Набор для проведения разведки в неблагоприятных условиях."
+ reference = "K_SSCT"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/raider/scout,
+ /datum/vox_pack/clothes/magboots/scout,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/equipment/ai_detector,
+ /datum/vox_pack/equipment/jammer,
+ )
+ contains_addition = list(
+ /obj/item/clothing/mask/breath/vox/respirator,
+ /obj/item/tank/internals/emergency_oxygen/double/vox,
+ )
+ discount_div = 0.65
+
+/datum/vox_pack/kit/medic
+ name = "Набор Космического Медика"
+ desc = "Набор для скорого оказания помощи в неблагоприятных условиях и защиты носителя."
+ reference = "K_MEDIC"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/raider/medic,
+ /datum/vox_pack/clothes/magboots,
+ /datum/vox_pack/clothes/gloves,
+ /datum/vox_pack/clothes/healthhud,
+ /datum/vox_pack/dart/gun,
+ /datum/vox_pack/clothes/belt/bio,
+ /datum/vox_pack/dart/cartridge/medical,
+ /datum/vox_pack/dart/cartridge/medical,
+ /datum/vox_pack/dart/cartridge/medical,
+ /datum/vox_pack/dart/cartridge/medical,
+ /datum/vox_pack/dart/cartridge/medical,
+ /datum/vox_pack/dart/cartridge/medical,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/heal,
+ /datum/vox_pack/medicine/dart/stabilizing,
+ /datum/vox_pack/medicine/dart/stabilizing,
+ )
+ discount_div = 0.65
+ contains_addition = list(
+ /obj/item/clothing/mask/breath/vox,
+ /obj/item/tank/internals/emergency_oxygen/double/vox,
+ /obj/item/roller/holo,
+ )
+
+/datum/vox_pack/kit/mechanic
+ name = "Набор Механика"
+ desc = "Набор первичного необходимого для ремонта вышедшего из строя оборудования в условиях боя."
+ reference = "K_MECH"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/raider/mechanic,
+ /datum/vox_pack/clothes/magboots/heavy,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/equipment/jammer,
+ /datum/vox_pack/equipment/ai_detector,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/melee/inflatable,
+ /datum/vox_pack/melee/inflatable,
+ /datum/vox_pack/melee/inflatable,
+ )
+ contains_addition = list(
+ /obj/item/clothing/glasses/hud/diagnostic/night,
+ /obj/item/clothing/mask/breath/vox,
+ /obj/item/tank/internals/emergency_oxygen/double/vox,
+ /obj/item/storage/belt/utility/full,
+ /obj/item/storage/firstaid/machine,
+ /obj/item/clothing/glasses/welding,
+ )
+ discount_div = 0.65
+
+/datum/vox_pack/kit/heavy
+ name = "Тяжелый Набор"
+ desc = "Полный набор тяжелого костюма для работы в условиях переизбыточной опасности."
+ reference = "K_HEAVY"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/raider/heavy,
+ /datum/vox_pack/clothes/magboots/heavy,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/clothes/sechud,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/clothes/belt
+ )
+ contains_addition = list(
+ /obj/item/clothing/mask/breath/vox/respirator,
+ /obj/item/tank/internals/emergency_oxygen/double/vox,
+ /obj/item/clothing/glasses/thermal/monocle,
+ )
+
+// ============== Наборы Киг-Йар ==============
+// Наборы с щитами и "полезными невостребованными вещами" для востребования покупки.
+
+/datum/vox_pack/kit/kigyar
+ name = "Набор Киг-Йар"
+ desc = "Набор стрелка Киг-Йар для ведения боевых действий на средних дистанциях."
+ time_until_available = 30
+ discount_div = 0.5
+ reference = "K_KIG"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/lamilar,
+ /datum/vox_pack/clothes/magboots/scout,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/melee/dropwall,
+ /datum/vox_pack/melee/dropwall,
+ /datum/vox_pack/melee/shield,
+ /datum/vox_pack/spike/gun,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/clothes/eye_night,
+ )
+
+/datum/vox_pack/kit/kigyar/long
+ name = "Набор Киг-Йар Пронзателя"
+ desc = "Набор Киг-Йар для ведения боевых действий сквозь укрытия."
+ reference = "K_KIG_LONG"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/lamilar/scout,
+ /datum/vox_pack/clothes/magboots/scout,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/melee/dropwall,
+ /datum/vox_pack/melee/shield,
+ /datum/vox_pack/spike/gun/long,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ /datum/vox_pack/spike/cell,
+ )
+ contains_addition = list(
+ /obj/item/clothing/glasses/thermal/monocle,
+ )
+
+/datum/vox_pack/kit/kigyar/bio
+ name = "Набор Киг-Йар Биоштурмовика"
+ desc = "Набор Киг-Йар для ведения боевых действий в ближнем бою"
+ reference = "K_KIG_BIO"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/bomber,
+ /datum/vox_pack/clothes/magboots/combat,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/melee/shield,
+ /datum/vox_pack/spike/gun/bio,
+ /datum/vox_pack/consumables/food,
+ /datum/vox_pack/consumables/food,
+ /datum/vox_pack/consumables/food,
+ /datum/vox_pack/consumables/food,
+ /datum/vox_pack/consumables/food,
+ /datum/vox_pack/consumables/food,
+ )
+ contains_addition = list(
+ /obj/item/clothing/glasses/sunglasses/big,
+ )
+
+/datum/vox_pack/kit/kigyar/biotech
+ name = "Набор Киг-Йар Биотехника"
+ desc = "Набор Киг-Йар хозяина биоядер."
+ reference = "K_KIG_BIOTECH"
+ cost = 100
+ packs_list = list(
+ /datum/vox_pack/mercenary/fieldmedic,
+ /datum/vox_pack/clothes/magboots/scout,
+ /datum/vox_pack/clothes/radio/alt,
+ /datum/vox_pack/clothes/gloves/insulated,
+ /datum/vox_pack/melee/shield,
+ /datum/vox_pack/bio/gun,
+ /datum/vox_pack/clothes/belt/bio,
+ /datum/vox_pack/bio/core/kusaka,
+ /datum/vox_pack/bio/core/kusaka,
+ /datum/vox_pack/bio/core/kusaka,
+ /datum/vox_pack/bio/core/kusaka,
+ /datum/vox_pack/bio/core/taran,
+ /datum/vox_pack/bio/core/tox,
+ /datum/vox_pack/bio/core/tox,
+ /datum/vox_pack/bio/core/acid,
+ /datum/vox_pack/bio/core/acid,
+ )
+ contains_addition = list(
+ /obj/item/clothing/glasses/sunglasses/big,
+ )
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_medicine.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_medicine.dm
new file mode 100644
index 000000000000..1b2a23af660c
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_medicine.dm
@@ -0,0 +1,58 @@
+/datum/vox_pack/medicine
+ name = "DEBUG Medicine Vox Pack"
+ category = VOX_PACK_MEDICINE
+
+/datum/vox_pack/medicine/blood
+ name = "Кровь"
+ desc = "Кровь предназначенная для переливания Воксам."
+ reference = "MED_BLOOD"
+ cost = 200
+ contains = list(/obj/item/reagent_containers/iv_bag/blood/vox)
+
+/datum/vox_pack/medicine/dart
+ name = "Медицинский дротик"
+ desc = "Дротик наполненный медикаментами от слабых повреждений."
+ reference = "MED_DART"
+ cost = 25
+ contains = list(/obj/item/reagent_containers/syringe/dart/medical)
+
+// 1 уровень
+/datum/vox_pack/medicine/dart/tainted
+ name = "Медицинский дротик - Просрочен"
+ desc = "Просроченный и списанный медицинский дротик."
+ reference = "MED_DART_TA"
+ cost = 10
+ contains = list(/obj/item/reagent_containers/syringe/dart/medical/tainted)
+
+// 2 уровень
+/datum/vox_pack/medicine/dart/heal
+ name = "Медицинский дротик - Лечебный"
+ desc = "Медицинский дротик для лечения тяжелых травм."
+ reference = "MED_DART_HE"
+ cost = 60
+ contains = list(/obj/item/reagent_containers/syringe/dart/medical/heal)
+
+/datum/vox_pack/medicine/dart/stabilizing
+ name = "Медицинский дротик - Стабилизирующий"
+ desc = "Медицинский дротик для стабилизации пациента."
+ reference = "MED_DART_ST"
+ cost = 80
+ contains = list(/obj/item/reagent_containers/syringe/dart/medical/stabilizing)
+
+// 3 уровень (1 час)
+/datum/vox_pack/medicine/dart/advanced
+ name = "Медицинский дротик - Продвинутый регенеративный"
+ desc = "Медицинский дротик стимулирующий быструю регенерацию."
+ reference = "MED_DART_AD"
+ time_until_available = 60
+ cost = 200
+ contains = list(/obj/item/reagent_containers/syringe/dart/medical/advanced)
+
+// 4 уровень (2 час)
+/datum/vox_pack/medicine/dart/combat
+ name = "Медицинский дротик - Боевой стимулянт"
+ desc = "передовой дротик с эксперементальными стимулянтами."
+ reference = "MED_DART_CO"
+ cost = 450
+ time_until_available = 120
+ contains = list(/obj/item/reagent_containers/syringe/dart/medical/combat)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_melee.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_melee.dm
new file mode 100644
index 000000000000..fce78cdf25bb
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_melee.dm
@@ -0,0 +1,89 @@
+
+/datum/vox_pack/melee
+ name = "DEBUG Melee Vox Pack"
+ category = VOX_PACK_MELEE
+
+// ============== Гарпун ==============
+
+/datum/vox_pack/melee/harpoon
+ name = "Гарпун"
+ desc = "Инструмент для охоты на космических китов."
+ reference = "MEL_HARP"
+ cost = 100
+ contains = list(/obj/item/harpoon)
+
+// ============== Щиты ==============
+
+/datum/vox_pack/melee/shield
+ name = "Энергощит"
+ desc = "Энергетический компактный ручной щит, пособный отражать энергетические снаряды, но не может блокировать прямые воздействия."
+ reference = "MEL_SH"
+ cost = 4000
+ contains = list(/obj/item/shield/energy)
+
+
+// ============== Мечи ==============
+
+/datum/vox_pack/melee/sword
+ name = "Энергосабля"
+ desc = "Энергетическая сабля для абордажей кораблей."
+ reference = "MEL_SW"
+ cost = 4000
+ time_until_available = 45
+ contains = list(/obj/item/melee/energy/sword/pirate)
+
+/datum/vox_pack/melee/sword/purple
+ name = "Энергомеч (Фиолетовый)"
+ desc = "Энергетический меч для прижигания ран отрубленных конечностей неприятеля. Цвет решительности, цвет Рейдеров. Классика Воксов."
+ reference = "MEL_SWP"
+ cost = 8000
+ time_until_available = 120
+ contains = list(/obj/item/melee/energy/sword/saber/purple)
+
+/datum/vox_pack/melee/sword/blue
+ name = "Энергомеч (Синий)"
+ desc = "Энергетический меч для прижигания ран отрубленных конечностей неприятеля. Цвет силы и стойкости. Его носят бастионы мира Воксов."
+ reference = "MEL_SWB"
+ cost = 10000
+ time_until_available = 120
+ contains = list(/obj/item/melee/energy/sword/saber/blue)
+
+/datum/vox_pack/melee/sword/green
+ name = "Энергомеч (Зелёный)"
+ desc = "Энергетический меч для прижигания ран отрубленных конечностей неприятеля. Цвет миротворцев, тех, кто не любит насилие и причиняет его с большой неохотой. С этим мечом причиняют добро и наносят радость."
+ reference = "MEL_SWG"
+ cost = 10000
+ time_until_available = 120
+ contains = list(/obj/item/melee/energy/sword/saber/green)
+
+/datum/vox_pack/melee/sword/red
+ name = "Энергомеч (Красный)"
+ desc = "Энергетический меч для прижигания ран отрубленных конечностей неприятеля. Цвет ненависти, гнева и злого злодейства злыхх злыдней. Безвкусица."
+ reference = "MEL_SWR"
+ cost = 12000
+ time_until_available = 120
+ contains = list(/obj/item/melee/energy/sword/saber/red)
+
+/datum/vox_pack/melee/fly
+ name = "Уничтожитель насекомых"
+ desc = "Всеми признанный лучший уничтожитель нианов и киданов."
+ reference = "MEL_FLY"
+ cost = 150
+ contains = list(/obj/item/melee/flyswatter)
+
+
+// ============== Раскладываемое ==============
+
+/datum/vox_pack/melee/dropwall
+ name = "Генератор щита"
+ desc = "Щитовой развертываемый генератор, активирующий временное укрытие, которое блокирует снаряды и взрывы с определенного направления, в то же время позволяя остальным снарядам свободно проходить сзади."
+ reference = "MEL_DW"
+ cost = 500
+ contains = list(/obj/item/grenade/barrier/dropwall)
+
+/datum/vox_pack/melee/inflatable
+ name = "Надувной Набор"
+ desc = "Развертываемый надувной набор для заделывания разгерметизаций."
+ reference = "MEL_IFL"
+ cost = 200
+ contains = list(/obj/item/storage/briefcase/inflatable)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_merc.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_merc.dm
new file mode 100644
index 000000000000..52a1848b5afc
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_merc.dm
@@ -0,0 +1,69 @@
+/datum/vox_pack/mercenary
+ name = "DEBUG Mercenary Vox Pack"
+ category = VOX_PACK_MERCENARIES
+ time_until_available = 10
+
+/datum/vox_pack/mercenary/lamilar
+ name = "Ламилярный Костюм"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ \nКомпактный и мобильный костюм отлично помещается в рюкзаке, сформирован из легких пластин позволяющий получить хорошие защитные свойства в совокупности с удобством для носителя, не мешающий его передвижению. Но, в отличии от других моделей, не дает приемлимых защитных параметров от воздействий внешней агрессивной среды и не защищает руки."
+ reference = "M_LAM"
+ cost = 500
+ contains = list(
+ /obj/item/clothing/suit/armor/vox_merc/laminar,
+ /obj/item/clothing/head/helmet/vox_merc/laminar
+ )
+
+/datum/vox_pack/mercenary/stormtrooper
+ name = "Штурмовой Бронекостюм"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ \nШтурмовой бронекостюм воксов разработан под их структуру тела и прикрывает наиболее уязвимые места, превосходно защищает носителя от огнестрельного вооружения и ближних атак."
+ reference = "M_STR"
+ cost = 2500
+ contains = list(
+ /obj/item/clothing/suit/armor/vox_merc/stormtrooper,
+ /obj/item/clothing/head/helmet/vox_merc/stormtrooper
+ )
+
+/datum/vox_pack/mercenary/fieldmedic
+ name = "Медицинский Полевой Костюм"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ \nМедицинский полевой костюм предназначен для защиты владельца от биологических угроз, радиации и кислотной атмосферы. Дает слабую защиту от внешне поступаемых энергетических снарядов, равномерно рассеивая остаточную энергию. Костюм абсолютно не предназначен для защиты в ближнем бою или от взрывчатых веществ за счет свое внутреннего строения, повреждающий носителя от осколков костюма при нарушении целостности. Имеет хранилище для ношения аптечек и контейнеров с химикатами."
+ reference = "M_FMC"
+ cost = 1000
+ contains = list(
+ /obj/item/clothing/suit/armor/vox_merc/fieldmedic,
+ /obj/item/clothing/head/helmet/vox_merc/fieldmedic
+ )
+
+/datum/vox_pack/mercenary/lamilar/scout
+ name = "Ламилярный Костюм Разведчика"
+ desc = "Компактный и мобильный костюм сформированный из лёгких пластин и за счет их особого размещения, увеличивает погашение импульсов перенаправляя их в ускорение носителя, но взамен теряя значимые защитные свойства. "
+ reference = "M_LAM_S"
+ cost = 1000
+ contains = list(
+ /obj/item/clothing/suit/armor/vox_merc/laminar/scout,
+ /obj/item/clothing/head/helmet/vox_merc/laminar
+ )
+
+/datum/vox_pack/mercenary/bomber
+ name = "Взрывозащитный Костюм"
+ desc = "Специализированный бронекостюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ \nОсобый разработанный штурмовой тяжелый костюм для действий в условиях крайне взрывоопасной атмосферы. Абсолютная жаростойкость, повышенная стойкость к кислотным жидкостям и лазерному воздействию делают эту броню основной для воксов действующих внутри активно разрушающихся комплексов и кораблей."
+ reference = "M_BOM"
+ cost = 1500
+ contains = list(
+ /obj/item/clothing/suit/armor/vox_merc/bomber,
+ /obj/item/clothing/head/helmet/vox_merc/bomber
+ )
+
+/datum/vox_pack/mercenary/stealth
+ name = "Маскировочный Костюм"
+ desc = "Специализированный маскировочный костюм воксов-наемников. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными для большинства атмосфер с приемлимым давлением. \
+ Предназначен для скрытых операций."
+ reference = "M_STE"
+ cost = 4500
+ contains = list(
+ /obj/item/clothing/suit/armor/vox_merc/stealth,
+ /obj/item/clothing/head/helmet/vox_merc/stealth,
+ )
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_raider.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_raider.dm
new file mode 100644
index 000000000000..dcdb8d2aff13
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_raider.dm
@@ -0,0 +1,58 @@
+/datum/vox_pack/raider
+ name = "DEBUG Raider Vox Pack"
+ category = VOX_PACK_RAIDER
+
+/datum/vox_pack/raider/trooper
+ name = "Скафандр Штурмовика"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nКостюм космического штурмовика рейдеров с защитой от огнестрела и колюще-режущего."
+ reference = "R_TRR"
+ cost = 6000
+ time_until_available = 60
+ contains = list(
+ /obj/item/clothing/suit/space/hardsuit/vox/trooper
+ )
+
+/datum/vox_pack/raider/scout
+ name = "Скафандр Разведчика"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nКостюм разведчика не сковывает движение и помогает владельцу удобней двигаться в условиях невесомости."
+ reference = "R_SCT"
+ cost = 4000
+ time_until_available = 45
+ contains = list(
+ /obj/item/clothing/suit/space/hardsuit/vox/scout
+ )
+
+/datum/vox_pack/raider/medic
+ name = "Скафандр Медика"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nКостюм для работы в условиях отдаленности от опасностей. Более подвижен и обладает приемлимыми свойствами защиты от воздействий различного рода снарядов, но из-за своей структуры способен нанести вред носителю при взрывных воздействиях или колющих атак. Костюм отлично выдерживает радиационный фон и кислотное воздействие и биологическими угрозами. Имеет хранилище для ношения аптечек контейнеров с химикатами."
+ reference = "R_MED"
+ cost = 3500
+ time_until_available = 45
+ contains = list(
+ /obj/item/clothing/suit/space/hardsuit/vox/medic
+ )
+
+/datum/vox_pack/raider/mechanic
+ name = "Скафандр Механика"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nКостюм для работы в условиях крайне опасных и недружелюбных атмосфер. За счет своей структуры и технологии рассеивания тепла, костюм обладает хорошей защитой от энергетического оружия."
+ reference = "R_MEC"
+ cost = 4000
+ time_until_available = 45
+ contains = list(
+ /obj/item/clothing/suit/space/hardsuit/vox/mechanic
+ )
+
+/datum/vox_pack/raider/heavy
+ name = "Тяжелый Бронескафандр"
+ desc = "Специализированный космический защитный костюм воксов-рейдеров. Синтетический материал используемый в костюмах воксов позволяет тем действовать в неблагоприятных для них окружающих условиях, делая их костюмы универсальными. За счет иной структуры, костюм рейдеров уступает в защитных свойствах костюму наемников. \
+ \nТяжелый огнеупорный и взрывостойкий костюм рейдеров с превосходной защитой от энергетического оружия и колюще-режущих и приемлимой от огнестрела. Костюм был разработан для противостояния механизированным силам в условиях космического пространства. К сожалению, его вес и ресиверы не настолько совершены, из-за чего он уступает в скорости."
+ reference = "R_HEV"
+ cost = 20000
+ time_until_available = 90
+ contains = list(
+ /obj/item/clothing/suit/space/hardsuit/vox/heavy
+ )
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_spike.dm b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_spike.dm
new file mode 100644
index 000000000000..d6de59e5165d
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/packs/vox_shop_pack_spike.dm
@@ -0,0 +1,40 @@
+/datum/vox_pack/spike
+ name = "DEBUG Spike Vox Pack"
+ category = VOX_PACK_SPIKE
+
+
+// ============== GUNS ==============
+
+/datum/vox_pack/spike/gun
+ name = "Шипомет"
+ desc = "Стандартный универсальный шипомет, перезаряжаемый через съемные батареи. Выстреливает энергетическими кристаллами. Никто кроме Воксов не сможет взять его в руки."
+ reference = "S_G"
+ cost = 1300
+ time_until_available = 45
+ contains = list(/obj/item/gun/energy/spike)
+
+/datum/vox_pack/spike/gun/long
+ name = "Длинный Шипомет"
+ desc = "Точное оружие с самовосстанавливающимися снарядами способное пронизить шипами сразу несколько целей по пути полета. Выстреливает длинными энергетическими кристаллами с увеличенной проникающей способностью, за счет снижения смертоносности. Подходит для толп противников. Никто кроме Воксов не сможет взять его в руки."
+ reference = "S_GL"
+ cost = 1800
+ time_until_available = 60
+ contains = list(/obj/item/gun/energy/spike/long)
+
+/datum/vox_pack/spike/gun/bio
+ name = "Био Шипомет"
+ desc = "Оружие восстанавливающее снаряды за счет нутриентов носителя-Вокса, но пожирает другие виды органиков при попытке его использования. Выстреливает большими энергетическими заостренными кристаллами, выматывающие цель. Подходит для сражения с одиночной целью на ближних дистанциях. Никто кроме Воксов не сможет взять его в руки. Чем дальше летит снаряд, тем больше он теряет в своей скорости и эффективности."
+ reference = "S_GB"
+ cost = 3000
+ time_until_available = 60
+ contains = list(/obj/item/gun/energy/spike/bio)
+
+// ============== AMMO ==============
+
+/datum/vox_pack/spike/cell
+ name = "Зарядная Ячейка"
+ desc = "Стандартная зарядная ячейка подходящая под большинство шипометов."
+ reference = "S_C"
+ cost = 100
+ time_until_available = 45
+ contains = list(/obj/item/stock_parts/cell/vox_spike)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/vox_cash.dm b/modular_ss220/antagonists/code/vox_raider/objects/vox_cash.dm
new file mode 100644
index 000000000000..014b30b14ede
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/vox_cash.dm
@@ -0,0 +1,68 @@
+/obj/item/stack/vox_cash
+ name = "Кикиридиты"
+ desc = "Криптографический чип доступа к адресам транзакций рассчетных средств воксов."
+ icon = 'modular_ss220/antagonists/icons/trader_machine.dmi'
+ icon_state = "vox_key"
+ hitsound = "swing_hit"
+ force = 1
+ throwforce = 1
+ throw_speed = 1
+ throw_range = 7
+ w_class = WEIGHT_CLASS_TINY
+ max_amount = MAX_STACKABLE_CASH*10
+ merge_type = /obj/item/stack/vox_cash
+
+/obj/item/stack/vox_cash/proc/rename_amount()
+ name = "[initial(name)] ([get_amount()])"
+
+/obj/item/stack/vox_cash/Initialize(mapload, new_amount, merge)
+ . = ..()
+ rename_amount()
+
+/obj/item/stack/vox_cash/merge(obj/item/stack/S)
+ . = ..()
+ rename_amount()
+
+/obj/item/stack/vox_cash/use(used, check = TRUE)
+ . = ..()
+ rename_amount()
+
+/obj/item/stack/vox_cash/add(newamount)
+ . = ..()
+ rename_amount()
+
+/obj/item/stack/vox_cash/c5
+ amount = 5
+
+/obj/item/stack/vox_cash/c10
+ amount = 10
+
+/obj/item/stack/vox_cash/c20
+ amount = 20
+
+/obj/item/stack/vox_cash/c50
+ amount = 50
+
+/obj/item/stack/vox_cash/c100
+ amount = 100
+
+/obj/item/stack/vox_cash/c200
+ amount = 200
+
+/obj/item/stack/vox_cash/c500
+ amount = 500
+
+/obj/item/stack/vox_cash/c1000
+ amount = 1000
+
+/obj/item/stack/vox_cash/c10000
+ amount = 10000
+
+/obj/item/stack/vox_cash/c25000
+ amount = 25000
+
+/obj/item/stack/vox_cash/c50000
+ amount = 50000
+
+/obj/item/stack/vox_cash/c100000
+ amount = 100000
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/vox_objects.dm b/modular_ss220/antagonists/code/vox_raider/objects/vox_objects.dm
new file mode 100644
index 000000000000..29cde724718c
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/vox_objects.dm
@@ -0,0 +1,26 @@
+/obj/item/clothing/glasses/meson/cyber/vox
+ name = "Мезонный Глаз Воксов"
+ desc = "Мезонный кибернетический глаз с системой вставки в глазной разъем. Полностью заменяет функционирующий глаз или его полость. \
+ ВНИМАНИЕ! Глаз возможно удалить только хирургическим путем. Из-за своего размера - не позволяет надевать прочие приблуды на глаза, заменяя очки."
+ flags = 0
+
+/obj/item/clothing/glasses/meson/cyber/vox/equipped(mob/user, slot, initial)
+ . = ..()
+ if(slot == ITEM_SLOT_EYES)
+ flags = NODROP
+ else
+ flags = initial(flags)
+
+/obj/item/clothing/glasses/thermal/cyber/vox
+ name = "Термальный Глаз Воксов"
+ desc = "Термальный кибернетический глаз с системой вставки в глазной разъем. Полностью заменяет функционирующий глаз или его полость. \
+ ВНИМАНИЕ! Глаз возможно удалить только хирургическим путем. Из-за своего размера - не позволяет надевать прочие приблуды на глаза, заменяя очки."
+ flags = 0
+
+/obj/item/clothing/glasses/thermal/cyber/vox/equipped(mob/user, slot, initial)
+ . = ..()
+ if(slot == ITEM_SLOT_EYES)
+ flags = NODROP
+ else
+ flags = initial(flags)
+
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/vox_shop.dm b/modular_ss220/antagonists/code/vox_raider/objects/vox_shop.dm
new file mode 100644
index 000000000000..64a7e22ee851
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/vox_shop.dm
@@ -0,0 +1,296 @@
+/obj/machinery/vox_shop
+ name = "Киконсоль Закиказов"
+ desc = "Технология связывающая воксов на дальних рубежах."
+ icon = 'modular_ss220/antagonists/icons/trader_machine.dmi'
+ icon_state = "shop"
+ max_integrity = 5000
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ anchored = TRUE
+ density = TRUE
+ var/cash_stored = 0
+
+ var/list/packs_cats = list() // Категории по предметам - ui_static_data
+ var/list/packs_items = list() // Все доступные предметы
+
+ var/list/cart_list
+ var/list/cart_data
+
+
+// ============ DATA ============
+
+/obj/machinery/vox_shop/Initialize(mapload)
+ . = ..()
+ generate_pack_items()
+ generate_pack_lists()
+
+/obj/machinery/vox_shop/proc/generate_pack_items()
+ var/list/shop_items = list()
+ var/obj/machinery/vox_trader/trader = locate() in GLOB.machines
+ for(var/path in subtypesof(/datum/vox_pack))
+ var/datum/vox_pack/pack = new path
+ if(pack.cost < 0)
+ continue
+ if(pack.is_need_trader_cost)
+ var/list/pack_contents = list()
+ for(var/object_type in pack.contains)
+ var/obj/O = new object_type()
+ pack_contents.Add(O)
+ var/pack_trader_cost = trader.get_value(null, pack_contents, TRUE)
+ QDEL_LIST_CONTENTS(pack_contents)
+ pack.cost += pack_trader_cost
+ if(!shop_items[pack.category])
+ shop_items[pack.category] = list()
+ shop_items[pack.category] += pack
+
+ packs_items = shop_items
+
+/obj/machinery/vox_shop/proc/generate_pack_lists()
+ var/list/cats = list()
+ for(var/category in packs_items)
+ cats[++cats.len] = list("cat" = category, "items" = list())
+ for(var/datum/vox_pack/pack in packs_items[category])
+ cats[cats.len]["items"] += list(list(
+ "name" = sanitize(pack.name),
+ "desc" = sanitize(pack.description()),
+ "cost" = pack.cost,
+ "obj_path" = pack.reference
+ ))
+ packs_items[pack.reference] = pack
+
+ packs_cats = cats
+ SStgui.update_uis(src)
+
+
+// ======= Interaction ==========
+
+/obj/machinery/vox_shop/attack_hand(mob/user)
+ if(!check_usable(user))
+ return
+ add_fingerprint(user)
+ ui_interact(user)
+
+/obj/machinery/vox_shop/proc/check_usable(mob/user)
+ . = FALSE
+ if(issilicon(user))
+ return
+ if(!isvox(user))
+ to_chat(user, span_notice("Вы осматриваете [src] и не понимаете как оно работает и куда сувать свои пальцы..."))
+ return
+ return TRUE
+
+/obj/machinery/vox_shop/attack_ai(mob/user)
+ return FALSE
+
+/obj/machinery/vox_shop/attackby__legacy__attackchain(obj/item/O, mob/user, params)
+ if(isvoxcash(O))
+ user.do_attack_animation(src)
+ insert_cash(O, user)
+ return TRUE
+ . = ..()
+
+/obj/machinery/vox_shop/proc/insert_cash(obj/item/stack/vox_cash, mob/user)
+ visible_message("[user] загрузил [vox_cash] в [src].")
+ cash_stored += vox_cash.amount
+ vox_cash.use(vox_cash.amount)
+ return TRUE
+
+/// Размещение предметов в отдельные емкости
+/obj/machinery/vox_shop/proc/make_container(mob/user, list/typepath_objects)
+ var/is_heavy = FALSE
+ var/list/objs_for_contain = list()
+
+ // Создаем объекты
+ for(var/typepath in typepath_objects)
+ var/obj/obj = new typepath()
+ objs_for_contain.Add(obj)
+ if(is_heavy)
+ continue
+ if(isitem(obj))
+ var/obj/item/item = obj
+ if(item.w_class >= WEIGHT_CLASS_NORMAL)
+ is_heavy = TRUE
+
+ // Размещаем по емкостям
+ if(length(objs_for_contain) > 2)
+ var/container_type = is_heavy ? /obj/structure/closet/crate/trashcart : /obj/item/storage/box
+ var/obj/container = new container_type(get_turf(src))
+ for(var/obj/obj in objs_for_contain)
+ obj.forceMove(container)
+ else if(length(objs_for_contain))
+ for(var/obj/obj as anything in objs_for_contain)
+ if(isitem(obj))
+ if(!user.put_in_any_hand_if_possible(obj) && ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.equip_or_collect(obj, ITEM_SLOT_IN_BACKPACK)
+ else
+ obj.forceMove(get_turf(src))
+
+ do_sparks(5, 1, get_turf(src))
+
+
+// ============= UI =============
+
+/obj/machinery/vox_shop/ui_interact(mob/user, datum/tgui/ui = null)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Shop", name)
+ ui.open()
+
+/obj/machinery/vox_shop/ui_data(mob/user)
+ var/list/data = list()
+
+ data["cash"] = cash_stored
+ data["cart"] = generate_tgui_cart()
+ data["cart_price"] = calculate_cart_cash()
+
+ var/list/vox_raider_members = list()
+ for(var/datum/team/vox_raiders/team in subtypesof(/datum/team/vox_raiders))
+ vox_raider_members.Add(team.members)
+ data["vox_members"] = vox_raider_members
+ // data["crewmembers"] = GLOB.crew_repository.health_data(viewing_current_z_level)
+ // data["critThreshold"] = HEALTH_THRESHOLD_CRIT
+
+ return data
+
+/obj/machinery/vox_shop/ui_static_data(mob/user)
+ var/list/static_data = list()
+
+ if(!packs_cats || !packs_items)
+ generate_pack_lists(user)
+ //static_data["packs"] = packs_items
+ static_data["cats"] = packs_cats
+
+ return static_data
+
+/obj/machinery/vox_shop/ui_act(action, list/params, datum/tgui/ui)
+ if(..())
+ return
+
+ . = TRUE
+
+ switch(action)
+ if("add_to_cart")
+ add_to_cart(params, ui.user)
+
+ if("remove_from_cart")
+ remove_from_cart(params)
+
+ if("set_cart_item_quantity")
+ set_cart_item_quantity(params)
+
+ if("purchase_cart")
+ if(!LAZYLEN(cart_list))
+ return
+ var/cart_cash = calculate_cart_cash()
+ if(cart_cash > cash_stored)
+ to_chat(ui.user, "[src] недостаточно кикиридитов! Неси больше!")
+ return
+
+ var/list/bought_typepath_objects = list()
+ for(var/reference in cart_list)
+ var/datum/vox_pack/pack = packs_items[reference]
+ var/amount = cart_list[reference]
+ if(amount <= 0)
+ continue
+ var/list/purchase_list = mass_purchase(pack, pack ? pack.reference : "", amount)
+ if(!length(purchase_list))
+ to_chat(ui.user, span_warning("[pack.name] - превысил допустимое возможное количество для покупки."))
+ return
+ bought_typepath_objects += purchase_list
+
+ // Обновляем количество купленного товара
+ for(var/reference in cart_list)
+ var/datum/vox_pack/pack = packs_items[reference]
+ if(pack.limited_stock < 0)
+ continue
+ var/amount = pack.purchased + cart_list[reference]
+ pack.purchased += amount
+
+ // Завершение покупки
+ make_container(ui.user, bought_typepath_objects)
+ cash_stored -= cart_cash
+ empty_cart()
+ SStgui.update_uis(src)
+
+ if("empty_cart")
+ empty_cart()
+
+
+// ========== UI Procs ==========
+
+/obj/machinery/vox_shop/proc/mass_purchase(datum/vox_pack/pack, reference, amount = 1)
+ if(!pack)
+ return
+ if(amount <= 0)
+ return
+ if(!pack.check_possible_buy(amount))
+ return
+ if(!pack.check_time_available())
+ return
+ var/list/bought_objects = list()
+ for(var/i in 1 to amount)
+ var/list/items_list = pack.get_items_list()
+ if(!length(items_list))
+ break
+ bought_objects += items_list
+ return bought_objects
+
+/obj/machinery/vox_shop/proc/calculate_cart_cash()
+ . = 0
+ for(var/reference in cart_list)
+ var/datum/vox_pack/item = packs_items[reference]
+ var/amount = cart_list[reference]
+ . += item.cost * amount
+
+/obj/machinery/vox_shop/proc/generate_tgui_cart(update = FALSE)
+ if(!update)
+ return cart_data
+
+ if(!length(cart_list))
+ cart_list = null
+ cart_data = null
+ return cart_data
+
+ cart_data = list()
+ for(var/reference in cart_list)
+ var/datum/vox_pack/pack = packs_items[reference]
+ cart_data += list(list(
+ "name" = sanitize(pack.name),
+ "desc" = sanitize(pack.description()),
+ "cost" = pack.cost,
+ "obj_path" = pack.reference,
+ "amount" = cart_list[reference],
+ "limit" = pack.limited_stock,
+ "is_time_available" = pack.check_time_available()
+ ))
+
+/obj/machinery/vox_shop/proc/add_to_cart(params, mob/user)
+ var/item = params["item"]
+ var/amount = 1
+ var/datum/vox_pack/pack = packs_items[item]
+ if(LAZYIN(cart_list, item))
+ amount += cart_list[item]
+ if(!pack.check_possible_buy(amount))
+ to_chat(user, span_warning("[pack.name] больше невозможно купить!"))
+ return
+ if(!pack.check_time_available())
+ to_chat(user, span_warning("[pack.name] будет доступен к покупке в [pack.get_time_available()], осталось [pack.get_time_left()]"))
+ return
+ LAZYSET(cart_list, item, max(amount, 1))
+ generate_tgui_cart(TRUE)
+
+/obj/machinery/vox_shop/proc/remove_from_cart(params)
+ LAZYREMOVE(cart_list, params["item"])
+ generate_tgui_cart(TRUE)
+
+/obj/machinery/vox_shop/proc/empty_cart()
+ cart_list = null
+ generate_tgui_cart(TRUE)
+
+/obj/machinery/vox_shop/proc/set_cart_item_quantity(params)
+ var/amount = text2num(params["quantity"])
+ if(amount <= 0)
+ remove_from_cart(params)
+ return
+ LAZYSET(cart_list, params["item"], max(amount, 0))
+ generate_tgui_cart(TRUE)
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/vox_trade.dm b/modular_ss220/antagonists/code/vox_raider/objects/vox_trade.dm
new file mode 100644
index 000000000000..70a741e8fa97
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/vox_trade.dm
@@ -0,0 +1,576 @@
+/obj/machinery/vox_trader
+ name = "Расчичетчикик"
+ desc = "Приемная и расчетная связная машина для ценностей. Проста также как еда воксов."
+ icon = 'modular_ss220/antagonists/icons/trader_machine.dmi'
+ icon_state = "trader-idle-off"
+ var/icon_state_on = "trader-idle"
+ max_integrity = 5000
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ anchored = TRUE
+ density = FALSE
+
+ var/cooldown = 3 SECONDS
+ var/is_trading_now = FALSE
+
+ var/list/connected_instruments = list()
+
+ // Забавные взаимодействия
+ var/angry_count = 0
+ var/list/blacklist_users = list()
+
+ // Данные для подсчета драгоценностей выполнения задачи.
+ // Обновляются при первом взаимодействии если есть воксы-рейдеры.
+ var/precious_collected_dict = list()
+ var/all_values_sum = 0
+ var/precious_value
+ var/collected_access_list = list()
+ var/collected_tech_dict = list()
+
+ // Списки запрещенных для продажи товаров, инициализируется через отдельный PROC, а не тут
+ var/list/blacklist_objects = list()
+
+ // ========= МНОЖИТЕЛИ =========
+
+ // произведения за параметры
+ var/tech_mult = 6
+ var/weight_mult = 3
+ var/force_mult = 5
+
+ // делители за параметры
+ var/armor_div = 10
+ var/stack_div = 8
+ var/temp_div = 5
+ var/no_unique_tech_div = 4
+ var/denomination_div = 5
+
+ // дополнительные бонусы
+ var/integrity_reward = 5
+ var/electroprotect_reward = 50
+ var/permeability_reward = 20
+ var/highrisk_reward = 2500
+ var/valuable_highrisk_reward = 5000
+ var/value_access_reward = 100
+ var/valuable_access_reward = 500
+ var/unique_tech_level_reward = 300 // учитываем также множитель за технологии
+ var/stock_parts_rating_reward = 50
+
+ // дополнительные списки
+ var/list/highrisk_list = list()
+ var/list/valuable_highrisk_list = list(
+ /obj/item/areaeditor/blueprints/ce,
+ /obj/item/disk/nuclear,
+ /obj/item/clothing/suit/armor/reactive,
+ /obj/item/documents,
+ )
+ var/list/valuable_access_list = list() // определяется при инициализации
+ var/list/valuable_tech_list = list("bluespace", "syndicate", "combat", "abductor")
+
+ // дополнительные суммы за ценности
+ var/list/valuable_objects_dict = list(
+ /obj/machinery/nuclearbomb = 5000, // Ядро внутри является хайриском, оно дороже и учитывается при продаже. ~12.5k
+ /obj/item/mod/core = 1000,
+ /obj/item/mod = 300,
+ /obj/machinery/power/port_gen = 800,
+ /obj/machinery/power = 600,
+ /obj/machinery/the_singularitygen/tesla = 8000,
+ /obj/machinery/the_singularitygen = 6000,
+ /obj/structure/particle_accelerator = 3000,
+ /obj/machinery/power/emitter = 500,
+ /obj/machinery/atmospherics/supermatter_crystal = 15000,
+ /obj/machinery/satellite/meteor_shield = 1200,
+ /obj/item/circuitboard/computer/sat_control = 2000,
+ /obj/item/dna_probe = 150,
+ /obj/item/circuitboard/machine/dna_vault = 3000,
+ /obj/item/circuitboard/machine/bluespace_tap = 4500,
+ /obj/item/circuitboard/machine/bsa = 800,
+ /obj/machinery/snow_machine = 750,
+ /obj/structure/toilet/material/bluespace = 5000,
+ /obj/structure/toilet/material/captain = 3500,
+ /obj/structure/toilet/material/king = 2250,
+ /obj/structure/toilet/material/gold = 1250,
+ /obj/structure/toilet = 250,
+ /obj/machinery/shower = 150,
+ /obj/structure/urinal = 150,
+ )
+ var/list/valuable_guns_dict = list(
+ /obj/item/gun/energy/taser = 300,
+ /obj/item/gun/energy/disabler = 100,
+ /obj/item/gun/energy/lasercannon = 400,
+
+ /obj/item/gun/energy/gun/blueshield = 300,
+ /obj/item/gun/energy/gun/nuclear = 300,
+ /obj/item/gun/energy/gun/advtaser = 500,
+ /obj/item/gun/energy/gun = 150,
+
+ /obj/item/gun/energy/pulse = 3000,
+ /obj/item/gun/energy/ionrifle = 1000,
+ /obj/item/gun/energy/decloner = 500,
+ /obj/item/gun/energy/floragun = 500,
+ /obj/item/gun/energy/meteorgun = 500,
+ /obj/item/gun/energy/mindflayer = 500,
+ /obj/item/gun/energy/wormhole_projector = 800,
+ /obj/item/gun/energy/laser/instakill = 10000,
+ /obj/item/gun/energy/plasmacutter/adv = 300,
+ /obj/item/gun/energy/laser = 200,
+
+ /obj/item/gun/magic/staff = 10000,
+ /obj/item/gun/magic/wand = 5000,
+ /obj/item/gun/magic = 2000,
+
+ /obj/item/gun/projectile/automatic/toy = 10,
+ /obj/item/gun/projectile/automatic/lasercarbine = 800,
+ /obj/item/gun/projectile/automatic/laserrifle = 1000,
+ /obj/item/gun/projectile/automatic/pistol = 300,
+ /obj/item/gun/projectile/automatic/l6_saw = 3000,
+ /obj/item/gun/projectile/automatic/sniper_rifle = 2000,
+ /obj/item/gun/projectile/automatic = 500,
+ /obj/item/gun/projectile = 300,
+
+ /obj/item/gun/rocketlauncher = 1000,
+ /obj/item/gun/medbeam = 2000,
+ /obj/item/gun/throw/crossbow = 300,
+ /obj/item/gun/syringe = 200,
+ )
+ // =============================
+
+/obj/machinery/vox_trader/Initialize(mapload)
+ . = ..()
+ for(var/theft_type in subtypesof(/datum/theft_objective))
+ highrisk_list += new theft_type
+ valuable_access_list += get_region_accesses(REGION_COMMAND) + get_all_centcom_access() + get_all_syndicate_access() + get_all_misc_access()
+
+/obj/machinery/vox_trader/attack_hand(mob/user)
+ if(!try_trade(user))
+ . = ..()
+
+/obj/machinery/vox_trader/attacked_by(obj/item/I, mob/living/user)
+ . = ..()
+ if(istype(I, /obj/item/hand_valuer))
+ var/obj/item/hand_valuer/valuer = I
+ valuer.connect(user, src)
+
+/obj/machinery/vox_trader/attack_ai(mob/user)
+ return FALSE // Ха-ха, глупая железяка не понимает как пользоваться технологиями ВОКСов!
+
+/obj/machinery/vox_trader/proc/check_usable(mob/user)
+ . = FALSE
+ if(issilicon(user))
+ return
+ if(!isvox(user))
+ to_chat(user, span_notice("Вы осматриваете [src] и не понимаете как оно работает и куда сувать свои пальцы..."))
+ return
+ if(is_trading_now)
+ to_chat(user, span_warning("[src] обрабатываем и пересчитывает ценности. Ожидайте."))
+ return
+ if(length(blacklist_users) && (user in blacklist_users))
+ to_chat(user, span_warning("Вы пытаетесь связаться с [src], но никто не отзывается."))
+ return
+ return TRUE
+
+/obj/machinery/vox_trader/proc/sparks()
+ do_sparks(5, 1, get_turf(src))
+
+/obj/machinery/vox_trader/proc/try_trade(mob/user)
+ if(!check_usable(user))
+ return FALSE
+ add_fingerprint(user)
+ user.do_attack_animation(src)
+ trade_start()
+ addtimer(CALLBACK(src, PROC_REF(do_trade), user), cooldown)
+ return TRUE
+
+/obj/machinery/vox_trader/proc/do_trade(mob/user)
+ var/list/items_list = get_trade_contents(user)
+ INVOKE_ASYNC(src, PROC_REF(make_cash), user, items_list)
+
+/obj/machinery/vox_trader/proc/make_cash(mob/user, list/items_list)
+ if(!src || QDELETED(src))
+ return
+
+ var/values_sum = get_value(user, items_list)
+
+ if(values_sum <= 10)
+ if(values_sum <= 0)
+ angry_count++
+ switch(angry_count)
+ if(3)
+ atom_say(span_warning("Вами очень недовольны. Где товар?!"))
+ if(4)
+ atom_say(span_warning("Вами ОЧЕНЬ недовольны... Нам нужен реальный товар!"))
+ if(5)
+ atom_say(span_warning("Отправляй товар!"))
+ if(6)
+ atom_say(span_warning("Что ты щелкаешь как дятел?!"))
+ if(7)
+ atom_say(span_warning("Или ты будешь отправлять товар или не будешь больше отправлять ничего!"))
+ if(8)
+ atom_say(span_warning("Я не буду с тобой торговать пока ты не дашь товар!"))
+ if(9)
+ atom_say(span_warning("Ты шутки шутишь? Товар. Последнее предупреждение."))
+ if(10)
+ atom_say(span_warning("[user.name], [src] больше не будет с вами торговать!"))
+ blacklist_users.Add(user) // Докикикировался.
+ else
+ atom_say(span_warning("Вами недовольны. Где товар?"))
+ else
+ atom_say(span_notice("Расчет окончен. Средства отправлены на транспортные погашения."))
+ trade_cancel()
+ return
+ if(values_sum > 100)
+ all_values_sum += values_sum
+ atom_say(span_greenannounce("Расчет окончен. [values_sum > 2000 ? "Крайне ценно!" : "Ценно!"] Ваша доля [values_sum]"))
+ else
+ atom_say(span_notice("Расчет окончен. Вы бы еще консервных банок насобирали! Ваша доля [values_sum]"))
+
+ angry_count = 0
+ trade_cancel()
+ beam()
+ new /obj/item/stack/vox_cash(get_turf(src), values_sum)
+
+/obj/machinery/vox_trader/proc/trade_start()
+ is_trading_now = TRUE
+ icon_state = icon_state_on
+ sparks()
+ playsound(get_turf(src), 'sound/weapons/flash.ogg', 25, 1)
+ try_update_blacklist()
+
+/obj/machinery/vox_trader/proc/trade_cancel()
+ is_trading_now = FALSE
+ icon_state = initial(icon_state)
+ sparks()
+
+/obj/machinery/vox_trader/proc/beam()
+ playsound(get_turf(src), 'sound/weapons/contractorbatonhit.ogg', 25, TRUE)
+ flick("trader-beam", src)
+
+/obj/machinery/vox_trader/proc/get_value(mob/user, list/items_list, is_visuale_only = FALSE)
+ var/values_sum = 0
+ var/values_sum_precious = 0 // считаем сумму без скидки, например для хайрисков и уникальных доступов. Оцень ценных вещей.
+ var/accepted_access = list()
+
+ // проверка для бонусной диалоговой строки
+ var/is_weight = FALSE
+ var/is_equip = FALSE
+ var/is_tech = FALSE
+ var/is_tech_valuable = FALSE
+ var/is_tech_unique = FALSE
+ var/is_access_unique = FALSE
+
+ for(var/obj/I in items_list)
+ if(I.anchored)
+ continue
+
+ if(isspacecash(I) || isvoxcash(I)) // воксам не нужны деньги мяса.
+ continue
+
+ var/temp_values_sum = 0
+ var/temp_values_sum_precious = 0
+
+ // целостность объекта
+ if(I.obj_integrity > 0)
+ temp_values_sum += round((I.obj_integrity / I.max_integrity) * integrity_reward)
+
+ if(length(I.armor))
+ var/temp_val = 0
+ var/list/armor_list = I.armor.getList()
+ for(var/param in armor_list)
+ var/param_value = armor_list[param] == INFINITY ? 500 : armor_list[param]
+ if(param_value == 0)
+ continue
+ var/div = 1
+ if(param in list(FIRE, ACID))
+ div = armor_div // избегаем легких очков за часто встречаемые свойства.
+ temp_val += div > 1 ? round(param_value / div) : temp_val
+ if(temp_val)
+ temp_values_sum += temp_val
+ is_equip = TRUE
+
+ if(I.force || I.throwforce)
+ temp_values_sum += round((I.force + I.throwforce) * force_mult + (throw_speed * throw_range))
+
+ if(istype(I, /obj/item/disk/tech_disk))
+ var/obj/item/disk/tech_disk/disk = I
+ if(disk.tech_id)
+ I.origin_tech = "[disk.tech_id]=[disk.tech_level]"
+
+ if(I.origin_tech)
+ var/list/tech_list = params2list(I.origin_tech)
+ for(var/tech in tech_list)
+ var/temp_mult = 1
+ var/tech_value = text2num(tech_list[tech])
+ if(tech in collected_tech_dict)
+ if(collected_tech_dict[tech] < tech_value)
+ temp_values_sum_precious += unique_tech_level_reward * (tech_value - collected_tech_dict[tech])
+ if(!is_visuale_only)
+ collected_tech_dict[tech] = tech_value
+ is_tech_unique = TRUE
+ else
+ temp_values_sum_precious += unique_tech_level_reward * tech_value
+ if(!is_visuale_only)
+ collected_tech_dict += list("[tech]" = tech_value)
+ is_tech_unique = TRUE
+ if(tech in valuable_tech_list)
+ temp_mult = tech_value
+ is_tech_valuable = TRUE
+ var/excess_mult = text2num(tech_value) > 7 ? 2 : 1 // переизбыток
+ temp_values_sum += round(tech_value * temp_mult * excess_mult)
+ is_tech = TRUE
+
+ if(istype(I, /obj/item/stack))
+ var/obj/item/stack/stack = I
+ var/point_value = 1
+ if(istype(I, /obj/item/stack/sheet))
+ var/obj/item/stack/sheet/sheet = stack
+ point_value += sheet.point_value
+ temp_values_sum *= round(stack.amount / stack_div * point_value)
+
+ if(istype(I, /obj/item/card/id))
+ var/obj/item/card/id/id = I
+ for(var/access in id.access)
+ if(access in collected_access_list)
+ continue
+ if(access in valuable_access_list)
+ temp_values_sum_precious += valuable_access_reward
+ is_access_unique = TRUE
+ else
+ temp_values_sum_precious += value_access_reward
+ accepted_access += access
+
+ if(isitem(I))
+ var/temp_value = 0
+ var/obj/item/item = I
+ temp_value += temp_values_sum / item.toolspeed
+ if(item.max_heat_protection_temperature)
+ temp_value += item.max_heat_protection_temperature / temp_div
+ if(item.siemens_coefficient)
+ temp_value += electroprotect_reward * (1 - item.siemens_coefficient)
+ if(item.permeability_coefficient)
+ temp_value += permeability_reward * (1 - item.permeability_coefficient)
+ if(item.w_class)
+ temp_value += item.w_class * weight_mult
+ if(item.w_class >= WEIGHT_CLASS_BULKY)
+ is_weight = TRUE
+ temp_values_sum += round(temp_value)
+
+ if(istype(I, /obj/item/stock_parts))
+ var/obj/item/stock_parts/part = I
+ temp_values_sum += part.rating * stock_parts_rating_reward
+
+ for(var/datum/theft_objective/objective in highrisk_list)
+ if(!istype(I, objective.typepath))
+ continue
+ var/temp_value = highrisk_reward
+ if(objective.special_equipment)
+ temp_value *= 2
+ if(objective.protected_jobs)
+ for(var/job in objective.protected_jobs)
+ switch(job)
+ if("Captain", "Head Of Security")
+ temp_value *= 2
+ else
+ temp_value *= 1.5
+ temp_values_sum_precious += temp_value
+
+ if(I in valuable_highrisk_list)
+ temp_values_sum_precious += valuable_highrisk_reward
+
+ for(var/valuable_type in valuable_objects_dict)
+ if(!istype(I, valuable_type))
+ continue
+ temp_values_sum_precious += valuable_objects_dict[valuable_type]
+ break
+
+ if(istype(I, /obj/item/gun))
+ for(var/valuable_type in valuable_guns_dict)
+ if(!istype(I, valuable_type))
+ continue
+ temp_values_sum_precious += valuable_guns_dict[valuable_type]
+ break
+
+ temp_values_sum /= denomination_div // деноминируем
+
+ //Оцениваем драгоценность для задания
+ if(!is_visuale_only)
+ precious_grading(user, I, temp_values_sum + temp_values_sum_precious)
+
+ // ____________________________
+ // Завершаем рассчет
+ values_sum += temp_values_sum
+ values_sum_precious += temp_values_sum_precious
+
+ if(!is_visuale_only && (temp_values_sum + temp_values_sum_precious) >= 0)
+ var/obj/O = I
+ if(ismob(O.loc)) // Cyborg Parts, wearing clothes, but not contents
+ var/mob/M = O
+ M.unEquip(I)
+ qdel(I)
+
+ var/addition_text = ""
+ if(length(accepted_access))
+ if(!is_visuale_only) // Заносим наши принятые доступы
+ collected_access_list += accepted_access
+ addition_text += span_boldnotice("\nОценка имеющихся доступов: \n")
+ for(var/access in accepted_access)
+ var/access_desc = get_access_desc(access)
+ if(!access_desc)
+ continue
+ addition_text += span_notice("[access_desc]; ")
+ if(is_access_unique)
+ addition_text += span_good("\nИмеются ценные доступы. Очень ценно!")
+ if(is_weight)
+ addition_text += span_notice("\nТяжесть - значит надежность.")
+ if(is_equip)
+ addition_text += span_notice("\nХорошее снаряжение. Ценно.")
+ if(is_tech)
+ addition_text += span_notice("\nТехнологии - ценно!")
+ if(is_tech_unique)
+ addition_text += span_notice("\nНовые технологии! Очень ценно! Необходимо!")
+ if(is_tech_valuable)
+ addition_text += span_notice("\nЦенные технологии! Крайне ценно!")
+
+ if(!is_visuale_only && is_tech_unique)
+ update_shops()
+ addition_text += span_notice("\nЦены на некоторые товары снижены!")
+
+ if(user && addition_text != "")
+ to_chat(user, chat_box_notice(addition_text))
+
+ values_sum -= values_sum % 10 // забираем процентик в семью
+ values_sum += values_sum_precious // Даем бонус за особые ценности
+ return round(values_sum)
+
+/obj/machinery/vox_trader/proc/precious_grading(mob/user, obj/O, value)
+ if(!user)
+ return
+ if(!correct_precious_value(user))
+ return
+ update_precious_collected_dict(O.name, value)
+
+/obj/machinery/vox_trader/proc/correct_precious_value(mob/user)
+ if(precious_value)
+ return TRUE
+ if(!user)
+ return FALSE
+ var/list/objectives = user.mind?.get_all_objectives()
+ if(!length(objectives))
+ return FALSE
+ var/datum/objective/raider_steal/objective = locate() in objectives
+ precious_value = objective.precious_value
+ return TRUE
+
+/obj/machinery/vox_trader/proc/update_precious_collected_dict(object_name, object_value)
+ if(!correct_precious_value())
+ return
+ if(object_value >= precious_value)
+ var/precious_data = precious_collected_dict[object_name]
+ if(!precious_data)
+ precious_collected_dict[object_name] = list("count" = 1, "value" = object_value)
+ else
+ precious_data["count"]++
+ precious_data["value"] = max(precious_data["value"], object_value)
+
+/obj/machinery/vox_trader/proc/synchronize_traders_stats()
+ for(var/obj/machinery/vox_trader/trader in GLOB.machines)
+ if(trader == src)
+ continue
+
+ all_values_sum += trader.all_values_sum
+
+ for(var/access in trader.collected_access_list)
+ if(access in collected_access_list)
+ continue
+ collected_access_list += access
+
+ for(var/tech in trader.collected_tech_dict)
+ if(tech in collected_tech_dict)
+ collected_tech_dict[tech][1] = max(collected_tech_dict[tech][1], trader.collected_tech_dict[tech][1])
+ continue
+ collected_tech_dict += tech
+
+ for(var/dict in trader.precious_collected_dict)
+ update_precious_collected_dict(trader.precious_collected_dict[dict], trader.precious_collected_dict[dict]["value"])
+
+/obj/machinery/vox_trader/proc/get_trade_contents(mob/user)
+ var/turf/current_turf = get_turf(src)
+ var/list/items_list = current_turf.GetAllContents(7)
+
+ for(var/I in items_list)
+ for(var/blacklist_object in blacklist_objects)
+ if(istype(I, blacklist_object))
+ items_list.Remove(I)
+ continue
+ if(istype(I, /obj/item/organ)) // Inner organs
+ var/obj/item/organ/organ = I
+ if(organ.owner)
+ items_list.Remove(I)
+ continue
+ if(isobj(I))
+ var/obj/O = I
+ if(ismob(O.loc)) // Cyborg Parts, wearing clothes, but not contents
+ items_list.Remove(I)
+ continue
+ if(isliving(I))
+ var/mob/living/M = I
+ items_list.Remove(I)
+ if(isvox(M))
+ make_new_vox_raider(user, M)
+ continue
+ send_to_station(M)
+
+ return items_list
+
+/obj/machinery/vox_trader/proc/send_to_station(mob/living/M)
+ M.Sleeping(16 SECONDS)
+ M.setOxyLoss(0)
+ M.adjustBruteLoss(-25)
+ M.adjustFireLoss(-25)
+ M.adjustToxLoss(-50)
+ M.forceMove(pick(GLOB.latejoin))
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ C.Silence(6 SECONDS)
+ C.clear_restraints()
+ to_chat(C, span_warning("Вы ощущаете как ваши мозги были промыты. \
+ Вы всё еще не можете прийти в себя и отрывками вспоминаете что неизвестные похители вас. \
+ Неизвестно сколько они продержали вас у себя и что с вами делали... \
+ Но вы чувствуете себя будто обновленным."))
+
+/obj/machinery/vox_trader/proc/make_new_vox_raider(mob/user, mob/living/M)
+ if(!M.mind)
+ return FALSE
+
+ var/datum/antagonist/vox_raider/antag = locate() in M.mind.antag_datums
+ if(antag)
+ return FALSE
+ for(var/datum/antagonist/A as anything in user.mind.antag_datums)
+ var/datum/team/team = A.get_team()
+ if(team)
+ team.add_member(M.mind, TRUE)
+ break
+
+ return TRUE
+
+/obj/machinery/vox_trader/proc/update_shops()
+ for(var/obj/machinery/vox_shop/shop in GLOB.machines)
+ shop.generate_pack_items()
+ shop.generate_pack_lists()
+
+/obj/machinery/vox_trader/proc/try_update_blacklist()
+ if(length(blacklist_objects))
+ return
+ var/obj/machinery/vox_shop/shop = locate() in GLOB.machines
+ if(!shop)
+ return
+
+ var/list/all_objects = list()
+
+ for(var/category in shop.packs_items)
+ for(var/datum/vox_pack/pack in shop.packs_items[category])
+ if(category == VOX_PACK_KIT)
+ continue
+ var/list/items_list = pack.get_items_list()
+ if(!length(items_list))
+ break
+ all_objects += items_list
+
+ blacklist_objects = all_objects
diff --git a/modular_ss220/antagonists/code/vox_raider/objects/vox_trade_instrument.dm b/modular_ss220/antagonists/code/vox_raider/objects/vox_trade_instrument.dm
new file mode 100644
index 000000000000..65020a39e94f
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/objects/vox_trade_instrument.dm
@@ -0,0 +1,40 @@
+/obj/item/hand_valuer
+ name = "ручной оценщик"
+ desc = "Приспособление воксов для оценки стоимости объекта."
+ icon = 'modular_ss220/antagonists/icons/trader_machine.dmi'
+ icon_state = "valuer"
+ item_state = "camera_bug"
+ var/obj/machinery/vox_trader/connected_trader
+
+/obj/item/hand_valuer/examine(mob/user)
+ . = ..()
+ if(!isvox(user))
+ . += span_notice("Выглядит непонятно. Как воксы этим пользуются?")
+
+/obj/item/hand_valuer/afterattack__legacy__attackchain(atom/target, mob/user, proximity, params)
+ if(!proximity)
+ return
+
+ if(!isvox(user))
+ to_chat(user, span_warning("Кажется вы тыкаете не той стороной... Или [name] не работает? Да как воксы этим пользуются?!"))
+ return
+
+ if(!connected_trader)
+ to_chat(user, span_warning("Невозможно получить сведения с оценочной базы данных. Подключите устройство."))
+ return
+
+ if(!isobj(target))
+ to_chat(user, span_notice("Данный объект не поддается оценке."))
+ return
+
+ if(!connected_trader.check_usable(user))
+ return
+
+ var/value = connected_trader.get_value(user, list(target), TRUE)
+ to_chat(user, chat_box_notice(span_green("Ценность [target.name]: [value]")))
+
+/obj/item/hand_valuer/proc/connect(mob/living/user, obj/machinery/vox_trader/input_trader)
+ to_chat(user, span_green("Устройство [connected_trader ? "пере" : ""]инициализировано в системе."))
+ playsound(src, 'modular_ss220/antagonists/sound/guns/m79_unload.ogg', 50, 1)
+ icon_state = "[initial(icon_state)]-on"
+ connected_trader = input_trader
diff --git a/modular_ss220/antagonists/code/vox_raider/vox_raider_datum.dm b/modular_ss220/antagonists/code/vox_raider/vox_raider_datum.dm
new file mode 100644
index 000000000000..b906b61023b7
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/vox_raider_datum.dm
@@ -0,0 +1,152 @@
+/datum/antagonist/vox_raider
+ name = "Vox Raider"
+ roundend_category = "vox raiders"
+ job_rank = ROLE_VOX_RAIDER
+ special_role = SPECIAL_ROLE_VOX_RAIDER
+ antag_hud_name = "hudvoxraider"
+ antag_hud_type = ANTAG_HUD_VOX_RAIDER
+ wiki_page_name = "vox_raiders"
+ var/datum/team/vox_raiders/raiders_team = null
+
+/datum/antagonist/vox_raider/add_owner_to_gamemode()
+ SSticker.mode.vox_raiders |= owner
+ if(owner.current && !("Vox" in owner.current.faction))
+ owner.current.faction |= list("Vox")
+
+/datum/antagonist/vox_raider/remove_owner_from_gamemode()
+ SSticker.mode.vox_raiders -= owner
+
+/datum/antagonist/vox_raider/greet()
+ . = ..()
+ SEND_SOUND(owner.current, sound('modular_ss220/antagonists/sound/ambience/antag/vox_raiders_intro.ogg'))
+
+ . += {"Вы Вокс Рейдер, вы и ваша стая нашли станцию Нанотрейзен имеющую ценности.
+ Раздобудьте эти ценности любым доступным способом: торговлей, кражей, договорами.
+ Главное помните, не допустите своей гибели или гибели членов стаи. Ценные блестяшки не стоят мертвого собрата.
+ \nВы можете заказывать товары и снаряжение в Киконсоле Закиказов.
+ \nСдавайте ценности в Расчичетчикик.
+ \nКовчег выделил вам товары которые могут потенциально заинтересовать экипаж станции.
+ Разумеется не за бесплатно, выберите что вам действительно нужно и закажите это."}
+
+ var/raider_names = get_raider_names_text()
+ if(raider_names)
+ . += "Оберегай собратьев и помогай стае: [raider_names]. Только стая важна!"
+ antag_memory += "Ваша стая:: [raider_names] "
+
+ . += "Нужно больше ценностей!"
+
+/datum/antagonist/vox_raider/create_team(datum/team/vox_raiders/team)
+ if(!istype(team))
+ error("Wrong team type passed to [type].")
+ return
+
+ raiders_team = team
+ return raiders_team
+
+/datum/antagonist/vox_raider/get_team()
+ return raiders_team
+
+/datum/antagonist/vox_raider/proc/get_raider_names_text()
+ PRIVATE_PROC(TRUE)
+ var/datum/team/vox_raiders/team = get_team()
+ if(!istype(team))
+ return ""
+
+ return team.get_raider_names_text(owner)
+
+/datum/antagonist/vox_raider/proc/admin_add(admin, datum/mind/new_antag)
+ if(!new_antag)
+ return FALSE
+
+ if(new_antag.has_antag_datum(/datum/antagonist/vox_raider))
+ alert(admin, "Кандидат уже Вокс Рейдер")
+ return FALSE
+
+ if(!can_be_owned(new_antag))
+ alert(admin, "Кандидат не может быть Вокс Рейдером")
+ return FALSE
+
+ switch(alert(admin, "Создать новую команду или добавить в существующую?", "Воксы Рейдеры", "Создать", "Добавить", "Закрыть"))
+ if("Создать")
+ return create_new_vox_raiders_team(admin, new_antag)
+ if("Добавить")
+ return add_to_existing_vox_raiders_team(admin, new_antag)
+
+ return FALSE
+
+/datum/antagonist/vox_raider/proc/create_new_vox_raiders_team(admin, datum/mind/first_raider)
+ PRIVATE_PROC(TRUE)
+ var/list/choices = list()
+ for(var/mob/living/alive_living_mob in GLOB.alive_mob_list)
+ var/datum/mind/mind_to_check = alive_living_mob.mind
+ if(!mind_to_check || mind_to_check == first_raider || !can_be_owned(mind_to_check))
+ continue
+
+ choices["[mind_to_check.name]([alive_living_mob.ckey])"] = mind_to_check
+
+ sortTim(choices, GLOBAL_PROC_REF(cmp_text_asc))
+
+ var/list/candidates_list = list(first_raider)
+ while(TRUE)
+ if(!length(choices))
+ break
+ var/choice = tgui_input_list(admin, "Выберите кандидата, если вы завершили выбор, то закройте окно.", "Добавить нового вокс рейдера", choices)
+ if(!choice)
+ break
+ var/datum/mind/mind = choices[choice]
+ if(!mind)
+ stack_trace("Chosen second vox raider `[choice]` was `null` for some reason")
+ choices.Remove(choice)
+ candidates_list.Add(mind)
+
+ var/datum/team/vox_raiders/team = new(candidates_list, FALSE)
+ for(var/datum/mind/mind in candidates_list)
+ if(isnull(mind.add_antag_datum(src, team)))
+ error("Antag datum couldn't be granted to new raider [mind.name] in `/datum/antagonist/vox_raider/proc/create_new_vox_raiders_team`")
+ alert(admin, "Кандидат [mind.name] не был выбран для `Vox Raider` по каким-то причинам. Попробуйте еще раз.")
+
+ offer_to_equip(admin, candidates_list)
+
+ log_admin("[key_name(admin)] made vox raiders.")
+ return TRUE
+
+/datum/antagonist/vox_raider/proc/add_to_existing_vox_raiders_team(admin, datum/mind/raider_to_add)
+ PRIVATE_PROC(TRUE)
+ var/list/choices = list()
+ for(var/datum/team/vox_raiders/team in GLOB.antagonist_teams)
+ var/list/member_ckeys = team.get_member_ckeys()
+ choices["[team.name][length(member_ckeys) ? "([member_ckeys.Join(", ")])" : ""]"] = team
+
+ if(!length(choices))
+ alert(admin, "Команда Воксов-Рейдеров не найдена. Попробуйте создать новую.")
+ return FALSE
+
+ sortTim(choices, GLOBAL_PROC_REF(cmp_text_asc))
+ var/choice = tgui_input_list(admin, "Выбор команды Воксов-Рейдеров.", "Команда Воксов-Рейдеров", choices)
+ if(!choice)
+ return FALSE
+
+ offer_to_equip(admin, list(raider_to_add))
+
+ var/datum/team/vox_raiders/team = choices[choice]
+ if(!team)
+ stack_trace("Chosen vox raiders team `[choice]` was `null` for some reason.")
+
+ return !isnull(raider_to_add.add_antag_datum(src, team))
+
+/datum/antagonist/vox_raider/proc/offer_to_equip(admin, list/candidates_list, visualsOnly)
+ if(!length(candidates_list))
+ return
+ var/choice = (alert(admin, "Снарядить в стандартную экипировку?", "Снаряжение", "Да", "Нет"))
+ if(!choice || choice == "Нет")
+ return
+ for(var/datum/mind/mind in candidates_list)
+ if(!isvox(mind.current))
+ make_body(mind.current, mind, TRUE, "Vox")
+ var/mob/living/carbon/human/H = mind.current
+ if(mind.current)
+ H.equipOutfit(/datum/outfit/vox, visualsOnly)
+
+/datum/antagonist/vox_raider/make_body(spawn_loc, datum/mind/mind, try_use_preference = FALSE, species_name = null, list/possible_species)
+ . = ..()
+ mind.store_memory(" Я Вокс-Рейдер, основа моя: беречь стаю, тащить ценности. .")
diff --git a/modular_ss220/antagonists/code/vox_raider/vox_raider_mode.dm b/modular_ss220/antagonists/code/vox_raider/vox_raider_mode.dm
new file mode 100644
index 000000000000..328da0db7ccc
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/vox_raider_mode.dm
@@ -0,0 +1,20 @@
+/datum/game_mode
+ var/list/datum/mind/vox_raiders = list()
+
+/datum/game_mode/antag_mix/vox_raider
+ name = "Vox Raiders"
+ config_tag = "vox_raiders"
+ required_players = 45
+
+/datum/game_mode/antag_mix/vox_raider/New()
+ . = ..()
+ list_scenarios = list(/datum/antag_scenario/team/vox_raiders)
+
+ var/datum/antag_scenario/antag_datum = /datum/antag_scenario/team/vox_raiders
+ required_players = initial(antag_datum.required_players)
+
+/datum/game_mode/antag_mix/vox_raider/announce()
+ to_chat(world, "The current game mode is - Vox Raiders!")
+ to_chat(world, "Поблизости сектора [world.name] обнаружен корабль воксов!")
+ to_chat(world, "Воксы - всей стаей падки на блестяшки и ценности, с ними можно выгодно поторговаться. Но больше ценностей они ценят друг друга.")
+ to_chat(world, "Экипаж - следите за воксами внимательно, в том числе и за теми кто на станции, не допустите потерю дорогостоящего оборудования!")
diff --git a/modular_ss220/antagonists/code/vox_raider/vox_raider_team.dm b/modular_ss220/antagonists/code/vox_raider/vox_raider_team.dm
new file mode 100644
index 000000000000..488bf1e14624
--- /dev/null
+++ b/modular_ss220/antagonists/code/vox_raider/vox_raider_team.dm
@@ -0,0 +1,79 @@
+/datum/team/vox_raiders
+ name = "Vox Raiders"
+ antag_datum_type = /datum/antagonist/vox_raider
+
+/datum/team/vox_raiders/New(list/starting_members, add_antag_datum)
+ . = ..()
+ forge_objectives()
+
+/datum/team/vox_raiders/proc/forge_objectives()
+ PRIVATE_PROC(TRUE)
+ // Основная цель
+ add_team_objective(new /datum/objective/raider_steal())
+ //Коллекционная цель
+ var/list/possible_collect_objective_types = list(
+ /datum/objective/raider_entirety_steal,
+ /datum/objective/raider_collection_access,
+ /datum/objective/raider_collection_tech
+ )
+ var/picked_collect_objective_type = pick(possible_collect_objective_types)
+ add_team_objective(new picked_collect_objective_type())
+ // Конечная цель
+ add_team_objective(new /datum/objective/survive(
+ {"Не допустите гибели вас и остальных Воксов из команды. Избегайте смерти влекущие за собой расходы стае."}))
+
+/datum/team/vox_raiders/handle_adding_member(datum/mind/new_member)
+ . = ..()
+ update_reider_name()
+
+/datum/team/vox_raiders/handle_removing_member(datum/mind/member, force = FALSE)
+ . = ..()
+ update_reider_name()
+
+/datum/team/vox_raiders/proc/update_reider_name()
+ PRIVATE_PROC(TRUE)
+ var/new_name = get_raider_names_text()
+ if(!new_name)
+ name = initial(name)
+ return
+
+ name = "[initial(name)] of [new_name]"
+
+/datum/team/vox_raiders/proc/get_raider_names_text(datum/mind/raider_to_exclude)
+ var/list/raider_names = list()
+ for(var/datum/mind/raider as anything in members)
+ if(raider == raider_to_exclude)
+ continue
+
+ raider_names += raider.name
+
+ return raider_names.Join(", ")
+
+/datum/team/vox_raiders/on_round_end()
+ . = ..()
+ var/list/to_send = list()
+ for(var/datum/team/vox_raiders/team in GLOB.antagonist_teams)
+ if(!objective_holder)
+ continue
+ var/teamwin = 1
+ to_send += " Стая [name]"
+ for(var/datum/objective/objective in objective_holder.get_objectives())
+ if(!objective.check_completion())
+ teamwin = 0
+ if(teamwin)
+ to_send += " Стая успешно завершила свои цели!"
+ else
+ to_send += " Стая провалилась!"
+ var/num_survive = length(members)
+ for(var/datum/mind/mind in members)
+ if(!mind.current || mind.current.stat==DEAD)
+ num_survive--
+ if(num_survive == length(members))
+ to_send += " Вся стая выжила!"
+ else if(num_survive <= 0)
+ to_send += " Вся стая погибла!"
+ else
+ to_send += " У стаи есть потери!"
+ if(!length(to_send))
+ return
+ to_chat(world, to_send.Join(" "))
diff --git a/modular_ss220/antagonists/icons/clothing/inhands/clothing_lefthand.dmi b/modular_ss220/antagonists/icons/clothing/inhands/clothing_lefthand.dmi
new file mode 100644
index 000000000000..fecc6c113693
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/inhands/clothing_lefthand.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/inhands/clothing_righthand.dmi b/modular_ss220/antagonists/icons/clothing/inhands/clothing_righthand.dmi
new file mode 100644
index 000000000000..2a4608a2d897
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/inhands/clothing_righthand.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/mob/back.dmi b/modular_ss220/antagonists/icons/clothing/mob/back.dmi
new file mode 100644
index 000000000000..9fdf14d5e256
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/mob/back.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/mob/vox/back.dmi b/modular_ss220/antagonists/icons/clothing/mob/vox/back.dmi
new file mode 100644
index 000000000000..e27f3e388542
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/mob/vox/back.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/mob/vox/feet.dmi b/modular_ss220/antagonists/icons/clothing/mob/vox/feet.dmi
new file mode 100644
index 000000000000..b7549f7b9195
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/mob/vox/feet.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/mob/vox/gloves.dmi b/modular_ss220/antagonists/icons/clothing/mob/vox/gloves.dmi
new file mode 100644
index 000000000000..fee1a6f4b311
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/mob/vox/gloves.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/mob/vox/head.dmi b/modular_ss220/antagonists/icons/clothing/mob/vox/head.dmi
new file mode 100644
index 000000000000..d1cc375be132
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/mob/vox/head.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/mob/vox/suit.dmi b/modular_ss220/antagonists/icons/clothing/mob/vox/suit.dmi
new file mode 100644
index 000000000000..ff192faa4f2b
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/mob/vox/suit.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/mob/vox/uniform.dmi b/modular_ss220/antagonists/icons/clothing/mob/vox/uniform.dmi
new file mode 100644
index 000000000000..f93b5db3ff06
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/mob/vox/uniform.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/obj_gloves.dmi b/modular_ss220/antagonists/icons/clothing/obj_gloves.dmi
new file mode 100644
index 000000000000..f44a43eefb9a
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/obj_gloves.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/obj_head.dmi b/modular_ss220/antagonists/icons/clothing/obj_head.dmi
new file mode 100644
index 000000000000..26a102acb37f
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/obj_head.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/obj_shoes.dmi b/modular_ss220/antagonists/icons/clothing/obj_shoes.dmi
new file mode 100644
index 000000000000..dedf8f9c9db5
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/obj_shoes.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/obj_storage.dmi b/modular_ss220/antagonists/icons/clothing/obj_storage.dmi
new file mode 100644
index 000000000000..6d20cdf64e64
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/obj_storage.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/obj_suit.dmi b/modular_ss220/antagonists/icons/clothing/obj_suit.dmi
new file mode 100644
index 000000000000..ed50984b34e4
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/obj_suit.dmi differ
diff --git a/modular_ss220/antagonists/icons/clothing/obj_under.dmi b/modular_ss220/antagonists/icons/clothing/obj_under.dmi
new file mode 100644
index 000000000000..691efeb15702
Binary files /dev/null and b/modular_ss220/antagonists/icons/clothing/obj_under.dmi differ
diff --git a/modular_ss220/antagonists/icons/flag.dmi b/modular_ss220/antagonists/icons/flag.dmi
new file mode 100644
index 000000000000..0c777e5df60a
Binary files /dev/null and b/modular_ss220/antagonists/icons/flag.dmi differ
diff --git a/modular_ss220/antagonists/icons/guns/ammo.dmi b/modular_ss220/antagonists/icons/guns/ammo.dmi
new file mode 100644
index 000000000000..777d90745500
Binary files /dev/null and b/modular_ss220/antagonists/icons/guns/ammo.dmi differ
diff --git a/modular_ss220/antagonists/icons/guns/inhands/guns_lefthand.dmi b/modular_ss220/antagonists/icons/guns/inhands/guns_lefthand.dmi
new file mode 100644
index 000000000000..94ba073d3547
Binary files /dev/null and b/modular_ss220/antagonists/icons/guns/inhands/guns_lefthand.dmi differ
diff --git a/modular_ss220/antagonists/icons/guns/inhands/guns_righthand.dmi b/modular_ss220/antagonists/icons/guns/inhands/guns_righthand.dmi
new file mode 100644
index 000000000000..95a206aa9e61
Binary files /dev/null and b/modular_ss220/antagonists/icons/guns/inhands/guns_righthand.dmi differ
diff --git a/modular_ss220/antagonists/icons/guns/vox_guns.dmi b/modular_ss220/antagonists/icons/guns/vox_guns.dmi
new file mode 100644
index 000000000000..78cd6d492c6e
Binary files /dev/null and b/modular_ss220/antagonists/icons/guns/vox_guns.dmi differ
diff --git a/modular_ss220/antagonists/icons/hud.dmi b/modular_ss220/antagonists/icons/hud.dmi
new file mode 100644
index 000000000000..c10534ebed76
Binary files /dev/null and b/modular_ss220/antagonists/icons/hud.dmi differ
diff --git a/modular_ss220/antagonists/icons/landmark.dmi b/modular_ss220/antagonists/icons/landmark.dmi
new file mode 100644
index 000000000000..40512d2511a2
Binary files /dev/null and b/modular_ss220/antagonists/icons/landmark.dmi differ
diff --git a/modular_ss220/antagonists/icons/objects/critter.dmi b/modular_ss220/antagonists/icons/objects/critter.dmi
new file mode 100644
index 000000000000..6e09f54898a8
Binary files /dev/null and b/modular_ss220/antagonists/icons/objects/critter.dmi differ
diff --git a/modular_ss220/antagonists/icons/objects/dart.dmi b/modular_ss220/antagonists/icons/objects/dart.dmi
new file mode 100644
index 000000000000..5708a3015663
Binary files /dev/null and b/modular_ss220/antagonists/icons/objects/dart.dmi differ
diff --git a/modular_ss220/antagonists/icons/trader_machine.dmi b/modular_ss220/antagonists/icons/trader_machine.dmi
new file mode 100644
index 000000000000..46abdac3568a
Binary files /dev/null and b/modular_ss220/antagonists/icons/trader_machine.dmi differ
diff --git a/modular_ss220/antagonists/sound/ambience/antag/blood_brothers_intro.ogg b/modular_ss220/antagonists/sound/ambience/antag/blood_brothers_intro.ogg
new file mode 100644
index 000000000000..51e1f421563c
Binary files /dev/null and b/modular_ss220/antagonists/sound/ambience/antag/blood_brothers_intro.ogg differ
diff --git a/modular_ss220/antagonists/sound/ambience/antag/vox_raiders_intro.ogg b/modular_ss220/antagonists/sound/ambience/antag/vox_raiders_intro.ogg
new file mode 100644
index 000000000000..40cc2323cc87
Binary files /dev/null and b/modular_ss220/antagonists/sound/ambience/antag/vox_raiders_intro.ogg differ
diff --git a/modular_ss220/antagonists/sound/guns/gun_es4.ogg b/modular_ss220/antagonists/sound/guns/gun_es4.ogg
new file mode 100644
index 000000000000..54210c02fa60
Binary files /dev/null and b/modular_ss220/antagonists/sound/guns/gun_es4.ogg differ
diff --git a/modular_ss220/antagonists/sound/guns/m79_break_open.ogg b/modular_ss220/antagonists/sound/guns/m79_break_open.ogg
new file mode 100644
index 000000000000..bf6bd477e556
Binary files /dev/null and b/modular_ss220/antagonists/sound/guns/m79_break_open.ogg differ
diff --git a/modular_ss220/antagonists/sound/guns/m79_reload.ogg b/modular_ss220/antagonists/sound/guns/m79_reload.ogg
new file mode 100644
index 000000000000..59b165cbbb80
Binary files /dev/null and b/modular_ss220/antagonists/sound/guns/m79_reload.ogg differ
diff --git a/modular_ss220/antagonists/sound/guns/m79_shoot.ogg b/modular_ss220/antagonists/sound/guns/m79_shoot.ogg
new file mode 100644
index 000000000000..bcb22fb04a9c
Binary files /dev/null and b/modular_ss220/antagonists/sound/guns/m79_shoot.ogg differ
diff --git a/modular_ss220/antagonists/sound/guns/m79_unload.ogg b/modular_ss220/antagonists/sound/guns/m79_unload.ogg
new file mode 100644
index 000000000000..1bff50bbfb2a
Binary files /dev/null and b/modular_ss220/antagonists/sound/guns/m79_unload.ogg differ
diff --git a/modular_ss220/autolathe_tgui/_autolathe_tgui.dm b/modular_ss220/autolathe_tgui/_autolathe_tgui.dm
new file mode 100644
index 000000000000..25ac5b6ef362
--- /dev/null
+++ b/modular_ss220/autolathe_tgui/_autolathe_tgui.dm
@@ -0,0 +1,4 @@
+/datum/modpack/autolathe_tgui
+ name = "Autolathe TGUI"
+ desc = "Новый интерфейс для автолата"
+ author = "Aylong"
diff --git a/modular_ss220/autolathe_tgui/_autolathe_tgui.dme b/modular_ss220/autolathe_tgui/_autolathe_tgui.dme
new file mode 100644
index 000000000000..9198c532fe03
--- /dev/null
+++ b/modular_ss220/autolathe_tgui/_autolathe_tgui.dme
@@ -0,0 +1,3 @@
+#include "_autolathe_tgui.dm"
+
+#include "code/autolathe_ui.dm"
diff --git a/modular_ss220/autolathe_tgui/code/autolathe_ui.dm b/modular_ss220/autolathe_tgui/code/autolathe_ui.dm
new file mode 100644
index 000000000000..b8ab9ceaba87
--- /dev/null
+++ b/modular_ss220/autolathe_tgui/code/autolathe_ui.dm
@@ -0,0 +1,6 @@
+/obj/machinery/autolathe/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Autolathe220", name)
+ ui.set_autoupdate(FALSE)
+ ui.open()
diff --git a/modular_ss220/awaymission_gun/_awaymission_gun.dm b/modular_ss220/awaymission_gun/_awaymission_gun.dm
new file mode 100644
index 000000000000..b9350a83a703
--- /dev/null
+++ b/modular_ss220/awaymission_gun/_awaymission_gun.dm
@@ -0,0 +1,4 @@
+/datum/modpack/awaymission_gun
+ name = "Гейтган"
+ desc = "Добавляет гейтган."
+ author = "PhantomRU"
diff --git a/modular_ss220/awaymission_gun/_awaymission_gun.dme b/modular_ss220/awaymission_gun/_awaymission_gun.dme
new file mode 100644
index 000000000000..25949a2657d2
--- /dev/null
+++ b/modular_ss220/awaymission_gun/_awaymission_gun.dme
@@ -0,0 +1,4 @@
+#include "_awaymission_gun.dm"
+
+#include "code/items/awaymission_gun.dm"
+#include "code/research_designs/weapon_designs.dm"
diff --git a/modular_ss220/awaymission_gun/code/items/awaymission_gun.dm b/modular_ss220/awaymission_gun/code/items/awaymission_gun.dm
new file mode 100644
index 000000000000..61659b4992d7
--- /dev/null
+++ b/modular_ss220/awaymission_gun/code/items/awaymission_gun.dm
@@ -0,0 +1,82 @@
+/obj/item/gun/energy/laser/awaymission_aeg
+ name = "Wireless Energy Gun"
+ desc = "An energy gun that recharges wirelessly during away missions. Does not work outside the gate."
+ icon = 'modular_ss220/awaymission_gun/icons/items/energy.dmi'
+ lefthand_file = 'modular_ss220/awaymission_gun/icons/inhands/lefthand.dmi'
+ righthand_file = 'modular_ss220/awaymission_gun/icons/inhands/righthand.dmi'
+ icon_state = "laser_gate"
+ item_state = "nucgun"
+ force = 10
+ origin_tech = "combat=5;magnets=3;powerstorage=4"
+ selfcharge = TRUE // Selfcharge is enabled and disabled, and used as the away mission tracker
+ can_charge = 0
+
+/obj/item/gun/energy/laser/awaymission_aeg/Initialize(mapload)
+ . = ..()
+ // Force update it incase it spawns outside an away mission and shouldnt be charged
+ onTransitZ(new_z = loc.z)
+
+/obj/item/gun/energy/laser/awaymission_aeg/onTransitZ(old_z, new_z)
+ . = ..()
+ if(is_away_level(new_z))
+ if(ismob(loc))
+ to_chat(loc, span_notice("Ваш [src] активируется, начиная аккумулировать энергию из материи сущего."))
+ selfcharge = TRUE
+ return
+ if(ismob(loc) && selfcharge)
+ to_chat(loc, span_danger("Ваш [src] деактивируется, так как он подавляется системами станции."))
+ cell.charge = 0
+ selfcharge = FALSE
+ update_icon()
+
+/obj/item/gun/energy/laser/awaymission_aeg/proc/update_mob()
+ if(ismob(loc))
+ var/mob/M = loc
+ M.unEquip(src)
+
+// GUNS
+/obj/item/gun/energy/laser/awaymission_aeg/rnd
+ name = "Exploreverse Mk.I"
+ desc = "Прототип оружия с миниатюрным реактором для исследований в крайне отдаленных секторах. \
+ \n Данная модель использует экспериментальную систему обратного восполнения, работающую на принципе огромной аккумуляции энергии, но крайне уязвимую к радиопомехам, которыми кишит сектор станции, попростую не работая там."
+ origin_tech = "combat=2;powerstorage=3"
+
+/obj/item/gun/energy/laser/awaymission_aeg/rnd/mk2
+ name = "Exploreverse Mk.II"
+ desc = "Второй прототип оружия с миниатюрным реактором и забавным рычагом для исследований в крайне отдаленных секторах. \
+ \nДанная модель оснащена системой ручного восполнения энергии \"Za.E.-8 A.L'sya\", \
+ позволяющей в короткие сроки восполнить необходимую электроэнергию с помощью ручного труда и конвертации личной энергии подключенного к системе зарядки. \
+ \nТеперь еще более нелепый дизайн с торчащими проводами!"
+ icon_state = "laser_gate_mk2"
+ origin_tech = "combat=3;magnets=2;powerstorage=2;programming=3;"
+
+/obj/item/gun/energy/laser/awaymission_aeg/rnd/mk2/attack_self__legacy__attackchain(mob/living/user)
+ var/msg_for_all = span_warning("[user.name] усердно давит на рычаг зарядки [src], но он не поддается!")
+ var/msg_for_user = span_notice("Вы пытаетесь надавить на рычаг зарядки [src], но он заблокирован.")
+ var/msg_recharge_all = span_notice("[user.name] усердно давит на рычаг зарядки [src]...")
+ var/msg_recharge_user = span_notice("Вы со всей силы давите на рычаг зарядки [src], пытаясь зарядить её...")
+
+ if(!is_away_level(loc.z))
+ user.visible_message(msg_for_all, msg_for_user)
+ return FALSE
+
+ if(cell.charge >= cell.maxcharge)
+ user.visible_message(msg_for_all, msg_for_user)
+ return FALSE
+
+ if(user.nutrition <= NUTRITION_LEVEL_STARVING)
+ user.visible_message(
+ span_warning("[user.name] слабо давит на [src], но бесполезно: слишком мало сил!"),
+ span_notice("Вы пытаетесь надавить на рычаг зарядки [src], но не можете из-за голода и усталости!"))
+ return FALSE
+
+ user.visible_message(msg_recharge_all, msg_recharge_user)
+ playsound(loc, 'sound/effects/sparks3.ogg', 10, 1)
+ do_sparks(1, 1, src)
+
+ if(!do_after_once(user, 3 SECONDS, target = src))
+ return
+ cell.give(166)
+ on_recharge()
+ user.adjust_nutrition(-25)
+ . = ..()
diff --git a/modular_ss220/awaymission_gun/code/research_designs/weapon_designs.dm b/modular_ss220/awaymission_gun/code/research_designs/weapon_designs.dm
new file mode 100644
index 000000000000..573902ccc1e8
--- /dev/null
+++ b/modular_ss220/awaymission_gun/code/research_designs/weapon_designs.dm
@@ -0,0 +1,21 @@
+/datum/design/gate_gun_mk1
+ name = "Gate Energy Gun MK1"
+ desc = "An energy gun with an experimental miniaturized reactor. Only works in the gate" //не отображаемое описание, т.к. печатается без кейса
+ id = "gate_energy_gun"
+ req_tech = list("combat" = 3, "magnets" = 3, "powerstorage" = 4)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 6000, MAT_GLASS = 1500, MAT_URANIUM = 1500, MAT_TITANIUM = 500)
+ build_path = /obj/item/gun/energy/laser/awaymission_aeg/rnd
+ locked = 0
+ category = list("Weapons")
+
+/datum/design/gate_gun_mk2
+ name = "Gate Energy Gun MK2"
+ desc = "An energy gun with an experimental miniaturized reactor. Only works in the gate" //не отображаемое описание, т.к. печатается без кейса
+ id = "gate_energy_gun_mk2"
+ req_tech = list("combat" = 5, "magnets" = 3, "powerstorage" = 5, "programming" = 3, "engineering" = 5)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 8000, MAT_GLASS = 2000, MAT_URANIUM = 2000, MAT_TITANIUM = 500, MAT_SILVER = 1000)
+ build_path = /obj/item/gun/energy/laser/awaymission_aeg/rnd/mk2
+ locked = 0
+ category = list("Weapons")
diff --git a/modular_ss220/awaymission_gun/icons/inhands/lefthand.dmi b/modular_ss220/awaymission_gun/icons/inhands/lefthand.dmi
new file mode 100644
index 000000000000..101610bd9fbd
Binary files /dev/null and b/modular_ss220/awaymission_gun/icons/inhands/lefthand.dmi differ
diff --git a/modular_ss220/awaymission_gun/icons/inhands/righthand.dmi b/modular_ss220/awaymission_gun/icons/inhands/righthand.dmi
new file mode 100644
index 000000000000..5174b1709ba8
Binary files /dev/null and b/modular_ss220/awaymission_gun/icons/inhands/righthand.dmi differ
diff --git a/modular_ss220/awaymission_gun/icons/items/energy.dmi b/modular_ss220/awaymission_gun/icons/items/energy.dmi
new file mode 100644
index 000000000000..0365ecc75907
Binary files /dev/null and b/modular_ss220/awaymission_gun/icons/items/energy.dmi differ
diff --git a/modular_ss220/balance/_balance.dm b/modular_ss220/balance/_balance.dm
new file mode 100644
index 000000000000..0c56d172ca6a
--- /dev/null
+++ b/modular_ss220/balance/_balance.dm
@@ -0,0 +1,4 @@
+/datum/modpack/balance
+ name = "Баланс"
+ desc = "Твики баланса."
+ author = "dj-34, larentoun, Yata9arasu"
diff --git a/modular_ss220/balance/_balance.dme b/modular_ss220/balance/_balance.dme
new file mode 100644
index 000000000000..8c1e00182243
--- /dev/null
+++ b/modular_ss220/balance/_balance.dme
@@ -0,0 +1,12 @@
+#include "_balance.dm"
+
+#include "code/access/access.dm"
+#include "code/events/blob.dm"
+#include "code/items/projectiles.dm"
+#include "code/items/weapons.dm"
+#include "code/items/storage/surgical_tray.dm"
+#include "code/items/storage/closets.dm"
+#include "code/jobs/warden.dm"
+#include "code/mobs/aliens/larva.dm"
+#include "code/species/machine.dm"
+#include "code/species/skrell.dm"
diff --git a/modular_ss220/balance/code/access/access.dm b/modular_ss220/balance/code/access/access.dm
new file mode 100644
index 000000000000..0f413c508d7f
--- /dev/null
+++ b/modular_ss220/balance/code/access/access.dm
@@ -0,0 +1,43 @@
+/datum/job/cargo_tech/New()
+ . = ..()
+ access |= list(ACCESS_MINING)
+
+/datum/job/mining/New()
+ . = ..()
+ access |= list(ACCESS_CARGO, ACCESS_CARGO_BAY, ACCESS_SUPPLY_SHUTTLE, ACCESS_MAILSORTING)
+
+/datum/job/bartender/New()
+ . = ..()
+ access |= list(ACCESS_KITCHEN, ACCESS_HYDROPONICS)
+
+/datum/job/chef/New()
+ . = ..()
+ access |= list(ACCESS_BAR, ACCESS_HYDROPONICS)
+
+/datum/job/hydro/New()
+ . = ..()
+ access |= list(ACCESS_KITCHEN, ACCESS_BAR)
+
+/datum/job/doctor/New()
+ . = ..()
+ access |= list(ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_VIROLOGY)
+
+/datum/job/paramedic/New()
+ . = ..()
+ access |= list(ACCESS_CARGO_BAY, ACCESS_SURGERY)
+
+/datum/job/atmos/New()
+ . = ..()
+ access |= list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP)
+
+/datum/job/engineer/New()
+ . = ..()
+ access |= list(ACCESS_ATMOSPHERICS)
+
+/datum/job/blueshield/New()
+ . = ..()
+ access |= list(ACCESS_CARGO_BAY)
+
+/datum/job/roboticist/New()
+ . = ..()
+ access |= list(ACCESS_TOX)
diff --git a/modular_ss220/balance/code/events/blob.dm b/modular_ss220/balance/code/events/blob.dm
new file mode 100644
index 000000000000..c6c5afd6462d
--- /dev/null
+++ b/modular_ss220/balance/code/events/blob.dm
@@ -0,0 +1,4 @@
+// Increases announce time
+/datum/event/blob
+ announceWhen = 420
+ endWhen = 480
diff --git a/modular_ss220/balance/code/items/projectiles.dm b/modular_ss220/balance/code/items/projectiles.dm
new file mode 100644
index 000000000000..90f063b5e34f
--- /dev/null
+++ b/modular_ss220/balance/code/items/projectiles.dm
@@ -0,0 +1,20 @@
+/obj/item/projectile
+ ///If TRUE, hit mobs even if they're on the floor and not our target
+ var/hit_prone_targets = FALSE
+
+/atom/handle_ricochet(obj/item/projectile/ricocheting_projectile)
+ . = ..()
+ if(.)
+ // here is confirmed ricochet - force projectile to hit targets
+ ricocheting_projectile.hit_prone_targets = TRUE
+
+/obj/item/ammo_casing/ready_proj(atom/target, mob/living/user, quiet, zone_override, atom/firer_source_atom)
+ . = ..()
+ if(!BB)
+ return
+ BB.hit_prone_targets = user.a_intent != INTENT_HELP
+
+/mob/living/carbon/human/projectile_hit_check(obj/item/projectile/P)
+ if(stat == CONSCIOUS)
+ return !P.hit_prone_targets && !density
+ return !density
diff --git a/modular_ss220/balance/code/items/storage/closets.dm b/modular_ss220/balance/code/items/storage/closets.dm
new file mode 100644
index 000000000000..ce635fffc864
--- /dev/null
+++ b/modular_ss220/balance/code/items/storage/closets.dm
@@ -0,0 +1,11 @@
+// Paramedic Closet
+/obj/structure/closet/secure_closet/paramedic/populate_contents()
+ . = ..()
+ new /obj/item/grenade/jaunter_grenade(src)
+ new /obj/item/grenade/jaunter_grenade(src)
+
+// Blueshield Closet
+/obj/structure/closet/secure_closet/blueshield/populate_contents()
+ . = ..()
+ new /obj/item/melee/baton/electrostaff/loaded(src)
+ new /obj/item/screwdriver(src)
diff --git a/modular_ss220/balance/code/items/storage/surgical_tray.dm b/modular_ss220/balance/code/items/storage/surgical_tray.dm
new file mode 100644
index 000000000000..7de5fbfb2b14
--- /dev/null
+++ b/modular_ss220/balance/code/items/storage/surgical_tray.dm
@@ -0,0 +1,14 @@
+/obj/item/storage/surgical_tray/Initialize(mapload)
+ . = ..()
+
+ QDEL_LIST_CONTENTS(contents)
+
+ new /obj/item/scalpel(src)
+ new /obj/item/cautery(src)
+ new /obj/item/hemostat(src)
+ new /obj/item/retractor(src)
+ new /obj/item/fix_o_vein(src)
+ new /obj/item/surgicaldrill(src)
+ new /obj/item/circular_saw(src)
+ new /obj/item/bonegel(src)
+ new /obj/item/bonesetter(src)
diff --git a/modular_ss220/balance/code/items/weapons.dm b/modular_ss220/balance/code/items/weapons.dm
new file mode 100644
index 000000000000..50e1dd9074a9
--- /dev/null
+++ b/modular_ss220/balance/code/items/weapons.dm
@@ -0,0 +1,37 @@
+/obj/item/gun/projectile/revolver/doublebarrel/sawoff(mob/user)
+ . = ..()
+ if(sawn_state == SAWN_OFF)
+ can_holster = TRUE
+ w_class = WEAPON_MEDIUM
+
+// MARK: Energy
+/obj/item/gun/energy/gun
+ w_class = WEIGHT_CLASS_BULKY
+
+/obj/item/gun/energy/immolator
+ w_class = WEIGHT_CLASS_BULKY
+
+/obj/item/gun/energy/gun/hos
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/gun/energy/gun/blueshield
+ w_class = WEIGHT_CLASS_NORMAL
+
+// MARK: Laser
+/obj/item/gun/energy/laser
+ w_class = WEIGHT_CLASS_BULKY
+
+/obj/item/gun/energy/xray
+ w_class = WEIGHT_CLASS_BULKY
+
+/obj/item/gun/energy/laser/captain
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/gun/energy/laser/tag
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/gun/energy/laser/practice
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/gun/energy/laser/awaymission_aeg/rnd
+ w_class = WEIGHT_CLASS_NORMAL
diff --git a/modular_ss220/balance/code/jobs/warden.dm b/modular_ss220/balance/code/jobs/warden.dm
new file mode 100644
index 000000000000..6e1c1df710ee
--- /dev/null
+++ b/modular_ss220/balance/code/jobs/warden.dm
@@ -0,0 +1,2 @@
+/datum/job/warden
+ department_account_access = TRUE
diff --git a/modular_ss220/balance/code/mobs/aliens/larva.dm b/modular_ss220/balance/code/mobs/aliens/larva.dm
new file mode 100644
index 000000000000..21803a808995
--- /dev/null
+++ b/modular_ss220/balance/code/mobs/aliens/larva.dm
@@ -0,0 +1,13 @@
+/obj/machinery/door/airlock/attack_larva(mob/user)
+ for(var/atom/movable/movable in get_turf(src))
+ if(movable != src && movable.density && !movable.CanPass(user, user.loc))
+ to_chat(user, span_warning("[movable] мешает вам протиснуться под [src]!"))
+ return
+ if(locked || welded) //Can't pass through airlocks that have been bolted down or welded
+ to_chat(user, span_warning("[src] герметично закрыт. Вы не можете протиснуться!"))
+ return
+ user.visible_message(
+ span_warning("[user] протискивается через [src]!"),
+ span_warning("Вы протискиваетесь через [src]."),
+ null)
+ user.forceMove(get_turf(src))
diff --git a/modular_ss220/balance/code/species/machine.dm b/modular_ss220/balance/code/species/machine.dm
new file mode 100644
index 000000000000..cd73b7616515
--- /dev/null
+++ b/modular_ss220/balance/code/species/machine.dm
@@ -0,0 +1,18 @@
+/datum/species/machine
+ speciesbox = /obj/item/storage/box/survival_ipc
+
+// Survival box for IPC
+/obj/item/storage/box/survival_ipc
+ icon = 'modular_ss220/aesthetics/boxes/icons/boxes.dmi'
+ icon_state = "machine_box"
+
+/obj/item/storage/box/survival_ipc/populate_contents()
+ new /obj/item/weldingtool(src)
+ new /obj/item/stack/cable_coil/five(src)
+ new /obj/item/flashlight/flare/glowstick/emergency(src)
+
+/obj/machinery/recharger/attackby__legacy__attackchain(obj/item/G, mob/user, params)
+ if(istype(G, /obj/item/melee/baton/electrostaff))
+ to_chat(user, span_notice("[G] не имеет внешних разъемов для подзарядки."))
+ return
+ . = ..()
diff --git a/modular_ss220/balance/code/species/skrell.dm b/modular_ss220/balance/code/species/skrell.dm
new file mode 100644
index 000000000000..7e44cfdf20af
--- /dev/null
+++ b/modular_ss220/balance/code/species/skrell.dm
@@ -0,0 +1,32 @@
+// Dealing toxins when drinking alcohol
+/obj/item/organ/internal/kidneys/skrell/on_life()
+ . = ..()
+ var/datum/reagent/consumable/ethanol/ethanol_reagent = locate(/datum/reagent/consumable/ethanol) in owner.reagents.reagent_list
+ if(!ethanol_reagent)
+ return
+ if(is_broken())
+ owner.adjustToxLoss(1.5 * max(ethanol_reagent.alcohol_perc, 1) * PROCESS_ACCURACY)
+ else
+ owner.adjustToxLoss(0.5 * max(ethanol_reagent.alcohol_perc, 1) * PROCESS_ACCURACY)
+ receive_damage(0.1 * PROCESS_ACCURACY)
+
+// Weak night vision
+/obj/item/organ/internal/eyes/skrell
+ see_in_dark = 3
+
+// Reagent scan for food
+/obj/item/food/examine(mob/user)
+ . = ..()
+ if(!isskrell(user))
+ return
+ . += "It contains:"
+ for(var/datum/reagent/reagent_inside_food as anything in reagents.reagent_list)
+ . += "[reagent_inside_food.volume] units of [reagent_inside_food.name]"
+
+// Reagent scan for solutions
+/mob/living/carbon/human/reagent_vision()
+ return isskrell(src) || ..()
+
+// Getting less toxins
+/datum/species/skrell
+ tox_mod = 0.9
diff --git a/modular_ss220/barsigns/_barsigns.dm b/modular_ss220/barsigns/_barsigns.dm
new file mode 100644
index 000000000000..106f29bca442
--- /dev/null
+++ b/modular_ss220/barsigns/_barsigns.dm
@@ -0,0 +1,4 @@
+/datum/modpack/barsigns
+ name = "Барные вывески"
+ desc = "Добавляет новые барные вывески"
+ author = "Aylong220, larentoun"
diff --git a/modular_ss220/barsigns/_barsigns.dme b/modular_ss220/barsigns/_barsigns.dme
new file mode 100644
index 000000000000..5bdc02915902
--- /dev/null
+++ b/modular_ss220/barsigns/_barsigns.dme
@@ -0,0 +1,3 @@
+#include "_barsigns.dm"
+
+#include "code/barsigns.dm"
diff --git a/modular_ss220/barsigns/code/barsigns.dm b/modular_ss220/barsigns/code/barsigns.dm
new file mode 100644
index 000000000000..0d9c0c4409fd
--- /dev/null
+++ b/modular_ss220/barsigns/code/barsigns.dm
@@ -0,0 +1,53 @@
+/obj/machinery/barsign/set_sign(datum/barsign/sign)
+ if(!istype(sign))
+ return
+ if(initial(sign.ss220_icon))
+ icon = initial(sign.ss220_icon)
+ else
+ icon = initial(icon)
+ . = ..()
+
+/datum/barsign
+ var/ss220_icon
+
+/datum/barsign/evahumanspace
+ name = "SS220 EVA Human in Space"
+ icon = "evahumanspace"
+ desc = "Безопасность - это привелегия."
+ ss220_icon = 'modular_ss220/barsigns/icons/barsigns.dmi'
+
+/datum/barsign/warpsurf
+ name = "SS220 Warp Surf"
+ icon = "warpsurf"
+ desc = "Welcome to the club, buddy!"
+ ss220_icon = 'modular_ss220/barsigns/icons/barsigns.dmi'
+
+/datum/barsign/papacafe
+ name = "SS220 Space Daddy's Cafe"
+ icon = "papacafe"
+ desc = "Уважай своего Космического Папу!"
+ ss220_icon = 'modular_ss220/barsigns/icons/barsigns.dmi'
+
+/datum/barsign/wycctide
+ name = "SS220 Wycctide"
+ icon = "wycctide"
+ desc = "О нет, он близится!"
+ ss220_icon = 'modular_ss220/barsigns/icons/barsigns.dmi'
+
+/datum/barsign/shitcur
+ name = "SS220 Shitcur"
+ icon = "shitcur"
+ desc = "Невиновность ничего не доказывает."
+ ss220_icon = 'modular_ss220/barsigns/icons/barsigns.dmi'
+
+/datum/barsign/pourndot
+ name = "SS220 Pour and that's it"
+ icon = "pourndot"
+ desc = "Нальют и Точка. Тяжёлые времена приближаются."
+ ss220_icon = 'modular_ss220/barsigns/icons/barsigns.dmi'
+
+/datum/barsign/moonipub
+ name = "SS220 Mooniverse pub"
+ icon = "mooni"
+ desc = "Совершенно новый паб."
+ ss220_icon = 'modular_ss220/barsigns/icons/barsigns.dmi'
diff --git a/modular_ss220/barsigns/icons/barsigns.dmi b/modular_ss220/barsigns/icons/barsigns.dmi
new file mode 100644
index 000000000000..58bcb474b620
Binary files /dev/null and b/modular_ss220/barsigns/icons/barsigns.dmi differ
diff --git a/modular_ss220/bureaucracy/_bureaucracy.dm b/modular_ss220/bureaucracy/_bureaucracy.dm
new file mode 100644
index 000000000000..cc9b26b56dab
--- /dev/null
+++ b/modular_ss220/bureaucracy/_bureaucracy.dm
@@ -0,0 +1,9 @@
+/datum/modpack/bureaucracy
+ name = "Бюрократия"
+ desc = "Добавляет бланки в ксерокс."
+ author = "Aylong220, Furior, RV666"
+
+/datum/modpack/bureaucracy/initialize()
+ . = ..()
+ for(var/datum/bureaucratic_form/form as anything in subtypesof(/datum/bureaucratic_form))
+ GLOB.bureaucratic_forms["[form]"] = new form
diff --git a/modular_ss220/bureaucracy/_bureaucracy.dme b/modular_ss220/bureaucracy/_bureaucracy.dme
new file mode 100644
index 000000000000..ed7bf92d9036
--- /dev/null
+++ b/modular_ss220/bureaucracy/_bureaucracy.dme
@@ -0,0 +1,5 @@
+#include "_bureaucracy.dm"
+
+#include "code/paper.dm"
+#include "code/forms.dm"
+#include "code/photocopier.dm"
diff --git a/modular_ss220/bureaucracy/code/forms.dm b/modular_ss220/bureaucracy/code/forms.dm
new file mode 100644
index 000000000000..54677acd4da4
--- /dev/null
+++ b/modular_ss220/bureaucracy/code/forms.dm
@@ -0,0 +1,549 @@
+GLOBAL_LIST_INIT(bureaucratic_forms, list())
+
+/datum/bureaucratic_form
+ var/const/footer_signstampfax = "
Подписи глав являются доказательством их согласия. Данный документ является недействительным при отсутствии релевантной печати. Пожалуйста, отправьте обратно подписанную/проштампованную копию факсом.
"
+ var/const/footer_signstamp = "
Подписи глав являются доказательством их согласия. Данный документ является недействительным при отсутствии релевантной печати.
"
+ var/const/footer_confidential = "
Данный документ является недействительным при отсутствии печати. Отказ от ответственности: Данный факс является конфиденциальным и не может быть прочтен сотрудниками не имеющего доступа. Если вы получили данный факс по ошибке, просим вас сообщить отправителю и удалить его из вашего почтового ящика или любого другого носителя. И Nanotrasen, и любой её агент не несёт ответственность за любые сделанные заявления, они являются исключительно заявлениями отправителя, за исключением если отправителем является Nanotrasen или один из её агентов. Отмечаем, что ни Nanotrasen, ни один из агентов корпорации не несёт ответственности за наличие вирусов, который могут содержаться в данном факсе или его приложения, и это только ваша прерогатива просканировать факс и приложения на них. Никакие контракты не могут быть заключены посредством факсимильной связи.
"
+
+ /// Form name. Will be applied to a paper
+ var/name
+ /// Form id
+ var/id
+ /// Alternative form name. Appears in printer this way with id
+ var/altername
+ /// In what category the form is
+ var/category
+ /// What access is required to print this form
+ var/req_access
+
+ /// Text that will be applied to a paper
+ var/text
+ var/is_header_needed = TRUE
+ /// Header that will be apllied to a paper
+ var/header
+ /// Footer that will be apllied to a paper
+ var/footer = footer_signstampfax
+
+ /// Used in header to decide to add or not CONFEDENTIAL text
+ var/confidential = FALSE
+ /// Used in some forms as a reminder of some stuff
+ var/notice = "Перед заполнением прочтите от начала до конца | Во всех PDA имеется ручка"
+ /// Is generated based on station name. Used in some forms
+ var/from
+
+/datum/bureaucratic_form/New()
+ . = ..()
+ from = "Научная станция Nanotrasen\
+ "[SSmapping.map_datum.fluff_name]""
+ if(is_header_needed)
+ header = "
"
+
+/datum/bureaucratic_form/proc/apply_to_paper(obj/item/paper/paper, mob/user = null)
+ paper.name = name
+ paper.info = admin_pencode_to_html(text, user)
+ paper.header = header
+ paper.footer = footer
+ paper.force_big = TRUE
+ paper.populatefields()
+
+// Главы станции
+/datum/bureaucratic_form/NT_COM_ST
+ name = "Форма NT-COM-ST"
+ id = "NT-COM-ST"
+ altername = "Отчет о ситуации на станции"
+ category = "Главы станции"
+ text = "
Приветствую Центральное командование
Сообщает вам , в должности .
В данный момент на станции код: Активные угрозы для станции: Потери среди экипажа: Повреждения на станции: Общее состояние станции: Дополнительная информация:
Подписи и штампы
Подпись: *В данном документе описывается полное состояние станции, необходимо перечислить всю доступную информацию. *Информацию, которую вы считаете нужной, необходимо сообщить в разделе – дополнительная информация. *Данный документ считается официальным только после подписи уполномоченного лица и наличии на документе его печати. "
+
+/datum/bureaucratic_form/NT_COM_ACAP
+ name = "Форма NT-COM-ACAP"
+ id = "NT-COM-ACAP"
+ altername = "Заявление о повышении главы отдела до и.о. капитана"
+ category = "Главы станции"
+ text = "Я, , в должности главы отделения , прошу согласовать нынешнее командование \[station\], в повышении меня до и.о. капитана.
⠀⠀⠀При назначении меня на данную должность, я обязуюсь выполнять все рекомендации и правила, согласно стандартным рабочим процедурам капитана. До появления капитана, я обеспечиваю порядок и управление станцией, сохранность и безопасность диска с кодами авторизации ядерной боеголовки, а также самой боеголовки, коды от сейфов и личные вещи капитана.
⠀⠀⠀При появлении капитана мне необходибо будет сообщить: состояние и статус станции, о своем продвижении до и.о. капитана, и обнулить капитанский доступ при первому требованию капитана.
Подписи и штампы
Подпись заявителя: Подпись инициатора повышения: Время вступления в должность и.о. капитана: Подпись главы отделения : Подпись главы отделения : Подпись главы отделения : *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченного лица, производившего инициацию повышения, и выдаче заявителю. *Если один (или более) глав отсутствуют, необходимо собрать подписи, действующих глав. *Так же в данном документе, главам, которые согласились с кандидатом, необходимо поставить свою печать и подпись."
+
+/datum/bureaucratic_form/NT_COM_ACOM
+ name = "Форма NT-COM-ACOM"
+ id = "NT-COM-ACOM"
+ altername = "Заявление о повышении сотрудника до и.о. главы отделения"
+ category = "Главы станции"
+ text = " ᅠᅠЯ, , в должности сотрудника отделения , прошу согласовать нынешнее командование \[station\], в повышении меня до звания и.о. главы .
⠀⠀⠀При назначении меня на данную должность, я обязуюсь выполнять все рекомендации, и правила, которые присутствуют на главе отделения . До появления основного главы отделения, я обеспечиваю порядок и управление своим отделом, сохранность и безопасность личных вещей главы отделения.
⠀⠀⠀При появлении главы отделения, мне неообходимо сообщить: состояние и статус своего отдела, о своем продвижении до и.о. главы отделения, и сдать доступ и.о. главы и взятые вещи при первом требовании прибывшего главы.
Подписи и штампы
Подпись заявителя: Подпись инициатора повышения: Время вступления в и.о. : Подпись главы отделения : Подпись главы отделения : Подпись главы отделения : *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченного лица, производившего инициацию повышения, и выдаче заявителю. *При указании главы, рекомендуется использовать сокращения: *СМО (главврач), СЕ (глав. инженер), РД (дир. исследований), КМ (завхоз), ГСБ (глава СБ), ГП (глава персонала). *Если один (или более) глав отсутствуют, необходимо собрать подписи, действующих глав. *Так же в данном документе, главам, которые согласились с кандидатом, необходимо поставить свою печать и подпись."
+
+/datum/bureaucratic_form/NT_COM_LCOM
+ name = "Форма NT-COM-LCOM"
+ id = "NT-COM-LCOM"
+ altername = "Заявление об увольнении главы отделения"
+ category = "Главы станции"
+ text = " ᅠᅠЯ, , в должности – , заявляю об официальном увольнении действующего главы , отделения . Причина увольнения: ⠀⠀⠀При наличии иных причин, от других глав, они так же могут написать их в данном документе.
Подписи и штампы
Подпись инициатора увольнения: Подпись увольняемого, о ознакомлении: Дата и время увольнения: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченного лица, производившего инициацию увольнения, и выдаче увольняемому. *Для полной эффективности данного документа, необходимо собрать как можно больше причин для увольнения, и перечислить их. Инициировать увольнение может только капитан или глава персонала. "
+
+/datum/bureaucratic_form/NT_COM_REQ
+ name = "Форма NT-COM-REQ"
+ id = "NT-COM-REQ"
+ altername = "Запрос на поставку с Центрального командования"
+ category = "Главы станции"
+ text = "
Приветствую Центральное командование
Сообщает вам , в должности .
Текст запроса:
Причина запроса:
Подписи и штампы
Подпись: *В данном документе описывается запросы на поставку оборудования/ресурсов, необходимо перечислить по пунктно необходимое для поставки. *Данный документ считается, официальным, только после подписи уполномоченного лица, и наличии на документе его печати. "
+
+/datum/bureaucratic_form/NT_COM_OS
+ name = "Форма NT-COM-OS"
+ id = "NT-COM-OS"
+ altername = "Отчёт о выполнении цели"
+ category = "Главы станции"
+ text = " Цель станции: Статус цели: Общее состояние станции: Активные угрозы: Оценка работы экипажа: Дополнительные замечания:
Подписи и штампы
Должность уполномоченного лица: Подпись уполномоченного лица: *Данное сообщение должно сообщить вам о состоянии цели, установленной Центральным командованием Nanotrasen для ИСН "Керберос". Убедительная просьба внимательно прочитать данное сообщение для вынесения наиболее эффективных указаний для последующей деятельности станции. *Данный документ считается официальным только при наличии подписи уполномоченного лица и соответствующего его должности штампа. В случае отсутствия любого из указанных элементов данный документ не является официальным и рекомендуется его удалить с любого информационного носителя. ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Корпорация Nanotrasen не несёт ответственности, если данный документ не попал в руки первоначального предполагаемого получателя. Однако, корпорация Nanotrasen запрещает использование любой имеющейся в данном документе информации третьими лицами и сообщает, что это преследуется по закону, даже если информация в данном документе не является достоверной.
"
+
+// Медицинский Отдел
+
+/datum/bureaucratic_form/NT_MD_01
+ name = "Форма NT-MD-01"
+ id = "NT-MD-01"
+ altername = "Постановление на поставку медикаментов"
+ category = "Медицинский отдел"
+ text = "⠀⠀⠀ Я, , в должности , запрашиваю следующие медикаменты на поставку в медбей:
Подписи и штампы
Подпись заказчика: Подпись грузчика: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче грузчику или производившему поставку."
+ footer = footer_signstamp
+
+/datum/bureaucratic_form/NT_MD_02
+ name = "Форма NT-MD-02"
+ id = "NT-MD-02"
+ altername = "Отчёт о вскрытии"
+ category = "Медицинский отдел"
+ text = "
Основная информация
Скончавшийся:
Раса:
Пол:
Возраст:
Группа крови:
Должность:
Отчёт о вскрытии
Тип смерти:
Описание тела:
Метки и раны:
Вероятная причина смерти:
Детали:
Подписи и штампы
Время:
Вскрытие провёл:
"
+ footer = footer_signstamp
+
+/datum/bureaucratic_form/NT_MD_03
+ name = "Форма NT-MD-03"
+ id = "NT-MD-03"
+ altername = "Постановление на изготовление химических препаратов"
+ category = "Медицинский отдел"
+ text = "⠀⠀⠀ Я, , в должности , запрашиваю следующие химические медикаменты, для служебного использования в медбее:
Подписи и штампы
Подпись заказчика: Подпись исполняющего: Время заказа: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче лицу исполнившему заказ"
+ footer = footer_signstamp
+
+/datum/bureaucratic_form/NT_MD_04
+ name = "Форма NT-MD-04"
+ id = "NT-MD-04"
+ altername = "Сводка о вирусе"
+ category = "Медицинский отдел"
+ text = "
Вирус:
Полное название вируса: Свойства вируса: Передача вируса: Побочные эффекты:
Дополнительная информация:
Лечение вируса:
Подписи и штампы
Подпись вирусолога: *В дополнительной информации, указывается вся остальная информация, по поводу данного вируса. "
+ footer = footer_signstamp
+
+/datum/bureaucratic_form/NT_MD_05
+ name = "Форма NT-MD-05"
+ id = "NT-MD-05"
+ altername = "Отчет об психологическом состоянии"
+ category = "Медицинский отдел"
+ text = " Пациент: Раздражители: Симптомы и побочные действия: Дополнительная информация:
Подписи и штампы
Подпись психолога: Время обследования: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче пациенту"
+ footer = footer_signstamp
+
+// Мед-без нумерации
+/datum/bureaucratic_form/NT_MD_VRR
+ name = "Форма NT-MD-VRR"
+ id = "NT-MD-VRR"
+ altername = "Запрос на распространение вируса"
+ category = "Медицинский отдел"
+ text = "
Основная информация
Я, , в должности – , запрашиваю право на распространение вируса среди экипажа станции.
Название вируса:
Задачи вируса:
Лечение:
Вакцина была произведена и в данный момент находится:
Подписи и штампы
Подпись вирусолога:
Подпись глав. Врача:
Подпись капитана:
*Производитель вируса несет полную ответственность за его распространение, изолирование и лечение *При возникновении опасных или смертельных побочных эффектов у членов экипажа, производитель должен незамедлительно предоставить вакцину, от данного вируса."
+ footer = footer_signstamp
+
+// Отдел исследований
+/datum/bureaucratic_form/NT_RND_01
+ name = "Форма NT-RND-01"
+ id = "NT-RND-01"
+ altername = "Отчет о странном предмете"
+ category = "Отдел исследований"
+ text = " Название предмета: Тип предмета: Строение: Особенности и функционал: Дополнительная информация:
Подписи и штампы
Подпись производившего осмотр: *В дополнительной информации, рекомендуется указать остальную информацию о предмете, любое взаимодействие с ним, модификации, итоговый вариант после модификации."
+
+/datum/bureaucratic_form/NT_RND_02
+ name = "Форма NT-RND-02"
+ id = "NT-RND-02"
+ altername = "Заявление на киберизацию"
+ category = "Отдел исследований"
+ text = "⠀⠀⠀ Я, , в должности , самовольно подтверждаю согласие на проведение киберизации. ⠀⠀⠀ Я полностью доверяю работнику в должности – . Я хорошо осведомлен о рисках, связанных как с операцией, так и с киберизацией, и понимаю, что Nanotrasen не несет ответственности, если эти процедуры вызовут боль, заражение или иные случаи летального характера.
Подписи и штампы
Подпись заявителя: Подпись уполномоченного: *Если член экипажа мертв, данный документ нету необходимости создавать. *Если член экипажа жив, данный документ сохраняется только у уполномоченного лица. *Данный документ может использоваться как для создания киборгов, так и для ИИ"
+
+/datum/bureaucratic_form/NT_RND_03
+ name = "Форма NT-RND-03"
+ id = "NT-RND-03"
+ altername = "Заявление на получение и установку импланта"
+ category = "Отдел исследований"
+ text = "
Заявление
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Требуемый имплантат: Может требовать дополнительного согласования
Причина: Объясните свои намерения
Подписи и штампы
Дата и время:
Подпись заявителя:
Подпись Руководителя Исследований:
Подпись выполняющего установку имплантата:
"
+
+// Общие формы
+/datum/bureaucratic_form/NT_BLANK
+ name = "Форма NT"
+ id = "NT-BLANK"
+ altername = "Пустой бланк для любых целей"
+ category = "Общие формы"
+ text = "
Основная информация
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Заявление
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
Подпись (дополнительная):
"
+ footer = null
+
+/datum/bureaucratic_form/NT_E_112
+ name = "Форма NT-E-112"
+ id = "NT-E-112"
+ altername = "Экстренное письмо"
+ category = "Общие формы"
+ notice = "Форма предназначена только для экстренного использования."
+ text = "
Основная информация
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Отчёт о ситуации
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_signstamp
+
+// Отдел кадров
+/datum/bureaucratic_form/NT_HR_00
+ name = "Форма NT-HR-00"
+ id = "NT-HR-00"
+ altername = "Бланк заявления"
+ category = "Отдел кадров"
+ text = "
Основная информация
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Заявление
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
Подпись (дополнительная):
"
+ footer = footer_signstamp
+
+/datum/bureaucratic_form/NT_HR_01
+ name = "Форма NT-HR-01"
+ id = "NT-HR-01"
+ altername = "Заявление о приеме на работу"
+ category = "Отдел кадров"
+ text = "
Заявление
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Запрашиваемая должность: Требует наличия квалификации
Список компетенций:
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
Подпись будущего главы:
"
+
+/datum/bureaucratic_form/NT_HR_02
+ name = "Форма NT-HR-02"
+ id = "NT-HR-02"
+ altername = "Заявление на смену должности"
+ category = "Отдел кадров"
+ text = "
Заявление
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Запрашиваемая должность: Требует наличия квалификации
Причина: Объясните свои намерения
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
Подпись текущего главы:
Подпись будущего главы:
"
+
+/datum/bureaucratic_form/NT_HR_12
+ name = "Форма NT-HR-12"
+ id = "NT-HR-12"
+ altername = "Приказ на смену должности"
+ category = "Отдел кадров"
+ text = "
Приказ
Имя сотрудника: Полностью и без ошибок
Номер аккаунта сотрудника: Эта информация есть у главы персонала
Текущая должность: Указано на ID карте
Запрашиваемая должность: Требует наличия квалификации
Причина: Объясните свои намерения
Подписи и штампы
Время:
Подпись инициатора:
Подпись главы персонала:
"
+
+/datum/bureaucratic_form/NT_HR_03
+ name = "Форма NT-HR-03"
+ id = "NT-HR-03"
+ altername = "Заявление об увольнении"
+ category = "Отдел кадров"
+ text = "
Заявление
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Причина: Объясните свои намерения
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
Подпись текущего главы:
"
+
+/datum/bureaucratic_form/NT_HR_13
+ name = "Форма NT-HR-13"
+ id = "NT-HR-13"
+ altername = "Приказ об увольнении"
+ category = "Отдел кадров"
+ text = "
Приказ
Имя увольняемого: Полностью и без ошибок
Номер аккаунта увольняемого: Эта информация есть у главы персонала
Текущая должность: Указано на ID карте
Причина: Объясните свои намерения
Подписи и штампы
Время:
Подпись инициатора:
Подпись главы персонала:
"
+
+/datum/bureaucratic_form/NT_HR_04
+ name = "Форма NT-HR-04"
+ id = "NT-HR-04"
+ altername = "Заявление на выдачу новой ID карты"
+ category = "Отдел кадров"
+ text = "
Заявление
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Причина: Объясните свои намерения
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
"
+
+/datum/bureaucratic_form/NT_HR_05
+ name = "Форма NT-HR-05"
+ id = "NT-HR-05"
+ altername = "Заявление на дополнительный доступ"
+ category = "Отдел кадров"
+ text = "
Заявление
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Требуемый доступ: Может требовать дополнительного согласования
Причина: Объясните свои намерения
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
Подпись текущего главы:
"
+
+/datum/bureaucratic_form/NT_HR_06
+ name = "Форма NT-HR-06"
+ id = "NT-HR-06"
+ altername = "Лицензия на создание организации/отдела"
+ category = "Отдел кадров"
+ text = "
Заявление
Я , прошу Вашего разрешения на создание для работы с экипажем.
Наше Агенство/Отдел займет .
Наша Организация обязуется соблюдать Космический Закон. Также я , как глава отдела, буду нести ответственность за своих сотрудников и обязуюсь наказывать их за несоблюдение Космического Закона. Или же передавать сотрудникам Службы Безопасности.
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала: *Обязательно провести копирование документа для главы персонала, оригинал документа должен быть выдан обладателю лицензии.
*Данная форма документа, обязательно должна подтверждаться печатью ответственного лица. В случае наличия опечаток и отсутствия подписей или печатей, лицензия будет являться недействительной."
+
+/datum/bureaucratic_form/NT_HR_07
+ name = "Форма NT-HR-07"
+ id = "NT-HR-07"
+ altername = "Разрешение на перестройку/перестановку"
+ category = "Отдел кадров"
+ text = "
Разрешение
Я , прошу Вашего разрешения на перестройку/перестановку помещения под свои нужды или нужды организации.
Должность заявителя:
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
*Обязательно провести копирование документа для главы персонала, оригинал документа должен быть выдан заявителю."
+
+/datum/bureaucratic_form/NT_HR_08
+ name = "Форма NT-HR-08"
+ id = "NT-HR-08"
+ altername = "Запрос о постройке меха"
+ category = "Отдел кадров"
+ text = "⠀⠀⠀Я, , прошу произвести постройку меха – , с данными модификациями – , для выполнения задач: . ⠀⠀⠀Так же я, , обязуюсь соблюдать все правила, законы и предупреждения, а также соглашаюсь выполнять все устные или письменные инструкции, или приказы со стороны командования, представителей или агентов Nanotrasen, и Центрального командования. ⠀⠀⠀При получении меха, я становлюсь ответственным за его повреждение, уничтожение, похищение, или попадание в руки людей, относящимся к врагам Nanotrasen.
Подписи и штампы
Подпись заявителя: Время постройки меха: Время передачи меха заявителю: Подпись изготовителя меха: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче заявителю."
+
+/datum/bureaucratic_form/NT_HR_09
+ name = "Форма NT-HR-09"
+ id = "NT-HR-09"
+ altername = "Квитанция о продаже пода"
+ category = "Отдел кадров"
+ text = "⠀⠀⠀Я, , в должности – произвожу передачу транспортного средства на платной основе члену экипажа , в должности – . Продаваемый под имеет модификации: . Стоимость пода: . ⠀⠀⠀Я, , как покупатель, становлюсь ответственным за его повреждение, уничтожение, похищение, или попадание в руки людей, относящимся к врагам Nanotrasen. ⠀⠀⠀Так же я, обязуюсь соблюдать все правила, законы и предупреждения, а также соглашаюсь выполнять все устные или письменные инструкции, или приказы со стороны командования, представителей или агентов Nanotrasen, и Центрального командования.
Подписи и штампы
Подпись продавца: Подпись покупателя: Время сделки: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче покупателю."
+
+// Отдел сервиса
+/datum/bureaucratic_form/NT_MR
+ name = "Форма NT-MR"
+ id = "NT-MR"
+ altername = "Свидетельство о заключении брака"
+ category = "Отдел сервиса"
+ text = "⠀⠀⠀Объявляется, что , и , официально прошли процедуру заключения гражданского брака.
*Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче одному из представителей брака. *При заявлении о расторжении брака, необходимо наличие двух супругов, и данного документа."
+
+/datum/bureaucratic_form/NT_MRL
+ name = "Форма NT-MRL"
+ id = "NT-MRL"
+ altername = "Заявление о расторжении брака"
+ category = "Отдел сервиса"
+ text = "⠀⠀⠀Просим произвести регистрацию расторжения брака, подтверждаем взаимное согласие на расторжение брака.
Подписи и штампы
Подпись супруга: Подпись супруги:
Подпись уполномоченного:
*Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче каждому, из супругов."
+
+// Отдел снабжения
+/datum/bureaucratic_form/NT_REQ_01
+ name = "Форма NT-REQ-01"
+ id = "NT-REQ-01"
+ altername = "Запрос на поставку"
+ category = "Отдел снабжения"
+ text = "
Сторона запроса
Имя запросившего: Полностью и без ошибок
Номер аккаунта: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Способ получения: Предпочитаемый способ
Причина запроса:
Список запроса:
Сторона поставки
Имя поставщика: Полностью и без ошибок
Номер аккаунта: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Способ доставки: Утверждённый способ
Комментарии:
Список поставки и цены:
Итоговая стоимость: Пропустите, если бесплатно
Подписи и штампы
Время:
Подпись стороны запроса:
Подпись стороны поставки:
Подпись главы (если требуется):
"
+ footer = footer_signstamp
+
+/datum/bureaucratic_form/NT_SUP_01
+ name = "Форма NT-SUP-01"
+ id = "NT-SUP-01"
+ altername = "Регистрационная форма для подтверждения заказа"
+ category = "Отдел снабжения"
+ text = "
Отдел снабжения
Регистрационная форма для подтверждения заказа
Имя заявителя: Должность заявителя: Подробное объяснение о необходимости заказа:
Данная форма является приложением для оригинального автоматического документа, полученного с рук заявителя. Для подтверждения заказа заявителя необходимы указанные подписи и соответствующие печати отдела по заказу. "
+ footer = null
+
+// Служба безопасности
+/datum/bureaucratic_form/NT_SEC_01
+ name = "Форма NT-SEC-01"
+ id = "NT-SEC-01"
+ altername = "Свидетельские показания"
+ category = "Служба безопасности"
+ text = "
Информация о свидетеле
Имя свидетеля: Полностью и без ошибок
Номер аккаунта свидетеля: Эта информация есть у главы персонала
Должность свидетеля: Указано на ID карте
Свидетельство
Я, (подпись свидетеля) , подтверждаю, что приведенная выше информация является правдивой и точной, насколько мне известно, и передана в меру моих возможностей. Подписываясь ниже, я тем самым подтверждаю, что Верховный Суд может признать меня неуважительным или виновным в лжесвидетельстве согласно Закону SolGov 552 (a) (c) и Постановлению корпорации Nanotrasen 7716 (c).
Подписи и штампы
Время:
Подпись сотрудника, получающего показания:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_11
+ name = "Форма NT-SEC-11"
+ id = "NT-SEC-11"
+ altername = "Ордер на обыск"
+ category = "Служба безопасности"
+ text = "
Информация о свидетеле
Имя свидетеля: Полностью и без ошибок
Номер аккаунта свидетеля: Эта информация есть у главы персонала
Должность свидетеля: Указано на ID карте
Ордер
В целях обыска: (помещения, имущества, лица)
Ознакомившись с письменными показаниями свидетеля(-ей), у меня появились основания полагать, что на лицах или помещениях, указанных выше, имеются соответствующие доказательства в этой связи или в пределах, в частности:
и другое имущество, являющееся доказательством уголовного преступления, контрабанды, плодов преступления или предметов, иным образом принадлежащих преступнику, или имущество, спроектированное или предназначенное для использования, или которое используется или использовалось в качестве средства совершения уголовного преступления, в частности заговор с целью совершения преступления, или совершения злонамеренного предъявления ложных и фиктивных претензий к или против корпорации Нанотрейзен или его дочерних компаний.
Я удовлетворен тем, что показания под присягой и любые записанные показания устанавливают вероятную причину полагать, что описанное имущество в данный момент скрыто в описанных выше помещениях, лицах или имуществе, и устанавливают законные основания для выдачи этого ордера.
ВЫ НАСТОЯЩИМ КОМАНДИРОВАНЫ для обыска вышеуказанного помещения, имущества или лица в течение минут с даты выдачи настоящего ордера на указанное скрытое имущество, и если будет установлено, что имущество изъято, оставить копию этого ордера в качестве доказательства на реквизированную собственность, в соответствии с требованиями указа корпорации Nanotrasen.
Слава Корпорации Nanotrasen!
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_21
+ name = "Форма NT-SEC-21"
+ id = "NT-SEC-21"
+ altername = "Ордер на арест"
+ category = "Служба безопасности"
+ text = "
Ордер
В целях ареста: Имя полностью и без ошибок
Должность:
Сотрудники Службы Безопасности настоящим уполномочены и направлены на задержание и арест указанного лица. Они будут игнорировать любые заявления о неприкосновенности или привилегии со стороны подозреваемого или агентов, действующих от его имени. Сотрудники немедленно доставят указанное лицо в Бриг для отбывать наказание за следующие преступления:
Предполагается, что подозреваемый будет отбывать наказание в за вышеуказанные преступления.
Слава Корпорации Nanotrasen!
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_02
+ name = "Форма NT-SEC-02"
+ id = "NT-SEC-02"
+ altername = "Отчёт по результатам расследования"
+ category = "Служба безопасности"
+ text = "
Дело
Тип проишествия/преступления:
Время проишествия/преступления:
Местоположение:
Краткое описание:
Участвующие лица
Арестованные:
Подозреваемые:
Свидетели:
Раненные:
Пропавшие:
Скончавшиеся:
Ход расследования
Прикреплённые доказательства:
Дополнительные замечания:
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_03
+ name = "Форма NT-SEC-03"
+ id = "NT-SEC-03"
+ altername = "Заявление о краже"
+ category = "Служба безопасности"
+ text = "⠀⠀⠀Я, , в должности , заявляю:
Подписи и штампы
Подпись потерпевшего: Подпись принимавшего заявление: Время принятия заявления: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче потерпевшему. *При обнаружении предмета кражи (предмет, жидкость или существо), данный предмет необходимо передать детективу, для дальнейшего осмотра и обследования. *После заключения детектива, предмет можно выдать владельцу. "
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_04
+ name = "Форма NT-SEC-04"
+ id = "NT-SEC-04"
+ altername = "Заявление о причинении вреда здоровью или имуществу"
+ category = "Служба безопасности"
+ text = "⠀⠀⠀Я, , в должности , заявляю:
Подписи и штампы
Подпись пострадавшего: Время происшествия: Подпись уполномоченного: Время принятия заявления: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче пострадавшему."
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_05
+ name = "Форма NT-SEC-05"
+ id = "NT-SEC-05"
+ altername = "Разрешение на оружие"
+ category = "Служба безопасности"
+ text = "⠀⠀⠀Члену экипажа, , в должности , было выдано разрешение на оружие. Я соглашаюсь с условиями его использования, хранения и применения. Данное оружие я обязуюсь применять только в целях самообороны, защиты своих личных вещей, и рабочего места, а так же для защиты своих коллег. ⠀⠀⠀При попытке применения оружия, против остальных членов экипажа не предоставляющих угрозу, или при запугивании данным оружием, я лишаюсь лицензии на оружие, а так же понесу наказания, при нарушении закона. Название и тип оружия:
Подписи и штампы
Подпись уполномоченного: Подпись получателя: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче получателю. *Документ не является действительным без печати Вардена/ГСБ и его подписи."
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_06
+ name = "Форма NT-SEC-06"
+ id = "NT-SEC-06"
+ altername = "Разрешение на присваивание канала связи"
+ category = "Служба безопасности"
+ text = "
Разрешение
Я , прошу Вашего разрешения на присваивание канала связи , для грамотной работы организации.
Должность заявителя:
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
Подпись главы службы безопасности:
*Обязательно провести копирование документа для главы персонала, оригинал документа должен быть выдан заявителю.
*Обязательно провести копирование документа для службы безопасности."
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_07
+ name = "Форма NT-SEC-07"
+ id = "NT-SEC-07"
+ altername = "Лицензия на использование канала связи и владение дополнительным оборудованием"
+ category = "Служба безопасности"
+ text = "
Лицензия
Имя обладателя лицензии:
Должность обладателя лицензии:
Зарегистрированный канал связи:
Перечень зарегистрированной экипировки:
Подписи и штампы
Время:
Подпись заявителя:
Подпись главы персонала:
Подпись главы службы безопасности: *Обязательно провести копирование документа для главы персонала, оригинал документа должен быть выдан обладателю лицензии.
*Обязательно провести копирование документа для службы безопасности.
*Данная форма документа, обязательно должна подтверждаться печатью ответственного лица. В случае наличия опечаток и отсутствия подписей или печатей, лицензия будет являться недействительной."
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_08
+ name = "Форма NT-SEC-08"
+ id = "NT-SEC-08"
+ altername = "Лицензирование вооружения и экипировки для исполнения деятельности"
+ category = "Служба безопасности"
+ text = "
Лицензия
Имя обладателя лицензии: Должность обладателя лицензии: Перечень зарегистрированного вооружения: Перечень зарегистрированной экипировки:
Подписи и штампы
Время: Подпись обладателя лицензии: Подпись главы службы безопасности:
*Данная форма документа, обязательно должна подтверждаться печатью ответственного лица. В случае наличия опечаток и отсутствия подписей или печатей, лицензия будет является недействительной. Обязательно провести копирование документа для службы безопасности, оригинал документа должен быть выдан обладателю лицензии. В случае несоответствия должности обладателя лицензии, можно приступить к процедуре аннулирования лицензии и изъятию вооружения, экипировки. "
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_SEC_09
+ name = "Форма NT-SEC-09"
+ id = "NT-SEC-09"
+ altername = "Запрет на реанимацию"
+ category = "Служба безопасности"
+ text = "Я, \[field\], в должности \[field\], сообщаю о запрете реанимации в отношении: \[b\]\[field\]\[br\]\[/b\]\[br\]Исходя из того, что вышеупомянутый член экипажа нарушил одну или несколько статей Космического Закона, а именно: \[field\]. \[br\]\[i\]Дополнительные сведения\[/i\]: \[field\]\[br\]\[i\]\[br\]\[br\]\[br\]Подпись уполномоченного: \[field\]\[br\]\[br\]Время вступления запрета в силу: \[field\]\[br\]\[/i\]\[hr\]\[small\]Тело будет помещено на хранение, утилизировано или космировано.\[br\]Данный документ должен иметь подпись и печать магистрата, или капитана. \[br\]При отсутствии данных членов командования, необходимо сообщить ЦК, и получить официальный ответ. \[br\]Без подписи и печати, или ответа со стороны ЦК данный документ не является официальным, инициатора запрета реанимации, а так же его подчиненных необходимо объявить в розыск, за нарушение статьи 205.\[/small\]"
+ footer = footer_confidential
+
+// Юридический отдел
+/datum/bureaucratic_form/NT_LD_00
+ name = "Форма NT-LD-00"
+ id = "NT-LD-00"
+ altername = "Бланк заявления"
+ category = "Юридический отдел"
+ text = "
Основная информация
Имя заявителя: Полностью и без ошибок
Номер аккаунта заявителя: Эта информация есть в ваших заметках
Текущая должность: Указано на ID карте
Заявление
Подписи и штампы
Время:
Подпись заявителя:
Подпись уполномоченного сотрудника:
"
+ footer = footer_signstamp
+
+/datum/bureaucratic_form/NT_LD_01
+ name = "Форма NT-LD-01"
+ id = "NT-LD-01"
+ altername = "Судебный приговор"
+ category = "Юридический отдел"
+ notice = "Данный документ является законным решением суда. Пожалуйста внимательно прочитайте его и следуйте предписаниям, указанные в нем."
+ text = "
Дело
Имя обвинителя: Полностью и без ошибок
Имя обвиняемого: Полностью и без ошибок
Приговор
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_LD_02
+ name = "Форма NT-LD-02"
+ id = "NT-LD-02"
+ altername = "Смертный приговор"
+ category = "Юридический отдел"
+ notice = "Любой смертный приговор, выданный человеком, званием младше, чем капитан, является не действительным, и все казни, действующие от этого приговора являются незаконными. Любой, кто незаконно привел в исполнение смертный приговор действую согласно ложному ордену виновен в убийстве первой степени, и должен быть приговорен минимум к пожизненному заключению и максимум к кибернизации. Этот документ или его факс-копия являются Приговором, который может оспорить только Магистрат или Дивизией защиты активов Nanotrasen (далее именуемой «Компанией»)"
+ text = "
Дело
Принимая во внимание, что (далее именуемый \"подсудимый\"), сознательно совершил преступления статей Космического закона (далее указаны как \"преступления\"), а именно: , суд приговаривает подсудимого к смертной казни через .
Приговор должен быть приведен в исполнение в течение 15 минут после получения данного приказа. Вещи подсудимого, включая ID-карту, ПДА, униформу и рюкзак, должны быть сохранены и переданы соответствующем органам (ID-карту передать главе персонала или капитану для уничтожения), возвращены в соответсвующий отдел или сложены в хранилище улик. Любая контрабанда должна немедленно помещена в хранилище улик. Любую контрабанду запрещено использовать защитой активов или другими персонами, представляющих компанию или её активы и цели, кроме сотрудников отдела исследований и развития.
Тело подсудимого должно быть помещено в морг и забальзамировано, только если данное действие не будет нести опасность станции, активам компании или её имуществу. Останки подсудимого должны быть собраны и подготовлены к доставке к близлежащему административному центру компании, всё имущество и активы должны быть переданы семье подсудимого после окончания смены.
Слава Nanotrasen!
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_LD_03
+ name = "Форма NT-LD-03"
+ id = "NT-LD-03"
+ altername = "Заявление о нарушении СРП членом экипажа"
+ category = "Юридический отдел"
+ text = " ⠀⠀⠀Я, , в должности – , заявляю, что член экипажа – , в должности , нарушил один (или несколько) пунктов из Стандартных Рабочих Процедур, а именно:
Примерное время нарушения:
Подписи и штампы
Подпись заявителя: Подпись принимающего: Время принятия заявления: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче заявителю. *После вынесения решения в отношении правонарушителя, желательно сообщить о решении заявителю. "
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_LD_04
+ name = "Форма NT-LD-04"
+ id = "NT-LD-04"
+ altername = "Заявление о нарушении СРП одним из отделов"
+ category = "Юридический отдел"
+ text = " ⠀⠀⠀Я, , в должности – , заявляю, что сотрудники в отделении , нарушили один (или несколько) пунктов из Стандартных Рабочих Процедур, а именно:
Примерное время нарушения: Подпись заявителя:
Подписи и штампы
Подпись принимающего: Время принятия заявления: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче заявителю. *После вынесения решения в отношении правонарушителей, желательно сообщить о решении заявителю. "
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_LD_05
+ name = "Форма NT-LD-05"
+ id = "NT-LD-05"
+ altername = "Отчет агента внутренних дел"
+ category = "Юридический отдел"
+ text = "ᅠᅠЯ, , Как агент внутренних дел, сообщаю:
Подписи и штампы
Подпись АВД: Подпись уполномоченного: Время принятия отчета: *Данный документ подлежит ксерокопированию, для сохранения в архиве уполномоченных лиц, и выдаче агенту. *Данный документ может содержать нарушения, неправильность выполнения работы, невыполнение правил/сводов/законов/СРП "
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_LD_06
+ name = "Форма NT-LD-06"
+ id = "NT-LD-06"
+ altername = "Бланк жалоб АВД"
+ category = "Юридический отдел"
+ text = "
Заявление
Заявитель: Укажите своё полное имя, должность и номер акаунта. Предмет жалобы: Укажите на что/кого вы жалуетесь. Обстоятельства: Укажите подробные обстоятельства произошедшего.
Подписи и штампы
Подпись: Ваша подпись. Жалоба рассмотрена: Имя и фамилия рассмотревшего.
*Обязательно провести копирование документа для агента внутренних дел, оригинал документа должен быть приложен к отчету о расследовании. Копия документа должна быть сохранена в картотеке офиса агента внутренних дел.
*Обязательно донести жалобу до главы отдела, который отвечает за данного сотрудника, если таковой имеется. Если главы отдела нет на смене или он отсуствует по какой то причине, жалобу следует донести до вышестоящего сотрудника станции.
*Если жалоба была написана на главу отдела, следует донести жалобу до вышестоящего сотрудника станции.
*Глава отдела, которому была донесена жалоба, обязан провести беседу с указаным в жалобе сотрудником станции. В зависимости от тяжести проступка, глава отдела имеет право подать приказ об увольнении."
+ footer = footer_confidential
+
+// Центральное командование
+/datum/bureaucratic_form/NT_COM_00
+ name = "Форма NT-COM-00"
+ id = "NT-COM-00"
+ altername = "Общая форма ЦК"
+ category = "Формы ЦК"
+ from = "Административная станция Nanotrasen "Trurl""
+ notice = "Перед заполнением прочтите от начала до конца | Высокий приоритет"
+ confidential = TRUE
+ req_access = ACCESS_CENT_GENERAL
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_COM_00/New()
+ text = "\[small\]Станция — \[b\]Центральное командование\[/b\]\[br\]Год: [GLOB.game_year]\[br\]Время: \[time\]\[/small\]\[br\]\[i\]\[large\]\[b\]\[field\] \[b\]\[/large\]\[/i\]\[/grid\]\[hr\]\[center\]Приветствую экипаж и руководство \[station\]!\[/center\]\[br\]\[br\]\[field\]\[br\]\[small\]\[i\]\[br\]Подпись: \[sign\]\[/i\], в должности: \[i\]\[field\].\[/i\]\[/small\]"
+
+/datum/bureaucratic_form/NT_COM_01
+ name = "Форма NT-COM-01"
+ id = "NT-COM-01"
+ altername = "Запрос отчёта общего состояния станции"
+ category = "Формы ЦК"
+ from = "Административная станция Nanotrasen "Trurl""
+ notice = "Перед заполнением прочтите от начала до конца | Высокий приоритет"
+ confidential = TRUE
+ req_access = ACCESS_CENT_GENERAL
+ text = "
Запрос
Уполномоченный офицер, , в должности , запрашивает сведения об общем состоянии станции.
Ответ
Общее состояние станции:
Криминальный статус:
Повышений:
Понижений:
Увольнений:
Раненные:
Пропавшие:
Скончавшиеся:
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_COM_02
+ name = "Форма NT-COM-02"
+ id = "NT-COM-02"
+ altername = "Запрос отчёта состояния трудовых активов станции"
+ category = "Формы ЦК"
+ from = "Административная станция Nanotrasen "Trurl""
+ notice = "Перед заполнением прочтите от начала до конца | Высокий приоритет"
+ confidential = TRUE
+ req_access = ACCESS_CENT_GENERAL
+ text = "
Запрос
Уполномоченный офицер, , в должности , запрашивает сведения о состоянии трудовых активов станции.
Ответ
Количество сотрудников:
Количество гражданских:
Количество киборгов:
Количество ИИ:
Заявлений о приёме на работу:
Заявлений на смену должности:
Приказов на смену должности:
Заявлений об увольнении:
Приказов об увольнении:
Заявлений на выдачу новой ID карты:
Заявлений на дополнительный доступ:
Медианный уровень кваллификации смены:
Уровень взаимодействия отделов:
Самый продуктивный отдел смены:
Приложите все имеющиеся документы:
NT-HR-00
NT-HR-01
NT-HR-02
NT-HR-12
NT-HR-03
NT-HR-13
NT-HR-04
NT-HR-05
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_COM_03
+ name = "Форма NT-COM-03"
+ id = "NT-COM-03"
+ altername = "Запрос отчёта криминального статуса станции"
+ category = "Формы ЦК"
+ from = "Административная станция Nanotrasen "Trurl""
+ notice = "Перед заполнением прочтите от начала до конца | Высокий приоритет"
+ confidential = TRUE
+ req_access = ACCESS_CENT_GENERAL
+ text = "
Запрос
\
+ Уполномоченный офицер, , в должности , запрашивает сведения о криминальном статусе станции.\
+
Ответ
\
+
Текущий статус угрозы:
Количество офицеров в отделе:
Количество раненных офицеров:
Количество скончавшихся офицеров:
Количество серъёзных инцидентов:
Количество незначительных инцидентов:
Количество раскрытых дел:
Количество арестованных:
Количество сбежавших:
Приложите все имеющиеся документы:
NT-SEC-01
NT-SEC-11
NT-SEC-21
NT-SEC-02
Лог камер заключения
Подписи и штампы
Время:
Подпись уполномоченного лица:
Должность уполномоченного лица:
"
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_COM_04
+ name = "Форма NT-COM-04"
+ id = "NT-COM-04"
+ altername = "Запрос отчёта здравоохранения станции"
+ category = "Формы ЦК"
+ from = "Административная станция Nanotrasen "Trurl""
+ notice = "Перед заполнением прочтите от начала до конца | Высокий приоритет"
+ confidential = TRUE
+ req_access = ACCESS_CENT_GENERAL
+ text = ""
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_COM_05
+ name = "Форма NT-COM-05"
+ id = "NT-COM-05"
+ altername = "Запрос отчёта научно-технического прогресса станции"
+ category = "Формы ЦК"
+ from = "Административная станция Nanotrasen "Trurl""
+ notice = "Перед заполнением прочтите от начала до конца | Высокий приоритет"
+ confidential = TRUE
+ req_access = ACCESS_CENT_GENERAL
+ text = ""
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_COM_06
+ name = "Форма NT-COM-06"
+ id = "NT-COM-06"
+ altername = "Запрос отчёта инженерного обеспечения станции"
+ category = "Формы ЦК"
+ from = "Административная станция Nanotrasen "Trurl""
+ notice = "Перед заполнением прочтите от начала до конца | Высокий приоритет"
+ confidential = TRUE
+ req_access = ACCESS_CENT_GENERAL
+ text = ""
+ footer = footer_confidential
+
+/datum/bureaucratic_form/NT_COM_07
+ name = "Форма NT-COM-07"
+ id = "NT-COM-07"
+ altername = "Запрос отчёта статуса снабжения станции "
+ category = "Формы ЦК"
+ from = "Административная станция Nanotrasen "Trurl""
+ notice = "Перед заполнением прочтите от начала до конца | Высокий приоритет"
+ confidential = TRUE
+ req_access = ACCESS_CENT_GENERAL
+ text = ""
+ footer = footer_confidential
diff --git a/modular_ss220/bureaucracy/code/paper.dm b/modular_ss220/bureaucracy/code/paper.dm
new file mode 100644
index 000000000000..093557d90d32
--- /dev/null
+++ b/modular_ss220/bureaucracy/code/paper.dm
@@ -0,0 +1,23 @@
+/obj/item/paper
+ var/paper_width_big = 600
+ var/paper_height_big = 700
+ var/small_paper_cap = 1024
+ var/force_big = FALSE
+
+/obj/item/paper/updateinfolinks()
+ . = ..()
+ update_size()
+
+/obj/item/paper/proc/update_size()
+ if(force_big || length(info) > small_paper_cap)
+ become_big()
+ else
+ reset_size()
+
+/obj/item/paper/proc/become_big()
+ paper_width = paper_width_big
+ paper_height = paper_height_big
+
+/obj/item/paper/proc/reset_size()
+ paper_width = initial(paper_width)
+ paper_height = initial(paper_height)
diff --git a/modular_ss220/bureaucracy/code/photocopier.dm b/modular_ss220/bureaucracy/code/photocopier.dm
new file mode 100644
index 000000000000..d031d9efaadf
--- /dev/null
+++ b/modular_ss220/bureaucracy/code/photocopier.dm
@@ -0,0 +1,112 @@
+#define PHOTOCOPIER_DELAY 5 SECONDS
+
+/obj/machinery/photocopier
+ toner = 30
+ /// Selected form's category
+ var/category = ""
+ /// Selected form's id
+ var/form_id = ""
+ /// List of available forms
+ var/list/forms
+ /// Selected form's datum
+ var/datum/bureaucratic_form/form
+ /// Printing sound
+ var/print_sound = 'modular_ss220/bureaucracy/sound/print.ogg'
+
+/obj/machinery/photocopier/Initialize(mapload)
+ . = ..()
+ forms = new
+
+/obj/machinery/photocopier/attack_ai(mob/user)
+ add_hiddenprint(user)
+ parse_forms(user)
+ ui_interact(user)
+
+/obj/machinery/photocopier/attack_ghost(mob/user)
+ ui_interact(user)
+
+/obj/machinery/photocopier/attack_hand(mob/user)
+ . = ..()
+ parse_forms(user)
+
+/obj/machinery/photocopier/ui_act(action, list/params)
+ . = ..()
+ if(isnull(.))
+ return
+
+ switch(action)
+ if("print_form")
+ for(var/i in 1 to copies)
+ if(toner <= 0)
+ break
+ print_form(form)
+ . = TRUE
+ if("choose_form")
+ form = GLOB.bureaucratic_forms[params["path"]]
+ form_id = params["id"]
+ . = TRUE
+ if("choose_category")
+ category = params["category"]
+ . = TRUE
+ if("copies")
+ copies = clamp(text2num(params["new"]), 0, maxcopies)
+
+/obj/machinery/photocopier/ui_state(mob/user)
+ return GLOB.default_state
+
+/obj/machinery/photocopier/ui_interact(mob/user, datum/tgui/ui = null)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Photocopier220", "Ксерокс")
+ ui.open()
+
+/obj/machinery/photocopier/ui_data(mob/user)
+ if(!length(forms))
+ parse_forms(user)
+
+ var/list/data = list()
+ data["isAI"] = issilicon(user)
+ data["copies"] = copies
+ data["maxcopies"] = maxcopies
+ data["toner"] = toner
+ data["copyitem"] = (copyitem ? copyitem.name : null)
+ data["folder"] = (folder ? folder.name : null)
+ data["mob"] = (copymob ? copymob.name : null)
+ data["form"] = form
+ data["category"] = category
+ data["form_id"] = form_id
+ data["forms"] = forms
+ return data
+
+/obj/machinery/photocopier/proc/parse_forms(mob/user)
+ var/list/access = user.get_access()
+ forms.Cut()
+ for(var/path in GLOB.bureaucratic_forms)
+ var/datum/bureaucratic_form/paper_form = GLOB.bureaucratic_forms[path]
+ var/req_access = paper_form.req_access
+ if(req_access && !(req_access in access))
+ continue
+ var/form[0]
+ form["path"] = paper_form.type
+ form["id"] = paper_form.id
+ form["altername"] = paper_form.altername
+ form["category"] = paper_form.category
+ forms.Add(list(form))
+
+/obj/machinery/photocopier/proc/print_form(datum/bureaucratic_form/form)
+ if(copying)
+ visible_message(span_notice("[src] работает, проявите терпение."))
+ return FALSE
+
+ toner--
+ copying = TRUE
+ playsound(loc, print_sound, 50)
+ use_power(active_power_consumption)
+ sleep(PHOTOCOPIER_DELAY)
+ var/obj/item/paper/paper = new(loc)
+ paper.pixel_x = rand(-10, 10)
+ paper.pixel_y = rand(-10, 10)
+ form.apply_to_paper(paper, usr)
+ copying = FALSE
+
+#undef PHOTOCOPIER_DELAY
diff --git a/modular_ss220/bureaucracy/sound/print.ogg b/modular_ss220/bureaucracy/sound/print.ogg
new file mode 100644
index 000000000000..a3b70ca66c03
Binary files /dev/null and b/modular_ss220/bureaucracy/sound/print.ogg differ
diff --git a/modular_ss220/camera_nanomap/README.md b/modular_ss220/camera_nanomap/README.md
new file mode 100644
index 000000000000..a59c858b4fb3
--- /dev/null
+++ b/modular_ss220/camera_nanomap/README.md
@@ -0,0 +1,7 @@
+В этом модуле, для добавления наномапы в камеры, были затронуты НЕ модульно следующие файлы:
+"NanoMap.js"
+"NanoMap.scss"
+"CameraConsole.scss"
+"ByondUI.js"
+
+К сожалению, иной путь мог создать больше проблем в будущем чем такой топорный.
diff --git a/modular_ss220/camera_nanomap/camera.dm b/modular_ss220/camera_nanomap/camera.dm
new file mode 100644
index 000000000000..1d58dd99e9d4
--- /dev/null
+++ b/modular_ss220/camera_nanomap/camera.dm
@@ -0,0 +1,4 @@
+/datum/modpack/camera_nanomap
+ name = "Карта в терминале камер"
+ desc = "В названии всё сказано"
+ author = "Aylong220, RV666"
diff --git a/modular_ss220/camera_nanomap/camera.dme b/modular_ss220/camera_nanomap/camera.dme
new file mode 100644
index 000000000000..6c5dfc2f4a7c
--- /dev/null
+++ b/modular_ss220/camera_nanomap/camera.dme
@@ -0,0 +1,3 @@
+#include "camera.dm"
+
+#include "code/camera.dm"
diff --git a/modular_ss220/camera_nanomap/code/camera.dm b/modular_ss220/camera_nanomap/code/camera.dm
new file mode 100644
index 000000000000..bb903e6d06d6
--- /dev/null
+++ b/modular_ss220/camera_nanomap/code/camera.dm
@@ -0,0 +1,107 @@
+/obj/machinery/camera
+ var/nanomap_png
+
+/obj/machinery/camera/Initialize(mapload, should_add_to_cameranet)
+ . = ..()
+ if(z == level_name_to_num(MAIN_STATION))
+ nanomap_png = "[SSmapping.map_datum.technical_name]_nanomap_z1.png"
+ else if(z == level_name_to_num(MINING))
+ nanomap_png = "[MINING]_nanomap_z1.png"
+
+/obj/machinery/computer/security
+ var/list/z_levels = list() // Assoc list, "z_level":"nanomap.png"
+ var/current_z_level_index
+
+/obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui = null)
+ // Update UI
+ ui = SStgui.try_update_ui(user, src, ui)
+ // Show static if can't use the camera
+ if(!active_camera?.can_use())
+ show_camera_static()
+ if(!ui)
+ var/user_uid = user.UID()
+ var/is_living = isliving(user)
+ // Ghosts shouldn't count towards concurrent users, which produces
+ // an audible terminal_on click.
+ if(is_living)
+ watchers += user_uid
+ // Turn on the console
+ if(length(watchers) == 1 && is_living)
+ if(!silent_console)
+ playsound(src, 'sound/machines/terminal_on.ogg', 25, FALSE)
+ use_power(active_power_consumption)
+ // Register map objects
+ user.client.register_map_obj(cam_screen)
+ for(var/plane in cam_plane_masters)
+ var/atom/movable/screen/plane_master/instance = new plane()
+ instance.assigned_map = map_name
+ instance.del_on_map_removal = FALSE
+ instance.screen_loc = "[map_name]:CENTER"
+ instance.backdrop(user)
+
+ user.client.register_map_obj(instance)
+ user.client.register_map_obj(cam_background)
+ // Open UI
+ ui = new(user, src, "CameraConsole220", name)
+ ui.open()
+
+/obj/machinery/computer/security/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/simple/nanomaps)
+ )
+
+/obj/machinery/computer/security/ui_data()
+ var/list/data = list()
+ data["network"] = network
+ data["activeCamera"] = null
+ if(active_camera)
+ data["activeCamera"] = list(
+ name = active_camera.c_tag,
+ status = active_camera.status,
+ )
+ var/list/cameras = get_available_cameras()
+ data["cameras"] = list()
+ z_levels = list()
+ for(var/i in cameras)
+ var/obj/machinery/camera/C = cameras[i]
+ data["cameras"] += list(list(
+ name = C.c_tag,
+ x = C.x,
+ y = C.y,
+ z = C.z,
+ status = C.status
+ ))
+ if(("[C.z]" in z_levels) || !C.nanomap_png)
+ continue
+ z_levels += list("[C.z]" = C.nanomap_png)
+ // Sort it by z levels
+ z_levels = sortAssoc(z_levels)
+ if(isnull(current_z_level_index))
+ current_z_level_index = clamp(z_levels.Find("[z]"), 1, length(z_levels))
+ else
+ current_z_level_index = clamp(current_z_level_index, 1, length(z_levels))
+ // On null, it uses map datum value
+ data["mapUrl"] = z_levels["[z_levels[current_z_level_index]]"] || null
+ // On null, it uses station's z level
+ data["selected_z_level"] = z_levels[current_z_level_index] || null
+ return data
+
+/obj/machinery/computer/security/ui_static_data()
+ var/list/data = ..()
+ data["stationLevel"] = level_name_to_num(MAIN_STATION)
+ return data
+
+/obj/machinery/computer/security/ui_act(action, params)
+ . = ..()
+ if(. && action == "switch_camera")
+ if(!active_camera)
+ return
+ current_z_level_index = z_levels.Find("[active_camera.z]")
+ return
+ if(.)
+ return
+
+ if(action == "switch_z_level")
+ var/z_dir = params["z_dir"]
+ current_z_level_index = clamp(current_z_level_index + z_dir, 1, length(z_levels))
+ return TRUE
diff --git a/modular_ss220/chat_badges/_chat_badges.dm b/modular_ss220/chat_badges/_chat_badges.dm
new file mode 100644
index 000000000000..a343b6d9bda4
--- /dev/null
+++ b/modular_ss220/chat_badges/_chat_badges.dm
@@ -0,0 +1,4 @@
+/datum/modpack/chat_badges
+ name = "Chat badges"
+ desc = "Добавляет иконки в OOC для различных ролей"
+ author = "furior"
diff --git a/modular_ss220/chat_badges/_chat_badges.dme b/modular_ss220/chat_badges/_chat_badges.dme
new file mode 100644
index 000000000000..d6350942a883
--- /dev/null
+++ b/modular_ss220/chat_badges/_chat_badges.dme
@@ -0,0 +1,3 @@
+#include "_chat_badges.dm"
+
+#include "code/badges.dm"
diff --git a/modular_ss220/chat_badges/code/badges.dm b/modular_ss220/chat_badges/code/badges.dm
new file mode 100644
index 000000000000..34d448d3cc17
--- /dev/null
+++ b/modular_ss220/chat_badges/code/badges.dm
@@ -0,0 +1,56 @@
+#define CHAT_BADGES_DMI 'modular_ss220/chat_badges/icons/chatbadges.dmi'
+
+GLOBAL_LIST(badge_icons_cache)
+
+/client/proc/get_ooc_badged_name()
+ var/icon/donator_badge_icon = get_badge_icon(get_donator_badge())
+ var/icon/worker_badge_icon = get_badge_icon(get_worker_badge())
+
+ var/badge_part = "[donator_badge_icon ? bicon(donator_badge_icon) : ""][worker_badge_icon ? bicon(worker_badge_icon) : ""]"
+ var/list/parts = list()
+ if(badge_part)
+ parts += badge_part
+ parts += key
+ return jointext(parts, " ")
+
+/client/proc/get_donator_badge()
+ if(donator_level && (prefs.toggles & PREFTOGGLE_DONATOR_PUBLIC))
+ return donator_level > 3 ? "Paradise" : "Trusted"
+
+ if(prefs.unlock_content && (prefs.toggles & PREFTOGGLE_MEMBER_PUBLIC))
+ return "Trusted"
+
+/client/proc/get_worker_badge()
+ var/static/list/rank_badge_map = list(
+ "Максон" = "Wycc",
+ "Банда" = "Streamer",
+ "Братюня" = "Streamer",
+ "Сестрюня" = "Streamer",
+ "Хост" = "Host",
+ "Ведущий Разработчик" = "HeadDeveloper",
+ "Старший Разработчик" = "Developer",
+ "Разработчик" = "Developer",
+ "Начальный Разработчик" = "MiniDeveloper",
+ "Бригадир Мапперов" = "HeadMapper",
+ "Маппер" = "Mapper",
+ "Спрайтер" = "Spriceter",
+ "Маленький Работяга" = "WikiLore",
+ "Старший Администратор" = "HeadAdmin",
+ "Администратор" = "GameAdmin",
+ "Триал Администратор" = "TrialAdmin",
+ "Ментор" = "Mentor"
+ )
+ return rank_badge_map[holder?.rank]
+
+/client/proc/get_badge_icon(badge)
+ if(isnull(badge))
+ return null
+
+ var/icon/badge_icon = LAZYACCESS(GLOB.badge_icons_cache, badge)
+ if(isnull(badge_icon))
+ badge_icon = icon(CHAT_BADGES_DMI, badge)
+ LAZYSET(GLOB.badge_icons_cache, badge, badge_icon)
+
+ return badge_icon
+
+#undef CHAT_BADGES_DMI
diff --git a/modular_ss220/chat_badges/icons/chatbadges.dmi b/modular_ss220/chat_badges/icons/chatbadges.dmi
new file mode 100644
index 000000000000..a49ca59811f5
Binary files /dev/null and b/modular_ss220/chat_badges/icons/chatbadges.dmi differ
diff --git a/modular_ss220/cinematics/_cinematics.dm b/modular_ss220/cinematics/_cinematics.dm
new file mode 100644
index 000000000000..ed8483ddad36
--- /dev/null
+++ b/modular_ss220/cinematics/_cinematics.dm
@@ -0,0 +1,4 @@
+/datum/modpack/cinematics
+ name = "Обновление системы Cinematics"
+ desc = "Обновление системы Cinematics, позволяя им работать в широкоформатном режиме"
+ author = "larentoun"
diff --git a/modular_ss220/cinematics/_cinematics.dme b/modular_ss220/cinematics/_cinematics.dme
new file mode 100644
index 000000000000..de676a447319
--- /dev/null
+++ b/modular_ss220/cinematics/_cinematics.dme
@@ -0,0 +1,13 @@
+#include "_cinematics.dm"
+
+#include "code/_defines.dm"
+#include "code/cinematics.dm"
+#include "code/cinematics_preferences.dm"
+#include "code/cinematics_client_proc.dm"
+#include "code/cinematics_screen.dm"
+#include "code/cinematics_ticker.dm"
+#include "code/cinematics/malf_doomsday.dm"
+#include "code/cinematics/narsie_summon.dm"
+#include "code/cinematics/nuke_cinematics.dm"
+#include "code/cinematics/credits.dm"
+#include "code/~undefs.dm"
diff --git a/modular_ss220/cinematics/code/_defines.dm b/modular_ss220/cinematics/code/_defines.dm
new file mode 100644
index 000000000000..b6e660b3675d
--- /dev/null
+++ b/modular_ss220/cinematics/code/_defines.dm
@@ -0,0 +1,5 @@
+#define COMSIG_GLOB_CINEMATIC_STOPPED_PLAYING "!cinematic_stopped_playing"
+#define COMSIG_CINEMATIC_WATCHER_LEAVES "cinematic_watcher_leaves"
+
+#define COMSIG_GLOB_PLAY_CINEMATIC "!play_cinematic"
+#define COMPONENT_GLOB_BLOCK_CINEMATIC (1<<0)
diff --git a/modular_ss220/cinematics/code/cinematics.dm b/modular_ss220/cinematics/code/cinematics.dm
new file mode 100644
index 000000000000..69dac505e424
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics.dm
@@ -0,0 +1,208 @@
+/**
+ * Plays a cinematic, duh. Can be to a select few people, or everyone.
+ *
+ * cinematic_type - datum typepath to what cinematic you wish to play.
+ * watchers - a list of all mobs you are playing the cinematic to. If world, the cinematical will play globally to all players.
+ * special_callback - optional callback to be invoked mid-cinematic.
+ */
+/proc/play_cinematic(datum/cinematic/cinematic_type, watchers, datum/callback/special_callback)
+ if(!ispath(cinematic_type, /datum/cinematic))
+ CRASH("play_cinematic called with a non-cinematic type. (Got: [cinematic_type])")
+ var/datum/cinematic/playing = new cinematic_type(watchers, special_callback)
+
+ if(watchers == world)
+ watchers = GLOB.mob_list
+
+ playing.start_cinematic(watchers)
+
+ return playing
+
+/// The cinematic screen showed to everyone
+/atom/movable/screen/cinematic
+ icon = 'icons/effects/station_explosion.dmi'
+ icon_state = "station_intact"
+ plane = SPLASHSCREEN_PLANE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ screen_loc = "BOTTOM,LEFT+50%"
+ appearance_flags = APPEARANCE_UI | TILE_BOUND
+
+/// Cinematic datum. Used to show an animation to everyone.
+/datum/cinematic
+ /// A list of all clients watching the cinematic
+ var/list/client/watching = list()
+ /// A list of all mobs who have notransform set while watching the cinematic
+ var/list/datum/locked = list()
+ // Whether the cinematic locks watchers or not
+ var/should_lock_watchers = TRUE
+ /// Whether the cinematic is a global cinematic or not
+ var/is_global = FALSE
+ /// Refernce to the cinematic screen shown to everyohne
+ var/atom/movable/screen/cinematic/screen
+ /// Callbacks passed that occur during the animation
+ var/datum/callback/special_callback
+ /// How long for the final screen remains shown
+ var/cleanup_time = 30 SECONDS
+ /// Whether the cinematic turns off ooc when played globally.
+ var/stop_ooc = TRUE
+ // screen type for cinematic backdrop
+ var/backdrop_type = /atom/movable/screen/fullscreen/cinematic_backdrop
+
+/datum/cinematic/New(watcher, datum/callback/special_callback)
+ screen = new(src)
+ if(watcher == world)
+ is_global = TRUE
+
+ src.special_callback = special_callback
+
+/datum/cinematic/Destroy()
+ QDEL_NULL(screen)
+ QDEL_NULL(special_callback)
+ watching.Cut()
+ locked.Cut()
+ return ..()
+
+/// Actually goes through the process of showing the cinematic to the list of watchers.
+/datum/cinematic/proc/start_cinematic(list/watchers)
+ if(SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PLAY_CINEMATIC, src) & COMPONENT_GLOB_BLOCK_CINEMATIC)
+ return
+
+ // Register a signal to handle what happens when a different cinematic tries to play over us.
+ RegisterSignal(SSdcs, COMSIG_GLOB_PLAY_CINEMATIC, PROC_REF(handle_replacement_cinematics))
+
+ // Pause OOC
+ var/ooc_toggled = FALSE
+ if(is_global && stop_ooc && GLOB.ooc_enabled)
+ ooc_toggled = TRUE
+ toggle_ooc()
+
+ // Place the /atom/movable/screen/cinematic into everyone's screens, and prevent movement.
+ for(var/mob/watching_mob in watchers)
+ show_to(watching_mob, watching_mob.client)
+ RegisterSignal(watching_mob, COMSIG_MOB_CLIENT_LOGIN, PROC_REF(show_to))
+ // Close watcher ui's, too, so they can watch it.
+ SStgui.close_user_uis(watching_mob)
+
+ // Actually plays the animation. This will sleep, likely.
+ play_cinematic()
+
+ // Cleans up after it's done playing.
+ addtimer(CALLBACK(src, PROC_REF(clean_up_cinematic), ooc_toggled), cleanup_time)
+
+/// Cleans up the cinematic after a set timer of it sticking on the end screen.
+/datum/cinematic/proc/clean_up_cinematic(was_ooc_toggled = FALSE)
+ if(was_ooc_toggled)
+ toggle_ooc(TRUE)
+
+ stop_cinematic()
+
+/// Whenever another cinematic starts to play over us, we have the chacne to block it.
+/datum/cinematic/proc/handle_replacement_cinematics(datum/source, datum/cinematic/other)
+ SIGNAL_HANDLER
+
+ // Stop our's and allow others to play if we're local and it's global
+ if(!is_global && other.is_global)
+ stop_cinematic()
+ return NONE
+
+ return COMPONENT_GLOB_BLOCK_CINEMATIC
+
+/datum/cinematic/proc/can_show(mob/watching_mob, client/watching_client)
+ // Only show the actual cinematic to cliented mobs.
+ if(!watching_client || (watching_client in watching))
+ return FALSE
+
+ return TRUE
+
+/// Whenever a mob watching the cinematic logs in, show them the ongoing cinematic
+/datum/cinematic/proc/show_to(mob/watching_mob, client/watching_client)
+ SIGNAL_HANDLER
+
+ // We could technically rip people out of notransform who shouldn't be,
+ // so we'll only lock down all viewing mobs who don't have it already set.
+ // This does potentially mean some mobs could lose their notrasnform and
+ // not be locked down by cinematics, but that should be very unlikely.
+ if(!watching_mob.notransform && should_lock_watchers)
+ lock_mob(watching_mob)
+
+ if(!can_show(watching_mob, watching_client))
+ return
+
+ watching += watching_client
+ watching_mob.overlay_fullscreen("cinematic", backdrop_type)
+ watching_client.screen += screen
+ add_verb(watching_client, /client/proc/cinematic_leave)
+
+ RegisterSignal(watching_client, list(COMSIG_PARENT_QDELETING, COMSIG_CINEMATIC_WATCHER_LEAVES), PROC_REF(remove_watcher))
+
+/// Simple helper for playing sounds from the cinematic.
+/datum/cinematic/proc/play_cinematic_sound(sound/sound_to_play)
+ sound_to_play.channel = CHANNEL_CINEMATIC
+ for(var/client/watching_client in watching)
+ sound_to_play.volume = 100 * watching_client.prefs.get_channel_volume(CHANNEL_CINEMATIC)
+ SEND_SOUND(watching_client, sound_to_play)
+
+/datum/cinematic/proc/stop_cinematic_sound()
+ if(is_global)
+ SEND_SOUND(world, sound(null, channel = CHANNEL_CINEMATIC))
+ else
+ for(var/client/watching_client in watching)
+ SEND_SOUND(watching_client, sound(null, channel = CHANNEL_CINEMATIC))
+
+
+/// Invoke any special callbacks for actual effects synchronized with animation.
+/// (Such as a real nuke explosion happening midway)
+/datum/cinematic/proc/invoke_special_callback()
+ special_callback?.Invoke()
+
+/// The actual cinematic occurs here.
+/datum/cinematic/proc/play_cinematic()
+ return
+
+/// Stops the cinematic and removes it from all the viewers.
+/datum/cinematic/proc/stop_cinematic()
+ stop_cinematic_sound()
+ for(var/client/viewing_client in watching)
+ remove_watcher(viewing_client)
+
+ for(var/datum/locked_ref in locked)
+ unlock_mob(locked_ref)
+
+ qdel(src)
+
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CINEMATIC_STOPPED_PLAYING, null)
+
+/// Locks a mob, preventing them from moving, being hurt, or acting
+/datum/cinematic/proc/lock_mob(mob/to_lock)
+ locked += to_lock
+ to_lock.notransform = TRUE
+
+/// Unlocks a previously locked ref
+/datum/cinematic/proc/unlock_mob(datum/mob_ref)
+ var/mob/locked_mob = mob_ref
+ if(isnull(locked_mob))
+ return
+ locked_mob.notransform = FALSE
+ UnregisterSignal(locked_mob, COMSIG_MOB_CLIENT_LOGIN)
+
+/// Removes the passed client from our watching list.
+/datum/cinematic/proc/remove_watcher(client/no_longer_watching)
+ SIGNAL_HANDLER
+
+ if(!(no_longer_watching in watching))
+ CRASH("cinematic remove_watcher was passed a client which wasn't watching.")
+
+ UnregisterSignal(no_longer_watching, list(COMSIG_PARENT_QDELETING, COMSIG_CINEMATIC_WATCHER_LEAVES))
+
+ if(no_longer_watching.mob)
+ unlock_mob(no_longer_watching.mob)
+ locked -= no_longer_watching.mob
+
+ // We'll clear the cinematic if they have a mob which has one,
+ // but we won't remove notransform. Wait for the cinematic end to do that.
+ SEND_SOUND(no_longer_watching, sound(null, channel = CHANNEL_CINEMATIC))
+
+ no_longer_watching.mob?.clear_fullscreen("cinematic")
+ no_longer_watching.screen -= screen
+
+ no_longer_watching.verbs -= /client/proc/cinematic_leave
+ watching -= no_longer_watching
diff --git a/modular_ss220/cinematics/code/cinematics/credits.dm b/modular_ss220/cinematics/code/cinematics/credits.dm
new file mode 100644
index 000000000000..6f34161d225d
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics/credits.dm
@@ -0,0 +1,88 @@
+/datum/cinematic/credits
+ is_global = TRUE
+ should_lock_watchers = FALSE
+ stop_ooc = FALSE
+ backdrop_type = /atom/movable/screen/fullscreen/cinematic_backdrop/credits
+
+/datum/cinematic/credits/New(watcher, datum/callback/special_callback)
+ . = ..()
+ screen = new /atom/movable/screen/cinematic/credits(src)
+
+/datum/cinematic/credits/can_show(mob/watching_mob, client/watching_client)
+ // Do not show credits if it's disabled for the client and not forced.
+ return ..() && (GLOB.credits_forced || (watching_client.prefs.toggles220 & PREFTOGGLE_220_WATCH_CREDITS))
+
+/datum/cinematic/credits/start_cinematic(list/watchers)
+ if(!(SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PLAY_CINEMATIC, src) & COMPONENT_GLOB_BLOCK_CINEMATIC))
+ . = ..()
+ RegisterSignal(SSdcs, COMSIG_GLOB_CINEMATIC_STOPPED_PLAYING, PROC_REF(queue_gone))
+ for(var/mob/watching_mob in watchers)
+ if(watching_mob.client)
+ watching += watching_mob
+
+/datum/cinematic/credits/proc/queue_gone(datum/source, datum/cinematic/other)
+ SIGNAL_HANDLER
+ UnregisterSignal(SSdcs, COMSIG_GLOB_CINEMATIC_STOPPED_PLAYING)
+ start_cinematic(src.watching)
+
+/datum/cinematic/credits/play_cinematic()
+
+ SScredits.roll_credits_for_clients(watching)
+
+ play_cinematic_sound(sound(SScredits.end_titles.soundtrack))
+
+ cleanup_time = SScredits.end_titles.playing_time + 3 SECONDS
+
+ special_callback?.Invoke()
+
+/datum/cinematic/credits/stop_cinematic()
+ for(var/client/client in watching)
+ SScredits.clear_credits(client)
+
+ UnregisterSignal(SSdcs, COMSIG_GLOB_CINEMATIC_STOPPED_PLAYING)
+
+ . = ..()
+
+/datum/cinematic/credits/remove_watcher(client/no_longer_watching)
+ . = ..()
+
+ SScredits.clear_credits(no_longer_watching)
+
+/datum/cinematic/credits/halloween
+
+/datum/cinematic/credits/halloween/New(watcher, datum/callback/special_callback)
+ . = ..()
+
+ screen = new /atom/movable/screen/cinematic/credits/halloween()
+
+/datum/cinematic/credits/new_year
+
+/datum/cinematic/credits/new_year/New(watcher, datum/callback/special_callback)
+ . = ..()
+
+ screen = new /atom/movable/screen/cinematic/credits/new_year()
+
+/atom/movable/screen/cinematic/credits
+ icon_state = "blank"
+ alpha = 0
+
+/atom/movable/screen/cinematic/credits/Initialize(mapload)
+ . = ..()
+
+ animate(src, alpha = 120, time = 3 SECONDS)
+
+/atom/movable/screen/cinematic/credits/halloween
+ icon = 'modular_ss220/cinematics/icons/backdrops.dmi'
+ icon_state = "halloween"
+
+/atom/movable/screen/cinematic/credits/new_year
+ icon = 'modular_ss220/cinematics/icons/backdrops.dmi'
+ icon_state = "new_year"
+
+/atom/movable/screen/fullscreen/cinematic_backdrop/credits
+ alpha = 0
+
+/atom/movable/screen/fullscreen/cinematic_backdrop/credits/Initialize(mapload)
+ . = ..()
+
+ animate(src, alpha = 220, time = 3 SECONDS)
diff --git a/modular_ss220/cinematics/code/cinematics/malf_doomsday.dm b/modular_ss220/cinematics/code/cinematics/malf_doomsday.dm
new file mode 100644
index 000000000000..2eb330d9a484
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics/malf_doomsday.dm
@@ -0,0 +1,10 @@
+/// A malfunctioning AI has activated the doomsday device and wiped the station!
+/datum/cinematic/malf
+
+/datum/cinematic/malf/play_cinematic()
+ flick("intro_malf", screen)
+ stoplag(7.6 SECONDS)
+ flick("station_explode_fade_red", screen)
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special_callback?.Invoke()
+ screen.icon_state = "summary_malf"
diff --git a/modular_ss220/cinematics/code/cinematics/narsie_summon.dm b/modular_ss220/cinematics/code/cinematics/narsie_summon.dm
new file mode 100644
index 000000000000..2ff7b3d0e27d
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics/narsie_summon.dm
@@ -0,0 +1,29 @@
+/// A blood cult summoned Nar'sie, and most of the station was harvested or converted!
+/datum/cinematic/cult_arm // Colloquially known as "the arm"
+
+/datum/cinematic/cult_arm/play_cinematic()
+ screen.icon_state = null
+ flick("intro_cult", screen)
+ stoplag(2.5 SECONDS)
+ play_cinematic_sound(sound('sound/misc/enter_blood.ogg'))
+ stoplag(2.8 SECONDS)
+ play_cinematic_sound(sound('sound/machines/terminal_off.ogg'))
+ stoplag(2 SECONDS)
+ flick("station_corrupted", screen)
+ play_cinematic_sound(sound('sound/effects/ghost.ogg'))
+ stoplag(7 SECONDS)
+ special_callback?.Invoke()
+
+/// A blood cult summoned Nar'sie, but some badass (or admin) managed to destroy Nar'sie themselves.
+/datum/cinematic/cult_fail
+
+/datum/cinematic/cult_fail/play_cinematic()
+ screen.icon_state = "station_intact"
+ stoplag(2 SECONDS)
+ play_cinematic_sound(sound('sound/creatures/narsie_rises.ogg'))
+ stoplag(6 SECONDS)
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ stoplag(1 SECONDS)
+ play_cinematic_sound(sound('sound/misc/demon_dies.ogg'))
+ stoplag(3 SECONDS)
+ special_callback?.Invoke()
diff --git a/modular_ss220/cinematics/code/cinematics/nuke_cinematics.dm b/modular_ss220/cinematics/code/cinematics/nuke_cinematics.dm
new file mode 100644
index 000000000000..dd827f7c0b9f
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics/nuke_cinematics.dm
@@ -0,0 +1,100 @@
+/// Simple, base cinematic for all animations based around a nuke detonating.
+/datum/cinematic/nuke
+ /// If set, this is the summary screen that pops up after the nuke is done.
+ var/after_nuke_summary_state
+
+/datum/cinematic/nuke/play_cinematic()
+ flick("intro_nuke", screen)
+ stoplag(3.5 SECONDS)
+ play_nuke_effect()
+ if(special_callback)
+ special_callback.Invoke()
+ if(after_nuke_summary_state)
+ screen.icon_state = after_nuke_summary_state
+
+/// Specific effects for each type of cinematics goes here.
+/datum/cinematic/nuke/proc/play_nuke_effect()
+ return
+
+/// The syndicate nuclear bomb was activated, and destroyed the station!
+/datum/cinematic/nuke/ops_victory
+ after_nuke_summary_state = "summary_nukewin"
+
+/datum/cinematic/nuke/ops_victory/play_nuke_effect()
+ flick("station_explode_fade_red", screen)
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+
+/// The syndicate nuclear bomb was activated, but just barely missed the station!
+/datum/cinematic/nuke/ops_miss
+ after_nuke_summary_state = "summary_nukefail"
+
+/datum/cinematic/nuke/ops_miss/play_nuke_effect()
+ flick("station_intact_fade_red", screen)
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+
+/// The self destruct, or another station-destroying entity like a blob, destroyed the station!
+/datum/cinematic/nuke/self_destruct
+ after_nuke_summary_state = "summary_selfdes"
+
+/datum/cinematic/nuke/self_destruct/play_nuke_effect()
+ flick("station_explode_fade_red", screen)
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+
+/// The self destruct was activated, yet somehow avoided destroying the station!
+/datum/cinematic/nuke/self_destruct_miss
+ after_nuke_summary_state = "station_intact"
+
+/datum/cinematic/nuke/self_destruct_miss/play_nuke_effect()
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special_callback?.Invoke()
+
+/// The syndicate nuclear bomb was activated, and the nuclear operatives failed to extract on their shuttle before it detonated on the station!
+/datum/cinematic/nuke/mutual_destruction
+ after_nuke_summary_state = "summary_totala"
+
+/datum/cinematic/nuke/mutual_destruction/play_nuke_effect()
+ flick("station_explode_fade_red", screen)
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+
+/// A blood cult summoned Nar'sie, but central command deployed a nuclear package to stop them.
+/datum/cinematic/nuke/cult
+ after_nuke_summary_state = "summary_cult"
+
+/datum/cinematic/nuke/cult/play_nuke_effect()
+ flick("station_explode_fade_red", screen)
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+
+/// A fake version of the nuclear detonation, where it winds up, but doesn't explode.
+/datum/cinematic/nuke/fake
+ cleanup_time = 10 SECONDS
+
+/datum/cinematic/nuke/fake/play_nuke_effect()
+ play_cinematic_sound(sound('sound/items/bikehorn.ogg'))
+ flick("summary_selfdes", screen) //???
+
+/// The clown operative nuclear bomb was activated and clowned the station!
+/datum/cinematic/nuke/clown
+ cleanup_time = 10 SECONDS
+
+/datum/cinematic/nuke/clown/play_nuke_effect()
+ play_cinematic_sound(sound('sound/items/airhorn.ogg'))
+ flick("summary_selfdes", screen) //???
+
+/// A fake version of the nuclear detonation, where it winds up, but doesn't explode as the nuke core within was missing.
+/datum/cinematic/nuke/no_core
+ cleanup_time = 10 SECONDS
+
+/datum/cinematic/nuke/no_core/play_nuke_effect()
+ flick("station_intact", screen)
+ play_cinematic_sound(sound('sound/ambience/signal.ogg'))
+ stoplag(10 SECONDS)
+
+/// The syndicate nuclear bomb was activated, but just missed the station by a whole z-level!
+/datum/cinematic/nuke/far_explosion
+ cleanup_time = 0 SECONDS
+
+/datum/cinematic/nuke/far_explosion/play_cinematic()
+ // This one has no intro sequence.
+ // It's actually just a global sound, which makes you wonder why it's a cinematic.
+ play_cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special_callback?.Invoke()
diff --git a/modular_ss220/cinematics/code/cinematics_client_proc.dm b/modular_ss220/cinematics/code/cinematics_client_proc.dm
new file mode 100644
index 000000000000..e045517f8776
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics_client_proc.dm
@@ -0,0 +1,28 @@
+/client/proc/cinematic_new()
+ set name = "Cinematic (NEW)"
+ set category = "Event"
+ set desc = "Shows a cinematic." // Intended for testing but I thought it might be nice for events on the rare occasion Feel free to comment it out if it's not wanted.
+ set hidden = TRUE
+
+ if(!SSticker)
+ return
+ if(!check_rights(R_MAINTAINER))
+ return
+
+ var/datum/cinematic/choice = input(usr, "Choose a cinematic to play to everyone in the server.", "Choose Cinematic") in sortTim(subtypesof(/datum/cinematic), GLOBAL_PROC_REF(cmp_typepaths_asc))
+ if(!choice || !ispath(choice, /datum/cinematic))
+ return
+
+ play_cinematic(choice, world)
+
+/client/proc/cinematic_leave()
+ set name = "Прекратить смотреть синематик"
+ set category = "OOC"
+ set desc = "Отключить проигрывание синематика."
+
+ verbs -= /client/proc/cinematic_leave
+
+ if(!mob.screens["cinematic"])
+ return
+
+ SEND_SIGNAL(src, COMSIG_CINEMATIC_WATCHER_LEAVES)
diff --git a/modular_ss220/cinematics/code/cinematics_preferences.dm b/modular_ss220/cinematics/code/cinematics_preferences.dm
new file mode 100644
index 000000000000..28c6fd27f305
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics_preferences.dm
@@ -0,0 +1,3 @@
+/datum/preferences/New(client/C, datum/db_query/Q)
+ . = ..()
+ volume_mixer |= (list("[CHANNEL_CINEMATIC]" = 50,))
diff --git a/modular_ss220/cinematics/code/cinematics_screen.dm b/modular_ss220/cinematics/code/cinematics_screen.dm
new file mode 100644
index 000000000000..77df18d85b61
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics_screen.dm
@@ -0,0 +1,8 @@
+/atom/movable/screen/fullscreen/cinematic_backdrop
+ icon = 'icons/mob/screen_gen.dmi'
+ screen_loc = "WEST,SOUTH to EAST,NORTH"
+ icon_state = "flash"
+ plane = SPLASHSCREEN_PLANE
+ layer = CINEMATIC_LAYER
+ color = "#000000"
+ show_when_dead = TRUE
diff --git a/modular_ss220/cinematics/code/cinematics_ticker.dm b/modular_ss220/cinematics/code/cinematics_ticker.dm
new file mode 100644
index 000000000000..b4ca5f25ab21
--- /dev/null
+++ b/modular_ss220/cinematics/code/cinematics_ticker.dm
@@ -0,0 +1,43 @@
+/datum/controller/subsystem/ticker/station_explosion_cinematic(nuke_site, override)
+ auto_toggle_ooc(TRUE) // Turn it on
+ if(nuke_site == NUKE_SITE_ON_STATION)
+ // Kill everyone on z-level 1 except for mobs in freezers and
+ // malfunctioning AIs.
+ for(var/mob/M in GLOB.mob_list)
+ if(M.stat != DEAD)
+ var/turf/T = get_turf(M)
+ if(T && is_station_level(T.z) && !istype(M.loc, /obj/structure/closet/secure_closet/freezer) && !(issilicon(M) && override == "AI malfunction"))
+ to_chat(M, span_danger("The blast wave from the explosion tears you atom from atom!"))
+ M.ghostize()
+ M.dust() // No mercy
+ CHECK_TICK
+
+ switch(nuke_site)
+ // Now animate the cinematic
+ if(NUKE_SITE_ON_STATION)
+ // Station was destroyed
+ if(mode && !override)
+ override = mode.name
+ switch(override)
+ if("nuclear emergency") // Nuke Ops successfully bombed the station
+ play_cinematic(/datum/cinematic/nuke/ops_victory, world)
+ if("AI malfunction") // Malf (screen,explosion,summary)
+ play_cinematic(/datum/cinematic/malf, world)
+ else //Station nuked (nuke,explosion,summary)
+ play_cinematic(/datum/cinematic/nuke/self_destruct, world)
+ if(NUKE_SITE_ON_STATION_ZLEVEL)
+ // Nuke was nearby but (mostly) missed
+ if(mode && !override)
+ override = mode.name
+ switch(override)
+ if("nuclear emergency") // Nuke wasn't on station when it blew up
+ play_cinematic(/datum/cinematic/nuke/ops_miss, world)
+ if("fake") // The round isn't over, we're just freaking people out for fun
+ play_cinematic(/datum/cinematic/nuke/fake, world)
+ else
+ play_cinematic(/datum/cinematic/nuke/self_destruct_miss, world)
+ if(NUKE_SITE_OFF_STATION_ZLEVEL, NUKE_SITE_INVALID)
+ // Nuke was nowhere nearby
+ // TODO: a really distant explosion animation
+ play_cinematic(/datum/cinematic/nuke/far_explosion, world)
+
diff --git a/modular_ss220/cinematics/code/~undefs.dm b/modular_ss220/cinematics/code/~undefs.dm
new file mode 100644
index 000000000000..91eeeee85824
--- /dev/null
+++ b/modular_ss220/cinematics/code/~undefs.dm
@@ -0,0 +1,5 @@
+#undef COMSIG_GLOB_CINEMATIC_STOPPED_PLAYING
+#undef COMSIG_CINEMATIC_WATCHER_LEAVES
+
+#undef COMSIG_GLOB_PLAY_CINEMATIC
+#undef COMPONENT_GLOB_BLOCK_CINEMATIC
diff --git a/modular_ss220/cinematics/icons/LICENSE.MD b/modular_ss220/cinematics/icons/LICENSE.MD
new file mode 100644
index 000000000000..82d18486ab4e
--- /dev/null
+++ b/modular_ss220/cinematics/icons/LICENSE.MD
@@ -0,0 +1,5 @@
+#####################################################################################################################################################################
+pumpkin screen image by Yuri_b from https://pixabay.com/illustrations/halloween-pumpkin-dark-background-1702677/ under https://pixabay.com/service/license-summary/
+#####################################################################################################################################################################
+red christmas background by monicore from https://pixabay.com/illustrations/red-christmas-tree-christmas-2892235/ under https://pixabay.com/service/license-summary/
+#####################################################################################################################################################################
diff --git a/modular_ss220/cinematics/icons/backdrops.dmi b/modular_ss220/cinematics/icons/backdrops.dmi
new file mode 100644
index 000000000000..3d9155641767
Binary files /dev/null and b/modular_ss220/cinematics/icons/backdrops.dmi differ
diff --git a/modular_ss220/closet_picklocking/_closet_picklocking.dm b/modular_ss220/closet_picklocking/_closet_picklocking.dm
new file mode 100644
index 000000000000..271510187c3b
--- /dev/null
+++ b/modular_ss220/closet_picklocking/_closet_picklocking.dm
@@ -0,0 +1,4 @@
+/datum/modpack/closet_picklocking
+ name = "Взлом шкафчиков"
+ desc = "Добавляет взлом шкафчиков."
+ author = "dj-34, RV666"
diff --git a/modular_ss220/closet_picklocking/_closet_picklocking.dme b/modular_ss220/closet_picklocking/_closet_picklocking.dme
new file mode 100644
index 000000000000..9af552e49663
--- /dev/null
+++ b/modular_ss220/closet_picklocking/_closet_picklocking.dme
@@ -0,0 +1,3 @@
+#include "_closet_picklocking.dm"
+
+#include "code/closet_picklocking.dm"
diff --git a/modular_ss220/closet_picklocking/code/closet_picklocking.dm b/modular_ss220/closet_picklocking/code/closet_picklocking.dm
new file mode 100644
index 000000000000..e3215d02156a
--- /dev/null
+++ b/modular_ss220/closet_picklocking/code/closet_picklocking.dm
@@ -0,0 +1,120 @@
+#define PANEL_OPEN 0
+#define WIRES_DISCONNECTED 1
+#define LOCK_OFF 2
+
+/obj/structure/closet
+ var/picklocking_stage
+
+/obj/structure/closet/examine(mob/user)
+ . = ..()
+ switch(picklocking_stage)
+ if(PANEL_OPEN)
+ . += span_notice("Панель управления снята.")
+ if(WIRES_DISCONNECTED)
+ . += span_notice("Панель управления снята.")
+ . += span_notice("Провода отключены и торчат наружу.")
+ if(LOCK_OFF)
+ . += span_notice("Панель управления снята.")
+ . += span_notice("Провода отключены и торчат наружу.")
+ . += span_notice("Замок отключён.")
+
+/* Secure closets */
+/obj/structure/closet/secure_closet/screwdriver_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(locked && picklocking_stage == null && user.a_intent != INTENT_HARM) // Stage one
+ to_chat(user, span_notice("Вы начинаете откручивать панель замка [src]..."))
+ if(I.use_tool(src, user, 16 SECONDS, volume = I.tool_volume))
+ if(prob(95)) // EZ
+ broken = TRUE
+ picklocking_stage = PANEL_OPEN
+ update_icon()
+ to_chat(user, span_notice("Вы успешно открутили и сняли панель с замка [src]!"))
+ else // Bad day
+ var/mob/living/carbon/human/H = user
+ var/obj/item/organ/external/affecting = H.get_organ(user.r_hand == I ? "l_hand" : "r_hand")
+ user.apply_damage(I.force, BRUTE , affecting)
+ user.emote("scream")
+ to_chat(user, span_warning("Проклятье! [I] сорвалась и повредила [affecting.name]!"))
+ return TRUE
+
+/obj/structure/closet/secure_closet/wirecutter_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(locked && picklocking_stage == PANEL_OPEN && user.a_intent != INTENT_HARM) // Stage two
+ to_chat(user, span_notice("Вы начинаете подготавливать провода панели [src]..."))
+ if(I.use_tool(src, user, 16 SECONDS, volume = I.tool_volume))
+ if(prob(80)) // Good hacker!
+ to_chat(user, span_notice("Вы успешно подготовили провода панели замка [src]!"))
+ picklocking_stage = WIRES_DISCONNECTED
+ else // Bad day
+ to_chat(user, span_warning("Черт! Не тот провод!"))
+ do_sparks(5, TRUE, src)
+ electrocute_mob(user, get_area(src), src, 0.5, TRUE)
+ return TRUE
+
+/obj/structure/closet/secure_closet/multitool_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(locked && picklocking_stage == WIRES_DISCONNECTED && user.a_intent != INTENT_HARM) // Stage three
+ to_chat(user, span_notice("Вы начинаете подключать провода панели замка [src] к [I]..."))
+ if(I.use_tool(src, user, 16 SECONDS, volume = I.tool_volume))
+ if(prob(80)) // Good hacker!
+ broken = FALSE // Can be emagged
+ picklocking_stage = LOCK_OFF
+ emag_act(user)
+ else // Bad day
+ to_chat(user, span_warning("Черт! Не тот провод!"))
+ do_sparks(5, TRUE, src)
+ electrocute_mob(user, get_area(src), src, 0.5, TRUE)
+ return TRUE
+
+/* Crates */
+/obj/structure/closet/crate/secure/screwdriver_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(locked && picklocking_stage == null && user.a_intent != INTENT_HARM) // Stage one
+ to_chat(user, span_notice("Вы начинаете откручивать панель замка [src]..."))
+ if(I.use_tool(src, user, 16 SECONDS, volume = I.tool_volume))
+ if(prob(95)) // EZ
+ broken = TRUE
+ picklocking_stage = PANEL_OPEN
+ update_icon()
+ to_chat(user, span_notice("Вы успешно открутили и сняли панель с замка [src]!"))
+ //icon_state = icon_off // Crates has no icon_off :(
+ else // Bad day)
+ var/mob/living/carbon/human/H = user
+ var/obj/item/organ/external/affecting = H.get_organ(user.r_hand == I ? "l_hand" : "r_hand")
+ user.apply_damage(I.force, BRUTE , affecting)
+ user.emote("scream")
+ to_chat(user, span_warning("Проклятье! [I] сорвалась и повредила [affecting.name]!"))
+ return TRUE
+
+/obj/structure/closet/crate/secure/wirecutter_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(locked && picklocking_stage == PANEL_OPEN && user.a_intent != INTENT_HARM) // Stage two
+ to_chat(user, span_notice("Вы начинаете подготавливать провода панели [src]..."))
+ if(I.use_tool(src, user, 16 SECONDS, volume = I.tool_volume))
+ if(prob(80)) // Good hacker!
+ to_chat(user, span_notice("Вы успешно подготовили провода панели замка [src]!"))
+ picklocking_stage = WIRES_DISCONNECTED
+ else // Bad day
+ to_chat(user, span_warning("Черт! Не тот провод!"))
+ do_sparks(5, TRUE, src)
+ electrocute_mob(user, get_area(src), src, 0.5, TRUE)
+ return TRUE
+
+/obj/structure/closet/crate/secure/multitool_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(locked && picklocking_stage == WIRES_DISCONNECTED && user.a_intent != INTENT_HARM) // Stage three
+ to_chat(user, span_notice("Вы начинаете подключать провода панели замка [src] к [I]..."))
+ if(I.use_tool(src, user, 16 SECONDS, volume = I.tool_volume))
+ if(prob(80)) // Good hacker!
+ broken = FALSE // Can be emagged
+ picklocking_stage = LOCK_OFF
+ emag_act(user)
+ else // Bad day
+ to_chat(user, span_warning("Черт! Не тот провод!"))
+ do_sparks(5, TRUE, src)
+ electrocute_mob(user, get_area(src), src, 0.5, TRUE)
+ return TRUE
+
+#undef PANEL_OPEN
+#undef WIRES_DISCONNECTED
+#undef LOCK_OFF
diff --git a/modular_ss220/clothing/_clothing.dm b/modular_ss220/clothing/_clothing.dm
new file mode 100644
index 000000000000..e8581715c24f
--- /dev/null
+++ b/modular_ss220/clothing/_clothing.dm
@@ -0,0 +1,10 @@
+/datum/modpack/clothing
+ name = "Одежда"
+ desc = "Всё для модного приговора."
+ author = "Aylong, Yata9arasu, Dekupich"
+
+/datum/modpack/clothing/initialize()
+ . = ..()
+ GLOB.cloth_recipes += list(
+ new /datum/stack_recipe("полотенце", /obj/item/clothing/under/towel/long, 4, time = 1 SECONDS)
+ )
diff --git a/modular_ss220/clothing/_clothing.dme b/modular_ss220/clothing/_clothing.dme
new file mode 100644
index 000000000000..a70b69054c10
--- /dev/null
+++ b/modular_ss220/clothing/_clothing.dme
@@ -0,0 +1,14 @@
+#include "_clothing.dm"
+#include "code/accessories.dm"
+#include "code/cloaks.dm"
+#include "code/clothing_vendors.dm"
+#include "code/garment_bag.dm"
+#include "code/gloves.dm"
+#include "code/hats.dm"
+#include "code/helmet.dm"
+#include "code/hev_suit.dm"
+#include "code/mask.dm"
+#include "code/shoes.dm"
+#include "code/suits.dm"
+#include "code/under.dm"
+#include "code/mod.dm"
diff --git a/modular_ss220/clothing/code/accessories.dm b/modular_ss220/clothing/code/accessories.dm
new file mode 100644
index 000000000000..9691be242ab1
--- /dev/null
+++ b/modular_ss220/clothing/code/accessories.dm
@@ -0,0 +1,33 @@
+/obj/item/storage/belt/chef/apron
+ name = "фартук"
+ desc = "Фартук с широкими карманами. Такому обзавидуется любой мясник."
+ icon = 'modular_ss220/clothing/icons/object/accessories.dmi'
+ icon_state = "apron"
+ item_state = "apron"
+ sprite_sheets = list(
+ "Abductor" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Ancient Skeleton" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/accessories.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/accessories.dmi',
+ "Human" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Monkey" = 'modular_ss220/clothing/icons/mob/species/monkey/accessories.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Plasmaman" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/accessories.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/accessories.dmi',
+ )
+
+/obj/item/storage/belt/chef/apron/red
+ name = "красный фартук"
+ icon_state = "apron_red"
+ item_state = "apron_red"
diff --git a/modular_ss220/clothing/code/cloaks.dm b/modular_ss220/clothing/code/cloaks.dm
new file mode 100644
index 000000000000..00a8afca9355
--- /dev/null
+++ b/modular_ss220/clothing/code/cloaks.dm
@@ -0,0 +1,67 @@
+/obj/item/clothing/suit/mantle/armor/captain/black
+ name = "чёрная капитанская мантия"
+ desc = "Носится верховным лидером станции NSS Cyberiad."
+ icon = 'modular_ss220/clothing/icons/object/cloaks.dmi'
+ icon_state = "capcloak_black"
+ icon_override = 'modular_ss220/clothing/icons/mob/cloaks.dmi'
+ item_state = "capcloak_black"
+
+/obj/item/clothing/suit/mantle/armor/captain/black/Initialize(mapload)
+ . = ..()
+ desc = "Носится верховным лидером станции [station_name()]."
+
+/* EI cloak */
+/obj/item/clothing/suit/hooded/ei_cloak
+ name = "плащ Gold On Black"
+ desc = "Корпоративный плащ, выполненный в угольных тонах все с тем же золотым покрытием и специальным логотипом от Etamin Industry – золотой звездой."
+ icon = 'modular_ss220/clothing/icons/object/cloaks.dmi'
+ icon_state = "ei_cloak"
+ sprite_sheets = list(
+ "Human" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/species/kidan/cloaks.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Skeleton" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/cloaks.dmi',
+ "Abductor" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/cloaks.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/cloaks.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/cloaks.dmi',
+ )
+ hoodtype = /obj/item/clothing/head/hooded/ei_hood
+
+/obj/item/clothing/head/hooded/ei_hood
+ name = "капюшон Gold On Black"
+ desc = "Капюшон, прикрепленный к плащу Gold On Black."
+ icon = 'modular_ss220/clothing/icons/object/hats.dmi'
+ icon_state = "ei_hood"
+ sprite_sheets = list(
+ "Human" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/species/tajaran/hats.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/species/vulpkanin/hats.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/species/kidan/hats.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Skeleton" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/hats.dmi',
+ "Abductor" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/hats.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/hats.dmi',
+ )
+ flags = BLOCKHAIR
+ flags_inv = HIDEEARS
diff --git a/modular_ss220/clothing/code/clothing_vendors.dm b/modular_ss220/clothing/code/clothing_vendors.dm
new file mode 100644
index 000000000000..fc2c06a42e5f
--- /dev/null
+++ b/modular_ss220/clothing/code/clothing_vendors.dm
@@ -0,0 +1,29 @@
+/obj/machinery/economy/vending/autodrobe/Initialize(mapload)
+ products += list(
+ /obj/item/clothing/head/ratge = 1,
+ )
+ contraband += list(
+ /obj/item/clothing/mask/rooster = 1,
+ )
+ prices += list(
+ /obj/item/clothing/head/ratge = 75,
+ /obj/item/clothing/mask/rooster = 100,
+ )
+ . = ..()
+
+/obj/machinery/economy/vending/chefdrobe/Initialize(mapload)
+ products += list(
+ /obj/item/clothing/under/rank/civilian/chef/red = 2,
+ /obj/item/clothing/suit/chef/red = 2,
+ /obj/item/clothing/head/chefhat/red = 2,
+ /obj/item/storage/belt/chef/apron = 1,
+ /obj/item/storage/belt/chef/apron/red = 1,
+ )
+ prices += list(
+ /obj/item/clothing/under/rank/civilian/chef/red = 50,
+ /obj/item/clothing/suit/chef/red = 50,
+ /obj/item/clothing/head/chefhat/red = 50,
+ /obj/item/storage/belt/chef/apron = 75,
+ /obj/item/storage/belt/chef/apron/red = 75,
+ )
+ . = ..()
diff --git a/modular_ss220/clothing/code/garment_bag.dm b/modular_ss220/clothing/code/garment_bag.dm
new file mode 100644
index 000000000000..461b6d20af61
--- /dev/null
+++ b/modular_ss220/clothing/code/garment_bag.dm
@@ -0,0 +1,8 @@
+/obj/item/storage/bag/garment/captain/populate_contents()
+ . = ..()
+ new /obj/item/clothing/head/caphat/beret_black(src)
+ new /obj/item/clothing/suit/mantle/armor/captain/black(src)
+
+/obj/item/storage/bag/garment/head_of_security/populate_contents()
+ . = ..()
+ new /obj/item/clothing/gloves/combat(src)
diff --git a/modular_ss220/clothing/code/gloves.dm b/modular_ss220/clothing/code/gloves.dm
new file mode 100644
index 000000000000..4ffc9b00fcbe
--- /dev/null
+++ b/modular_ss220/clothing/code/gloves.dm
@@ -0,0 +1,33 @@
+/obj/item/clothing/gloves/fingerless/biker_gloves
+ name = "байкерские перчатки"
+ desc = "Обычные черные перчатки с черепом."
+ icon = 'modular_ss220/clothing/icons/object/gloves.dmi'
+ icon_state = "bike_gloves"
+ icon_override = 'modular_ss220/clothing/icons/mob/hands.dmi'
+
+/* EI gloves */
+/obj/item/clothing/gloves/color/ei_gloves
+ name = "перчатки Gold On Black"
+ desc = "Качественные перчатки с золотой вставкой 999 пробы."
+ icon = 'modular_ss220/clothing/icons/object/gloves.dmi'
+ icon_state = "ei_gloves"
+ sprite_sheets = list(
+ "Human" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/species/kidan/gloves.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Skeleton" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/gloves.dmi',
+ "Abductor" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/hands.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/gloves.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/gloves.dmi',
+ )
diff --git a/modular_ss220/clothing/code/hats.dm b/modular_ss220/clothing/code/hats.dm
new file mode 100644
index 000000000000..6358041f9db8
--- /dev/null
+++ b/modular_ss220/clothing/code/hats.dm
@@ -0,0 +1,141 @@
+/obj/item/clothing/head/caphat/beret_black
+ name = "чёрный капитанский берет"
+ desc = "Хорошо быть королём."
+ icon = 'modular_ss220/clothing/icons/object/hats.dmi'
+ icon_state = "cap_beret_black"
+ icon_override = 'modular_ss220/clothing/icons/mob/hats.dmi'
+
+/obj/item/clothing/head/ratge
+ name = "ratge head"
+ desc = "Ну ты и крыса!"
+ icon = 'modular_ss220/clothing/icons/object/hats.dmi'
+ icon_state = "ratgehead"
+ lefthand_file = 'modular_ss220/clothing/icons/inhands/left_hand.dmi'
+ righthand_file = 'modular_ss220/clothing/icons/inhands/right_hand.dmi'
+ flags = BLOCKHAIR
+ flags_inv = HIDEMASK | HIDEEARS | HIDEEYES | HIDEFACE
+ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
+ sprite_sheets = list(
+ "Abductor" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Ancient Skeleton" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/hats.dmi',
+ "Human" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/species/kidan/hats.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Monkey" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Plasmaman" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/species/tajaran/hats.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/species/vulpkanin/hats.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ )
+
+/obj/item/clothing/head/chefhat/red
+ name = "chef's red hat"
+ desc = "Красный поварской колпак, для тех, кто хочет показать что он тут настоящий босс кухни."
+ icon = 'modular_ss220/clothing/icons/object/hats.dmi'
+ icon_state = "chef_red"
+ sprite_sheets = list(
+ "Abductor" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Ancient Skeleton" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/hats.dmi',
+ "Human" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Monkey" = 'modular_ss220/clothing/icons/mob/species/monkey/hats.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Plasmaman" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/hats.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ )
+
+/obj/item/clothing/head/towel
+ name = "шапка из полотенца"
+ desc = "Полотенце замотанное в импровизированную шапку. Можно надеть на голову."
+ icon = 'modular_ss220/clothing/icons/object/hats.dmi'
+ icon_state = "towel_head"
+ item_color = "towel_head"
+ sprite_sheets = list(
+ "Abductor" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Ancient Skeleton" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/hats.dmi',
+ "Human" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Monkey" = 'modular_ss220/clothing/icons/mob/species/monkey/hats.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Plasmaman" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/hats.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ )
+
+/obj/item/clothing/head/towel/attackby__legacy__attackchain(obj/item/S, mob/user, params)
+ . = ..()
+ if(istype(S, /obj/item/toy/crayon/spraycan))
+ var/obj/item/toy/crayon/spraycan/spcan = S
+ var/list/hsl = rgb2hsl(hex2num(copytext(spcan.colour, 2, 4)), hex2num(copytext(spcan.colour, 4, 6)), hex2num(copytext(spcan.colour, 6, 8)))
+ hsl[3] = max(hsl[3], 0.4)
+ var/list/rgb = hsl2rgb(arglist(hsl))
+ var/new_color = "#[num2hex(rgb[1], 2)][num2hex(rgb[2], 2)][num2hex(rgb[3], 2)]"
+ color = new_color
+ to_chat(user, "Вы перекрашиваете [src.name].")
+ return
+
+/obj/item/clothing/head/towel/red
+ name = "красная шапочка из полотенца"
+ color = "#EE204D"
+
+/obj/item/clothing/head/towel/green
+ name = "зелёная шапочка из полотенца"
+ color = "#32CD32"
+
+/obj/item/clothing/head/towel/blue
+ name = "синяя шапочка из полотенца"
+ color = "#1E90FF"
+
+/obj/item/clothing/head/towel/orange
+ name = "оранжевая шапочка из полотенца"
+ color = "#FFA500"
+
+/obj/item/clothing/head/towel/purple
+ name = "фиолетовая шапочка из полотенца"
+ color = "#DA70D6"
+
+/obj/item/clothing/head/towel/cyan
+ name = "голубая шапочка из полотенца"
+ color = "#40E0D0"
+
+/obj/item/clothing/head/towel/brown
+ name = "коричневая шапочка из полотенца"
+ color = "#DEB887"
+
+/obj/item/clothing/head/beret/centcom/intern
+ name = "nanotrasen intern beret"
+ desc = "Берет стажера НТ. Белый берет с зеленой звездой. Выглядит подозрительно похожим на берет главного инженера..."
+ icon_state = "beret_ce"
diff --git a/modular_ss220/clothing/code/helmet.dm b/modular_ss220/clothing/code/helmet.dm
new file mode 100644
index 000000000000..9fc5388a9aa3
--- /dev/null
+++ b/modular_ss220/clothing/code/helmet.dm
@@ -0,0 +1,181 @@
+// MARK: Miscellaneous
+/obj/item/clothing/head/helmet/bike_helmet
+ name = "байкерский шлем"
+ desc = "Крутой шлем."
+ icon = 'modular_ss220/clothing/icons/object/hats.dmi'
+ icon_state = "bike_helmet"
+ lefthand_file = 'modular_ss220/clothing/icons/inhands/left_hand.dmi'
+ righthand_file = 'modular_ss220/clothing/icons/inhands/right_hand.dmi'
+ toggle_message = "Вы опустили защитное стекло"
+ alt_toggle_message = "Вы подняли защитное стекло"
+ actions_types = list(/datum/action/item_action/toggle_helmet_mode)
+ can_toggle = TRUE
+ toggle_sound = 'sound/weapons/tap.ogg'
+ dog_fashion = null
+ sprite_sheets = list(
+ "Abductor" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Ancient Skeleton" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/helmet.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Human" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Monkey" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Plasmaman" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/species/skrell/helmet.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/hats.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/species/tajaran/helmet.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/species/unathi/helmet.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/helmet.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/species/vulpkanin/helmet.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ )
+
+/obj/item/clothing/head/helmet/bike_helmet/replica
+ desc = "Крутой шлем. На вид хлипкий..."
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
+
+// MARK: ERT
+/obj/item/clothing/head/helmet/ert
+ icon = 'modular_ss220/clothing/icons/object/helmet.dmi'
+ icon_state = "ember_sec"
+ item_state = "ember_sec"
+ sprite_sheets = list(
+ "Abductor" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Ancient Skeleton" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/helmet.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Human" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Monkey" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Plasmaman" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/helmet.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/species/vulpkanin/helmet.dmi',
+ "Lich" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ )
+
+/obj/item/clothing/head/helmet/ert/security
+ icon_state = "ember_sec"
+ item_state = "ember_sec"
+
+/obj/item/clothing/head/helmet/ert/engineer
+ icon_state = "ember_eng"
+ item_state = "ember_eng"
+
+/obj/item/clothing/head/helmet/ert/medical
+ icon_state = "ember_med"
+ item_state = "ember_med"
+
+/obj/item/clothing/head/helmet/ert/janitor
+ icon_state = "ember_jan"
+ item_state = "ember_jan"
+
+/obj/item/clothing/head/helmet/ert/command
+ icon_state = "ember_com"
+ item_state = "ember_com"
+ actions_types = list(/datum/action/item_action/toggle_nvg)
+ /// Is night vision goggles enabled?
+ var/nvg_enabled = FALSE
+
+/datum/action/item_action/toggle_nvg
+ name = "Toggle Nightvision"
+
+/obj/item/clothing/head/helmet/ert/command/ui_action_click(mob/user, actiontype)
+ if(actiontype == /datum/action/item_action/toggle_nvg)
+ toggle_nvg(user)
+
+/obj/item/clothing/head/helmet/ert/command/item_action_slot_check(slot)
+ if(slot == ITEM_SLOT_HEAD)
+ return TRUE
+
+/obj/item/clothing/head/helmet/ert/command/equipped(mob/user, slot, initial)
+ . = ..()
+ if(nvg_enabled && slot == ITEM_SLOT_HEAD)
+ ADD_TRAIT(user, TRAIT_NIGHT_VISION, "ert_commander_helmet[UID()]")
+
+/obj/item/clothing/head/helmet/ert/command/dropped(mob/user)
+ . = ..()
+ if(user)
+ REMOVE_TRAIT(user, TRAIT_NIGHT_VISION, "ert_commander_helmet[UID()]")
+
+/obj/item/clothing/head/helmet/ert/command/update_icon_state()
+ . = ..()
+ if(nvg_enabled)
+ icon_state = initial(icon_state) + "_nvg"
+ item_state = initial(item_state) + "_nvg"
+ else
+ icon_state = initial(icon_state)
+ item_state = initial(item_state)
+
+/obj/item/clothing/head/helmet/ert/command/proc/toggle_nvg(mob/user)
+ var/msg
+ if(!HAS_TRAIT_FROM(user, TRAIT_NIGHT_VISION, "ert_commander_helmet[UID()]"))
+ ADD_TRAIT(user, TRAIT_NIGHT_VISION, "ert_commander_helmet[UID()]")
+ msg = "You lowered your night-vision goggles over your eyes."
+ nvg_enabled = TRUE
+ else
+ REMOVE_TRAIT(user, TRAIT_NIGHT_VISION, "ert_commander_helmet[UID()]")
+ msg = "You raised your night-vision goggles."
+ nvg_enabled = FALSE
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.head == src)
+ H.update_sight()
+
+ update_icon(UPDATE_ICON_STATE)
+ user.update_inv_head()
+ to_chat(user, span_notice("[msg]"))
+
+/obj/item/clothing/head/helmet/ert/security/paranormal
+ icon_state = "knight_templar"
+ item_state = "knight_templar"
+ sprite_sheets = list(
+ "Vox" = 'icons/mob/clothing/species/vox/helmet.dmi',
+ "Drask" = 'icons/mob/clothing/species/drask/helmet.dmi',
+ "Grey" = 'icons/mob/clothing/species/grey/helmet.dmi'
+ )
+
+/obj/item/clothing/head/helmet/space/ert_engineer
+ name = "emergency response team engineer space helmet"
+ desc = "Space helmet worn by engineering members of the Nanotrasen Emergency Response Team. Has orange highlights."
+ icon = 'modular_ss220/clothing/icons/object/helmet.dmi'
+ icon_state = "ember_eng"
+ item_state = "ember_eng"
+ sprite_sheets = list(
+ "Abductor" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Ancient Skeleton" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/helmet.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Human" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Monkey" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Plasmaman" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/species/tajaran/helmet.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/helmet.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/species/vulpkanin/helmet.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/helmet.dmi',
+ )
+ armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 10, RAD = 50, FIRE = 200, ACID = 115)
diff --git a/modular_ss220/clothing/code/hev_suit.dm b/modular_ss220/clothing/code/hev_suit.dm
new file mode 100644
index 000000000000..31d5e9e94d61
--- /dev/null
+++ b/modular_ss220/clothing/code/hev_suit.dm
@@ -0,0 +1,196 @@
+#define SOUND_BEEP(sound) add_queue(##sound, 20)
+#define MORPHINE_INJECTION_DELAY (30 SECONDS)
+
+//Suit
+/obj/item/clothing/suit/space/hev
+ name = "\improper hazardous environment suit"
+ desc = "The Mark IV HEV suit protects the user from a number of hazardous environments and has in build ballistic protection."
+ icon = 'modular_ss220/clothing/icons/object/suits.dmi'
+ icon_state = "hev"
+ icon_override = 'modular_ss220/clothing/icons/mob/suits.dmi'
+ lefthand_file = 'modular_ss220/clothing/icons/inhands/left_hand.dmi'
+ righthand_file = 'modular_ss220/clothing/icons/inhands/right_hand.dmi'
+ resistance_flags = FIRE_PROOF | ACID_PROOF | FREEZE_PROOF | STOPSPRESSUREDMAGE
+ body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
+ flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL
+ armor = list(MELEE = 35, BULLET = 30, LASER = 20, ENERGY = 25, BOMB = 30, RAD = 100, FIRE = 80, ACID = 50)
+ allowed = list(
+ /obj/item/tank/internals/emergency_oxygen,
+ /obj/item/tank/internals/plasmaman,
+ /obj/item/gun/energy,
+ /obj/item/gun/projectile,
+ /obj/item/crowbar,
+ )
+ slowdown = 0.25
+
+ var/static/list/funny_signals = list(
+ COMSIG_MOB_SAY = PROC_REF(handle_speech),
+ COMSIG_MOB_DEATH = PROC_REF(handle_death),
+ COMSIG_LIVING_IGNITED = PROC_REF(handle_ignite),
+ COMSIG_LIVING_ELECTROCUTE_ACT = PROC_REF(handle_shock),
+ // COMSIG_MOB_APPLY_DAMAGE= PROC_REF(handle_damage),
+ )
+
+
+ var/list/sound_queue = list()
+
+ var/mob/living/carbon/owner
+
+ var/obj/item/geiger_counter/GC
+
+ COOLDOWN_DECLARE(next_damage_notify)
+ COOLDOWN_DECLARE(next_morphine)
+
+/obj/item/clothing/suit/space/hev/Initialize(mapload)
+ . = ..()
+ GC = new(src)
+ GC.scanning = TRUE
+ update_appearance(UPDATE_ICON)
+
+/obj/item/clothing/suit/space/hev/Destroy()
+ QDEL_NULL(GC)
+ owner = null
+ return ..()
+
+/obj/item/clothing/suit/space/hev/proc/process_sound_queue()
+
+ var/list/sound_data = sound_queue[1]
+ var/sound_file = sound_data[1]
+ var/sound_delay = sound_data[2]
+
+ playsound(owner, sound_file, 20)
+
+ sound_queue.Cut(1,2)
+
+ if(!length(sound_queue))
+ return
+
+ addtimer(CALLBACK(src, PROC_REF(process_sound_queue)), sound_delay)
+
+/obj/item/clothing/suit/space/hev/proc/add_queue(desired_file, desired_delay, purge_queue=FALSE)
+
+ var/was_empty_sound_queue = !length(sound_queue)
+
+ if(purge_queue)
+ sound_queue.Cut()
+
+ sound_queue += list(list(desired_file,desired_delay)) //BYOND is fucking weird so you have to do this bullshit if you want to add a list to a list.
+
+ if(was_empty_sound_queue)
+ addtimer(CALLBACK(src, PROC_REF(process_sound_queue)), 1 SECONDS)
+
+ return TRUE
+
+//Signal handling.
+/obj/item/clothing/suit/space/hev/equipped(mob/M, slot)
+ ..()
+ if(slot == ITEM_SLOT_OUTER_SUIT && iscarbon(M))
+ for(var/voice in funny_signals)
+ RegisterSignal(M, voice, funny_signals[voice])
+ owner = M
+ add_queue('modular_ss220/aesthetics_sounds/sound/hev/blip.ogg', 2 SECONDS, purge_queue=TRUE)
+ add_queue('modular_ss220/aesthetics_sounds/sound/hev/01_hev_logon.ogg', 11 SECONDS)
+ add_queue('modular_ss220/aesthetics_sounds/sound/hev/04_vitalsigns_on.ogg', 4 SECONDS)
+ add_queue('modular_ss220/aesthetics_sounds/sound/hev/09_safe_day.ogg', 8 SECONDS)
+ else
+ for(var/voice in funny_signals)
+ UnregisterSignal(M, voice)
+
+/obj/item/clothing/suit/space/hev/dropped(mob/M)
+ ..()
+ for(var/voice in funny_signals)
+ UnregisterSignal(M, voice)
+
+//Death
+/obj/item/clothing/suit/space/hev/proc/handle_death(gibbed)
+ SIGNAL_HANDLER
+ add_queue('modular_ss220/aesthetics_sounds/sound/hev/death.ogg', 5 SECONDS, purge_queue=TRUE)
+
+//Mute
+/obj/item/clothing/suit/space/hev/proc/handle_speech(datum/source, list/speech_args)
+ SIGNAL_HANDLER
+ var/static/list/cancel_messages = list(
+ "Вам трудно говорить, когда костюм туго сдавливает ваше горло...",
+ "Ваши связки ощущаются сдавленными, что пресекает любую попытку выдавить хоть какой-то звук...",
+ "Вы пытаетесь что-то сказать, но костюм сдавливает вам гортань..."
+ )
+
+ speech_args[SPEECH_MESSAGE] = "..."
+ to_chat(source, span_warning(pick(cancel_messages)))
+
+//Fire
+/obj/item/clothing/suit/space/hev/proc/handle_ignite(mob/living)
+ SIGNAL_HANDLER
+ SOUND_BEEP('modular_ss220/aesthetics_sounds/sound/hev/beep_3.ogg')
+ add_queue('modular_ss220/aesthetics_sounds/sound/hev/heat.ogg', 3 SECONDS)
+
+//Shock
+/obj/item/clothing/suit/space/hev/proc/handle_shock(mob/living)
+ SIGNAL_HANDLER
+ SOUND_BEEP('modular_ss220/aesthetics_sounds/sound/hev/beep_3.ogg')
+ add_queue('modular_ss220/aesthetics_sounds/sound/hev/shok.ogg', 3 SECONDS)
+
+//Helmet
+/obj/item/clothing/head/helmet/hev_helmet
+ name = "hazardous environment suit helmet"
+ desc = "The Mark IV HEV suit helmet."
+ icon = 'modular_ss220/clothing/icons/object/helmet.dmi'
+ icon_override = 'modular_ss220/clothing/icons/mob/helmet.dmi'
+ item_state = "hev_helmet"
+ icon_state = "hev0"
+ lefthand_file = 'modular_ss220/clothing/icons/inhands/left_hand.dmi'
+ righthand_file = 'modular_ss220/clothing/icons/inhands/right_hand.dmi'
+ armor = list(MELEE = 10, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 5, RAD = 100, FIRE = 15, ACID = 20)
+ flags = BLOCKHAIR | STOPSPRESSUREDMAGE | THICKMATERIAL
+ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
+ flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
+ visor_flags = STOPSPRESSUREDMAGE
+ flash_protect = FLASH_PROTECTION_WELDER
+ dog_fashion = null
+ var/on = FALSE
+ var/brightness_on = 4
+ actions_types = list(/datum/action/item_action/toggle_helmet_light)
+ var/hud_types = DATA_HUD_MEDICAL_ADVANCED
+
+/obj/item/clothing/head/helmet/hev_helmet/Initialize(mapload)
+ . = ..()
+ if(!islist(hud_types) && hud_types)
+ hud_types = list(hud_types)
+
+/obj/item/clothing/head/helmet/hev_helmet/equipped(mob/living/carbon/human/user, slot)
+ ..()
+ if(slot != ITEM_SLOT_HEAD)
+ return
+ for(var/new_hud in hud_types)
+ var/datum/atom_hud/H = GLOB.huds[new_hud]
+ H.add_hud_to(user)
+
+/obj/item/clothing/head/helmet/hev_helmet/dropped(mob/living/carbon/human/user)
+ ..()
+ for(var/new_hud in hud_types)
+ var/datum/atom_hud/H = GLOB.huds[new_hud]
+ H.remove_hud_from(user)
+
+/obj/item/clothing/head/helmet/hev_helmet/ui_action_click(mob/user, toggle_helmet_light)
+ light_toggle(user)
+
+/obj/item/clothing/head/helmet/hev_helmet/proc/light_toggle(mob/user)
+ on = !on
+ icon_state = "hev[on]"
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_head()
+
+ if(on)
+ set_light(brightness_on)
+ else
+ set_light(0)
+
+/obj/item/clothing/head/helmet/hev_helmet/extinguish_light(force = FALSE)
+ if(on)
+ light_toggle()
+ visible_message(span_danger("[src]'s light fades and turns off."))
+
+#undef MORPHINE_INJECTION_DELAY
+#undef SOUND_BEEP
diff --git a/modular_ss220/clothing/code/mask.dm b/modular_ss220/clothing/code/mask.dm
new file mode 100644
index 000000000000..07e4c663643e
--- /dev/null
+++ b/modular_ss220/clothing/code/mask.dm
@@ -0,0 +1,125 @@
+/obj/item/clothing/mask
+ var/modifies_speech = FALSE
+
+/obj/item/clothing/mask/proc/handle_speech(datum/source, list/speech_args)
+ SIGNAL_HANDLER
+ return
+
+/obj/item/clothing/mask/equipped(mob/M, slot)
+ . = ..()
+
+ if((slot & ITEM_SLOT_MASK) && modifies_speech)
+ RegisterSignal(M, COMSIG_MOB_SAY, PROC_REF(handle_speech))
+ else
+ UnregisterSignal(M, COMSIG_MOB_SAY)
+
+/obj/item/clothing/mask/dropped(mob/M)
+ . = ..()
+ UnregisterSignal(M, COMSIG_MOB_SAY)
+
+/obj/item/clothing/mask/fakemoustache/chef
+ name = "абсолютно настоящие усы шефа"
+ desc = "Осторожно: усы накладные."
+ modifies_speech = TRUE
+
+/obj/item/clothing/mask/fakemoustache/chef/handle_speech(datum/source, list/speech_args)
+ var/message = speech_args[SPEECH_MESSAGE]
+ if(message[1] != "*")
+ var/static/regex/words = new(@"(?Вы перекрашиваете [src.name].")
+ return
+
+/obj/item/clothing/under/towel/long
+ name = "полотенце"
+ desc = "Полотенце, сотканное из синтетической ткани. Можно обмотать вокруг тела."
+ icon_state = "towel_long"
+ item_color = "towel_long"
+
+/obj/item/clothing/under/towel/long/alt
+ name = "махровое полотенце"
+ desc = "Полотенце, сотканное из синтетической ткани, на взгляд шершавое. Можно обмотать вокруг тела."
+ icon_state = "towel_long_alt"
+ item_color = "towel_long_alt"
+
+/obj/item/clothing/under/towel/short
+ name = "маленькое полотенце"
+ desc = "Полотенце, сотканное из синтетической ткани, но маленькое. Можно обмотать вокруг тела."
+ icon_state = "towel_short"
+ item_color = "towel_short"
+
+/obj/item/clothing/under/towel/short/alt
+ name = "маленькое махровое полотенце"
+ desc = "Полотенце, сотканное из синтетической ткани, на взгляд шершавое и маленькое. Можно обмотать вокруг тела."
+ icon_state = "towel_short_alt"
+ item_color = "towel_short_alt"
+
+// Длинное полотенце
+/obj/item/clothing/under/towel/long/red
+ name = "красное полотенце"
+ color = "#EE204D"
+
+/obj/item/clothing/under/towel/long/green
+ name = "зелёное полотенце"
+ color = "#32CD32"
+
+/obj/item/clothing/under/towel/long/blue
+ name = "синее полотенце"
+ color = "#1E90FF"
+
+/obj/item/clothing/under/towel/long/orange
+ name = "оранжевое полотенце"
+ color = "#FFA500"
+
+/obj/item/clothing/under/towel/long/purple
+ name = "фиолетовое полотенце"
+ color = "#DA70D6"
+
+/obj/item/clothing/under/towel/long/cyan
+ name = "голубое полотенце"
+ color = "#40E0D0"
+
+/obj/item/clothing/under/towel/long/brown
+ name = "коричневое полотенце"
+ color = "#DEB887"
+
+// Длинное махровое полотенце
+/obj/item/clothing/under/towel/long/alt/red
+ name = "красное махровое полотенце"
+ color = "#EE204D"
+
+/obj/item/clothing/under/towel/long/alt/green
+ name = "зелёное махровое полотенце"
+ color = "#32CD32"
+
+/obj/item/clothing/under/towel/long/alt/blue
+ name = "синее махровое полотенце"
+ color = "#1E90FF"
+
+/obj/item/clothing/under/towel/long/alt/orange
+ name = "оранжевое махровое полотенце"
+ color = "#FFA500"
+
+/obj/item/clothing/under/towel/long/alt/purple
+ name = "фиолетовое махровое полотенце"
+ color = "#DA70D6"
+
+/obj/item/clothing/under/towel/long/alt/cyan
+ name = "голубое махровое полотенце"
+ color = "#40E0D0"
+
+/obj/item/clothing/under/towel/long/alt/brown
+ name = "коричневое махровое полотенце"
+ color = "#DEB887"
+
+// Маленькое полотенце
+/obj/item/clothing/under/towel/short/red
+ name = "красное маленькое полотенце"
+ color = "#EE204D"
+
+/obj/item/clothing/under/towel/short/green
+ name = "зелёное маленькое полотенце"
+ color = "#32CD32"
+
+/obj/item/clothing/under/towel/short/blue
+ name = "синее маленькое полотенце"
+ color = "#1E90FF"
+
+/obj/item/clothing/under/towel/short/orange
+ name = "оранжевое маленькое полотенце"
+ color = "#FFA500"
+
+/obj/item/clothing/under/towel/short/purple
+ name = "фиолетовое маленькое полотенце"
+ color = "#DA70D6"
+
+/obj/item/clothing/under/towel/short/cyan
+ name = "голубое маленькое полотенце"
+ color = "#40E0D0"
+
+/obj/item/clothing/under/towel/short/brown
+ name = "коричневое маленькое полотенце"
+ color = "#DEB887"
+
+// Маленькое махровое полотенце
+/obj/item/clothing/under/towel/short/alt/red
+ name = "красное махровое маленькое полотенце"
+ color = "#EE204D"
+
+/obj/item/clothing/under/towel/short/alt/green
+ name = "зелёное махровое маленькое полотенце"
+ color = "#32CD32"
+
+/obj/item/clothing/under/towel/short/alt/blue
+ name = "синее махровое маленькое полотенце"
+ color = "#1E90FF"
+
+/obj/item/clothing/under/towel/short/alt/orange
+ name = "оранжевое махровое маленькое полотенце"
+ color = "#FFA500"
+
+/obj/item/clothing/under/towel/short/alt/purple
+ name = "фиолетовое махровое маленькое полотенце"
+ color = "#DA70D6"
+
+/obj/item/clothing/under/towel/short/alt/cyan
+ name = "голубое махровое маленькое полотенце"
+ color = "#40E0D0"
+
+/obj/item/clothing/under/towel/short/alt/brown
+ name = "коричневое махровое маленькое полотенце"
+ color = "#DEB887"
+
+/* EI uniform */
+/obj/item/clothing/under/ei_combat
+ name = "тактическая водолазка Gold on Black"
+ desc = "Все то же удобство, но в прекрасной гамме угольных оттенков."
+ icon = 'modular_ss220/clothing/icons/object/under.dmi'
+ icon_state = "ei_combat"
+ item_color = "ei_combat"
+ lefthand_file = 'modular_ss220/clothing/icons/inhands/left_hand.dmi'
+ righthand_file = 'modular_ss220/clothing/icons/inhands/right_hand.dmi'
+ sprite_sheets = list(
+ "Human" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/species/kidan/under.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Skeleton" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/under.dmi',
+ "Abductor" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/under.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/under.dmi',
+ )
+
+/obj/item/clothing/under/ei_skirt
+ name = "блузка с юбкой Gold on Black"
+ desc = "Не волнуйтесь, запачкать её будет крайне сложно, так что вы всегда будете прелестны и очаровательны. Даже если руки по локоть в крови."
+ icon = 'modular_ss220/clothing/icons/object/under.dmi'
+ icon_state = "ei_skirt"
+ item_color = "ei_skirt"
+ lefthand_file = 'modular_ss220/clothing/icons/inhands/left_hand.dmi'
+ righthand_file = 'modular_ss220/clothing/icons/inhands/right_hand.dmi'
+ sprite_sheets = list(
+ "Human" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/species/kidan/under.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Skeleton" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/under.dmi',
+ "Abductor" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/under.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/under.dmi',
+ )
+
+/obj/item/clothing/under/ei_skirt_alt
+ name = "юбка «Солнце» от EI"
+ desc = "Юбка «Солнце» в классических цветах корпорации EI."
+ icon = 'modular_ss220/clothing/icons/object/under.dmi'
+ icon_state = "ei_skirt_alt"
+ item_color = "ei_skirt_alt"
+ sprite_sheets = list(
+ "Human" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Tajaran" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Vulpkanin" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Kidan" = 'modular_ss220/clothing/icons/mob/species/kidan/under.dmi',
+ "Skrell" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Nucleation" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Skeleton" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Slime People" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Unathi" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Grey" = 'modular_ss220/clothing/icons/mob/species/grey/under.dmi',
+ "Abductor" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Golem" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Machine" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Diona" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Nian" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Shadow" = 'modular_ss220/clothing/icons/mob/under.dmi',
+ "Vox" = 'modular_ss220/clothing/icons/mob/species/vox/under.dmi',
+ "Drask" = 'modular_ss220/clothing/icons/mob/species/drask/under.dmi',
+ )
diff --git a/modular_ss220/clothing/icons/inhands/left_hand.dmi b/modular_ss220/clothing/icons/inhands/left_hand.dmi
new file mode 100644
index 000000000000..388dde1feacd
Binary files /dev/null and b/modular_ss220/clothing/icons/inhands/left_hand.dmi differ
diff --git a/modular_ss220/clothing/icons/inhands/right_hand.dmi b/modular_ss220/clothing/icons/inhands/right_hand.dmi
new file mode 100644
index 000000000000..30f99a7a85e7
Binary files /dev/null and b/modular_ss220/clothing/icons/inhands/right_hand.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/accessories.dmi b/modular_ss220/clothing/icons/mob/accessories.dmi
new file mode 100644
index 000000000000..1012e226c4bc
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/accessories.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/cloaks.dmi b/modular_ss220/clothing/icons/mob/cloaks.dmi
new file mode 100644
index 000000000000..b09be504a679
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/cloaks.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/hands.dmi b/modular_ss220/clothing/icons/mob/hands.dmi
new file mode 100644
index 000000000000..380ab3f64c68
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/hands.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/hats.dmi b/modular_ss220/clothing/icons/mob/hats.dmi
new file mode 100644
index 000000000000..6c86f54f84bb
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/helmet.dmi b/modular_ss220/clothing/icons/mob/helmet.dmi
new file mode 100644
index 000000000000..f446553cf564
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/mask.dmi b/modular_ss220/clothing/icons/mob/mask.dmi
new file mode 100644
index 000000000000..afe1144c0a0c
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/mask.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/mod_clothing.dmi b/modular_ss220/clothing/icons/mob/mod_clothing.dmi
new file mode 100644
index 000000000000..cc7d72e6d5d1
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/mod_clothing.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/shoes.dmi b/modular_ss220/clothing/icons/mob/shoes.dmi
new file mode 100644
index 000000000000..6bf2712da541
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/shoes.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/accessories.dmi b/modular_ss220/clothing/icons/mob/species/drask/accessories.dmi
new file mode 100644
index 000000000000..a63a43c32f8d
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/accessories.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/cloaks.dmi b/modular_ss220/clothing/icons/mob/species/drask/cloaks.dmi
new file mode 100644
index 000000000000..16e62552dcee
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/cloaks.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/gloves.dmi b/modular_ss220/clothing/icons/mob/species/drask/gloves.dmi
new file mode 100644
index 000000000000..1f502c4a92bb
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/gloves.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/hats.dmi b/modular_ss220/clothing/icons/mob/species/drask/hats.dmi
new file mode 100644
index 000000000000..18ab856b2320
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/helmet.dmi b/modular_ss220/clothing/icons/mob/species/drask/helmet.dmi
new file mode 100644
index 000000000000..36b7c7462bee
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/mask.dmi b/modular_ss220/clothing/icons/mob/species/drask/mask.dmi
new file mode 100644
index 000000000000..098e6d9e1c46
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/mask.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/shoes.dmi b/modular_ss220/clothing/icons/mob/species/drask/shoes.dmi
new file mode 100644
index 000000000000..201cacb5d03f
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/shoes.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/suits.dmi b/modular_ss220/clothing/icons/mob/species/drask/suits.dmi
new file mode 100644
index 000000000000..1fdb6b70608c
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/suits.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/drask/under.dmi b/modular_ss220/clothing/icons/mob/species/drask/under.dmi
new file mode 100644
index 000000000000..9e5b8f3a7f07
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/drask/under.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/grey/accessories.dmi b/modular_ss220/clothing/icons/mob/species/grey/accessories.dmi
new file mode 100644
index 000000000000..561fdf7b490b
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/grey/accessories.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/grey/cloaks.dmi b/modular_ss220/clothing/icons/mob/species/grey/cloaks.dmi
new file mode 100644
index 000000000000..8c676731e867
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/grey/cloaks.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/grey/gloves.dmi b/modular_ss220/clothing/icons/mob/species/grey/gloves.dmi
new file mode 100644
index 000000000000..77f4c571ea8f
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/grey/gloves.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/grey/hats.dmi b/modular_ss220/clothing/icons/mob/species/grey/hats.dmi
new file mode 100644
index 000000000000..9d52d6b5939a
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/grey/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/grey/mask.dmi b/modular_ss220/clothing/icons/mob/species/grey/mask.dmi
new file mode 100644
index 000000000000..1b315f9ef806
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/grey/mask.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/grey/mod_clothing.dmi b/modular_ss220/clothing/icons/mob/species/grey/mod_clothing.dmi
new file mode 100644
index 000000000000..4613804d7899
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/grey/mod_clothing.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/grey/suits.dmi b/modular_ss220/clothing/icons/mob/species/grey/suits.dmi
new file mode 100644
index 000000000000..3f62407fd4d2
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/grey/suits.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/grey/under.dmi b/modular_ss220/clothing/icons/mob/species/grey/under.dmi
new file mode 100644
index 000000000000..be528b4ba07b
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/grey/under.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/kidan/cloaks.dmi b/modular_ss220/clothing/icons/mob/species/kidan/cloaks.dmi
new file mode 100644
index 000000000000..be78528f8df1
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/kidan/cloaks.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/kidan/gloves.dmi b/modular_ss220/clothing/icons/mob/species/kidan/gloves.dmi
new file mode 100644
index 000000000000..e0807cf5e01b
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/kidan/gloves.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/kidan/hats.dmi b/modular_ss220/clothing/icons/mob/species/kidan/hats.dmi
new file mode 100644
index 000000000000..18e2d4b7dc0e
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/kidan/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/kidan/helmet.dmi b/modular_ss220/clothing/icons/mob/species/kidan/helmet.dmi
new file mode 100644
index 000000000000..be0f897a88dc
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/kidan/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/kidan/mask.dmi b/modular_ss220/clothing/icons/mob/species/kidan/mask.dmi
new file mode 100644
index 000000000000..bc686ad2d48e
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/kidan/mask.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/kidan/shoes.dmi b/modular_ss220/clothing/icons/mob/species/kidan/shoes.dmi
new file mode 100644
index 000000000000..f931a3169dd9
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/kidan/shoes.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/kidan/suits.dmi b/modular_ss220/clothing/icons/mob/species/kidan/suits.dmi
new file mode 100644
index 000000000000..1f95f6438931
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/kidan/suits.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/kidan/under.dmi b/modular_ss220/clothing/icons/mob/species/kidan/under.dmi
new file mode 100644
index 000000000000..dda63767a270
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/kidan/under.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/monkey/accessories.dmi b/modular_ss220/clothing/icons/mob/species/monkey/accessories.dmi
new file mode 100644
index 000000000000..e289479fda3d
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/monkey/accessories.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/monkey/hats.dmi b/modular_ss220/clothing/icons/mob/species/monkey/hats.dmi
new file mode 100644
index 000000000000..84cddd53877d
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/monkey/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/monkey/suits.dmi b/modular_ss220/clothing/icons/mob/species/monkey/suits.dmi
new file mode 100644
index 000000000000..e0d6001edc68
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/monkey/suits.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/monkey/under.dmi b/modular_ss220/clothing/icons/mob/species/monkey/under.dmi
new file mode 100644
index 000000000000..5d12bb67679e
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/monkey/under.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/skrell/helmet.dmi b/modular_ss220/clothing/icons/mob/species/skrell/helmet.dmi
new file mode 100644
index 000000000000..6635a7e9d60f
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/skrell/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/skrell/mod_clothing.dmi b/modular_ss220/clothing/icons/mob/species/skrell/mod_clothing.dmi
new file mode 100644
index 000000000000..cc7d72e6d5d1
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/skrell/mod_clothing.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/tajaran/hats.dmi b/modular_ss220/clothing/icons/mob/species/tajaran/hats.dmi
new file mode 100644
index 000000000000..499768c34054
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/tajaran/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/tajaran/helmet.dmi b/modular_ss220/clothing/icons/mob/species/tajaran/helmet.dmi
new file mode 100644
index 000000000000..31865926b986
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/tajaran/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/tajaran/mod_clothing.dmi b/modular_ss220/clothing/icons/mob/species/tajaran/mod_clothing.dmi
new file mode 100644
index 000000000000..9cfee846ce24
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/tajaran/mod_clothing.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/unathi/helmet.dmi b/modular_ss220/clothing/icons/mob/species/unathi/helmet.dmi
new file mode 100644
index 000000000000..34ca762e9dc8
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/unathi/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/unathi/mask.dmi b/modular_ss220/clothing/icons/mob/species/unathi/mask.dmi
new file mode 100644
index 000000000000..1f1dfc5103c4
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/unathi/mask.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/unathi/mod_clothing.dmi b/modular_ss220/clothing/icons/mob/species/unathi/mod_clothing.dmi
new file mode 100644
index 000000000000..e5c67a6e51fd
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/unathi/mod_clothing.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/unathi/under.dmi b/modular_ss220/clothing/icons/mob/species/unathi/under.dmi
new file mode 100644
index 000000000000..8f61504d2047
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/unathi/under.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/accessories.dmi b/modular_ss220/clothing/icons/mob/species/vox/accessories.dmi
new file mode 100644
index 000000000000..a4bba0332086
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/accessories.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/cloaks.dmi b/modular_ss220/clothing/icons/mob/species/vox/cloaks.dmi
new file mode 100644
index 000000000000..83d59eef44b5
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/cloaks.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/gloves.dmi b/modular_ss220/clothing/icons/mob/species/vox/gloves.dmi
new file mode 100644
index 000000000000..34d6618a1060
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/gloves.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/hats.dmi b/modular_ss220/clothing/icons/mob/species/vox/hats.dmi
new file mode 100644
index 000000000000..ee53b84a1d9c
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/helmet.dmi b/modular_ss220/clothing/icons/mob/species/vox/helmet.dmi
new file mode 100644
index 000000000000..9bd035a6efbb
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/mask.dmi b/modular_ss220/clothing/icons/mob/species/vox/mask.dmi
new file mode 100644
index 000000000000..eeb523eea4ae
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/mask.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/mod_clothing.dmi b/modular_ss220/clothing/icons/mob/species/vox/mod_clothing.dmi
new file mode 100644
index 000000000000..ff1a808992b1
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/mod_clothing.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/shoes.dmi b/modular_ss220/clothing/icons/mob/species/vox/shoes.dmi
new file mode 100644
index 000000000000..a62578dc97fb
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/shoes.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/suits.dmi b/modular_ss220/clothing/icons/mob/species/vox/suits.dmi
new file mode 100644
index 000000000000..c1b4423ee12e
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/suits.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vox/under.dmi b/modular_ss220/clothing/icons/mob/species/vox/under.dmi
new file mode 100644
index 000000000000..92db8e05e138
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vox/under.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vulpkanin/hats.dmi b/modular_ss220/clothing/icons/mob/species/vulpkanin/hats.dmi
new file mode 100644
index 000000000000..6e61169fc42c
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vulpkanin/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vulpkanin/helmet.dmi b/modular_ss220/clothing/icons/mob/species/vulpkanin/helmet.dmi
new file mode 100644
index 000000000000..736081458282
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vulpkanin/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vulpkanin/mask.dmi b/modular_ss220/clothing/icons/mob/species/vulpkanin/mask.dmi
new file mode 100644
index 000000000000..7199f7cd3e20
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vulpkanin/mask.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/species/vulpkanin/mod_clothing.dmi b/modular_ss220/clothing/icons/mob/species/vulpkanin/mod_clothing.dmi
new file mode 100644
index 000000000000..415391a72552
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/species/vulpkanin/mod_clothing.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/suits.dmi b/modular_ss220/clothing/icons/mob/suits.dmi
new file mode 100644
index 000000000000..1fdf65d327a2
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/suits.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/under.dmi b/modular_ss220/clothing/icons/mob/under.dmi
new file mode 100644
index 000000000000..d0c71f83a2cb
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/under.dmi differ
diff --git a/modular_ss220/clothing/icons/mob/uniform.dmi b/modular_ss220/clothing/icons/mob/uniform.dmi
new file mode 100644
index 000000000000..e665a9badbdf
Binary files /dev/null and b/modular_ss220/clothing/icons/mob/uniform.dmi differ
diff --git a/modular_ss220/clothing/icons/object/accessories.dmi b/modular_ss220/clothing/icons/object/accessories.dmi
new file mode 100644
index 000000000000..d8f4f4e75384
Binary files /dev/null and b/modular_ss220/clothing/icons/object/accessories.dmi differ
diff --git a/modular_ss220/clothing/icons/object/cloaks.dmi b/modular_ss220/clothing/icons/object/cloaks.dmi
new file mode 100644
index 000000000000..450347b6f451
Binary files /dev/null and b/modular_ss220/clothing/icons/object/cloaks.dmi differ
diff --git a/modular_ss220/clothing/icons/object/gloves.dmi b/modular_ss220/clothing/icons/object/gloves.dmi
new file mode 100644
index 000000000000..4538b9e4dfdb
Binary files /dev/null and b/modular_ss220/clothing/icons/object/gloves.dmi differ
diff --git a/modular_ss220/clothing/icons/object/hats.dmi b/modular_ss220/clothing/icons/object/hats.dmi
new file mode 100644
index 000000000000..c9c47cb05d8f
Binary files /dev/null and b/modular_ss220/clothing/icons/object/hats.dmi differ
diff --git a/modular_ss220/clothing/icons/object/helmet.dmi b/modular_ss220/clothing/icons/object/helmet.dmi
new file mode 100644
index 000000000000..683c86811fb5
Binary files /dev/null and b/modular_ss220/clothing/icons/object/helmet.dmi differ
diff --git a/modular_ss220/clothing/icons/object/masks.dmi b/modular_ss220/clothing/icons/object/masks.dmi
new file mode 100644
index 000000000000..0f256e88b4d8
Binary files /dev/null and b/modular_ss220/clothing/icons/object/masks.dmi differ
diff --git a/modular_ss220/clothing/icons/object/mod_clothing.dmi b/modular_ss220/clothing/icons/object/mod_clothing.dmi
new file mode 100644
index 000000000000..d1b91725df35
Binary files /dev/null and b/modular_ss220/clothing/icons/object/mod_clothing.dmi differ
diff --git a/modular_ss220/clothing/icons/object/shoes.dmi b/modular_ss220/clothing/icons/object/shoes.dmi
new file mode 100644
index 000000000000..af39eb1b29f8
Binary files /dev/null and b/modular_ss220/clothing/icons/object/shoes.dmi differ
diff --git a/modular_ss220/clothing/icons/object/suits.dmi b/modular_ss220/clothing/icons/object/suits.dmi
new file mode 100644
index 000000000000..2adce2ca6a0b
Binary files /dev/null and b/modular_ss220/clothing/icons/object/suits.dmi differ
diff --git a/modular_ss220/clothing/icons/object/under.dmi b/modular_ss220/clothing/icons/object/under.dmi
new file mode 100644
index 000000000000..b918484e20ea
Binary files /dev/null and b/modular_ss220/clothing/icons/object/under.dmi differ
diff --git a/modular_ss220/clothing/sounds/moffstep01.ogg b/modular_ss220/clothing/sounds/moffstep01.ogg
new file mode 100644
index 000000000000..6350cb057bf0
Binary files /dev/null and b/modular_ss220/clothing/sounds/moffstep01.ogg differ
diff --git a/modular_ss220/clumsy_table/_clumsy_table.dm b/modular_ss220/clumsy_table/_clumsy_table.dm
new file mode 100644
index 000000000000..25f225f2c01e
--- /dev/null
+++ b/modular_ss220/clumsy_table/_clumsy_table.dm
@@ -0,0 +1,4 @@
+/datum/modpack/clumsy_table
+ name = "Раскидывание на столах"
+ desc = "Причина по которой на столы не стоит лазать, не стоит по ним бегать, не стоит в них швырять, иначе предметы на них улетят во все стороны."
+ author = "PhantomRU, Vladisvell"
diff --git a/modular_ss220/clumsy_table/_clumsy_table.dme b/modular_ss220/clumsy_table/_clumsy_table.dme
new file mode 100644
index 000000000000..82516cf41c2f
--- /dev/null
+++ b/modular_ss220/clumsy_table/_clumsy_table.dme
@@ -0,0 +1,4 @@
+#include "_clumsy_table.dm"
+
+#include "code/clumsy_table.dm"
+#include "code/clumsy_climb_component.dm"
diff --git a/modular_ss220/clumsy_table/code/clumsy_climb_component.dm b/modular_ss220/clumsy_table/code/clumsy_climb_component.dm
new file mode 100644
index 000000000000..69ce54a64411
--- /dev/null
+++ b/modular_ss220/clumsy_table/code/clumsy_climb_component.dm
@@ -0,0 +1,86 @@
+/datum/component/clumsy_climb
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS // Only one of the component can exist on table
+ /// default for all human-sized livings
+ var/thrown_chance = 80
+ /// force damage modifier
+ var/force_mod = 0.1
+ // max current possible thrown objects
+ var/max_thrown_objects = 15
+ // max possible thrown objects when not forced
+ var/max_thrown_objects_low = 5
+
+/datum/component/clumsy_climb/Initialize()
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+/datum/component/clumsy_climb/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, PROC_REF(cross))
+ RegisterSignal(parent, COMSIG_CLIMBED_ON, PROC_REF(cross))
+ RegisterSignal(parent, COMSIG_DANCED_ON, PROC_REF(cross))
+
+/datum/component/clumsy_climb/UnregisterFromParent()
+ UnregisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_CLIMBED_ON, COMSIG_DANCED_ON))
+
+/datum/component/clumsy_climb/proc/cross(atom/table, mob/living/user)
+ SIGNAL_HANDLER
+ INVOKE_ASYNC(src, PROC_REF(try_clumsy), table, user)
+
+/datum/component/clumsy_climb/proc/try_clumsy(atom/table, mob/living/user)
+ if(!table.contents)
+ return
+
+ if(!istype(user))
+ return
+
+ if(user.mob_size <= MOB_SIZE_SMALL && !user.throwing)
+ return
+
+ max_thrown_objects = initial(max_thrown_objects)
+ if(!user.throwing)
+ max_thrown_objects = max_thrown_objects_low
+
+ throw_items(user)
+
+
+/datum/component/clumsy_climb/proc/throw_items(mob/living/user)
+ if(!user)
+ return
+
+ switch(user.mob_size)
+ if(MOB_SIZE_LARGE)
+ thrown_chance = 100
+ if(MOB_SIZE_SMALL)
+ thrown_chance = 20
+ if(MOB_SIZE_TINY)
+ thrown_chance = 10
+
+ if(HAS_TRAIT(user, TRAIT_CLUMSY))
+ thrown_chance += 20
+ if(user.mind?.miming)
+ thrown_chance -= 30
+
+ thrown_chance = clamp(thrown_chance, 1, 100)
+
+ var/list/items_to_throw = list()
+
+ var/turf/user_turf = get_turf(user)
+ for(var/obj/item/candidate_to_throw in user_turf)
+ if(length(items_to_throw) >= max_thrown_objects)
+ break
+
+ if(candidate_to_throw.anchored || !prob(thrown_chance))
+ continue
+
+ items_to_throw += candidate_to_throw
+
+ for(var/obj/item/item_to_throw as anything in items_to_throw)
+ var/atom/thrown_target = get_edge_target_turf(user, get_dir(user_turf, get_step_away(item_to_throw, user_turf)))
+ item_to_throw.throw_at(target = thrown_target, range = 1, speed = 1)
+ item_to_throw.force *= force_mod
+ item_to_throw.throwforce *= force_mod //no killing using shards :lul:
+ item_to_throw.pixel_x = rand(-10, 10)
+ item_to_throw.pixel_y = rand(-4, 16)
+ item_to_throw.force /= force_mod
+ item_to_throw.throwforce /= force_mod
+
+ qdel(src)
diff --git a/modular_ss220/clumsy_table/code/clumsy_table.dm b/modular_ss220/clumsy_table/code/clumsy_table.dm
new file mode 100644
index 000000000000..3edfd64c3c18
--- /dev/null
+++ b/modular_ss220/clumsy_table/code/clumsy_table.dm
@@ -0,0 +1,10 @@
+/obj/structure/table/Crossed(atom/movable/AM, oldloc)
+ AddComponent(/datum/component/clumsy_climb, 5)
+ . = ..()
+
+/obj/structure/table/do_climb(mob/living/user)
+ . = ..()
+ if(!.)
+ return FALSE
+ AddComponent(/datum/component/clumsy_climb, 15)
+ SEND_SIGNAL(src, COMSIG_CLIMBED_ON, user)
diff --git a/modular_ss220/crawl_speed/_crawl_speed.dm b/modular_ss220/crawl_speed/_crawl_speed.dm
new file mode 100644
index 000000000000..6c356c94c464
--- /dev/null
+++ b/modular_ss220/crawl_speed/_crawl_speed.dm
@@ -0,0 +1,4 @@
+/datum/modpack/crawl_speed
+ name = "Скорость ползания"
+ desc = "Ползание накладывает модификатор ходьбы."
+ author = "larentoun"
diff --git a/modular_ss220/crawl_speed/_crawl_speed.dme b/modular_ss220/crawl_speed/_crawl_speed.dme
new file mode 100644
index 000000000000..b81498fc1d27
--- /dev/null
+++ b/modular_ss220/crawl_speed/_crawl_speed.dme
@@ -0,0 +1,5 @@
+#include "_crawl_speed.dm"
+
+#include "code/_crawl_speed_defines.dm"
+#include "code/crawl_speed_mob.dm"
+#include "code/~crawl_speed_defines.dm"
diff --git a/modular_ss220/crawl_speed/code/_crawl_speed_defines.dm b/modular_ss220/crawl_speed/code/_crawl_speed_defines.dm
new file mode 100644
index 000000000000..a5484a523c35
--- /dev/null
+++ b/modular_ss220/crawl_speed/code/_crawl_speed_defines.dm
@@ -0,0 +1,2 @@
+#define CRAWL_SPEED_TRAIT "crawl-speed-trait"
+#define TRAIT_FORCE_WALK_SPEED "force_walk_speed"
diff --git a/modular_ss220/crawl_speed/code/crawl_speed_mob.dm b/modular_ss220/crawl_speed/code/crawl_speed_mob.dm
new file mode 100644
index 000000000000..dcfd2860433b
--- /dev/null
+++ b/modular_ss220/crawl_speed/code/crawl_speed_mob.dm
@@ -0,0 +1,13 @@
+/mob/living/carbon/set_body_position(new_value)
+ . = ..()
+ if(!.)
+ return
+ if(new_value == LYING_DOWN)
+ ADD_TRAIT(src, TRAIT_FORCE_WALK_SPEED, CRAWL_SPEED_TRAIT)
+ else
+ REMOVE_TRAIT(src, TRAIT_FORCE_WALK_SPEED, CRAWL_SPEED_TRAIT)
+
+/mob/living/carbon/movement_delay(ignorewalk)
+ . = ..()
+ if(m_intent != MOVE_INTENT_WALK && HAS_TRAIT(src, TRAIT_FORCE_WALK_SPEED))
+ . += GLOB.configuration.movement.base_walk_speed - GLOB.configuration.movement.base_run_speed
diff --git a/modular_ss220/crawl_speed/code/~crawl_speed_defines.dm b/modular_ss220/crawl_speed/code/~crawl_speed_defines.dm
new file mode 100644
index 000000000000..fa9dabba2795
--- /dev/null
+++ b/modular_ss220/crawl_speed/code/~crawl_speed_defines.dm
@@ -0,0 +1,2 @@
+#undef CRAWL_SPEED_TRAIT
+#undef TRAIT_FORCE_WALK_SPEED
diff --git a/modular_ss220/create_modpack.bat b/modular_ss220/create_modpack.bat
new file mode 100644
index 000000000000..4747e88f810f
--- /dev/null
+++ b/modular_ss220/create_modpack.bat
@@ -0,0 +1,13 @@
+@echo off
+set /p modpackName=Enter modpack name :
+
+xcopy "example" "%modpackName%" /s /i
+
+ren "%modpackName%\_example.dm" "_%modpackName%.dm"
+ren "%modpackName%\_example.dme" "_%modpackName%.dme"
+ren "%modpackName%\code\example.dm" "%modpackName%.dm"
+
+Powershell -Command "(Get-Content '%modpackName%\_%modpackName%.dm') -replace 'Example modpack', '%modpackName%' | Set-Content '%modpackName%\_%modpackName%.dm'"
+Powershell -Command "(Get-Content '%modpackName%\_%modpackName%.dme') -replace 'Example modpack', '%modpackName%' | Set-Content '%modpackName%\_%modpackName%.dme'"
+Powershell -Command "(Get-Content '%modpackName%\_%modpackName%.dm') -replace 'example', '%modpackName%' | Set-Content '%modpackName%\_%modpackName%.dm'"
+Powershell -Command "(Get-Content '%modpackName%\_%modpackName%.dme') -replace 'example', '%modpackName%' | Set-Content '%modpackName%\_%modpackName%.dme'"
diff --git a/modular_ss220/credits/_credits.dm b/modular_ss220/credits/_credits.dm
new file mode 100644
index 000000000000..ddace1d105dc
--- /dev/null
+++ b/modular_ss220/credits/_credits.dm
@@ -0,0 +1,9 @@
+/datum/modpack/credits
+ name = "Credits"
+ desc = "Добавление титров в конце раунда, основа кода была взята из данного репозитория https://github.com/Baystation12/Baystation12"
+ author = "Legendaxe"
+
+/datum/modpack/credits/initialize()
+ GLOB.admin_verbs_admin += list(
+ /client/proc/toggle_credits
+ )
diff --git a/modular_ss220/credits/_credits.dme b/modular_ss220/credits/_credits.dme
new file mode 100644
index 000000000000..7d1b97946084
--- /dev/null
+++ b/modular_ss220/credits/_credits.dme
@@ -0,0 +1,8 @@
+#include "code\SScredits.dm"
+#include "code\credits.dm"
+#include "code\admin_procs.dm"
+#include "code\halloween_credits.dm"
+#include "code\new_year_credits.dm"
+#include "code\aprils_fool_credits.dm"
+
+#include "_credits.dm"
diff --git a/modular_ss220/credits/code/SScredits.dm b/modular_ss220/credits/code/SScredits.dm
new file mode 100644
index 000000000000..a072165167fa
--- /dev/null
+++ b/modular_ss220/credits/code/SScredits.dm
@@ -0,0 +1,48 @@
+SUBSYSTEM_DEF(credits)
+ name = "Credits"
+ runlevels = RUNLEVEL_POSTGAME
+ flags = SS_NO_FIRE
+
+ var/datum/cinematic/credits/current_cinematic
+
+ var/datum/credits/end_titles
+ var/title_music = ""
+
+ var/credit_roll_speed = 22 SECONDS
+ var/credit_spawn_speed = 2 SECONDS
+ var/credit_animate_height
+
+/datum/controller/subsystem/credits/Initialize()
+ credit_animate_height = 16 * world.icon_size
+
+/datum/controller/subsystem/credits/proc/play_credits_cinematic()
+ var/cinematic_type
+
+ if(NEW_YEAR in SSholiday.holidays)
+ end_titles = new /datum/credits/new_year()
+ cinematic_type = /datum/cinematic/credits/new_year
+ else if(HALLOWEEN in SSholiday.holidays)
+ end_titles = new /datum/credits/halloween()
+ cinematic_type = /datum/cinematic/credits/halloween
+ else if(APRIL_FOOLS in SSholiday.holidays)
+ end_titles = new /datum/credits/aprils_fool()
+ cinematic_type = /datum/cinematic/credits
+ else
+ end_titles = new /datum/credits/default()
+ cinematic_type = /datum/cinematic/credits
+
+ title_music = end_titles.soundtrack
+
+ current_cinematic = play_cinematic(cinematic_type, world)
+
+/datum/controller/subsystem/credits/proc/roll_credits_for_clients(list/client/clients)
+ end_titles.roll_credits_for_clients(clients)
+
+/datum/controller/subsystem/credits/proc/clear_credits(client/client)
+ if(!client?.credits)
+ return
+
+ for(var/credit in client.credits)
+ client.screen -= credit
+
+ client.credits.Cut()
diff --git a/modular_ss220/credits/code/admin_procs.dm b/modular_ss220/credits/code/admin_procs.dm
new file mode 100644
index 000000000000..42c90fdc8f9e
--- /dev/null
+++ b/modular_ss220/credits/code/admin_procs.dm
@@ -0,0 +1,20 @@
+// Force everyone to watch credits?
+GLOBAL_VAR_INIT(credits_forced, FALSE)
+
+/client/proc/toggle_credits()
+ set category = "Server"
+ set desc = "Просмотр титров по окончании раунда"
+ set name = "Toggle Credits"
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ GLOB.credits_forced = !GLOB.credits_forced
+ if(GLOB.credits_forced)
+ to_chat(world, "Все будут смотреть титры по окончании раунда.")
+ message_admins("[key_name_admin(usr)] устанавливает принудительные титры.", 1)
+ else
+ to_chat(world, "Игроки будут смотреть титры в зависимости от своих настроек.")
+ message_admins("[key_name_admin(usr)] устанавливает титры по умолчанию.", 1)
+ log_admin("[key_name(usr)] toggled credits.")
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Credits")
diff --git a/modular_ss220/credits/code/aprils_fool_credits.dm b/modular_ss220/credits/code/aprils_fool_credits.dm
new file mode 100644
index 000000000000..dc01ab085b11
--- /dev/null
+++ b/modular_ss220/credits/code/aprils_fool_credits.dm
@@ -0,0 +1,24 @@
+/datum/credits/aprils_fool/fill_credits()
+ credits += new /datum/credit/episode_title/aprils_fool()
+
+ var/list/jokes = file2list("config/credits/aprils_fool/jokes.txt")
+ jokes.Remove("")
+
+
+ for(var/i = 0, i < 7, i++)
+ var/joke = pick(jokes)
+ credits += new /datum/credit/joke(joke)
+ jokes -= joke
+
+ credits += new /datum/credit/crewlist()
+
+ credits += new /datum/credit/disclaimer()
+
+/datum/credit/episode_title/aprils_fool/New()
+ var/mob/living/carbon/human/fool = pick(GLOB.alive_mob_list| GLOB.dead_mob_list)
+ content += "
"
+
+/datum/credit/disclaimer
+
+/datum/credit/disclaimer/New()
+ . = ..()
+
+ var/disclaimer = " Sponsored by WYCCSTATION. All rights reserved. \
+ This motion picture is protected under the copyright laws of the Sol Central Government and other nations throughout the galaxy. \
+ Colony of First Publication: [pick("Mars", "Luna", "Earth", "Venus", "Phobos", "Ceres", "Tiamat", "Ceti Epsilon", "Eos", "Pluto", "Ouere",\
+ "Tadmor", "Brahe", "Pirx", "Iolaus", "Saffar", "Gaia")]. "
+ disclaimer += pick("Use for parody prohibited. PROHIBITED.",
+ "All stunts were performed by underpaid interns. Do NOT try at home.",
+ "WYCCSTATION does not endorse behaviour depicted. Attempt at your own risk.",
+ "No animals were harmed in the making of this motion picture except for those listed previously as dead. Do not try this at home.")
+ content += ""
+ content += "
Отчет о состоянии на 11.8.2489 в 8:09 утра по Лавалендскому времени
Ничего необычного. Система сейсмического предупреждения сообщает о скором землетрясении, но Скотт сказал мне, что исправит это к выходным. Нам пришлось перенести некоторые эксперименты на следующую среду из-за поломки оборудования, но ничего серьезного, чтобы беспокоиться.
Подпись: Доктор Джеймс Уокер
"
+
+
+/obj/item/paper/scp/seismic_warning
+ name = "СЕЙСМИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ"
+ info = "ЭТО АВТОМАТИЧЕСКОЕ СООБЩЕНИЕ, ГЕНЕРИРУЕМОЕ СИСТЕМОЙ ПРЕДУПРЕЖДЕНИЯ О СЕЙСМИЧЕСКИХ ЯВЛЕНИЯХ (c).
К ЮГО-ВОСТОКУ БЫЛИ ЗАФИКСИРОВАНЫ СЛАБЫЕ ТОЛЧКИ. СОГЛАСНО НАШЕМУ ТЕКУЩЕМУ АЛГОРИТМУ, СЕЙСМИЧЕСКАЯ НЕСТАБИЛЬНОСТЬ РАСПРОСТРАНИТСЯ ДО ВАШЕГО ТЕКУЩЕГО МЕСТОПОЛОЖЕНИЯ.
МЫ ПРОГНОЗИРУЕМ 67,2% ВЕРОЯТНОСТЬ ВОЗНИКНОВЕНИЯ ЗНАЧИТЕЛЬНОГО ЗЕМЛЕТРЯСЕНИЯ В ВАШЕМ ТЕКУЩЕМ МЕСТОПОЛОЖЕНИИ ЧЕРЕЗ 6-12 ЧАСОВ. ПОЖАЛУЙСТА, ДЕЙСТВУЙТЕ В СООТВЕТСТВИИ С ПРОТОКОЛОМ УГРОЗЫ ЗЕМЛЕТРЯСЕНИЯ, КАК УКАЗАНО НА СТРАНИЦЕ 515 РАЗДЕЛА 61-X РУКОВОДСТВА ПО ЭКСПЛУАТАЦИИ ОБЪЕКТА САО."
+
+/obj/item/paper/scp/research_notes
+ name = "Заметки об исследованиях: Объекты 15-25"
+ info = "AO-15:
Охрана: Высокая Информация: Странное существо, извлеченное из старого шахтерского астероида. Темная кожа, пронзительные красные глаза. Очень агрессивное. Кажется разумным.
AO-16:
Защита: Средняя Информация: Капюшон и мантия. Красный цвет. Испускает поле темной энергии, которое гравирует все материалы вблизи на нем нерасшифрованные узоры. Предполагается, что он связан с культом УДАЛЕНО
AO-17:
Охрана: Аполлион Информация: УДАЛЕНО связано с УДАЛЕНО, которое нельзя размещать ни при каких обстоятельствах, включая УДАЛЕНО. Примечание ЦК: Зона 21 отсутствует. Необходимы меры безопасности.Перенос в зону 11-Х запланирован на УДАЛЕНО.
Несколько абзацев выделены черным маркером...
AO-21:
Безопасность: низкая Информация: Глазная железа, извлеченная из АО-6 во время эксперимента EX-56b. Очень агрессивна. После нарушения 91-А субъект был нейтрализован с помощью раствора ядов. Субъекту необходимо вводить раствор каждые полчаса, чтобы поддерживать его в полукоматозном состоянии. Рецепт раствора хранится в архивах Зоны 11-X.
Остальная часть бумаги покрыта каракулями странных символов, сделанных из засохшей крови."
+
+/obj/item/paper/caves/pacman
+ name = "Напоминание главного техника"
+ info = "Стажёрчик, последний, мать твою, раз тебе объясняю. Генератор НАСТРОЕН!!! Ты просто заправляешь его топливом, ждешь пока СМЕС прогреется и ВСЕ!!! Еще раз я увижу как ты ковыряешься в проводке - с треском вылетишь к паукам."
+
+/*Black Mesa*/
+//Tapes (Переводик бы. UPD.Че то перевел даже)
+/obj/item/tape/black_mesa/first_eas //First EAS record, the local disaster.
+ icon_state = "tape_blue"
+ desc = "Старая компакт-кассета. Видимо, использовалась начинающим радиолюбителем."
+
+ used_capacity = 240
+ storedinfo = list(
+ 1 = "Универсальный диктофонвоспроизводит, \"Начало записи.\"",
+ 2 = "Оповещение EASобъявляет, \"Следующее сообщение передается по запросу местных властей.\"",
+ 3 = "Оповещение EASсообщает, \"В 9:47 утра по стандартному времени в исследовательском центре Black Mesa произошла катастрофа неизвестного типа, вызвавшая значительный ущерб и сбой в работе различных систем электроснабжения и связи в прилегающих районах.\"",
+ 4 = "Оповещение EASутверждает, \"Местными властями отдан приказ о немедленной эвакуации всех жителей в радиусе 75 миль от объекта, на место были направлены силы самообороны для оказания помощи.\"",
+ 5 = "Оповещение EASзаявляет, \"Убедитесь, что при вас имеются аварийный запас еды, воды, одежды, аптечка первой помощи, фонарики с дополнительными батарейками и радиоприемники на батарейках.\"",
+ 6 = "Оповещение EASоповещает, \"Следуйте местным маршрутам эвакуации, обозначенным местными властями. Используйте только одно транспортное средство.\"",
+ 7 = "Оповещение EASпредупреждает, \"НЕ возвращайтесь в карантинную зону, пока властями не будет отданой прямой приказ об обратном.\"",
+ 8 = "Оповещение EASсообщает, \"Если вы не находитесь в зоне эвакуации, оставайтесь на месте.\"",
+ 9 = "Оповещение EASсообщает, \"Если вы находитесь в зоне эвакуации и у вас нет транспорта, проследуйте в ближайшее отделение местного правопорядка.\"",
+ 10 = "Оповещение EASсообщает, \"Не используйте никаких средств связи, за исключением радиоприемника.\"",
+ 11 = "Оповещение EASaсообщает, \"Следите за новостями местных СМИ для получения дополнительной информации о текущей ситуации...\"",
+ 12 = "Универсальный диктофонвоспроизводит, \"Конец записи.\"",
+ )
+ timestamp = list(
+ 1 = 0,
+ 2 = 20,
+ 3 = 40,
+ 4 = 80,
+ 5 = 100,
+ 6 = 120,
+ 7 = 140,
+ 8 = 160,
+ 9 = 180,
+ 10 = 200,
+ 11 = 220,
+ 12 = 240,
+ )
+
+/obj/item/tape/black_mesa/second_eas //Second EAS record, the local disaster.
+ icon_state = "tape_white"
+ desc = "Компакт-кассета со следами крови. Видимо, использовалась начинающим радиолюбителем (ныне покойным)."
+
+ used_capacity = 240
+ storedinfo = list(
+ 1 = "Универсальный диктофонвоспроизводит, \"Начало записи.\"",
+ 2 = "Оповещение EASгромко оповещает, \"Следующее сообщение передается по запросу депортамента экстренных служб сектора Нова.\"",
+ 3 = "Оповещение EASзаявляет, \"В 9:47 утра по стандартному времени в исследовательском центре Black Mesa произошла катастрофа неизвестного типа, вызвавшая значительный ущерб и сбой в работе различных систем электроснабжения и связи в прилегающих районах.\"",
+ 4 = "Оповещение EASуточняет, \"Сегодняшнее сообщение заменяет предыдущее, вышедшее вчера в 22:01 по стандартному времени.\"",
+ 5 = "Оповещение EASповторяет, \"В районе Black Mesa объявлен полный карантин. В интересах общественной безопасности всем жителям сектора Нова, проживающим в радиусе 150 миль от Black Mesa рекомендуется немедленно эвакуироваться.\"",
+ 6 = "Оповещение EASзаявляет, \"Возьмите с собой только предметы первой необходимости и радиоприемник на батарейках. Не используйте для поездок более одного транспортного средства.\"",
+ 7 = "Оповещение EASпредупреждает, \"Следуйте местным маршрутам эвакуации, которые были обозначены властями.\"",
+ 8 = "Оповещение EASобъявляет, \"Если вы находитесь в зоне эвакуации и у вас нет транспорта, проследуйте в ближайшее отделение местного правопорядка.\"",
+ 9 = "Оповещение EASзаявляет, \"Если вы отмечаете у себя лихорадку, кашель, тошноту, рвоту, головокружение, мышечные боли, выпадение волос или любые иные недуги... \"",
+ 10 = "Оповещение EASгромко оповещает, \"..пожалуйста, немедленно обратитесь в ближайший центр контроля заболеваний, так как эти симптомы могут быть связаны с произошедшей катастрофой .\"",
+ 11 = "Оповещение EASобъявляет, \"Следите за новостями местных СМИ для получения дополнительной информации о текущей ситуации.\"",
+ 12 = "Универсальный диктофонвоспроизводит, \"Конец записи.\"",
+ )
+ timestamp = list(
+ 1 = 0,
+ 2 = 20,
+ 3 = 40,
+ 4 = 80,
+ 5 = 100,
+ 6 = 120,
+ 7 = 140,
+ 8 = 160,
+ 9 = 180,
+ 10 = 200,
+ 11 = 220,
+ 12 = 240,
+ )
+
+/obj/item/tape/black_mesa/third_eas //Third EAS record, the global disaster.
+ icon_state = "tape_purple"
+ desc = "Компакт-кассета со следами... странной лозы, прорастающей внутрь. Видимо, использовалась каким то ксеносом."
+
+ used_capacity = 260
+ storedinfo = list(
+ 1 = "Универсальный диктофонвоспроизводит, \"Начало записи.\"",
+ 2 = "Оповещение EASобъявляет, \"Следующее сообщение передается по запросу Министерства Самообороны планеты Рикс-6. Это не учебная тревога.\"",
+ 3 = "Оповещение EASзаявляет, \"Сегодня, в 16:16 по стандартному времени, Высший Управитель Рикс-6 объявил чрезвычайное положение.\"",
+ 4 = "Оповещение EASуточняет, \"Неизвестные враждебно настроенные силы были обнаружены в исследовательском центре Black Mesa, а так же в нескольких соседних секторах, прилегающих к сектору Нова.\"",
+ 5 = "Оповещение EASгромко оповещает, \"По состоянию на 17:42 по стандартному времени, Верховный Управитель издал указ о мобилизации всех наземных сил самообороны...\"",
+ 6 = "Оповещение EASгромко оповещает, \"....и начать немедленные авиаудары по исследовательскому центру Black Mesa и прилегающим секторам, начиная не позднее 18:42 этим вечером.\"",
+ 7 = "Оповещение EASпредупреждает, \"Для вашей собственной безопасности был отдан приказ о немедленной эвакуации по всему сектору Нова.\"",
+ 8 = "Оповещение EASзаявляет, \"Всем жителям сектора Нова и прилегающих районов, просьба оставить все свои личные вещи. Возьмите с собой радиоприемник на батарейках и только самые необходимые бытовые принадлежности.\"",
+ 9 = "Оповещение EASпредупреждает, \"Не оставайтесь в своих домах! Найдите убежище в ближайшей к вам зоне сил самообороны за пределами сектора Нова и ждите дальнейших указаний.\"",
+ 10 = "Оповещение EASоповещает, \"Если вы не можете найти ближайший маршрут эвакуации, немедленно обратитесь за помощью к местным властям.\"",
+ 11 = "Оповещение EASechoes, \"Если у вас имеются навыки военной подготовки, навыки стрельбы из огнестрельного или энергетического оружия - немедленно обратитесь к ближайшему офицеру сил самообороны..\"",
+ 12 = "Оповещение EASуточняет, \"Оставайтесь на частоте 740 для получения дополнительной информации.\"",
+ 13 = "Универсальный диктофонвоспроизводит, \"Конец записи.\"",
+ )
+ timestamp = list(
+ 1 = 0,
+ 2 = 20,
+ 3 = 40,
+ 4 = 80,
+ 5 = 100,
+ 6 = 120,
+ 7 = 140,
+ 8 = 160,
+ 9 = 180,
+ 10 = 200,
+ 11 = 220,
+ 12 = 240,
+ 13 = 260,
+ )
+
+/obj/item/tape/black_mesa/first_hecu //First HECU record, the "You are abandoned" kinda one; meant to be added to SL so they're, you know, informed. And depressed.
+ icon_state = "tape_purple"
+ desc = "Свежезаписанная компакт-кассета, еще даже не подписанная."
+
+ used_capacity = 100
+ storedinfo = list(
+ 1 = "Универсальный диктофонвоспроизводит, \"Начало записи.\"",
+ 2 = "Штаб сил самообороныспрашивает, \"Прием, офицер, вы меня слышите? Офицер, вы меня слышите!?\"",
+ 3 = "Штаб сил самооборонысообщает, \"Забудьте о ███████! Мы покидаем базу!\"",
+ 4 = "Штаб сил самооборонысообщает, \"Мы сокращаем наши потери и уходим! Все, кто остался там, внизу, сейчас предоставлены сами себе!\"",
+ 5 = "Штаб сил самообороныгромко оповещает, \"Повторяю, если вас еще не эвакуировались, то вы предоставлены сами себе!\"",
+ 6 = "Универсальный диктофонвоспроизводит, \"Конец записи.\"",
+ )
+ timestamp = list(
+ 1 = 0,
+ 2 = 20,
+ 3 = 40,
+ 4 = 60,
+ 5 = 80,
+ 6 = 100,
+ )
+
+/obj/item/tape/black_mesa/second_hecu //Second HECU record, for Vanguard to know that there's military nearby.
+ icon_state = "tape_red"
+ desc = "Относительно свежая компакт-кассета, подписанная как \"радиопередача от XX XX.XX.25XX\". Дата и серийные номера были поцарапаны до неузнаваемости. Как удобно."
+
+ used_capacity = 140
+ storedinfo = list(
+ 1 = "Универсальный диктофонвоспроизводит, \"Начало записи.\"",
+ 2 = "Эхо-5 Бравогромко сообщает, \"Любой станции, любой станции, это Эхо-5 Браво! Поблизости есть хоть какие то наземные силы, способные поддержать в 8 районе?\"",
+ 3 = "Эхо-5 Бравоповторно сообщает, \"Любой станции, любой станции, это Эхо-5 Браво! Поблизости есть хоть какие то наземные силы, способные поддержать в 8 районе? Хоть кто ниубдь слышит нас?!\"",
+ 4 = "Эхо-5 Зеттазаявляет, \"Это Эхо-5 Зетта! Больше не в состоянии вести боевые действия. Мы сворачиваемся в сторону сектора Дельта!\"",
+ 5 = "Эхо-5 Бравогромко спрашивает, \"Что, черт возьми, ты несешь?! Нас здесь давят в окружении!!!\"",
+ 6 = "Эхо-5 Зеттасообщает, \"Прорывайтесь к ближайшей трассе и ждите указаний, как слышали?!\"",
+ 7 = "Универсальный диктофонвоспроизводит, \"Конец записи.\"",
+ )
+ timestamp = list(
+ 1 = 0,
+ 2 = 20,
+ 3 = 40,
+ 4 = 80,
+ 5 = 100,
+ 6 = 120,
+ 7 = 140,
+ )
+
+/obj/item/tape/black_mesa/third_hecu //Third HECU record, because it's s a d .
+ icon_state = "tape_blue"
+ desc = "Окровавленная компакт-кассета. Это уже слишком..."
+
+ used_capacity = 120
+ storedinfo = list(
+ 1 = "Универсальный диктофонвоспроизводит, \"Начало записи.\"",
+ 2 = "Эхо-5 Джульеттагромко сообщает, \"Любой станции, любой станции, это Эхо-5 Джульетта... Мой отряд попал в засаду... Меня ранили... Я здесь истекаю кровью... Левая.. Левая нога.\"",
+ 3 = "Эхо-5 Ромеосообщает, \"Эхо-5 Джульетта, это Эхо-5 Ромео. Мне нужно что бы ты наложил жгут выше раны, на расстоянии ладони. Живо доставай его из своего ИПП!\"",
+ 4 = "Эхо-5 Джульеттазаявляет, \"ИПП больше нету.\"",
+ 5 = "Эхо-5 Ромеоспрашивает, \"Повтори?\"",
+ 6 = "Эхо-5 Джульеттауточняет, \"Мой ИПП закончился... Я..эээ... *отчетливый звук падения*\"",
+ 7 = "Эхо-5 Ромеосообщает, \"Так, тебе срочно нужно найти другой и достать из него жгут. \"",
+ 8 = "Эхо-5 Ромеогромко спрашивает, \"Ты еще на короткой? Эхо-5 Джульетта, ты меня слышишь?!\"",
+ 9 = "Универсальный диктофонвоспроизводит, \"Конец записи.\"",
+ )
+ timestamp = list(
+ 1 = 0,
+ 2 = 10,
+ 3 = 30,
+ 4 = 40,
+ 5 = 50,
+ 6 = 70,
+ 7 = 90,
+ 8 = 110,
+ 9 = 120,
+ )
+
+/*Space battle*/
+/obj/item/paper/spacebattle
+ icon = 'icons/obj/bureaucracy.dmi';
+ icon_state = "paper_words"
+
+/obj/item/paper/spacebattle/syndicate1
+ info = "
- Какого черта это было? - Группа, стоп... Сейчас свяжусь с этим кораблем. - Провожу сканирование... ... ... - Это корабль НТ! Полная боевая! - Сканеры показывают большое число турелей, подавите турели. ... - Абордажным командам занять поды! - Все готовы? - Так точно! - Запускайте поды!
"
+
+/obj/item/paper/spacebattle/syndicate2
+ info = "
- Всем носителям - выпускайте дроны. - Принял. Дроны пошли. ... - Это носитель DC-28... Агхх... Обшивка сильно повреждена, запрос эвакуации. - Принято, DC-28, отправляем под на ваши координаты. ... ... - Твою мать, у них есть БСА! Они только что разнесли под. - Сканирование не обнаружило орудие. - Дьявол, несем потери. ...
"
+
+/obj/item/paper/spacebattle/syndicate3
+ info = "
- Птичка-4, прием, мы на корабле, действуем согласно плану дельта-1. - Альфа, якорь пристыкован, активируем через 5, сейчас тряхнет. - 10-4. ... ... ... - Птичка-4, прием, экипаж уничтожен. У них на корабле гребаный БСА! - Альфа, ищите любые ценные документы. - Принято. ...
"
+
+// Механик правого борта
+/obj/item/paper/crumpled/bloody/spacebattle/mechanic
+ info = "
Я бортовой механик Нанотрейзен, состоящий в экипаже засекреченного крейсера 'Безымянный'. Если вы это читаете - я мертв. Несколько часов назад наша экспедиция отправилась на тестирование экспериментальной установки, начальство говорило, что она использует какой-то 'блюспейс' - передовую технологию. Хрен его знает что за голубое пространство, но видать оно очень ценно. После выстрела этой бандуры нас так тряхануло, что датчики взбесились - считали, что мы пересекли несколько десятков секторов, а календари показывали чуть ли не на 200 лет позже. Судно атаковали пираты, мы пытались отбится, но их слишком много. Думаю, что все остальные мертвы. Я забаррикадировался у себя в отсеке, ворота на палубу достаточно крепкие, пока есть время - попытаюсь собрать челнок. Нет ядра для челнока, чёрт, думаю есть шанс, что на мастерской левого борта будет хотя бы одно. Кажется, они догадались, что тех.тоннель ведет ко мне, надо рвать когти, пан или пропал.
"
+
+// Офицер в туалете
+/obj/item/paper/crumpled/bloody/spacebattle/officer
+ info = "
РАПОРТ
Лейтенант ТСФ Дребин, докладываю: 'Безымянный' под обстрелом, нас взяли на абордаж. После затяжного боя на палубах крейсера мы, видимо, проиграли... К черту эту корпортивную чушь! Мы притащили на борт крысу! Какая то сволочь точно слила наши координаты, ведь мы пробовали какую-то огромную пушку - они точно пришли за ней, только я не успел найти эту сволочь! Меня ранили... протяну от силы не больше часа, мед у нас отбили почти сразу, как сука знали! Я выберусь отсюда, я не умру в туале "
+
+// Желе в холодильнике
+/obj/item/paper/spacebattle/kitchen
+ info = "
от Кока Рэмси Капитану 'Безымянного'
Капитан, после выстрела из вашей погремушки у меня в холодильнике завелся вредитель! Я открыл холодильник, а там на меня смотрело желе! Я не готовил это сраное желе! ОНО СМОТРИТ НА МЕНЯ! Прошу, пришлите кого-то, хотя бы яйцеголовых, я не могу работать, КОГДА НА МЕНЯ СМОТРИТ ЭТО!
"
+
+// Задача на вылет крейсера
+/obj/item/paper/spacebattle/bridge
+ info = "
Форма NTcorp. NT-CC-REQ Станция — Центральное командование Год: 2367
Распоряжение Центрального командования
Командование судна 'Безымянный', ваш крейсер был оснащен экспериментальной установкой под кодовым именем БСА - рассекречивание наличия данной установки, принципов её работы и любые упоминания о её существование вне экипажа и высшего командования строго запрещены! Ваша задача: После полного прочтения данных директив, совершить вылет из системы, после чего будут получены координаты засекреченного испытательного полигона для тестирования данной установки. Требуется произвести минимум 3 выстрела с рассчетным интервалом в 30-40 минут, что обуславливает время необходимое для заряда батарей установки от экспериментального двигателя, использующего осколок суперматерии. Последний выстрел необходимо произвести во время сверхсветового скачка на максимально возможной скорости. Затем вернутся в док с соответствующей отчетной документацией для получения новых распоряжений. Подпись: ███████ ████████ , в должности: Nanotrasen Navy Officer. *Несоблюдение указаний, содержащихся в данном документе, считается нарушением политики компании; Дисциплинарное взыскание за нарушения может быть применено на месте или в конце смены в Центральном командовании; *Получатель(и) данного меморандума подтверждает(ют), что он(она/они) несут ответственность за любой ущерб, который может возникнуть в результате игнорирования приведенных здесь директив или рекомендаций; *Все отчеты должны храниться конфиденциально их предполагаемым получателем и любой соответствующей стороной. Несанкционированное распространение данного меморандума может привести к дисциплинарным взысканиям. "
+
+//Бортовой журнал
+/obj/item/paper/docs_part/spacebattle/bridge2
+ info = "
Форма NTcorp. NT-COM-BB Судно — ЭКН 'Безымянный' Год: 2367 Бортовой журнал ██.03.2367 - Вылет. Док №2, ИОН ███████, █████ спутник планеты █████ системы ███████ ██████-█. ██.03.2367 - Прибыли на координаты ████, ████, ██ - ████████, планета ████████, система ██████████-███. ██.03.2367 - Начато испытание установки ███. ██.03.2367 - Произведен залп из ███ по мишени №1. Переход к мишени №2. ██.03.2367 - Произведен залп из ███ по мишени №2. Переход к задаче №3. Запуск сверхсветовых двигателей. ██.03.2367 - Произведен залп из ███ во время сверхсветовоого скачка при достижении нагрузки на ССД двигатели = 95% ██.̴̼̝̐͌͠0̴͓̦̝͘͝͠6̴̡̦͙͐̓̐.̴͉̘͙̓͛͊2̴͓͒̔̈́͜4̴͙͎͊͌͌͜6̵̞̟̘̈́́̚7̴̙͉̝̓̐͘ -̵͓͇̾̐̚͜ О̴͍̟͓̽̒͘б̴̢̪͍͒͋̈́н̴̠̼̪̒̿́а̴̢͉͕͛͐͝р̵̢͓́̈́у̴̫̟̓̾̚͜ж̴̝̞̽̀̚е̸̡͎̦͌̓͐н̸͉̦̞͋͊͘ с̵̺͖̞͛̀͝б̴̦͔͍̒͛͋о̸̠̟́̒̿й̴̢̘͙͆̚͝ с̵̡̺͉̒̚̚ӥ̸͖͓͍́͒͆с̴̙͎͉͒͌͑т̴͓̫͊̀͜е̴͓͖͎͒͛̀м̸̺̼͐̈́̾ы̵̞̪͋͐̕͜.̸͔̝͖́͆̀ О̸̡̫̼̾͑͘б̸̺̦͊͜͠͠р̸̢̺͚̕͝͝а̵͇̟͇͐̐͋т̵̟̪͛͘͘͜и̴̢͎͙͐̾т̴̞̾̿̈́͜е̸͙͖͍̓̔с̸͍͙̙͆̀̾ь̴̟͕̺̓͋͛ к̴̺͖͔̿̈́ б̵͖̻͎͐̓͘о̵̦͕̦͊͘͠р̴̢̻̞̔̈́̚т̴͉̦̪͒̕͠о̸̞̺͊̾в̸͕͍̠̽̒̈́о̸͇̫̓͘͠м̸̡͖̪̓͆͊у̸̡͍͒͛̿ т̸͉̼̐͐͝е̴̡͓̞͋͠х̴͖̙͖̚͘͝н̵͍͙̒̐̚͜и̴̻̻͇̽͋̚к̴̪͖̔̐͐у̸͚̪̼̀͋̾.̵͍͚͔͑͒̽ ██.̴͉̝̠̔͆͠0̸̞͍͓̐̽̈́9̵̢͍͙͋͛͊.̴͍͉̀͛2̸̟͔̘̽̀̈́4̴͖͔͙̓͝͝6̴̼͔̽͑͝7̵̟̓͝͝ -̸̟͕͆́̓ О̵̡͖̘̓̔͝б̴̼̪̈́̽н̸̘̺͓͑̀͘а̵͇̦̓̾̚͜р̴͖̞͊̓̚ӱ̸̼̻́̔̿͜ж̴̟͚̒͌͝е̵̪̫̓͆͘н̵͍̈́̓͛͜ с̴̢̢̠͌̓͑б̴͚͎̞̔͐͝о̵͓͔̝̿͘͠й̵̺͚͙͒͝ с̵̘͇̾̽͜͠и̵̻̺͓̾̒̕с̴̻̝̀͋̚т̵̦̼͚͊̓̚е̴̟͇̼͌̈́̀м̸̝̪͕͌̾̒ы̴̫̟͓̓͛̓.̵͍͚̪̓͘͝ О̸̦̙̔̓̈́б̵̡͔̪͑̿̿р̵̫̪͙̽͋͑а̴̫͓̠̾̈́͘т̴̡͓͙̔̚͝и̵͎͙͉͛̈́͛т̵͙̼͉́̈́͒е̵͕͓̦͒͘͝с̵̪̘͍̔̿̈́ь̸̠̙͎̓̈́ к̵̡̡̙͆͒͝ б̵̡̻̚͝о̸͙͒͊̕͜р̴̪̟̺̿͑͝т̵̘͔͚́̐̕о̵̢̘͍͘̚͝в̵̡̫̙̀͌̚о̵͔̟̺̀̐̿м̸͍͓͔́̿̓у̵̢̡̦̐̈́̒ т̵̺̘͍͒̕͘е̵̞̺͇͐̔̕х̵̠͎͍͊̈́͒н̵̫͕̟̿̚и̵̙̼̿͜͝͝к̸͕̻̟̓͊͒у̸͓̠̘̔̿̿.̴̡͖̀͐̿ .ʎdoꓕɐdꓕɔиниᥕჩɐ ʎᥕoнᥕǝꓕɔиɔ ʞ ৭ɔǝꓕиꓕɐdܦО .ыᥕǝꓕɔиɔ и̯oܦɔ нǝжʎdɐнܦО - ↋↊0↊.↋0.↋0 ██.丨己.己丩67 - 乃ы尸闩⻏廾и⻏闩廾и🝗 爪ㄖ⼭廾ㄖ⼕ти ⼕и⼕т🝗爪ы. 闩⻏闩尸ий廾ый ⼕石尸ㄖ⼕ ⼕长ㄖ尸ㄖ⼕ти ⼕⻏🝗尸〤⼕⻏🝗тㄖ⻏ы〤 具⻏и⺁闩т🝗人🝗й. ██.██.2567 - Выход из сверхсветового коридора. координаты ████,████,██ - Поле астериодов. ██.██.2567 - Обнаружено физическое нарушение целостности двигательного отсека. ██.██.2567 - Обнаружены разгерметизации левого борта: двигательный отсек, секция ЭМР-2, левый ангар. ██.██.██67 - Нарушение целостности корпуса судна. Запуск протокола 'Черный Ящик' ██.██.████ - Н███шен█е це██ст███ти к█рп█с█. З█п█ск пр███кола 'Шифрат█р.NT' ██.██.████ - █████████████████████████████. █████████████████████████... ██.██.████ - ███████ ██████████ ███ - ███████ ████ █████: '███████████ ██████' ██████████ - ████████████████████████████████..."
+
+// Капитан говнит экипаж на воксовском
+/obj/item/paper/spacebattle/voxcap
+ info = "
Дешифрованное сообщение с вокс-пиджина К'цай, ты не поверишь куда я попал! Эти пылевые мешки все-таки позвали меня рулить их кораблем! Говорят, у нас будет нормальное дело на поживится всяким НТшным добром, готовьте скипджек, вышлю координаты как будем собираться возвращаться.
Командир, мы вообще не поняли подобного юмора - вокс?! Мы понимаем, что эти чашуйчатые говнюки грабят только так, это у них в крови или той хрени, что у них течет в жилах, но ВОКС-КАПИТАН? Мы не будем терпеть этого мудака, он успел обосрать половину составва, называя то лысыми, то пылевиками, то еще как-то, если он выпрется из каюты и еще выдаст хоть какую-то хрень на своем чик-чирике мы его порешаем на месте!
"
+
+// Механик центрального корабля
+/obj/item/paper/spacebattle/voxcap2
+ info = "
Личная запись
Бортовой техник: Позывной '12й' Эта крыса чашуйчатая опять полезла ко мне в ангар жрать запчасти от моих дронов. Я не могу грубить старшему, но у меня так половина дронов из строя выйдет, если эта скатина продолжит искать 'вкикикусненькикое' в них! Слыхал, что другие тоже недовольны положением, оно и видно - такую хрень поставили за главного! "
+
+// Бортовой журнал центрального корабля
+/obj/item/paper/slip/spacebattle/voxcap3
+ info = "
Обрывок бортового журнала
На корабле стоит напряженная атмосфера. Почти весь экипаж недоволен новым капитаном-воксом. Абсолютно непонятно где он раздобыл нужные документы, скорее всего, украл у какого-нибудь офицера. Из-за системы скрытых званий мы не можем точно интендифицировать подлинность его статуса. Нас выслали на срочное дело и не было времени на разборки, ввиду этого чашуйчатый стал руководить данным рейдом. По завершению задачи, кикпитан либо полетит за борт, либо отправится в самую темную задницу для выяснения откуда он достал удостоверение офицера. "
+
+// Секретное биоружие-мимики
+/obj/item/paper/spacebattle/mimics
+ info = "
Личная запись
Капитан рейдерского грузового судна: 'Легкий' Пит Недавно вафельные подогнали разработку биотехов - живые ящики! Говорят, что сами возят в таких товар, мол такие вора быстрее загрызут, чем он поймет что это не обычный ящик. Они как-то надрессировали эти штуки и говорят, что кидаются они только на чужих, я пока не пробовал, да и желания нет. Надеюсь, они не втюхали нам обычные ящики по завышенной цене. "
diff --git a/modular_ss220/maps220/code/spawners.dm b/modular_ss220/maps220/code/spawners.dm
new file mode 100644
index 000000000000..f5c97f091793
--- /dev/null
+++ b/modular_ss220/maps220/code/spawners.dm
@@ -0,0 +1,315 @@
+/* Random food spawners */
+/obj/effect/spawner/random/ccfood
+
+
+/obj/effect/spawner/random/ccfood/dessert
+ spawn_loot_count = 3
+ loot = list(
+ /obj/item/food/baguette,
+ /obj/item/food/applepie,
+ /obj/item/food/bananabreadslice,
+ /obj/item/food/bananacakeslice,
+ /obj/item/food/carrotcakeslice,
+ /obj/item/food/croissant,
+ /obj/item/reagent_containers/drinks/cans/cola,
+ )
+
+/obj/effect/spawner/random/ccfood/meat
+ spawn_loot_count = 3
+ loot = list(
+ /obj/item/food/lasagna,
+ /obj/item/food/burger/bigbite,
+ /obj/item/food/fishandchips,
+ /obj/item/food/fishburger,
+ /obj/item/food/hotdog,
+ /obj/item/food/meatpie,
+ /obj/item/reagent_containers/drinks/cans/cola,
+ )
+
+/obj/effect/spawner/random/ccfood/alcohol
+ spawn_loot_count = 1
+ loot = list(
+ /obj/item/reagent_containers/drinks/flask/detflask,
+ /obj/item/reagent_containers/drinks/cans/tonic,
+ /obj/item/reagent_containers/drinks/cans/thirteenloko,
+ /obj/item/reagent_containers/drinks/cans/synthanol,
+ /obj/item/reagent_containers/drinks/cans/space_mountain_wind,
+ /obj/item/reagent_containers/drinks/cans/lemon_lime,
+ )
+
+/* Lootdrop */
+/obj/effect/spawner/random/maintenance
+ icon = 'modular_ss220/maps220/icons/spawner_icons.dmi'
+
+/obj/effect/spawner/random/trash
+ icon = 'modular_ss220/maps220/icons/spawner_icons.dmi'
+
+/obj/effect/spawner/random/trash/Initialize(mapload)
+ . = ..()
+ loot += list(
+ list(
+ /obj/item/trash/bowl,
+ /obj/item/trash/can,
+ /obj/item/trash/candle,
+ /obj/item/trash/candy,
+ /obj/item/trash/cheesie,
+ /obj/item/trash/chips,
+ /obj/item/trash/fried_vox,
+ /obj/item/trash/gum,
+ /obj/item/trash/liquidfood,
+ /obj/item/trash/pistachios,
+ /obj/item/trash/plate,
+ /obj/item/trash/popcorn,
+ /obj/item/trash/raisins,
+ /obj/item/trash/semki,
+ /obj/item/trash/snack_bowl,
+ /obj/item/trash/sosjerky,
+ /obj/item/trash/spacetwinkie,
+ /obj/item/trash/spentcasing,
+ /obj/item/trash/syndi_cakes,
+ /obj/item/trash/tapetrash,
+ /obj/item/trash/tastybread,
+ /obj/item/trash/tray,
+ /obj/item/trash/waffles,
+ /obj/item/trash/vulpix_chips,
+ /obj/item/trash/foodtray,
+ ) = 5,
+ )
+
+// Office toys spawner
+/obj/effect/spawner/random/officetoys
+ name = "office desk toy spawner"
+ icon = 'modular_ss220/maps220/icons/spawner_icons.dmi'
+ icon_state = "officetoy"
+ loot = list(
+ /obj/item/toy/desk/officetoy,
+ /obj/item/toy/desk/dippingbird,
+ /obj/item/toy/desk/newtoncradle,
+ /obj/item/toy/desk/fan,
+ /obj/item/hourglass
+ )
+
+/* Random spawners */
+/obj/effect/spawner/random/mod
+ icon = 'modular_ss220/maps220/icons/spawner_icons.dmi'
+ icon_state = "mod"
+
+/obj/effect/spawner/random/syndicate/loot
+ icon = 'modular_ss220/maps220/icons/spawner_icons.dmi'
+
+/obj/effect/spawner/random/syndicate/loot/common
+ icon_state = "common"
+
+/obj/effect/spawner/random/syndicate/loot/rare
+ icon_state = "rare"
+
+/obj/effect/spawner/random/syndicate/loot/officer
+ icon_state = "officer"
+
+/obj/effect/spawner/random/syndicate/loot/armory
+ icon_state = "armory"
+
+/obj/effect/spawner/random/syndicate/loot/stetchkin
+ icon_state = "stetchkin"
+
+/obj/item/reagent_containers/pill/random_drugs
+ icon = 'modular_ss220/maps220/icons/spawner_icons.dmi'
+ icon_state = "pills"
+
+/obj/item/reagent_containers/pill/random_drugs/Initialize(mapload)
+ icon = 'icons/obj/chemical.dmi'
+ . = ..()
+
+/obj/item/reagent_containers/drinks/bottle/random_drink
+ icon = 'modular_ss220/maps220/icons/spawner_icons.dmi'
+ icon_state = "drinks"
+
+/obj/item/reagent_containers/drinks/bottle/random_drink/Initialize(mapload)
+ icon = 'icons/obj/drinks.dmi'
+ . = ..()
+
+/* Space Battle */
+/obj/effect/mob_spawn/human/corpse/spacebattle
+ var/list/pocketloot = list(/obj/item/storage/fancy/cigarettes/cigpack_robust,
+ /obj/item/storage/fancy/cigarettes/cigpack_uplift,
+ /obj/item/storage/fancy/cigarettes/cigpack_random,
+ /obj/item/cigbutt,
+ /obj/item/clothing/mask/cigarette/menthol,
+ /obj/item/clothing/mask/cigarette,
+ /obj/item/clothing/mask/cigarette/random,
+ /obj/item/lighter/random,
+ /obj/item/assembly/igniter,
+ /obj/item/storage/fancy/matches,
+ /obj/item/match,
+ /obj/item/food/donut,
+ /obj/item/food/candy/candybar,
+ /obj/item/food/tastybread,
+ /obj/item/reagent_containers/drinks/cans/dr_gibb,
+ /obj/item/pen,
+ /obj/item/screwdriver,
+ /obj/item/stack/tape_roll,
+ /obj/item/radio,
+ /obj/item/coin,
+ /obj/item/coin/twoheaded,
+ /obj/item/coin/iron,
+ /obj/item/coin/silver,
+ /obj/item/flashlight,
+ /obj/item/stock_parts/cell,
+ /obj/item/paper/crumpled,
+ /obj/item/extinguisher/mini,
+ /obj/item/deck/cards,
+ /obj/item/reagent_containers/pill/salbutamol,
+ /obj/item/reagent_containers/patch/silver_sulf/small,
+ /obj/item/reagent_containers/patch/styptic/small,
+ /obj/item/reagent_containers/pill/salicylic,
+ /obj/item/stack/medical/bruise_pack,
+ /obj/item/stack/medical/ointment,
+ /obj/item/tank/internals/emergency_oxygen,
+ /obj/item/weldingtool/mini,
+ /obj/item/flashlight/flare/glowstick/emergency,
+ /obj/item/flashlight/flare,
+ /obj/item/toy/crayon/white,
+ )
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/Initialize(mapload)
+ l_pocket = pick(pocketloot)
+ r_pocket = pick(pocketloot)
+ return ..()
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/assistant
+ name = "Dead Civilian"
+ mob_name = "Ship Personnel"
+ id = /obj/item/card/id/away/old
+ uniform = /obj/item/clothing/under/color/random
+ shoes = /obj/item/clothing/shoes/black
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/security
+ name = "Dead Officer"
+ mob_name = "Ship Officer"
+ id = /obj/item/card/id/away/old/sec
+ uniform = /obj/item/clothing/under/retro/security
+ belt = /obj/item/clothing/accessory/holster/waist
+ suit = /obj/item/clothing/suit/armor/vest/security
+ shoes = /obj/item/clothing/shoes/jackboots
+ head = /obj/item/clothing/head/helmet
+ gloves = /obj/item/clothing/gloves/fingerless
+ back = /obj/item/storage/backpack/satchel_sec
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/security/Initialize(mapload)
+ var/secgun = rand(1,10)
+ switch(secgun)
+ //70%
+ if(1 to 7)
+ suit_store = /obj/item/gun/projectile/automatic/pistol/enforcer/lethal
+ backpack_contents = list(
+ /obj/item/storage/box/survival = 1,
+ /obj/item/ammo_box/magazine/enforcer/lethal = 1
+ )
+ //20%
+ if(8 to 9)
+ suit_store = /obj/item/gun/projectile/automatic/wt550
+ backpack_contents = list(
+ /obj/item/storage/box/survival = 1,
+ /obj/item/ammo_box/magazine/wt550m9 = 1
+ )
+ //10%
+ if(10)
+ suit_store = /obj/item/gun/projectile/shotgun/riot
+ backpack_contents = list(
+ /obj/item/storage/box/survival = 1,
+ /obj/item/storage/fancy/shell/buck = 1
+ )
+ return ..()
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/engineer
+ name = "Dead Engineer"
+ mob_name = "Engineer"
+ id = /obj/item/card/id/away/old/eng
+ uniform = /obj/item/clothing/under/retro/engineering
+ belt = /obj/item/storage/belt/utility/full
+ suit = /obj/item/clothing/suit/storage/hazardvest
+ shoes = /obj/item/clothing/shoes/workboots
+ mask = /obj/item/clothing/mask/gas
+ head = /obj/item/clothing/head/hardhat/orange
+ glasses = /obj/item/clothing/glasses/meson
+ suit_store = /obj/item/tank/internals/emergency_oxygen/engi
+ gloves = /obj/item/clothing/gloves/color/fyellow/old
+ back = /obj/item/storage/backpack/duffel/engineering
+ backpack_contents = /obj/item/storage/box/engineer
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/engineer/Initialize(mapload)
+ var/engstaff = rand(1,3)
+ switch(engstaff)
+ if(1)
+ backpack_contents = list(
+ /obj/item/clothing/head/welding = 1,
+ /obj/item/weldingtool/largetank = 1,
+ /obj/item/stack/sheet/metal{amount = 10} = 1,
+ /obj/item/stack/rods{amount = 3} = 1
+ )
+ if(2)
+ backpack_contents = list(
+ /obj/item/apc_electronics = 1,
+ /obj/item/stock_parts/cell/high = 1,
+ /obj/item/t_scanner = 1,
+ /obj/item/stack/cable_coil{amount = 7} = 1
+ )
+ if(3)
+ backpack_contents = list(
+ /obj/item/storage/briefcase/inflatable = 1,
+ /obj/item/stack/sheet/glass{amount = 5} = 1,
+ /obj/item/grenade/gas/oxygen = 1,
+ /obj/item/analyzer = 1
+ )
+ return ..()
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/engineer/space
+ suit = /obj/item/clothing/suit/space/hardsuit/ancient
+ head = /obj/item/clothing/head/helmet/space/hardsuit/ancient
+ shoes = /obj/item/clothing/shoes/magboots
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/medic
+ name = "Dead Medic"
+ mob_name = "Medic"
+ id = /obj/item/card/id/away/old/med
+ uniform = /obj/item/clothing/under/retro/medical
+ suit = /obj/item/clothing/suit/storage/labcoat
+ shoes = /obj/item/clothing/shoes/white
+ id = /obj/item/card/id/medical
+ back = /obj/item/storage/backpack/satchel_med
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/medic/Initialize(mapload)
+ backpack_contents = list(
+ /obj/item/storage/firstaid/regular = 1,
+ /obj/item/storage/pill_bottle/random_drug_bottle = 1,
+ )
+ return ..()
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/bridgeofficer
+ name = "Bridge Officer"
+ mob_name = "Bridge Officer"
+ id = /obj/item/card/id/away/old/sec
+ uniform = /obj/item/clothing/under/rank/procedure/blueshield{name = "Bridge Officer uniform"}
+ belt = /obj/item/clothing/accessory/holster/waist
+ suit = /obj/item/clothing/suit/armor/vest/security
+ shoes = /obj/item/clothing/shoes/jackboots
+ head = /obj/item/clothing/head/helmet/night
+ gloves = /obj/item/clothing/gloves/fingerless
+ back = /obj/item/storage/backpack/satchel
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/bridgeofficer/Initialize(mapload)
+ backpack_contents = list(
+ /obj/item/reagent_containers/patch/silver_sulf/small,
+ /obj/item/reagent_containers/patch/styptic/small,
+ /obj/item/stock_parts/cell/high = 1,
+ /obj/item/storage/fancy/shell/buck = 1
+ )
+ return ..()
+
+/obj/effect/mob_spawn/human/corpse/spacebattle/scientist
+ name = "Dead Scientist"
+ mob_name = "Scientist"
+ id = /obj/item/card/id/away/old/sci
+ uniform = /obj/item/clothing/under/retro/science
+ shoes = /obj/item/clothing/shoes/black
+ suit = /obj/item/clothing/suit/storage/labcoat/science
diff --git a/modular_ss220/maps220/code/walls.dm b/modular_ss220/maps220/code/walls.dm
new file mode 100644
index 000000000000..2ac9418ada3d
--- /dev/null
+++ b/modular_ss220/maps220/code/walls.dm
@@ -0,0 +1,132 @@
+/* Indestructible */
+/turf/simulated/wall/indestructible/rock/mineral
+ name = "dense rock"
+ desc = "An extremely densely-packed rock, Most mining tools or explosives would never get through this."
+ icon = 'icons/turf/walls//smoothrocks.dmi'
+ icon_state = "smoothrocks-0"
+ base_icon_state = "smoothrocks"
+ color = COLOR_ROCK
+ smoothing_flags = SMOOTH_BITMASK | SMOOTH_BORDER
+ smoothing_groups = list(SMOOTH_GROUP_SIMULATED_TURFS, SMOOTH_GROUP_MINERAL_WALLS)
+ canSmoothWith = list(SMOOTH_GROUP_MINERAL_WALLS)
+
+/turf/simulated/wall/indestructible/cult
+ name = "runed metal wall"
+ icon = 'icons/turf/walls/cult_wall.dmi'
+ icon_state = "cult_wall-0"
+ base_icon_state = "cult_wall"
+ smoothing_flags = SMOOTH_BITMASK
+ canSmoothWith = list(SMOOTH_GROUP_WALLS, SMOOTH_GROUP_CULT_WALLS)
+
+/* White Shuttle */
+/turf/simulated/wall/indestructible/whiteshuttle
+ name = "wall"
+ desc = "A light-weight titanium wall used in shuttles."
+ icon = 'icons/turf/walls/plastinum_wall.dmi'
+ icon_state = "plastinum_wall-0"
+ base_icon_state = "plastinum_wall"
+ explosion_block = 3
+ flags_ricochet = RICOCHET_SHINY | RICOCHET_HARD
+ sheet_type = /obj/item/stack/sheet/mineral/titanium
+ smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS
+ smoothing_groups = list(SMOOTH_GROUP_TITANIUM_WALLS, SMOOTH_GROUP_WINDOW_FULLTILE_SHUTTLE)
+ canSmoothWith = list(SMOOTH_GROUP_TITANIUM_WALLS, SMOOTH_GROUP_AIRLOCK, SMOOTH_GROUP_SHUTTLE_PARTS, SMOOTH_GROUP_WINDOW_FULLTILE_SHUTTLE)
+
+/turf/simulated/wall/indestructible/whiteshuttle/nodiagonal
+ icon_state = "map-shuttle_nd"
+ smoothing_flags = SMOOTH_BITMASK
+
+/turf/simulated/wall/indestructible/whiteshuttle/nosmooth
+ smoothing_flags = NONE
+
+/turf/simulated/wall/indestructible/whiteshuttle/overspace
+ icon_state = "map-overspace"
+ smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS
+ fixed_underlay = list("space" = TRUE)
+
+// sub-type to be used for interior shuttle walls
+// won't get an underlay of the destination turf on shuttle move
+/turf/simulated/wall/indestructible/whiteshuttle/interior/copyTurf(turf/T)
+ if(T.type != type)
+ T.ChangeTurf(type)
+ if(underlays.len)
+ T.underlays = underlays
+ if(T.icon_state != icon_state)
+ T.icon_state = icon_state
+ if(T.icon != icon)
+ T.icon = icon
+ if(color)
+ T.atom_colours = atom_colours.Copy()
+ T.update_atom_colour()
+ if(T.dir != dir)
+ T.setDir(dir)
+ T.transform = transform
+ return T
+
+/turf/simulated/wall/indestructible/whiteshuttle/copyTurf(turf/T)
+ . = ..()
+ T.transform = transform
+
+/* Syndie Shuttle */
+/turf/simulated/wall/indestructible/syndishuttle
+ name = "wall"
+ desc = "An evil wall of plasma and titanium."
+ icon = 'icons/turf/walls/plastitanium_wall.dmi'
+ icon_state = "plastitanium_wall-0"
+ base_icon_state = "plastitanium_wall"
+ explosion_block = 4
+ sheet_type = /obj/item/stack/sheet/mineral/plastitanium
+ smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS
+ smoothing_groups = list(SMOOTH_GROUP_PLASTITANIUM_WALLS)
+ canSmoothWith = list(SMOOTH_GROUP_PLASTITANIUM_WALLS, SMOOTH_GROUP_AIRLOCK, SMOOTH_GROUP_SHUTTLE_PARTS)
+
+/turf/simulated/wall/indestructible/syndishuttle/nodiagonal
+ icon_state = "map-shuttle_nd"
+ base_icon_state = "plastitanium_wall"
+ smoothing_flags = SMOOTH_BITMASK
+
+/turf/simulated/wall/indestructible/syndishuttle/nosmooth
+ smoothing_flags = NONE
+
+/turf/simulated/wall/indestructible/syndishuttle/overspace
+ icon_state = "map-overspace"
+ smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS
+ fixed_underlay = list("space" = TRUE)
+
+/turf/simulated/wall/indestructible/syndishuttle/interior/copyTurf(turf/T)
+ if(T.type != type)
+ T.ChangeTurf(type)
+ if(underlays.len)
+ T.underlays = underlays
+ if(T.icon_state != icon_state)
+ T.icon_state = icon_state
+ if(T.icon != icon)
+ T.icon = icon
+ if(color)
+ T.atom_colours = atom_colours.Copy()
+ T.update_atom_colour()
+ if(T.dir != dir)
+ T.setDir(dir)
+ T.transform = transform
+ return T
+
+/turf/simulated/wall/indestructible/syndishuttle/copyTurf(turf/T)
+ . = ..()
+ T.transform = transform
+
+/* False Wall */
+/obj/structure/falsewall/bookcase
+ name = "bookcase"
+ desc = "Bookcase made of tropical wood. All the books are covered with a thick layer of dust, except for one..."
+ icon = 'modular_ss220/maps220/icons/bookcase_wall.dmi'
+ icon_state = "fbookcase_wall-0"
+ base_icon_state = "fbookcase_wall"
+ mineral = /obj/item/stack/sheet/wood
+ walltype = /turf/simulated/wall/mineral/wood
+ smoothing_flags = null
+ smoothing_groups = null
+ canSmoothWith = null
+
+/*Black Mesa*/
+/turf/simulated/wall/indestructible/rock/mineral/xen
+ color = "#4e1a02"
diff --git a/modular_ss220/maps220/icons/3x3.dmi b/modular_ss220/maps220/icons/3x3.dmi
new file mode 100644
index 000000000000..a1f65a0d135b
Binary files /dev/null and b/modular_ss220/maps220/icons/3x3.dmi differ
diff --git a/modular_ss220/maps220/icons/areas.dmi b/modular_ss220/maps220/icons/areas.dmi
new file mode 100644
index 000000000000..a73470565a07
Binary files /dev/null and b/modular_ss220/maps220/icons/areas.dmi differ
diff --git a/modular_ss220/maps220/icons/bookcase_wall.dmi b/modular_ss220/maps220/icons/bookcase_wall.dmi
new file mode 100644
index 000000000000..1dc604243fa5
Binary files /dev/null and b/modular_ss220/maps220/icons/bookcase_wall.dmi differ
diff --git a/modular_ss220/maps220/icons/chairs.dmi b/modular_ss220/maps220/icons/chairs.dmi
new file mode 100644
index 000000000000..5cd8aa4e8e37
Binary files /dev/null and b/modular_ss220/maps220/icons/chairs.dmi differ
diff --git a/modular_ss220/maps220/icons/clown_mobs.dmi b/modular_ss220/maps220/icons/clown_mobs.dmi
new file mode 100644
index 000000000000..d962055a966c
Binary files /dev/null and b/modular_ss220/maps220/icons/clown_mobs.dmi differ
diff --git a/modular_ss220/maps220/icons/crates.dmi b/modular_ss220/maps220/icons/crates.dmi
new file mode 100644
index 000000000000..2c3cbcdfae54
Binary files /dev/null and b/modular_ss220/maps220/icons/crates.dmi differ
diff --git a/modular_ss220/maps220/icons/decals.dmi b/modular_ss220/maps220/icons/decals.dmi
new file mode 100644
index 000000000000..2872ce2d8710
Binary files /dev/null and b/modular_ss220/maps220/icons/decals.dmi differ
diff --git a/modular_ss220/maps220/icons/effects.dmi b/modular_ss220/maps220/icons/effects.dmi
new file mode 100644
index 000000000000..c55226d6e8aa
Binary files /dev/null and b/modular_ss220/maps220/icons/effects.dmi differ
diff --git a/modular_ss220/maps220/icons/flags.dmi b/modular_ss220/maps220/icons/flags.dmi
new file mode 100644
index 000000000000..e943ebe1f7a0
Binary files /dev/null and b/modular_ss220/maps220/icons/flags.dmi differ
diff --git a/modular_ss220/maps220/icons/floors.dmi b/modular_ss220/maps220/icons/floors.dmi
new file mode 100644
index 000000000000..2bb04fe9164b
Binary files /dev/null and b/modular_ss220/maps220/icons/floors.dmi differ
diff --git a/modular_ss220/maps220/icons/freeman.dmi b/modular_ss220/maps220/icons/freeman.dmi
new file mode 100644
index 000000000000..620995bc8445
Binary files /dev/null and b/modular_ss220/maps220/icons/freeman.dmi differ
diff --git a/modular_ss220/maps220/icons/machinery.dmi b/modular_ss220/maps220/icons/machinery.dmi
new file mode 100644
index 000000000000..6d04b512b19b
Binary files /dev/null and b/modular_ss220/maps220/icons/machinery.dmi differ
diff --git a/modular_ss220/maps220/icons/mapping_helpers.dmi b/modular_ss220/maps220/icons/mapping_helpers.dmi
new file mode 100644
index 000000000000..98f6b9118df8
Binary files /dev/null and b/modular_ss220/maps220/icons/mapping_helpers.dmi differ
diff --git a/modular_ss220/maps220/icons/mesaflora.dmi b/modular_ss220/maps220/icons/mesaflora.dmi
new file mode 100644
index 000000000000..a21cb1e3894b
Binary files /dev/null and b/modular_ss220/maps220/icons/mesaflora.dmi differ
diff --git a/modular_ss220/maps220/icons/misc_objects.dmi b/modular_ss220/maps220/icons/misc_objects.dmi
new file mode 100644
index 000000000000..d6c3b91c8867
Binary files /dev/null and b/modular_ss220/maps220/icons/misc_objects.dmi differ
diff --git a/modular_ss220/maps220/icons/nanotrasen_logo.dmi b/modular_ss220/maps220/icons/nanotrasen_logo.dmi
new file mode 100644
index 000000000000..ba509221aac3
Binary files /dev/null and b/modular_ss220/maps220/icons/nanotrasen_logo.dmi differ
diff --git a/modular_ss220/maps220/icons/nihilanth.dmi b/modular_ss220/maps220/icons/nihilanth.dmi
new file mode 100644
index 000000000000..5e1c2ad3f0ae
Binary files /dev/null and b/modular_ss220/maps220/icons/nihilanth.dmi differ
diff --git a/modular_ss220/maps220/icons/plants.dmi b/modular_ss220/maps220/icons/plants.dmi
new file mode 100644
index 000000000000..74bb1ae1d967
Binary files /dev/null and b/modular_ss220/maps220/icons/plants.dmi differ
diff --git a/modular_ss220/maps220/icons/shuttle.dmi b/modular_ss220/maps220/icons/shuttle.dmi
new file mode 100644
index 000000000000..4a08e8a79b18
Binary files /dev/null and b/modular_ss220/maps220/icons/shuttle.dmi differ
diff --git a/modular_ss220/maps220/icons/simple_human.dmi b/modular_ss220/maps220/icons/simple_human.dmi
new file mode 100644
index 000000000000..71131c48ef90
Binary files /dev/null and b/modular_ss220/maps220/icons/simple_human.dmi differ
diff --git a/modular_ss220/maps220/icons/spacebattle.dmi b/modular_ss220/maps220/icons/spacebattle.dmi
new file mode 100644
index 000000000000..37532e09589b
Binary files /dev/null and b/modular_ss220/maps220/icons/spacebattle.dmi differ
diff --git a/modular_ss220/maps220/icons/spawner_icons.dmi b/modular_ss220/maps220/icons/spawner_icons.dmi
new file mode 100644
index 000000000000..cff4c17b607b
Binary files /dev/null and b/modular_ss220/maps220/icons/spawner_icons.dmi differ
diff --git a/modular_ss220/maps220/icons/syndie_logo.dmi b/modular_ss220/maps220/icons/syndie_logo.dmi
new file mode 100644
index 000000000000..dd7c1eff1015
Binary files /dev/null and b/modular_ss220/maps220/icons/syndie_logo.dmi differ
diff --git a/modular_ss220/maps220/icons/trees.dmi b/modular_ss220/maps220/icons/trees.dmi
new file mode 100644
index 000000000000..2885ef1d7483
Binary files /dev/null and b/modular_ss220/maps220/icons/trees.dmi differ
diff --git a/modular_ss220/maps220/icons/wish_granter.dmi b/modular_ss220/maps220/icons/wish_granter.dmi
new file mode 100644
index 000000000000..7e9afcdf1696
Binary files /dev/null and b/modular_ss220/maps220/icons/wish_granter.dmi differ
diff --git a/modular_ss220/mecha_skins/code/fabricator_design.dm b/modular_ss220/mecha_skins/code/fabricator_design.dm
new file mode 100644
index 000000000000..08cdb86a0d62
--- /dev/null
+++ b/modular_ss220/mecha_skins/code/fabricator_design.dm
@@ -0,0 +1,235 @@
+/obj/machinery/mecha_part_fabricator/Initialize(mapload)
+ . = ..()
+
+ categories.Insert(categories.Find("Exosuit Equipment")+1, "Exosuit Paintkits")
+
+// Paintkits
+/datum/design/paint_ripley_titan
+ name = "Ripley, Firefighter \"Titan's Fist\""
+ id = "p_titan"
+ build_type = MECHFAB
+ req_tech = list("programming" = 4, "materials" = 2)
+ build_path = /obj/item/paintkit/ripley_titansfist
+ materials = list(MAT_METAL=20000, MAT_PLASMA=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_ripley_earth
+ name = "Ripley, Firefighter \"Strike the Earth!\""
+ id = "p_earth"
+ build_type = MECHFAB
+ req_tech = list("combat" = 4, "materials" = 2)
+ build_path = /obj/item/paintkit/ripley_gurren
+ materials = list(MAT_METAL=10000, MAT_PLASMA=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_ripley_red
+ name = "Ripley, Firefighter \"Firestarter\""
+ id = "p_red"
+ build_type = MECHFAB
+ req_tech = list("engineering" = 4, "materials" = 2)
+ build_path = /obj/item/paintkit/ripley_red
+ materials = list(MAT_METAL=10000, MAT_PLASMA=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_firefighter_hauler
+ name = "Ripley, Firefighter \"Hauler\""
+ id = "p_hauler"
+ build_type = MECHFAB
+ req_tech = list("biotech" = 4, "materials" = 2)
+ build_path = /obj/item/paintkit/firefighter_hauler
+ materials = list(MAT_METAL=10000, MAT_PLASMA=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_firefighter_zairjah
+ name = "Ripley, Firefighter \"Zairjah\""
+ id = "p_zairjah"
+ build_type = MECHFAB
+ req_tech = list("engineering" = 4, "materials" = 2)
+ build_path = /obj/item/paintkit/firefighter_zairjah
+ materials = list(MAT_METAL=10000, MAT_PLASMA=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_firefighter_combat
+ name = "Ripley, Firefighter \"Combat Ripley\""
+ id = "p_combat"
+ build_type = MECHFAB
+ req_tech = list("combat" = 4, "materials" = 2)
+ build_path = /obj/item/paintkit/firefighter_combat
+ materials = list(MAT_METAL=10000, MAT_PLASMA=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_firefighter_aluminizer
+ name = "Ripley, Firefighter \"Aluminizer\""
+ id = "p_aluminizer"
+ build_type = MECHFAB
+ req_tech = list("engineering" = 4, "materials" = 2)
+ build_path = /obj/item/paintkit/firefighter_aluminizer
+ materials = list(MAT_METAL=10000, MAT_PLASMA=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_firefighter_reaper
+ name = "Ripley, Firefighter \"Reaper\""
+ id = "p_reaper"
+ build_type = MECHFAB
+ req_tech = list("combat" = 5, "toxins" = 5)
+ build_path = /obj/item/paintkit/firefighter_reaper
+ materials = list(MAT_METAL=10000, MAT_PLASMA=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_odysseus_hermes
+ name = "Odysseus \"Hermes\""
+ id = "p_hermes"
+ build_type = MECHFAB
+ req_tech = list("engineering" = 5, "biotech" = 5)
+ build_path = /obj/item/paintkit/odysseus_hermes
+ materials = list(MAT_METAL=20000, MAT_GOLD=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_odysseus_reaper
+ name = "Odysseus \"Reaper\""
+ id = "p_odyreaper"
+ build_type = MECHFAB
+ req_tech = list("combat" = 5, "biotech" = 5)
+ build_path = /obj/item/paintkit/odysseus_death
+ materials = list(MAT_METAL=20000, MAT_GOLD=2000, MAT_GLASS=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_gygax_alt
+ name = "Gygax \"Old\""
+ id = "p_altgygax"
+ build_type = MECHFAB
+ req_tech = list("combat" = 4, "engineering" = 5, "materials" = 5, "programming" = 4)
+ build_path = /obj/item/paintkit/gygax_alt
+ materials = list(MAT_METAL=30000, MAT_GLASS =3000)
+ construction_time = 20 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_gygax_pobeda
+ name = "Gygax \"Pobeda\""
+ id = "p_pobedagygax"
+ build_type = MECHFAB
+ req_tech = list("combat" = 5, "engineering" = 4, "materials" = 4, "programming" = 6)
+ build_path = /obj/item/paintkit/gygax_pobeda
+ materials = list(MAT_METAL=30000, MAT_DIAMOND=3000, MAT_URANIUM= 3000)
+ construction_time = 20 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_gygax_white
+ name = "Gygax \"White\""
+ id = "p_whitegygax"
+ build_type = MECHFAB
+ req_tech = list("biotech" = 4, "engineering" = 4, "materials" = 5, "programming" = 3)
+ build_path = /obj/item/paintkit/gygax_white
+ materials = list(MAT_METAL=30000, MAT_TITANIUM=3000, MAT_URANIUM= 3000)
+ construction_time = 20 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_gygax_mime
+ name = "Gygax \"Recitence\""
+ id = "p_gygax_mime"
+ build_type = MECHFAB
+ req_tech = list("biotech" = 4, "engineering" = 4, "materials" = 5, "programming" = 3)
+ build_path = /obj/item/paintkit/gygax_mime
+ materials = list(MAT_METAL=30000, MAT_TITANIUM=3000, MAT_TRANQUILLITE= 2000)
+ construction_time = 20 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_gygax_medgax
+ name = "Gygax \"Medgax\""
+ id = "p_medgax"
+ build_type = MECHFAB
+ req_tech = list("biotech" = 4, "engineering" = 4, "materials" = 5, "programming" = 3)
+ build_path = /obj/item/paintkit/gygax_medgax
+ materials = list(MAT_METAL=30000, MAT_TITANIUM=3000, MAT_URANIUM= 3000)
+ construction_time = 20 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_gygax_black
+ name = "Gygax \"Syndicate\""
+ id = "p_blackgygax"
+ build_type = MECHFAB
+ req_tech = list("combat" = 6, "engineering" = 5, "syndicate" = 3)
+ build_path = /obj/item/paintkit/gygax_syndie
+ materials = list(MAT_METAL=30000, MAT_TRANQUILLITE=2000, MAT_DIAMOND=4000)
+ construction_time = 20 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_durand_unathi
+ name = "Durand \"Kharn MK. IV\""
+ id = "p_unathi"
+ build_type = MECHFAB
+ req_tech = list("materials" = 6, "biotech" = 6)
+ build_path = /obj/item/paintkit/durand_unathi
+ materials = list(MAT_METAL=40000, MAT_TITANIUM=4000, MAT_URANIUM=4000)
+ construction_time = 30 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_durand_shire
+ name = "Durand \"Shire\""
+ id = "p_shire"
+ build_type = MECHFAB
+ req_tech = list("combat" = 6, "engineering" = 6, "materials" = 6, "programming" = 6)
+ build_path = /obj/item/paintkit/durand_shire
+ materials = list(MAT_METAL=40000, MAT_TRANQUILLITE=2000, MAT_TITANIUM=4000)
+ construction_time = 30 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_durand_soviet
+ name = "Durand \"Dollhouse\""
+ id = "p_soviet"
+ build_type = MECHFAB
+ req_tech = list("combat" = 6, "engineering" = 6, "materials" = 6, "programming" = 6)
+ build_path = /obj/item/paintkit/durand_soviet
+ materials = list(MAT_METAL=40000, MAT_DIAMOND=4000, MAT_URANIUM=4000, MAT_TITANIUM=4000)
+ construction_time = 30 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_phazon_imperion
+ name = "Phazon \"Imperion\""
+ id = "p_imperion"
+ build_type = MECHFAB
+ req_tech = list("bluespace" = 7, "engineering" = 6, "materials" = 6, "programming" = 6)
+ build_path = /obj/item/paintkit/phazon_imperion
+ materials = list(MAT_METAL=50000, MAT_DIAMOND=4000, MAT_BLUESPACE=4000)
+ construction_time = 40 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_phazon_janus
+ name = "Phazon \"Janus\""
+ id = "p_janus"
+ build_type = MECHFAB
+ req_tech = list("bluespace" = 7, "engineering" = 6, "materials" = 6, "programming" = 6)
+ build_path = /obj/item/paintkit/phazon_janus
+ materials = list(MAT_METAL=50000, MAT_DIAMOND=4000, MAT_BLUESPACE=4000)
+ construction_time = 40 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_phazon_plazmus
+ name = "Phazon \"Plazmus\""
+ id = "p_plazmus"
+ build_type = MECHFAB
+ req_tech = list("bluespace" = 7, "engineering" = 6, "materials" = 6)
+ build_path = /obj/item/paintkit/phazon_plazmus
+ materials = list(MAT_METAL=50000, MAT_DIAMOND=4000, MAT_PLASMA=5000)
+ construction_time = 40 SECONDS
+ category = list("Exosuit Paintkits")
+
+/datum/design/paint_phazon_blanco
+ name = "Phazon \"Blanco\""
+ id = "p_blanco"
+ build_type = MECHFAB
+ req_tech = list("bluespace" = 7, "engineering" = 7, "materials" = 7)
+ build_path = /obj/item/paintkit/phazon_blanco
+ materials = list(MAT_METAL=50000, MAT_DIAMOND=4000, MAT_BLUESPACE=4000)
+ construction_time = 40 SECONDS
+ category = list("Exosuit Paintkits")
diff --git a/modular_ss220/mecha_skins/code/paintkit_install.dm b/modular_ss220/mecha_skins/code/paintkit_install.dm
new file mode 100644
index 000000000000..75333809bc92
--- /dev/null
+++ b/modular_ss220/mecha_skins/code/paintkit_install.dm
@@ -0,0 +1,191 @@
+/obj/mecha/attackby__legacy__attackchain(obj/item/W, mob/user, params)
+ if(!istype(W, /obj/item/paintkit))
+ return ..()
+ if(occupant)
+ to_chat(user, span_warning("Вы не можете кастомизировать экзокостюм, пока кто-то его пилотирует - это небезопасно!"))
+ return
+
+ var/obj/item/paintkit/P = W
+ var/found = null
+
+ for(var/type in P.allowed_types)
+ if(type == initial_icon)
+ found = 1
+ break
+
+ if(!found)
+ to_chat(user, span_warning("Этот комплект не предназначен для использования на экзокостюме данного класса."))
+ return
+
+ user.visible_message(
+ span_notice("[user] открывает [P] и проводит некоторое время за кастомизацией [src]."),
+ span_notice("Вы открываете [P] и начинаете кастомизировать [src]."))
+ if(!do_after_once(user, 3 SECONDS, target = src))
+ to_chat(user, span_warning("Вы должны стоять смирно при настройке экзокостюма!"))
+ return
+ name = P.new_name
+ desc = P.new_desc
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ initial_icon = P.new_icon
+ wreckage = P.new_wreckage
+ reset_icon()
+ qdel(P)
+
+/obj/mecha/go_out(forced, atom/newloc = loc)
+ . = ..()
+ icon_state = reset_icon(icon_state)+"-open"
+
+// MARK: Ripley
+
+/obj/structure/mecha_wreckage/ripley/titan
+ name = "\improper Обломки \"Кулака Титана\""
+ desc = "А что вы ожидали от реплики?"
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "titan-broken"
+
+/obj/structure/mecha_wreckage/ripley/gurren
+ name = "\improper Обломки \"Strike The Earth!\""
+ desc = "Настоящий мех не умрет, даже если его разрушить. Не должно мужчине ходить повесив голову, Симон!"
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "earth-broken"
+
+/obj/structure/mecha_wreckage/ripley/red
+ name = "\improper Обломки \"Поджигателя\""
+ desc = "А горит то как..."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "ripley_flames_red-broken"
+
+/obj/structure/mecha_wreckage/ripley/hauler
+ name = "\improper Обломки \"Тягача\""
+ desc = "Этот мех отработал своё..."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "hauler-broken"
+
+/obj/structure/mecha_wreckage/ripley/zairjah
+ name = "\improper Обломки \"Зари\""
+ desc = "Впрочем, никакая модификация не спасет вас от реальности."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "ripley_zairjah-broken"
+
+/obj/structure/mecha_wreckage/ripley/combat
+ name = "\improper Обломки боевого Рипли"
+ desc = "Надо было ставить больше ракет..."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "combatripley-broken"
+
+/obj/structure/mecha_wreckage/ripley/aluminizer
+ name = "\improper Обломки \"Алюминатора\""
+ desc = "Слишком выделялся..."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "aluminizer-broken"
+
+/obj/structure/mecha_wreckage/ripley/reaper
+ name = "\improper Обломки \"Жнеца\""
+ desc = "От греха подальше эти обломки лучше еще и взорвать..."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "deathripley-broken"
+
+// MARK: Odysseus
+
+/obj/structure/mecha_wreckage/odysseus/hermes
+ name = "\improper Обломки \"Гермеса\""
+ desc = "Рождённый плавать бегать не умеет.."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "hermes-broken"
+
+/obj/structure/mecha_wreckage/odysseus/reaper
+ name = "\improper Обломки \"Жнеца\""
+ desc = ".. а пыль развеять по ветру."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "murdysseus-broken"
+
+// MARK: Gygax
+
+/obj/structure/mecha_wreckage/gygax/medigax
+ name = "\improper Обломки \"Медигакса\""
+ desc = "Шприц был не лучшим оружием на перестрелке."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "medigax-broken"
+
+/obj/structure/mecha_wreckage/gygax/old
+ name = "\improper Обломки старого Гигакса"
+ desc = "Удивительно, как он не развалился раньше."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "gygax_alt-broken"
+
+/obj/structure/mecha_wreckage/gygax/pobeda
+ name = "\improper Обломки \"Победы\""
+ desc = "Не выдержал проверку временем.."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "pobeda-broken"
+
+/obj/structure/mecha_wreckage/gygax/whitegax
+ name = "\improper Обломки белого Гигакса"
+ desc = "Краска не повреждена. Забавно."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "whitegax-broken"
+
+/obj/structure/mecha_wreckage/gygax/mimegax
+ name = "\improper Обломки \"Молчигакса\""
+ desc = "..."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "mime-broken"
+
+/obj/structure/mecha_wreckage/gygax/gygax_black
+ name = "\improper Обломки черного Гигакса"
+ desc = "Логотип Синдиката все ещё на месте. Хм..."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "gygax_black-broken"
+
+// MARK: Durand
+
+/obj/structure/mecha_wreckage/durand/dollhouse
+ name = "\improper Обломки \"Кукольного домика\""
+ desc = "Теперь больше похож на дырявый сарай.."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "dollhouse-broken"
+
+/obj/structure/mecha_wreckage/durand/unathi
+ name = "\improper Обломки \"Кхарн MK. IV\""
+ desc = "Душу за Императницу!"
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "unathi-broken"
+
+/obj/structure/mecha_wreckage/durand/shire
+ name = "\improper Обломки \"Шир\""
+ desc = "Это всего лишь тестовый образец.."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "shire-broken"
+
+/obj/structure/mecha_wreckage/durand/skull
+ name = "\improper Обломки \"Скелемеха\""
+ desc = "Ужасающие останки нечто, похожего на одного из боссов Лаваленда..."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "skullmech-broken"
+
+// MARK: Phazon
+
+/obj/structure/mecha_wreckage/phazon/imperion
+ name = "\improper Обломки \"Империона\""
+ desc = "Великая трагедия \"Нанотрейзен\", которая не останется незамеченной."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "imperion-broken"
+
+/obj/structure/mecha_wreckage/phazon/janus
+ name = "\improper Обломки \"Януса\""
+ desc = "Великая трагедия \"Нанотрейзен\", которая не останется незамеченной." //да у них одинаковое описание
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "janus-broken"
+
+/obj/structure/mecha_wreckage/phazon/plazmus
+ name = "\improper Обломки \"Плазмуса\""
+ desc = "Как жаль что даже этого не хватило."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "plazmus-broken"
+
+/obj/structure/mecha_wreckage/phazon/phazon_blanco
+ name = "\improper Обломки \"Бланко\""
+ desc = "Обломки полугода работы бедного художника и трех лет одобрения этого дизайна. Издевательство.."
+ icon = 'modular_ss220/mecha_skins/icons/mecha.dmi'
+ icon_state = "phazon_blanco-broken"
+
diff --git a/modular_ss220/mecha_skins/code/paintkit_menu.dm b/modular_ss220/mecha_skins/code/paintkit_menu.dm
new file mode 100644
index 000000000000..4012fb455659
--- /dev/null
+++ b/modular_ss220/mecha_skins/code/paintkit_menu.dm
@@ -0,0 +1,285 @@
+// Please don't use this for anything, it's a base type for custom mech paintjobs.
+/obj/item/paintkit
+ name = "Набор кастомизации меха"
+ desc = "Дефолтный набор кастомизации, превращающий мех в другой мех (визуально)."
+ icon = 'modular_ss220/mecha_skins/icons/paintkit.dmi'
+ icon_state = "paintkit"
+ // New type of wreckage
+ var/new_wreckage = null
+
+/obj/item/paintkit/titansfist
+ icon = 'icons/obj/painting.dmi'
+
+// MARK: Ripley
+
+/obj/item/paintkit/ripley_titansfist
+ name = "Набор кастомизации АЭП \"Кулак Титана\""
+ icon_state = "paintkit_titan"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Рипли в \"Кулак Титана\""
+
+ new_name = "АЭП \"Кулак Титана\""
+ new_desc = "Этот обычный шахтерский Рипли был переделан так, чтобы выглядеть как боевая единица Кулака Титанов."
+ new_icon = "titan"
+ allowed_types = list("ripley", "firefighter")
+ new_wreckage = /obj/structure/mecha_wreckage/ripley/titan
+
+/obj/item/paintkit/ripley_gurren
+ name = "Набор кастомизации АЭП \"Strike the Earth!\""
+ icon_state = "paintkit_earth"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Рипли в старый АЭП боевика."
+
+ new_name = "АЭП \"Strike the Earth!\""
+ new_desc = "Выглядит как сильно поврежденный от бесконечной работы Рипли. Вам померещилось, или в кабине горят зеленые огни?..."
+ new_icon = "earth"
+ allowed_types = list("ripley", "firefighter")
+ new_wreckage = /obj/structure/mecha_wreckage/ripley/gurren
+
+/obj/item/paintkit/ripley_red
+ name = "Набор кастомизации АЭП \"Поджигатель\""
+ icon_state = "paintkit_red"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Рипли в АЭП \"Поджигатель\"."
+
+ new_name = "АЭП \"Поджигатель\""
+ new_desc = "Стандарный АЭП с стильными огненными декалями."
+ new_icon = "ripley_flames_red"
+ allowed_types = list("ripley", "firefighter")
+ new_wreckage = /obj/structure/mecha_wreckage/ripley/red
+
+/obj/item/paintkit/firefighter_hauler
+ name = "Набор кастомизации АЭП \"Тягач\""
+ icon_state = "paintkit_hauler"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Рипли в старый инженерный экзокостюм."
+
+ new_name = "АЭП \"Тягач\""
+ new_desc = "Старый инженерный экзокостюм. Для любителей классики."
+ new_icon = "hauler"
+ allowed_types = list("ripley", "firefighter")
+ new_wreckage = /obj/structure/mecha_wreckage/ripley/hauler
+
+/obj/item/paintkit/firefighter_zairjah
+ name = "Набор кастомизации АЭП \"Заря\""
+ icon_state = "paintkit_zairjah"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Рипли в странно выглядящий экзокостюм."
+
+ new_name = "АЭП \"Заря\""
+ new_desc = "Шахтерская машина индивидуальной разработки, закрытая кабина с придаточными устройствами."
+ new_icon = "ripley_zairjah"
+ allowed_types = list("ripley", "firefighter")
+ new_wreckage = /obj/structure/mecha_wreckage/ripley/zairjah
+
+/obj/item/paintkit/firefighter_combat
+ name = "Набор кастомизации АЭП \"Боевой Рипли\""
+ icon_state = "paintkit_combat"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Рипли в настоящий боевой экзокостюм. Оружие в комплект не входит!"
+
+ new_name = "АЭП \"Combat Ripley\""
+ new_desc = "Погоди-ка, почему от этого меха исходят горящие искры?"
+ new_icon = "combatripley"
+ allowed_types = list("ripley", "firefighter")
+ new_wreckage = /obj/structure/mecha_wreckage/ripley/combat
+
+/obj/item/paintkit/firefighter_aluminizer
+ name = "Набор кастомизации АЭП \"Алюминатор\""
+ icon_state = "paintkit"
+ desc = "Набор, содержащий белую краску для Рипли."
+
+ new_name = "АЭП \"Алюминатор\""
+ new_desc = "Вы только что покрасили свой Рипли в белый цвет? Выглядит хорошо."
+ new_icon = "aluminizer"
+ allowed_types = list("ripley", "firefighter")
+ new_wreckage = /obj/structure/mecha_wreckage/ripley/aluminizer
+
+/obj/item/paintkit/firefighter_reaper
+ name = "Набор кастомизации АЭП \"Жнец\""
+ icon_state = "paintkit_death"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Рипли в знаменитого меха из мегапопулярного аниме \"Отряд Смерти\"!"
+
+ new_name = "АЭП \"Жнец\""
+ new_desc = "ОХ БЛЯТЬ, ЭТО ОНИ, МЫ ВСЕ УМР- а, это просто перекрашенный Рипли."
+ new_icon = "deathripley"
+ allowed_types = list("ripley", "firefighter")
+ new_wreckage = /obj/structure/mecha_wreckage/ripley/reaper
+
+// MARK: Odysseus
+
+/obj/item/paintkit/odysseus_hermes
+ name = "Набор кастомизации Одиссея \"Гермес\""
+ icon_state = "paintkit_hermes"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Одиссея в инопланетный водолазный экзокостюм."
+
+ new_name = "Гермес"
+ new_desc = "Водолазный экзокостюм, разработанный и выпускаемый для проведения узкоспециализированных подводных операций. Как он здесь оказался?"
+ new_icon = "hermes"
+ allowed_types = list("odysseus")
+ new_wreckage = /obj/structure/mecha_wreckage/odysseus/hermes
+
+/obj/item/paintkit/odysseus_death
+ name = "Набор кастомизации Одиссея \"Жнец\""
+ icon_state = "paintkit_death"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Одиссея в ужасающий мех."
+
+ new_name = "Жнец"
+ new_desc = "ОХ БЛЯТЬ, МЫ ВСЕ... получим плохое лечение?"
+ new_icon = "murdysseus"
+ allowed_types = list("odysseus")
+ new_wreckage = /obj/structure/mecha_wreckage/odysseus/reaper
+
+// MARK: Gygax
+
+/obj/item/paintkit/gygax_alt
+ name = "Набор кастомизации старого Гигакса"
+ icon_state = "paintkit_alt"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Гигакса в устаревшую версию самого себя. Зачем вам это нужно?"
+
+ new_name = "старый Гигакс"
+ new_desc = "Устаревший защитный экзокостюм. Найти сохранившийся экзокостюм этой модели - настоящее достижение."
+ new_icon = "gygax_alt"
+ allowed_types = list("gygax")
+ new_wreckage = /obj/structure/mecha_wreckage/gygax/old
+
+/obj/item/paintkit/gygax_pobeda
+ name = "Набор кастомизации Гигакса \"Победа\""
+ icon_state = "paintkit_pobeda"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Гигакса в советский экзокостюм."
+
+ new_name = "Победа"
+ new_desc = "Сверхмощный старый Гигакс, раскрашенный в СССП стилистике. Слава космической России!"
+ new_icon = "pobeda"
+ allowed_types = list("gygax")
+ new_wreckage = /obj/structure/mecha_wreckage/gygax/pobeda
+
+/obj/item/paintkit/gygax_white
+ name = "Набор кастомизации белого Гигакса"
+ icon_state = "paintkit_white"
+ desc = "Набор с белой краской для Гигакса."
+
+ new_name = "белый Гигакс"
+ new_desc = "Ты только что покрасил свой Гигакс в белый? Мне нравится."
+ new_icon = "whitegax"
+ allowed_types = list("gygax")
+ new_wreckage = /obj/structure/mecha_wreckage/gygax/whitegax
+
+/obj/item/paintkit/gygax_medgax
+ name = "Набор кастомизации Гигакса \"Медигакс\""
+ icon_state = "paintkit_white"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Гигакс в старый \"медицинский\" мех."
+
+ new_name = "Медигакс"
+ new_desc = "ОХ БЛЯТЬ, В БОЛЬНИЦЕ МЕДИЦИНСКИЙ МЕХ, ОН НАС ВСЕХ УБЬЕТ!!!"
+ new_icon = "medigax"
+ allowed_types = list("gygax")
+ new_wreckage = /obj/structure/mecha_wreckage/gygax/medigax
+
+/obj/item/paintkit/gygax_mime
+ name = "Набор кастомизации Гигакса \"Молчигакс\""
+ icon_state = "paintkit_white"
+ desc = "Набор кастомизации Гигакса, присланный с любовью от мимов-ассасинов. Глушитель в комплект не входит."
+
+ new_name = "Молчигакс"
+ new_desc = "...!"
+ new_icon = "mime"
+ allowed_types = list("gygax")
+ new_wreckage = /obj/structure/mecha_wreckage/gygax/mimegax
+
+/obj/item/paintkit/gygax_syndie
+ name = "Набор кастомизации черного Гигакса"
+ icon_state = "paintkit_Black"
+ desc = "Очень подозрительный набор, содержащий все необходимые инструменты и детали для превращения Гигакса в печально известный черный Гигакс."
+
+ new_name = "черный Гигакс"
+ new_desc = "Почему на этой штуке есть логотип Синдиката? Погодите-ка..."
+ new_icon = "gygax_black"
+ allowed_types = list("gygax")
+ new_wreckage = /obj/structure/mecha_wreckage/gygax/gygax_black
+
+// MARK: Durand
+
+/obj/item/paintkit/durand_soviet
+ name = "Набор кастомизации Дюранда \"Кукольный домик\""
+ icon_state = "paintkit_doll"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Дюранда в советский мех. Слава космической России!"
+
+ new_name = "Кукольный домик"
+ new_desc = "Сверхмощный боевой мех, разработанный в СССП. Слава космической России!"
+ new_icon = "dollhouse"
+ allowed_types = list("durand")
+ new_wreckage = /obj/structure/mecha_wreckage/durand/dollhouse
+
+/obj/item/paintkit/durand_unathi
+ name = "Набор кастомизации Дюранда \"Кхарн MK. IV\""
+ icon_state = "paintkit_unathi"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Дюранда в ящероподобный инопланетный мех."
+
+ new_name = "Кхарн MK. IV"
+ new_desc = "Жизнь за Императницу!"
+ new_icon = "unathi"
+ allowed_types = list("durand")
+ new_wreckage = /obj/structure/mecha_wreckage/durand/unathi
+
+/obj/item/paintkit/durand_shire
+ name = "Набор кастомизации Дюранда \"Шир\""
+ icon_state = "paintkit_shire"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Дюранда в невероятно тяжелую боевую машину."
+
+ new_name = "Шир"
+ new_desc = "Невероятно тяжелая боевая машина, созданная по проекту Межзвездной Войны."
+ new_icon = "shire"
+ allowed_types = list("durand")
+ new_wreckage = /obj/structure/mecha_wreckage/durand/shire
+
+/obj/item/paintkit/durand_skull
+ name = "Набор кастомизации Дюранда \"Скелемех\""
+ icon_state = "paintkit_skull"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Дюранда в монстра Лаваленда!"
+
+ new_name = "Скелемех"
+ new_desc = "Мех, укрепленный черепами древних монстров. На этот ужас нужен опытный шахтёр."
+ new_icon = "skullmech"
+ allowed_types = list("durand")
+ new_wreckage = /obj/structure/mecha_wreckage/durand/skull
+
+// MARK: Phazon
+
+/obj/item/paintkit/phazon_imperion
+ name = "Набор кастомизации Фазона \"Империон\""
+ icon_state = "paintkit_imperon"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения дорогого и совершенного Фазона в еще более дорогой и совершенный Империон."
+
+ new_name = "Империон"
+ new_desc = "Вершина научных исследований и гордость \"Нанотрейзен\", в нем используются передовые технологии блюспейса и дорогостоящие материалы."
+ new_icon = "imperion"
+ allowed_types = list("phazon")
+ new_wreckage = /obj/structure/mecha_wreckage/phazon/imperion
+
+/obj/item/paintkit/phazon_janus
+ name = "Набор кастомизации Фазона \"Янус\""
+ icon_state = "paintkit_janus"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Фазона в более темную и дорогую версию самого себя."
+
+ new_name = "Янус"
+ new_desc = "Вершина научных исследований и гордость \"Нанотрейзен\", в нем используются передовые технологии блюспейса и дорогостоящие материалы."
+ new_icon = "janus"
+ allowed_types = list("phazon")
+ new_wreckage = /obj/structure/mecha_wreckage/phazon/janus
+
+/obj/item/paintkit/phazon_plazmus
+ name = "Набор кастомизации Фазона \"Плазмус\""
+ icon_state = "paintkit_plazmus"
+ desc = "Набор, содержащий все необходимые инструменты и детали для превращения Фазона в фиолетовый мех."
+
+ new_name = "Плазмус"
+ new_desc = "Значит, вы объединили в этой штуке две самые опасные технологии?"
+ new_icon = "plazmus"
+ allowed_types = list("phazon")
+ new_wreckage = /obj/structure/mecha_wreckage/phazon/plazmus
+
+/obj/item/paintkit/phazon_blanco
+ name = "Набор кастомизации Фазона \"Бланко\""
+ icon_state = "paintkit_white"
+ desc = "Набор с белой краской для Фазона."
+
+ new_name = "Бланко"
+ new_desc = "Потребовалось более полугода работы, чтобы найти идеальные пастельные цвета для этого меха."
+ new_icon = "phazon_blanco"
+ allowed_types = list("phazon")
+ new_wreckage = /obj/structure/mecha_wreckage/phazon/phazon_blanco
diff --git a/modular_ss220/mecha_skins/icons/mecha.dmi b/modular_ss220/mecha_skins/icons/mecha.dmi
new file mode 100644
index 000000000000..afc16f71cd00
Binary files /dev/null and b/modular_ss220/mecha_skins/icons/mecha.dmi differ
diff --git a/modular_ss220/mecha_skins/icons/paintkit.dmi b/modular_ss220/mecha_skins/icons/paintkit.dmi
new file mode 100644
index 000000000000..32b1da5e5e59
Binary files /dev/null and b/modular_ss220/mecha_skins/icons/paintkit.dmi differ
diff --git a/modular_ss220/mecha_skins/mecha_skins.dm b/modular_ss220/mecha_skins/mecha_skins.dm
new file mode 100644
index 000000000000..260d42f2b1ea
--- /dev/null
+++ b/modular_ss220/mecha_skins/mecha_skins.dm
@@ -0,0 +1,4 @@
+/datum/modpack/mecha_skins
+ name = "Скины на мехи в фабрикаторе"
+ desc = "Без скинов жизнь говно, а с ними говно, но стильное. Вводим не думая."
+ author = "Сиротка"
diff --git a/modular_ss220/mecha_skins/mecha_skins.dme b/modular_ss220/mecha_skins/mecha_skins.dme
new file mode 100644
index 000000000000..143f30c078ff
--- /dev/null
+++ b/modular_ss220/mecha_skins/mecha_skins.dme
@@ -0,0 +1,5 @@
+#include "mecha_skins.dm"
+
+#include "code/fabricator_design.dm"
+#include "code/paintkit_install.dm"
+#include "code/paintkit_menu.dm"
diff --git a/modular_ss220/mobs/_mobs.dm b/modular_ss220/mobs/_mobs.dm
new file mode 100644
index 000000000000..a121601ad900
--- /dev/null
+++ b/modular_ss220/mobs/_mobs.dm
@@ -0,0 +1,4 @@
+/datum/modpack/mobs
+ name = "Мобы"
+ desc = "Пак животных, питомцев, холдеров для их держания и изменения."
+ author = "PhantomRU, dj-34"
diff --git a/modular_ss220/mobs/_mobs.dme b/modular_ss220/mobs/_mobs.dme
new file mode 100644
index 000000000000..9618cae7a42c
--- /dev/null
+++ b/modular_ss220/mobs/_mobs.dme
@@ -0,0 +1,39 @@
+#include "_mobs.dm"
+
+#include "code/simple_animal/friendly/butterfly.dm"
+#include "code/simple_animal/friendly/crab.dm"
+#include "code/simple_animal/friendly/farm_animals.dm"
+#include "code/simple_animal/friendly/frog.dm"
+#include "code/simple_animal/friendly/hamster.dm"
+#include "code/simple_animal/friendly/lizard.dm"
+#include "code/simple_animal/friendly/moth.dm"
+#include "code/simple_animal/friendly/mouse.dm"
+#include "code/simple_animal/friendly/possum.dm"
+#include "code/simple_animal/friendly/rat.dm"
+#include "code/simple_animal/friendly/snail.dm"
+#include "code/simple_animal/hostile/alien.dm"
+#include "code/simple_animal/hostile/bear.dm"
+#include "code/simple_animal/hostile/bee.dm"
+#include "code/simple_animal/hostile/headcrab.dm"
+#include "code/simple_animal/hostile/lizard.dm"
+#include "code/simple_animal/hostile/snake.dm"
+#include "code/simple_animal/hostile/spider.dm"
+#include "code/simple_animal/hostile/syndi_rat.dm"
+#include "code/simple_animal/hostile/undead.dm"
+#include "code/simple_animal/pets/cat.dm"
+#include "code/simple_animal/pets/dog.dm"
+#include "code/simple_animal/pets/fashion.dm"
+#include "code/simple_animal/pets/fox.dm"
+#include "code/simple_animal/pets/pet.dm"
+#include "code/simple_animal/pets/rouge.dm"
+#include "code/simple_animal/pets/security_dogs.dm"
+#include "code/simple_animal/pets/slugcat.dm"
+#include "code/simple_animal/items.dm"
+#include "code/simple_animal/mobs.dm"
+#include "code/simple_animal/named_animals.dm"
+#include "code/simple_animal/overrides.dm"
+#include "code/supplypacks/crittercrate.dm"
+#include "code/supplypacks/pack_animals.dm"
+#include "code/mob_holder.dm"
+#include "code/mob_spawner.dm"
+#include "code/pet_carrier.dm"
diff --git a/modular_ss220/mobs/code/mob_holder.dm b/modular_ss220/mobs/code/mob_holder.dm
new file mode 100644
index 000000000000..d9fbf24f3829
--- /dev/null
+++ b/modular_ss220/mobs/code/mob_holder.dm
@@ -0,0 +1,414 @@
+// \code\modules\mob\mob_holder.dm
+/obj/item/holder
+ icon_override = 'modular_ss220/mobs/icons/mob/inhead/head.dmi'
+ lefthand_file = 'modular_ss220/mobs/icons/mob/inhands/mobs_lefthand.dmi'
+ righthand_file = 'modular_ss220/mobs/icons/mob/inhands/mobs_righthand.dmi'
+ origin_tech = "biotech=2"
+ slot_flags = ITEM_SLOT_HEAD
+
+/obj/item/holder/attack__legacy__attackchain(mob/living/target, mob/living/user, def_zone)
+ ASSERT(length(contents) > 0)
+ var/mob/living/simple_animal/animal = contents[1]
+ var/mob/living/carbon/devourer = target
+ if(!istype(animal) || !istype(devourer))
+ return ..()
+
+ if(user.a_intent != INTENT_HARM)
+ return ..()
+
+ if(!is_type_in_list(animal, devourer.dna.species.allowed_consumed_mobs))
+ if(user != devourer)
+ to_chat(user, span_notice("Вряд ли это понравится [devourer]..."))
+ else if(ishuman(devourer))
+ to_chat(user, span_notice("Интересно, каков на вкус [animal]? Но проверять не будем."))
+ return
+
+ if(!user.canUnEquip(src, FALSE))
+ to_chat(user, span_notice("[src] никак не отлипает от руки!"))
+ return
+
+ if(user != devourer)
+ visible_message(span_danger("[user] пытается скормить [devourer] [animal]!"))
+ else
+ visible_message(span_danger("[user] пытается съесть [animal]!"))
+
+ if(!do_after(user, 3 SECONDS, target = devourer))
+ return
+
+ visible_message(span_danger("[devourer] съедает [animal]!"))
+ if(animal.mind)
+ add_attack_logs(devourer, animal, "Devoured")
+
+ if(istype(animal, /mob/living/simple_animal/hostile/poison/bees)) // Eating a bee will end up damaging you
+ var/obj/item/organ/external/mouth = devourer.get_organ(BODY_ZONE_PRECISE_MOUTH)
+ var/mob/living/simple_animal/hostile/poison/bees/bee = animal
+ mouth.receive_damage(1)
+ if(bee.beegent)
+ bee.beegent.reaction_mob(devourer, REAGENT_INGEST)
+ devourer.reagents.add_reagent(bee.beegent.id, rand(1, 5))
+ else
+ devourer.reagents.add_reagent("spidertoxin", 5)
+ devourer.visible_message(
+ span_warning("Рот [devourer] опух."),
+ span_danger("Ваш рот ужален, он теперь опухает!"))
+
+ animal.forceMove(devourer)
+ LAZYADD(devourer.stomach_contents, animal)
+ icon = null // workaround to hide cringy holder lying on the floor for 1 sec
+ user.drop_item()
+
+/mob/living/simple_animal/attackby__legacy__attackchain(obj/item/O, mob/living/user)
+ if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_GRAB)
+ if(istype(O, /obj/item/pet_carrier))
+ var/obj/item/pet_carrier/C = O
+ if(C.put_in_carrier(src, user))
+ return
+ return ..()
+
+
+
+
+
+
+
+
+//!!!!!!!!!! Проверить работу без этого прока, а потом с этим при захвате ПИИ, мышей, Куриц разных цветов
+// /mob/living/proc/get_scooped(mob/living/carbon/grabber, has_variant = FALSE)
+// . = ..()
+// if(.)
+// H.icon = icon
+// H.icon_state = icon_state
+
+/mob/living/get_scooped(mob/living/carbon/grabber, has_variant = FALSE)
+ var/obj/item/holder/H = ..()
+ if(!H)
+ return FALSE
+
+ switch(mob_size)
+ if(MOB_SIZE_TINY)
+ H.w_class = WEIGHT_CLASS_TINY
+ if(MOB_SIZE_SMALL)
+ H.w_class = WEIGHT_CLASS_SMALL
+ if(MOB_SIZE_HUMAN)
+ H.w_class = WEIGHT_CLASS_NORMAL
+ if(MOB_SIZE_LARGE)
+ H.w_class = WEIGHT_CLASS_HUGE
+
+ return H
+
+
+/obj/item/holder/diona
+ name = "diona nymph"
+ desc = "It's a tiny plant critter."
+ icon_state = "nymph"
+ origin_tech = "biotech=5"
+ icon = 'icons/mob/monkey.dmi' // why...
+
+/obj/item/holder/pai
+ name = "pAI"
+ desc = "It's a little robot."
+ origin_tech = "materials=3;programming=4;engineering=4"
+ slot_flags = ITEM_SLOT_HEAD | ITEM_SLOT_BOTH_EARS
+
+/obj/item/holder/bee
+ name = "bee"
+ desc = "Buzzy buzzy bee, stingy sti- Ouch!"
+ icon = 'icons/mob/bees.dmi'
+ icon_state = "queen_item"
+ origin_tech = "biotech=5"
+ slot_flags = null
+
+/obj/item/holder/bunny
+ slot_flags = ITEM_SLOT_HEAD | ITEM_SLOT_BOTH_EARS
+
+/obj/item/holder/butterfly
+ name = "butterfly"
+ desc = "A colorful butterfly, how'd it get up here?"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "butterfly"
+ origin_tech = "biotech=4"
+ slot_flags = ITEM_SLOT_HEAD | ITEM_SLOT_BOTH_EARS
+
+/obj/item/holder/mouse
+ name = "mouse"
+ desc = "It's a small, disease-ridden rodent."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "mouse_gray"
+ slot_flags = ITEM_SLOT_HEAD | ITEM_SLOT_BOTH_EARS
+
+/obj/item/holder/drone
+ name = "maintenance drone"
+ desc = "It's a small maintenance robot."
+ icon_state = "drone"
+ origin_tech = "materials=3;programming=4;powerstorage=3;engineering=4"
+
+/obj/item/holder/drone/emagged
+ name = "maintenance drone"
+ icon_state = "drone-emagged"
+ origin_tech = "materials=3;programming=4;powerstorage=3;engineering=4;syndicate=3"
+
+/obj/item/holder/monkey
+ name = "monkey"
+ desc = "It's a monkey"
+ icon_state = "monkey"
+ origin_tech = "biotech=3"
+
+/obj/item/holder/farwa
+ name = "farwa"
+ desc = "It's a farwa"
+ icon_state = "farwa"
+ origin_tech = "biotech=3"
+
+/obj/item/holder/stok
+ name = "stok"
+ desc = "It's a stok"
+ icon_state = "stok"
+ origin_tech = "biotech=3"
+
+/obj/item/holder/neara
+ name = "neara"
+ desc = "It's a neara"
+ icon_state = "neara"
+ origin_tech = "biotech=3"
+
+/obj/item/holder/corgi
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "corgi"
+
+/obj/item/holder/lisa
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "lisa"
+
+/obj/item/holder/old_corgi
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "old_corgi"
+
+/obj/item/holder/borgi
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "borgi"
+
+/obj/item/holder/void_puppy
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "void_puppy"
+ origin_tech = "biotech=4;bluespace=5"
+
+/obj/item/holder/slime_puppy
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "slime_puppy"
+ origin_tech = "biotech=6"
+
+/obj/item/holder/narsian
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "narsian"
+ slot_flags = null
+ origin_tech = "bluespace=10"
+
+/obj/item/holder/pug
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "pug"
+
+/obj/item/holder/fox
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "fox"
+
+/obj/item/holder/sloth
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "sloth"
+ slot_flags = null
+
+/obj/item/holder/cat
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "cat"
+
+/obj/item/holder/cat2
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "cat2"
+
+/obj/item/holder/cak
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "cak"
+ origin_tech = "biotech=5"
+
+/obj/item/holder/fatcat
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "iriska"
+ origin_tech = "biotech=5"
+ slot_flags = null
+
+/obj/item/holder/crusher
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "crusher"
+
+/obj/item/holder/spacecat
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "spacecat"
+
+/obj/item/holder/bullterrier
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "bullterrier"
+ slot_flags = null
+
+/obj/item/holder/crab
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "crab"
+
+/obj/item/holder/evilcrab
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "evilcrab"
+
+/obj/item/holder/snake
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "snake"
+
+/obj/item/holder/parrot
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "parrot_fly"
+
+/obj/item/holder/axolotl
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "axolotl"
+
+/obj/item/holder/lizard
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "lizard"
+
+/obj/item/holder/chick
+ name = "pet"
+ desc = "It's a small chicken"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "chick"
+
+/obj/item/holder/chicken
+ name = "pet"
+ desc = "It's a chicken"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "chicken_brown"
+ slot_flags = null
+
+/obj/item/holder/cock
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "cock"
+ slot_flags = null
+
+/obj/item/holder/hamster
+ name = "pet"
+ desc = "It's a pet"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "hamster"
+
+/obj/item/holder/hamster_rep
+ name = "Представитель Алексей"
+ desc = "Уважаемый хомяк"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "hamster_rep"
+
+/obj/item/holder/fennec
+ name = "fennec"
+ desc = "It's a fennec. Yiff!"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "fennec"
+ origin_tech = "biotech=4"
+
+/obj/item/holder/moth
+ name = "moth"
+ desc = "Bzzzz"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "moth"
+ origin_tech = "biotech=4"
+
+/obj/item/holder/headslug
+ name = "headslug"
+ desc = "It's a headslug. Ewwww..."
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "headslug"
+ origin_tech = "biotech=6"
+
+/obj/item/holder/possum
+ name = "possum"
+ desc = "It's a possum. Ewwww..."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "possum"
+ origin_tech = "biotech=3"
+
+/obj/item/holder/possum/poppy
+ name = "poppy"
+ desc = "It's a possum Poppy. Ewwww..."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "possum_poppy"
+
+/obj/item/holder/frog
+ name = "frog"
+ desc = "It's a wednesday, my dudes."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "frog"
+
+/obj/item/holder/frog/toxic
+ name = "rare frog"
+ desc = "It's a toxic wednesday, my dudes."
+ icon_state = "rare_frog"
+
+/obj/item/holder/snail
+ name = "snail"
+ desc = "Slooooow"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "snail"
+
+/obj/item/holder/turtle
+ name = "yeeslow"
+ desc = "Slooooow"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "yeeslow"
+
+/obj/item/holder/clowngoblin
+ name = "clowngoblin"
+ desc = "Honk honk"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "clowngoblin"
diff --git a/modular_ss220/mobs/code/mob_spawner.dm b/modular_ss220/mobs/code/mob_spawner.dm
new file mode 100644
index 000000000000..56a0449a4a68
--- /dev/null
+++ b/modular_ss220/mobs/code/mob_spawner.dm
@@ -0,0 +1,20 @@
+/obj/structure/spawner/headcrab
+ name = "headcrab nest"
+ desc = "A living nest for headcrabs. It is moving ominously."
+ icon_state = "headcrab_nest"
+ icon = 'modular_ss220/mobs/icons/mob/headcrab.dmi'
+ max_integrity = 200
+ max_mobs = 15
+ spawn_time = 600
+ mob_types = list(/mob/living/simple_animal/hostile/blackmesa/xen/headcrab, /mob/living/simple_animal/hostile/blackmesa/xen/headcrab/fast, /mob/living/simple_animal/hostile/blackmesa/xen/headcrab/poison)
+ spawn_text = "crawls out of"
+ faction = list("hostile")
+
+// Headcrab corpse
+/obj/effect/mob_spawn/headcrab
+ mob_type = /mob/living/simple_animal/hostile/blackmesa/xen/headcrab
+ death = TRUE
+ name = "Dead headcrab"
+ desc = "A small dead parasitic creature that would like to connect with your brain stem."
+ icon = 'modular_ss220/mobs/icons/mob/headcrab.dmi'
+ icon_state = "headcrab_dead"
diff --git a/modular_ss220/mobs/code/pet_carrier.dm b/modular_ss220/mobs/code/pet_carrier.dm
new file mode 100644
index 000000000000..eaff3fdfed45
--- /dev/null
+++ b/modular_ss220/mobs/code/pet_carrier.dm
@@ -0,0 +1,271 @@
+/obj/item/pet_carrier
+ name = "маленькая переноска"
+ desc = "Переноска для маленьких животных. "
+ icon = 'modular_ss220/mobs/icons/pet_carrier.dmi'
+ icon_state = "pet_carrier"
+ item_state = "pet_carrier"
+ max_integrity = 100
+ w_class = WEIGHT_CLASS_SMALL
+ var/mob_size = MOB_SIZE_SMALL
+
+ var/list/possible_skins = list("black", "blue", "red", "yellow", "green", "purple")
+ var/color_skin
+
+ var/opened = TRUE
+ var/contains_pet = FALSE
+ var/contains_pet_color_open = "#d8d8d8ff"
+ var/contains_pet_color_close = "#949494ff"
+
+/obj/item/pet_carrier/normal
+ name = "переноска"
+ desc = "Переноска для небольших животных. "
+ icon_state = "pet_carrier_normal"
+ item_state = "pet_carrier_normal"
+ max_integrity = 200
+ w_class = WEIGHT_CLASS_NORMAL
+ mob_size = MOB_SIZE_LARGE
+
+
+/obj/item/pet_carrier/Initialize(mapload)
+ . = ..()
+ if(!color_skin)
+ color_skin = pick(possible_skins)
+ update_icon()
+
+/obj/item/pet_carrier/Destroy()
+ free_content()
+ . = ..()
+
+/obj/item/pet_carrier/attack_self__legacy__attackchain(mob/user)
+ ..()
+ change_state()
+
+/obj/item/pet_carrier/attackby__legacy__attackchain(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/holder))
+ var/obj/item/holder/H = I
+ for(var/mob/M in H.contents)
+ if(put_in_carrier(M, user))
+ qdel(H)
+ return TRUE
+ return FALSE
+ . = ..()
+
+/obj/item/pet_carrier/emp_act(intensity)
+ for(var/mob/living/M in contents)
+ M.emp_act(intensity)
+
+/obj/item/pet_carrier/ex_act(intensity)
+ for(var/mob/living/M in contents)
+ M.ex_act(intensity)
+
+/obj/item/pet_carrier/proc/put_in_carrier(mob/living/target, mob/living/user)
+ if(!opened)
+ to_chat(user, span_warning("Ваша переноска закрыта!"))
+ return FALSE
+ if(contains_pet)
+ to_chat(user, span_warning("Ваша переноска заполнена!"))
+ return FALSE
+ if(target.mob_size > mob_size)
+ to_chat(user, span_warning("Ваша переноска слишком мала!"))
+ return FALSE
+ if(!istype(target, /mob/living/simple_animal/pet))
+ to_chat(user, span_warning("Это существо не очень похоже на ручное животное."))
+ return FALSE
+ //if(target.mob_size < mob_size)
+ // to_chat(user, span_warning("Ваша переноска слишком большая!"))
+ // return FALSE
+
+ target.forceMove(src)
+ name += " ([target.name])"
+ if(target.desc)
+ desc += "\n\nВнутри [target.name]\n"
+ desc += target.desc
+ contains_pet = TRUE
+
+ to_chat(user, span_notice("Вы поместили [target.name] в [src.name]."))
+ to_chat(target, span_notice("[user.name] поместил[user.gender == FEMALE ? "" : "а"] вас в [src.name]."))
+ update_icon()
+ return TRUE
+
+/obj/item/pet_carrier/proc/try_free_content(atom/new_location, mob/user)
+ if(!opened)
+ if(user)
+ to_chat(user, span_warning("Ваша переноска закрыта! Содержимое невозможно выгрузить!"))
+ return FALSE
+ free_content(new_location)
+
+/obj/item/pet_carrier/proc/free_content(atom/new_location)
+ if(istype(loc,/turf) || length(contents))
+ for(var/mob/M in contents)
+ var/atom/movable/mob_container
+ mob_container = M
+ mob_container.forceMove(new_location ? new_location : get_turf(src))
+ contains_pet = FALSE
+ name = initial(name)
+ desc = initial(desc)
+ update_icon()
+ return TRUE
+ return FALSE
+
+/obj/item/pet_carrier/proc/change_state()
+ opened = !opened
+ update_icon()
+
+/obj/item/pet_carrier/update_icon()
+ overlays.Cut()
+ if(contains_pet)
+ var/mob/living/M
+ for(var/mob/living/temp_M in contents)
+ M = temp_M
+ break
+ var/image/I = image(M.icon, icon_state = M.icon_state)
+ I.color = opened ? contains_pet_color_open : contains_pet_color_close
+ I.pixel_y = M.mob_size <= MOB_SIZE_TINY ? 6 : 3
+ overlays += I
+
+ if(!opened)
+ var/image/I = image(icon, icon_state = "[icon_state]_door")
+ overlays += I
+
+ if(color_skin)
+ var/image/I = image(icon, icon_state = "[icon_state]_[color_skin]")
+ overlays += I
+
+ return ..()
+
+/obj/item/pet_carrier/emp_act(intensity)
+ for(var/mob/living/M in contents)
+ M.emp_act(intensity)
+
+/obj/item/pet_carrier/ex_act(intensity)
+ for(var/mob/living/M in contents)
+ M.ex_act(intensity)
+
+/obj/item/pet_carrier/container_resist(mob/living/L)
+ var/breakout_time = 60 SECONDS //1 minute
+ var/breakout_time_open = 5 SECONDS //for escape
+
+ if(do_after(L,(breakout_time_open/2), target = src))
+ to_chat(L, span_warning("ТЕСТ 1 - Вы начали вылезать из переноски (это займет [breakout_time_open] секунд, не двигайтесь)"))
+
+ if(do_after(L,(breakout_time_open/2)))
+ to_chat(L, span_warning("ТЕСТ 2 - Вы начали вылезать из переноски (это займет [breakout_time_open] секунд, не двигайтесь)"))
+
+ if(do_after(L,(breakout_time_open/2), target = loc))
+ to_chat(L, span_warning("ТЕСТ 3 - Вы начали вылезать из переноски (это займет [breakout_time_open] секунд, не двигайтесь)"))
+
+ if(do_after(L,(breakout_time_open/2), target = src.loc))
+ to_chat(L, span_warning("ТЕСТ 4 - Вы начали вылезать из переноски (это займет [breakout_time_open] секунд, не двигайтесь)"))
+
+ if(do_after(L,(breakout_time_open/2), target = L))
+ to_chat(L, span_warning("ТЕСТ 5 - Вы начали вылезать из переноски (это займет [breakout_time_open] секунд, не двигайтесь)"))
+
+ if(do_after(L,(breakout_time_open/2), target = L.loc))
+ to_chat(L, span_warning("ТЕСТ 6 - Вы начали вылезать из переноски (это займет [breakout_time_open] секунд, не двигайтесь)"))
+
+
+
+ if(opened && L.loc == src)
+ to_chat(L, span_warning("Вы начали вылезать из переноски (это займет [breakout_time_open] секунд, не двигайтесь)"))
+ spawn(0)
+ if(do_after(L,(breakout_time_open), target = src))
+ if(!src || !L || L.stat != CONSCIOUS || L.loc != src || !opened)
+ to_chat(L, span_warning("Побег прерван!"))
+ return
+
+ free_content()
+ visible_message(span_warning("[L.name] вылез из переноски."))
+ return
+
+ to_chat(L, span_warning("Вы начали ломиться в закрытую дверцу переноски и пытаетесь её выбить или открыть. (это займет [breakout_time] секунд, не двигайтесь)"))
+ for(var/mob/O in viewers(usr.loc))
+ O.show_message(span_danger("[src.name] начинает трястись!"), 1)
+
+ spawn(0)
+ if(do_after(L,(breakout_time), target = src))
+ if(!src || !L || L.stat != CONSCIOUS || L.loc != src || opened) //closet/user destroyed OR user dead/unconcious OR user no longer in closet OR closet opened
+ to_chat(L, span_warning("Побег прерван!"))
+ return
+
+ var/mob/M = src.loc
+ if(istype(M))
+ to_chat(M, "[src.name] вырывается из вашей переноски!")
+ to_chat(L, "Вы вырываетесь из переноски [M.name]!")
+ else
+ to_chat(L, "Вы выбираетесь из переноски.")
+
+ //Free & open
+ free_content()
+ change_state()
+ return
+
+/obj/item/pet_carrier/examine(mob/user)
+ . = ..()
+ . += span_notice("Alt-Click to unload.")
+ . += span_notice("Alt-Shift-Click to toggle lock.")
+
+/obj/item/pet_carrier/AltClick(mob/user)
+ unload_content(user)
+
+/obj/item/pet_carrier/AltShiftClick(mob/user)
+ open_close(user)
+
+/obj/item/pet_carrier/proc/open_close(mob/user)
+ if(user.stat || !ishuman(user) || user.restrained())
+ return
+
+ change_state()
+
+/obj/item/pet_carrier/proc/unload_content(mob/user)
+ if(user.stat || !ishuman(user) || user.restrained())
+ return
+
+ try_free_content(user)
+
+/obj/item/pet_carrier/MouseDrop(obj/over_object)
+ if(ishuman(usr))
+ var/mob/M = usr
+
+ if(istype(M.loc,/obj/mecha) || M.incapacitated(FALSE, TRUE, TRUE)) // Stops inventory actions in a mech as well as while being incapacitated
+ return
+
+ if(over_object == M && Adjacent(M)) // this must come before the screen objects only block
+ try_free_content(M, M)
+ return
+
+ if((istype(over_object, /obj/structure/table) || istype(over_object, /turf/simulated/floor)) \
+ && length(contents) && loc == usr && !usr.stat && !usr.restrained() && over_object.Adjacent(usr))
+ var/turf/T = get_turf(over_object)
+ if(istype(over_object, /turf/simulated/floor))
+ if(get_turf(usr) != T)
+ return // Can only empty containers onto the floor under you
+ if("Да" != alert(usr,"Вытащить питомца из [src.name] на [T.name]?","Подтверждение","Да","Нет"))
+ return
+ if(!(usr && over_object && contents.len && loc == usr && !usr.stat && !usr.restrained() && get_turf(usr) == T))
+ return // Something happened while the player was thinking
+
+ usr.face_atom(over_object)
+ usr.visible_message(
+ span_notice("[usr] вытащил питомца из [src.name] на [over_object.name]."),
+ span_notice("Вы вытащили питомца из [src.name] на [over_object.name]."))
+
+ try_free_content(T, usr)
+ return TRUE
+
+ if(!is_screen_atom(over_object))
+ return ..()
+ if(!(loc == usr) || (loc && loc.loc == usr))
+ return
+ playsound(loc, "rustle", 50, TRUE, -5)
+ if(!(M.restrained()) && !(M.stat))
+ switch(over_object.name)
+ if("r_hand")
+ if(!M.unEquip(src))
+ return
+ M.put_in_r_hand(src)
+ if("l_hand")
+ if(!M.unEquip(src))
+ return
+ M.put_in_l_hand(src)
+ add_fingerprint(usr)
+ return
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/butterfly.dm b/modular_ss220/mobs/code/simple_animal/friendly/butterfly.dm
new file mode 100644
index 000000000000..bb90f50e4e39
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/butterfly.dm
@@ -0,0 +1,2 @@
+/mob/living/simple_animal/butterfly
+ holder_type = /obj/item/holder/butterfly
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/crab.dm b/modular_ss220/mobs/code/simple_animal/friendly/crab.dm
new file mode 100644
index 000000000000..d2b4dcc9491c
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/crab.dm
@@ -0,0 +1,38 @@
+/mob/living/simple_animal/crab
+ death_sound = 'modular_ss220/mobs/sound/creatures/crack_death2.ogg'
+ mob_size = MOB_SIZE_SMALL
+ response_help = "гладит"
+ response_disarm = "отталкивает"
+ response_harm = "щипает"
+ holder_type = /obj/item/holder/crab
+
+/mob/living/simple_animal/crab/sea
+ name = "морской краб"
+ desc = "Кто проживает на дне океана?"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "bluecrab"
+ icon_living = "bluecrab"
+ icon_dead = "bluecrab_dead"
+ response_help = "гладит"
+ response_disarm = "отталкивает"
+ response_harm = "щипает"
+ health = 50
+ maxHealth = 50
+ butcher_results = list(/obj/item/food/meat = 3)
+
+/mob/living/simple_animal/crab/royal
+ name = "королевский краб"
+ desc = "Величественный королевский краб."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "royalcrab"
+ icon_living = "royalcrab"
+ icon_dead = "royalcrab_dead"
+ response_help = "с уважением гладит"
+ response_disarm = "с уважением отталкивает"
+ response_harm = "щипает без уважения"
+ health = 50
+ maxHealth = 50
+ butcher_results = list(/obj/item/food/meat = 5)
+
+/mob/living/simple_animal/crab/evil
+ holder_type = /obj/item/holder/evilcrab
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/farm_animals.dm b/modular_ss220/mobs/code/simple_animal/friendly/farm_animals.dm
new file mode 100644
index 000000000000..0613e4a03292
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/farm_animals.dm
@@ -0,0 +1,120 @@
+/mob/living/simple_animal/hostile/retaliate/goat
+ attacktext = "бодает"
+ death_sound = 'modular_ss220/mobs/sound/creatures/goat_death.ogg'
+
+/mob/living/simple_animal/cow
+ attacktext = "бодает"
+ death_sound = 'modular_ss220/mobs/sound/creatures/cow_death.ogg'
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/cow_damaged.ogg')
+ talk_sound = list('modular_ss220/mobs/sound/creatures/cow_talk1.ogg', 'modular_ss220/mobs/sound/creatures/cow_talk2.ogg')
+
+/mob/living/simple_animal/chicken
+ name = "курица"
+ desc = "Гордая несушка. Яички должны быть хороши!"
+ death_sound = 'modular_ss220/mobs/sound/creatures/chicken_death.ogg'
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/chicken_damaged1.ogg', 'modular_ss220/mobs/sound/creatures/chicken_damaged2.ogg')
+ talk_sound = list('modular_ss220/mobs/sound/creatures/chicken_talk.ogg')
+ holder_type = /obj/item/holder/chicken
+
+/mob/living/simple_animal/chick
+ name = "цыпленок"
+ desc = "Маленькая прелесть! Но пока что маловата..."
+ attacktext = "клюёт"
+ death_sound = 'modular_ss220/mobs/sound/creatures/mouse_squeak.ogg'
+ holder_type = /obj/item/holder/chick
+
+/mob/living/simple_animal/chick/Life(seconds, times_fired)
+ if(amount_grown >= 100 && prob(20))
+ var/mob/living/simple_animal/C = new /mob/living/simple_animal/cock(loc)
+ if(mind)
+ mind.transfer_to(C)
+ qdel(src)
+ . = ..()
+
+/mob/living/simple_animal/cock
+ name = "петух"
+ desc = "Гордый и важный вид."
+ gender = MALE
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "cock"
+ icon_living = "cock"
+ icon_dead = "cock_dead"
+ speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
+ speak_emote = list("clucks","croons")
+ emote_hear = list("clucks")
+ emote_see = list("pecks at the ground","flaps its wings viciously")
+ density = 0
+ speak_chance = 2
+ turns_per_move = 3
+ butcher_results = list(/obj/item/food/meat = 4)
+ response_help = "pets the"
+ response_disarm = "gently pushes aside the"
+ response_harm = "kicks the"
+ melee_damage_type = STAMINA
+ melee_damage_lower = 2
+ melee_damage_upper = 6
+ attacktext = "клюёт"
+ death_sound = 'modular_ss220/mobs/sound/creatures/chicken_death.ogg'
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/chicken_damaged1.ogg', 'modular_ss220/mobs/sound/creatures/chicken_damaged2.ogg')
+ talk_sound = list('modular_ss220/mobs/sound/creatures/chicken_talk.ogg')
+ health = 30
+ maxHealth = 30
+ ventcrawler = 2
+ pass_flags = PASSTABLE | PASSMOB
+ mob_size = MOB_SIZE_SMALL
+ can_hide = 1
+ can_collar = 1
+ gold_core_spawnable = FRIENDLY_SPAWN
+ footstep_type = FOOTSTEP_MOB_CLAW
+ holder_type = /obj/item/holder/cock
+
+/mob/living/simple_animal/cock/npc_safe(mob/user)
+ return TRUE
+
+/mob/living/simple_animal/pig
+ name = "свинья"
+ attacktext = "лягает"
+ death_sound = 'modular_ss220/mobs/sound/creatures/pig_death.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/pig_talk1.ogg', 'modular_ss220/mobs/sound/creatures/pig_talk2.ogg')
+ damaged_sound = list()
+
+/mob/living/simple_animal/pig/npc_safe(mob/user)
+ return TRUE
+
+/mob/living/simple_animal/turkey
+ name = "индюшка"
+ desc = "И не благодари."
+ death_sound = 'modular_ss220/mobs/sound/creatures/duck_quak1.ogg'
+
+
+/mob/living/simple_animal/goose
+ name = "гусь"
+ desc = "Прекрасная птица для набива подушек и страха детишек."
+ icon_resting = "goose_rest"
+ melee_damage_type = STAMINA
+ melee_damage_lower = 2
+ melee_damage_upper = 8
+ attacktext = "щипает"
+ death_sound = 'modular_ss220/mobs/sound/creatures/duck_quak1.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/duck_talk1.ogg', 'modular_ss220/mobs/sound/creatures/duck_talk2.ogg', 'modular_ss220/mobs/sound/creatures/duck_talk3.ogg', 'modular_ss220/mobs/sound/creatures/duck_quak1.ogg', 'modular_ss220/mobs/sound/creatures/duck_quak2.ogg', 'modular_ss220/mobs/sound/creatures/duck_quak3.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/duck_aggro1.ogg', 'modular_ss220/mobs/sound/creatures/duck_aggro2.ogg')
+
+/mob/living/simple_animal/goose/npc_safe(mob/user)
+ return TRUE
+
+/mob/living/simple_animal/goose/gosling
+ name = "гусенок"
+ desc = "Симпатичный гусенок. Скоро он станей грозой всей станции."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "gosling"
+ icon_living = "gosling"
+ icon_dead = "gosling_dead"
+ icon_resting = "gosling_rest"
+ butcher_results = list(/obj/item/food/meat = 3)
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ health = 20
+ maxHealth = 20
+
+/mob/living/simple_animal/seal
+ death_sound = 'modular_ss220/mobs/sound/creatures/seal_death.ogg'
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/frog.dm b/modular_ss220/mobs/code/simple_animal/friendly/frog.dm
new file mode 100644
index 000000000000..b5b181feddd6
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/frog.dm
@@ -0,0 +1,147 @@
+/mob/living/simple_animal/frog
+ name = "лягушка"
+ real_name = "лягушка"
+ desc = "Выглядит грустным не по средам и когда её не целуют."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "frog"
+ icon_living = "frog"
+ icon_dead = "frog_dead"
+ icon_resting = "frog"
+ speak = list("Квак!","КУААК!","Квуак!")
+ speak_emote = list("квак","куак","квуак")
+ emote_hear = list("квак","куак","квуак")
+ emote_see = list("лежит расслабленная", "издает гортанные звуки", "лупает глазками")
+ var/scream_sound = list ('modular_ss220/mobs/sound/creatures/frog_scream_1.ogg','modular_ss220/mobs/sound/creatures/frog_scream_2.ogg','modular_ss220/mobs/sound/creatures/frog_scream_3.ogg')
+ talk_sound = list('modular_ss220/mobs/sound/creatures/frog_talk1.ogg', 'modular_ss220/mobs/sound/creatures/frog_talk2.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/frog_damaged.ogg')
+ death_sound = 'modular_ss220/mobs/sound/creatures/frog_death.ogg'
+ speak_chance = 1
+ turns_per_move = 5
+ see_in_dark = 10
+ maxHealth = 10
+ health = 10
+ blood_volume = BLOOD_VOLUME_SURVIVE
+ butcher_results = list(/obj/item/food/monstermeat/lizardmeat = 1)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "stamps on"
+ density = 0
+ ventcrawler = 2
+ pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
+ mob_size = MOB_SIZE_TINY
+ layer = MOB_LAYER
+ atmos_requirements = list("min_oxy" = 16, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 223 // Below -50 Degrees Celcius
+ maxbodytemp = 323 // Above 50 Degrees Celcius
+ universal_speak = 0
+ can_hide = 1
+ holder_type = /obj/item/holder/frog
+ can_collar = 1
+ gold_core_spawnable = FRIENDLY_SPAWN
+
+/mob/living/simple_animal/frog/toxic
+ name = "яркая лягушка"
+ real_name = "яркая лягушка"
+ desc = "Уникальная токсичная раскраска. Лучше не трогать голыми руками."
+ icon_state = "rare_frog"
+ icon_living = "rare_frog"
+ icon_dead = "rare_frog_dead"
+ icon_resting = "rare_frog"
+ var/toxin_per_touch = 2.5
+ var/toxin_type = "toxin"
+ gold_core_spawnable = HOSTILE_SPAWN
+ holder_type = /obj/item/holder/frog/toxic
+
+/mob/living/simple_animal/frog/scream
+ name = "орущая лягушка"
+ real_name = "орущая лягушка"
+ desc = "Не любит когда на неё наступают. Используется в качестве наказания за проступки"
+ var/squeak_sound = list ('modular_ss220/mobs/sound/creatures/frog_scream1.ogg','modular_ss220/mobs/sound/creatures/frog_scream2.ogg')
+ gold_core_spawnable = NO_SPAWN
+
+// Frog procs
+/mob/living/simple_animal/frog/attack_hand(mob/living/carbon/human/M as mob)
+ if(M.a_intent == INTENT_HELP)
+ get_scooped(M)
+ ..()
+
+/mob/living/simple_animal/frog/Crossed(AM as mob|obj, oldloc)
+ if(ishuman(AM))
+ if(!stat)
+ var/mob/M = AM
+ to_chat(M, span_notice("[bicon(src)] квакнул!"))
+ ..()
+
+// Toxic frog procs
+/mob/living/simple_animal/frog/toxic/attack_hand(mob/living/carbon/human/H as mob)
+ if(ishuman(H))
+ if(!istype(H.gloves, /obj/item/clothing/gloves))
+ for(var/obj/item/organ/external/A in H.bodyparts)
+ if(!A.is_robotic())
+ if((A.body_part == HAND_LEFT) || (A.body_part == HAND_RIGHT))
+ to_chat(H, span_warning("Дотронувшись до [src.name], ваша кожа начинает чесаться!"))
+ toxin_affect(H)
+ if(H.a_intent == INTENT_DISARM || H.a_intent == INTENT_HARM)
+ ..()
+ ..()
+
+/mob/living/simple_animal/frog/toxic/Crossed(AM as mob|obj, oldloc)
+ if(ishuman(AM))
+ var/mob/living/carbon/human/H = AM
+ if(!istype(H.shoes, /obj/item/clothing/shoes))
+ for(var/obj/item/organ/external/F in H.bodyparts)
+ if(!F.is_robotic())
+ if((F.body_part == FOOT_LEFT) || (F.body_part == FOOT_RIGHT))
+ toxin_affect(H)
+ to_chat(H, span_warning("Ваши ступни начинают чесаться!"))
+ ..()
+
+/mob/living/simple_animal/frog/toxic/proc/toxin_affect(mob/living/carbon/human/M as mob)
+ if(M.reagents && !toxin_per_touch == 0)
+ M.reagents.add_reagent(toxin_type, toxin_per_touch)
+
+// Scream frog procs
+/mob/living/simple_animal/frog/scream/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/squeak, squeak_sound, 50, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) //as quiet as a frog or whatever
+
+/mob/living/simple_animal/frog/toxic/scream
+ var/squeak_sound = list ('modular_ss220/mobs/sound/creatures/frog_scream1.ogg','modular_ss220/mobs/sound/creatures/frog_scream2.ogg')
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/frog/toxic/scream/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/squeak, squeak_sound, 50, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) //as quiet as a frog or whatever
+
+// Additional procs
+/mob/living/simple_animal/frog/handle_automated_movement()
+ . = ..()
+ if(!resting && !buckled)
+ if(prob(1))
+ custom_emote(1,"издаёт боевой клич!")
+ playsound(src, pick(src.scream_sound), 50, TRUE)
+
+/mob/living/simple_animal/frog/emote(emote_key, type_override = 1, message, intentional, force_silence)
+ if(incapacitated())
+ return
+
+ var/on_CD = 0
+ emote_key = lowertext(emote_key)
+ switch(emote_key)
+ if("warcry")
+ on_CD = start_audio_emote_cooldown()
+ else
+ on_CD = 0
+
+ if(!force_silence && on_CD == 1)
+ return
+
+ switch(emote_key)
+ if("warcry")
+ message = "издаёт боевой клич!"
+ type_override = 2 //audible
+ playsound(src, pick(src.scream_sound), 50, TRUE)
+ if("help")
+ to_chat(src, "warcry")
+ ..()
+
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/hamster.dm b/modular_ss220/mobs/code/simple_animal/friendly/hamster.dm
new file mode 100644
index 000000000000..847c3ce70874
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/hamster.dm
@@ -0,0 +1,96 @@
+/mob/living/simple_animal/mouse/hamster
+ name = "хомяк"
+ real_name = "хомяк"
+ desc = "С надутыми щечками."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "hamster"
+ icon_living = "hamster"
+ icon_dead = "hamster_dead"
+ icon_resting = "hamster_rest"
+ gender = MALE
+ non_standard = TRUE
+ speak_chance = 0
+ childtype = list(/mob/living/simple_animal/mouse/hamster/baby)
+ animal_species = /mob/living/simple_animal/mouse/hamster
+ holder_type = /obj/item/holder/hamster
+ gold_core_spawnable = FRIENDLY_SPAWN
+ maxHealth = 10
+ health = 10
+
+
+/mob/living/simple_animal/mouse/hamster/baby
+ name = "хомячок"
+ real_name = "хомячок"
+ desc = "Очень миленький! Какие у него пушистые щечки!"
+ turns_per_move = 2
+ response_help = "полапал"
+ response_disarm = "аккуратно отодвинул"
+ response_harm = "пихнул"
+ attacktext = "толкается"
+ transform = matrix(0.7, 0, 0, 0, 0.7, 0)
+ health = 3
+ maxHealth = 3
+ var/amount_grown = 0
+ can_hide = 1
+ can_collar = 0
+ holder_type = /obj/item/holder/hamster
+
+// Hamster procs
+#define MAX_HAMSTER 20
+GLOBAL_VAR_INIT(hamster_count, 0)
+
+/mob/living/simple_animal/mouse/hamster/Initialize(mapload)
+ . = ..()
+ gender = prob(80) ? MALE : FEMALE
+
+ icon_state = initial(icon_state)
+ icon_living = initial(icon_living)
+ icon_dead = initial(icon_dead)
+ icon_resting = initial(icon_resting)
+
+ update_appearance(UPDATE_ICON_STATE, UPDATE_DESC)
+ GLOB.hamster_count++
+
+/mob/living/simple_animal/mouse/hamster/Destroy()
+ GLOB.hamster_count--
+ . = ..()
+
+/mob/living/simple_animal/mouse/hamster/color_pick()
+ return
+
+/mob/living/simple_animal/mouse/hamster/update_desc()
+ . = ..()
+ desc = initial(desc)
+ desc += MALE ? " Самец!" : " Самочка! Ох... Нет... "
+
+/mob/living/simple_animal/mouse/hamster/pull_constraint(atom/movable/AM, show_message = FALSE)
+ return TRUE
+
+/mob/living/simple_animal/mouse/hamster/Life(seconds, times_fired)
+ ..()
+ if(GLOB.hamster_count < MAX_HAMSTER)
+ make_babies()
+
+/mob/living/simple_animal/mouse/hamster/baby/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
+ if(show_message)
+ to_chat(src, span_warning("Вы слишком малы чтобы что-то тащить."))
+ return
+
+/mob/living/simple_animal/mouse/hamster/baby/Life(seconds, times_fired)
+ . =..()
+ if(.)
+ amount_grown++
+ if(amount_grown >= 100)
+ var/mob/living/simple_animal/A = new /mob/living/simple_animal/mouse/hamster(loc)
+ if(mind)
+ mind.transfer_to(A)
+ qdel(src)
+
+/mob/living/simple_animal/mouse/hamster/baby/Crossed(AM as mob|obj, oldloc)
+ if(ishuman(AM))
+ if(!stat)
+ var/mob/M = AM
+ to_chat(M, span_notice("[bicon(src)] раздавлен!"))
+ death()
+ splat(user = AM)
+ ..()
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/lizard.dm b/modular_ss220/mobs/code/simple_animal/friendly/lizard.dm
new file mode 100644
index 000000000000..309255b67206
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/lizard.dm
@@ -0,0 +1,14 @@
+/mob/living/simple_animal/lizard
+ death_sound = 'modular_ss220/mobs/sound/creatures/lizard_death.ogg'
+ holder_type = /obj/item/holder/lizard
+
+/mob/living/simple_animal/lizard/axolotl
+ name = "Аксолотль"
+ desc = "Маленький милый аксолотль."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "axolotl"
+ icon_living = "axolotl"
+ icon_dead = "axolotl_dead"
+ holder_type = /obj/item/holder/axolotl
+
+
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/moth.dm b/modular_ss220/mobs/code/simple_animal/friendly/moth.dm
new file mode 100644
index 000000000000..c41c715b0fbb
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/moth.dm
@@ -0,0 +1,29 @@
+/mob/living/simple_animal/moth
+ name = "моль"
+ desc = "Смотря на эту моль становится понятно куда пропали шубы перевозимые СССП."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "moth"
+ icon_living = "moth"
+ icon_dead = "moth_dead"
+ turns_per_move = 1
+ emote_see = list("flutters")
+ response_help = "shoos"
+ response_disarm = "brushes aside"
+ response_harm = "squashes"
+ speak_chance = 0
+ maxHealth = 15
+ health = 15
+ see_in_dark = 100
+ friendly = "nudges"
+ density = 0
+ initial_traits = list(TRAIT_FLYING)
+ pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
+ ventcrawler = 2
+ mob_size = MOB_SIZE_TINY
+ butcher_results = list(/obj/item/food/monstermeat/xenomeat = 1)
+ gold_core_spawnable = FRIENDLY_SPAWN
+ holder_type = /obj/item/holder/moth
+
+/mob/living/simple_animal/nian_caterpillar/Initialize(mapload)
+ . = ..()
+ butcher_results |= list(/obj/item/stack/sheet/animalhide/mothroach = 1)
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/mouse.dm b/modular_ss220/mobs/code/simple_animal/friendly/mouse.dm
new file mode 100644
index 000000000000..f5d8cae71425
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/mouse.dm
@@ -0,0 +1,78 @@
+/mob/living/simple_animal/mouse
+ var/non_standard = FALSE // for no "mouse_" with mouse_color
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ death_sound = 'modular_ss220/mobs/sound/creatures/rat_death.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/rat_talk.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/rat_wound.ogg')
+ blood_volume = BLOOD_VOLUME_SURVIVE
+ butcher_results = list(/obj/item/food/meat/mouse = 1)
+
+/mob/living/simple_animal/mouse/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/squeak, list("[squeak_sound]" = 1), 100, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) //as quiet as a mouse or whatever
+
+ pixel_x = rand(-6, 6)
+ pixel_y = rand(0, 10)
+
+ mouse_color = initial(mouse_color) // сбрасываем из-за наследования чтобы своим проком переписать
+ color_pick()
+ update_appearance(UPDATE_ICON_STATE|UPDATE_DESC)
+
+/mob/living/simple_animal/mouse/proc/color_pick()
+ if(!mouse_color)
+ mouse_color = pick( list("brown","gray","white") )
+ icon_state = "mouse_[mouse_color]"
+ icon_living = "mouse_[mouse_color]"
+ icon_dead = "mouse_[mouse_color]_dead"
+ icon_resting = "mouse_[mouse_color]_sleep"
+
+/mob/living/simple_animal/mouse/splat(obj/item/item = null, mob/living/user = null)
+ if(non_standard)
+ var/temp_state = initial(icon_state)
+ icon_dead = "[temp_state]_splat"
+ icon_state = "[temp_state]_splat"
+ else
+ ..()
+
+ if(prob(50))
+ var/turf/location = get_turf(src)
+ add_splatter_floor(location)
+ if(item)
+ item.add_mob_blood(src)
+ if(user)
+ user.add_mob_blood(src)
+
+/mob/living/simple_animal/mouse/death(gibbed)
+ if(gibbed)
+ make_remains()
+ . = ..(gibbed)
+
+/mob/living/simple_animal/mouse/proc/make_remains()
+ var/obj/effect/decal/remains = new /obj/effect/decal/remains/mouse(src.loc)
+ remains.pixel_x = pixel_x
+ remains.pixel_y = pixel_y
+
+
+// /mob/living/simple_animal/mouse/emote(act, m_type = 1, message = null, force)
+
+// if("help")
+// to_chat(src, "scream, squeak")
+// playsound(src, damaged_sound, 40, 1)
+
+/mob/living/simple_animal/mouse/brown/tom
+ maxHealth = 10
+ health = 10
+
+/mob/living/simple_animal/mouse/fluff/clockwork
+ name = "Chip"
+ real_name = "Chip"
+ mouse_color = "clockwork"
+ icon_state = "mouse_clockwork"
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "stamps on"
+ gold_core_spawnable = NO_SPAWN
+ can_collar = 0
+ butcher_results = list(/obj/item/stack/sheet/metal = 1)
+ maxHealth = 20
+ health = 20
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/possum.dm b/modular_ss220/mobs/code/simple_animal/friendly/possum.dm
new file mode 100644
index 000000000000..aad8c2b75514
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/possum.dm
@@ -0,0 +1,50 @@
+/mob/living/simple_animal/possum
+ name = "possum"
+ desc = "The opossum is a small, scavenging marsupial of the order Didelphimorphia, previously \
+ endemic to the Americas of Earth, but now inexplicably found across settled space. Nobody is \
+ entirely sure how they travel to such disparate locations, with the leading theories including \
+ smuggling, cargo stowaways, fungal spore reproduction, teleportation, or unknown quantum effects."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "possum"
+ icon_living = "possum"
+ icon_dead = "possum_dead"
+ icon_resting = "possum_sleep"
+ var/icon_harm = "possum_aaa"
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "kicks"
+ speak = list("Hsss...", "Hisss...")
+ speak_emote = list("Hsss", "Hisss")
+ emote_hear = list("Aaaaa!", "Ahhss!")
+ emote_see = list("shakes its head.", "chases its tail.", "shivers.")
+ faction = list("neutral")
+ maxHealth = 30
+ health = 30
+ mob_size = MOB_SIZE_SMALL
+ pass_flags = PASSTABLE
+ ventcrawler = VENTCRAWLER_ALWAYS
+ blood_volume = BLOOD_VOLUME_NORMAL
+ melee_damage_type = STAMINA
+ melee_damage_lower = 3
+ melee_damage_upper = 8
+ attacktext = "кусает"
+ attack_sound = 'sound/weapons/bite.ogg'
+ see_in_dark = 5
+ speak_chance = 1
+ turns_per_move = 10
+ gold_core_spawnable = FRIENDLY_SPAWN
+ footstep_type = FOOTSTEP_MOB_CLAW
+ butcher_results = list(/obj/item/food/meat = 2)
+ holder_type = /obj/item/holder/possum
+
+/mob/living/simple_animal/possum/attackby__legacy__attackchain(obj/item/O, mob/living/user)
+ icon_state = icon_harm
+ . = ..()
+
+/mob/living/simple_animal/possum/attack_hand(mob/living/carbon/human/M)
+ switch(M.a_intent)
+ if(INTENT_HELP)
+ icon_state = initial(icon_state)
+ if(INTENT_HARM, INTENT_DISARM, INTENT_GRAB)
+ icon_state = icon_harm
+ . = ..()
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/rat.dm b/modular_ss220/mobs/code/simple_animal/friendly/rat.dm
new file mode 100644
index 000000000000..4269efa853f5
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/rat.dm
@@ -0,0 +1,59 @@
+/mob/living/simple_animal/mouse/rat
+ name = "rat"
+ real_name = "rat"
+ desc = "Серая крыса. Не яркий представитель своего вида."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ squeak_sound = 'modular_ss220/mobs/sound/creatures/rat_squeak.ogg'
+ icon_state = "rat_gray"
+ icon_living = "rat_gray"
+ icon_dead = "rat_gray_dead"
+ icon_resting = "rat_gray_sleep"
+ non_standard = TRUE
+ mouse_color = null
+ maxHealth = 15
+ health = 15
+ mob_size = MOB_SIZE_SMALL
+ butcher_results = list(/obj/item/food/meat/mouse = 2)
+
+/mob/living/simple_animal/mouse/rat/update_desc()
+ . = ..()
+ switch(mouse_color)
+ if("white")
+ desc = /mob/living/simple_animal/mouse/rat/white::desc
+ if("irish")
+ desc = /mob/living/simple_animal/mouse/rat/irish::desc
+ else
+ desc = /mob/living/simple_animal/mouse/rat::desc
+
+/mob/living/simple_animal/mouse/rat/white
+ name = "white rat"
+ real_name = "white rat"
+ desc = "Типичный представитель лабораторных крыс."
+ icon_state = "rat_white"
+ icon_living = "rat_white"
+ icon_dead = "rat_white_dead"
+ icon_resting = "rat_white_sleep"
+ mouse_color = "white"
+
+/mob/living/simple_animal/mouse/rat/irish
+ name = "irish rat"
+ real_name = "irish rat"
+ desc = "Ирландская крыса, борец за независимость. На космической станции?! На этот раз им точно некуда бежать!"
+ icon_state = "rat_irish"
+ icon_living = "rat_irish"
+ icon_dead = "rat_irish_dead"
+ icon_resting = "rat_irish_sleep"
+ mouse_color = "irish"
+
+/mob/living/simple_animal/mouse/rat/color_pick()
+ if(!mouse_color)
+ mouse_color = pick(list("gray","white","irish"))
+ icon_state = "rat_[mouse_color]"
+ icon_living = "rat_[mouse_color]"
+ icon_dead = "rat_[mouse_color]_dead"
+ icon_resting = "rat_[mouse_color]_sleep"
+
+/mob/living/simple_animal/mouse/rat/pull_constraint(atom/movable/AM, show_message = FALSE)
+ return TRUE
+
+
diff --git a/modular_ss220/mobs/code/simple_animal/friendly/snail.dm b/modular_ss220/mobs/code/simple_animal/friendly/snail.dm
new file mode 100644
index 000000000000..e887ff0bfe0d
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/friendly/snail.dm
@@ -0,0 +1,85 @@
+/mob/living/simple_animal/snail
+ name = "space snail"
+ desc = "Маленькая космо-улиточка со своим космо-домиком. Прочная, тихая и медленная."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "snail"
+ icon_living = "snail"
+ icon_dead = "snail_dead"
+ speak = list("Uhh.", "Hurrr.")
+ health = 100
+ maxHealth = 100
+ speed = 10
+ attacktext = "толкает"
+ death_sound = 'modular_ss220/mobs/sound/creatures/crack_death1.ogg'
+ response_help = "pets"
+ response_disarm = "shoos"
+ response_harm = "stomps on"
+ ventcrawler = 2
+ density = 0
+ pass_flags = PASSTABLE | PASSMOB
+ mob_size = MOB_SIZE_SMALL
+ gender = NEUTER
+ can_hide = 1
+ butcher_results = list(/obj/item/food/salmonmeat/snailmeat = 1, /obj/item/stack/ore/tranquillite = 1)
+ can_collar = 1
+ gold_core_spawnable = FRIENDLY_SPAWN
+ stop_automated_movement_when_pulled = 0
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ faction = list("slime", "neutral")
+ reagents = new()
+ holder_type = /obj/item/holder/snail
+
+/mob/living/simple_animal/snail/Process_Spacemove(movement_dir = 0)
+ return 1
+
+/mob/living/simple_animal/snail/Move(atom/newloc, direct, movetime)
+ var/oldLoc = src.loc
+ . = ..()
+ if(.)
+ if(stat != DEAD)
+ make_wet_floor(oldLoc)
+
+/mob/living/simple_animal/snail/proc/make_wet_floor(atom/oldLoc)
+ if(oldLoc != src.loc)
+ reagents.add_reagent("water",10)
+ reagents.reaction(oldLoc, REAGENT_TOUCH, 10) //10 is the multiplier for the reaction effect. probably needed to wet the floor properly.
+ reagents.remove_any(10)
+
+/mob/living/simple_animal/snail/lube
+ name = "space snail"
+ desc = "Маленькая космо-улиточка со своим космо-домиком. Прочная, тихая и медленная. И очень склизкая."
+ gold_core_spawnable = HOSTILE_SPAWN
+ faction = list("slime", "hostile")
+
+/mob/living/simple_animal/snail/lube/make_wet_floor(atom/oldLoc)
+ if(oldLoc != src.loc)
+ reagents.add_reagent("lube",10)
+ reagents.reaction(oldLoc, REAGENT_TOUCH, 10)
+ reagents.remove_any(10)
+
+/mob/living/simple_animal/turtle
+ name = "черепаха"
+ desc = "Большая космочерепаха. Прочная, тихая и медленная."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "yeeslow"
+ icon_living = "yeeslow"
+ icon_dead = "yeeslow_dead"
+ icon_resting = "yeeslow_scared"
+ speak = list("Uhh.", "Hurrr.")
+ health = 500
+ maxHealth = 500
+ speed = 20
+ attacktext = "толкает"
+ death_sound = 'modular_ss220/mobs/sound/creatures/crack_death1.ogg'
+ response_help = "pets"
+ response_disarm = "shoos"
+ response_harm = "stomps on"
+ ventcrawler = 0
+ density = 1
+ pass_flags = PASSTABLE | PASSGRILLE
+ status_flags = CANPARALYSE | CANPUSH
+ mob_size = MOB_SIZE_SMALL
+ butcher_results = list(/obj/item/food/salmonmeat/turtlemeat = 10, /obj/item/stack/ore/tranquillite = 5)
+ footstep_type = FOOTSTEP_MOB_SLIME
+ holder_type = /obj/item/holder/turtle
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/alien.dm b/modular_ss220/mobs/code/simple_animal/hostile/alien.dm
new file mode 100644
index 000000000000..938a3ff541d3
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/alien.dm
@@ -0,0 +1,2 @@
+/mob/living/simple_animal/hostile/alien
+ attacktext = "кромсает"
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/bear.dm b/modular_ss220/mobs/code/simple_animal/hostile/bear.dm
new file mode 100644
index 000000000000..938b44a71ed7
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/bear.dm
@@ -0,0 +1,10 @@
+/mob/living/simple_animal/hostile/bear
+ attacktext = "терзает"
+ death_sound = 'modular_ss220/mobs/sound/creatures/bear_death.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/bear_talk1.ogg', 'modular_ss220/mobs/sound/creatures/bear_talk2.ogg', 'modular_ss220/mobs/sound/creatures/bear_talk3.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/bear_onerawr1.ogg', 'modular_ss220/mobs/sound/creatures/bear_onerawr2.ogg', 'modular_ss220/mobs/sound/creatures/bear_onerawr3.ogg')
+ var/trigger_sound = 'modular_ss220/mobs/sound/creatures/bear_rawr.ogg'
+
+/mob/living/simple_animal/hostile/bear/handle_automated_movement()
+ if(..())
+ playsound(src, src.trigger_sound, 40, 1)
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/bee.dm b/modular_ss220/mobs/code/simple_animal/hostile/bee.dm
new file mode 100644
index 000000000000..6d70cd380b84
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/bee.dm
@@ -0,0 +1,2 @@
+/mob/living/simple_animal/hostile/poison/bees
+ holder_type = /obj/item/holder/bee
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/headcrab.dm b/modular_ss220/mobs/code/simple_animal/hostile/headcrab.dm
new file mode 100644
index 000000000000..f896b3cbede6
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/headcrab.dm
@@ -0,0 +1,194 @@
+// port old headcrabs
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab
+ name = "headcrab"
+ desc = "A small parasitic creature that would like to connect with your brain stem."
+ icon = 'modular_ss220/mobs/icons/mob/headcrab.dmi'
+ icon_state = "headcrab"
+ icon_living = "headcrab"
+ icon_dead = "headcrab_dead"
+ health = 60
+ maxHealth = 60
+ dodging = 1
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ ranged = 1
+ ranged_message = "leaps"
+ ranged_cooldown_time = 40
+ var/jumpdistance = 4
+ var/jumpspeed = 1
+ attacktext = "грызёт"
+ attack_sound = 'modular_ss220/mobs/sound/creatures/headcrab_attack.ogg'
+ speak_emote = list("hisses")
+ var/is_zombie = 0
+ stat_attack = DEAD // Necessary for them to attack (zombify) dead humans
+ robust_searching = 1
+ var/host_species = ""
+ var/list/human_overlays = list()
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/Life(seconds, times_fired)
+ if(..() && !stat)
+ if(!is_zombie && isturf(src.loc))
+ for(var/mob/living/carbon/human/H in oview(src, 1)) //Only for corpse right next to/on same tile
+ if(H.stat == DEAD || (!H.check_death_method() && H.health <= HEALTH_THRESHOLD_DEAD))
+ Zombify(H)
+ break
+ if(times_fired % 4 == 0)
+ for(var/mob/living/simple_animal/K in oview(src, 1)) //Only for corpse right next to/on same tile
+ if(K.stat == DEAD || (!K.check_death_method() && K.health <= HEALTH_THRESHOLD_DEAD))
+ visible_message(span_danger("[src] consumes [K] whole!"))
+ if(health < maxHealth)
+ health += 10
+ qdel(K)
+ break
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/OpenFire(atom/A)
+ if(check_friendly_fire)
+ for(var/turf/T in get_line(src,A)) // Not 100% reliable but this is faster than simulating actual trajectory
+ for(var/mob/living/L in T)
+ if(L == src || L == A)
+ continue
+ if(faction_check_mob(L) && !attack_same)
+ return
+ visible_message(span_danger("[src] [ranged_message] at [A]!"))
+ throw_at(A, jumpdistance, jumpspeed, spin = FALSE, diagonals_first = TRUE)
+ ranged_cooldown = world.time + ranged_cooldown_time
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/proc/Zombify(mob/living/carbon/human/H)
+ if(!H.check_death_method())
+ H.death()
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ is_zombie = TRUE
+ if(H.wear_suit)
+ var/obj/item/clothing/suit/armor/A = H.wear_suit
+ if(A.armor && A.armor.getRating("melee"))
+ maxHealth += A.armor.getRating("melee") //That zombie's got armor, I want armor!
+ maxHealth += 200
+ health = maxHealth
+ name = "zombie"
+ desc = "A corpse animated by the alien being on its head."
+ melee_damage_lower = 10
+ melee_damage_upper = 15
+ ranged = 0
+ stat_attack = CONSCIOUS // Disables their targeting of dead mobs once they're already a zombie
+ icon = H.icon
+ speak = list('modular_ss220/mobs/sound/creatures/zombie_idle1.ogg','modular_ss220/mobs/sound/creatures/zombie_idle2.ogg','modular_ss220/mobs/sound/creatures/zombie_idle3.ogg')
+ speak_chance = 50
+ speak_emote = list("groans")
+ attacktext = "грызёт"
+ attack_sound = 'modular_ss220/mobs/sound/creatures/zombie_attack.ogg'
+ icon_state = "zombie2_s"
+ if(head_organ)
+ head_organ.h_style = null
+ H.update_hair()
+ host_species = H.dna.species.name
+ human_overlays = H.overlays
+ update_icons()
+ H.forceMove(src)
+ visible_message(span_warning("The corpse of [H.name] suddenly rises!"))
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/death()
+ ..()
+ if(is_zombie)
+ qdel(src)
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/handle_automated_speech() // This way they have different screams when attacking, sometimes. Might be seen as sphagetthi code though.
+ if(speak_chance)
+ if(rand(0,200) < speak_chance)
+ if(speak && speak.len)
+ playsound(get_turf(src), pick(speak), 200, 1)
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/Destroy()
+ if(contents)
+ for(var/mob/M in contents)
+ M.loc = get_turf(src)
+ return ..()
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/update_icons()
+ . = ..()
+ if(is_zombie)
+ overlays.Cut()
+ overlays = human_overlays
+ var/image/I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "headcrabpod")
+ if(host_species == "Vox")
+ I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "headcrabpod_vox")
+ else if(host_species == "Gray")
+ I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "headcrabpod_gray")
+ overlays += I
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/CanAttack(atom/the_target)
+ if(stat_attack == DEAD && isliving(the_target) && !ishuman(the_target))
+ var/mob/living/L = the_target
+ if(L.stat == DEAD)
+ // Override default behavior of stat_attack, to stop headcrabs targeting dead mobs they cannot infect, such as silicons.
+ return FALSE
+ return ..()
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/fast
+ name = "fast headcrab"
+ desc = "A fast parasitic creature that would like to connect with your brain stem."
+ icon = 'modular_ss220/mobs/icons/mob/headcrab.dmi'
+ icon_state = "fast_headcrab"
+ icon_living = "fast_headcrab"
+ icon_dead = "fast_headcrab_dead"
+ health = 40
+ maxHealth = 40
+ ranged_cooldown_time = 30
+ jumpdistance = 8
+ jumpspeed = 2
+ speak_emote = list("screech")
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/fast/update_icons()
+ . = ..()
+ if(is_zombie)
+ overlays.Cut()
+ overlays = human_overlays
+ var/image/I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "fast_headcrabpod")
+ if(host_species == "Vox")
+ I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "fast_headcrabpod_vox")
+ else if(host_species == "Gray")
+ I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "fast_headcrabpod_gray")
+ overlays += I
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/fast/Zombify(mob/living/carbon/human/H)
+ . = ..()
+ speak = list('modular_ss220/mobs/sound/creatures/fast_zombie_idle1.ogg','modular_ss220/mobs/sound/creatures/fast_zombie_idle2.ogg','modular_ss220/mobs/sound/creatures/fast_zombie_idle3.ogg')
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/poison
+ name = "poison headcrab"
+ desc = "A poison parasitic creature that would like to connect with your brain stem."
+ icon = 'modular_ss220/mobs/icons/mob/headcrab.dmi'
+ icon_state = "poison_headcrab"
+ icon_living = "poison_headcrab"
+ icon_dead = "poison_headcrab_dead"
+ health = 80
+ maxHealth = 80
+ ranged_cooldown_time = 50
+ jumpdistance = 3
+ jumpspeed = 1
+ melee_damage_lower = 8
+ melee_damage_upper = 20
+ attack_sound = 'modular_ss220/mobs/sound/creatures/ph_scream1.ogg'
+ speak_emote = list("screech")
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/poison/update_icons()
+ . = ..()
+ if(is_zombie)
+ overlays.Cut()
+ overlays = human_overlays
+ var/image/I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "poison_headcrabpod")
+ if(host_species == "Vox")
+ I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "poison_headcrabpod_vox")
+ else if(host_species == "Gray")
+ I = image('modular_ss220/mobs/icons/mob/headcrab.dmi', icon_state = "poison_headcrabpod_gray")
+ overlays += I
+
+
+/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/poison/AttackingTarget()
+ . = ..()
+ if(iscarbon(target) && target.reagents)
+ var/inject_target = pick("chest", "head")
+ var/mob/living/carbon/C = target
+ if(C.IsStunned() || C.can_inject(null, FALSE, inject_target, FALSE))
+ if(C.AmountEyeBlurry() < 60)
+ C.AdjustEyeBlurry(10)
+ visible_message(span_danger("[src] buries its fangs deep into the [inject_target] of [target]!"))
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/lizard.dm b/modular_ss220/mobs/code/simple_animal/hostile/lizard.dm
new file mode 100644
index 000000000000..da2e3befb375
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/lizard.dm
@@ -0,0 +1,71 @@
+/mob/living/simple_animal/hostile/lizard
+ name = "игуана"
+ desc = "Грациозный предок космодраконов. Её взгляд не вызывает никаких враждебных подозрений... Но она по прежнему хочет съесть вас."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "iguana"
+ icon_living = "iguana"
+ icon_dead = "iguana_dead"
+ speak = list("RAWR!","Rawr!","GRR!","Growl!")
+ speak_emote = list("growls", "roars")
+ emote_hear = list("rawrs","grumbles","grawls")
+ emote_see = list("stares ferociously", "stomps")
+ speak_chance = 1
+ turns_per_move = 5
+ see_in_dark = 6
+ butcher_results = list(/obj/item/food/monstermeat/lizardmeat = 3, /obj/item/stack/sheet/animalhide/lizard = 1)
+ response_help = "погладил"
+ response_disarm = "аккуратно оттолкнул"
+ response_harm = "ударил"
+ stop_automated_movement_when_pulled = 0
+ speed = 2
+ maxHealth = 40
+ health = 40
+ blood_volume = BLOOD_VOLUME_NORMAL
+ obj_damage = 60
+ melee_damage_lower = 20
+ melee_damage_upper = 30
+ attacktext = "терзает"
+ attack_sound = 'sound/weapons/bite.ogg'
+ death_sound = 'modular_ss220/mobs/sound/creatures/lizard_death_big.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/lizard_angry1.ogg', 'modular_ss220/mobs/sound/creatures/lizard_angry2.ogg', 'modular_ss220/mobs/sound/creatures/lizard_angry3.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/lizard_damaged.ogg')
+ footstep_type = FOOTSTEP_MOB_CLAW
+
+ minbodytemp = 250 //Weak to cold
+ maxbodytemp = T0C + 200
+
+ gold_core_spawnable = HOSTILE_SPAWN
+
+/mob/living/simple_animal/hostile/lizard/gator
+ name = "аллигатор"
+ desc = "Величавый аллигатор, так и норовящийся оторвать от вас самый лакомый кусочек. Или кусок. Не путать с крокодилом!"
+ icon_state = "gator"
+ icon_living = "gator"
+ icon_dead = "gator_dead"
+ butcher_results = list(/obj/item/food/monstermeat/lizardmeat = 7, /obj/item/stack/sheet/animalhide/lizard = 5)
+ speed = 4
+ maxHealth = 200
+ health = 200
+ obj_damage = 80
+ melee_damage_lower = 30
+ melee_damage_upper = 80
+
+/mob/living/simple_animal/hostile/lizard/croco
+ name = "крокодил"
+ desc = "Не стоит сувать голову ему в пасть! Это негативно сказывается на умственных способностях"
+ icon_state = "steppy"
+ icon_living = "steppy"
+ icon_dead = "steppy_dead"
+ butcher_results = list(/obj/item/food/monstermeat/lizardmeat = 5, /obj/item/stack/sheet/animalhide/lizard = 3)
+ maxHealth = 100
+ health = 100
+ obj_damage = 80
+ melee_damage_lower = 20
+ melee_damage_upper = 50
+
+
+
+
+
+
+
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/snake.dm b/modular_ss220/mobs/code/simple_animal/hostile/snake.dm
new file mode 100644
index 000000000000..101d46e3c8cd
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/snake.dm
@@ -0,0 +1,5 @@
+/mob/living/simple_animal/hostile/retaliate/poison/snake
+ attacktext = "кусает"
+ attack_sound = 'sound/weapons/bite.ogg'
+ death_sound = 'modular_ss220/mobs/sound/creatures/snake_death.ogg'
+ holder_type = /obj/item/holder/snake
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/spider.dm b/modular_ss220/mobs/code/simple_animal/hostile/spider.dm
new file mode 100644
index 000000000000..8ae8750a47d1
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/spider.dm
@@ -0,0 +1,23 @@
+//Giants
+
+/mob/living/simple_animal/hostile/poison/giant_spider
+ death_sound = 'modular_ss220/mobs/sound/creatures/spider_death.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/spider_talk1.ogg', 'modular_ss220/mobs/sound/creatures/spider_talk2.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/spider_attack1.ogg', 'modular_ss220/mobs/sound/creatures/spider_attack2.ogg')
+ attacktext = "кусает"
+ response_help = "лапает"
+ response_disarm = "осторожно отталкивает"
+ friendly = "осторожно проводит лапками по"
+
+// Terrors
+/mob/living/simple_animal/hostile/poison/terror_spider
+ response_help = "лапает"
+ response_disarm = "осторожно отталкивает"
+ friendly = "осторожно проводит лапками по"
+ death_sound = 'modular_ss220/mobs/sound/creatures/spider_death.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/spider_talk1.ogg', 'modular_ss220/mobs/sound/creatures/spider_talk2.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/spider_attack1.ogg', 'modular_ss220/mobs/sound/creatures/spider_attack2.ogg')
+ attacktext = "кусает"
+ response_help = "лапает"
+ response_disarm = "осторожно отталкивает"
+ friendly = "осторожно проводит лапками по"
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/syndi_rat.dm b/modular_ss220/mobs/code/simple_animal/hostile/syndi_rat.dm
new file mode 100644
index 000000000000..0a780c08c10c
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/syndi_rat.dm
@@ -0,0 +1,118 @@
+/mob/living/simple_animal/hostile/retaliate/syndirat
+ name = "Синди-мышь"
+ desc = "Мышь на службе синдиката?"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "syndirat"
+ icon_living = "syndirat"
+ icon_dead = "syndirat_dead"
+ icon_resting = "syndirat_sleep"
+ response_help = "pets the"
+ response_disarm = "gently pushes aside the"
+ response_harm = "stamps on the"
+ health = 50
+ maxHealth = 50
+ speak_chance = 2
+ turns_per_move = 5
+ pull_force = 1000
+ density = 0
+ ventcrawler = 2
+ can_hide = 1
+ can_collar = 1
+ pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
+ see_in_dark = 6
+ speak = list("Слава Синдикату!","Смерть НаноТрейзен!", "У вас есть сыр?")
+ speak_emote = list("squeeks","squeaks","squiks")
+ emote_hear = list("squeeks","squeaks","squiks")
+ emote_see = list("runs in a circle", "shakes", "scritches at something")
+
+ mob_size = MOB_SIZE_TINY // If theyre not at least small it doesnt seem like the treadmill works or makes sound
+ pass_flags = PASSTABLE
+ stop_automated_movement = 1
+
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+
+ ranged = 1
+ projectiletype = /obj/item/projectile/beam/disabler
+
+ attack_sound = 'sound/weapons/punch1.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/rat_talk.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/rat_wound.ogg')
+ death_sound = 'modular_ss220/mobs/sound/creatures/rat_death.ogg'
+
+ harm_intent_damage = 5
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ var/chew_probability = 1
+ var/squeak_sound = 'sound/creatures/mousesqueak.ogg'
+
+/mob/living/simple_animal/hostile/retaliate/syndirat/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/squeak, list('sound/creatures/mousesqueak.ogg' = 1), 100, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) //as quiet as a mouse or whatever
+
+/mob/living/simple_animal/hostile/retaliate/syndirat/handle_automated_action()
+ if(prob(chew_probability) && isturf(loc))
+ var/turf/simulated/floor/F = get_turf(src)
+ if(istype(F) && !F.intact)
+ var/obj/structure/cable/C = locate() in F
+ if(C && prob(15))
+ if(C.get_available_power() && !HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
+ visible_message(span_warning("[src] chews through [C]. It's toast!"))
+ playsound(src, 'sound/effects/sparks2.ogg', 100, 1)
+ toast() // mmmm toasty.
+ else
+ visible_message(span_warning("[src] chews through [C]."))
+ investigate_log("was chewed through by a mouse at [COORD(F)]", "wires")
+ C.deconstruct()
+
+/mob/living/simple_animal/hostile/retaliate/syndirat/proc/toast()
+ add_atom_colour("#3A3A3A", FIXED_COLOUR_PRIORITY)
+ desc = "It's toast."
+ death()
+
+/mob/living/simple_animal/hostile/retaliate/syndirat/handle_automated_speech()
+ ..()
+ if(prob(speak_chance) && !incapacitated())
+ playsound(src, squeak_sound, 100, 1)
+
+/mob/living/simple_animal/hostile/retaliate/syndirat/handle_automated_movement()
+ . = ..()
+ if(resting)
+ if(prob(1))
+ on_standing_up()
+ else if(prob(5))
+ custom_emote(2, "snuffles")
+ else if(prob(0.5))
+ on_lying_down()
+
+/mob/living/simple_animal/hostile/retaliate/syndirat/Crossed(AM as mob|obj, oldloc)
+ if(ishuman(AM))
+ if(!stat)
+ var/mob/M = AM
+ to_chat(M, span_notice("[bicon(src)] Squeek!"))
+ ..()
+
+/mob/living/simple_animal/hostile/retaliate/syndirat/emote(emote_key, type_override = 1, message, intentional, force_silence)
+ if(stat != CONSCIOUS)
+ return
+
+ var/on_CD = 0
+ emote_key = lowertext(emote_key)
+ switch(emote_key)
+ if("squeak") //Mouse time
+ on_CD = start_audio_emote_cooldown()
+ else
+ on_CD = 0
+
+ if(!force_silence && on_CD == 1)
+ return
+
+ switch(emote_key)
+ if("squeak")
+ message = "[pick(emote_hear)]!"
+ type_override = 2 //audible
+ playsound(src, squeak_sound, 40, 1)
+ if("help")
+ to_chat(src, "scream, squeak")
+
+ ..()
diff --git a/modular_ss220/mobs/code/simple_animal/hostile/undead.dm b/modular_ss220/mobs/code/simple_animal/hostile/undead.dm
new file mode 100644
index 000000000000..7a9db442d4cd
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/hostile/undead.dm
@@ -0,0 +1,12 @@
+/mob/living/simple_animal/hostile/undead
+ attacktext = "бьет"
+ attack_sound = 'modular_ss220/mobs/sound/creatures/zombie_attack.ogg'
+ death_sound = 'modular_ss220/mobs/sound/creatures/zombie_idle2.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/zombie_idle1.ogg', 'modular_ss220/mobs/sound/creatures/zombie_idle3.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/zombie_idle1.ogg', 'modular_ss220/mobs/sound/creatures/zombie_idle2.ogg', 'modular_ss220/mobs/sound/creatures/zombie_idle3.ogg')
+
+/mob/living/simple_animal/hostile/undead/zombie/fast
+ death_sound = 'modular_ss220/mobs/sound/creatures/fast_zombie_idle3.ogg'
+ talk_sound = list('modular_ss220/mobs/sound/creatures/fast_zombie_idle1.ogg', 'modular_ss220/mobs/sound/creatures/fast_zombie_idle2.ogg')
+ damaged_sound = list('modular_ss220/mobs/sound/creatures/fast_zombie_idle1.ogg')
+
diff --git a/modular_ss220/mobs/code/simple_animal/items.dm b/modular_ss220/mobs/code/simple_animal/items.dm
new file mode 100644
index 000000000000..9c792a9d2ac1
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/items.dm
@@ -0,0 +1,56 @@
+// Meat
+/obj/item/food/meat/dog
+ name = "dog meat"
+ desc = "Не слишком питательно. Но говорят деликатес космокорейцев."
+ list_reagents = list("protein" = 2, "epinephrine" = 2)
+
+/obj/item/food/meat/security
+ name = "security meat"
+ desc = "Мясо наполненное чувством мужества и долга."
+ list_reagents = list("protein" = 3, "epinephrine" = 5)
+
+/obj/item/food/meat/pug
+ name = "pug meat"
+ desc = "Чуть менее очарователен в нарезке."
+ list_reagents = list("protein" = 2, "epinephrine" = 2)
+
+/obj/item/food/meat/ham/old
+ name = "жесткая ветчина"
+ desc = "Мясо почтенного хряка."
+ list_reagents = list("protein" = 2, "porktonium" = 10)
+
+/obj/item/food/meat/mouse
+ name = "мышатина"
+ desc = "На безрыбье и мышь мясо. Кто знает чем питался этот грызун до его подачи к столу."
+ icon = 'modular_ss220/mobs/icons/items.dmi'
+ icon_state = "meat_clear"
+ list_reagents = list("nutriment" = 2, "blood" = 3, "toxin" = 1)
+
+/obj/item/food/salmonmeat/snailmeat
+ name = "snail meat"
+ desc = "Сырая космо-улитка в собственном соку."
+ filling_color = "#6bb4a8"
+ list_reagents = list("protein" = 5, "vitamin" = 5)
+
+/obj/item/food/salmonmeat/turtlemeat
+ name = "snail meat"
+ desc = "Сырая космо-улитка в собственном соку."
+ filling_color = "#2fa24c"
+ list_reagents = list("protein" = 10, "vitamin" = 8)
+
+/obj/structure/bed/dogbed/pet
+ name = "Удобная лежанка"
+ desc = "Комфортная лежанка для любимейшего питомца отдела."
+ anchored = TRUE
+
+// Останки
+/obj/effect/decal/remains/mouse
+ name = "remains"
+ desc = "Некогда бывшая мышь. Её останки. Больше не будет пищать..."
+ icon = 'modular_ss220/mobs/icons/items.dmi'
+ icon_state = "mouse_skeleton"
+ anchored = FALSE
+ move_resist = MOVE_FORCE_EXTREMELY_WEAK
+
+/obj/effect/decal/remains/mouse/water_act(volume, temperature, source, method)
+ . = ..()
diff --git a/modular_ss220/mobs/code/simple_animal/mobs.dm b/modular_ss220/mobs/code/simple_animal/mobs.dm
new file mode 100644
index 000000000000..1decab575cf3
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/mobs.dm
@@ -0,0 +1,16 @@
+/mob/living/simple_animal/cockroach
+ death_sound = 'modular_ss220/mobs/sound/creatures/crack_death2.ogg'
+
+/mob/living/simple_animal/hostile/feral_cat
+ blood_volume = BLOOD_VOLUME_NORMAL
+ attacktext = "рвёт"
+
+/mob/living/simple_animal/hostile/headslug
+ attacktext = "грызёт"
+ holder_type = /obj/item/holder/headslug
+
+/mob/living/simple_animal/hostile/retaliate/clown/goblin
+ holder_type = /obj/item/holder/clowngoblin
+
+/mob/living/simple_animal/parrot
+ holder_type = /obj/item/holder/parrot
diff --git a/modular_ss220/mobs/code/simple_animal/named_animals.dm b/modular_ss220/mobs/code/simple_animal/named_animals.dm
new file mode 100644
index 000000000000..31b93ad6757a
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/named_animals.dm
@@ -0,0 +1,174 @@
+/mob/living/simple_animal/pig/sanya
+ name = "Саня"
+ desc = "Старый добрый хряк с сединой. Слегка подслеповат, но нюх и харизма по прежнему с ним. Чудом не пущен на мясо и дожил до почтенного возраста."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "pig_old"
+ icon_living = "pig_old"
+ icon_dead = "pig_old_dead"
+ butcher_results = list(/obj/item/food/meat/ham/old = 10)
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 80
+ health = 80
+
+/mob/living/simple_animal/pig/sanya/npc_safe(mob/user) // depriving the chef of his animals is not cool
+ return FALSE
+
+/mob/living/simple_animal/hostile/retaliate/goat/chef
+ name = "Боря"
+ desc = "Этот козёл - парнокопытное гурме шефа, в его мрачных глазах-бусинках так и читается амибициозный нрав! Он не твой друг, ведь за каждым игривым прыжком может скрываться неожиданный выпад."
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/cow/betsy
+ name = "Бетси"
+ desc = "Старая добрая старушка. Нескончаемый источник природного молока без ГМО. Ну почти без ГМО..."
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/chicken/wife
+ name = "Галя"
+ desc = "Почетная наседка. Жена Коммандора, следующая за ним в коммандировки по космическим станциям."
+ icon_state = "chicken_white"
+ icon_living = "chicken_white"
+ icon_dead = "chicken_white_dead"
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 20
+ health = 20
+
+/mob/living/simple_animal/chicken/wife/npc_safe(mob/user) // depriving the chef of his animals is not cool
+ return FALSE
+
+/mob/living/simple_animal/cock/clucky
+ name = "Коммандор Клакки"
+ desc = "Его великая армия бесчисленна. Ко-ко-ко."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 40 // Veteran
+ health = 40
+
+/mob/living/simple_animal/cock/clucky/npc_safe(mob/user) // depriving the chef of his animals is not cool
+ return FALSE
+
+/mob/living/simple_animal/goose/scientist
+ name = "Гуськор"
+ desc = "Учёный Гусь. Везде учусь. Крайне умная и задиристая птица. Обожает генетику. Надеемся это не бывший пропавший генетик..."
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "goose_labcoat"
+ icon_living = "goose_labcoat"
+ icon_dead = "goose_labcoat_dead"
+ icon_resting = "goose_labcoat_rest"
+ attacktext = "умно щипает"
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 80
+ health = 80
+ resting = TRUE
+
+/mob/living/simple_animal/goose/scientist/npc_safe(mob/user)
+ return FALSE
+
+/mob/living/simple_animal/hostile/lizard/croco/gena
+ name = "Гена"
+ desc = "Крокодил обожающий музыкальные инструменты и плюшевые игрушки. Пожевать."
+ faction = list("neutral")
+
+/mob/living/simple_animal/mouse/brown/demon
+ name = "Мышедемон"
+ desc = "Секретная разработка синдиката. Сидит тут потому, что сам хочет"
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 20
+ health = 20
+
+/mob/living/simple_animal/mouse/brown/demon/update_desc()
+ . = ..()
+ desc = initial(desc)
+
+// rats
+/mob/living/simple_animal/mouse/rat/ratatui
+ name = "Рататуй"
+ real_name = "Рататуй"
+ desc = "Личная крыса шеф повара, помогающая ему при готовке наиболее изысканных блюд. До момента пока он не пропадет и повар не начнет готовить что-то новенькое..."
+ mouse_color = "gray"
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 20
+ health = 20
+
+/mob/living/simple_animal/mouse/rat/ratatui/update_desc()
+ . = ..()
+ desc = initial(desc)
+
+/mob/living/simple_animal/mouse/rat/irish/remi
+ name = "Реми"
+ real_name = "Реми"
+ desc = "Близкий друг Рататуя. Не любимец повара, но пока тот не мешает на кухне, ему разрешили здесь остаться. Очень толстая крыса."
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 25
+ health = 25
+ transform = matrix(1.250, 0, 0, 0, 1, 0) // Толстячок на +2 пикселя
+
+/mob/living/simple_animal/mouse/rat/irish/remi/update_desc()
+ . = ..()
+ desc = initial(desc)
+
+/mob/living/simple_animal/mouse/rat/white/brain
+ name = "Брейн"
+ real_name = "Брейн"
+ desc = "Сообразительная личная лабораторная крыса директора исследований, даже освоившая речь. Настолько часто сбегал, что его перестали помещать в клетку. Он явно хочет захватить мир. Где-то спрятался его напарник..."
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 20
+ health = 20
+ universal_speak = 1
+ resting = TRUE
+
+/mob/living/simple_animal/mouse/rat/white/brain/update_desc()
+ . = ..()
+ desc = initial(desc)
+
+/obj/effect/decal/remains/mouse/pinkie
+ name = "Пинки"
+ desc = "Когда-то это был напарник самой сообразительной крысы в мире. К сожалению он таковым не являлся..."
+ anchored = TRUE
+
+// hamster
+/mob/living/simple_animal/mouse/hamster/representative
+ name = "представитель Алексей"
+ desc = "Представитель федерации хомяков. Проявите уважение при его виде, ведь он с позитивным исходом решил немало дипломатических вопросов между федерацией мышей, республикой крыс и корпорацией Нанотрейзен. Да и кто вообще хомяка так назвал?!"
+ icon = 'modular_ss220/mobs/icons/mob/animal.dmi'
+ icon_state = "hamster_rep"
+ icon_living = "hamster_rep"
+ icon_dead = "hamster_rep_dead"
+ icon_resting = "hamster_rep_rest"
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ holder_type = /obj/item/holder/hamster_rep
+ maxHealth = 20
+ health = 20
+ resting = TRUE
+
+/mob/living/simple_animal/possum/poppy
+ name = "Ключик"
+ desc = "Маленький работяга. Его жилетка подчеркивает его рабочие... лапы. Тот еще трудяга. Очень не любит ассистентов в инженерном отделе. И Полли. Интересно, почему?"
+ icon_state = "possum_poppy"
+ icon_living = "possum_poppy"
+ icon_dead = "possum_poppy_dead"
+ icon_resting = "possum_poppy_sleep"
+ icon_harm = "possum_poppy_aaa"
+ maxHealth = 50
+ health = 50
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ holder_type = /obj/item/holder/possum/poppy
+
+/mob/living/simple_animal/frog/wednesday
+ name = "Среда"
+ real_name = "Среда"
+ desc = "Это Среда, мои чуваки!"
+ maxHealth = 20
+ health = 20
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
diff --git a/modular_ss220/mobs/code/simple_animal/overrides.dm b/modular_ss220/mobs/code/simple_animal/overrides.dm
new file mode 100644
index 000000000000..4bc28f829b41
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/overrides.dm
@@ -0,0 +1,106 @@
+/mob/living/simple_animal
+ response_help = "тычет"
+ response_disarm = "толкает"
+ response_harm = "пихает"
+ attacktext = "атакует"
+ attack_sound = null
+ friendly = "утыкается в" //If the mob does no damage with it's attack
+ var/list/damaged_sound = null // The sound played when player hits animal
+ var/list/talk_sound = null // The sound played when talk
+
+
+/mob/living/simple_animal/say(message, verb, sanitize, ignore_speech_problems, ignore_atmospherics)
+ . = ..()
+ if(. && length(src.talk_sound))
+ playsound(src, pick(src.talk_sound), 75, TRUE)
+
+/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user)
+ . = ..()
+ if(. && length(src.damaged_sound) && src.stat != DEAD)
+ playsound(src, pick(src.damaged_sound), 40, 1)
+
+/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M)
+ . = ..()
+ if(. && length(src.damaged_sound) && src.stat != DEAD)
+ playsound(src, pick(src.damaged_sound), 40, 1)
+
+/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M)
+ . = ..()
+ if(. && length(src.damaged_sound) && src.stat != DEAD)
+ playsound(src, pick(src.damaged_sound), 40, 1)
+
+/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M)
+ . = ..()
+ if(. && length(src.damaged_sound) && src.stat != DEAD)
+ playsound(src, pick(src.damaged_sound), 40, 1)
+
+/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
+ . = ..()
+ if(. && length(src.damaged_sound) && src.stat != DEAD)
+ playsound(src, pick(src.damaged_sound), 40, 1)
+
+/mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/M)
+ . = ..()
+ if(. && length(src.damaged_sound) && src.stat != DEAD)
+ playsound(src, pick(src.damaged_sound), 40, 1)
+
+/mob/living/simple_animal/attack_robot(mob/living/user)
+ . = ..()
+ if(. && length(src.damaged_sound) && src.stat != DEAD)
+ playsound(src, pick(src.damaged_sound), 40, 1)
+
+
+// Simple animal procs
+/mob/living/simple_animal/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
+ if(pull_constraint(AM, show_message))
+ return ..()
+
+/mob/living/simple_animal/proc/pull_constraint(atom/movable/AM, show_message = FALSE)
+ return TRUE
+
+
+// Animals additions
+
+/* Megafauna */
+/mob/living/simple_animal/hostile/megafauna/legion
+ death_sound = 'modular_ss220/mobs/sound/creatures/legion_death.ogg'
+
+/mob/living/simple_animal/hostile/megafauna/legion/death(gibbed)
+ for(var/area/lavaland/L in world)
+ SEND_SOUND(L, sound('modular_ss220/mobs/sound/creatures/legion_death_far.ogg'))
+ . = ..()
+
+/* Nar Sie */
+/obj/singularity/narsie/large/Destroy()
+ SEND_SOUND(world, sound('modular_ss220/mobs/sound/creatures/narsie_rises.ogg'))
+ . = ..()
+
+
+/* Loot Drops */
+/obj/effect/spawner/random/bluespace_tap/organic/Initialize(mapload)
+ . = ..()
+ LAZYADD(loot, list(
+ //mob/living/simple_animal/pet/dog/corgi = 5,
+
+ /mob/living/simple_animal/pet/dog/brittany = 2,
+ /mob/living/simple_animal/pet/dog/german = 2,
+ /mob/living/simple_animal/pet/dog/tamaskan = 2,
+ /mob/living/simple_animal/pet/dog/bullterrier = 2,
+
+ //mob/living/simple_animal/pet/cat = 5,
+
+ /mob/living/simple_animal/pet/cat/cak = 2,
+ /mob/living/simple_animal/pet/cat/fat = 2,
+ /mob/living/simple_animal/pet/cat/white = 2,
+ /mob/living/simple_animal/pet/cat/birman = 2,
+ /mob/living/simple_animal/pet/cat/spacecat = 2,
+
+ //mob/living/simple_animal/pet/dog/fox = 5,
+
+ /mob/living/simple_animal/pet/dog/fox/forest = 2,
+ /mob/living/simple_animal/pet/dog/fox/fennec = 2,
+ /mob/living/simple_animal/possum = 2,
+
+ /mob/living/simple_animal/pet/penguin = 5,
+ //mob/living/simple_animal/pig = 5,
+ ))
diff --git a/modular_ss220/mobs/code/simple_animal/pets/cat.dm b/modular_ss220/mobs/code/simple_animal/pets/cat.dm
new file mode 100644
index 000000000000..b80e495c2e77
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/pets/cat.dm
@@ -0,0 +1,123 @@
+/mob/living/simple_animal/pet/cat
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ holder_type = /obj/item/holder/cat2
+
+/mob/living/simple_animal/pet/cat/runtime
+ holder_type = /obj/item/holder/cat
+
+/mob/living/simple_animal/pet/cat/cak
+ holder_type = /obj/item/holder/cak
+
+/mob/living/simple_animal/pet/cat/fat
+ name = "fat cat"
+ desc = "Упитана. Счастлива."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "iriska"
+ icon_living = "iriska"
+ icon_dead = "iriska_dead"
+ icon_resting = "iriska"
+ gender = FEMALE
+ mob_size = MOB_SIZE_LARGE // THICK!!!
+ //canmove = FALSE
+ butcher_results = list(/obj/item/food/meat = 8)
+ maxHealth = 40 // Sooooo faaaat...
+ health = 40
+ speed = 10 // TOO FAT
+ wander = 0 // LAZY
+ can_hide = 0
+ resting = TRUE
+ holder_type = /obj/item/holder/fatcat
+
+/mob/living/simple_animal/pet/cat/fat/handle_automated_action()
+ return
+
+/mob/living/simple_animal/pet/cat/white
+ name = "white cat"
+ desc = "Белоснежная шерстка. Плохо различается на белой плитке, зато отлично виден в темноте!"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "penny"
+ icon_living = "penny"
+ icon_dead = "penny_dead"
+ icon_resting = "penny_rest"
+ gender = MALE
+ holder_type = /obj/item/holder/cak
+
+/mob/living/simple_animal/pet/cat/birman
+ name = "birman cat"
+ real_name = "birman cat"
+ desc = "Священная порода Бирма."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "crusher"
+ icon_living = "crusher"
+ icon_dead = "crusher_dead"
+ icon_resting = "crusher_rest"
+ gender = MALE
+ holder_type = /obj/item/holder/crusher
+
+
+/mob/living/simple_animal/pet/cat/black
+ name = "black cat"
+ real_name = "black cat"
+ desc = "Он ужас летящий на крыльях ночи! Он - тыгыдык и спотыкание во тьме ночной! Бойся не заметить черного кота в тени!"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "salem"
+ icon_living = "salem"
+ icon_dead = "salem_dead"
+ icon_resting = "salem_rest"
+ gender = MALE
+ holder_type = /obj/item/holder/cat
+
+/mob/living/simple_animal/pet/cat/spacecat
+ name = "spacecat"
+ desc = "Space Kitty!!"
+ icon_state = "spacecat"
+ icon_living = "spacecat"
+ icon_dead = "spacecat_dead"
+ icon_resting = "spacecat_rest"
+ unsuitable_atmos_damage = 0
+ minbodytemp = TCMB
+ maxbodytemp = T0C + 40
+ holder_type = /obj/item/holder/spacecat
+
+//named
+/mob/living/simple_animal/pet/cat/floppa
+ name = "Большой Шлёпа"
+ desc = "Он выглядит так, будто собирается совершить военное преступление."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "floppa"
+ icon_living = "floppa"
+ icon_dead = "floppa_dead"
+ icon_resting = "floppa_rest"
+ unique_pet = TRUE
+
+/mob/living/simple_animal/pet/cat/fat/iriska
+ name = "Ириска"
+ desc = "Упитана. Счастлива. Бюрократы её обожают. И похоже даже черезчур сильно."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/pet/cat/white/penny
+ name = "Копейка"
+ desc = "Любит таскать монетки и мелкие предметы. Успевайте прятать их!"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ resting = TRUE
+
+/mob/living/simple_animal/pet/cat/birman/crusher
+ name = "Бедокур"
+ desc = "Любит крушить всё что не прикручено. Нужно вовремя прибираться."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ resting = TRUE
+
+/mob/living/simple_animal/pet/cat/spacecat/musya
+ name = "Муся"
+ desc = "Любимая почтенная кошка отдела токсинов. Всегда готова к вылетам!"
+
+/mob/living/simple_animal/pet/cat/black/salem
+ name = "Салем"
+ real_name = "Салем"
+ desc = "Говорят что это бывший колдун, лишенный всех своих сил и превратившейся в черного кота Советом Колдунов из-за попытки захватить мир, а в руки НТ попал чтобы отбывать своё наказание. Судя по его скверному нраву, это может быть похоже на правду."
diff --git a/modular_ss220/mobs/code/simple_animal/pets/dog.dm b/modular_ss220/mobs/code/simple_animal/pets/dog.dm
new file mode 100644
index 000000000000..7a17335e535f
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/pets/dog.dm
@@ -0,0 +1,165 @@
+/mob/living/simple_animal/pet/dog
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ maxHealth = 50
+ health = 50
+ melee_damage_type = STAMINA
+ melee_damage_lower = 6
+ melee_damage_upper = 10
+ attacktext = "кусает"
+ var/growl_sound = list('modular_ss220/mobs/sound/creatures/dog_grawl1.ogg','modular_ss220/mobs/sound/creatures/dog_grawl2.ogg') //Used in emote.
+
+ butcher_results = list(/obj/item/food/meat/dog = 4)
+ collar_type = "dog"
+
+/mob/living/simple_animal/pet/dog/wuv(change, mob/M)
+ . = ..()
+ if(change)
+ if(change < 0)
+ if(M && stat != DEAD) // Same check here, even though emote checks it as well (poor form to check it only in the help case)
+ playsound(src, pick(src.growl_sound), 75, TRUE)
+
+
+/mob/living/simple_animal/pet/dog/corgi
+ holder_type = /obj/item/holder/corgi
+
+/mob/living/simple_animal/pet/dog/corgi/ian/persistent_load()
+ . = ..()
+ if(age == record_age)
+ holder_type = /obj/item/holder/old_corgi
+
+/mob/living/simple_animal/pet/dog/corgi/narsie
+ holder_type = /obj/item/holder/narsian
+ maxHealth = 300
+ health = 300
+ melee_damage_type = STAMINA //Пади ниц!
+ melee_damage_lower = 50
+ melee_damage_upper = 100
+
+/* // При добавлении Ратвара
+/mob/living/simple_animal/pet/dog/corgi/ratvar
+ name = "Cli-k"
+ desc = "It's a coolish Ian that clicks!"
+ icon = 'icons/mob/clockwork_mobs.dmi'
+ icon_state = "clik"
+ icon_living = "clik"
+ icon_dead = "clik_dead"
+ faction = list("neutral", "clockwork_cult")
+ gold_core_spawnable = NO_SPAWN
+ nofur = TRUE
+ unique_pet = TRUE
+ maxHealth = 100
+ health = 100
+
+/mob/living/simple_animal/pet/dog/corgi/ratvar/update_corgi_fluff()
+ ..()
+ speak = list("V'z fuvavat jneevbe!", "CLICK!", "KL-KL-KLIK")
+ speak_emote = list("growls", "barks ominously")
+ emote_hear = list("barks echoingly!", "woofs hauntingly!", "yaps in an judicial manner.", "mutters something unspeakable.")
+ emote_see = list("communes with the unnameable.", "seeks the light in souls.", "shakes.")
+
+/mob/living/simple_animal/pet/dog/corgi/ratvar/ratvar_act()
+ adjustBruteLoss(-maxHealth)
+*/
+
+/mob/living/simple_animal/pet/dog/corgi/puppy
+ maxHealth = 20
+ health = 20
+ butcher_results = list(/obj/item/food/meat/corgi = 1)
+
+/mob/living/simple_animal/pet/dog/corgi/puppy/void
+ maxHealth = 60
+ health = 60
+ holder_type = /obj/item/holder/void_puppy
+
+/mob/living/simple_animal/pet/dog/corgi/puppy/slime
+ name = "\improper slime puppy"
+ real_name = "slimy"
+ desc = "Крайне склизкий. Но прикольный!"
+ icon_state = "slime_puppy"
+ icon_living = "slime_puppy"
+ icon_dead = "slime_puppy_dead"
+ nofur = TRUE
+ holder_type = /obj/item/holder/slime_puppy
+ minbodytemp = 250 //Weak to cold
+ maxbodytemp = INFINITY
+
+/mob/living/simple_animal/pet/dog/corgi/lisa
+ holder_type = /obj/item/holder/lisa
+
+/mob/living/simple_animal/pet/dog/corgi/borgi
+ holder_type = /obj/item/holder/borgi
+
+/mob/living/simple_animal/pet/dog/pug
+ holder_type = /obj/item/holder/pug
+ maxHealth = 30
+ health = 30
+
+/mob/living/simple_animal/pet/dog/bullterrier
+ name = "bullterrier"
+ real_name = "bullterrier"
+ desc = "Кого-то его мордочка напоминает..."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "bullterrier"
+ icon_living = "bullterrier"
+ icon_dead = "bullterrier_dead"
+ holder_type = /obj/item/holder/bullterrier
+
+/mob/living/simple_animal/pet/dog/tamaskan
+ name = "tamaskan"
+ real_name = "tamaskan"
+ desc = "Хорошая семейная собака. Уживается с другими собаками и ассистентами."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "tamaskan"
+ icon_living = "tamaskan"
+ icon_dead = "tamaskan_dead"
+ holder_type = /obj/item/holder/bullterrier
+
+/mob/living/simple_animal/pet/dog/german
+ name = "german"
+ real_name = "german"
+ desc = "Немецкая овчарка с помесью двортерьера. Судя по крупу - явно не породистый."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "german"
+ icon_living = "german"
+ icon_dead = "german_dead"
+
+/mob/living/simple_animal/pet/dog/brittany
+ name = "brittany"
+ real_name = "brittany"
+ desc = "Старая порода, которую любят аристократы."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "brittany"
+ icon_living = "brittany"
+ icon_dead = "brittany_dead"
+
+
+
+// named
+/mob/living/simple_animal/pet/dog/brittany/psycho
+ name = "Перрито"
+ real_name = "Перрито"
+ desc = "Собака, обожающая котов, особенно в сапогах, прекрасно лающая на Испанском, прошла терапевтические курсы, готова выслушать все ваши проблемы и выдать вам целебных объятий с завершением в виде почесыванием животика."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ resting = TRUE
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/pet/dog/pug/frank
+ name = "Фрэнк"
+ real_name = "Фрэнк"
+ desc = "Мопс полученный в результате эксперимента ученых в черном. Почему его не забрали интересный вопрос. Похоже он всем надоел своей болтовней, после чего его лишили дара речи."
+ resting = TRUE
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+
+
+/mob/living/simple_animal/pet/dog/bullterrier/genn
+ name = "Геннадий"
+ desc = "Собачий аристократ. Выглядит очень важным и начитанным. Доброжелательный любимец ассистентов."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ maxHealth = 5
+ health = 5
+ resting = TRUE
+
diff --git a/modular_ss220/mobs/code/simple_animal/pets/fashion.dm b/modular_ss220/mobs/code/simple_animal/pets/fashion.dm
new file mode 100644
index 000000000000..037344bbb529
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/pets/fashion.dm
@@ -0,0 +1,131 @@
+/obj/item
+ var/datum/muhtar_fashion/muhtar_fashion = null
+ var/datum/snake_fashion/snake_fashion = null
+
+/// Muhtar fashion
+/datum/muhtar_fashion
+ var/name
+ var/desc
+ var/emote_see
+ var/emote_hear
+ var/speak
+ var/speak_emote
+
+ // This isn't applied to the dog, but stores the icon_state of the
+ // sprite that the associated item uses
+ var/icon_file
+ var/obj_icon_state
+ var/obj_alpha
+ var/obj_color
+
+/datum/muhtar_fashion/New(mob/M)
+ name = replacetext(name, "REAL_NAME", M.real_name)
+ desc = replacetext(desc, "NAME", name)
+
+/datum/muhtar_fashion/proc/apply(mob/living/simple_animal/pet/dog/D)
+ if(name)
+ D.name = name
+ if(desc)
+ D.desc = desc
+ if(emote_see)
+ D.emote_see = emote_see
+ if(emote_hear)
+ D.emote_hear = emote_hear
+ if(speak)
+ D.speak = speak
+ if(speak_emote)
+ D.speak_emote = speak_emote
+
+/datum/muhtar_fashion/proc/get_overlay(dir)
+ if(icon_file && obj_icon_state)
+ var/image/muhtar = image(icon_file, obj_icon_state, dir = dir)
+ muhtar.alpha = obj_alpha
+ muhtar.color = obj_color
+ return muhtar
+
+// Item datums
+/datum/muhtar_fashion/head
+ icon_file = 'modular_ss220/mobs/icons/muhtar_accessories.dmi'
+
+/datum/muhtar_fashion/mask
+ icon_file = 'modular_ss220/mobs/icons/muhtar_accessories.dmi'
+
+/datum/muhtar_fashion/head/detective
+ name = "Детектив REAL_NAME"
+ desc = "NAME sees through your lies..."
+ emote_see = list("investigates the area.","sniffs around for clues.","searches for scooby snacks.","takes a candycorn from the hat.")
+
+/datum/muhtar_fashion/mask/cigar
+ obj_icon_state = "cigar"
+
+/datum/muhtar_fashion/head/beret
+ name = "Лейтенант REAL_NAME"
+ obj_icon_state = "beret"
+
+// Muhtar items
+/obj/item/clothing/mask/cigarette/cigar
+ muhtar_fashion = /datum/muhtar_fashion/mask/cigar
+
+/obj/item/clothing/head/det_hat
+ muhtar_fashion = /datum/muhtar_fashion/head/detective
+
+/obj/item/clothing/head/beret/sec
+ muhtar_fashion = /datum/muhtar_fashion/head/beret
+
+/// Snake fashion
+/datum/snake_fashion
+ var/name
+ var/desc
+ var/emote_see
+ var/emote_hear
+ var/speak
+ var/speak_emote
+
+ // This isn't applied to the snake, but stores the icon_state of the
+ // sprite that the associated item uses
+ var/icon_file
+ var/obj_icon_state
+ var/icon_state
+ var/icon_living
+ var/icon_dead
+ var/obj_alpha
+ var/obj_color
+
+/datum/snake_fashion/New(mob/M)
+ name = replacetext(name, "REAL_NAME", M.real_name)
+ desc = replacetext(desc, "NAME", name)
+
+/datum/snake_fashion/proc/apply(mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/D)
+ if(name)
+ D.name = name
+ if(desc)
+ D.desc = desc
+ if(emote_see)
+ D.emote_see = emote_see
+ if(emote_hear)
+ D.emote_hear = emote_hear
+ if(speak)
+ D.speak = speak
+ if(speak_emote)
+ D.speak_emote = speak_emote
+
+/datum/snake_fashion/proc/get_overlay()
+ if(icon_file && obj_icon_state)
+ var/image/snek = image(icon_file, obj_icon_state)
+ snek.alpha = obj_alpha
+ snek.color = obj_color
+ return snek
+
+// Item datums
+/datum/snake_fashion/head
+ icon_file = 'modular_ss220/mobs/icons/rouge_accessories.dmi'
+
+/datum/snake_fashion/head/beret_hos_black
+ name = "Ля Руж"
+ desc = "Mon Dieu! C'est un serpent à trois têtes!"
+ speak = list("le shhh!")
+ emote_see = list("трясётся в наигранном страхе.", "сдаётся.","устраивает тихую битву между своими головами.", "притворяется мёртвой.","ведёт себя так будто перед ней невидимая стенка.")
+
+// Rouge items
+/obj/item/clothing/head/hos/beret
+ snake_fashion = /datum/snake_fashion/head/beret_hos_black
diff --git a/modular_ss220/mobs/code/simple_animal/pets/fox.dm b/modular_ss220/mobs/code/simple_animal/pets/fox.dm
new file mode 100644
index 000000000000..f1fb158c8840
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/pets/fox.dm
@@ -0,0 +1,57 @@
+/mob/living/simple_animal/pet/dog/fox
+ yelp_sound = 'modular_ss220/mobs/sound/creatures/fox_yelp.ogg' //Used on death.
+ holder_type = /obj/item/holder/fox
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+
+/mob/living/simple_animal/pet/dog/fox/fennec
+ name = "fennec"
+ real_name = "fennec"
+ desc = "Миниатюрная лисичка с очень большими ушами. Фенек, фенек, зачем тебе такие большие уши? Чтобы избегать дормитория?"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "fennec"
+ icon_living = "fennec"
+ icon_dead = "fennec_dead"
+ icon_resting = "fennec_rest"
+ see_in_dark = 10
+ holder_type = /obj/item/holder/fennec
+
+/mob/living/simple_animal/pet/dog/fox/forest
+ name = "forest fox"
+ real_name = "forest fox"
+ desc = "Лесная дикая лисица. Может укусить."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "fox_forest"
+ icon_living = "fox_forest"
+ icon_dead = "fox_forest_dead"
+ icon_resting = "fox_forest_rest"
+ melee_damage_type = BRUTE
+ melee_damage_lower = 6
+ melee_damage_upper = 12
+
+
+
+// named
+
+/mob/living/simple_animal/pet/dog/fox/alisa
+ name = "Алиса"
+ desc = "Алиса, любимый питомец любого Офицера Специальных Операций. Интересно, что она говорит?"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "alisa"
+ icon_living = "alisa"
+ icon_dead = "alisa_dead"
+ icon_resting = "alisa_rest"
+ faction = list("nanotrasen")
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+
+/mob/living/simple_animal/pet/dog/fox/fennec/fenya
+ name = "Феня"
+ desc = "Миниатюрная лисичка c важным видом и очень большими ушами. Был пойман во время разливания огромного мороженого по формочкам и теперь Магистрат держит его при себе и следит за ним. Но похоже что ему даже нравится быть частью правосудия."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ resting = TRUE
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
diff --git a/modular_ss220/mobs/code/simple_animal/pets/pet.dm b/modular_ss220/mobs/code/simple_animal/pets/pet.dm
new file mode 100644
index 000000000000..e3b107c46b3a
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/pets/pet.dm
@@ -0,0 +1,17 @@
+
+/mob/living/simple_animal/pet
+ attacktext = "кусает"
+ attack_sound = 'sound/weapons/bite.ogg'
+
+/mob/living/simple_animal/pet/sloth
+ holder_type = /obj/item/holder/sloth
+
+/mob/living/simple_animal/pet/sloth/paperwork
+ name = "Пэйперворк" // Бумажник
+ desc = "Офисный ленивец. Так же быстро решает проблемы отделов, как и остальные агенты внутренних дел."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "cool_sloth"
+ icon_living = "cool_sloth"
+ icon_dead = "cool_sloth_dead"
+ unique_pet = TRUE
+ gold_core_spawnable = NO_SPAWN
diff --git a/modular_ss220/mobs/code/simple_animal/pets/rouge.dm b/modular_ss220/mobs/code/simple_animal/pets/rouge.dm
new file mode 100644
index 000000000000..c9126e86b2eb
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/pets/rouge.dm
@@ -0,0 +1,216 @@
+//Уникальный питомец Офицера Телекомов. Спрайты от Элл Гуда
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge
+ name = "Руж"
+ desc = "Уникальная трёхголовая змея Офицера Телекоммуникаций синдиката. Выращена в лаборатории. У каждой головы свой характер!"
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ mob_size = MOB_SIZE_SMALL
+ blood_volume = BLOOD_VOLUME_NORMAL
+ can_collar = TRUE
+ gender = FEMALE
+ icon_state = "rouge"
+ icon_living = "rouge"
+ icon_dead = "rouge_dead"
+ icon_resting = "rouge_rest"
+ speak_chance = 5
+ speak = list("Шшш", "Тсс!", "Тц тц тц!", "ШШшшШШшшШ!")
+ speak_emote = list("hisses")
+ emote_hear = list("Зевает", "Шипит", "Дурачится", "Толкается")
+ emote_see = list("Высовывает язык", "Кружится", "Трясёт хвостом")
+ health = 20
+ maxHealth = 20
+ attacktext = "кусает"
+ melee_damage_lower = 5
+ melee_damage_upper = 6
+ response_help = "pets"
+ var/rest = FALSE
+ response_disarm = "shoos"
+ response_harm = "steps on"
+ var/obj/item/inventory_head
+ faction = list("neutral", "syndicate")
+ gold_core_spawnable = NO_SPAWN
+ unique_pet = TRUE
+ can_hide = 1
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/verb/chasetail()
+ set name = "Chase your tail"
+ set desc = "d'awwww."
+ set category = "Animal"
+ visible_message("[src] [pick("dances around", "chases [p_their()] tail")].", "[pick("You dance around", "You chase your tail")].")
+ spin(20, 1)
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/emote(emote_key, type_override = 1, message, intentional, force_silence)
+ if(incapacitated())
+ return
+
+ emote_key = lowertext(emote_key)
+ if(!force_silence && emote_key == "hiss" && start_audio_emote_cooldown())
+ return
+
+ switch(emote_key)
+ if("hiss")
+ message = "[src] [pick(src.speak_emote)]!"
+ ..()
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/attack_hand(mob/living/carbon/human/M)
+ . = ..()
+ switch(M.a_intent)
+ if(INTENT_HELP)
+ shh(1, M)
+ if(INTENT_HARM)
+ shh(-1, M)
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/on_lying_down(updating = 1)
+ ..()
+ if(icon_resting && stat != DEAD)
+ icon_state = icon_resting
+ rest = TRUE
+ if(collar_type)
+ collar_type = "[initial(collar_type)]_rest"
+ regenerate_icons()
+ if(inventory_head)
+ regenerate_icons()
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/on_standing_up(updating = 1)
+ ..()
+ if(icon_resting && stat != DEAD)
+ icon_state = icon_living
+ rest = FALSE
+ if(collar_type)
+ collar_type = "[initial(collar_type)]"
+ regenerate_icons()
+ if(inventory_head)
+ regenerate_icons()
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/proc/shh(change, mob/M)
+ if(!M || stat)
+ return
+ if(change > 0)
+ new /obj/effect/temp_visual/heart(loc)
+ custom_emote(1, "hisses happily!")
+ else
+ custom_emote(1, "hisses angrily!")
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/Initialize(mapload)
+ . = ..()
+ regenerate_icons()
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/Destroy()
+ QDEL_NULL(inventory_head)
+ return ..()
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/handle_atom_del(atom/A)
+ if(A == inventory_head)
+ inventory_head = null
+ regenerate_icons()
+ return ..()
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/Life(seconds, times_fired)
+ . = ..()
+ regenerate_icons()
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/death(gibbed)
+ ..(gibbed)
+ regenerate_icons()
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/getarmor(def_zone, type)
+ var/armorval = inventory_head?.armor.getRating(type)
+ if(!def_zone)
+ armorval *= 0.5
+ else if(def_zone != "head")
+ armorval = 0
+ return armorval
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/proc/place_on_head(obj/item/item_to_add, mob/user)
+
+ if(istype(item_to_add, /obj/item/grenade/plastic/c4)) // last thing she ever wears, I guess
+ item_to_add.afterattack__legacy__attackchain(src,user,1)
+ return
+
+ if(inventory_head)
+ if(user)
+ to_chat(user, span_warning("You can't put more than one hat on [src]!"))
+ return
+ if(!item_to_add)
+ user.visible_message(
+ span_notice("[user] pets [src]."),
+ span_notice("You rest your hand on [src]'s head for a moment."))
+ if(flags_2 & HOLOGRAM_2)
+ return
+ return
+
+ if(user && !user.unEquip(item_to_add))
+ to_chat(user, span_warning("\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!"))
+ return 0
+
+ var/valid = FALSE
+ if(ispath(item_to_add.snake_fashion, /datum/snake_fashion/head))
+ valid = TRUE
+
+ if(valid)
+ if(health <= 0)
+ to_chat(user, span_notice("Безжизненный взгляд в глазах [real_name] никак не меняется, когда вы надеваете [item_to_add] на неё."))
+ else if(user)
+ user.visible_message(
+ span_notice("[user] надевает [item_to_add] на центральную голову [real_name]. [src] смотрит на [user] и довольно шипит."),
+ span_notice("Вы надеваете [item_to_add] на голову [real_name]. [src] озадачено смотрит на вас, пока другие головы смотрят на центральную с завистью."),
+ span_italics("Вы слышите дружелюбное шипение."))
+ item_to_add.forceMove(src)
+ inventory_head = item_to_add
+ update_snek_fluff()
+ regenerate_icons()
+ else
+ to_chat(user, span_warning("Вы надеваете [item_to_add] на голову [src], но она скидывает [item_to_add] с себя!"))
+ item_to_add.forceMove(drop_location())
+ if(prob(25))
+ step_rand(item_to_add)
+ for(var/i in list(1,2,4,8,4,8,4,dir))
+ setDir(i)
+ sleep(1)
+
+ return valid
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/proc/update_snek_fluff() //имя, описание, эмоуты
+ // First, change back to defaults
+ name = real_name
+ desc = initial(desc)
+ // BYOND/DM doesn't support the use of initial on lists.
+ speak = list("Шшш", "Тсс!", "Тц тц тц!", "ШШшшШШшшШ!")
+ speak_emote = list("hisses")
+ emote_hear = list("Зевает", "Шипит", "Дурачится", "Толкается")
+ emote_see = list("Высовывает язык", "Кружится", "Трясёт хвостом")
+
+///Этот код скопирован с кода для корги и обнуляет показатели которые ему даёт риг. Если когда нибудь змейке дадут риг, раскомментируете///
+/*
+ set_light(0)
+ atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
+ mutations.Remove(BREATHLESS)
+ minbodytemp = initial(minbodytemp)
+*/
+ if(inventory_head?.snake_fashion)
+ var/datum/snake_fashion/SF = new inventory_head.snake_fashion(src)
+ SF.apply(src)
+
+/mob/living/simple_animal/hostile/retaliate/poison/snake/rouge/regenerate_icons() // оверлей
+ ..()
+ if(inventory_head)
+ var/image/head_icon
+ var/datum/snake_fashion/SF = new inventory_head.snake_fashion(src)
+
+ if(!SF.obj_icon_state)
+ SF.obj_icon_state = inventory_head.icon_state
+ if(src.rest || stat == DEAD)
+ SF.obj_icon_state += "_rest"
+ if(!SF.obj_alpha)
+ SF.obj_alpha = inventory_head.alpha
+ if(!SF.obj_color)
+ SF.obj_color = inventory_head.color
+
+ if(stat || src.rest) //без сознания или отдыхает
+ head_icon = SF.get_overlay()
+ if(stat)
+ head_icon.pixel_y = -2
+ head_icon.pixel_x = -2
+ else
+ head_icon = SF.get_overlay()
+
+ add_overlay(head_icon)
diff --git a/modular_ss220/mobs/code/simple_animal/pets/security_dogs.dm b/modular_ss220/mobs/code/simple_animal/pets/security_dogs.dm
new file mode 100644
index 000000000000..4158536d0713
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/pets/security_dogs.dm
@@ -0,0 +1,211 @@
+/mob/living/simple_animal/pet/dog/security
+ name = "Мухтар"
+ real_name = "Мухтар"
+ desc = "Верный служебный пес. Он гордо несёт бремя хорошего мальчика."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "german_shep"
+ icon_living = "german_shep"
+ icon_resting = "german_shep_rest"
+ icon_dead = "german_shep_dead"
+ health = 35
+ maxHealth = 35
+ melee_damage_type = STAMINA
+ melee_damage_lower = 8
+ melee_damage_upper = 10
+ attacktext = "кусает"
+ var/obj/item/inventory_head
+ var/obj/item/inventory_mask
+ footstep_type = FOOTSTEP_MOB_CLAW
+ butcher_results = list(/obj/item/food/meat/security = 3)
+
+/mob/living/simple_animal/pet/dog/security/ranger
+ name = "Ranger"
+ real_name = "Ranger"
+ desc = "That's Ranger, your friendly and fierce k9. He has seen the terror of Xenomorphs, so it's best to be nice to him. RANGER LEAD THE WAY!"
+ icon_state = "ranger"
+ icon_living = "ranger"
+ icon_resting = "ranger_rest"
+ icon_dead = "ranger_dead"
+
+/mob/living/simple_animal/pet/dog/security/warden
+ name = "Джульбарс"
+ real_name = "Джульбарс"
+ desc = "Мудрый служебный пес, названный в честь единственной собаки удостоившийся боевой награды."
+ icon_state = "german_shep2"
+ icon_living = "german_shep2"
+ icon_resting = "german_shep2_rest"
+ icon_dead = "german_shep2_dead"
+
+/mob/living/simple_animal/pet/dog/security/detective
+ name = "Гав-Гавыч"
+ desc = "Старый служебный пёс. Он давно потерял нюх, однако детектив по-прежнему содержит и заботится о нём."
+ icon_state = "blackdog"
+ icon_living = "blackdog"
+ icon_dead = "blackdog_dead"
+ icon_resting = "blackdog_rest"
+
+/mob/living/simple_animal/pet/dog/security/on_lying_down(new_lying_angle)
+ ..()
+ if(icon_resting && stat != DEAD)
+ icon_state = icon_resting
+ regenerate_icons()
+ if(collar_type)
+ collar_type = "[initial(collar_type)]_rest"
+ regenerate_icons()
+
+/mob/living/simple_animal/pet/dog/security/on_standing_up(updating = 1)
+ ..()
+ if(icon_resting && stat != DEAD)
+ icon_state = icon_living
+ regenerate_icons()
+ if(collar_type)
+ collar_type = "[initial(collar_type)]"
+ regenerate_icons()
+
+
+/mob/living/simple_animal/pet/dog/security/Initialize(mapload)
+ . = ..()
+ regenerate_icons()
+
+/mob/living/simple_animal/pet/dog/security/Destroy()
+ QDEL_NULL(inventory_head)
+ QDEL_NULL(inventory_mask)
+ return ..()
+
+/mob/living/simple_animal/pet/dog/security/handle_atom_del(atom/A)
+ if(A == inventory_head)
+ inventory_head = null
+ regenerate_icons()
+ if(A == inventory_mask)
+ inventory_mask = null
+ regenerate_icons()
+ return ..()
+
+/mob/living/simple_animal/pet/dog/security/Life(seconds, times_fired)
+ . = ..()
+ regenerate_icons()
+
+/mob/living/simple_animal/pet/dog/security/death(gibbed)
+ ..(gibbed)
+ regenerate_icons()
+
+/mob/living/simple_animal/pet/dog/security/proc/place_on_head(obj/item/item_to_add, mob/user)
+
+ if(istype(item_to_add, /obj/item/grenade/plastic/c4)) // last thing he ever wears, I guess
+ item_to_add.afterattack__legacy__attackchain(src,user,1)
+ return
+
+ if(inventory_head)
+ if(user)
+ to_chat(user, span_warning("You can't put more than one hat on [src]!"))
+ return
+ if(!item_to_add)
+ user.visible_message(
+ span_notice("[user] pets [src]."),
+ span_notice("You rest your hand on [src]'s head for a moment."))
+ if(flags_2 & HOLOGRAM_2)
+ return
+ return
+
+ if(user && !user.unEquip(item_to_add))
+ to_chat(user, span_warning("\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!"))
+ return 0
+
+ var/valid = FALSE
+ if(ispath(item_to_add.muhtar_fashion, /datum/muhtar_fashion/head))
+ valid = TRUE
+
+ //Various hats and items (worn on his head) change muhtar's behaviour. His attributes are reset when a hat is removed.
+
+ if(valid)
+ if(health <= 0)
+ to_chat(user, span_notice("There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()]."))
+ else if(user)
+ user.visible_message(
+ span_notice("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once."),
+ span_notice("You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks."),
+ span_italics("You hear a friendly-sounding bark."))
+ item_to_add.forceMove(src)
+ inventory_head = item_to_add
+ update_muhtar_fluff()
+ regenerate_icons()
+ else
+ to_chat(user, span_warning("You set [item_to_add] on [src]'s head, but it falls off!"))
+ item_to_add.forceMove(drop_location())
+ if(prob(25))
+ step_rand(item_to_add)
+ for(var/i in list(1,2,4,8,4,8,4,dir))
+ setDir(i)
+ sleep(1)
+
+ return valid
+
+/mob/living/simple_animal/pet/dog/security/proc/update_muhtar_fluff()
+ // First, change back to defaults
+ name = real_name
+ desc = initial(desc)
+ // BYOND/DM doesn't support the use of initial on lists.
+ speak = list("YAP", "Woof!", "Bark!", "AUUUUUU")
+ speak_emote = list("barks", "woofs")
+ emote_hear = list("barks!", "woofs!", "yaps.","pants.")
+ emote_see = list("shakes its head.", "chases its tail.","shivers.")
+ desc = initial(desc)
+
+ if(inventory_head && inventory_head.muhtar_fashion)
+ var/datum/muhtar_fashion/DF = new inventory_head.muhtar_fashion(src)
+ DF.apply(src)
+
+ if(inventory_mask && inventory_mask.muhtar_fashion)
+ var/datum/muhtar_fashion/DF = new inventory_mask.muhtar_fashion(src)
+ DF.apply(src)
+
+/mob/living/simple_animal/pet/dog/security/regenerate_icons()
+ ..()
+ if(inventory_head)
+ var/image/head_icon
+ var/datum/muhtar_fashion/DF = new inventory_head.muhtar_fashion(src)
+
+ if(!DF.obj_icon_state)
+ DF.obj_icon_state = inventory_head.icon_state
+ if(!DF.obj_alpha)
+ DF.obj_alpha = inventory_head.alpha
+ if(!DF.obj_color)
+ DF.obj_color = inventory_head.color
+
+
+ if(icon_state == icon_resting)
+ head_icon = DF.get_overlay()
+ head_icon.pixel_y = -2
+ else
+ head_icon = DF.get_overlay()
+
+ if(health <= 0)
+ head_icon = DF.get_overlay(dir = EAST)
+ head_icon.pixel_y = -8
+ head_icon.transform = turn(head_icon.transform, 180)
+
+ add_overlay(head_icon)
+
+ if(inventory_mask)
+ var/image/mask_icon
+ var/datum/muhtar_fashion/DF = new inventory_mask.muhtar_fashion(src)
+
+ if(!DF.obj_icon_state)
+ DF.obj_icon_state = inventory_mask.icon_state
+ if(!DF.obj_alpha)
+ DF.obj_alpha = inventory_mask.alpha
+ if(!DF.obj_color)
+ DF.obj_color = inventory_mask.color
+
+ if(icon_state == icon_resting)
+ mask_icon = DF.get_overlay()
+ mask_icon.pixel_y = -2
+ else
+ mask_icon = DF.get_overlay()
+
+ if(health <= 0)
+ mask_icon = DF.get_overlay(dir = EAST)
+ mask_icon.pixel_y = -11
+ mask_icon.transform = turn(mask_icon.transform, 180)
+
+ add_overlay(mask_icon)
diff --git a/modular_ss220/mobs/code/simple_animal/pets/slugcat.dm b/modular_ss220/mobs/code/simple_animal/pets/slugcat.dm
new file mode 100644
index 000000000000..805c44bd2b9a
--- /dev/null
+++ b/modular_ss220/mobs/code/simple_animal/pets/slugcat.dm
@@ -0,0 +1,305 @@
+/mob/living/simple_animal/pet/slugcat
+ name = "слизнекот"
+ desc = "Удивительное существо, напоминающая кота и слизня в одном обличии. Но это не слизь, а иной вид существа. Гордость ксенобиологии. Крайне ловкое и умное, родом с планеты с опасной средой обитания. Обожает копья, не стоит давать ему его в лапки. На нем отлично смотрятся шляпы."
+ icon = 'modular_ss220/mobs/icons/mob/pets.dmi'
+ icon_state = "slugcat"
+ icon_living = "slugcat"
+ icon_dead = "slugcat_dead"
+ icon_resting = "slugcat_rest"
+ speak = list("Furrr.","Uhh.", "Hurrr.")
+ gender = MALE
+ turns_per_move = 5
+ see_in_dark = 8
+ health = 100
+ maxHealth = 100
+ blood_volume = BLOOD_VOLUME_NORMAL
+ melee_damage_type = STAMINA
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ attacktext = "бьет"
+ mob_size = MOB_SIZE_SMALL
+ pass_flags = PASSTABLE
+ ventcrawler = VENTCRAWLER_ALWAYS
+ can_collar = 1
+ butcher_results = list(/obj/item/food/meat = 5)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ gold_core_spawnable = FRIENDLY_SPAWN
+ footstep_type = FOOTSTEP_MOB_SLIME
+ faction = list("slime","neutral")
+ //holder_type = /obj/item/holder/cat2
+
+ //Шляпы для слизнекота!
+ var/obj/item/inventory_head
+ var/obj/item/inventory_hand
+
+ var/hat_offset_y = -8
+ var/hat_offset_y_rest = -19
+ var/hat_icon_file = 'icons/mob/clothing/head.dmi'
+ var/hat_icon_state
+ var/hat_alpha
+ var/hat_color
+
+ var/is_pacifist = FALSE
+ var/is_reduce_damage = TRUE
+
+/mob/living/simple_animal/pet/slugcat/monk
+ name = "слизнекот-монах"
+ desc = "Удивительное существо, напоминающая кота и слизня в одном обличии. Но это не слизь, а иной вид существа. Гордость ксенобиологии. Крайне ловкое и умное, родом с планеты с опасной средой обитания. Не любит охоту и не умеет пользоваться копьями. На нем отлично смотрятся шляпы."
+ icon_state = "slugcat_monk"
+ icon_living = "slugcat_monk"
+ icon_dead = "slugcat_monk_dead"
+ icon_resting = "slugcat_monk_rest"
+ is_pacifist = TRUE
+ gold_core_spawnable = FRIENDLY_SPAWN
+ health = 80
+ maxHealth = 80
+
+/mob/living/simple_animal/pet/slugcat/hunter
+ name = "слизнекот-охотник"
+ desc = "Удивительное существо, напоминающая кота и слизня в одном обличии. Но это не слизь, а иной вид существа. Гордость ксенобиологии. Крайне ловкое и умное, родом с планеты с опасной средой обитания. Обожает копья и умело управляется ими, не стоит давать ему его в лапки. На нем отлично смотрятся шляпы."
+ icon_state = "slugcat_hunter"
+ icon_living = "slugcat_hunter"
+ icon_dead = "slugcat_hunter_dead"
+ icon_resting = "slugcat_hunter_rest"
+ is_pacifist = FALSE
+ is_reduce_damage = FALSE
+ faction = list("slime","neutral","hostile")
+ gold_core_spawnable = HOSTILE_SPAWN
+ health = 150
+ maxHealth = 150
+
+/mob/living/simple_animal/pet/slugcat/gold //for admins
+ name = "золотой слизнекот"
+ desc = "Уникальный золотой слизнекот полученный чудотворным путём."
+ icon_state = "slugcat_gold"
+ icon_living = "slugcat_gold"
+ icon_dead = "slugcat_gold_dead"
+ icon_resting = "slugcat_gold_rest"
+ is_pacifist = FALSE
+ is_reduce_damage = FALSE
+ gold_core_spawnable = NO_SPAWN
+ health = 300
+ maxHealth = 300
+
+/mob/living/simple_animal/pet/slugcat/New()
+ ..()
+ regenerate_icons()
+
+
+/mob/living/simple_animal/pet/slugcat/attackby__legacy__attackchain(obj/item/W, mob/user, params)
+ if(stat != DEAD)
+ if(istype(W, /obj/item/clothing/head) && user.a_intent == INTENT_HELP)
+ place_on_head(user.get_active_hand(), user)
+ return
+ if(istype(W, /obj/item/spear) && user.a_intent != INTENT_HARM)
+ place_to_hand(user.get_active_hand(), user)
+ return
+
+ . = ..()
+
+/mob/living/simple_animal/pet/slugcat/death(gibbed)
+ drop_hat()
+ drop_hand()
+ . = ..()
+
+/mob/living/simple_animal/pet/slugcat/regenerate_icons()
+ overlays.Cut()
+ ..()
+
+ if(inventory_hand)
+ if(istype(inventory_hand, /obj/item/spear))
+ speared()
+
+ if(inventory_head)
+ var/image/head_icon
+
+ if(!hat_icon_state)
+ hat_icon_state = inventory_head.icon_state
+ if(!hat_alpha)
+ hat_alpha = inventory_head.alpha
+ if(!hat_color)
+ hat_color = inventory_head.color
+
+ head_icon = get_hat_overlay()
+
+ add_overlay(head_icon)
+
+/mob/living/simple_animal/pet/slugcat/on_lying_down(updating = 1)
+ if(inventory_head || inventory_hand)
+ hat_offset_y = hat_offset_y_rest
+ drop_hand()
+ regenerate_icons()
+ . = ..()
+
+/mob/living/simple_animal/pet/slugcat/on_standing_up(updating = 1)
+ if(inventory_head)
+ hat_offset_y = initial(hat_offset_y)
+ regenerate_icons()
+ . = ..()
+
+/mob/living/simple_animal/pet/slugcat/proc/speared()
+ icon_state = "[initial(icon_state)]_spear"
+
+ var/obj/item/spear/spear = inventory_hand
+
+ attacktext = "бьет копьем"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ melee_damage_type = BRUTE
+ melee_damage_lower = round(spear.force_unwielded / (is_reduce_damage ? 2 : 1))
+ melee_damage_upper = round(spear.force_wielded / (is_reduce_damage ? 2 : 1))
+ obj_damage = spear.force
+
+/mob/living/simple_animal/pet/slugcat/proc/unspeared()
+ icon_state = initial(icon_state)
+ attacktext = initial(attacktext)
+ attack_sound = initial(attack_sound)
+ melee_damage_type = initial(melee_damage_type)
+ melee_damage_lower = initial(melee_damage_lower)
+ melee_damage_upper = initial(melee_damage_upper)
+ obj_damage = initial(obj_damage)
+
+/mob/living/simple_animal/pet/slugcat/proc/get_hat_overlay()
+ if(hat_icon_file && hat_icon_state)
+ var/image/slugI = image(hat_icon_file, hat_icon_state)
+ slugI.alpha = hat_alpha
+ slugI.color = hat_color
+ slugI.pixel_y = hat_offset_y
+ //slugI.transform = matrix(1, 0, 1, 0, 1, 0)
+ return slugI
+
+/mob/living/simple_animal/pet/slugcat/proc/place_on_head(obj/item/item_to_add, mob/user)
+ if(!item_to_add)
+ user.visible_message(
+ span_notice("[user] похлопывает по голове [src.name]."),
+ span_notice("Вы положили руку на голову [src.name]."))
+ if(flags_2 & HOLOGRAM_2)
+ return 0
+ return 0
+
+ if(!istype(item_to_add, /obj/item/clothing/head))
+ to_chat(user, span_warning("[item_to_add.name] нельзя надеть на голову [src.name]!"))
+ return 0
+
+ if(inventory_head)
+ if(user)
+ to_chat(user, span_warning("Нельзя надеть больше одного головного убора на голову [src.name]!"))
+ return 0
+
+ if(user && !user.unEquip(item_to_add))
+ to_chat(user, span_warning("[item_to_add.name] застрял в ваших руках, вы не можете его надеть на голову [src.name]!"))
+ return 0
+
+ user.visible_message(
+ span_notice("[user] надевает [item_to_add].name на голову [real_name]."),
+ span_notice("Вы надеваете [item_to_add.name] на голову [real_name]."),
+ span_italics("Вы слышите как что-то нацепили."))
+ item_to_add.forceMove(src)
+ inventory_head = item_to_add
+ regenerate_icons()
+
+ return 1
+
+/mob/living/simple_animal/pet/slugcat/proc/remove_from_head(mob/user)
+ if(inventory_head)
+ if(inventory_head.flags & NODROP)
+ to_chat(user, span_warning("[inventory_head.name] застрял на голове [src.name]! Его невозможно снять!"))
+ return TRUE
+
+ to_chat(user, span_warning("Вы сняли [inventory_head.name] с головы [src.name]."))
+ drop_item(inventory_head)
+ user.put_in_hands(inventory_head)
+
+ null_hat()
+
+ regenerate_icons()
+ else
+ to_chat(user, span_warning("На голове [src.name] нет головного убора!"))
+ return FALSE
+
+ return TRUE
+
+/mob/living/simple_animal/pet/slugcat/proc/drop_hat()
+ if(inventory_head)
+ drop_item(inventory_head)
+ null_hat()
+ regenerate_icons()
+
+/mob/living/simple_animal/pet/slugcat/proc/null_hat()
+ inventory_head = null
+ hat_icon_state = null
+ hat_alpha = null
+ hat_color = null
+
+/mob/living/simple_animal/pet/slugcat/proc/place_to_hand(obj/item/item_to_add, mob/user)
+ if(!item_to_add)
+ user.visible_message(
+ span_notice("[user] пощупал лапки [src]."),
+ span_notice("Вы пощупали лапки [src]."))
+ if(flags_2 & HOLOGRAM_2)
+ return 0
+ return 0
+
+ if(resting)
+ to_chat(user, span_warning("[src.name] спит и не принимает [item_to_add.name]!"))
+ return 0
+
+ if(!istype(item_to_add, /obj/item/spear))
+ to_chat(user, span_warning("[src.name] не принимает [item_to_add.name]!"))
+ return 0
+
+ if(inventory_hand)
+ if(user)
+ to_chat(user, span_warning("Лапки [src.name] заняты [inventory_hand.name]!"))
+ return 0
+
+ if(user && !user.drop_item(item_to_add))
+ to_chat(user, span_warning("[item_to_add.name] застрял в ваших руках, вы не можете его дать [src.name]!"))
+ return 0
+
+ if(is_pacifist)
+ to_chat(user, span_warning("[src.name] пацифист и не пользуется [item_to_add.name]!"))
+ return 0
+
+ user.visible_message(
+ span_notice("[real_name] выхватывает [item_to_add] с рук [user]."),
+ span_notice("[real_name] выхватывает [item_to_add] с ваших рук."),
+ span_italics("Вы видите довольные глаза."))
+ move_item_to_hand(item_to_add)
+
+ return 1
+
+/mob/living/simple_animal/pet/slugcat/proc/move_item_to_hand(obj/item/item_to_add)
+ item_to_add.forceMove(src)
+ inventory_hand = item_to_add
+ regenerate_icons()
+
+/mob/living/simple_animal/pet/slugcat/proc/remove_from_hand(mob/user)
+ if(inventory_hand)
+ if(inventory_hand.flags & NODROP)
+ to_chat(user, span_warning("[inventory_hand.name] застрял в лапах [src]! Его невозможно отнять!"))
+ return TRUE
+
+ to_chat(user, span_warning("Вы забрали [inventory_hand.name] с лап [src]."))
+ drop_item(inventory_hand)
+ user.put_in_hands(inventory_hand)
+
+ null_hand()
+
+ regenerate_icons()
+ else
+ to_chat(user, span_warning("В лапах [src] нечего отбирать!"))
+ return FALSE
+
+ return TRUE
+
+/mob/living/simple_animal/pet/slugcat/proc/drop_hand()
+ if(inventory_hand)
+ drop_item(inventory_hand)
+ null_hand()
+ regenerate_icons()
+
+/mob/living/simple_animal/pet/slugcat/proc/null_hand()
+ unspeared()
+ inventory_hand = null
diff --git a/modular_ss220/mobs/code/supplypacks/crittercrate.dm b/modular_ss220/mobs/code/supplypacks/crittercrate.dm
new file mode 100644
index 000000000000..bc644327eaca
--- /dev/null
+++ b/modular_ss220/mobs/code/supplypacks/crittercrate.dm
@@ -0,0 +1,158 @@
+//dogs
+/obj/structure/closet/critter/corgi
+ name = "dog corgi crate"
+
+/obj/structure/closet/critter/pug
+ name = "dog pug crate"
+
+/obj/structure/closet/critter/dog_bullterrier
+ name = "dog bullterrier crate"
+ content_mob = /mob/living/simple_animal/pet/dog/bullterrier
+
+/obj/structure/closet/critter/dog_tamaskan
+ name = "dog tamaskan crate"
+ content_mob = /mob/living/simple_animal/pet/dog/tamaskan
+
+/obj/structure/closet/critter/dog_german
+ name = "dog german crate"
+ content_mob = /mob/living/simple_animal/pet/dog/german
+
+/obj/structure/closet/critter/dog_brittany
+ name = "dog brittany crate"
+ content_mob = /mob/living/simple_animal/pet/dog/brittany
+
+
+// cats
+/obj/structure/closet/critter/cat/populate_contents()
+ . = ..()
+ if(prob(5))
+ content_mob = /mob/living/simple_animal/pet/cat/fat
+
+/obj/structure/closet/critter/cat_white
+ name = "white cat crate"
+ content_mob = /mob/living/simple_animal/pet/cat/white
+
+/obj/structure/closet/critter/cat_birman
+ name = "birman cat crate"
+ content_mob = /mob/living/simple_animal/pet/cat/birman
+
+// fox
+/obj/structure/closet/critter/fox/populate_contents()
+ . = ..()
+ if(prob(30))
+ content_mob = /mob/living/simple_animal/pet/dog/fox/forest
+
+/obj/structure/closet/critter/fennec
+ name = "fennec crate"
+ content_mob = /mob/living/simple_animal/pet/dog/fox/fennec
+
+// amphibians
+/obj/structure/closet/critter/frog
+ name = "frog crate"
+ content_mob = /mob/living/simple_animal/frog
+
+/obj/structure/closet/critter/frog/populate_contents()
+ amount = rand(1, 3)
+
+/obj/structure/closet/critter/frog/toxic
+ name = "frog crate"
+ content_mob = /mob/living/simple_animal/frog/toxic
+
+/obj/structure/closet/critter/frog/toxic/populate_contents()
+ . = ..()
+ if(prob(25))
+ content_mob = /mob/living/simple_animal/frog/toxic/scream
+
+/obj/structure/closet/critter/frog/scream
+ name = "frog crate"
+ content_mob = /mob/living/simple_animal/frog/scream
+
+/obj/structure/closet/critter/snail
+ name = "snail crate"
+ content_mob = /mob/living/simple_animal/snail
+
+/obj/structure/closet/critter/snail/populate_contents()
+ amount = rand(1, 5)
+
+/obj/structure/closet/critter/turtle
+ name = "turtle crate"
+ content_mob = /mob/living/simple_animal/turtle
+
+// lizards
+/obj/structure/closet/critter/iguana
+ name = "iguana crate"
+ content_mob = /mob/living/simple_animal/hostile/lizard
+
+/obj/structure/closet/critter/gator
+ name = "gator crate"
+ content_mob = /mob/living/simple_animal/hostile/lizard/gator
+
+/obj/structure/closet/critter/croco
+ name = "croco crate"
+ content_mob = /mob/living/simple_animal/hostile/lizard/croco
+
+//misc
+/obj/structure/closet/critter/sloth
+ name = "sloth crate"
+ content_mob = /mob/living/simple_animal/pet/sloth
+
+/obj/structure/closet/critter/goose
+ name = "goose crate"
+ content_mob = /mob/living/simple_animal/goose
+
+/obj/structure/closet/critter/gosling
+ name = "gosling crate"
+ content_mob = /mob/living/simple_animal/goose/gosling
+
+/obj/structure/closet/critter/gosling/populate_contents()
+ amount = rand(1, 3)
+
+/obj/structure/closet/critter/hamster
+ name = "hamster crate"
+ content_mob = /mob/living/simple_animal/mouse/hamster
+
+/obj/structure/closet/critter/hamster/populate_contents()
+ amount = rand(1, 5)
+
+/obj/structure/closet/critter/possum
+ name = "possum crate"
+ content_mob = /mob/living/simple_animal/possum
+
+/obj/structure/closet/critter/possum/populate_contents()
+ amount = rand(1, 5)
+
+/obj/structure/closet/critter/moth //ящик дорогих шуб поели моли. Увынск.
+ name = "ящик дорогих шуб"
+ content_mob = /mob/living/simple_animal/moth
+ var/static/prob_clothes = 50
+ var/static/possible_clothes_list = list(
+ /obj/item/clothing/suit/pimpcoat = 50,
+
+ /obj/item/clothing/suit/tailcoat = 25,
+ /obj/item/clothing/suit/victcoat = 25,
+ /obj/item/clothing/suit/victcoat/red = 25,
+ /obj/item/clothing/suit/draculacoat = 25,
+ /obj/item/clothing/suit/browntrenchcoat = 25,
+ /obj/item/clothing/suit/blacktrenchcoat = 25,
+
+ /obj/item/clothing/suit/storage/blueshield = 5,
+ /obj/item/clothing/suit/sovietcoat = 5,
+
+ /obj/item/clothing/suit/armor/vest/capcarapace/jacket = 1,
+ /obj/item/clothing/suit/armor/vest/capcarapace/jacket/tunic = 1,
+ /obj/item/clothing/suit/armor/vest/capcarapace/coat = 1,
+ /obj/item/clothing/suit/armor/vest/capcarapace/coat/white = 1,
+ )
+
+/obj/structure/closet/critter/moth/populate_contents()
+ amount = rand(1, 5)
+ if(prob(50))
+ content_mob = /mob/living/simple_animal/nian_caterpillar
+
+ if(prob(prob_clothes))
+ //contains = list()
+ var/clothes_amount = rand(1, 8)
+ for(var/i in 1 to clothes_amount)
+ var/picked = pick(possible_clothes_list)
+ new picked(src)
+ //contains.add(picked)
diff --git a/modular_ss220/mobs/code/supplypacks/pack_animals.dm b/modular_ss220/mobs/code/supplypacks/pack_animals.dm
new file mode 100644
index 000000000000..2558d2b1c1f3
--- /dev/null
+++ b/modular_ss220/mobs/code/supplypacks/pack_animals.dm
@@ -0,0 +1,142 @@
+//dogs
+/datum/supply_packs/organic/corgi
+ name = "Dog Corgi Crate"
+
+/datum/supply_packs/organic/pug
+ name = "Dog Pug Crate"
+ cost = 300
+ containertype = /obj/structure/closet/critter/pug
+ containername = "dog pug crate"
+
+/datum/supply_packs/organic/dog_bullterrier
+ name = "Dog Bullterrie Crate"
+ cost = 300
+ containertype = /obj/structure/closet/critter/dog_bullterrier
+ containername = "dog bullterrie crate"
+
+/datum/supply_packs/organic/dog_tamaskan
+ name = "Dog Tamaskan Crate"
+ cost = 300
+ containertype = /obj/structure/closet/critter/dog_tamaskan
+ containername = "dog tamaskan crate"
+
+/datum/supply_packs/organic/dog_german
+ name = "Dog German Crate"
+ cost = 300
+ containertype = /obj/structure/closet/critter/dog_german
+ containername = "dog german crate"
+
+/datum/supply_packs/organic/dog_brittany
+ name = "Dog Brittany Crate"
+ cost = 300
+ containertype = /obj/structure/closet/critter/dog_brittany
+ containername = "dog brittany crate"
+
+//cats
+/datum/supply_packs/organic/cat/white
+ name = "White Cat Crate"
+ cost = 400
+ containername = "white crate"
+ containertype = /obj/structure/closet/critter/cat_white
+
+/datum/supply_packs/organic/cat/birman
+ name = "Birman Cat Crate"
+ cost = 500
+ containername = "birman crate"
+ containertype = /obj/structure/closet/critter/cat_birman
+
+//fox
+/datum/supply_packs/organic/fennec
+ name = "Fennec Crate"
+ cost = 500
+ containertype = /obj/structure/closet/critter/fennec
+ containername = "fennec crate"
+
+//amphibia
+/datum/supply_packs/organic/frog
+ name = "Frog Crate"
+ cost = 250
+ containertype = /obj/structure/closet/critter/frog
+ containername = "frog crate"
+
+/datum/supply_packs/organic/frog/toxic
+ name = "ERROR frog Crate"
+ cost = 1500
+ containertype = /obj/structure/closet/critter/frog/toxic
+ containername = "ERROR frog crate"
+ hidden = 1
+
+/datum/supply_packs/organic/frog/toxic
+ name = "LOUD frog Crate"
+ cost = 1000
+ containertype = /obj/structure/closet/critter/frog/scream
+ containername = "LOUD frog crate"
+ hidden = 1
+
+/datum/supply_packs/organic/snail
+ name = "Snail Crate"
+ cost = 600
+ containertype = /obj/structure/closet/critter/snail
+ containername = "snail crate"
+
+/datum/supply_packs/organic/turtle
+ name = "Turtle Crate"
+ cost = 400
+ containertype = /obj/structure/closet/critter/turtle
+ containername = "turtle crate"
+
+//lizards
+/datum/supply_packs/organic/iguana
+ name = "Iguana Crate"
+ cost = 550
+ containertype = /obj/structure/closet/critter/iguana
+ containername = "iguana crate"
+
+/datum/supply_packs/organic/gator
+ name = "Gator Crate"
+ cost = 1000 //most dangerous
+ containertype = /obj/structure/closet/critter/gator
+ containername = "gator crate"
+
+/datum/supply_packs/organic/croco
+ name = "Croco Crate"
+ cost = 850
+ containertype = /obj/structure/closet/critter/croco
+ containername = "croco crate"
+
+//misc
+/datum/supply_packs/organic/sloth
+ name = "Sloth Crate"
+ cost = 500
+ containertype = /obj/structure/closet/critter/sloth
+ containername = "sloth crate"
+
+/datum/supply_packs/organic/goose
+ name = "Goose Crate"
+ cost = 250
+ containertype = /obj/structure/closet/critter/goose
+ containername = "goose crate"
+
+/datum/supply_packs/organic/gosling
+ name = "Gosling Crate"
+ cost = 50
+ containertype = /obj/structure/closet/critter/gosling
+ containername = "gosling crate"
+
+/datum/supply_packs/organic/hamster
+ name = "Hamster Crate"
+ cost = 150
+ containertype = /obj/structure/closet/critter/hamster
+ containername = "hamster crate"
+
+/datum/supply_packs/organic/possum
+ name = "Possum Crate"
+ cost = 200
+ containertype = /obj/structure/closet/critter/possum
+ containername = "possum crate"
+
+/datum/supply_packs/misc/moth
+ name = "ящик дорогих шуб"
+ cost = 2000
+ containertype = /obj/structure/closet/critter/moth
+ containername = "fur crate"
diff --git a/modular_ss220/mobs/icons/items.dmi b/modular_ss220/mobs/icons/items.dmi
new file mode 100644
index 000000000000..24d56208221a
Binary files /dev/null and b/modular_ss220/mobs/icons/items.dmi differ
diff --git a/modular_ss220/mobs/icons/mob/animal.dmi b/modular_ss220/mobs/icons/mob/animal.dmi
new file mode 100644
index 000000000000..8aa7c7099949
Binary files /dev/null and b/modular_ss220/mobs/icons/mob/animal.dmi differ
diff --git a/modular_ss220/mobs/icons/mob/headcrab.dmi b/modular_ss220/mobs/icons/mob/headcrab.dmi
new file mode 100644
index 000000000000..a1081b398350
Binary files /dev/null and b/modular_ss220/mobs/icons/mob/headcrab.dmi differ
diff --git a/modular_ss220/mobs/icons/mob/inhands/mobs_lefthand.dmi b/modular_ss220/mobs/icons/mob/inhands/mobs_lefthand.dmi
new file mode 100644
index 000000000000..f62231afbc2c
Binary files /dev/null and b/modular_ss220/mobs/icons/mob/inhands/mobs_lefthand.dmi differ
diff --git a/modular_ss220/mobs/icons/mob/inhands/mobs_righthand.dmi b/modular_ss220/mobs/icons/mob/inhands/mobs_righthand.dmi
new file mode 100644
index 000000000000..b6947c613fcd
Binary files /dev/null and b/modular_ss220/mobs/icons/mob/inhands/mobs_righthand.dmi differ
diff --git a/modular_ss220/mobs/icons/mob/inhead/ears.dmi b/modular_ss220/mobs/icons/mob/inhead/ears.dmi
new file mode 100644
index 000000000000..7876fe6d7c53
Binary files /dev/null and b/modular_ss220/mobs/icons/mob/inhead/ears.dmi differ
diff --git a/modular_ss220/mobs/icons/mob/inhead/head.dmi b/modular_ss220/mobs/icons/mob/inhead/head.dmi
new file mode 100644
index 000000000000..e08634fcd4dd
Binary files /dev/null and b/modular_ss220/mobs/icons/mob/inhead/head.dmi differ
diff --git a/modular_ss220/mobs/icons/mob/pets.dmi b/modular_ss220/mobs/icons/mob/pets.dmi
new file mode 100644
index 000000000000..8e18c44950b9
Binary files /dev/null and b/modular_ss220/mobs/icons/mob/pets.dmi differ
diff --git a/modular_ss220/mobs/icons/mob/unsorted.dmi b/modular_ss220/mobs/icons/mob/unsorted.dmi
new file mode 100644
index 000000000000..2fc6c72b9a1c
Binary files /dev/null and b/modular_ss220/mobs/icons/mob/unsorted.dmi differ
diff --git a/modular_ss220/mobs/icons/muhtar_accessories.dmi b/modular_ss220/mobs/icons/muhtar_accessories.dmi
new file mode 100644
index 000000000000..bad7da59ddc8
Binary files /dev/null and b/modular_ss220/mobs/icons/muhtar_accessories.dmi differ
diff --git a/modular_ss220/mobs/icons/pet_carrier.dmi b/modular_ss220/mobs/icons/pet_carrier.dmi
new file mode 100644
index 000000000000..927532ff3316
Binary files /dev/null and b/modular_ss220/mobs/icons/pet_carrier.dmi differ
diff --git a/modular_ss220/mobs/icons/rouge_accessories.dmi b/modular_ss220/mobs/icons/rouge_accessories.dmi
new file mode 100644
index 000000000000..118748c522d9
Binary files /dev/null and b/modular_ss220/mobs/icons/rouge_accessories.dmi differ
diff --git a/modular_ss220/mobs/sound/creatures/bear_death.ogg b/modular_ss220/mobs/sound/creatures/bear_death.ogg
new file mode 100644
index 000000000000..8b5717ae9c79
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bear_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/bear_onerawr1.ogg b/modular_ss220/mobs/sound/creatures/bear_onerawr1.ogg
new file mode 100644
index 000000000000..3b68421ad61e
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bear_onerawr1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/bear_onerawr2.ogg b/modular_ss220/mobs/sound/creatures/bear_onerawr2.ogg
new file mode 100644
index 000000000000..98d71af8f0ee
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bear_onerawr2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/bear_onerawr3.ogg b/modular_ss220/mobs/sound/creatures/bear_onerawr3.ogg
new file mode 100644
index 000000000000..1e2b0ef5a1d0
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bear_onerawr3.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/bear_rawr.ogg b/modular_ss220/mobs/sound/creatures/bear_rawr.ogg
new file mode 100644
index 000000000000..61565198f46f
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bear_rawr.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/bear_talk1.ogg b/modular_ss220/mobs/sound/creatures/bear_talk1.ogg
new file mode 100644
index 000000000000..bb6815c20487
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bear_talk1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/bear_talk2.ogg b/modular_ss220/mobs/sound/creatures/bear_talk2.ogg
new file mode 100644
index 000000000000..ae3dbf335758
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bear_talk2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/bear_talk3.ogg b/modular_ss220/mobs/sound/creatures/bear_talk3.ogg
new file mode 100644
index 000000000000..a8f28d93075d
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bear_talk3.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/bee.ogg b/modular_ss220/mobs/sound/creatures/bee.ogg
new file mode 100644
index 000000000000..ea8dcc2b369b
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/bee.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/cat_meow.ogg b/modular_ss220/mobs/sound/creatures/cat_meow.ogg
new file mode 100644
index 000000000000..f52cbd2a172f
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/cat_meow.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/caw.ogg b/modular_ss220/mobs/sound/creatures/caw.ogg
new file mode 100644
index 000000000000..dc199f7f4fe6
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/caw.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/chicken_damaged1.ogg b/modular_ss220/mobs/sound/creatures/chicken_damaged1.ogg
new file mode 100644
index 000000000000..6cc8e63e1511
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/chicken_damaged1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/chicken_damaged2.ogg b/modular_ss220/mobs/sound/creatures/chicken_damaged2.ogg
new file mode 100644
index 000000000000..01a4308d53dc
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/chicken_damaged2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/chicken_death.ogg b/modular_ss220/mobs/sound/creatures/chicken_death.ogg
new file mode 100644
index 000000000000..989c35b9d472
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/chicken_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/chicken_talk.ogg b/modular_ss220/mobs/sound/creatures/chicken_talk.ogg
new file mode 100644
index 000000000000..2f38d2e6c7dc
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/chicken_talk.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/cow_damaged.ogg b/modular_ss220/mobs/sound/creatures/cow_damaged.ogg
new file mode 100644
index 000000000000..7ba82ddb8f4e
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/cow_damaged.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/cow_death.ogg b/modular_ss220/mobs/sound/creatures/cow_death.ogg
new file mode 100644
index 000000000000..00555ec9b620
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/cow_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/cow_talk1.ogg b/modular_ss220/mobs/sound/creatures/cow_talk1.ogg
new file mode 100644
index 000000000000..1a1f03b69351
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/cow_talk1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/cow_talk2.ogg b/modular_ss220/mobs/sound/creatures/cow_talk2.ogg
new file mode 100644
index 000000000000..3ad84c9134f6
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/cow_talk2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/crack_death1.ogg b/modular_ss220/mobs/sound/creatures/crack_death1.ogg
new file mode 100644
index 000000000000..bad0933700b7
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/crack_death1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/crack_death2.ogg b/modular_ss220/mobs/sound/creatures/crack_death2.ogg
new file mode 100644
index 000000000000..8c9ed6aa56a5
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/crack_death2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/dog_bark1.ogg b/modular_ss220/mobs/sound/creatures/dog_bark1.ogg
new file mode 100644
index 000000000000..809f3897c889
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/dog_bark1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/dog_bark2.ogg b/modular_ss220/mobs/sound/creatures/dog_bark2.ogg
new file mode 100644
index 000000000000..e4e27b0f8628
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/dog_bark2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/dog_grawl1.ogg b/modular_ss220/mobs/sound/creatures/dog_grawl1.ogg
new file mode 100644
index 000000000000..1e55c9b09c4d
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/dog_grawl1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/dog_grawl2.ogg b/modular_ss220/mobs/sound/creatures/dog_grawl2.ogg
new file mode 100644
index 000000000000..33b51191149e
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/dog_grawl2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/dog_yelp.ogg b/modular_ss220/mobs/sound/creatures/dog_yelp.ogg
new file mode 100644
index 000000000000..22f1586014dc
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/dog_yelp.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/duck_aggro1.ogg b/modular_ss220/mobs/sound/creatures/duck_aggro1.ogg
new file mode 100644
index 000000000000..9c65adb557aa
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/duck_aggro1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/duck_aggro2.ogg b/modular_ss220/mobs/sound/creatures/duck_aggro2.ogg
new file mode 100644
index 000000000000..2f70b7724dfb
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/duck_aggro2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/duck_quak1.ogg b/modular_ss220/mobs/sound/creatures/duck_quak1.ogg
new file mode 100644
index 000000000000..a21e1022690e
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/duck_quak1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/duck_quak2.ogg b/modular_ss220/mobs/sound/creatures/duck_quak2.ogg
new file mode 100644
index 000000000000..c841535916c0
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/duck_quak2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/duck_quak3.ogg b/modular_ss220/mobs/sound/creatures/duck_quak3.ogg
new file mode 100644
index 000000000000..c985b116279c
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/duck_quak3.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/duck_talk1.ogg b/modular_ss220/mobs/sound/creatures/duck_talk1.ogg
new file mode 100644
index 000000000000..9c38a1220d19
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/duck_talk1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/duck_talk2.ogg b/modular_ss220/mobs/sound/creatures/duck_talk2.ogg
new file mode 100644
index 000000000000..43302c82dc1f
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/duck_talk2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/duck_talk3.ogg b/modular_ss220/mobs/sound/creatures/duck_talk3.ogg
new file mode 100644
index 000000000000..c511727a9d6b
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/duck_talk3.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/fast_zombie_idle1.ogg b/modular_ss220/mobs/sound/creatures/fast_zombie_idle1.ogg
new file mode 100644
index 000000000000..373df5f68acb
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/fast_zombie_idle1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/fast_zombie_idle2.ogg b/modular_ss220/mobs/sound/creatures/fast_zombie_idle2.ogg
new file mode 100644
index 000000000000..54d7a5890665
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/fast_zombie_idle2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/fast_zombie_idle3.ogg b/modular_ss220/mobs/sound/creatures/fast_zombie_idle3.ogg
new file mode 100644
index 000000000000..f9f97049c9a5
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/fast_zombie_idle3.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/fox_yelp.ogg b/modular_ss220/mobs/sound/creatures/fox_yelp.ogg
new file mode 100644
index 000000000000..83c60317f65e
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/fox_yelp.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_damaged.ogg b/modular_ss220/mobs/sound/creatures/frog_damaged.ogg
new file mode 100644
index 000000000000..0a5096e51f8f
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_damaged.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_death.ogg b/modular_ss220/mobs/sound/creatures/frog_death.ogg
new file mode 100644
index 000000000000..c5afa7145b84
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_scream1.ogg b/modular_ss220/mobs/sound/creatures/frog_scream1.ogg
new file mode 100644
index 000000000000..9be0bebcfbd8
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_scream1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_scream2.ogg b/modular_ss220/mobs/sound/creatures/frog_scream2.ogg
new file mode 100644
index 000000000000..6a635f5a676b
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_scream2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_scream_1.ogg b/modular_ss220/mobs/sound/creatures/frog_scream_1.ogg
new file mode 100644
index 000000000000..0c397369b4fe
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_scream_1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_scream_2.ogg b/modular_ss220/mobs/sound/creatures/frog_scream_2.ogg
new file mode 100644
index 000000000000..25dd16c0f7b5
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_scream_2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_scream_3.ogg b/modular_ss220/mobs/sound/creatures/frog_scream_3.ogg
new file mode 100644
index 000000000000..232f32bd50d1
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_scream_3.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_talk1.ogg b/modular_ss220/mobs/sound/creatures/frog_talk1.ogg
new file mode 100644
index 000000000000..eb34774607a1
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_talk1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/frog_talk2.ogg b/modular_ss220/mobs/sound/creatures/frog_talk2.ogg
new file mode 100644
index 000000000000..f905914a3b00
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/frog_talk2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/goat_death.ogg b/modular_ss220/mobs/sound/creatures/goat_death.ogg
new file mode 100644
index 000000000000..630d1ac75d50
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/goat_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/headcrab_attack.ogg b/modular_ss220/mobs/sound/creatures/headcrab_attack.ogg
new file mode 100644
index 000000000000..4f6d114aa757
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/headcrab_attack.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/hoot.ogg b/modular_ss220/mobs/sound/creatures/hoot.ogg
new file mode 100644
index 000000000000..a1b6b5f18fa4
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/hoot.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/legion_death.ogg b/modular_ss220/mobs/sound/creatures/legion_death.ogg
new file mode 100644
index 000000000000..fdcf9c8a6596
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/legion_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/legion_death_far.ogg b/modular_ss220/mobs/sound/creatures/legion_death_far.ogg
new file mode 100644
index 000000000000..3e3261687c3b
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/legion_death_far.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/legion_spawn.ogg b/modular_ss220/mobs/sound/creatures/legion_spawn.ogg
new file mode 100644
index 000000000000..9fce6dec4c6c
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/legion_spawn.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/lizard_angry1.ogg b/modular_ss220/mobs/sound/creatures/lizard_angry1.ogg
new file mode 100644
index 000000000000..0d73ac0d7fcd
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/lizard_angry1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/lizard_angry2.ogg b/modular_ss220/mobs/sound/creatures/lizard_angry2.ogg
new file mode 100644
index 000000000000..56f1f311ae90
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/lizard_angry2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/lizard_angry3.ogg b/modular_ss220/mobs/sound/creatures/lizard_angry3.ogg
new file mode 100644
index 000000000000..c68ec9e56078
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/lizard_angry3.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/lizard_damaged.ogg b/modular_ss220/mobs/sound/creatures/lizard_damaged.ogg
new file mode 100644
index 000000000000..aeb97e6de64d
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/lizard_damaged.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/lizard_death.ogg b/modular_ss220/mobs/sound/creatures/lizard_death.ogg
new file mode 100644
index 000000000000..300e36a33fd1
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/lizard_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/lizard_death_big.ogg b/modular_ss220/mobs/sound/creatures/lizard_death_big.ogg
new file mode 100644
index 000000000000..aeb97e6de64d
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/lizard_death_big.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/mouse_squeak.ogg b/modular_ss220/mobs/sound/creatures/mouse_squeak.ogg
new file mode 100644
index 000000000000..7b413d6da2a0
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/mouse_squeak.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/narsie_rises.ogg b/modular_ss220/mobs/sound/creatures/narsie_rises.ogg
new file mode 100644
index 000000000000..ccd10cf115fa
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/narsie_rises.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/nymphchirp.ogg b/modular_ss220/mobs/sound/creatures/nymphchirp.ogg
new file mode 100644
index 000000000000..e0e573d497d6
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/nymphchirp.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/ph_scream1.ogg b/modular_ss220/mobs/sound/creatures/ph_scream1.ogg
new file mode 100644
index 000000000000..857cf11b0a21
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/ph_scream1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/pig_death.ogg b/modular_ss220/mobs/sound/creatures/pig_death.ogg
new file mode 100644
index 000000000000..0b83fd283627
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/pig_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/pig_talk1.ogg b/modular_ss220/mobs/sound/creatures/pig_talk1.ogg
new file mode 100644
index 000000000000..0763252277d8
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/pig_talk1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/pig_talk2.ogg b/modular_ss220/mobs/sound/creatures/pig_talk2.ogg
new file mode 100644
index 000000000000..ec5a425459df
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/pig_talk2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/rat_death.ogg b/modular_ss220/mobs/sound/creatures/rat_death.ogg
new file mode 100644
index 000000000000..47021115d4aa
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/rat_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/rat_squeak.ogg b/modular_ss220/mobs/sound/creatures/rat_squeak.ogg
new file mode 100644
index 000000000000..99bbbbe731e9
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/rat_squeak.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/rat_talk.ogg b/modular_ss220/mobs/sound/creatures/rat_talk.ogg
new file mode 100644
index 000000000000..e120c9a33336
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/rat_talk.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/rat_wound.ogg b/modular_ss220/mobs/sound/creatures/rat_wound.ogg
new file mode 100644
index 000000000000..d92c85978870
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/rat_wound.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/seal_death.ogg b/modular_ss220/mobs/sound/creatures/seal_death.ogg
new file mode 100644
index 000000000000..ba40ebc441a8
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/seal_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/snake_death.ogg b/modular_ss220/mobs/sound/creatures/snake_death.ogg
new file mode 100644
index 000000000000..a4104f994f8c
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/snake_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/space_dragon_roar.ogg b/modular_ss220/mobs/sound/creatures/space_dragon_roar.ogg
new file mode 100644
index 000000000000..f7f4503b8946
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/space_dragon_roar.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/spider_attack1.ogg b/modular_ss220/mobs/sound/creatures/spider_attack1.ogg
new file mode 100644
index 000000000000..15d275799502
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/spider_attack1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/spider_attack2.ogg b/modular_ss220/mobs/sound/creatures/spider_attack2.ogg
new file mode 100644
index 000000000000..c7d66176dd0a
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/spider_attack2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/spider_death.ogg b/modular_ss220/mobs/sound/creatures/spider_death.ogg
new file mode 100644
index 000000000000..405b4f4842ec
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/spider_death.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/spider_talk1.ogg b/modular_ss220/mobs/sound/creatures/spider_talk1.ogg
new file mode 100644
index 000000000000..e51baac6b528
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/spider_talk1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/spider_talk2.ogg b/modular_ss220/mobs/sound/creatures/spider_talk2.ogg
new file mode 100644
index 000000000000..634d89c2d0ad
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/spider_talk2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/zombie_attack.ogg b/modular_ss220/mobs/sound/creatures/zombie_attack.ogg
new file mode 100644
index 000000000000..1e9b2a630241
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/zombie_attack.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/zombie_idle1.ogg b/modular_ss220/mobs/sound/creatures/zombie_idle1.ogg
new file mode 100644
index 000000000000..851c88deff49
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/zombie_idle1.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/zombie_idle2.ogg b/modular_ss220/mobs/sound/creatures/zombie_idle2.ogg
new file mode 100644
index 000000000000..04e75da9b226
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/zombie_idle2.ogg differ
diff --git a/modular_ss220/mobs/sound/creatures/zombie_idle3.ogg b/modular_ss220/mobs/sound/creatures/zombie_idle3.ogg
new file mode 100644
index 000000000000..b4cd26007570
Binary files /dev/null and b/modular_ss220/mobs/sound/creatures/zombie_idle3.ogg differ
diff --git a/modular_ss220/modular_ss220.dme b/modular_ss220/modular_ss220.dme
new file mode 100644
index 000000000000..e80023eb857f
--- /dev/null
+++ b/modular_ss220/modular_ss220.dme
@@ -0,0 +1,121 @@
+#include "_modpack.dm"
+#include "_modpacks.dm"
+
+// #include "example/_example.dme"
+
+// --- MAINTENANCE --- //
+#include "_rust_utils/_rust_utils.dme"
+#include "_components/_components.dme"
+#include "_defines220/_defines220.dme"
+#include "_signals220/_signals220.dme"
+#include "_misc/_misc.dme"
+#include "_span/_span.dme"
+#include "maps220/_maps220.dme"
+
+// --- ICONS --- //
+#include "aesthetics/_aesthetics.dme"
+#ifdef MODPACK_CHAT_BADGES
+#include "chat_badges/_chat_badges.dme"
+#endif
+#include "hairs/_hairs.dme"
+
+// --- OBJECTS --- //
+#include "awaymission_gun/_awaymission_gun.dme"
+#include "barsigns/_barsigns.dme"
+#include "clothing/_clothing.dme"
+#include "devices/_devices.dme"
+#include "food_and_drinks/_food_and_drinks.dme"
+#include "gateway/_gateway.dme"
+#include "hydroponics/hydroponics.dme"
+#include "objects/_objects.dme"
+#include "sechailer/sechailer.dme"
+#include "spy_spider/_spy_spider.dme"
+#include "unique_objects/_unique_objects.dme"
+#include "vending/vending.dme"
+#include "wire_splicing/wiresplicing.dme"
+#include "silicons/_silicons.dme"
+#include "windows_airbag/_windows_airbag.dme"
+#include "clumsy_table/_clumsy_table.dme"
+#include "pt_monitor/_pt_monitor.dme"
+
+// --- MISC --- //
+#include "administration/_administration.dme"
+#include "aesthetics_sounds/_aesthetics_sounds.dme"
+#include "agent_id_tgui/_agent_id_tgui.dme"
+#include "ai_integration/_ai_integration.dme"
+#include "antagonists/_antagonists_vox_raiders.dme"
+#include "antagonists/_antagonists.dme"
+#include "autolathe_tgui/_autolathe_tgui.dme"
+#include "balance/_balance.dme"
+#include "bureaucracy/_bureaucracy.dme"
+#include "camera_nanomap/camera.dme"
+#include "cinematics/_cinematics.dme"
+#include "closet_picklocking/_closet_picklocking.dme"
+#include "crawl_speed/_crawl_speed.dme"
+#include "credits/_credits.dme"
+#include "cyrillic_fixes/_cyrillic_fixes.dme"
+#include "debug/_debug.dme"
+#include "detective_rework/detective_rework.dme"
+#include "discord_link/_discord_link.dme"
+#include "donor/_donor.dme"
+#include "emotes/_emotes.dme"
+#include "events/_events.dme"
+#include "gunhud/_gunhud.dme"
+#include "instruments/_instruments.dme"
+#include "jobs/_jobs.dme"
+#include "jukebox/_jukebox.dme"
+#include "keybindings/_keybindings.dme"
+#include "loadout/_loadout.dme"
+#include "logs/_logs.dme"
+#include "mecha_skins/mecha_skins.dme"
+#include "mobs/_mobs.dme"
+#include "outfits/_outfits.dme"
+#include "phrases/_phrases.dme"
+#include "pixel_shift/_pixel_shift.dme"
+#include "preferences/_preferences.dme"
+#include "queue/_queue.dme"
+#include "redis220/_redis220.dme"
+#include "robolimbs/_robolimbs.dme"
+#include "screentip_change/_screentip_change.dme"
+#include "shuttles/_shuttles.dme"
+#include "sm_space_drop/sm_space_drop.dme"
+#include "smart_equip_targeted/_smart_equip_targeted.dme"
+#include "species_whitelist/_species_whitelist.dme"
+#include "species/_species.dme"
+#include "speech_filter/_speech_filter.dme"
+#include "station_traits/_station_traits.dme"
+#include "text_to_speech/_tts.dme"
+#include "title_screen/_title_screen.dme"
+#include "translations/_translations.dme"
+#include "uplink_items/_uplink_items.dme"
+#include "verbs/_verbs.dme"
+#include "whitelist/_whitelist.dme"
+#include "world_view_bigger/_world_view_bigger.dme"
+
+// --- PRIME --- //
+// #define MODPACK_MAIN_ONLY
+// Чтобы отключить модпаки прайма, нужно добавиту строку выше в code/__DEFINES/_ss220.dm.
+// Изначально они включены. Сделано так, по двум причинам.
+// 1. Добавить новый дефайн на мейне на хосте куда проще, чем на прайме.
+// 2. Так модпаки прайма будут включены в тестах и линтере.
+#ifndef MODPACK_MAIN_ONLY
+#include "security_redalert_accesses/_security_redalert_accesses.dme"
+#include "prime_only/_prime.dme"
+#endif
+
+// --- UNUSED MODS --- //
+
+ /*------------------------------------------------------------------
+ Почему UNUSED MODS стоит хранить?
+ Потому что никто не проверяет использование тех или иных файлов
+ в коде, и мод просто исчезнет из поля зрения, когда находясь здесь
+ он всегда напоминает о своём существовании. Небольшая библиотека,
+ если так вообще можно выразиться.
+ ---------------------------------------------------------------------*/
+
+// #include "crit_rework/_crit_rework.dme"
+
+// --- TESTING --- //
+#ifdef UNIT_TESTS
+#include "unit_tests/_unit_tests.dme"
+#endif
diff --git a/modular_ss220/objects/_objects.dm b/modular_ss220/objects/_objects.dm
new file mode 100644
index 000000000000..1e1c56e02537
--- /dev/null
+++ b/modular_ss220/objects/_objects.dm
@@ -0,0 +1,24 @@
+/datum/modpack/objects
+ name = "Объекты"
+ desc = "В основном включает в себя портированные объекты и всякие мелочи, которым не нужен отдельный модпак."
+ author = "dj-34"
+
+// Maybe it would be better, if i didn't make it modular, because i can't change order in the recipe list :catDespair:
+/datum/modpack/objects/initialize()
+ GLOB.metal_recipes += list(
+ new /datum/stack_recipe("metal platform", /obj/structure/platform, 4, time = 3 SECONDS,one_per_turf = TRUE, on_floor = TRUE),
+ new /datum/stack_recipe("metal platform corner", /obj/structure/platform/corner, 2, time = 20, one_per_turf = TRUE, on_floor = TRUE)
+ )
+
+ GLOB.plasteel_recipes += list(
+ new /datum/stack_recipe("reinforced plasteel platform", /obj/structure/platform/reinforced, 4, time = 4 SECONDS,one_per_turf = TRUE, on_floor = TRUE),
+ new /datum/stack_recipe("reinforced plasteel platform corner", /obj/structure/platform/reinforced/corner, 2, time = 30,one_per_turf = TRUE, on_floor = TRUE)
+ )
+
+ GLOB.wood_recipes += list(
+ new /datum/stack_recipe("tribune", /obj/structure/tribune, 5, time = 5 SECONDS, one_per_turf = TRUE, on_floor = TRUE)
+ )
+
+ GLOB.plastic_recipes += list(
+ new /datum/stack_recipe("пластиковый стул", /obj/structure/chair/plastic, time = 2 SECONDS, one_per_turf = TRUE, on_floor = TRUE),
+ )
diff --git a/modular_ss220/objects/_objects.dme b/modular_ss220/objects/_objects.dme
new file mode 100644
index 000000000000..e38f4a613dc4
--- /dev/null
+++ b/modular_ss220/objects/_objects.dme
@@ -0,0 +1,56 @@
+#include "_objects.dm"
+
+// Flora
+#include "code/flora/sakura.dm"
+
+// ID Skins
+#include "code/id_skins/_id_skins_base.dm"
+#include "code/id_skins/id_skins.dm"
+#include "code/id_skins/id_skins_spawners.dm"
+
+// Mecha
+#include "code/mecha/lockermech.dm"
+#include "code/mecha/combat.dm"
+
+// Weapons
+#include "code/weapons/melee/baseball_bat.dm"
+#include "code/weapons/melee/electrostaff.dm"
+#include "code/weapons/melee/stylet.dm"
+#include "code/weapons/melee/vibroblade.dm"
+#include "code/weapons/ranged/beretta.dm"
+#include "code/weapons/ranged/pneumagun.dm"
+#include "code/weapons/ranged/revolvers.dm"
+#include "code/weapons/ranged/sslr.dm"
+#include "code/weapons/ranged/sakhno.dm"
+#include "code/weapons/ranged/skrell_rifle.dm"
+
+// Plushies
+#include "code/plushies/hampters.dm"
+#include "code/plushies/macvulpix.dm"
+
+// Miscellaneous
+#include "code/beach_umbrella.dm"
+#include "code/big_bed.dm"
+#include "code/billboard.dm"
+#include "code/closets.dm"
+#include "code/coffin.dm"
+#include "code/computer.dm"
+#include "code/mattress.dm"
+#include "code/miscellaneous.dm"
+#include "code/officetoys.dm"
+#include "code/papershredder.dm"
+#include "code/plastic_chair.dm"
+#include "code/platform.dm"
+#include "code/posters.dm"
+#include "code/shuttle.dm"
+#include "code/smartfridge.dm"
+#include "code/tribune.dm"
+#include "code/key.dm"
+#include "code/musician.dm"
+#include "code/flag.dm"
+#include "code/wallets.dm"
+#include "code/flashlight.dm"
+#include "code/material_pouch.dm"
+#include "code/components.dm"
+#include "code/airlock_painter.dm"
+#include "code/animalhide.dm"
diff --git a/modular_ss220/objects/code/airlock_painter.dm b/modular_ss220/objects/code/airlock_painter.dm
new file mode 100644
index 000000000000..f540156d64aa
--- /dev/null
+++ b/modular_ss220/objects/code/airlock_painter.dm
@@ -0,0 +1,45 @@
+// Tweak for multi-tile airlocks, to make them paintable
+
+/obj/machinery/door/airlock/multi_tile
+ paintable = TRUE
+
+/datum/painter/airlock
+ var/static/list/multi_paint_jobs = list(
+ "Atmospherics" = /obj/machinery/door/airlock/multi_tile/atmospheric,
+ "Command" = /obj/machinery/door/airlock/multi_tile/command,
+ "Engineering" = /obj/machinery/door/airlock/multi_tile/engineering,
+ "Mining" = /obj/machinery/door/airlock/multi_tile/supply,
+ "Public" = /obj/machinery/door/airlock/multi_tile,
+ "Security" = /obj/machinery/door/airlock/multi_tile/security,
+ )
+
+// Special behavior for multi-tile airlocks
+/datum/painter/airlock/paint_atom(atom/target, mob/user)
+ if(!istype(target, /obj/machinery/door/airlock/multi_tile))
+ return ..()
+
+ if(!paint_setting)
+ to_chat(user, span_warning("Сперва вам нужно выбрать стиль покраски."))
+ return
+
+ var/obj/machinery/door/airlock/A = target
+ if(!A.paintable)
+ to_chat(user, span_warning("Этот тип шлюза не может быть покрашен."))
+ return
+
+ var/obj/machinery/door/airlock/airlock = multi_paint_jobs["[paint_setting]"]
+ if(isnull(airlock))
+ to_chat(user, span_warning("У выбранного стиля шлюзов нету двойной версии."))
+ return
+
+ var/obj/structure/door_assembly/assembly = initial(airlock.assemblytype)
+ if(A.assemblytype == assembly)
+ to_chat(user, span_notice("Этот шлюз уже покрашен в цветовую схему \"[paint_setting]\"!"))
+ return
+
+ if(do_after_once(user, 2 SECONDS, FALSE, A))
+ A.icon = initial(airlock.icon)
+ A.overlays_file = initial(airlock.overlays_file)
+ A.assemblytype = initial(airlock.assemblytype)
+ A.update_icon()
+ return TRUE
diff --git a/modular_ss220/objects/code/animalhide.dm b/modular_ss220/objects/code/animalhide.dm
new file mode 100644
index 000000000000..92ac128f04b0
--- /dev/null
+++ b/modular_ss220/objects/code/animalhide.dm
@@ -0,0 +1,5 @@
+/obj/item/stack/sheet/animalhide/mothroach
+ name = "mothroach hide"
+ desc = "Тонкий слой шкуры моли."
+ icon = 'modular_ss220/objects/icons/animalhide.dmi'
+ icon_state = "mothroach_hide"
diff --git a/modular_ss220/objects/code/beach_umbrella.dm b/modular_ss220/objects/code/beach_umbrella.dm
new file mode 100644
index 000000000000..6f8cfcf1222d
--- /dev/null
+++ b/modular_ss220/objects/code/beach_umbrella.dm
@@ -0,0 +1,23 @@
+/obj/structure/fluff/beach_umbrella
+ name = "пляжный зонтик"
+ desc = "Зонтик, предназначенный для защиты от солнца на пляже."
+ icon = 'modular_ss220/objects/icons/umbrella.dmi'
+ icon_state = "brella"
+ density = FALSE
+ anchored = TRUE
+ deconstructible = FALSE
+
+/obj/structure/fluff/beach_umbrella/security
+ icon_state = "hos_brella"
+
+/obj/structure/fluff/beach_umbrella/science
+ icon_state = "rd_brella"
+
+/obj/structure/fluff/beach_umbrella/engine
+ icon_state = "ce_brella"
+
+/obj/structure/fluff/beach_umbrella/cap
+ icon_state = "cap_brella"
+
+/obj/structure/fluff/beach_umbrella/syndi
+ icon_state = "syndi_brella"
diff --git a/modular_ss220/objects/code/big_bed.dm b/modular_ss220/objects/code/big_bed.dm
new file mode 100644
index 000000000000..e6a812368c14
--- /dev/null
+++ b/modular_ss220/objects/code/big_bed.dm
@@ -0,0 +1,20 @@
+// Double Beds, for luxurious sleeping, i.e. the captain and maybe heads- if people use this for ERP, send them to skyrat
+/obj/structure/bed/double
+ name = "double bed"
+ desc = "A luxurious double bed, for those too important for small dreams."
+ icon = 'modular_ss220/objects/icons/bed.dmi'
+ icon_state = "bed_double"
+ buildstackamount = 4
+ max_buckled_mobs = 2
+ /// The mob who buckled to this bed second, to avoid other mobs getting pixel-shifted before he unbuckles.
+ var/mob/living/goldilocks
+
+/obj/structure/bed/double/post_buckle_mob(mob/living/target)
+ if(buckled_mobs.len > 1 && !goldilocks) // Push the second buckled mob a bit higher from the normal lying position
+ target.pixel_y = target.pixel_y + 12
+ goldilocks = target
+
+/obj/structure/bed/double/post_unbuckle_mob(mob/living/target)
+ target.pixel_y = target.pixel_y + target.get_standard_pixel_y_offset()
+ if(target == goldilocks)
+ goldilocks = null
diff --git a/modular_ss220/objects/code/billboard.dm b/modular_ss220/objects/code/billboard.dm
new file mode 100644
index 000000000000..27936d34a08f
--- /dev/null
+++ b/modular_ss220/objects/code/billboard.dm
@@ -0,0 +1,106 @@
+/obj/structure/billboard
+ name = "\improper Пустой билборд"
+ desc = "Пустой рекламный щит, на котором есть место для любой рекламы."
+ icon = 'modular_ss220/objects/icons/billboard.dmi'
+ icon_state = "billboard_blank"
+ layer = ABOVE_ALL_MOB_LAYER
+ max_integrity = 1000
+ bound_width = 96
+ bound_height = 32
+ density = TRUE
+ anchored = TRUE
+
+/obj/structure/billboard/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/largetransparency, 0, 1, 2, 0)
+
+/obj/structure/billboard/donk_n_go
+ name = "\improper Билборд Donk-n-Go"
+ desc = "Рекламный щит, рекламирующий Donk-n-Go, вечно актуальное и вечно нездоровое предприятие быстрого питания Donk Co: ЗАШЕЛ, НАЕЛСЯ, УШЕЛ!"
+ icon_state = "billboard_donk_n_go"
+
+/obj/structure/billboard/space_cola
+ name = "\improper Билборд Space Cola"
+ desc = "Рекламный щит с рекламой Space Cola: Расслабьтесь, выпейте колы."
+ icon_state = "billboard_space_cola"
+
+/obj/structure/billboard/nanotrasen
+ name = "\improper Билборд Nanotrasen"
+ desc = "Рекламный щит с рекламой Nanotrasen. Лучшее завтра - сегодня."
+ icon_state = "billboard_nanotrasen"
+
+/obj/structure/billboard/nanotrasen/defaced
+ name = "\improper Обезображенный билборд Nanotrasen"
+ desc = "Рекламный щит, рекламирующий Nanotrasen. Кто-то намалевал на нем сообщение: Нахуй Корпоратских Свиней."
+ icon_state = "billboard_fuck_corps"
+
+/obj/structure/billboard/azik
+ name = "\improper Билборд Azik Interstellar"
+ desc = "Рекламный щит, рекламирующий компанию Azik Interstellar и ее новейшую модель - солнечный парусник Autocrat. Azik Interstellar: Тизирийские технологии для галактических нужд."
+ icon_state = "billboard_azik"
+
+/obj/structure/billboard/cvr
+ name = "\improper Билборд Charlemagne von Rheinland"
+ desc = "Рекламный щит, рекламирующий супер-яхту класса Germania компании Charlemagne von Rheinland. Карл Великий из Рейнланда: верфь королей."
+ icon_state = "billboard_cvr"
+
+/obj/structure/billboard/twenty_four_seven
+ name = "\improper Билборд 24-Seven"
+ desc = "Рекламный щит, рекламирующий новую линейку лимитированных вкусов Slushee от 24-Seven. 24-Seven: Весь день, каждый день."
+ icon_state = "billboard_twenty_four_seven"
+
+/obj/structure/billboard/starway
+ name = "\improper Билборд Starway Transit"
+ desc = "Рекламный щит, рекламирующий прямой рейс Starway Transit из Новой Москвы в Нью-Йорк: всего 2000 кредитов за место в эконом-классе. Starway: Ваш билет к звездам."
+ icon_state = "billboard_starway"
+
+/obj/structure/billboard/lizards_gas
+ name = "\improper Билборд The Lizard's Gas"
+ desc = "Рекламный щит с надписью о заправке, известной как 'The Lizard's Gas'. Она была утрачена со временем, и это единственная известная заправка такого типа. По качеству рекламного щита трудно понять, почему она провалилась."
+ icon_state = "billboard_lizards_gas"
+
+/obj/structure/billboard/lizards_gas/defaced
+ desc = "Рекламный щит с надписью о заправке, известной как 'The Lizard's Gas'. Душевно нарисованный рекламный щит был измазан граффити, и добрый незнакомец закрасил его."
+ icon_state = "billboard_lizards_gas_defaced"
+
+/obj/structure/billboard/roadsign
+ name = "\improper Билборд Roadsign"
+ desc = "Рекламный щит, уведомляющий читателя о том, сколько километров осталось до заправки. Однако этот щит, похоже, пустой."
+ icon_state = "billboard_roadsign_blank"
+
+/obj/structure/billboard/roadsign/two
+ desc = "Рекламный щит, информирующий читателя о том, сколько километров осталось до следующей заправки. Трудно понять, для чего вообще нужен этот знак."
+ icon_state = "billboard_roadsign_two"
+
+/obj/structure/billboard/roadsign/twothousand
+ desc = "Рекламный щит, информирующий читателя о том, сколько километров осталось до следующей заправки. Увидев такое, вы наверняка захотите запастись едой и бензином."
+ icon_state = "billboard_roadsign_twothousand"
+
+/obj/structure/billboard/roadsign/twomillion
+ desc = "Рекламный щит, информирующий читателя о том, сколько километров осталось до следующей заправки. Если вы способны преодолевать многомиллионные расстояния, это не должно вызвать у вас затруднений! Если же нет..."
+ icon_state = "billboard_roadsign_twomillion"
+
+/obj/structure/billboard/roadsign/error
+ desc = "Рекламный щит, информирующий читателя о том, сколько километров осталось до следующей заправки. Это статичная надпись, так что остается только гадать, какой человек мог бы ее напечатать и повесить."
+ icon_state = "billboard_roadsign_error"
+
+/obj/structure/billboard/smoothies
+ name = "\improper Билборд Spinward Smoothies"
+ desc = "Рекламный щит с рекламой Spinward Smoothies."
+ icon_state = "billboard_smoothies"
+
+/obj/structure/billboard/fortune_telling
+ name = "\improper Билборд Fortune Teller"
+ desc = "Рекламный щит с рекламой гаданий. Оказывается, это делают настоящие экстрасенсы!"
+ icon_state = "billboard_fortune_tell"
+
+/obj/structure/billboard/phone_booth
+ name = "\improper Билборд Holophone"
+ desc = "Рекламный щит, рекламирующий голофоны. Межзвездные вызовы по доступной цене 49,99 кредитов с беспошлинными закусками!"
+ icon_state = "billboard_phone"
+
+/obj/structure/billboard/american_diner
+ name = "\improper Билборд All-American Diner"
+ desc = "Рекламный щит, рекламирующий франшизу ресторана старой школы 1950-х годов \"All-American Diner\"."
+ icon_state = "billboard_american_diner"
+
diff --git a/modular_ss220/objects/code/closets.dm b/modular_ss220/objects/code/closets.dm
new file mode 100644
index 000000000000..0069d62ffd2e
--- /dev/null
+++ b/modular_ss220/objects/code/closets.dm
@@ -0,0 +1,48 @@
+/obj/structure/closet/secure_closet/expedition
+ name = "expeditors locker"
+ icon = 'modular_ss220/objects/icons/closets.dmi'
+ icon_state = "explorer"
+ req_access = list(ACCESS_EXPEDITION)
+
+/obj/structure/closet/secure_closet/expedition/populate_contents()
+ new /obj/item/gun/energy/laser/awaymission_aeg/rnd(src)
+ new /obj/item/storage/firstaid/regular(src)
+ new /obj/item/paper/pamphlet/gateway(src)
+
+/obj/structure/closet/secure_closet/geneticist
+ name = "geneticist's locker"
+ icon = 'modular_ss220/objects/icons/closets.dmi'
+ icon_state = "gen"
+ req_access = list(ACCESS_GENETICS)
+
+/obj/structure/closet/secure_closet/geneticist/populate_contents()
+ new /obj/item/storage/backpack/genetics(src)
+ new /obj/item/storage/backpack/satchel_gen(src)
+ new /obj/item/clothing/under/rank/rnd/geneticist(src)
+ new /obj/item/clothing/under/rank/rnd/geneticist/skirt(src)
+ new /obj/item/clothing/suit/storage/labcoat/genetics(src)
+ new /obj/item/clothing/shoes/white(src)
+ new /obj/item/clothing/shoes/sandal/white(src)
+ new /obj/item/radio/headset/headset_medsci(src)
+ new /obj/item/radio/headset/headset_medsci(src)
+ new /obj/item/storage/box/disks(src)
+ new /obj/item/storage/box/syringes(src)
+
+/obj/structure/closet/crate/freezer/iv_storage/organ
+ name = "organ freezer"
+ desc = "Холодильник для хранения органов и пакетов с кровью."
+ icon = 'modular_ss220/objects/icons/closets.dmi'
+ icon_state = "organ_freezer"
+ icon_opened = "organ_freezer_open"
+ icon_closed = "organ_freezer"
+ storage_capacity = 60
+
+/obj/structure/closet/secure_closet/freezer/products
+ name = "refrigerator"
+ icon_state = "freezer"
+
+/obj/structure/closet/secure_closet/freezer/products/populate_contents()
+ new /obj/item/storage/box/donkpockets(src)
+ new /obj/item/storage/box/donkpockets(src)
+ new /obj/item/storage/fancy/egg_box(src)
+ new /obj/item/storage/fancy/egg_box(src)
diff --git a/modular_ss220/objects/code/coffin.dm b/modular_ss220/objects/code/coffin.dm
new file mode 100644
index 000000000000..7d28cd19ed78
--- /dev/null
+++ b/modular_ss220/objects/code/coffin.dm
@@ -0,0 +1,23 @@
+/obj/structure/closet/coffin/corn
+ name = "cornffin"
+ desc = "Мы потеряли его. Он скукурузился."
+ icon = 'modular_ss220/objects/icons/closets.dmi'
+ icon_state = "coffin_corn"
+ resistance_flags = FLAMMABLE
+ max_integrity = 300
+ material_drop = /obj/item/food/grown/corn
+ material_drop_amount = 10
+
+// Выращивание кукурузогроба
+/obj/item/seeds/corn/cornffin
+ name = "pack of cornffin seeds"
+ desc = "Эти семена вырастут и скукурузятся.."
+ icon_state = "seed-corn"
+ species = "corn"
+ plantname = "Cornffin Stalks"
+ product = /obj/structure/closet/coffin/corn
+
+
+/obj/item/seeds/corn/Initialize(mapload)
+ . = ..()
+ mutatelist |= list(/obj/item/seeds/corn/cornffin)
diff --git a/modular_ss220/objects/code/components.dm b/modular_ss220/objects/code/components.dm
new file mode 100644
index 000000000000..5fad71d49fa3
--- /dev/null
+++ b/modular_ss220/objects/code/components.dm
@@ -0,0 +1,34 @@
+/datum/component/ckey_and_role_locked_pickup
+ var/pickup_damage
+ var/force = 20
+ var/list/ckeys = list()
+ var/offstation_role
+ var/refusal_text
+
+/datum/component/ckey_and_role_locked_pickup/Initialize(offstation_role = TRUE, ckey_whitelist, pickup_damage = 0, refusal_text)
+ src.offstation_role = offstation_role
+ src.ckeys = ckey_whitelist
+ src.pickup_damage = pickup_damage
+ src.refusal_text = refusal_text
+
+/datum/component/ckey_and_role_locked_pickup/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_ITEM_PICKUP, PROC_REF(try_pick_up))
+
+/datum/component/ckey_and_role_locked_pickup/UnregisterFromParent()
+ UnregisterSignal(parent, COMSIG_ITEM_PICKUP)
+
+/datum/component/ckey_and_role_locked_pickup/proc/try_pick_up(obj/item/I, mob/living/user)
+
+ if(check_role_and_ckey(user))
+ return
+ user.Weaken(10 SECONDS)
+ user.unEquip(I, force, silent = FALSE)
+ to_chat(user, span_userdanger(refusal_text))
+ if(ishuman(user))
+ user.apply_damage(rand(pickup_damage, pickup_damage * 2), BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
+
+/datum/component/ckey_and_role_locked_pickup/proc/check_role_and_ckey(mob/user)
+ if(user.client.ckey in ckeys)
+ return TRUE
+
+ return user.mind.offstation_role == offstation_role
diff --git a/modular_ss220/objects/code/computer.dm b/modular_ss220/objects/code/computer.dm
new file mode 100644
index 000000000000..67b07ef9dadc
--- /dev/null
+++ b/modular_ss220/objects/code/computer.dm
@@ -0,0 +1,3 @@
+/obj/machinery/computer/security/telescreen/ce
+ name = "chief engineer's monitor"
+ network = list("Engineering","Singularity","engine")
diff --git a/modular_ss220/objects/code/flag.dm b/modular_ss220/objects/code/flag.dm
new file mode 100644
index 000000000000..1a6439244ec3
--- /dev/null
+++ b/modular_ss220/objects/code/flag.dm
@@ -0,0 +1,15 @@
+/obj/item/flag/soundhand
+ name = "флаг группы Саундхэнд"
+ desc = "Флаг легендарной группы Саундхэнд. Вероятно были созданы исключительно для сжигания и эффекта восхищения от крутости."
+ icon = 'modular_ss220/objects/icons/flag.dmi'
+ icon_state = "flag_group"
+ lefthand_file = 'modular_ss220/objects/icons/inhands/flags_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/flags_righthand.dmi'
+
+/obj/item/flag/vox_raider
+ name = "флаг вокс рейдеров"
+ desc = "Флаг одной из небезызвестных организаций, вершащие кражи и грабежи в космосе для наживы."
+ icon = 'modular_ss220/objects/icons/flag.dmi'
+ icon_state = "flag_vox_raider"
+ lefthand_file = 'modular_ss220/objects/icons/inhands/flags_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/flags_righthand.dmi'
diff --git a/modular_ss220/objects/code/flashlight.dm b/modular_ss220/objects/code/flashlight.dm
new file mode 100644
index 000000000000..1a1b220037ee
--- /dev/null
+++ b/modular_ss220/objects/code/flashlight.dm
@@ -0,0 +1,6 @@
+/obj/item/flashlight/shadowlight
+ icon = 'modular_ss220/objects/icons/lighting.dmi'
+ icon_state = "shadowlight"
+ brightness_on = 3 // A little better than the standard flashlight.
+ light_power = -2
+ hitsound = 'sound/weapons/genhit1.ogg'
diff --git a/modular_ss220/objects/code/flora/sakura.dm b/modular_ss220/objects/code/flora/sakura.dm
new file mode 100644
index 000000000000..c9eb97d78e60
--- /dev/null
+++ b/modular_ss220/objects/code/flora/sakura.dm
@@ -0,0 +1,213 @@
+/// Time before blossom starts
+#define BLOSSOM_START_TIME (30 MINUTES)
+/// Time before blossom ends
+#define BLOSSOM_END_TIME (10 MINUTES)
+/// Time before blossom leaves a pile
+#define LEAVES_PILE_SPAWN_TIME (2 MINUTES)
+/// Time before blossom transforms grass tile to Sakura's grass
+#define TRANSFORM_TURF_TIME (10 MINUTES)
+
+/* Sakura Tree */
+/obj/structure/flora/tree/sakura
+ name = "Sakura"
+ desc = "It's a cherry blossom. Beautiful!"
+ icon = 'modular_ss220/objects/icons/flora/sakura.dmi'
+ icon_state = "cherry_blossom"
+ pixel_y = 10
+ var/obj/effect/blossom/blossom_effect
+ var/timer_handle_start
+ var/timer_handle_end
+
+/obj/structure/flora/tree/sakura/Initialize(mapload)
+ . = ..()
+ RegisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING, PROC_REF(on_round_start))
+
+/obj/structure/flora/tree/sakura/New()
+ . = ..()
+ if(SSticker.IsRoundInProgress())
+ initiate_blossom_cycle()
+
+/obj/structure/flora/tree/sakura/Destroy()
+ if(timer_handle_start && timer_handle_end)
+ deltimer(timer_handle_start)
+ deltimer(timer_handle_end)
+ if(blossom_effect)
+ QDEL_NULL(blossom_effect)
+ timer_handle_start = null
+ timer_handle_end = null
+ return ..()
+
+/obj/structure/flora/tree/sakura/proc/on_round_start()
+ initiate_blossom_cycle()
+ SIGNAL_HANDLER
+ UnregisterSignal(src, COMSIG_TICKER_ROUND_STARTING)
+ return
+
+/// Initiates the blooming cycle, in which the countdown begins
+/obj/structure/flora/tree/sakura/proc/initiate_blossom_cycle()
+ // Start the bloom cycle 30 minutes after the start of the round or creating new tree
+ timer_handle_start = addtimer(CALLBACK(src, PROC_REF(start_blossom)), BLOSSOM_START_TIME, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE)
+
+/// Starts blooming itself as part of the cycle
+/obj/structure/flora/tree/sakura/proc/start_blossom()
+ var/turf/T = get_turf(src)
+ if(!blossom_effect)
+ // Spawns blossom effect
+ blossom_effect = new(T)
+ blossom_effect.parent_tree = src
+ // Start the timer to remove the blossom effect after 10 minutes
+ timer_handle_end = addtimer(CALLBACK(src, PROC_REF(end_blossom)), BLOSSOM_END_TIME, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE)
+
+/// Ends blooming, starts timer for a new one
+/obj/structure/flora/tree/sakura/proc/end_blossom()
+ if(blossom_effect)
+ // Deletes blossom effect
+ QDEL_NULL(blossom_effect)
+ // Restart cycle
+ initiate_blossom_cycle()
+
+/* Effects */
+/obj/effect/blossom
+ name = "blossom"
+ desc = "It's sakura fubuki."
+ icon = 'modular_ss220/objects/icons/flora/sakura.dmi'
+ icon_state = "blossom_less"
+ layer = 12
+ pixel_x = -16
+ pixel_y = 10
+ var/obj/structure/flora/tree/sakura/parent_tree
+
+/obj/effect/blossom/Initialize(mapload)
+ . = ..()
+ // Start the timer to spawn a pile of Sakura leaves after 2 minutes
+ addtimer(CALLBACK(src, PROC_REF(make_sakura_leaves)), LEAVES_PILE_SPAWN_TIME, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE)
+
+/obj/effect/blossom/New(turf, obj/structure/flora/tree/sakura/Sakura)
+ ..()
+ if(Sakura && istype(Sakura))
+ parent_tree = Sakura
+
+/obj/effect/blossom/Destroy()
+ if(isnull(parent_tree))
+ qdel(src)
+ return ..()
+
+/// Spawns pile of sakura leaves under sakura tree
+/obj/effect/blossom/proc/make_sakura_leaves()
+ var/turf/T = get_turf(src)
+ if(locate(/obj/effect/decal/sakura_leaves, T))
+ return
+ if(istype(T, /turf/simulated/floor/grass/sakura))
+ return
+ if(!parent_tree)
+ return
+ new /obj/effect/decal/sakura_leaves(T, src)
+ // Start the timer to replace grass tile with sakura's one after 10 minutes
+ addtimer(CALLBACK(src, PROC_REF(transform_turf)), TRANSFORM_TURF_TIME, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE)
+
+/// Transforms grass tile to sakura grass under blossom effect
+/obj/effect/blossom/proc/transform_turf()
+ var/turf/T = get_turf(src)
+ if(istype(T, /turf/simulated/floor/grass/sakura))
+ return
+ if(!istype(T, /turf/simulated/floor/grass))
+ return
+ T.ChangeTurf(/turf/simulated/floor/grass/sakura)
+ // Deletes pile of Sakura leaves
+ for(var/obj/effect/decal/sakura_leaves/D in T)
+ qdel(D)
+
+/// Sakura Leaves
+/obj/effect/decal/sakura_leaves
+ name = "pile of sakura leaves"
+ desc = "It's fallen sakura leaves."
+ icon = 'modular_ss220/objects/icons/flora/sakura.dmi'
+ icon_state = "leaves"
+ pixel_y = 5
+ max_integrity = 50
+ resistance_flags = FLAMMABLE
+ layer = 11
+ plane = -1
+ no_scoop = TRUE
+ no_clear = TRUE
+ // Is leaves on fire?
+ var/on_fire = FALSE
+
+/obj/effect/decal/sakura_leaves/New()
+ . = ..()
+ update_icon(UPDATE_ICON_STATE)
+
+/obj/effect/decal/sakura_leaves/examine(mob/user)
+ . = ..()
+ if(on_fire)
+ . += span_danger("[src] is on fire!")
+
+/obj/effect/decal/sakura_leaves/update_icon_state()
+ . = ..()
+ var/turf/T = get_turf(src)
+ for(var/obj/structure/flora/tree/sakura/sakura in T)
+ if(sakura.icon_state == "cherry_blossom")
+ pixel_x = -2
+ dir = WEST
+ if(sakura.icon_state == "cherry_blossom2")
+ pixel_x = 5
+ dir = EAST
+ if(sakura.icon_state == "cherry_blossom3")
+ pixel_x = -7
+
+/obj/effect/decal/sakura_leaves/attackby__legacy__attackchain(obj/item/I, mob/user)
+ if(I.get_heat() && !on_fire)
+ visible_message(span_danger("[src] bursts into flames!"))
+ fire_act()
+ if(istype(I, /obj/item/cultivator))
+ var/obj/item/cultivator/C = I
+ user.visible_message(
+ span_notice("[user] is clearing [src] from the ground..."),
+ span_notice("You begin clearing [src] from the ground..."),
+ span_warning("You hear a sound of leaves rustling."))
+ playsound(loc, 'sound/effects/shovel_dig.ogg', 50, 1)
+ if(!do_after(user, 50 * C.toolspeed, target = src))
+ return
+ user.visible_message(
+ span_notice("[user] clears [src] from the ground!"),
+ span_notice("You clear [src] from the ground!"))
+ qdel(src)
+ else
+ return ..()
+
+// This is fake fire actually
+/obj/effect/decal/sakura_leaves/fire_act()
+ if(resistance_flags & FLAMMABLE)
+ on_fire = TRUE
+ add_overlay(custom_fire_overlay ? custom_fire_overlay : GLOB.fire_overlay)
+ addtimer(CALLBACK(src, PROC_REF(delete_decal)), 5 SECONDS)
+
+/obj/effect/decal/sakura_leaves/proc/delete_decal()
+ cut_overlays()
+ qdel(src)
+
+/* Sakura Floor */
+/// Sakura grass
+/turf/simulated/floor/grass/sakura
+ name = "sakura grass"
+ icon = 'modular_ss220/objects/icons/flora/sakura_grass.dmi'
+ icon_state = "grass"
+ base_icon_state = "grass"
+ smoothing_groups = list(SMOOTH_GROUP_TURF, SMOOTH_GROUP_GRASS, SMOOTH_GROUP_JUNGLE_GRASS)
+
+/turf/simulated/floor/grass/sakura/no_creep
+ smoothing_flags = null
+ smoothing_groups = null
+ canSmoothWith = null
+ layer = GRASS_UNDER_LAYER
+ transform = null
+
+/turf/simulated/floor/grass/sakura/update_icon_state()
+ . = ..()
+ if(broken || burnt)
+ icon_state = "damaged"
+
+#undef BLOSSOM_START_TIME
+#undef BLOSSOM_END_TIME
+#undef LEAVES_PILE_SPAWN_TIME
+#undef TRANSFORM_TURF_TIME
diff --git a/modular_ss220/objects/code/id_skins/_id_skins_base.dm b/modular_ss220/objects/code/id_skins/_id_skins_base.dm
new file mode 100644
index 000000000000..d469646b56ab
--- /dev/null
+++ b/modular_ss220/objects/code/id_skins/_id_skins_base.dm
@@ -0,0 +1,140 @@
+/obj/item/card/id
+ var/skinable = TRUE
+ var/obj/item/id_skin/skin_applied = null
+
+/obj/item/card/id/guest
+ skinable = FALSE
+
+/obj/item/card/id/data
+ skinable = FALSE
+
+/obj/item/card/id/away
+ skinable = FALSE
+
+/obj/item/card/id/thunderdome
+ skinable = FALSE
+
+/obj/item/card/id/attackby__legacy__attackchain(obj/item/item, mob/user, params)
+ . = ..()
+ if(!istype(item, /obj/item/id_skin))
+ return .
+
+ return apply_skin(item, user)
+
+/obj/item/card/id/examine(mob/user)
+ . = ..()
+ if(skin_applied)
+ . += span_notice("Нажмите Alt-Click на карту, чтобы снять наклейку.")
+
+/obj/item/card/id/AltClick(mob/living/carbon/user)
+ if(!iscarbon(user))
+ return
+
+ if(!Adjacent(user) || user.incapacitated())
+ to_chat(user, span_warning("У вас нет возможности снять наклейку!"))
+ return
+
+ if(!skin_applied)
+ to_chat(user, span_warning("На карте нет наклейки!"))
+ return
+
+ if(user.a_intent == INTENT_HARM)
+ to_chat(user, span_warning("Вы срываете наклейку с карты!"))
+ playsound(user.loc, 'sound/items/poster_ripped.ogg', 50, TRUE)
+ remove_skin(delete = TRUE)
+ else
+ to_chat(user, span_notice("Вы начинаете аккуратно снимать наклейку с карты."))
+ if(!do_after(user, 5 SECONDS, target = src, progress = TRUE))
+ return FALSE
+
+ to_chat(user, span_notice("Вы сняли наклейку с карты."))
+
+ if(!user.get_active_hand() && Adjacent(user))
+ user.put_in_hands(skin_applied)
+ else
+ skin_applied.forceMove(get_turf(user))
+ remove_skin()
+
+/obj/item/card/id/proc/apply_skin(obj/item/id_skin/skin, mob/user)
+ if(skin_applied)
+ to_chat(usr, span_warning("На карте уже есть наклейка, сначала соскребите её!"))
+ return FALSE
+
+ if(!skinable)
+ to_chat(usr, span_warning("Наклейка не подходит для [src]!"))
+ return FALSE
+
+ to_chat(user, span_notice("Вы начинаете наносить наклейку на карту."))
+ if(!do_after(user, 2 SECONDS, target = src, progress = TRUE, allow_moving = TRUE))
+ return FALSE
+
+ var/mutable_appearance/card_skin = mutable_appearance(skin.icon, skin.icon_state)
+ card_skin.color = skin.color
+ to_chat(user, span_notice("Вы наклеили [skin.pronoun_name] на [src]."))
+ desc += " [skin.info]"
+ user.drop_item()
+ skin.forceMove(src)
+ skin_applied = skin
+ add_overlay(card_skin)
+ return TRUE
+
+/obj/item/card/id/proc/remove_skin(delete = FALSE)
+ if(delete)
+ qdel(skin_applied)
+ skin_applied = null
+ desc = initial(desc)
+ overlays.Cut()
+
+/obj/item/id_skin
+ name = "\improper наклейка на карту"
+ desc = "Этим можно изменить внешний вид своей карты! Покажи службе безопасности какой ты стильный."
+ icon = 'modular_ss220/objects/icons/id_skins.dmi'
+ icon_state = ""
+ var/pronoun_name = "наклейку"
+ var/info = "На ней наклейка."
+
+/obj/item/id_skin/Initialize(mapload)
+ . = ..()
+ pixel_y = rand(-5, 5)
+ pixel_x = rand(-5, 5)
+
+/obj/item/id_skin/colored
+ name = "\improper голо-наклейка на карту"
+ desc = "Голографическая наклейка на карту. Вы можете выбрать цвет который она примет."
+ icon_state = "colored"
+ pronoun_name = "голо-наклейку"
+ info = "На ней голо-наклейка."
+ var/static/list/color_list = list(
+ "Красный" = LIGHT_COLOR_RED,
+ "Зелёный" = LIGHT_COLOR_GREEN,
+ "Синий" = LIGHT_COLOR_LIGHTBLUE,
+ "Жёлтый" = LIGHT_COLOR_HOLY_MAGIC,
+ "Оранжевый" = LIGHT_COLOR_ORANGE,
+ "Фиолетовый" = LIGHT_COLOR_LAVENDER,
+ "Голубой" = LIGHT_COLOR_LIGHT_CYAN,
+ "Циановый" = LIGHT_COLOR_CYAN,
+ "Аквамариновый" = LIGHT_COLOR_BLUEGREEN,
+ "Розовый" = LIGHT_COLOR_PINK)
+
+/obj/item/id_skin/colored/Initialize(mapload)
+ . = ..()
+ if(color)
+ return .
+
+ color = color_list[pick(color_list)]
+
+/obj/item/id_skin/colored/attack_self__legacy__attackchain(mob/living)
+ var/choice = tgui_input_list(usr, "Какой цвет предпочитаете?", "Выбор цвета", list("Выбрать предустановленный", "Выбрать вручную"))
+ if(!choice)
+ return
+ switch(choice)
+ if("Выбрать предустановленный")
+ choice = tgui_input_list(usr, "Выберите цвет", "Выбор цвета", color_list)
+ var/color_to_set = color_list[choice]
+ if(!color_to_set)
+ return
+
+ color = color_to_set
+
+ if("Выбрать вручную")
+ color = input(usr,"Выберите цвет") as color
diff --git a/modular_ss220/objects/code/id_skins/id_skins.dm b/modular_ss220/objects/code/id_skins/id_skins.dm
new file mode 100644
index 000000000000..9a73a884791b
--- /dev/null
+++ b/modular_ss220/objects/code/id_skins/id_skins.dm
@@ -0,0 +1,156 @@
+/obj/item/id_skin/donut
+ name = "\improper пончиковая наклейка на карту"
+ icon_state = "donut"
+ pronoun_name = "пончиковую наклейку"
+ info = "На ней пончиковая наклейка. С глазурью!"
+
+/obj/item/id_skin/silver
+ name = "\improper серебрянная наклейка на карту"
+ icon_state = "silver"
+ pronoun_name = "серебрянную наклейку"
+ info = "На ней серебрянная наклейка."
+
+/obj/item/id_skin/colored/silver
+ name = "\improper серебрянная голо-наклейка"
+ desc = "Голографическая наклейка на карту, изготовленная из специального материала, похожего на серебро. Вы можете выбрать цвет который она примет."
+ pronoun_name = "серебрянную голо-наклейку"
+ icon_state = "colored_shiny"
+ info = "На ней металлическая голо-наклейка."
+
+/obj/item/id_skin/gold
+ name = "\improper золотая наклейка на карту"
+ desc = "Можно продать какому-то дураку за баснословные деньги. Ой..."
+ icon_state = "gold"
+ pronoun_name = "золотую наклейку"
+ info = "На ней золотая наклейка."
+
+/obj/item/id_skin/business
+ name = "\improper бизнесменская наклейка на карту"
+ desc = "Осталось раздобыть портмоне и стильный костюм."
+ icon_state = "business"
+ pronoun_name = "бизнесменскую наклейку"
+ info = "На ней бизнесменская наклейка."
+
+/obj/item/id_skin/lifetime
+ name = "\improper стильная наклейка на карту"
+ desc = "Ничего особенного, но что-то в этом есть..."
+ icon_state = "lifetime"
+ pronoun_name = "стильную наклейку"
+ info = "На ней стильная наклейка."
+
+/obj/item/id_skin/ussp
+ name = "\improper коммунистическая наклейка на карту"
+ desc = "Партия гордится вами! Возьмите своя миска-рис в ближайшем баре."
+ icon_state = "ussp"
+ pronoun_name = "коммунистическую наклейку"
+ info = "На ней коммунистическая наклейка."
+
+/obj/item/id_skin/clown
+ name = "\improper клоунская наклейка на карту"
+ desc = "HONK!"
+ icon_state = "clown"
+ pronoun_name = "клоунскую наклейку"
+ info = "На ней клоунская наклейка. HONK!"
+
+/obj/item/id_skin/neon
+ name = "\improper неоновая наклейка на карту"
+ desc = "Неоновая наклейка в цианово-розовых цветах."
+ icon_state = "neon"
+ pronoun_name = "неоновую наклейку"
+ info = "Кажется будто она светится."
+
+/obj/item/id_skin/colored/neon
+ name = "\improper неоновая голо-наклейка на карту"
+ desc = "Какая же она яркая... Ещё и цвета меняет!"
+ icon_state = "colored_neon"
+ pronoun_name = "неоновую наклейку"
+ info = "Кажется будто она светится."
+
+/obj/item/id_skin/missing
+ name = "\improper чёрно-розовая наклейка на карту"
+ desc = "Текстура пропала..."
+ icon_state = "missing"
+ pronoun_name = "чёрно-розовую наклейку"
+ info = "А где?"
+
+/obj/item/id_skin/ouija
+ name = "\improper Уиджи наклейка на карту"
+ desc = "Ходят легенты, что тот кто наклеит это на карту, может общаться с духами..."
+ icon_state = "ouija"
+ pronoun_name = "наклейку в виде доски Уиджи"
+ info = "Умеет ли он общаться с призраками?"
+
+/obj/item/id_skin/paradise
+ name = "\improper пляжная наклейка на карту"
+ desc = "Хола!"
+ icon_state = "paradise"
+ pronoun_name = "пляжную наклейку"
+ info = "На ней пляжная наклейка."
+
+/obj/item/id_skin/rainbow
+ name = "\improper радужная наклейка на карту"
+ desc = "Переливается всеми цветами радуги!"
+ icon_state = "rainbow"
+ pronoun_name = "радужную наклейку"
+ info = "На ней радужная наклейка. Одобряемо."
+
+/obj/item/id_skin/space
+ name = "\improper КОСМИЧЕСКАЯ наклейка на карту"
+ desc = "Яркая, блестящая и бескрайняя. Прямо как хозяин карты на которую её приклеят."
+ icon_state = "space"
+ pronoun_name = "КОСМИЧЕСКУЮ наклейку"
+ info = "Есть 3 вещи на которые можно смотреть вечно. Это четвёртая."
+
+/obj/item/id_skin/kitty
+ name = "\improper кото-клейка на карту"
+ desc = "Прекрасная наклейка, которая делает вашу карту похожей на котика. UwU."
+ icon_state = "kitty"
+ pronoun_name = "кото-клейку"
+ info = "Так и хочется погладить, жаль это всего-лишь наклейка..."
+
+/obj/item/id_skin/colored/kitty
+ name = "\improper голо-кото-клейка на карту"
+ desc = "Прекрасная наклейка, которая делает вашу карту похожей на котика. Эта может менять цвет."
+ icon_state = "colored_kitty"
+
+/obj/item/id_skin/cursedmiku
+ name = "\improper аниме наклейка на карту"
+ desc = "Kawaii!!!"
+ icon_state = "cursedmiku"
+ pronoun_name = "анимешную наклейку"
+ info = "На ней анимешная наклейка. AYAYA!"
+
+/obj/item/id_skin/colored/snake
+ name = "\improper бегущая наклейка на карту"
+ desc = "Она что-то загружает?"
+ icon_state = "snake"
+ pronoun_name = "бегущую наклейку"
+ info = "Бегает и бегает..."
+
+/obj/item/id_skin/magic
+ name = "\improper магическая наклейка на карту"
+ desc = "EI NATH!"
+ icon_state = "magic"
+ pronoun_name = "магическую наклейку"
+ info = "Кто-то до сих пор девственник..."
+
+/obj/item/id_skin/terminal
+ name = "\improper наклейка на карту в виде терминала"
+ desc = "HACKERMAN."
+ icon_state = "terminal"
+ pronoun_name = "наклейку в виде терминала"
+ info = "Эта карта похожа на терминал."
+
+/obj/item/id_skin/jokerge
+ name = "\improper джокерге наклейка на карту"
+ desc = "Jokerge."
+ icon_state = "jokerge"
+ pronoun_name = "наклейку в виде Джокерге"
+ info = "Jokerge."
+
+/obj/item/id_skin/boykisser
+ name = "\improper бойкиссерская наклейка на карту"
+ desc = "Наклеив её на карту, у вас с почти 100% вероятностью, появится желание целовать мальчиков."
+ icon_state = "boykisser"
+ pronoun_name = "наклейку в виде бойкиссера"
+ info = "Он любит целовать мальчиков."
diff --git a/modular_ss220/objects/code/id_skins/id_skins_spawners.dm b/modular_ss220/objects/code/id_skins/id_skins_spawners.dm
new file mode 100644
index 000000000000..f90a5aea5dad
--- /dev/null
+++ b/modular_ss220/objects/code/id_skins/id_skins_spawners.dm
@@ -0,0 +1,66 @@
+// Supply Crate
+/datum/supply_packs/misc/randomised/id_skins
+ name = "Наклейки на карточку"
+ containertype = /obj/structure/closet/crate/plastic
+ num_contained = 10
+ contains = list()
+ cost = 2000
+ containername = "ящик с наклейками"
+
+/datum/supply_packs/misc/randomised/id_skins/New()
+ for(var/i in 1 to 10)
+ contains += pick(subtypesof(/obj/item/id_skin))
+ . = ..()
+
+// Spawner
+/obj/effect/spawner/random/id_skins
+ name = "Случайная наклейка на карту"
+ icon = 'modular_ss220/maps220/icons/spawner_icons.dmi'
+ icon_state = "ID_Random"
+ loot = list(
+ /obj/item/id_skin/colored = 10,
+ /obj/item/id_skin/donut = 5,
+ /obj/item/id_skin/business = 5,
+ /obj/item/id_skin/ussp = 5,
+ /obj/item/id_skin/colored/silver = 5,
+ /obj/item/id_skin/silver = 5,
+ /obj/item/id_skin/gold = 1,
+ /obj/item/id_skin/lifetime = 1,
+ /obj/item/id_skin/clown = 1,
+ /obj/item/id_skin/neon = 1,
+ /obj/item/id_skin/colored/neon = 1,
+ /obj/item/id_skin/missing = 1,
+ /obj/item/id_skin/ouija = 1,
+ /obj/item/id_skin/paradise = 1,
+ /obj/item/id_skin/rainbow = 1,
+ /obj/item/id_skin/space = 1,
+ /obj/item/id_skin/kitty = 1,
+ /obj/item/id_skin/colored/kitty = 1,
+ /obj/item/id_skin/cursedmiku = 1,
+ /obj/item/id_skin/colored/snake = 1,
+ /obj/item/id_skin/magic = 1,
+ /obj/item/id_skin/terminal = 1,
+ /obj/item/id_skin/jokerge = 1,
+ /obj/item/id_skin/boykisser = 1
+ )
+
+/obj/effect/spawner/random/id_skins/no_chance
+ spawn_loot_chance = 40
+
+// Prize Counter
+/datum/prize_item/id_skin
+ name = "Наклейки на карту"
+ desc = "Коробочка с тремя многоразовыми наклейками на ID карту."
+ typepath = /obj/item/storage/box/id_skins
+ cost = 200
+
+/obj/item/storage/box/id_skins
+ name = "наклейки на карту"
+ desc = "Коробка с кучкой наклеек на ID карту."
+ icon = 'modular_ss220/objects/icons/id_skins.dmi'
+ icon_state = "id_skins_box"
+
+/obj/item/storage/box/id_skins/populate_contents()
+ for(var/I in 1 to 3)
+ var/skin = pick(subtypesof(/obj/item/id_skin))
+ new skin(src)
diff --git a/modular_ss220/objects/code/key.dm b/modular_ss220/objects/code/key.dm
new file mode 100644
index 000000000000..16637d80d6ed
--- /dev/null
+++ b/modular_ss220/objects/code/key.dm
@@ -0,0 +1,109 @@
+
+/obj/item/door_remote/key
+ desc = "Обычный немного ржавый ключ."
+ icon = 'modular_ss220/objects/icons/key.dmi'
+ icon_state = "key"
+ /// Are you already using the key?
+ var/busy = FALSE
+ /// How fast does the key open an airlock.
+ var/hack_speed = 1 SECONDS
+
+/obj/item/door_remote/key/attack_self__legacy__attackchain(mob/user)
+ return
+
+/obj/item/door_remote/key/afterattack__legacy__attackchain(obj/machinery/door/airlock/attacked_airlock, mob/user, proximity)
+ if(!proximity)
+ return
+
+ if(!istype(attacked_airlock))
+ return
+
+ if(HAS_TRAIT(attacked_airlock, TRAIT_CMAGGED))
+ to_chat(user, span_danger("[src] не вставляется в панель доступа [attacked_airlock], тут повсюду слизь!"))
+ return
+
+ if(attacked_airlock.is_special)
+ to_chat(user, span_danger("[src] не помещается в панель доступа [attacked_airlock]!"))
+ return
+
+ if(!attacked_airlock.arePowerSystemsOn())
+ to_chat(user, span_danger("[attacked_airlock] без питания!"))
+ return
+
+ if(busy)
+ to_chat(user, span_warning("Ты уже используешь [src] на панели доступа [attacked_airlock]!"))
+ return
+
+ playsound(src, 'sound/items/keyring_unlock.ogg', 50)
+ attacked_airlock.add_fingerprint(user)
+
+ busy = TRUE
+ if(!do_after(user, hack_speed, target = attacked_airlock, progress = 1))
+ busy = FALSE
+ return
+ busy = FALSE
+
+ if(!attacked_airlock.check_access(ID))
+ to_chat(user, span_danger("[src] похоже не подходит к панели доступа [attacked_airlock]!"))
+ return
+
+ if(!attacked_airlock.density)
+ attacked_airlock.close()
+ return
+ attacked_airlock.open()
+
+/obj/item/door_remote/key/engineer
+ name = "\proper ключ от инженерного отдела"
+ icon_state = "eng"
+ additional_access = list(ACCESS_ENGINE,ACCESS_CONSTRUCTION)
+
+/obj/item/door_remote/key/medical
+ name = "\proper ключ от медицинского отдела"
+ icon_state = "med"
+ additional_access = list(ACCESS_MEDICAL)
+
+/obj/item/door_remote/key/supply
+ name = "\proper ключ от отдела снабжения"
+ icon_state = "supply"
+ additional_access = list(ACCESS_CARGO, ACCESS_MINING)
+
+/obj/item/door_remote/key/rnd
+ name = "\proper ключ от отдела исследований"
+ icon_state = "rnd"
+ additional_access = list(ACCESS_RESEARCH)
+
+/obj/item/door_remote/key/sec
+ name = "\proper ключ от отдела службы безопасности"
+ icon_state = "sec"
+ additional_access = list(ACCESS_SEC_DOORS)
+
+/obj/item/door_remote/key/service
+ name = "\proper ключ от отдела сервиса"
+ icon_state = "service"
+ additional_access = list(ACCESS_KITCHEN, ACCESS_BAR, ACCESS_HYDROPONICS, ACCESS_JANITOR)
+
+/obj/item/door_remote/key/command
+ name = "\proper ключ командования"
+ icon_state = "com"
+ additional_access = list(ACCESS_HEADS)
+
+/obj/item/storage/box/keys
+ name = "коробка с ключами"
+ desc = "Коробка с ключами к отделам. Имеют неполный доступ к шлюзам."
+
+/obj/item/storage/box/keys/populate_contents()
+ new /obj/item/door_remote/key/sec(src)
+ new /obj/item/door_remote/key/sec(src)
+ new /obj/item/door_remote/key/supply(src)
+ new /obj/item/door_remote/key/supply(src)
+ new /obj/item/door_remote/key/service(src)
+ new /obj/item/door_remote/key/service(src)
+ new /obj/item/door_remote/key/engineer(src)
+ new /obj/item/door_remote/key/engineer(src)
+ new /obj/item/door_remote/key/rnd(src)
+ new /obj/item/door_remote/key/rnd(src)
+ new /obj/item/door_remote/key/command(src)
+ new /obj/item/door_remote/key/command(src)
+ new /obj/item/door_remote/key/medical(src)
+ new /obj/item/door_remote/key/medical(src)
+
diff --git a/modular_ss220/objects/code/material_pouch.dm b/modular_ss220/objects/code/material_pouch.dm
new file mode 100644
index 000000000000..4fa2cf70d904
--- /dev/null
+++ b/modular_ss220/objects/code/material_pouch.dm
@@ -0,0 +1,34 @@
+/obj/item/storage/bag/material_pouch
+ name = "material pouch"
+ desc = "Сумка для хранения листов материалов."
+ icon = 'modular_ss220/objects/icons/material_pouch.dmi'
+ icon_state = "materialpouch"
+ storage_slots = 5
+ max_combined_w_class = 250
+ w_class = WEIGHT_CLASS_BULKY
+ can_hold = list(
+ /obj/item/stack/sheet,
+ /obj/item/stack/rods,
+ )
+ cant_hold = list(
+ /obj/item/stack/sheet/mineral/sandbags,
+ /obj/item/stack/sheet/mineral/snow,
+ /obj/item/stack/sheet/animalhide,
+ /obj/item/stack/sheet/xenochitin,
+ /obj/item/stack/sheet/hairlesshide,
+ /obj/item/stack/sheet/wetleather,
+ /obj/item/stack/sheet/leather,
+ /obj/item/stack/sheet/sinew,
+ /obj/item/stack/sheet/cloth,
+ /obj/item/stack/sheet/durathread,
+ /obj/item/stack/sheet/cotton,
+ /obj/item/stack/sheet/cotton/durathread,
+ /obj/item/stack/sheet/bone,
+ /obj/item/stack/sheet/soil,
+ /obj/item/stack/sheet/cardboard,
+ /obj/item/stack/sheet/cheese,
+ )
+ resistance_flags = FLAMMABLE
+ max_w_class = WEIGHT_CLASS_NORMAL
+ slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BOTH_POCKETS
+
diff --git a/modular_ss220/objects/code/mattress.dm b/modular_ss220/objects/code/mattress.dm
new file mode 100644
index 000000000000..fd39614d7388
--- /dev/null
+++ b/modular_ss220/objects/code/mattress.dm
@@ -0,0 +1,13 @@
+/obj/structure/bed/mattress
+ name = "матрас"
+ icon = 'modular_ss220/objects/icons/mattress.dmi'
+ icon_state = "mattress"
+ desc = "Голый матрас. Выглядит не очень удобным, но может быть лучше чем лежать на полу."
+ anchored = FALSE
+ comfort = 1
+
+/obj/structure/bed/mattress/dirty
+ name = "грязный матрас"
+ icon_state = "dirty_mattress"
+ desc = "Грязный, вонючий матрас, заляпанный различными жидкостями. Здесь не то что прилечь нельзя, к этому вовсе прикасаться не хочется..."
+ comfort = 0
diff --git a/modular_ss220/objects/code/mecha/combat.dm b/modular_ss220/objects/code/mecha/combat.dm
new file mode 100644
index 000000000000..6c49ced534de
--- /dev/null
+++ b/modular_ss220/objects/code/mecha/combat.dm
@@ -0,0 +1,109 @@
+#define ERT_TYPE_AMBER 1
+#define ERT_TYPE_RED 2
+#define ERT_TYPE_GAMMA 3
+
+// GYGAX
+
+/// NT Special Gygax
+/obj/mecha/combat/gygax/nt
+ name = "Специальный Гигакс НТ"
+ desc = "Козырь Nanotrasen при решении проблем, легкий мех окрашенный в победоносные цвета НТ. Если вы видите этот мех, вероятно все проблемы уже решены."
+ icon = 'modular_ss220/objects/icons/mecha.dmi'
+ icon_state = "ntgygax"
+ initial_icon = "ntgygax"
+ max_integrity = 300
+ deflect_chance = 20
+ leg_overload_coeff = 100
+ max_temperature = 35000
+ armor = list(melee = 40, bullet = 40, laser = 50, energy = 35, bomb = 20, rad = 20, fire = 100, acid = 100)
+ operation_req_access = list(ERT_TYPE_AMBER)
+ max_equip = 5
+ wreckage = /obj/structure/mecha_wreckage/gygax/gygax_nt
+ starting_voice = /obj/item/mecha_modkit/voice/nanotrasen
+ destruction_sleep_duration = 2 SECONDS
+
+/obj/mecha/combat/gygax/nt/loaded_red/Initialize(mapload)
+ . = ..()
+ var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/disabler
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters
+ ME.attach(src)
+
+/obj/mecha/combat/gygax/nt/loaded_epsilon/Initialize(mapload)
+ . = ..()
+ var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/xray/triple
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/heavy
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters
+ ME.attach(src)
+
+/obj/mecha/combat/gygax/nt/add_cell()
+ cell = new /obj/item/stock_parts/cell/high/slime(src)
+
+// NT Special Gygax wreckage
+/obj/structure/mecha_wreckage/gygax/gygax_nt
+ name = "\improper Обломки Специального Гигакса НТ"
+ desc = "Видимо козырь был плохим..."
+ icon = 'modular_ss220/objects/icons/mecha.dmi'
+ icon_state = "ntgygax-broken"
+
+// DURAND
+
+/// Rover
+/obj/mecha/combat/durand/rover
+ name = "Ровер"
+ desc = "Боевой мех, разработанный Синдикатом на основе Durand Mk. II путем удаления ненужных вещей и добавления некоторых своих технологий. Гораздо лучше защищен от любых опасностей, связанных с Нанотрейзен."
+ icon = 'modular_ss220/objects/icons/mecha.dmi'
+ icon_state = "darkdurand"
+ initial_icon = "darkdurand"
+ armor = list(melee = 30, bullet = 40, laser = 50, energy = 50, bomb = 20, rad = 50, fire = 100, acid = 100)
+ operation_req_access = list(ACCESS_SYNDICATE)
+ max_equip = 4
+ internal_damage_threshold = 35
+ wreckage = /obj/structure/mecha_wreckage/durand/rover
+ starting_voice = /obj/item/mecha_modkit/voice/syndicate
+ destruction_sleep_duration = 2 SECONDS
+
+/obj/mecha/combat/durand/rover/GrantActions(mob/living/user, human_occupant = 0)
+ ..()
+ thrusters_action.Grant(user, src)
+
+/obj/mecha/combat/durand/rover/RemoveActions(mob/living/user, human_occupant = 0)
+ ..()
+ thrusters_action.Remove(user)
+
+/obj/mecha/combat/durand/rover/loaded/Initialize(mapload)
+ . = ..()
+ var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg/syndi
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/repair_droid
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/ion
+ ME.attach(src)
+
+/obj/mecha/combat/durand/rover/loaded/add_cell()
+ cell = new /obj/item/stock_parts/cell/bluespace(src)
+
+// Rover's wreckage
+/obj/structure/mecha_wreckage/durand/rover
+ name = "\improper Обломки Ровера"
+ desc = "И как такой гигант пал?"
+ icon = 'modular_ss220/objects/icons/mecha.dmi'
+ icon_state = "darkdurand-broken"
+
+#undef ERT_TYPE_AMBER
+#undef ERT_TYPE_RED
+#undef ERT_TYPE_GAMMA
diff --git a/modular_ss220/objects/code/mecha/lockermech.dm b/modular_ss220/objects/code/mecha/lockermech.dm
new file mode 100644
index 000000000000..8cd103e6195b
--- /dev/null
+++ b/modular_ss220/objects/code/mecha/lockermech.dm
@@ -0,0 +1,176 @@
+// Makeshift (Lockermech)
+/obj/mecha/lockermech
+ name = "Шкафомех"
+ desc = "Шкафчик с украденными проводами, стойками, электроникой и шлюзовыми сервоприводами, грубо собранными в нечто, напоминающее мех."
+ icon = 'modular_ss220/objects/icons/mecha.dmi'
+ icon_state = "lockermech"
+ initial_icon = "lockermech"
+ // It's made of scraps
+ max_integrity = 100
+ lights_power = 5
+ // Same speed as Ripley
+ step_in = 4
+ armor = list(melee = 20, bullet = 10, laser = 10, energy = 0, bomb = 10, rad = 0, fire = 70, acid = 60)
+ internal_damage_threshold = 30
+ max_equip = 2
+ wreckage = /obj/structure/mecha_wreckage/lockermech
+ /// step_in while in normal pressure conditions
+ var/fast_pressure_step_in = 2
+ /// step_in while in better pressure conditions
+ var/slow_pressure_step_in = 4
+ var/list/cargo
+ /// You can fit a few things in this locker but not much.
+ var/cargo_capacity = 5
+
+/obj/mecha/lockermech/go_out()
+ ..()
+ update_icon(UPDATE_OVERLAYS)
+
+/obj/mecha/lockermech/moved_inside(mob/living/carbon/human/H)
+ ..()
+ update_icon(UPDATE_OVERLAYS)
+
+/obj/mecha/lockermech/mmi_moved_inside(obj/item/mmi/mmi_as_oc, mob/user)
+ ..()
+ update_icon(UPDATE_OVERLAYS)
+
+/obj/mecha/lockermech/Move()
+ . = ..()
+ update_pressure()
+
+/obj/mecha/lockermech/proc/update_pressure()
+ if(thrusters_active)
+ return // Don't calculate this if they have thrusters on, this is calculated right after domove because of course it is
+
+ var/turf/target_turf = get_turf(loc)
+
+ if(lavaland_equipment_pressure_check(target_turf))
+ step_in = fast_pressure_step_in
+ for(var/obj/item/mecha_parts/mecha_equipment/drill/lockermech/drill in equipment)
+ drill.equip_cooldown = initial(drill.equip_cooldown)/2
+ else
+ step_in = slow_pressure_step_in
+ for(var/obj/item/mecha_parts/mecha_equipment/drill/lockermech/drill in equipment)
+ drill.equip_cooldown = initial(drill.equip_cooldown)
+
+/obj/mecha/lockermech/Exit(atom/movable/object)
+ LAZYINITLIST(cargo)
+ if(object in cargo)
+ return FALSE
+ return ..()
+
+/obj/mecha/lockermech/get_stats_part()
+ LAZYINITLIST(cargo)
+ var/output = ..()
+ output += "Cargo Compartment Contents:
"
+ return output
+
+/obj/mecha/lockermech/Topic(href, href_list)
+ . = ..()
+ LAZYINITLIST(cargo)
+ if(!href_list["drop_from_cargo"])
+ return
+
+ var/obj/cargo_to_unload = locateUID(href_list["drop_from_cargo"])
+ if(!cargo_to_unload || !(cargo_to_unload in cargo))
+ return
+
+ occupant_message(span_notice("You unload [cargo_to_unload]."))
+ cargo_to_unload.forceMove(get_turf(src))
+ cargo -= cargo_to_unload
+ log_message("Unloaded [cargo_to_unload]. Cargo compartment capacity: [cargo_capacity - length(cargo)]")
+
+/obj/mecha/lockermech/Destroy()
+ LAZYINITLIST(cargo)
+ for(var/atom/movable/thing in cargo)
+ thing.forceMove(loc)
+ step_rand(thing)
+ cargo.Cut()
+ return ..()
+
+/obj/mecha/lockermech/ex_act(severity)
+ . = ..()
+ LAZYINITLIST(cargo)
+ for(var/thing in cargo)
+ var/obj/object = thing
+ if(prob(30 / severity))
+ cargo -= object
+ object.forceMove(drop_location())
+
+/obj/mecha/lockermech/emag_act(mob/user)
+ if(!emagged)
+ emagged = TRUE
+ desc += span_danger("The mech's equipment slots spark dangerously!")
+ return ..()
+
+// Crafting
+/datum/crafting_recipe/lockermech
+ name = "Locker Mech"
+ result = list(/obj/mecha/lockermech)
+ reqs = list(/obj/item/stack/cable_coil = 20,
+ /obj/item/stack/sheet/metal = 10,
+ /obj/item/storage/toolbox = 2, // For feet
+ /obj/item/tank/internals/oxygen = 1, // For air
+ /obj/item/airlock_electronics = 1, // You are stealing the motors from airlocks
+ /obj/item/extinguisher = 1, // For bastard pnumatics
+ /obj/item/c_tube = 1, // To make it airtight
+ /obj/item/flashlight = 1, // For the mech light
+ /obj/item/stack/tape_roll = 25, // ¯\_(ツ)_/¯
+ /obj/item/stock_parts/cell/high = 1,
+ /obj/item/stack/rods = 4) // To mount the equipment
+ tools = list(TOOL_WELDER, TOOL_SCREWDRIVER)
+ time = 200
+ category = CAT_ROBOT
+
+/datum/crafting_recipe/lockermech_drill
+ name = "Locker Mech Exosuit Drill"
+ result = list(/obj/item/mecha_parts/mecha_equipment/drill/lockermech)
+ reqs = list(/obj/item/stack/cable_coil = 5,
+ /obj/item/stack/sheet/metal = 2,
+ /obj/item/surgicaldrill = 1)
+ tools = list(TOOL_SCREWDRIVER)
+ time = 50
+ category = CAT_ROBOT
+
+/datum/crafting_recipe/lockermech_clamp
+ name = "Locker Mech Exosuit Clamp"
+ result = list(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/lockermech)
+ reqs = list(/obj/item/stack/cable_coil = 5,
+ /obj/item/stack/sheet/metal = 2,
+ /obj/item/wirecutters = 1) // Don't ask, its just for the grabby grabby thing
+ tools = list(TOOL_SCREWDRIVER)
+ time = 50
+ category = CAT_ROBOT
+
+// Wreckage
+/obj/structure/mecha_wreckage/lockermech
+ name = "\improper Обломки Шкафомеха"
+ desc = "Владелец данного изделия, на что он надеялся?..."
+ icon = 'modular_ss220/objects/icons/mecha.dmi'
+ icon_state = "lockermech-broken"
+
+// Equipment
+/obj/item/mecha_parts/mecha_equipment/drill/lockermech
+ name = "locker mech exosuit drill"
+ desc = "Собранная из, скорее всего, краденых деталей, эта дрель не сравнится по эффективности с настоящей."
+ equip_cooldown = 60 // Its slow as shit
+ force = 10 // Its not very strong
+ drill_delay = 15
+
+/obj/item/mecha_parts/mecha_equipment/drill/lockermech/can_attach(obj/mecha/M)
+ return istype(M, /obj/mecha/lockermech) && M.equipment.len < M.max_equip
+
+/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/lockermech
+ name = "locker mech clamp"
+ desc = "Беспорядочное расположение собранных вместе деталей, напоминающее зажим."
+ equip_cooldown = 25
+ dam_force = 10
+
+/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/lockermech/can_attach(obj/mecha/M)
+ return istype(M, /obj/mecha/lockermech) && M.equipment.len < M.max_equip
diff --git a/modular_ss220/objects/code/miscellaneous.dm b/modular_ss220/objects/code/miscellaneous.dm
new file mode 100644
index 000000000000..8d3d8a5e8ba4
--- /dev/null
+++ b/modular_ss220/objects/code/miscellaneous.dm
@@ -0,0 +1,144 @@
+/**
+* Use that for creating non-varedited objects,
+* or that you don't want to specify because they're insignificant for personal DM file
+*/
+// Fountain
+/obj/structure/statue/fountain
+ name = "фонтан"
+ desc = "Фонтан, собранный из настоящего, тёсанного камня."
+ icon = 'modular_ss220/objects/icons/fountain.dmi'
+ icon_state = "fountain_g"
+ layer = ABOVE_ALL_MOB_LAYER
+ anchored = TRUE
+ pixel_x = -16
+
+/obj/structure/statue/fountain/aged
+ name = "старый фонтан"
+ desc = "Фонтан, собранный из настоящего, тёсанного камня. Его помотало временем."
+ icon = 'modular_ss220/objects/icons/fountain.dmi'
+ icon_state = "fountain"
+
+// Spotlights, used for floors on station
+/obj/structure/marker_beacon/spotlight
+ name = "напольный прожектор"
+ desc = "Осветительное устройство. Из него исходит яркий луч света."
+ icon_state = "markerrandom"
+ var/spotlight_color
+
+/obj/structure/marker_beacon/spotlight/yellow
+ icon_state = "markeryellow-on"
+ spotlight_color = "Yellow"
+
+/obj/structure/marker_beacon/spotlight/jade
+ icon_state = "markerjade-on"
+ spotlight_color = "Jade"
+
+/obj/structure/marker_beacon/spotlight/Initialize(mapload)
+ . = ..()
+ picked_color = spotlight_color
+ update_icon(UPDATE_ICON_STATE)
+
+/obj/structure/marker_beacon/spotlight/yellow/update_icon_state()
+ set_light(light_range, light_power, LIGHT_COLOR_YELLOW)
+
+/obj/structure/marker_beacon/spotlight/jade/update_icon_state()
+ set_light(light_range, light_power, LIGHT_COLOR_BLUEGREEN)
+
+// Pamphlets
+/obj/item/paper/pamphlet
+ name = "pamphlet"
+ desc = "A pamphlet that promotes something."
+ icon_state = "pamphlet"
+
+// TODO: Write something
+/obj/item/paper/pamphlet/deathsquad
+ name = "deathsquad pamphlet"
+ icon_state = "pamphlet-ds"
+
+/obj/item/paper/pamphlet/gateway
+ info = "Welcome to the Nanotrasen Gateway project... \
+ Congratulations! If you're reading this, you and your superiors have decided that you're \
+ ready to commit to a life spent colonising the rolling hills of far away worlds. You \
+ must be ready for a lifetime of adventure, a little bit of hard work, and an award \
+ winning dental plan- but that's not all the Nanotrasen Gateway project has to offer. \
+ Because we care about you, we feel it is only fair to make sure you know the risks \
+ before you commit to joining the Nanotrasen Gateway project. All away destinations have \
+ been fully scanned by a Nanotrasen expeditionary team, and are certified to be 100% safe. \
+ We've even left a case of space beer along with the basic materials you'll need to expand \
+ Nanotrasen's operational area and start your new life.
\
+ Gateway Operation Basics \
+ All Nanotrasen approved Gateways operate on the same basic principals. They operate off \
+ area equipment power as you would expect, but they also require a backup wire with at least \
+ 128, 000 Watts of power running through it. Without this supply, it cannot safely function \
+ and will reject all attempts at operation.
\
+ Once it is correctly setup, and once it has enough power to operate, the Gateway will begin \
+ searching for an output location. The amount of time this takes is variable, but the Gateway \
+ interface will give you an estimate accurate to the minute. Power loss will not interrupt the \
+ searching process. Influenza will not interrupt the searching process. Temporal anomalies \
+ may cause the estimate to be inaccurate, but will not interrupt the searching process.
\
+ Life On The Other Side \
+ Once you have traversed the Gateway, you may experience some disorientation. Do not panic. \
+ This is a normal side effect of travelling vast distances in a short period of time. You should \
+ survey the immediate area, and attempt to locate your complimentary case of space beer. Our \
+ expeditionary teams have ensured the complete safety of all away locations, but in a small \
+ number of cases, the Gateway they have established may not be immediately obvious. \
+ Do not panic if you cannot locate the return Gateway. Begin colonisation of the destination. \
+
A New World \
+ As a participant in the Nanotrasen Gateway Project, you will be on the frontiers of space. \
+ Though complete safety is assured, participants are advised to prepare for inhospitable \
+ environs."
+
+// TODO: Rewrite text (update info and add map)
+/obj/item/paper/pamphlet/deltainfo
+ name = "информационный буклет ИСН «Керберос»"
+ info = "
Буклет нового сотрудника \
+ на борту НСС "Керберос"
\
+
Цель
\
+ Данное руководство было создано с целью \
+ облегчить процесс введения в работу станции нового экипажа, \
+ а также для информирования сотрудников об оптимальных маршрутах \
+ передвижения. В данном буклете находится основная карта "Кербероса" \
+ и несколько интересных фактов о станции.\
+ За время строительства проект станции претерпел несколько значительных \
+ изменений. Изначально новая станция должна была стать туристическим объектом, \
+ но после произошедшей в 2549 году серии террористических актов \
+ объект вошёл в состав парка научно-исследовательских станций корпорации. В \
+ нынешних технических туннелях до сих пор можно найти заброшенные комнаты для \
+ гостей, бары и клубы. В связи с плачевным состоянием несущих конструкций \
+ посещать эти части станции не рекомендуется, однако неиспользуемые площади \
+ могут быть использованы для строительства новых отсеков.\
+
Особенности станции
\
+ В отличие от большинства других научно-исследовательских станций Nanotrasen, \
+ таких как "Кибериада", ИСН "Керборос" имеет менее \
+ жёсткую систему контроля за личными вещами экипажа. В частности, в отсеках \
+ были построены дополнительные автолаты, в том числе публичные \
+ (в карго и РНД). Также, благодаря более высокому бюджету, были возведены \
+ новые отсеки, такие как ангар или склад в отсеке РнД.\
+ Был расширен отдел вирусологии и возведены новые техничесские туннели для \
+ новых проектов."
+
+/obj/item/paper/pamphlet/update_icon_state()
+ return
+
+// Wallets
+// Adding more items that wallet can hold
+/obj/item/storage/wallet/Initialize(mapload)
+ . = ..()
+ can_hold += list(
+ /obj/item/encryptionkey,
+ /obj/item/clothing/gloves/ring)
+
+// These objects are deleted by Offs, i returned them
+// Archive structure
+/obj/structure/cult/archives
+ name = "Desk"
+ desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl."
+ icon_state = "archives"
+ light_range = 1.5
+ light_color = LIGHT_COLOR_FIRE
+
+// Display Cases
+/obj/structure/displaycase/hos
+ alert = TRUE
+ start_showpiece_type = /obj/item/gun/projectile/revolver/reclinable/judge
+ req_access = list(ACCESS_HOS)
diff --git a/modular_ss220/objects/code/musician.dm b/modular_ss220/objects/code/musician.dm
new file mode 100644
index 000000000000..067f88e19585
--- /dev/null
+++ b/modular_ss220/objects/code/musician.dm
@@ -0,0 +1,11 @@
+/obj/structure/musician/piano
+ allowed_instrument_ids = "crgrand1"
+
+/obj/item/instrument/guitar
+ allowed_instrument_ids = "csteelgt"
+
+/obj/item/instrument/trumpet
+ allowed_instrument_ids = "crtrumpet"
+
+/obj/item/instrument/trombone
+ allowed_instrument_ids = "crtrombone"
diff --git a/modular_ss220/objects/code/officetoys.dm b/modular_ss220/objects/code/officetoys.dm
new file mode 100644
index 000000000000..78443e9b4b17
--- /dev/null
+++ b/modular_ss220/objects/code/officetoys.dm
@@ -0,0 +1,199 @@
+#define HOURGLASS_STATES 7 // Remember to update if you change the sprite
+
+// Hourglass
+/obj/item/hourglass
+ name = "hourglass"
+ desc = "Nanotrasen patented gravity invariant hourglass. Guaranteed to flow perfectly under any conditions."
+ icon = 'modular_ss220/objects/icons/officetoys.dmi'
+ icon_state = "hourglass_idle"
+ var/obj/effect/countdown/hourglass/countdown
+ var/time = 1 MINUTES
+ var/finish_time // So countdown doesn't need to fiddle with timers
+ var/timing_id // If present we're timing
+ var/hand_activated = TRUE
+
+/obj/item/hourglass/Initialize(mapload)
+ . = ..()
+ countdown = new(src)
+
+/obj/item/hourglass/attack_self__legacy__attackchain(mob/user)
+ . = ..()
+ if(hand_activated)
+ toggle(user)
+
+/obj/item/hourglass/proc/toggle(mob/user)
+ if(!timing_id)
+ to_chat(user, span_notice("You flip [src]."))
+ start()
+ flick("hourglass_flip",src)
+ else
+ to_chat(user, span_notice("You stop [src].")) // Sand magically flows back because that's more convinient to use.
+ stop()
+
+/obj/item/hourglass/update_icon()
+ icon_state = "hourglass_[timing_id ? "active" : "idle"]"
+ return ..()
+
+/obj/item/hourglass/proc/start()
+ finish_time = world.time + time
+ timing_id = addtimer(CALLBACK(src, PROC_REF(finish)), time, TIMER_STOPPABLE)
+ countdown.start()
+ timing_animation()
+
+/obj/item/hourglass/proc/timing_animation()
+ var/step_time = time / HOURGLASS_STATES
+ animate(src, time = step_time, icon_state = "hourglass_1")
+ for(var/i in 2 to HOURGLASS_STATES)
+ animate(time = step_time, icon_state = "hourglass_[i]")
+
+/obj/item/hourglass/proc/stop()
+ if(timing_id)
+ deltimer(timing_id)
+ timing_id = null
+ countdown.stop()
+ finish_time = null
+ animate(src)
+ update_icon()
+
+/obj/item/hourglass/proc/finish()
+ visible_message(span_notice("[src] stops."))
+ stop()
+
+/obj/item/hourglass/Destroy()
+ QDEL_NULL(countdown)
+ . = ..()
+
+// Admin events zone
+/obj/item/hourglass/admin
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ anchored = TRUE
+ hand_activated = FALSE
+
+/obj/item/hourglass/admin/attack_hand(mob/user, list/modifiers)
+ . = ..()
+ if(user.client && user.client.holder)
+ toggle(user)
+
+/obj/item/hourglass/admin/attack_ghost(mob/user)
+ if(user.client && user.client.holder)
+ toggle(user)
+
+#undef HOURGLASS_STATES
+
+// Hourglass countdown
+/obj/effect/countdown/hourglass
+ name = "hourglass countdown"
+
+/obj/effect/countdown/hourglass/get_value()
+ var/obj/item/hourglass/H = attached_to
+ if(!istype(H))
+ return
+ else
+ var/time_left = max(0, (H.finish_time - world.time) / 10)
+ return round(time_left)
+
+/*
+* Office desk toys
+*/
+/obj/item/toy/desk
+ name = "desk toy master"
+ desc = "A object that does not exist. Parent Item."
+ icon = 'modular_ss220/objects/icons/officetoys.dmi'
+ layer = ABOVE_MOB_LAYER
+ var/on = 0
+ var/activation_sound = 'modular_ss220/objects/sound/officetoys/buttonclick.ogg'
+
+/obj/item/toy/desk/update_icon_state()
+ if(on)
+ icon_state = "[initial(icon_state)]-on"
+ else
+ icon_state = "[initial(icon_state)]"
+
+/obj/item/toy/desk/attack_self__legacy__attackchain(mob/user)
+ on = !on
+ if(activation_sound)
+ playsound(src.loc, activation_sound, 75, 1)
+ update_icon()
+ return TRUE
+
+/obj/item/toy/desk/examine(mob/user)
+ . = ..()
+ . += span_notice("Alt-Click to rotate.")
+
+/obj/item/toy/desk/proc/rotate(mob/user)
+ if(user.incapacitated())
+ return
+ dir = turn(dir, 270)
+ return TRUE
+
+/obj/item/toy/desk/AltClick(mob/user)
+ if(user.incapacitated())
+ to_chat(user, span_warning("You can't do that right now!"))
+ return
+ if(!in_range(src, user))
+ return
+ else
+ rotate(user)
+
+/obj/item/toy/desk/officetoy
+ name = "office toy"
+ desc = "A generic microfusion powered office desk toy. Only generates magnetism and ennui."
+ icon_state = "desktoy"
+
+/obj/item/toy/desk/dippingbird
+ name = "dipping bird toy"
+ desc = "A ancient human bird idol, worshipped by clerks and desk jockeys."
+ icon_state = "dippybird"
+
+/obj/item/toy/desk/newtoncradle
+ name = "\improper Newton's cradle"
+ desc = "A ancient 21th century super-weapon model demonstrating that Sir Isaac Newton is the deadliest sonuvabitch in space."
+ icon_state = "newtoncradle"
+ var/datum/looping_sound/newtonballs/soundloop
+
+/obj/item/toy/desk/newtoncradle/Initialize(mapload)
+ . = ..()
+ soundloop = new(list(src), FALSE)
+
+/obj/item/toy/desk/newtoncradle/attack_self__legacy__attackchain(mob/user)
+ on = !on
+ update_icon()
+ if(on)
+ soundloop.start()
+ else
+ soundloop.stop()
+
+/obj/item/toy/desk/fan
+ name = "office fan"
+ desc = "Your greatest fan."
+ icon_state = "fan"
+ var/datum/looping_sound/fanblow/soundloop
+
+/obj/item/toy/desk/fan/Initialize(mapload)
+ . = ..()
+ soundloop = new(list(src), FALSE)
+
+/obj/item/toy/desk/fan/attack_self__legacy__attackchain(mob/user)
+ on = !on
+ update_icon()
+ if(on)
+ soundloop.start()
+ else
+ soundloop.stop()
+
+// Item datums
+/datum/looping_sound/fanblow
+ start_sound = 'modular_ss220/objects/sound/officetoys/fan_start.ogg'
+ start_length = 40
+ mid_sounds = 'modular_ss220/objects/sound/officetoys/fan_mid1.ogg'
+ mid_length = 23
+ end_sound = 'modular_ss220/objects/sound/officetoys/fan_end.ogg'
+ volume = 30
+
+/datum/looping_sound/newtonballs
+ start_sound = FALSE
+ start_length = FALSE
+ mid_sounds = 'modular_ss220/objects/sound/officetoys/newtoncradle_mid1.ogg'
+ mid_length = 9
+ end_sound = FALSE
+ volume = 50
diff --git a/modular_ss220/objects/code/papershredder.dm b/modular_ss220/objects/code/papershredder.dm
new file mode 100644
index 000000000000..50d5f0bad793
--- /dev/null
+++ b/modular_ss220/objects/code/papershredder.dm
@@ -0,0 +1,141 @@
+/obj/machinery/papershredder
+ name = "paper shredder"
+ desc = "For those documents you don't want seen."
+ icon = 'modular_ss220/objects/icons/papershredder.dmi'
+ icon_state = "papershredder0"
+ density = TRUE
+ anchored = TRUE
+ var/max_paper = 15
+ var/paperamount = 0
+ var/list/shred_amounts = list(
+ /obj/item/photo = 1,
+ /obj/item/shredded_paper = 1,
+ /obj/item/paper = 1,
+ /obj/item/newspaper = 3,
+ /obj/item/card/id = 3,
+ /obj/item/paper_bundle = 3,
+ /obj/item/folder = 4,
+ /obj/item/book = 5
+ )
+
+/obj/machinery/papershredder/attackby__legacy__attackchain(obj/item/item, mob/user, params)
+ if(istype(item, /obj/item/storage))
+ add_fingerprint(user)
+ empty_bin(user, item)
+ return
+ var/paper_result
+ if(item.type in shred_amounts)
+ paper_result = shred_amounts[item.type]
+ if(!paper_result)
+ . = ..()
+ return
+ if(paperamount == max_paper)
+ to_chat(user, span_warning("[src] is full; please empty it before you continue."))
+ return
+ paperamount += paper_result
+ qdel(item)
+ playsound(loc, 'modular_ss220/objects/sound/pshred.ogg', 75, 1)
+ if(paperamount > max_paper)
+ to_chat(user, span_danger("[src] was too full, and shredded paper goes everywhere!"))
+ for(var/i in 1 to paperamount-max_paper)
+ var/obj/item/shredded_paper/shredp = get_shredded_paper()
+ shredp.loc = get_turf(src)
+ shredp.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), 1, 1)
+ paperamount = max_paper
+ update_icon()
+ add_fingerprint(user)
+
+/obj/machinery/papershredder/wrench_act(mob/user, obj/item/tool)
+ . = TRUE
+ if(!tool.use_tool(src, user, 0, volume = tool.tool_volume))
+ return
+ anchored = !anchored
+ if(anchored)
+ WRENCH_ANCHOR_MESSAGE
+ else
+ WRENCH_UNANCHOR_MESSAGE
+
+/obj/machinery/papershredder/examine(mob/user)
+ . = ..()
+ . += span_notice("Alt-Click to empty [src].")
+
+/obj/machinery/papershredder/AltClick(mob/user)
+ empty_contents(user)
+
+/obj/machinery/papershredder/proc/empty_contents(mob/user)
+ if(user.stat || user.restrained())
+ to_chat(user, span_notice("You need your hands and legs free for this."))
+ return
+
+ if(!paperamount)
+ to_chat(user, span_notice("[src] is empty."))
+ return
+
+ empty_bin(user)
+
+/obj/machinery/papershredder/proc/empty_bin(mob/living/user, obj/item/storage/empty_into)
+
+ // Sanity.
+ if(empty_into && !istype(empty_into))
+ empty_into = null
+
+ if(empty_into && length(empty_into.contents) >= empty_into.storage_slots)
+ to_chat(user, span_notice("[empty_into] is full."))
+ return
+
+ while(paperamount)
+ var/obj/item/shredded_paper/SP = get_shredded_paper()
+ if(!SP)
+ break
+ if(empty_into)
+ empty_into.handle_item_insertion(SP)
+ if(length(empty_into.contents) >= empty_into.storage_slots)
+ break
+ if(empty_into)
+ if(paperamount)
+ to_chat(user, span_notice("You fill [empty_into] with as much shredded paper as it will carry."))
+ else
+ to_chat(user, span_notice("You empty [src] into [empty_into]."))
+
+ else
+ to_chat(user, span_notice("You empty [src]."))
+ update_icon()
+
+/obj/machinery/papershredder/proc/get_shredded_paper()
+ if(!paperamount)
+ return
+ paperamount--
+ return new /obj/item/shredded_paper(get_turf(src))
+
+/obj/machinery/papershredder/update_icon_state()
+ icon_state = "papershredder[clamp(round(paperamount/3), 0, 5)]"
+
+/obj/item/shredded_paper/attackby__legacy__attackchain(obj/item/shredp as obj, mob/user)
+ if(resistance_flags & ON_FIRE)
+ add_fingerprint(user)
+ return
+ if(shredp.get_heat())
+ add_fingerprint(user)
+ user.visible_message(
+ span_danger("\The [user] burns right through [src], turning it to ash. It flutters through the air before settling on the floor in a heap."),
+ span_danger("You burn right through [src], turning it to ash. It flutters through the air before settling on the floor in a heap."))
+ fire_act()
+ else
+ ..()
+
+/obj/item/shredded_paper
+ name = "shredded paper"
+ icon = 'modular_ss220/objects/icons/papershredder.dmi'
+ icon_state = "shredp"
+ throwforce = 0
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+ layer = 4
+ max_integrity = 25
+ throw_range = 3
+ throw_speed = 2
+
+/obj/item/shredded_paper/Initialize(mapload)
+ . = ..()
+ if(prob(65))
+ color = pick("#8b8b8b","#e7e4e4", "#c9c9c9")
diff --git a/modular_ss220/objects/code/plastic_chair.dm b/modular_ss220/objects/code/plastic_chair.dm
new file mode 100644
index 000000000000..5da2fcfeb765
--- /dev/null
+++ b/modular_ss220/objects/code/plastic_chair.dm
@@ -0,0 +1,51 @@
+/obj/structure/chair/plastic
+ name = "\improper складной пластиковый стул"
+ desc = "Как бы вы ни ёрзали, все равно будет неудобно."
+ icon = 'modular_ss220/objects/icons/plastic.dmi'
+ icon_state = "plastic_chair"
+ resistance_flags = FLAMMABLE
+ max_integrity = 50
+ buildstacktype = /obj/item/stack/sheet/plastic
+ buildstackamount = 2
+ item_chair = /obj/item/chair/plastic
+
+/obj/structure/chair/plastic/post_buckle_mob(mob/living/Mob)
+ Mob.pixel_y += 2
+ .=..()
+ if(iscarbon(Mob))
+ INVOKE_ASYNC(src, PROC_REF(snap_check), Mob)
+
+/obj/structure/chair/plastic/post_unbuckle_mob(mob/living/Mob)
+ Mob.pixel_y -= 2
+
+/obj/structure/chair/plastic/proc/snap_check(mob/living/carbon/M)
+ if(M.nutrition >= NUTRITION_LEVEL_FAT)
+ to_chat(M, span_warning("Стул начинает хрустеть и трещать, ты слишком тяжёлый!"))
+ if(do_after(M, 6 SECONDS, progress = FALSE))
+ M.visible_message(span_notice("\improper [M] садится на пластиковый стул, и проламывает его своим весом!"))
+ new /obj/effect/decal/cleanable/plastic(loc)
+ M.Weaken(5 SECONDS)
+ M.emote("scream")
+ playsound(src, 'sound/effects/snap.ogg', 50, 1, -1)
+ qdel(src)
+
+/obj/item/chair/plastic
+ name = "\improper складной пластиковый стул"
+ desc = "Почему-то, всегда можно найти под рингом."
+ icon = 'modular_ss220/objects/icons/plastic.dmi'
+ icon_state = "folded_chair"
+ item_state = "folded_chair"
+ lefthand_file = 'modular_ss220/objects/icons/inhands/chairs_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/chairs_righthand.dmi'
+ w_class = WEIGHT_CLASS_NORMAL
+ force = 7
+ throw_range = 5
+ break_chance = 25
+ origin_type = /obj/structure/chair/plastic
+
+/obj/effect/decal/cleanable/plastic
+ name = "\improper пластиковые осколки"
+ desc = "Куски рваного, сломанного, никчёмного пластика."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "shards"
+ color = "#c6f4ff"
diff --git a/modular_ss220/objects/code/platform.dm b/modular_ss220/objects/code/platform.dm
new file mode 100644
index 000000000000..c7086e605748
--- /dev/null
+++ b/modular_ss220/objects/code/platform.dm
@@ -0,0 +1,186 @@
+// Platform Code by Danaleja2005
+/obj/structure/platform
+ name = "platform"
+ icon = 'modular_ss220/objects/icons/platform.dmi'
+ icon_state = "metal"
+ desc = "A metal platform."
+ flags = ON_BORDER
+ anchored = FALSE
+ climbable = TRUE
+ max_integrity = 200
+ armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 50, BOMB = 20, RAD = 0, FIRE = 30, ACID = 30)
+ var/corner = FALSE
+ var/material_type = /obj/item/stack/sheet/metal
+ var/material_amount = 4
+ var/decon_speed
+
+/obj/structure/platform/proc/CheckLayer()
+ if(dir == SOUTH)
+ layer = ABOVE_MOB_LAYER
+ else if(corner || dir == NORTH)
+ layer = BELOW_MOB_LAYER
+
+/obj/structure/platform/setDir(newdir)
+ . = ..()
+ CheckLayer()
+
+/obj/structure/platform/Initialize(mapload)
+ . = ..()
+ CheckLayer()
+
+/obj/structure/platform/New()
+ ..()
+ if(corner)
+ decon_speed = 20
+ density = FALSE
+ climbable = FALSE
+ else
+ decon_speed = 30
+ CheckLayer()
+
+/obj/structure/platform/examine(mob/user)
+ . = ..()
+ . += span_notice("[src] is [anchored == TRUE ? "screwed" : "unscrewed"] [anchored == TRUE ? "to" : "from"] the floor.")
+ . += span_notice("Alt-Click to rotate.")
+
+/obj/structure/platform/proc/rotate(mob/user)
+ if(user.incapacitated())
+ return
+
+ if(anchored)
+ to_chat(user, span_warning("[src] cannot be rotated while it is screwed to the floor!"))
+ return FALSE
+
+ var/target_dir = turn(dir, 90)
+
+ setDir(target_dir)
+ recalculate_atmos_connectivity()
+ add_fingerprint(user)
+ return TRUE
+
+/obj/structure/platform/AltClick(mob/user)
+ rotate(user)
+
+// Construction
+/obj/structure/platform/screwdriver_act(mob/user, obj/item/I)
+ . = TRUE
+ to_chat(user, span_notice("You begin [anchored == TRUE ? "unscrewing" : "screwing"] [src] [anchored == TRUE ? "from" : "to"] the floor."))
+ if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume))
+ return
+ to_chat(user, span_notice("You [anchored == TRUE ? "unscrew" : "screw"] [src] [anchored == TRUE ? "from" : "to"] the floor."))
+ anchored = !anchored
+
+/obj/structure/platform/wrench_act(mob/user, obj/item/I)
+ if(user.a_intent != INTENT_HELP)
+ return
+ . = TRUE
+ if(anchored)
+ to_chat(user, span_notice("You cannot disassemble [src], unscrew it first!"))
+ return
+ TOOL_ATTEMPT_DISMANTLE_MESSAGE
+ if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume))
+ return
+ var/obj/item/stack/sheet/G = new material_type(user.loc, material_amount)
+ G.add_fingerprint(user)
+ playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
+ TOOL_DISMANTLE_SUCCESS_MESSAGE
+ qdel(src)
+
+
+/obj/structure/platform/CheckExit(atom/movable/O, turf/target)
+ if(!anchored)
+ CheckLayer()
+ if(istype(O, /obj/structure/platform))
+ return FALSE
+ if(istype(O, /obj/item/projectile) || istype(O, /obj/effect))
+ return TRUE
+ if(corner)
+ return !density
+ if(O && O.throwing)
+ return TRUE
+ if(((flags & ON_BORDER) && get_dir(loc, target) == dir))
+ return FALSE
+ else
+ return TRUE
+
+/obj/structure/platform/CanPass(atom/movable/mover, turf/target)
+ if(!anchored)
+ CheckLayer()
+ if(istype(mover, /obj/structure/platform))
+ return FALSE
+ if(istype(mover, /obj/item/projectile))
+ return TRUE
+ if(corner)
+ return !density
+ if(mover && mover.throwing)
+ return TRUE
+ var/obj/structure/S = locate(/obj/structure) in get_turf(mover)
+ if(S && S.climbable && !(S.flags & ON_BORDER) && climbable && isliving(mover))// Climbable objects allow you to universally climb over others
+ return TRUE
+ if(!(flags & ON_BORDER) || get_dir(loc, target) == dir)
+ return FALSE
+ else
+ return TRUE
+
+/obj/structure/platform/do_climb(mob/living/user)
+ if(!can_touch(user) || !climbable)
+ return
+ var/blocking_object = density_check()
+ if(blocking_object)
+ to_chat(user, span_warning("You cannot climb over [src], as it is blocked by \a [blocking_object]!"))
+ return
+
+ var/destination_climb = get_step(src, dir)
+ if(is_blocked_turf(destination_climb))
+ to_chat(user, span_warning("You cannot climb over [src], the path is blocked!"))
+ return
+ var/turf/T = src.loc
+ if(!T || !istype(T)) return
+
+ if(get_turf(user) == get_turf(src))
+ usr.visible_message(span_warning("[user] starts climbing over \the [src]!"))
+ else
+ usr.visible_message(span_warning("[user] starts getting off \the [src]!"))
+ climbers += user
+ if(!do_after(user, 50, target = src))
+ climbers -= user
+ return
+
+ if(!can_touch(user) || !climbable)
+ climbers -= user
+ return
+
+ if(get_turf(user) == get_turf(src))
+ usr.loc = get_step(src, dir)
+ usr.visible_message(span_warning("[user] leaves \the [src]!"))
+ else
+ usr.loc = get_turf(src)
+ usr.visible_message(span_warning("[user] starts climbing over \the [src]!"))
+ climbers -= user
+
+/obj/structure/platform/CanAtmosPass()
+ return TRUE
+
+// Platform types
+/obj/structure/platform/reinforced
+ name = "reinforced platform"
+ desc = "A robust platform made of plasteel, more resistance for hazard sites."
+ icon_state = "plasteel"
+ material_type = /obj/item/stack/sheet/plasteel
+ max_integrity = 300
+ armor = list(MELEE = 20, BULLET = 30, LASER = 30, ENERGY = 100, BOMB = 50, RAD = 75, FIRE = 100, ACID = 100)
+
+// Platform corners
+/obj/structure/platform/corner
+ name = "platform corner"
+ desc = "A metal platform corner."
+ icon_state = "metalcorner"
+ corner = TRUE
+ material_amount = 2
+
+/obj/structure/platform/reinforced/corner
+ name = "reinforced platform corner"
+ desc = "A robust platform corner made of plasteel, more resistance for hazard sites."
+ icon_state = "plasteelcorner"
+ corner = TRUE
+ material_amount = 2
diff --git a/modular_ss220/objects/code/plushies/hampters.dm b/modular_ss220/objects/code/plushies/hampters.dm
new file mode 100644
index 000000000000..430269fdeb3c
--- /dev/null
+++ b/modular_ss220/objects/code/plushies/hampters.dm
@@ -0,0 +1,141 @@
+// "Микро-компонент" модульности ради...? Возможно, и, скорее всего, плохая идея.
+// Не использовал squeak.dm ибо у squeak есть регистрация COMSIG_ACTIVATE_SELF, который мешает использовать attack_self() с проверкой интентов
+/datum/component/plushtoy/Initialize()
+ . = ..()
+ // Пищит при ударах
+ RegisterSignal(parent, list(COMSIG_ATOM_HULK_ATTACK, COMSIG_ATTACK_BY, COMSIG_MOVABLE_BUMP, COMSIG_ATTACK, COMSIG_ATTACK_OBJ), PROC_REF(play_squeak))
+
+ // Пищит при наступании
+ RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, PROC_REF(play_squeak_crossed))
+
+// Пищание
+/datum/component/plushtoy/proc/play_squeak()
+ playsound(parent, 'sound/items/squeaktoy.ogg', 50, TRUE, -10)
+
+// Стащенный кусок кода для фикса большого числа писков в зависимости от числа хамптеров в инвентаре
+/datum/component/plushtoy/proc/play_squeak_crossed(atom/movable/AM)
+ if(isitem(AM))
+ var/obj/item/I = AM
+ if(I.flags & ABSTRACT)
+ return
+ else if(istype(AM, /obj/item/projectile))
+ var/obj/item/projectile/P = AM
+ if(P.original != parent)
+ return
+ if(ismob(AM))
+ var/mob/M = AM
+ if(HAS_TRAIT(M, TRAIT_FLYING))
+ return
+ if(isliving(AM))
+ var/mob/living/L = M
+ if(L.floating)
+ return
+ var/atom/current_parent = parent
+ if(isturf(current_parent.loc))
+ play_squeak()
+
+// Спавнер рандомного хамптера для карты
+/obj/random/hampter
+ name = "Random Hampter"
+ desc = "This is a random hampter spawner."
+ icon = 'modular_ss220/objects/icons/plushies.dmi'
+ icon_state = "hampter"
+
+/obj/random/hampter/item_to_spawn()
+ return pick(typesof(/obj/item/toy/hampter))
+
+// Хамптер
+/obj/item/toy/hampter
+ name = "хамптер"
+ desc = "Просто плюшевый хамптер. Самый обычный."
+ icon = 'modular_ss220/objects/icons/plushies.dmi'
+ icon_state = "hampter"
+ icon_override = 'modular_ss220/objects/icons/inhead/head.dmi'
+ lefthand_file = 'modular_ss220/objects/icons/inhands/plushies_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/plushies_righthand.dmi'
+ slot_flags = ITEM_SLOT_HEAD
+ w_class = WEIGHT_CLASS_TINY
+ blood_color = "#d42929"
+ var/squeak = 'sound/items/squeaktoy.ogg'
+ var/cooldown = 0
+
+// Добавляем наш "микро-компонент" хамптеру
+/obj/item/toy/hampter/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/plushtoy)
+
+// Действия при взаимодействии в руке при разных интентах
+/obj/item/toy/hampter/attack_self__legacy__attackchain(mob/living/carbon/human/user)
+ . = ..()
+ // Небольшой кулдаун дабы нельзя было спамить
+ if(cooldown < world.time - 10)
+ switch(user.a_intent)
+ // Если выбрано что угодно кроме харма - жмякаем с писком хамптера
+ if(INTENT_HELP, INTENT_DISARM, INTENT_GRAB)
+ playsound(get_turf(src), squeak, 50, 1, -10)
+
+ // Если выбран харм, сжимаем хамптера до "краски" (?) в его туловище
+ if(INTENT_HARM)
+ // Прописываю это здесь ибо иначе хомяки будут отмечаться кровавыми в игре
+ blood_DNA = "Plush hampter's paint"
+
+ user.visible_message(
+ span_warning("[user] раздавил хамптера в своей руке!"),
+ span_warning("Вы раздавили хамптера в своей руке!"))
+ playsound(get_turf(src), "bonebreak", 50, TRUE, -10)
+
+ user.hand_blood_color = blood_color
+ user.transfer_blood_dna(blood_DNA)
+ // Сколько бы я не хотел ставить 0 - не выйдет. Нельзя будет отмыть руки в раковине
+ user.bloody_hands = 1
+ user.update_inv_gloves()
+
+ qdel(src)
+
+ cooldown = world.time
+
+// Подвиды
+/obj/item/toy/hampter/assistant
+ name = "хамптер ассистент"
+ desc = "Плюшевый хамптер ассистент. Зачем ему изольки?"
+ icon_state = "hampter_ass"
+
+/obj/item/toy/hampter/security
+ name = "хамптер офицер"
+ desc = "Плюшевый хамптер офицер службы безопасности. У него станбатон!"
+ icon_state = "hampter_sec"
+
+/obj/item/toy/hampter/medical
+ name = "хамптер врач"
+ desc = "Плюшевый хамптер врач. Тащите дефибриллятор!"
+ icon_state = "hampter_med"
+
+/obj/item/toy/hampter/janitor
+ name = "хамптер уборщик"
+ desc = "Плюшевый хамптер уборщик. Переключись на шаг."
+ icon_state = "hampter_jan"
+
+/obj/item/toy/hampter/old_captain
+ name = "хамптер старый капитан"
+ desc = "ПЛюшевый хамптер капитан в старой униформе. Это какой год?"
+ icon_state = "hampter_old-cap"
+
+/obj/item/toy/hampter/captain
+ name = "хамптер капитан"
+ desc = "Плюшевый хамптер капитан. Где его запасная карта?"
+ icon_state = "hampter_cap"
+
+/obj/item/toy/hampter/syndicate
+ name = "хамптер Синдиката"
+ desc = "Плюшевый хамптер агент Синдиката. Ваши активы пострадают."
+ icon_state = "hampter_sdy"
+
+/obj/item/toy/hampter/deadsquad
+ name = "хамптер Дедсквада"
+ desc = "Плюшевый хамптер Отряда Смерти. Все контракты расторгнуты."
+ icon_state = "hampter_ded"
+
+/obj/item/toy/hampter/ert
+ name = "хамптер ОБР"
+ desc = "Плюшевый хамптер ОБР. Доложите о ситуации на станции."
+ icon_state = "hampter_ert"
diff --git a/modular_ss220/objects/code/plushies/macvulpix.dm b/modular_ss220/objects/code/plushies/macvulpix.dm
new file mode 100644
index 000000000000..db999bd8a894
--- /dev/null
+++ b/modular_ss220/objects/code/plushies/macvulpix.dm
@@ -0,0 +1,65 @@
+/obj/item/toy/plushie/macvulpix
+ name = "Business Red Fox"
+ desc = "Мягкая и приятная на ощупь игрушка важного рыжего лиса в пальто."
+ icon = 'modular_ss220/objects/icons/plushies.dmi'
+ icon_state = "macvulpix"
+ item_state = "macvulpix"
+ lefthand_file = 'modular_ss220/objects/icons/inhands/plushies_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/plushies_righthand.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+ /// Static list of allowed glasses
+ var/static/list/allowed_glasses = typesof(/obj/item/clothing/glasses/sunglasses) + typesof(/obj/item/clothing/glasses/sunglasses_fake)
+ /// Equiped glasses on plushie
+ var/obj/item/clothing/glasses/glasses
+
+/obj/item/toy/plushie/macvulpix/Destroy()
+ . = ..()
+ QDEL_NULL(glasses)
+ return ..()
+
+/obj/item/toy/plushie/macvulpix/update_icon_state()
+ if(glasses)
+ icon_state = "[initial(icon_state)]_glasses"
+ item_state = "[initial(item_state)]_glasses"
+ else
+ icon_state = "[initial(icon_state)]"
+ item_state = "[initial(item_state)]"
+
+ if(ismob(loc))
+ var/mob/M = loc
+ M.update_inv_r_hand()
+ M.update_inv_l_hand()
+
+/obj/item/toy/plushie/macvulpix/attackby__legacy__attackchain(obj/item/clothing/glasses/sunglasses, mob/living/user, params)
+ . = ..()
+ if(is_type_in_list(sunglasses, allowed_glasses))
+ user.drop_item()
+ sunglasses.forceMove(src)
+ glasses = sunglasses
+ desc = "Мягкая и приятная на ощупь игрушка важного рыжего лиса в пальто и солнечных очках! Oh yeah!"
+ update_icon(UPDATE_ICON_STATE)
+ return TRUE
+
+/obj/item/toy/plushie/macvulpix/AltClick(mob/user)
+ if(!glasses)
+ return
+
+ if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || user.restrained())
+ to_chat(user, span_warning("У вас нет возможности снять очки с [src]!"))
+ return
+
+ if(!user.get_active_hand() && Adjacent(user))
+ user.put_in_hands(glasses)
+ else
+ glasses.forceMove(get_turf(user))
+
+ glasses = null
+ desc = initial(desc)
+ update_icon(UPDATE_ICON_STATE)
+
+/obj/item/toy/plushie/macvulpix/examine(mob/user)
+ . = ..()
+ if(glasses)
+ . += span_notice("Нажмите Alt-Click на игрушку, чтобы снять очки.")
+ else
+ . += span_notice("На эту игрушку можно надеть солнцезащитные очки.")
diff --git a/modular_ss220/objects/code/posters.dm b/modular_ss220/objects/code/posters.dm
new file mode 100644
index 000000000000..c5882030bff7
--- /dev/null
+++ b/modular_ss220/objects/code/posters.dm
@@ -0,0 +1,94 @@
+/obj/structure/sign/poster
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+
+// MARK: Contraband
+/obj/structure/sign/poster/contraband/lady
+ name = "Соблазнительная Красотка"
+ desc = "На плакате изображена крайне сексуальная девушка."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "contraband1"
+
+/obj/structure/sign/poster/contraband/very_robust
+ name = "Робаст"
+ desc = "Вы видите слегка потрёпанный плакат, на котором изображен КРАСНЫЙ туллбокс! На плакате написано \"Опасно, робастное!\", некоторые утверждают, что эта красная краска на плакате сделана из настоящей крови."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "contraband2"
+
+/obj/structure/sign/poster/contraband/vodka
+ name = "Водка"
+ desc = "Рекламный плакат водки, напитка от настоящих мужчин для настоящих мужчин. Почувствуй себя космическим медведем."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "contraband3"
+
+/obj/structure/sign/poster/contraband/wanted
+ name = "Никодим Парадайзович"
+ desc = "На плакате вы видите: лысый, черноглазый мужчина, лет 40, и его разыскивают на просторах всего космоса. Что он не сделал, чтобы его так разыскивали..."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "contraband4"
+
+/obj/structure/sign/poster/contraband/soulless_figures
+ name = "Бездушные фигуры"
+ desc = "Плакат изображает множество безвольно слоняющихся тёмных фигур. Кажется они смотрят прямо на тебя, жуть..."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "contraband5"
+
+/obj/structure/sign/poster/contraband/your_fate
+ name = "Твоя судьба"
+ desc = "На плакате изображается дом и ряд одинаковых домов уходящих вдаль, расположенных на кровавом полотне. Ниже можно разглядеть тень искореженной руки.\nНад домами возвышаются существа чертоватого вида, а надпись снизу гласит: \"Твоя судьба?\""
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "contraband6"
+
+/obj/structure/sign/poster/contraband/watching_eye
+ name = "Всевидящее Око"
+ desc = "На плакате изображен глаз, излучающий свет. Текст на плакате гласит: \"Оно следит за\", \"Тобой\"."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "contraband7"
+
+/obj/structure/sign/poster/contraband/argonian
+ name = "Аргонианская горничная"
+ desc = "Вы видите ящероподобную горничную. Вам раньше не доводилось видеть подобную расу, однако она имеет некоторые сходства с унатхами."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "contraband8"
+
+// MARK: Legit
+/obj/structure/sign/poster/official/mars
+ name = "Плакат Марса"
+ desc = "Это плакат, выпущенный компанией Generic Space в рамках серии памятных плакатов, посвящённых чудесам космоса."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "legit1"
+
+/obj/structure/sign/poster/official/wild_west
+ name = "Дикое Карго"
+ desc = "Красивое дикое место с собственным шерифом."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "legit2"
+
+/obj/structure/sign/poster/official/razumause
+ name = "Разумышь"
+ desc = "Хей-хей! Что может пойти не так, да?"
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "legit3"
+
+/obj/structure/sign/poster/official/assist_pride
+ name = "Гордость ассистента"
+ desc = "Даже в космосе профессия ассистента востребована. И этот плакат демонстрирует их красоту."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "legit4"
+
+/obj/structure/sign/poster/official/taa
+ name = "Плохой парень"
+ desc = "Лицо того, кто погряз в непомерном курении."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "legit5"
+
+/obj/structure/sign/poster/official/mac_vulpix
+ name = "Коммерческий постер MacVulpix"
+ desc = "Рекламный постер с новой линейкой продукции “Большой Укус” от ресторана быстрого питания МакВульпикс."
+ icon = 'modular_ss220/objects/icons/posters.dmi'
+ icon_state = "legit6"
+
+/obj/item/poster/mac_vulpix
+ name = "Постер MacVulpix"
+ desc = "Рекламный постер с новой линейкой продукции “Большой Укус” от ресторана быстрого питания МакВульпикс."
+ icon_state = "rolled_poster_legit"
+ poster_type = /obj/structure/sign/poster/official/mac_vulpix
diff --git a/modular_ss220/objects/code/shuttle.dm b/modular_ss220/objects/code/shuttle.dm
new file mode 100644
index 000000000000..f64ceb72f7f0
--- /dev/null
+++ b/modular_ss220/objects/code/shuttle.dm
@@ -0,0 +1,25 @@
+/obj/machinery/computer/shuttle/vox
+ name = "Scavenger console"
+ desc = "Консоль контроля полета шаттла мусорщиков."
+ shuttleId = "vox_shuttle"
+ possible_destinations = "vox_shuttle_home;vox_shuttle_away;vox_shuttle_custom"
+ req_access = list(ACCESS_VOX)
+ resistance_flags = INDESTRUCTIBLE
+ flags = NODECONSTRUCT
+
+/obj/machinery/computer/shuttle/vox/attack_ai(mob/user)
+ return
+
+/obj/machinery/computer/camera_advanced/shuttle_docker/vox
+ name = "Scavenger navigation computer"
+ desc = "Консоль навигации шаттла мусорщиков."
+ icon_screen = "navigation"
+ icon_keyboard = "med_key"
+ shuttleId = "vox_shuttle"
+ shuttlePortId = "vox_shuttle_custom"
+ view_range = 13
+ x_offset = 0
+ y_offset = 0
+ resistance_flags = INDESTRUCTIBLE
+ flags = NODECONSTRUCT
+ access_mining = FALSE
diff --git a/modular_ss220/objects/code/smartfridge.dm b/modular_ss220/objects/code/smartfridge.dm
new file mode 100644
index 000000000000..68d578745a38
--- /dev/null
+++ b/modular_ss220/objects/code/smartfridge.dm
@@ -0,0 +1,10 @@
+/obj/machinery/smartfridge/load(obj/I, mob/user)
+ var/item_loc_origin = I.loc
+ if(!..())
+ return FALSE
+
+ if(istype(item_loc_origin, /obj/item/gripper))
+ var/obj/item/gripper/gripper = item_loc_origin
+ gripper.drop_gripped_item(silent = TRUE)
+ I.forceMove(src)
+ return TRUE
diff --git a/modular_ss220/objects/code/tribune.dm b/modular_ss220/objects/code/tribune.dm
new file mode 100644
index 000000000000..f683a108fa27
--- /dev/null
+++ b/modular_ss220/objects/code/tribune.dm
@@ -0,0 +1,82 @@
+/obj/structure/tribune
+ name = "tribune"
+ icon = 'modular_ss220/objects/icons/tribune.dmi'
+ icon_state = "nt_tribune"
+ desc = "A sturdy wooden tribune. When you look at it, you want to start making a speech."
+ density = TRUE
+ anchored = FALSE
+ max_integrity = 100
+ resistance_flags = FLAMMABLE
+ var/buildstacktype = /obj/item/stack/sheet/wood
+ var/buildstackamount = 5
+ var/mover_dir = null
+ var/ini_dir = null
+
+/obj/structure/tribune/wrench_act(mob/user, obj/item/tool)
+ . = TRUE
+ default_unfasten_wrench(user, tool)
+
+/obj/structure/tribune/screwdriver_act(mob/user, obj/item/tool)
+ . = TRUE
+ if(flags & NODECONSTRUCT)
+ to_chat(user, span_warning("Try as you might, you can't figure out how to deconstruct [src]."))
+ return
+ if(!tool.use_tool(src, user, 30, volume = tool.tool_volume))
+ return
+ deconstruct(TRUE)
+
+/obj/structure/tribune/deconstruct()
+ // If we have materials, and don't have the NOCONSTRUCT flag
+ if(buildstacktype && (!(flags & NODECONSTRUCT)))
+ new buildstacktype(loc, buildstackamount)
+ ..()
+
+/obj/structure/tribune/proc/after_rotation(mob/user)
+ add_fingerprint(user)
+
+/obj/structure/tribune/Initialize(mapload) //Only for mappers
+ ..()
+ handle_layer()
+
+/obj/structure/tribune/setDir(newdir)
+ ..()
+ handle_layer()
+
+/obj/structure/tribune/Move(newloc, direct, movetime)
+ . = ..()
+ handle_layer()
+
+/obj/structure/tribune/proc/handle_layer()
+ if(dir == NORTH)
+ layer = LOW_ITEM_LAYER
+ else
+ layer = ABOVE_MOB_LAYER
+
+/obj/structure/tribune/AltClick(mob/user)
+ if(!Adjacent(user))
+ return
+ if(anchored)
+ to_chat(user, span_warning("It is fastened to the floor!"))
+ return
+ setDir(turn(dir, 90))
+ after_rotation(user)
+
+/obj/structure/tribune/CanPass(atom/movable/mover, turf/target, height=0)
+ if(istype(mover) && mover.checkpass(PASSGLASS))
+ return TRUE
+ if(get_dir(loc, target) == dir)
+ return !density
+ return TRUE
+
+/obj/structure/tribune/CheckExit(atom/movable/object, target)
+ if(istype(object) && object.checkpass(PASSGLASS))
+ return TRUE
+ if(get_dir(object.loc, target) == dir)
+ return FALSE
+ return TRUE
+
+/obj/structure/tribune/centcom
+ name = "CentCom tribune"
+ icon = 'modular_ss220/objects/icons/tribune.dmi'
+ icon_state = "nt_tribune_cc"
+ desc = "A richly decorated tribune. Just looking at her makes your heart skip a beat."
diff --git a/modular_ss220/objects/code/wallets.dm b/modular_ss220/objects/code/wallets.dm
new file mode 100644
index 000000000000..aab0dc25f601
--- /dev/null
+++ b/modular_ss220/objects/code/wallets.dm
@@ -0,0 +1,39 @@
+/obj/item/storage/wallet
+ var/photo_overlay = "photo"
+
+/obj/item/storage/wallet/wallet_NT
+ name = "leather wallet NT"
+ desc = "Ваш кошелек настолько шикарен, что с ним вы выглядите просто потрясающе."
+ icon = 'modular_ss220/objects/icons/wallets.dmi'
+ icon_state = "wallet_NT"
+ photo_overlay = "photo_NT"
+
+/obj/item/storage/wallet/wallet_USSP_1
+ name = "leather wallet USSP"
+ desc = "Говорят, такие кошельки в СССП носят исключительно для зажигалок."
+ icon = 'modular_ss220/objects/icons/wallets.dmi'
+ icon_state = "wallet_USSP_1"
+ photo_overlay = "photo_USSP"
+ storage_slots = 5
+
+/datum/prize_item/wallet_USSP_1
+ name = "Настоящий кошелёк СССП!"
+ desc = "Красота"
+ typepath = /obj/item/storage/wallet/wallet_USSP_1
+ cost = 35
+
+/obj/item/storage/wallet/wallet_USSP_2
+ name = "leather wallet USSP"
+ desc = "Говорят, такие кошельки в СССП носят исключительно для зажигалок."
+ icon = 'modular_ss220/objects/icons/wallets.dmi'
+ icon_state = "wallet_USSP_2"
+ photo_overlay = "photo_USSP"
+
+/obj/item/storage/wallet/wallet_wyci
+ name = "Кошелек W.Y.C.I."
+ desc = "Кошелек, законодателя моды WYCI,\
+ украшен золотой пуговицей cшит позолочеными и платиновыми нитями, сверх прочный.\
+ И сверх модный. И сверх дорогой. И сшит по принципу WYCI."
+ icon = 'modular_ss220/objects/icons/wallets.dmi'
+ icon_state = "wallet_wyci"
+ photo_overlay = "photo_wyci_overlay"
diff --git a/modular_ss220/objects/code/weapons/melee/baseball_bat.dm b/modular_ss220/objects/code/weapons/melee/baseball_bat.dm
new file mode 100644
index 000000000000..09f96305d243
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/melee/baseball_bat.dm
@@ -0,0 +1,77 @@
+// Тактическая бита Флота Nanotrasen
+/obj/item/melee/baseball_bat/homerun/central_command
+ name = "Nanotrasen Fleet tactical bat"
+ desc = "Выдвижная тактическая бита Центрального Командования Nanotrasen. \
+ В официальных документах эта бита проходит под элегантным названием \"Высокоскоростная система доставки СРП\". \
+ Выдаваясь только самым верным и эффективным офицерам Nanotrasen, это оружие является одновременно символом статуса \
+ и инструментом высшего правосудия."
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+
+ var/on = FALSE
+ /// Force when concealed
+ force = 5
+ /// Force when extended
+ var/force_on = 20
+
+ lefthand_file = 'modular_ss220/objects/icons/inhands/melee_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/melee_righthand.dmi'
+ icon = 'modular_ss220/objects/icons/melee.dmi'
+ /// Item state when concealed
+ item_state = "centcom_bat_0"
+ /// Item state when extended
+ var/item_state_on = "centcom_bat_1"
+ /// Icon state when concealed
+ icon_state = "centcom_bat_0"
+ /// Icon state when extended
+ var/icon_state_on = "centcom_bat_1"
+ /// Sound to play when concealing or extending
+ var/extend_sound = 'sound/weapons/batonextend.ogg'
+ /// Attack verbs when concealed (created on Initialize)
+ attack_verb = list("hit", "poked")
+ /// Attack verbs when extended (created on Initialize)
+ var/list/attack_verb_on = list("smacked", "struck", "cracked", "beaten")
+
+/obj/item/melee/baseball_bat/homerun/central_command/pickup(mob/living/user)
+ . = ..()
+ if(!(user.mind.offstation_role))
+ user.Weaken(10 SECONDS)
+ user.unEquip(src, force, silent = FALSE)
+ to_chat(user, span_userdanger("Это - оружие истинного правосудия. Тебе не дано обуздать его мощь."))
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.apply_damage(rand(force/2, force), BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
+ else
+ user.adjustBruteLoss(rand(force/2, force))
+
+/obj/item/melee/baseball_bat/homerun/central_command/attack_self__legacy__attackchain(mob/user)
+ on = !on
+
+ if(on)
+ to_chat(user, span_userdanger("Вы активировали [name] - время для правосудия!"))
+ item_state = item_state_on
+ icon_state = icon_state_on
+ w_class = WEIGHT_CLASS_HUGE
+ force = force_on
+ attack_verb = attack_verb_on
+ else
+ to_chat(user, span_notice("Вы деактивировали [name]."))
+ item_state = initial(item_state)
+ icon_state = initial(icon_state)
+ w_class = initial(w_class)
+ force = initial(force)
+ attack_verb = initial(attack_verb)
+
+ homerun_able = on
+ // Update mob hand visuals
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+ playsound(loc, extend_sound, 50, TRUE)
+ add_fingerprint(user)
+
+/obj/item/melee/baseball_bat/homerun/central_command/attack__legacy__attackchain(mob/living/target, mob/living/user)
+ if(on)
+ homerun_ready = TRUE
+ . = ..()
diff --git a/modular_ss220/objects/code/weapons/melee/electrostaff.dm b/modular_ss220/objects/code/weapons/melee/electrostaff.dm
new file mode 100644
index 000000000000..5550f3386b22
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/melee/electrostaff.dm
@@ -0,0 +1,166 @@
+/obj/item/melee/baton/electrostaff
+ name = "electrostaff"
+ desc = "Шоковая палка, только более мощная, двуручная и доступная наиболее авторитетным членам силовых структур Nanotrasen. А еще у неё нет тупого конца."
+ lefthand_file = 'modular_ss220/objects/icons/inhands/melee_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/melee_righthand.dmi'
+ icon = 'modular_ss220/objects/icons/melee.dmi'
+ base_icon = "electrostaff"
+ icon_state = "electrostaff_orange"
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_HUGE
+ force = 10
+ throwforce = 7
+ origin_tech = "combat=5"
+ attack_verb = list("attacked", "beaten")
+ /// What sound plays when its opening
+ var/sound_on = 'modular_ss220/objects/sound/weapons/melee/electrostaff/on.ogg'
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, RAD = 0, FIRE = 80, ACID = 80)
+
+ stam_damage = 80
+ /// How much burn damage it does when turned on
+ var/burn_damage = 5
+
+ turned_on = FALSE
+ knockdown_duration = 15 SECONDS
+ hitcost = 1600 // 6 hits to 0 power
+ cooldown = 3.5 SECONDS
+ knockdown_delay = 2.5 SECONDS
+
+ /// allows one-time reskinning
+ var/unique_reskin = TRUE
+ /// the skin choice
+ var/current_skin = null
+ var/list/options = list()
+
+/obj/item/melee/baton/electrostaff/Initialize(mapload)
+ current_skin = "_orange"
+ AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = NON_PROJECTILE_ATTACKS)
+ AddComponent(/datum/component/two_handed, force_unwielded = force / 2, force_wielded = force, wield_callback = CALLBACK(src, PROC_REF(on_wield)), unwield_callback = CALLBACK(src, PROC_REF(on_unwield)))
+ options["Оранжевое свечение"] = "_orange"
+ options["Красное свечение"] = "_red"
+ options["Фиолетовое свечение"] = "_purple"
+ options["Синее свечение"] = "_blue"
+ . = ..()
+
+/obj/item/melee/baton/electrostaff/loaded/Initialize(mapload) //this one starts with a cell pre-installed.
+ link_new_cell()
+ . = ..()
+
+/obj/item/melee/baton/electrostaff/update_icon_state()
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
+ if(cell?.charge >= hitcost)
+ icon_state = "[base_icon][current_skin]_active"
+ else
+ if(cell != null)
+ icon_state = "[base_icon][current_skin]_wield"
+ else
+ icon_state = "[base_icon][current_skin]_nocell_wield"
+ else
+ if(cell != null)
+ icon_state = "[base_icon][current_skin]"
+ else
+ icon_state = "[base_icon][current_skin]_nocell"
+
+/obj/item/melee/baton/electrostaff/examine(mob/user)
+ . = ..()
+ if(unique_reskin)
+ . += span_notice("Alt-click, to reskin it.")
+
+/obj/item/melee/baton/electrostaff/attack_self__legacy__attackchain(mob/user)
+ var/signal_ret = SEND_SIGNAL(src, COMSIG_ACTIVATE_SELF, user)
+ if(signal_ret & COMPONENT_NO_INTERACT)
+ return
+ if(signal_ret & COMPONENT_CANCEL_ATTACK_CHAIN)
+ return TRUE
+
+/obj/item/melee/baton/electrostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ if(!HAS_TRAIT(src, TRAIT_WIELDED))
+ return FALSE
+ . = ..()
+
+/obj/item/melee/baton/electrostaff/proc/on_wield(obj/item/source, mob/living/carbon/user)
+ after_turn(TRUE, user)
+
+/obj/item/melee/baton/electrostaff/proc/on_unwield(obj/item/source, mob/living/carbon/user)
+ turned_on = FALSE
+ after_turn(FALSE, user)
+
+/obj/item/melee/baton/electrostaff/proc/after_turn(to_turn_on, mob/living/carbon/user)
+ if(cell?.charge >= hitcost)
+ if(to_turn_on)
+ turned_on = TRUE
+ to_chat(user, span_notice("[src] [turned_on ? "включен" : "выключен"]."))
+ playsound(src, turned_on ? sound_on : "sparks", 75, TRUE, -1)
+ else
+ if(!cell)
+ to_chat(user, span_warning("[src] не имеет источников питания!"))
+ else
+ to_chat(user, span_warning("[src] обесточен."))
+ update_icon()
+ add_fingerprint(user)
+
+/// returning false results in no baton attack animation, returning true results in an animation.
+/obj/item/melee/baton/electrostaff/baton_stun(mob/living/L, mob/user, skip_cooldown = FALSE, ignore_shield_check = FALSE)
+ . = ..(L, user, skip_cooldown)
+ if(. == TRUE)
+ if(user.a_intent == INTENT_HARM)
+ L.apply_damage(burn_damage, BURN)
+
+/obj/item/melee/baton/electrostaff/AltClick(mob/user)
+ . = ..()
+ if(user.incapacitated())
+ to_chat(user, span_warning("Вы не можете этого сделать прямо сейчас!"))
+ return
+ if(unique_reskin && loc == user)
+ reskin_staff(user)
+
+/obj/item/melee/baton/electrostaff/proc/reskin_staff(mob/M)
+ var/list/skins = list()
+ for(var/I in options)
+ skins[I] = image(icon, icon_state = "[base_icon][options[I]]")
+ var/choice = show_radial_menu(M, src, skins, radius = 40, custom_check = CALLBACK(src, PROC_REF(reskin_radial_check), M), require_near = TRUE)
+
+ if(choice && reskin_radial_check(M))
+ current_skin = options[choice]
+ to_chat(M, "[choice] идеально подходит вашему посоху.")
+ unique_reskin = FALSE
+ update_icon()
+ M.update_inv_r_hand()
+ M.update_inv_l_hand()
+
+/obj/item/melee/baton/electrostaff/proc/reskin_radial_check(mob/user)
+ if(!ishuman(user))
+ return FALSE
+ var/mob/living/carbon/human/H = user
+ if(!src || !H.is_in_hands(src) || HAS_TRAIT(H, TRAIT_HANDS_BLOCKED))
+ return FALSE
+ return TRUE
+
+/obj/item/weaponcrafting/gunkit/electrostaff
+ name = "electrostaff parts kit"
+ desc = "Возьмите 2 оглушающие дубинки. Соедините их вместе, поместив внутрь батарею. Используйте остальные инструменты (лишних винтиков быть не должно)."
+ origin_tech = "combat=6;materials=4"
+ outcome = /obj/item/melee/baton/electrostaff/loaded
+
+/datum/design/electrostaff
+ name = "Electrostaff Parts Kit"
+ desc = "Оперативный ответ."
+ id = "electrostaff"
+ req_tech = list("combat" = 7, "magnets" = 5, "powerstorage" = 5)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 4000, MAT_GLASS = 1000, MAT_GOLD = 3000, MAT_SILVER = 1500)
+ build_path = /obj/item/weaponcrafting/gunkit/electrostaff
+ category = list("Weapons")
+
+/datum/crafting_recipe/electrostaff
+ name = "Electrostaff"
+ tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
+ result = list(/obj/item/melee/baton/electrostaff/loaded)
+ reqs = list(/obj/item/melee/baton = 2,
+ /obj/item/stock_parts/cell/high = 1,
+ /obj/item/stack/cable_coil = 5,
+ /obj/item/assembly/signaler/anomaly/flux = 1,
+ /obj/item/weaponcrafting/gunkit/electrostaff = 1)
+ time = 10 SECONDS
+ category = CAT_WEAPONRY
+ subcategory = CAT_WEAPON
diff --git a/modular_ss220/objects/code/weapons/melee/stylet.dm b/modular_ss220/objects/code/weapons/melee/stylet.dm
new file mode 100644
index 000000000000..a7aa9a0978e1
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/melee/stylet.dm
@@ -0,0 +1,57 @@
+/obj/item/melee/stylet
+ name = "stylet"
+ desc = "Маленький складной нож скрытого ношения. \
+ Нож в итальянском стиле, который исторически стал предметом споров и даже запретов \
+ Его лезвие практически мгновенно выбрасывается при нажатии кнопки-качельки."
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_TINY
+
+ var/on = FALSE
+ force = 2
+ var/force_on = 8
+
+ lefthand_file = 'modular_ss220/objects/icons/inhands/melee_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/melee_righthand.dmi'
+ icon = 'modular_ss220/objects/icons/melee.dmi'
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ item_state = "stylet_0"
+ var/item_state_on = "stylet_1"
+ icon_state = "stylet_0"
+ var/icon_state_on = "stylet_1"
+ var/extend_sound = 'modular_ss220/objects/sound/weapons/styletext.ogg'
+ attack_verb = list("hit", "poked")
+ sharp = TRUE
+ var/list/attack_verb_on = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+
+/obj/item/melee/stylet/update_icon_state()
+ . = ..()
+ if(on)
+ icon_state = "stylet_1"
+ else
+ icon_state = "stylet_0"
+
+/obj/item/melee/stylet/attack_self__legacy__attackchain(mob/user)
+ on = !on
+
+ if(on)
+ to_chat(user, span_userdanger("Вы разложили [name]."))
+ item_state = item_state_on
+ update_icon(UPDATE_ICON_STATE)
+ w_class = WEIGHT_CLASS_SMALL
+ force = force_on
+ attack_verb = attack_verb_on
+ else
+ to_chat(user, span_notice("Вы сложили [name]."))
+ item_state = initial(item_state)
+ update_icon(UPDATE_ICON_STATE)
+ w_class = initial(w_class)
+ force = initial(force)
+ attack_verb = initial(attack_verb)
+
+ // Update mob hand visuals
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+ playsound(loc, extend_sound, 50, TRUE)
+ add_fingerprint(user)
diff --git a/modular_ss220/objects/code/weapons/melee/vibroblade.dm b/modular_ss220/objects/code/weapons/melee/vibroblade.dm
new file mode 100644
index 000000000000..37667a1006e8
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/melee/vibroblade.dm
@@ -0,0 +1,173 @@
+// MARK: Vibroblade
+#define CHARGE_LEVEL_NONE 0
+#define CHARGE_LEVEL_LOW 1
+#define CHARGE_LEVEL_MEDIUM 2
+#define CHARGE_LEVEL_HIGH 3
+#define CHARGE_LEVEL_OVERCHARGE 4
+
+/obj/item/melee/vibroblade
+ name = "\improper vibroblade"
+ desc = "Виброклинок воинов Раскинта. Микрогенератор ультразвука в рукояти позволяет лезвию вибрировать \
+ с огромной частотой, что позволяет при его достаточной зарядке наносить глубокие раны даже ударами по касательной."
+ icon = 'modular_ss220/objects/icons/melee.dmi'
+ icon_state = "vibroblade"
+ item_state = "vibroblade"
+ lefthand_file = 'modular_ss220/objects/icons/inhands/melee_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/melee_righthand.dmi'
+ hitsound = 'modular_ss220/objects/sound/weapons/melee/sardaukar/knifehit1.ogg'
+ drop_sound = 'modular_ss220/aesthetics_sounds/sound/handling/drop/knife.ogg'
+ pickup_sound = 'modular_ss220/objects/sound/weapons/melee/sardaukar/equip.ogg'
+ attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ force = 20
+ throwforce = 15
+ throw_speed = 2
+ throw_range = 5
+ armour_penetration_percentage = 75
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_NORMAL
+ sharp = TRUE
+ flags = CONDUCT
+ var/charge_level = CHARGE_LEVEL_NONE
+ var/max_charge_level = CHARGE_LEVEL_OVERCHARGE
+ /// How long does it take to reach next level of charge.
+ var/charge_time = 4 SECONDS
+ /// TRUE if the item keeps charge only when is held in hands. FALSE if the item always keeps charge.
+ var/hold_to_be_charged = TRUE
+ var/emp_proof = FALSE
+ /// Body parts that can be cut off.
+ var/list/cutoff_candidates = list(
+ BODY_ZONE_L_LEG,
+ BODY_ZONE_R_LEG,
+ BODY_ZONE_L_ARM,
+ BODY_ZONE_R_ARM,
+ BODY_ZONE_PRECISE_L_FOOT,
+ BODY_ZONE_PRECISE_R_FOOT,
+ BODY_ZONE_PRECISE_L_HAND,
+ BODY_ZONE_PRECISE_R_HAND,
+ )
+
+/obj/item/melee/vibroblade/Initialize(mapload)
+ . = ..()
+ RegisterSignal(src, COMSIG_MOVABLE_POST_THROW, PROC_REF(thrown))
+ AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
+
+/obj/item/melee/vibroblade/Destroy()
+ . = ..()
+ UnregisterSignal(src, COMSIG_MOVABLE_POST_THROW)
+
+/obj/item/melee/vibroblade/update_icon_state()
+ icon_state = initial(icon_state) + (charge_level > CHARGE_LEVEL_NONE ? "_[charge_level]" : "")
+
+/obj/item/melee/vibroblade/examine(mob/user)
+ . = ..()
+ . += span_notice("Используйте [src] в руке, чтобы повысить уровень заряда.")
+ if(charge_level == CHARGE_LEVEL_NONE)
+ . += span_notice("[src] не заряжен.")
+ return
+
+ . += span_notice("[src] заряжен на [(charge_level / max_charge_level)*100]%.")
+ . += charge_level == max_charge_level \
+ ? span_danger("Следующий удар будет крайне травмирующим!") \
+ : span_warning("Следующий удар будет усиленным!")
+
+/obj/item/melee/vibroblade/attack_self__legacy__attackchain(mob/living/user)
+ . = ..()
+ if(charge_level >= max_charge_level)
+ user.visible_message(
+ span_notice("[user.name] пытается зарядить [src], но кнопка на рукояти не поддается!"),
+ span_notice("Вы пытаетесь нажать на кнопку зарядки [src], но она заблокирована.")
+ )
+ return FALSE
+
+ user.visible_message(
+ span_notice("[user.name] нажимает на кнопку зарядки [src]..."),
+ span_notice("Вы нажимаете на кнопку зарядки [src], заряжая микрогенератор...")
+ )
+
+ if(!do_after_once(user, charge_time, allow_moving = TRUE, must_be_held = TRUE, target = src))
+ return
+ playsound(loc, 'sound/effects/sparks3.ogg', vol = 10, vary = TRUE)
+ do_sparks(1, TRUE, src)
+ set_charge_level(charge_level + 1)
+
+/obj/item/melee/vibroblade/pre_attack(atom/A, mob/living/user, params)
+ . = ..()
+ force = initial(force) * get_damage_factor()
+
+/obj/item/melee/vibroblade/attack__legacy__attackchain(mob/living/target, mob/living/user, def_zone)
+ var/obj/item/organ/external/selected_bodypart
+ if(user.zone_selected in cutoff_candidates)
+ selected_bodypart = target.get_organ(user.zone_selected)
+ . = ..()
+
+ if(charge_level == CHARGE_LEVEL_HIGH)
+ target.Weaken(1.5 SECONDS)
+ else if(charge_level == CHARGE_LEVEL_OVERCHARGE && selected_bodypart && istype(target, /mob/living/carbon/human))
+ var/obj/item/organ/external/after_attack_bodypart = target.get_organ(user.zone_selected)
+
+ // We compare these in case the body part hasn't been cut off by standard attack logic
+ if(after_attack_bodypart == selected_bodypart)
+ after_attack_bodypart.droplimb(TRUE, DROPLIMB_SHARP)
+ user.visible_message(
+ span_danger("[user] изящно и непринужденно отсекает [selected_bodypart] [target]!"),
+ span_biggerdanger("Вы искусно отсекаете [selected_bodypart] [target]!")
+ )
+
+ set_charge_level(CHARGE_LEVEL_NONE)
+
+/obj/item/melee/vibroblade/suicide_act(mob/living/carbon/human/user)
+ var/obj/item/organ/external/head = user.get_organ(BODY_ZONE_HEAD)
+ user.visible_message(span_suicide("[user] прижимает лезвие [src] к своей шее и нажимает на кнопку зарядки микрогенератора. \
+ Кажется, это попытка самоубийства!"))
+ user.atom_say("Слава Вечной Империи!")
+ head.droplimb(TRUE, DROPLIMB_SHARP, FALSE, TRUE)
+ set_charge_level(CHARGE_LEVEL_NONE)
+ return BRUTELOSS
+
+/obj/item/melee/vibroblade/emp_act(severity)
+ . = ..()
+ if(emp_proof)
+ return
+ set_charge_level(CHARGE_LEVEL_NONE)
+
+/obj/item/melee/vibroblade/equipped(mob/user, slot, initial)
+ . = ..()
+ if(hold_to_be_charged && slot != ITEM_SLOT_LEFT_HAND && slot != ITEM_SLOT_RIGHT_HAND)
+ set_charge_level(CHARGE_LEVEL_NONE)
+
+/obj/item/melee/vibroblade/dropped(mob/user, silent)
+ . = ..()
+ if(hold_to_be_charged && !silent)
+ set_charge_level(CHARGE_LEVEL_NONE)
+
+/obj/item/melee/vibroblade/proc/thrown(datum/thrownthing/thrown_thing, spin)
+ SIGNAL_HANDLER
+ if(hold_to_be_charged)
+ set_charge_level(CHARGE_LEVEL_NONE)
+
+/obj/item/melee/vibroblade/proc/get_damage_factor()
+ return 1 + 0.25 * clamp(charge_level, CHARGE_LEVEL_NONE, max_charge_level)
+
+/obj/item/melee/vibroblade/proc/set_charge_level(charge_level)
+ src.charge_level = charge_level
+ force = initial(force) * get_damage_factor()
+ update_icon(UPDATE_ICON_STATE)
+
+/obj/item/melee/vibroblade/sardaukar
+ name = "\improper emperor guard vibroblade"
+ desc = "Виброклинок гвардейцев Императора. Микрогенератор ультразвука в рукояти позволяет лезвию вибрировать \
+ с огромной частотой, что позволяет при его достаточной зарядке наносить глубокие раны даже ударами по касательной. \
+ Воины Куи'кверр-Кэтиш обучаются мастерству ближнего боя с детства, поэтому в их руках он особо опасен и жесток. \
+ Каждый будущий гвардеец добывает свой клинок в ритуальном бою, и его сохранность есть вопрос жизни и смерти владельца."
+ icon_state = "vibroblade_elite"
+ item_state = "vibroblade_elite"
+ force = 25
+ charge_time = 2 SECONDS
+ hold_to_be_charged = FALSE
+ emp_proof = TRUE
+
+#undef CHARGE_LEVEL_NONE
+#undef CHARGE_LEVEL_LOW
+#undef CHARGE_LEVEL_MEDIUM
+#undef CHARGE_LEVEL_HIGH
+#undef CHARGE_LEVEL_OVERCHARGE
diff --git a/modular_ss220/objects/code/weapons/ranged/beretta.dm b/modular_ss220/objects/code/weapons/ranged/beretta.dm
new file mode 100644
index 000000000000..efb6b1f844e4
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/ranged/beretta.dm
@@ -0,0 +1,217 @@
+// Beretta M9
+/obj/item/gun/projectile/automatic/pistol/beretta
+ name = "Beretta M9"
+ desc = "Один из самых распространенных и узнаваемых пистолетов во вселенной. К сожалению, из-за особенности ствола, на пистолет нельзя приделать глушитель. Старая добрая классика."
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ icon_state = "beretta_modified"
+ item_state = "beretta_modified"
+ w_class = WEIGHT_CLASS_NORMAL
+ can_suppress = FALSE
+ can_flashlight = TRUE
+ unique_reskin = TRUE
+ mag_type = /obj/item/ammo_box/magazine/beretta
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/beretta_shot.ogg'
+
+/obj/item/gun/projectile/automatic/pistol/beretta/Initialize(mapload)
+ . = ..()
+ options["Modified grip"] = "beretta_modified"
+ options["Black skin"] = "beretta_black"
+ options["Desert skin"] = "beretta_desert"
+
+/obj/item/gun/projectile/automatic/pistol/beretta/update_icon_state()
+ if(current_skin)
+ icon_state = "[current_skin][chambered ? "" : "-e"]"
+ else
+ icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
+
+/obj/item/gun/projectile/automatic/pistol/beretta/update_overlays()
+ . = list()
+ if(gun_light)
+ var/flashlight = "beretta_light"
+ if(gun_light.on)
+ flashlight = "beretta_light-on"
+ . += image(icon = icon, icon_state = flashlight, pixel_x = 0)
+
+/obj/item/gun/projectile/automatic/pistol/beretta/ui_action_click()
+ toggle_gunlight()
+
+// Beretta Ammo Boxes
+/obj/item/ammo_box/beretta
+ name = "box of rubber 9x19mm cartridges"
+ desc = "Содержит до 30 резиновых патронов калибра 9x19mm."
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "9mmr_box"
+ w_class = WEIGHT_CLASS_NORMAL
+ ammo_type = /obj/item/ammo_casing/beretta/mmrub919
+ max_ammo = 30
+
+/obj/item/ammo_box/beretta/mm919
+ name = "box of lethal 9x19mm cartridges"
+ desc = "Содержит до 20 летальных патронов калибра 9x19mm."
+ icon_state = "9mm_box"
+ ammo_type = /obj/item/ammo_casing/beretta/mm919
+ max_ammo = 20
+
+/obj/item/ammo_box/beretta/mmbsp919
+ name = "box of bluespace 9x19mm cartridges"
+ desc = "Содержит до 20 Блюспейс патронов калибра 9x19mm."
+ icon_state = "9mmb_box"
+ ammo_type = /obj/item/ammo_casing/beretta/mmbsp919
+ max_ammo = 20
+
+/obj/item/ammo_box/beretta/mmap919
+ name = "box of armor-penetration 9x19mm cartridges"
+ desc = "Содержит до 20 бронебойных патронов калибра 9x19mm."
+ icon_state = "9mmap_box"
+ ammo_type = /obj/item/ammo_casing/beretta/mmap919
+ max_ammo = 20
+
+// Beretta Magazines
+/obj/item/ammo_box/magazine/beretta
+ name = "beretta rubber 9x19mm magazine"
+ desc = "Магазин резиновых патронов калибра 9x19mm."
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "berettar"
+ multi_sprite_step = 2
+ ammo_type = /obj/item/ammo_casing/beretta/mmrub919
+ max_ammo = 10
+ multiload = 0
+ slow_loading = TRUE
+ caliber = "919mm"
+
+/obj/item/ammo_box/magazine/beretta/mm919
+ name = "beretta lethal 9x19mm magazine"
+ desc = "Магазин летальных патронов калибра 9x19mm."
+ icon_state = "berettal"
+ ammo_type = /obj/item/ammo_casing/beretta/mm919
+
+/obj/item/ammo_box/magazine/beretta/mmbsp919
+ name = "beretta bluespace 9x19mm magazine"
+ desc = "Магазин экспериментальных Блюспейс патронов калибра 9x19mm. Из-за особенности корпуса вмещает только Блюспейс патроны."
+ icon_state = "berettab"
+ ammo_type = /obj/item/ammo_casing/beretta/mmbsp919
+ caliber = "919bmm"
+
+/obj/item/ammo_box/magazine/beretta/mmap919
+ name = "beretta armor-piercing 9x19mm magazine"
+ desc = "Магазин бронебойных патронов калибра 9x19mm."
+ icon_state = "berettaap"
+ ammo_type = /obj/item/ammo_casing/beretta/mmap919
+
+// Beretta Casings
+/obj/item/ammo_casing/beretta/mmbsp919
+ name = "9x19mm bluespace bullet casing"
+ desc = "A 9x19mm bluespace bullet casing."
+ caliber = "919bmm"
+ projectile_type = /obj/item/projectile/bullet/mmbsp919
+
+/obj/item/ammo_casing/beretta/mmap919
+ name = "9x19mm armor-piercing bullet casing"
+ desc = "A 9x19 armor-piercing bullet casing."
+ caliber = "919mm"
+ projectile_type = /obj/item/projectile/bullet/mmap919
+
+/obj/item/ammo_casing/beretta/mmrub919
+ name = "9x19mm rubber bullet casing"
+ desc = "A 9x19 rubber bullet casing."
+ caliber = "919mm"
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "casingmm919"
+ projectile_type = /obj/item/projectile/bullet/weakbullet4
+
+/obj/item/ammo_casing/beretta/mm919
+ name = "9x19mm lethal bullet casing"
+ desc = "A 9x19 lethal bullet casing."
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "casingmm919"
+ caliber = "919mm"
+ projectile_type = /obj/item/projectile/bullet/weakbullet3
+
+// Beretta Projectiles
+/obj/item/projectile/bullet/mmap919
+ name = "9x19mm armor-piercing bullet"
+ damage = 18
+ armour_penetration_percentage = 35
+ armour_penetration_flat = 15
+
+/obj/item/projectile/bullet/mmbsp919
+ name = "9x19 bluespace bullet"
+ damage = 18
+ speed = 0.2
+
+// Beretta Supply Packs
+/datum/supply_packs/security/armory/beretta
+ name = "Beretta M9 Crate"
+ contains = list(/obj/item/gun/projectile/automatic/pistol/beretta,
+ /obj/item/gun/projectile/automatic/pistol/beretta)
+ cost = 650
+ containername = "beretta m9 pack"
+
+/datum/supply_packs/security/armory/berettarubberammo
+ name = "Beretta M9 Rubber Ammunition Crate"
+ contains = list(/obj/item/ammo_box/beretta,
+ /obj/item/ammo_box/beretta,
+ /obj/item/ammo_box/magazine/beretta,
+ /obj/item/ammo_box/magazine/beretta)
+ cost = 350
+ containername = "beretta rubber ammunition pack"
+
+/datum/supply_packs/security/armory/berettalethalammo
+ name = "Beretta M9 Lethal Ammunition Crate"
+ contains = list(/obj/item/ammo_box/beretta/mm919,
+ /obj/item/ammo_box/beretta/mm919,
+ /obj/item/ammo_box/magazine/beretta/mm919,
+ /obj/item/ammo_box/magazine/beretta/mm919)
+ cost = 400
+ containername = "beretta lethal ammunition pack"
+
+/datum/supply_packs/security/armory/berettaexperimentalammo
+ name = "Beretta M9 Bluespace Ammunition Crate"
+ contains = list(/obj/item/ammo_box/beretta/mmbsp919,
+ /obj/item/ammo_box/beretta/mmbsp919,
+ /obj/item/ammo_box/magazine/beretta/mmbsp919,
+ /obj/item/ammo_box/magazine/beretta/mmbsp919)
+ cost = 650
+ containername = "beretta bluespace ammunition pack"
+
+/datum/supply_packs/security/armory/berettaarmorpiercingammo
+ name = "Beretta M9 Armor-piercing Ammunition Crate"
+ contains = list(/obj/item/ammo_box/beretta/mmap919,
+ /obj/item/ammo_box/beretta/mmap919,
+ /obj/item/ammo_box/magazine/beretta/mmap919,
+ /obj/item/ammo_box/magazine/beretta/mmap919)
+ cost = 500
+ containername = "beretta AP ammunition pack"
+
+// Beretta Designs
+/datum/design/box_beretta/lethal
+ name = "Beretta M9 Lethal Ammo Box (9mm)"
+ desc = "A box of 20 lethal rounds for Beretta M9."
+ id = "box_beretta"
+ req_tech = list("combat" = 2, "materials" = 1)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 6000, MAT_SILVER = 600)
+ build_path = /obj/item/ammo_box/beretta/mm919
+ category = list("Weapons")
+
+/datum/design/box_beretta/ap
+ name = "Beretta M9 AP Ammo Box (9mm)"
+ desc = "A box of 20 armor-piercing rounds for Beretta M9."
+ id = "box_beretta_ap"
+ req_tech = list("combat" = 3, "materials" = 2)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_GLASS = 1000)
+ build_path = /obj/item/ammo_box/beretta/mmap919
+ category = list("Weapons")
+
+/datum/design/box_beretta/bluespace
+ name = "Beretta M9 Bluespace Ammo Box (9mm)"
+ desc = "A box of 20 high velocity bluespace rounds for Beretta M9."
+ id = "box_beretta_bsp"
+ req_tech = list("combat" = 6, "materials" = 5, "bluespace" = 6)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 8000, MAT_SILVER = 600, MAT_BLUESPACE = 1000)
+ build_path = /obj/item/ammo_box/beretta/mmbsp919
+ category = list("Weapons")
diff --git a/modular_ss220/objects/code/weapons/ranged/pneumagun.dm b/modular_ss220/objects/code/weapons/ranged/pneumagun.dm
new file mode 100644
index 000000000000..45f04510d618
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/ranged/pneumagun.dm
@@ -0,0 +1,105 @@
+//Pneumagun
+/obj/item/gun/projectile/automatic/pneumaticgun
+ name = "pneumatic rifle"
+ desc = "Стандартное пневморужье с магазинным заряжанием."
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ icon_state = "pneumagun"
+ w_class = WEIGHT_CLASS_NORMAL
+ mag_type = /obj/item/ammo_box/magazine/pneuma
+ magazine = new /obj/item/ammo_box/magazine/pneuma/pepper
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/gunshot_pneumatic.ogg'
+ magin_sound = 'sound/weapons/gun_interactions/batrifle_magin.ogg'
+ magout_sound = 'sound/weapons/gun_interactions/batrifle_magout.ogg'
+ fire_delay = 2
+ can_suppress = FALSE
+ burst_size = 1
+ actions_types = list()
+
+/obj/item/gun/projectile/automatic/pneumaticgun/process_chamber(eject_casing = 0, empty_chamber = 1)
+ ..(eject_casing, empty_chamber)
+
+/obj/item/gun/projectile/automatic/pneumaticgun/update_icon_state()
+ var/obj/item/ammo_box/magazine/pneuma/M = magazine
+ icon_state = "pneumagun[M ? "[M.col]" : ""]"
+ item_state = icon_state
+
+// Базовые боеприпасы для пневморужья
+/obj/item/ammo_box/magazine/pneuma
+ name = "pneumatic rifle magazine"
+ desc = "Наполняется шариками с реагентом."
+ caliber = "pneumatic"
+ var/col = "_g" // Цвет магазина (необходим для выбора скина)
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "pneumamag_g"
+ ammo_type = /obj/item/ammo_casing/pneuma
+ max_ammo = 12
+ multiload = 0
+
+/obj/item/ammo_casing/pneuma
+ name = "pneumatic ball"
+ desc = "Пустой пневматический шарик."
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "pneumaball_g"
+ caliber = "pneumatic"
+ casing_drop_sound = null
+ projectile_type = /obj/item/projectile/bullet/pneumaball
+ muzzle_flash_strength = null
+ harmful = FALSE
+
+/obj/item/projectile/bullet/pneumaball
+ name = "pneumatic ball"
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "pneumaball_g"
+ stamina = 7
+ damage = 1
+
+/obj/item/projectile/bullet/pneumaball/New()
+ ..()
+ create_reagents(15)
+ reagents.set_reacting(FALSE)
+
+/obj/item/projectile/bullet/pneumaball/on_hit(atom/target, blocked = 0)
+ ..(target, blocked)
+ if(!iscarbon(target))
+ return
+ var/mob/living/carbon/H = target
+ reagents.reaction(H)
+ reagents.set_reacting(TRUE)
+ reagents.handle_reactions()
+
+// Боеприпасы для перцового типа пневморужья
+/obj/item/ammo_box/magazine/pneuma/pepper
+ ammo_type = /obj/item/ammo_casing/pneuma/pepper
+ col = "_r"
+ icon_state = "pneumamag_r"
+
+/obj/item/ammo_casing/pneuma/pepper
+ desc = "Шарик с капсаицином. Эффективно подходит для задержания преступников, не носящих очки."
+ projectile_type = /obj/item/projectile/bullet/pneumaball/pepper
+ icon_state = "pneumaball_r"
+
+/obj/item/projectile/bullet/pneumaball/pepper
+ icon_state = "pneumaball_r"
+
+/obj/item/projectile/bullet/pneumaball/pepper/New()
+ ..()
+ reagents.add_reagent("condensedcapsaicin", 15)
+
+/datum/supply_packs/security/armory/pneumagun
+ name = "Pneumatic Pepper Rifles Crate"
+ contains = list(/obj/item/gun/projectile/automatic/pneumaticgun,
+ /obj/item/gun/projectile/automatic/pneumaticgun,
+ /obj/item/ammo_box/magazine/pneuma/pepper,
+ /obj/item/ammo_box/magazine/pneuma/pepper)
+ cost = 500
+ containername = "pneumatic pepper rifles pack"
+
+/datum/supply_packs/security/armory/pneumapepperballs
+ name = "Pneumatic Pepper Rifle Ammunition Crate"
+ contains = list(/obj/item/ammo_box/magazine/pneuma/pepper,
+ /obj/item/ammo_box/magazine/pneuma/pepper,
+ /obj/item/ammo_box/magazine/pneuma/pepper)
+ cost = 250
+ containername = "pneumatic pepper ammunition pack"
diff --git a/modular_ss220/objects/code/weapons/ranged/revolvers.dm b/modular_ss220/objects/code/weapons/ranged/revolvers.dm
new file mode 100644
index 000000000000..b709294ddd99
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/ranged/revolvers.dm
@@ -0,0 +1,222 @@
+// Base Heavy Revolver
+/obj/item/gun/projectile/revolver/reclinable
+ var/snapback_sound = 'modular_ss220/objects/sound/weapons/cylinder/snapback_rsh12.ogg'
+ var/reclined_sound = 'modular_ss220/objects/sound/weapons/cylinder/reclined_rsh12.ogg'
+ var/dry_fire_sound = 'sound/weapons/empty.ogg'
+ var/reclined = FALSE
+
+/obj/item/gun/projectile/revolver/reclinable/attack_self__legacy__attackchain(mob/living/user)
+ reclined = !reclined
+ playsound(user, reclined ? reclined_sound : snapback_sound, 50, 1)
+ update_icon()
+
+ if(reclined)
+ return ..()
+
+/obj/item/gun/projectile/revolver/reclinable/update_icon_state()
+ icon_state = initial(icon_state) + (reclined ? "_reclined" : "")
+
+/obj/item/gun/projectile/revolver/reclinable/attackby__legacy__attackchain(obj/item/A, mob/user, params)
+ if(!reclined)
+ return
+ return ..()
+
+/obj/item/gun/projectile/revolver/reclinable/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
+ if(!reclined)
+ return ..()
+
+ to_chat(user, span_danger("*click*"))
+ playsound(user, dry_fire_sound, 100, 1)
+
+// Colt Anaconda .44
+/obj/item/gun/projectile/revolver/reclinable/anaconda
+ name = "Anaconda"
+ desc = "Крупнокалиберный револьвер двадцатого века. Несмотря на то, что оружие хранилось в хороших условиях, старина даёт о себе знать."
+ mag_type = /obj/item/ammo_box/magazine/internal/cylinder/d44
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ icon_state = "anaconda"
+ item_state = "anaconda"
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/gunshot_anaconda.ogg'
+
+/obj/item/gun/projectile/revolver/reclinable/anaconda/attackby__legacy__attackchain(obj/item/A, mob/user, params)
+ if(istype(A, /obj/item/ammo_box/box_d44))
+ return
+ return ..()
+
+/obj/item/ammo_box/magazine/internal/cylinder/d44
+ name = ".44 revolver cylinder"
+ ammo_type = /obj/item/ammo_casing/d44
+ caliber = "44"
+ max_ammo = 6
+
+/obj/item/ammo_casing/d44
+ desc = "A .44 bullet casing."
+ caliber = "44"
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "casing44"
+ projectile_type = /obj/item/projectile/bullet/d44
+ muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL
+ muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG
+
+/obj/item/projectile/bullet/d44
+ name = ".44 bullet"
+ icon_state = "bullet"
+ damage = 50
+ damage_type = BRUTE
+ flag = "bullet"
+ hitsound_wall = "ricochet"
+ impact_effect_type = /obj/effect/temp_visual/impact_effect
+ spread = 20
+
+/obj/item/ammo_box/speed_loader_d44
+ name = "speed loader (.44)"
+ desc = "Designed to quickly reload revolvers."
+ ammo_type = /obj/item/ammo_casing/d44
+ max_ammo = 6
+ multi_sprite_step = 1
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "44"
+
+/obj/item/ammo_box/box_d44
+ name = "ammo box (.44)"
+ desc = "Contains up to 24 .44 cartridges, intended to either be inserted into a speed loader or into the gun manually."
+ w_class = WEIGHT_CLASS_NORMAL
+ ammo_type = /obj/item/ammo_casing/d44
+ max_ammo = 24
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "44_box"
+
+/obj/item/gun/projectile/revolver/reclinable/judge
+ name = "\improper Judge"
+ desc = "Тяжёлый револьвер ружейного калибра. Несмотря на короткий ствол и высокую отдачу крайне эффективное оружие ближней дистанции."
+ mag_type = /obj/item/ammo_box/magazine/internal/cylinder/ga12
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ icon_state = "judge"
+ item_state = "judge"
+ w_class = WEIGHT_CLASS_NORMAL
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/gunshot_judge.ogg'
+ spread = 10
+ recoil = 2
+ fire_delay = 5
+
+/obj/item/ammo_box/magazine/internal/cylinder/ga12
+ name = ".12 revolver cylinder"
+ ammo_type = /obj/item/ammo_casing/shotgun/rubbershot
+ caliber = "shotgun"
+ max_ammo = 3
+
+// RSH-12 12.7
+/obj/item/gun/projectile/revolver/reclinable/rsh12
+ name = "RSh-12"
+ desc = "Тяжёлый револьвер винтовочного калибра с откидным стволом. По слухам, всё ещё находится на вооружении у СССП."
+ mag_type = /obj/item/ammo_box/magazine/internal/cylinder/rsh12
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ icon_state = "rsh12"
+ item_state = "rsh12"
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/gunshot_rsh12.ogg'
+
+/obj/item/gun/projectile/revolver/reclinable/rsh12/attackby__legacy__attackchain(obj/item/A, mob/user, params)
+ if(istype(A, /obj/item/ammo_box/box_mm127))
+ return
+ return ..()
+
+/obj/item/ammo_box/magazine/internal/cylinder/rsh12
+ name = "12.7mm revolver cylinder"
+ ammo_type = /obj/item/ammo_casing/mm127
+ caliber = "127mm"
+ max_ammo = 5
+
+/obj/item/ammo_casing/mm127
+ desc = "A 12.7mm bullet casing."
+ caliber = "127mm"
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "casing127mm"
+ projectile_type = /obj/item/projectile/bullet/mm127
+ muzzle_flash_strength = MUZZLE_FLASH_RANGE_STRONG
+ muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG
+
+/obj/item/projectile/bullet/mm127
+ name = "127mm bullet"
+ icon_state = "bullet"
+ damage = 75
+ damage_type = BRUTE
+ flag = "bullet"
+ hitsound_wall = "ricochet"
+ impact_effect_type = /obj/effect/temp_visual/impact_effect
+
+/obj/item/projectile/bullet/mm127/on_hit(atom/target, blocked, hit_zone)
+ . = ..()
+ if(!isliving(target))
+ return
+ var/mob/living/L = target
+ if(L.move_resist == INFINITY)
+ return
+ var/atom/throw_target = get_edge_target_turf(L, get_dir(src, get_step_away(L, starting)))
+ L.throw_at(throw_target, 2, 2)
+
+/obj/item/ammo_box/speed_loader_mm127
+ name = "speed loader (12.7mm)"
+ desc = "Designed to quickly reload... is it a revolver speedloader with rifle cartidges in it?"
+ ammo_type = /obj/item/ammo_casing/mm127
+ max_ammo = 5
+ multi_sprite_step = 1
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "mm127"
+
+/obj/item/ammo_box/box_mm127
+ name = "ammo box (12.7)"
+ desc = "Contains up to 100 12.7mm cartridges."
+ w_class = WEIGHT_CLASS_BULKY
+ ammo_type = /obj/item/ammo_casing/mm127
+ max_ammo = 100
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "mm127_box"
+
+// Peas Shooter
+/obj/item/gun/projectile/revolver/peas_shooter
+ name = "Peas Shooter"
+ desc = "Живой горох! Может стрелять горошинами, которые наносят слабый урон самооценке."
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ icon_state = "peas_shooter"
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/peas_shooter_gunshot.ogg'
+ drop_sound = 'modular_ss220/objects/sound/weapons/drop/peas_shooter_drop.ogg'
+ w_class = WEIGHT_CLASS_NORMAL
+ mag_type = /obj/item/ammo_box/magazine/peas_shooter
+
+/obj/item/ammo_box/magazine/peas_shooter
+ name = "peacock shooter magazine"
+ desc = "хранилище горошин для горохострела, вмещает до 6 горошин за раз."
+ ammo_type = /obj/item/ammo_casing/peas_shooter
+ max_ammo = 6
+
+/obj/item/ammo_casing/peas_shooter
+ name = "pea bullet"
+ desc = "Пуля из гороха, не может нанести какого-либо ощутимого урона."
+ projectile_type = /obj/item/projectile/bullet/midbullet_r/peas_shooter
+ icon_state = "peashooter_bullet"
+
+// Пуля горохострела
+/obj/item/projectile/bullet/midbullet_r/peas_shooter
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ item_state = "peashooter_bullet"
+ stamina = 5
+ damage = 0
+ var/additional_zombie_damage = 10
+
+/obj/item/projectile/bullet/midbullet_r/peas_shooter/prehit(atom/target)
+ if(HAS_TRAIT(target, TRAIT_I_WANT_BRAINS))
+ damage += additional_zombie_damage
+ return ..()
+
+/obj/item/projectile/bullet/midbullet_r/peas_shooter/on_hit(mob/H)
+ . = ..()
+ if(ishuman(H) && prob(15))
+ H.emote("moan")
diff --git a/modular_ss220/objects/code/weapons/ranged/sakhno.dm b/modular_ss220/objects/code/weapons/ranged/sakhno.dm
new file mode 100644
index 000000000000..cd1f09d88c25
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/ranged/sakhno.dm
@@ -0,0 +1,43 @@
+// MARK: Sakhno rifle
+/obj/item/gun/projectile/shotgun/boltaction/sakhno
+ name = "\improper Sakhno precision rifle"
+ desc = "Высокоточная винтовка Sakhno со скользящим затвором, которая была (и, безусловно, остается) крайне популярной среди \
+ покорителей фронтира, контрабандистов, ЧОП'овцев, исследователей, и прочих рисковых ребят. Эта модель \
+ была разработана и производится с 2440 года."
+ icon = 'modular_ss220/objects/icons/wide_guns.dmi'
+ icon_state = "sakhno"
+ item_state = "sakhno"
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/shot_heavy.ogg'
+ mag_type = /obj/item/ammo_box/magazine/internal/boltaction/sakhno
+ knife_x_offset = 30
+ knife_y_offset = 12
+
+/obj/item/ammo_box/magazine/internal/boltaction/sakhno
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "310"
+ ammo_type = /obj/item/ammo_casing/s310
+ caliber = "s310"
+ max_ammo = 5
+ multiload = 1
+
+// MARK: .310
+/obj/item/ammo_box/s310
+ name = "stripper clip (.310)"
+ desc = "A stripper clip for .310 cartridges, used in Sakhno rifles. Five round capacity."
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "310"
+ ammo_type = /obj/item/ammo_casing/s310
+ max_ammo = 5
+ multi_sprite_step = 1
+
+/obj/item/ammo_casing/s310
+ name = ".310 round"
+ desc = "A .310 rifle cartridge"
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "310-casing"
+ caliber = "s310"
+ projectile_type = /obj/item/projectile/bullet/midbullet3/hp
+ muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG
+ muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG
diff --git a/modular_ss220/objects/code/weapons/ranged/skrell_rifle.dm b/modular_ss220/objects/code/weapons/ranged/skrell_rifle.dm
new file mode 100644
index 000000000000..37782883759c
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/ranged/skrell_rifle.dm
@@ -0,0 +1,148 @@
+// MARK: Skrellian carbine
+/obj/item/gun/energy/gun/skrell_carbine
+ name = "\improper skrellian carbine"
+ desc = "Энергетический карабин Vuu'Xqu*ix T-3, более известный в ТСФ как 'VT-3'. Это оружие редко можно увидеть где-то, помимо ОСС. \
+ Имеет два режима мощности энерголуча: 'летальный' и 'штурмовой'. Второй предназначен для прорыва сквозь укрпеления противника."
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ item_state = "skrell_carbine"
+ icon_state = "skrell_carbine"
+ cell_type = /obj/item/stock_parts/cell/skrell_carbine_cell
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/skrell_light, /obj/item/ammo_casing/energy/laser/skrell_assault)
+ origin_tech = "combat=6;magnets=5"
+ modifystate = 2
+ execution_speed = 3 SECONDS
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/gun/energy/gun/skrell_carbine/elite
+ name = "\improper elite skrellian carbine"
+ desc = "Энергетический карабин Vuu'Xqu*ix T-3, более известный в ТСФ как 'VT-3'. Это оружие редко можно увидеть где-то, помимо ОСС. \
+ Этот экземпляр обладает батареей повышенной емкости, а так же дополнительными стабилизаторами стрельбы. \
+ Имеет два режима мощности энерголуча: 'летальный' и 'штурмовой'. Второй предназначен для прорыва сквозь укрпеления противника."
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/skrell_light/elite, /obj/item/ammo_casing/energy/laser/skrell_assault/elite)
+
+/obj/item/ammo_casing/energy/laser/skrell_light
+ projectile_type = /obj/item/projectile/beam/laser/skrell_light
+ muzzle_flash_color = LIGHT_COLOR_LAVENDER
+ select_name = "light"
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/blaster.ogg'
+
+/obj/item/ammo_casing/energy/laser/skrell_assault
+ projectile_type = /obj/item/projectile/beam/pulse/skrell_laser_assault
+ muzzle_flash_color = LIGHT_COLOR_LAVENDER
+ select_name = "assault"
+ e_cost = 1600
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/blaster.ogg'
+
+/obj/item/ammo_casing/energy/laser/skrell_light/elite
+ e_cost = 50
+
+/obj/item/ammo_casing/energy/laser/skrell_assault/elite
+ e_cost = 200
+
+/obj/item/projectile/beam/laser/skrell_light
+ name = "laser"
+ icon_state = "purple_laser"
+ damage = 23
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
+ light_color = LIGHT_COLOR_LAVENDER
+
+/obj/item/projectile/beam/pulse/skrell_laser_assault
+ name = "heavy laser"
+ icon_state = "u_laser_alt"
+ damage = 10
+ stamina = 80
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
+ light_color = LIGHT_COLOR_DARK_BLUE
+ weakened_against_rwalls = TRUE
+
+/obj/item/stock_parts/cell/skrell_carbine_cell
+ name = "\improper Vuu'Xqu*ix T-3 gun power cell"
+ maxcharge = 1600
+
+// MARK: Skrellian railgun rifle
+/obj/item/gun/projectile/automatic/sniper_rifle/skrell_rifle
+ name = "\improper skrellian rifle"
+ desc = "Винтовка Zquiv*Tzuuli-8, или ''ZT-8'' - это рельсотрон, стоящий на вооружении тяжелых штурмовых отрядов Раскинта из ОСС. \
+ Имеет цилиндрический магазин заряжания, разгонный магнитный блок и стабилизаторы для точной стрельбы."
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ icon_state = "sniper"
+ item_state = "sniper"
+ fire_sound = 'modular_ss220/objects/sound/weapons/gunshots/railgun.ogg'
+ recoil = 0
+ fire_delay = 25
+ slot_flags = ITEM_SLOT_BELT
+ zoomable = FALSE
+ can_suppress = FALSE
+ mag_type = /obj/item/ammo_box/magazine/skrell_magazine
+
+/obj/item/gun/projectile/automatic/sniper_rifle/skrell_rifle/elite
+ name = "\improper elite skrellian rifle"
+ desc = "Винтовка Zquiv*Tzuuli-8, или ''ZT-8'' - это рельсотрон, стоящий на вооружении тяжелых штурмовых отрядов Раскинта из ОСС. \
+ Имеет цилиндрический магазин заряжания, разгонный магнитный блок и стабилизаторы для точной стрельбы. \
+ Этот экземпляр обладает расширенным магазинным гнездом, а так же оптическим прицелом."
+ fire_delay = 20
+ zoomable = TRUE
+ mag_type = /obj/item/ammo_box/magazine/skrell_magazine/skrell_magazine_elite
+
+/obj/item/ammo_box/magazine/skrell_magazine
+ name = "\improper ammo cylinder"
+ desc = "Цилиндровый магазин для рельсотрона."
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "skrell_magazine"
+ multi_sprite_step = 3
+ ammo_type = /obj/item/ammo_casing/railgun
+ max_ammo = 4
+ caliber = "railgun"
+ multiload = TRUE
+
+/obj/item/ammo_box/magazine/skrell_magazine/skrell_magazine_elite
+ icon_state = "skrell_magazine_elite"
+ multi_sprite_step = 7
+ max_ammo = 8
+ ammo_type = /obj/item/ammo_casing/railgun/railgun_strong
+
+/obj/item/ammo_casing/railgun
+ name = "\improper railgun ammo casing"
+ desc = "Снаряд для рельсотрона. Состоит из поражающего элемента и магнитного стабилизатора."
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "railgun-casing"
+ caliber = "railgun"
+ projectile_type = /obj/item/projectile/bullet/railgun
+
+/obj/item/ammo_casing/railgun/railgun_strong
+ projectile_type = /obj/item/projectile/bullet/railgun/railgun_strong
+
+/obj/item/projectile/bullet/railgun
+ damage = 35
+ armour_penetration_flat = 80
+ pass_flags = PASSTABLE | PASSGRILLE | PASSGIRDER
+ speed = 0.2
+ icon_state = "gauss_silenced"
+ light_color = LIGHT_COLOR_LIGHT_CYAN
+
+/obj/item/projectile/bullet/railgun/railgun_strong
+ damage = 45
+ armour_penetration_flat = 30
+ weaken = 0.2
+ speed = 0.2
+
+// MARK: Skrellian pistol
+/obj/item/gun/energy/gun/skrell_pistol
+ name = "\improper self-charge skrellian pistol"
+ desc = "Энергетический пистолет Qua'l*Sarqzix-44x, известный на территориях ТСФ как QS-44. Компактный и удобный в использовании, имеет два режима мощности энерголуча: 'летальный' и 'нейтрализующий'. \
+ Встроенный микрогенератор постепенно пополняет запас аккамулятора прямо в бою."
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ icon_state = "skrell_pistol"
+ item_state = "skrell_pistol"
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/skrell_light, /obj/item/ammo_casing/energy/disabler)
+ w_class = WEIGHT_CLASS_SMALL
+ shaded_charge = FALSE
+ can_holster = TRUE
+ execution_speed = 4 SECONDS
+ selfcharge = TRUE
diff --git a/modular_ss220/objects/code/weapons/ranged/sslr.dm b/modular_ss220/objects/code/weapons/ranged/sslr.dm
new file mode 100644
index 000000000000..22525c8fd222
--- /dev/null
+++ b/modular_ss220/objects/code/weapons/ranged/sslr.dm
@@ -0,0 +1,72 @@
+/obj/item/gun/projectile/automatic/sslr
+ name = "SSLR"
+ desc = "Стандартная лазерная винтовка производства Warp-Tac Industries, использующая лазерные картриджи вместо аккумулятора. Одно из самых популярных решений для службы безопасности Nanotrasen."
+ icon = 'modular_ss220/objects/icons/guns.dmi'
+ lefthand_file = 'modular_ss220/objects/icons/inhands/guns_lefthand.dmi'
+ righthand_file = 'modular_ss220/objects/icons/inhands/guns_righthand.dmi'
+ icon_state = "sslr"
+ item_state = "sslr"
+ w_class = WEIGHT_CLASS_BULKY
+ weapon_weight = WEAPON_HEAVY
+ origin_tech = "combat=1;materials=1"
+ mag_type = /obj/item/ammo_box/magazine/sslr
+ fire_sound = 'sound/weapons/gunshots/gunshot_lascarbine.ogg'
+ magin_sound = 'sound/weapons/gun_interactions/batrifle_magin.ogg'
+ magout_sound = 'sound/weapons/gun_interactions/batrifle_magout.ogg'
+ can_suppress = FALSE
+ burst_size = 1
+ actions_types = list()
+
+/obj/item/gun/projectile/automatic/sslr/update_icon_state()
+ icon_state = "sslr[magazine ? "-[CEILING(get_ammo(0) / 4, 1) * 4]" : ""]"
+ item_state = "sslr[magazine ? "" : "_empty"]"
+
+/obj/item/ammo_box/magazine/sslr
+ name = "SSLR magazine"
+ desc = "Стандартный магазин для винтовки SSLR производства Warp-Tac Industries."
+ icon = 'modular_ss220/objects/icons/ammo.dmi'
+ icon_state = "sslr"
+ ammo_type = /obj/item/ammo_casing/caseless/laser
+ origin_tech = "combat=1"
+ caliber = "laser"
+ max_ammo = 8
+ multi_sprite_step = 4
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/ammo_box/small_laser
+ name = "small ammo box (laser)"
+ desc = "Упаковка на 8 лазерных патронов для лазерных винтовок с магазинным способом заряжания."
+ icon_state = "laserbox"
+ origin_tech = "combat=1"
+ ammo_type = /obj/item/ammo_casing/caseless/laser
+ max_ammo = 8
+ w_class = WEIGHT_CLASS_NORMAL
+
+/datum/design/sslr_magazine
+ name = "Security Laser Rifle Magazine"
+ desc = "Стандратный магазин на 8 патронов для SSLR."
+ id = "mag_sslr"
+ build_type = PROTOLATHE
+ req_tech = list("combat" = 1, "powerstorage" = 1)
+ materials = list(MAT_METAL = 1600, MAT_PLASMA = 240)
+ build_path = /obj/item/ammo_box/magazine/sslr
+ category = list("Weapons")
+
+/datum/design/laser_rifle_small_ammo_box
+ name = "Security Laser Rifle Ammunition"
+ desc = "Упаковка на 8 лазерных патронов для лазерных винтовок с магазинным способом заряжания."
+ id = "small_box_laser"
+ build_type = PROTOLATHE
+ req_tech = list("combat" = 1, "powerstorage" = 1)
+ materials = list(MAT_METAL = 1600, MAT_PLASMA = 240)
+ build_path = /obj/item/ammo_box/small_laser
+ category = list("Weapons")
+
+/datum/supply_packs/security/armory/sslr_ammo
+ name = "SSLR Ammo Crate"
+ contains = list(/obj/item/ammo_box/magazine/sslr,
+ /obj/item/ammo_box/magazine/sslr,
+ /obj/item/ammo_box/magazine/sslr,
+ /obj/item/ammo_box/magazine/sslr)
+ cost = 150
+ containername = "SSLR ammo crate"
diff --git a/modular_ss220/objects/icons/ammo.dmi b/modular_ss220/objects/icons/ammo.dmi
new file mode 100644
index 000000000000..9e52b4ae7c81
Binary files /dev/null and b/modular_ss220/objects/icons/ammo.dmi differ
diff --git a/modular_ss220/objects/icons/animalhide.dmi b/modular_ss220/objects/icons/animalhide.dmi
new file mode 100644
index 000000000000..cadaf51049c5
Binary files /dev/null and b/modular_ss220/objects/icons/animalhide.dmi differ
diff --git a/modular_ss220/objects/icons/bed.dmi b/modular_ss220/objects/icons/bed.dmi
new file mode 100644
index 000000000000..7f5dced6d7a9
Binary files /dev/null and b/modular_ss220/objects/icons/bed.dmi differ
diff --git a/modular_ss220/objects/icons/billboard.dmi b/modular_ss220/objects/icons/billboard.dmi
new file mode 100644
index 000000000000..f9f6445a77d9
Binary files /dev/null and b/modular_ss220/objects/icons/billboard.dmi differ
diff --git a/modular_ss220/objects/icons/boxes.dmi b/modular_ss220/objects/icons/boxes.dmi
new file mode 100644
index 000000000000..7290c8bf0f25
Binary files /dev/null and b/modular_ss220/objects/icons/boxes.dmi differ
diff --git a/modular_ss220/objects/icons/closets.dmi b/modular_ss220/objects/icons/closets.dmi
new file mode 100644
index 000000000000..4551f3423ae8
Binary files /dev/null and b/modular_ss220/objects/icons/closets.dmi differ
diff --git a/modular_ss220/objects/icons/flag.dmi b/modular_ss220/objects/icons/flag.dmi
new file mode 100644
index 000000000000..82cd49360f01
Binary files /dev/null and b/modular_ss220/objects/icons/flag.dmi differ
diff --git a/modular_ss220/objects/icons/flora/sakura.dmi b/modular_ss220/objects/icons/flora/sakura.dmi
new file mode 100644
index 000000000000..838137105a73
Binary files /dev/null and b/modular_ss220/objects/icons/flora/sakura.dmi differ
diff --git a/modular_ss220/objects/icons/flora/sakura_grass.dmi b/modular_ss220/objects/icons/flora/sakura_grass.dmi
new file mode 100644
index 000000000000..7fd3130684ed
Binary files /dev/null and b/modular_ss220/objects/icons/flora/sakura_grass.dmi differ
diff --git a/modular_ss220/objects/icons/fountain.dmi b/modular_ss220/objects/icons/fountain.dmi
new file mode 100644
index 000000000000..299ed085e4dd
Binary files /dev/null and b/modular_ss220/objects/icons/fountain.dmi differ
diff --git a/modular_ss220/objects/icons/guns.dmi b/modular_ss220/objects/icons/guns.dmi
new file mode 100644
index 000000000000..0b1e0c63091e
Binary files /dev/null and b/modular_ss220/objects/icons/guns.dmi differ
diff --git a/modular_ss220/objects/icons/id_skins.dmi b/modular_ss220/objects/icons/id_skins.dmi
new file mode 100644
index 000000000000..58cb4b9e8d18
Binary files /dev/null and b/modular_ss220/objects/icons/id_skins.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/chairs_lefthand.dmi b/modular_ss220/objects/icons/inhands/chairs_lefthand.dmi
new file mode 100644
index 000000000000..47e5b1987120
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/chairs_lefthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/chairs_righthand.dmi b/modular_ss220/objects/icons/inhands/chairs_righthand.dmi
new file mode 100644
index 000000000000..b4d36788d281
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/chairs_righthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/flags_lefthand.dmi b/modular_ss220/objects/icons/inhands/flags_lefthand.dmi
new file mode 100644
index 000000000000..c79d3bdce4c7
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/flags_lefthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/flags_righthand.dmi b/modular_ss220/objects/icons/inhands/flags_righthand.dmi
new file mode 100644
index 000000000000..72911ea69e02
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/flags_righthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/guns_lefthand.dmi b/modular_ss220/objects/icons/inhands/guns_lefthand.dmi
new file mode 100644
index 000000000000..8b77e53ebc47
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/guns_lefthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/guns_righthand.dmi b/modular_ss220/objects/icons/inhands/guns_righthand.dmi
new file mode 100644
index 000000000000..bbecbad178b5
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/guns_righthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/melee_lefthand.dmi b/modular_ss220/objects/icons/inhands/melee_lefthand.dmi
new file mode 100644
index 000000000000..738f8c58acc4
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/melee_lefthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/melee_righthand.dmi b/modular_ss220/objects/icons/inhands/melee_righthand.dmi
new file mode 100644
index 000000000000..844e8b00b1c7
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/melee_righthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/plushies_lefthand.dmi b/modular_ss220/objects/icons/inhands/plushies_lefthand.dmi
new file mode 100644
index 000000000000..e98ca7b4ffae
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/plushies_lefthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhands/plushies_righthand.dmi b/modular_ss220/objects/icons/inhands/plushies_righthand.dmi
new file mode 100644
index 000000000000..7ecb36e7a9cf
Binary files /dev/null and b/modular_ss220/objects/icons/inhands/plushies_righthand.dmi differ
diff --git a/modular_ss220/objects/icons/inhead/head.dmi b/modular_ss220/objects/icons/inhead/head.dmi
new file mode 100644
index 000000000000..b47d9ce9b1a5
Binary files /dev/null and b/modular_ss220/objects/icons/inhead/head.dmi differ
diff --git a/modular_ss220/objects/icons/key.dmi b/modular_ss220/objects/icons/key.dmi
new file mode 100644
index 000000000000..4740d7b5e706
Binary files /dev/null and b/modular_ss220/objects/icons/key.dmi differ
diff --git a/modular_ss220/objects/icons/lighting.dmi b/modular_ss220/objects/icons/lighting.dmi
new file mode 100644
index 000000000000..681726d0fedb
Binary files /dev/null and b/modular_ss220/objects/icons/lighting.dmi differ
diff --git a/modular_ss220/objects/icons/material_pouch.dmi b/modular_ss220/objects/icons/material_pouch.dmi
new file mode 100644
index 000000000000..861e224027ff
Binary files /dev/null and b/modular_ss220/objects/icons/material_pouch.dmi differ
diff --git a/modular_ss220/objects/icons/mattress.dmi b/modular_ss220/objects/icons/mattress.dmi
new file mode 100644
index 000000000000..812e358712fb
Binary files /dev/null and b/modular_ss220/objects/icons/mattress.dmi differ
diff --git a/modular_ss220/objects/icons/mech.dmi b/modular_ss220/objects/icons/mech.dmi
new file mode 100644
index 000000000000..0bf1578d0628
Binary files /dev/null and b/modular_ss220/objects/icons/mech.dmi differ
diff --git a/modular_ss220/objects/icons/mecha.dmi b/modular_ss220/objects/icons/mecha.dmi
new file mode 100644
index 000000000000..8ed14e52e3ac
Binary files /dev/null and b/modular_ss220/objects/icons/mecha.dmi differ
diff --git a/modular_ss220/objects/icons/melee.dmi b/modular_ss220/objects/icons/melee.dmi
new file mode 100644
index 000000000000..d219ebe2a30d
Binary files /dev/null and b/modular_ss220/objects/icons/melee.dmi differ
diff --git a/modular_ss220/objects/icons/officetoys.dmi b/modular_ss220/objects/icons/officetoys.dmi
new file mode 100644
index 000000000000..ecf83d6b82bd
Binary files /dev/null and b/modular_ss220/objects/icons/officetoys.dmi differ
diff --git a/modular_ss220/objects/icons/papershredder.dmi b/modular_ss220/objects/icons/papershredder.dmi
new file mode 100644
index 000000000000..2cb519d6d4a2
Binary files /dev/null and b/modular_ss220/objects/icons/papershredder.dmi differ
diff --git a/modular_ss220/objects/icons/plastic.dmi b/modular_ss220/objects/icons/plastic.dmi
new file mode 100644
index 000000000000..638c504f65e0
Binary files /dev/null and b/modular_ss220/objects/icons/plastic.dmi differ
diff --git a/modular_ss220/objects/icons/platform.dmi b/modular_ss220/objects/icons/platform.dmi
new file mode 100644
index 000000000000..1f6dcf8a4251
Binary files /dev/null and b/modular_ss220/objects/icons/platform.dmi differ
diff --git a/modular_ss220/objects/icons/plushies.dmi b/modular_ss220/objects/icons/plushies.dmi
new file mode 100644
index 000000000000..92bad5aeadbb
Binary files /dev/null and b/modular_ss220/objects/icons/plushies.dmi differ
diff --git a/modular_ss220/objects/icons/posters.dmi b/modular_ss220/objects/icons/posters.dmi
new file mode 100644
index 000000000000..3e9e1fdaaae5
Binary files /dev/null and b/modular_ss220/objects/icons/posters.dmi differ
diff --git a/modular_ss220/objects/icons/tribune.dmi b/modular_ss220/objects/icons/tribune.dmi
new file mode 100644
index 000000000000..5e8775263ec9
Binary files /dev/null and b/modular_ss220/objects/icons/tribune.dmi differ
diff --git a/modular_ss220/objects/icons/umbrella.dmi b/modular_ss220/objects/icons/umbrella.dmi
new file mode 100644
index 000000000000..78bf6eaa3b9a
Binary files /dev/null and b/modular_ss220/objects/icons/umbrella.dmi differ
diff --git a/modular_ss220/objects/icons/wallets.dmi b/modular_ss220/objects/icons/wallets.dmi
new file mode 100644
index 000000000000..6671ebef4606
Binary files /dev/null and b/modular_ss220/objects/icons/wallets.dmi differ
diff --git a/modular_ss220/objects/icons/wide_guns.dmi b/modular_ss220/objects/icons/wide_guns.dmi
new file mode 100644
index 000000000000..9e84712f81f2
Binary files /dev/null and b/modular_ss220/objects/icons/wide_guns.dmi differ
diff --git a/modular_ss220/objects/sound/officetoys/buttonclick.ogg b/modular_ss220/objects/sound/officetoys/buttonclick.ogg
new file mode 100644
index 000000000000..0c03b6b6289a
Binary files /dev/null and b/modular_ss220/objects/sound/officetoys/buttonclick.ogg differ
diff --git a/modular_ss220/objects/sound/officetoys/fan_end.ogg b/modular_ss220/objects/sound/officetoys/fan_end.ogg
new file mode 100644
index 000000000000..1c50757d2b90
Binary files /dev/null and b/modular_ss220/objects/sound/officetoys/fan_end.ogg differ
diff --git a/modular_ss220/objects/sound/officetoys/fan_mid1.ogg b/modular_ss220/objects/sound/officetoys/fan_mid1.ogg
new file mode 100644
index 000000000000..1abf9b9b5e68
Binary files /dev/null and b/modular_ss220/objects/sound/officetoys/fan_mid1.ogg differ
diff --git a/modular_ss220/objects/sound/officetoys/fan_start.ogg b/modular_ss220/objects/sound/officetoys/fan_start.ogg
new file mode 100644
index 000000000000..5ff9b64ffccb
Binary files /dev/null and b/modular_ss220/objects/sound/officetoys/fan_start.ogg differ
diff --git a/modular_ss220/objects/sound/officetoys/microfan.ogg b/modular_ss220/objects/sound/officetoys/microfan.ogg
new file mode 100644
index 000000000000..26631f593245
Binary files /dev/null and b/modular_ss220/objects/sound/officetoys/microfan.ogg differ
diff --git a/modular_ss220/objects/sound/officetoys/newtoncradle.ogg b/modular_ss220/objects/sound/officetoys/newtoncradle.ogg
new file mode 100644
index 000000000000..48cf91228a1a
Binary files /dev/null and b/modular_ss220/objects/sound/officetoys/newtoncradle.ogg differ
diff --git a/modular_ss220/objects/sound/officetoys/newtoncradle_mid1.ogg b/modular_ss220/objects/sound/officetoys/newtoncradle_mid1.ogg
new file mode 100644
index 000000000000..35e6bb6ec62b
Binary files /dev/null and b/modular_ss220/objects/sound/officetoys/newtoncradle_mid1.ogg differ
diff --git a/modular_ss220/objects/sound/pshred.ogg b/modular_ss220/objects/sound/pshred.ogg
new file mode 100644
index 000000000000..a722f3006899
Binary files /dev/null and b/modular_ss220/objects/sound/pshred.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/cylinder/reclined_rsh12.ogg b/modular_ss220/objects/sound/weapons/cylinder/reclined_rsh12.ogg
new file mode 100644
index 000000000000..698b798cdc74
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/cylinder/reclined_rsh12.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/cylinder/snapback_rsh12.ogg b/modular_ss220/objects/sound/weapons/cylinder/snapback_rsh12.ogg
new file mode 100644
index 000000000000..8a5a76170a84
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/cylinder/snapback_rsh12.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/drop/peas_shooter_drop.ogg b/modular_ss220/objects/sound/weapons/drop/peas_shooter_drop.ogg
new file mode 100644
index 000000000000..dd760f244901
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/drop/peas_shooter_drop.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/beretta_shot.ogg b/modular_ss220/objects/sound/weapons/gunshots/beretta_shot.ogg
new file mode 100644
index 000000000000..4a413dd2cb8a
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/beretta_shot.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/blaster.ogg b/modular_ss220/objects/sound/weapons/gunshots/blaster.ogg
new file mode 100644
index 000000000000..829a5c365579
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/blaster.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/gunshot_anaconda.ogg b/modular_ss220/objects/sound/weapons/gunshots/gunshot_anaconda.ogg
new file mode 100644
index 000000000000..bca062190f94
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/gunshot_anaconda.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/gunshot_judge.ogg b/modular_ss220/objects/sound/weapons/gunshots/gunshot_judge.ogg
new file mode 100644
index 000000000000..12205a02d695
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/gunshot_judge.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/gunshot_pneumatic.ogg b/modular_ss220/objects/sound/weapons/gunshots/gunshot_pneumatic.ogg
new file mode 100644
index 000000000000..69607153d610
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/gunshot_pneumatic.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/gunshot_rsh12.ogg b/modular_ss220/objects/sound/weapons/gunshots/gunshot_rsh12.ogg
new file mode 100644
index 000000000000..0e200cf97395
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/gunshot_rsh12.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/peas_shooter_gunshot.ogg b/modular_ss220/objects/sound/weapons/gunshots/peas_shooter_gunshot.ogg
new file mode 100644
index 000000000000..8ff2a18feaee
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/peas_shooter_gunshot.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/railgun.ogg b/modular_ss220/objects/sound/weapons/gunshots/railgun.ogg
new file mode 100644
index 000000000000..0b939fd9a60e
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/railgun.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/gunshots/shot_heavy.ogg b/modular_ss220/objects/sound/weapons/gunshots/shot_heavy.ogg
new file mode 100644
index 000000000000..f91b21ec4d80
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/gunshots/shot_heavy.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/melee/electrostaff/on.ogg b/modular_ss220/objects/sound/weapons/melee/electrostaff/on.ogg
new file mode 100644
index 000000000000..4a3e0f0abb07
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/melee/electrostaff/on.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/melee/sardaukar/equip.ogg b/modular_ss220/objects/sound/weapons/melee/sardaukar/equip.ogg
new file mode 100644
index 000000000000..92ca5f02172f
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/melee/sardaukar/equip.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/melee/sardaukar/knifehit1.ogg b/modular_ss220/objects/sound/weapons/melee/sardaukar/knifehit1.ogg
new file mode 100644
index 000000000000..3e4a04c0f1de
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/melee/sardaukar/knifehit1.ogg differ
diff --git a/modular_ss220/objects/sound/weapons/styletext.ogg b/modular_ss220/objects/sound/weapons/styletext.ogg
new file mode 100644
index 000000000000..c5d7484a9452
Binary files /dev/null and b/modular_ss220/objects/sound/weapons/styletext.ogg differ
diff --git a/modular_ss220/outfits/_outfits.dm b/modular_ss220/outfits/_outfits.dm
new file mode 100644
index 000000000000..a761085d5890
--- /dev/null
+++ b/modular_ss220/outfits/_outfits.dm
@@ -0,0 +1,4 @@
+/datum/modpack/outfits
+ name = "Outfits"
+ desc = "Аутфиты для админ спавна."
+ author = "Grombila"
diff --git a/modular_ss220/outfits/_outfits.dme b/modular_ss220/outfits/_outfits.dme
new file mode 100644
index 000000000000..d10bfeea5088
--- /dev/null
+++ b/modular_ss220/outfits/_outfits.dme
@@ -0,0 +1,3 @@
+#include "_outfits.dm"
+
+#include "code/outfits.dm"
diff --git a/modular_ss220/outfits/code/outfits.dm b/modular_ss220/outfits/code/outfits.dm
new file mode 100644
index 000000000000..e3b3fc8e5ce7
--- /dev/null
+++ b/modular_ss220/outfits/code/outfits.dm
@@ -0,0 +1,453 @@
+// MARK: Soviets
+/datum/outfit/admin/soviet/admiral
+ belt = /obj/item/gun/projectile/revolver/reclinable/rsh12
+
+ backpack_contents = list(
+ /obj/item/storage/box/soviet = 1,
+ /obj/item/ammo_box/speed_loader_mm127 = 3
+ )
+
+/datum/outfit/admin/soviet/marine/captain
+
+ backpack_contents = list(
+ /obj/item/storage/box/soviet = 1,
+ /obj/item/gun/projectile/revolver/reclinable/anaconda = 1,
+ /obj/item/ammo_box/speed_loader_d44 = 2,
+ /obj/item/storage/fancy/cigarettes/cigpack_syndicate = 1,
+ /obj/item/lighter/zippo/engraved = 1
+ )
+
+/datum/outfit/admin/soviet/officer
+ belt = /obj/item/gun/projectile/revolver/reclinable/rsh12
+
+ backpack_contents = list(
+ /obj/item/storage/box/soviet = 1,
+ /obj/item/lighter/zippo = 1,
+ /obj/item/storage/fancy/cigarettes/cigpack_syndicate = 1,
+ /obj/item/ammo_box/speed_loader_mm127 = 2
+ )
+
+// MARK: NT & Syndie Officers
+/datum/outfit/job/syndicateofficer
+ suit = /obj/item/clothing/suit/space/deathsquad/officer/syndie
+
+/datum/outfit/job/ntnavyofficer
+ l_pocket = /obj/item/melee/baseball_bat/homerun/central_command
+
+/obj/item/clothing/head/beret/centcom/officer/navy/marine
+ name = "navy blue beret"
+
+// MARK: NT Officer outfits
+/datum/outfit/job/admin/ntnavyofficer
+ name = "Nanotrasen Navy Officer"
+ jobtype = /datum/job/ntnavyofficer
+
+ uniform = /obj/item/clothing/under/rank/centcom/officer
+ gloves = /obj/item/clothing/gloves/color/white
+ shoes = /obj/item/clothing/shoes/centcom
+ head = /obj/item/clothing/head/beret/centcom/officer
+ l_ear = /obj/item/radio/headset/centcom
+ glasses = /obj/item/clothing/glasses/hud/security/sunglasses
+ id = /obj/item/card/id/centcom
+ pda = /obj/item/pda/centcom
+ bio_chips = list(
+ /obj/item/bio_chip/mindshield,
+ /obj/item/bio_chip/dust
+ )
+ backpack = /obj/item/storage/backpack/satchel
+ backpack_contents = list(
+ /obj/item/stamp/centcom = 1,
+ )
+ box = /obj/item/storage/box/centcomofficer
+ cybernetic_implants = list(
+ /obj/item/organ/internal/cyberimp/chest/nutriment/plus/hardened,
+ /obj/item/organ/internal/cyberimp/arm/combat/centcom
+ )
+
+/datum/outfit/job/admin/ntnavyofficer/on_mind_initialize(mob/living/carbon/human/H)
+ . = ..()
+ H.mind.offstation_role = TRUE
+
+/datum/outfit/job/admin/ntspecops
+ name = "Special Operations Officer"
+ jobtype = /datum/job/ntspecops
+ allow_backbag_choice = FALSE
+ uniform = /obj/item/clothing/under/rank/centcom/captain
+ suit = /obj/item/clothing/suit/space/deathsquad/officer
+ belt = /obj/item/storage/belt/military/assault
+ gloves = /obj/item/clothing/gloves/combat
+ shoes = /obj/item/clothing/shoes/combat
+ mask = /obj/item/clothing/mask/holo_cigar
+ head = /obj/item/clothing/head/helmet/space/deathsquad/beret
+ l_ear = /obj/item/radio/headset/centcom
+ glasses = /obj/item/clothing/glasses/hud/security/sunglasses
+ id = /obj/item/card/id/centcom
+ pda = /obj/item/pda/centcom
+ r_pocket = /obj/item/storage/fancy/matches
+ back = /obj/item/storage/backpack/satchel
+ box = /obj/item/storage/box/centcomofficer
+ backpack_contents = list(
+ /obj/item/clothing/shoes/magboots/advance = 1,
+ /obj/item/storage/box/zipties = 1
+ )
+ bio_chips = list(
+ /obj/item/bio_chip/mindshield,
+ /obj/item/bio_chip/dust
+ )
+ cybernetic_implants = list(
+ /obj/item/organ/internal/eyes/cybernetic/xray/hardened,
+ /obj/item/organ/internal/cyberimp/brain/anti_stam/hardened,
+ /obj/item/organ/internal/cyberimp/chest/nutriment/plus/hardened,
+ /obj/item/organ/internal/cyberimp/arm/combat/centcom
+ )
+
+/datum/outfit/job/admin/ntspecops/on_mind_initialize(mob/living/carbon/human/H)
+ . = ..()
+ H.mind.offstation_role = TRUE
+
+/datum/outfit/job/admin/ntspecops/alt
+ name = "Specops alt. RSH-12, saber, bandana"
+ belt = /obj/item/storage/belt/sheath/saber
+ backpack_contents = list(
+ /obj/item/gun/projectile/revolver/reclinable/rsh12,
+ /obj/item/ammo_box/speed_loader_mm127,
+ /obj/item/ammo_box/speed_loader_mm127,
+ /obj/item/ammo_box/speed_loader_mm127,
+ /obj/item/clothing/mask/bandana/red
+ )
+ suit_store = /obj/item/ammo_box/box_mm127
+
+/datum/outfit/job/admin/ntnavyofficer/alt
+ name = "NT Navy Officer alt. Coat NT, holo, noble, cane"
+ mask = /obj/item/clothing/mask/holo_cigar
+ suit = /obj/item/clothing/suit/space/deathsquad/officer/field/cloak_nt/coat_nt
+ shoes = /obj/item/clothing/shoes/fluff/noble_boot
+ belt = /obj/item/melee/classic_baton/ntcane
+
+/datum/outfit/job/admin/ntnavyofficer/alt2
+ name = "NT Navy Officer alt. Cloak NT, holo"
+ suit = /obj/item/clothing/suit/space/deathsquad/officer/field/cloak_nt
+ mask = /obj/item/clothing/mask/holo_cigar
+
+/datum/outfit/job/admin/ntnavyofficer/field
+ name = "Nanotrasen Navy Field Officer"
+
+ gloves = /obj/item/clothing/gloves/combat
+ suit = /obj/item/clothing/suit/space/deathsquad/officer/field
+ head = /obj/item/clothing/head/helmet/space/deathsquad/beret/field
+ l_pocket = /obj/item/melee/baseball_bat/homerun/central_command
+
+ bio_chips = list(
+ /obj/item/bio_chip/mindshield,
+ /obj/item/bio_chip/dust,
+ /obj/item/organ/internal/cyberimp/brain/anti_sleep/hardened,
+ /obj/item/organ/internal/cyberimp/chest/reviver/hardened,
+ /obj/item/organ/internal/cyberimp/eyes/hud/medical,
+ /obj/item/organ/internal/cyberimp/brain/anti_stam/hardened,
+ /obj/item/organ/internal/eyes/cybernetic/thermals/hardened
+ )
+
+/datum/outfit/job/admin/ntnavyofficer/field/alt
+ name = "Nanotrasen Navy Field Officer alt. Ring, mateba, holster"
+ gloves =/obj/item/clothing/gloves/ring/silver
+ mask = /obj/item/clothing/mask/holo_cigar
+ backpack_contents = list(
+ /obj/item/clothing/accessory/scarf/purple,
+ /obj/item/clothing/gloves/combat,
+ /obj/item/gun/projectile/revolver/mateba,
+ /obj/item/ammo_box/a357,
+ /obj/item/ammo_box/a357,
+ /obj/item/ammo_box/a357,
+ /obj/item/clothing/accessory/holster
+ )
+
+/datum/outfit/job/admin/nt_navy_captain
+ name = "NT Navy Captain (Advanced)"
+
+ uniform = /obj/item/clothing/under/rank/centcom/captain
+ back = /obj/item/storage/backpack/satchel
+ belt = /obj/item/storage/belt/sheath/saber
+ gloves = /obj/item/clothing/gloves/color/white
+ shoes = /obj/item/clothing/shoes/centcom
+ head = /obj/item/clothing/head/beret/centcom/captain
+ l_ear = /obj/item/radio/headset/centcom
+ glasses = /obj/item/clothing/glasses/hud/security/sunglasses
+ id = /obj/item/card/id/centcom
+ pda = /obj/item/pda/centcom
+ backpack_contents = list(
+ /obj/item/storage/box/centcomofficer,
+ /obj/item/bio_chip_implanter/death_alarm,
+ /obj/item/stamp/centcom,
+ /obj/item/gun/projectile/revolver/reclinable/rsh12,
+ /obj/item/ammo_box/speed_loader_mm127,
+ /obj/item/ammo_box/speed_loader_mm127
+ )
+ bio_chips = list(
+ /obj/item/bio_chip/mindshield,
+ /obj/item/bio_chip/dust
+ )
+ cybernetic_implants = list(
+ /obj/item/organ/internal/eyes/cybernetic/xray/hardened,
+ /obj/item/organ/internal/cyberimp/brain/anti_stam/hardened,
+ /obj/item/organ/internal/cyberimp/chest/nutriment/plus/hardened
+ )
+
+/datum/outfit/job/admin/nt_navy_captain/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ if(visualsOnly)
+ return
+
+ var/obj/item/card/id/I = H.wear_id
+ if(istype(I))
+ apply_to_card(I, H, get_centcom_access("Nanotrasen Navy Captain"), "Nanotrasen Navy Captain")
+ H.sec_hud_set_ID()
+
+/datum/outfit/job/admin/ntnavyofficer/field/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ if(visualsOnly)
+ return
+ H.mind.offstation_role = TRUE
+ var/obj/item/card/id/I = H.wear_id
+ if(istype(I))
+ apply_to_card(I, H, get_centcom_access("Nanotrasen Navy Officer"), "Nanotrasen Navy Field Officer")
+ I.rank = "Nanotrasen Navy Officer"
+ I.assignment = "Nanotrasen Navy Field Officer"
+ H.sec_hud_set_ID()
+
+/datum/outfit/job/admin/ntnavyofficer/intern
+ name = "NT Intern"
+ uniform = /obj/item/clothing/under/rank/centcom/intern
+ head = /obj/item/clothing/head/beret/centcom/intern
+ glasses = /obj/item/clothing/glasses/hud/skills/sunglasses
+ gloves = /obj/item/clothing/gloves/fingerless
+ id = /obj/item/card/id/centcom
+ backpack_contents = list(
+ /obj/item/stamp/centcom,
+ /obj/item/clipboard,
+ /obj/item/stack/spacecash/c200
+ )
+ bio_chips = list(
+ /obj/item/bio_chip/mindshield
+ )
+ cybernetic_implants = list(
+ /obj/item/organ/internal/cyberimp/chest/nutriment/plus/hardened
+ )
+
+/datum/outfit/job/admin/ntnavyofficer/intern/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ if(visualsOnly)
+ return
+
+ var/obj/item/card/id/I = H.wear_id
+ if(istype(I))
+ apply_to_card(I, H, get_centcom_access("Nanotrasen Navy Officer"), "Nanotrasen CentCom Intern")
+ I.rank = "Nanotrasen Navy Officer"
+ I.assignment = "Nanotrasen CentCom Intern"
+ H.sec_hud_set_ID()
+
+/obj/item/clothing/head/helmet/space/deathsquad/beret/field
+ icon_state = "beret_centcom_officer"
+
+// MARK: SRT
+/datum/outfit/admin/srt
+ name = "Special Response Team Member"
+
+ uniform = /obj/item/clothing/under/solgov/srt
+ suit = /obj/item/clothing/suit/armor/vest/fluff/tactical
+ suit_store = /obj/item/gun/energy/gun/blueshield/pdw9
+ back = /obj/item/storage/backpack/satchel_blueshield
+ belt = /obj/item/storage/belt/military/assault/srt
+ gloves = /obj/item/clothing/gloves/combat
+ shoes = /obj/item/clothing/shoes/combat/swat
+ head = /obj/item/clothing/head/beret/centcom/officer/navy/marine
+ l_ear = /obj/item/radio/headset/ert/alt
+ glasses = /obj/item/clothing/glasses/hud/security/sunglasses
+ id = /obj/item/card/id/ert/security
+ pda = /obj/item/pda/heads/ert/security
+ box = /obj/item/storage/box/responseteam
+ r_pocket = /obj/item/flashlight/seclite
+ l_pocket = /obj/item/pinpointer/advpinpointer
+ backpack_contents = list(
+ /obj/item/clothing/mask/gas/explorer/marines,
+ /obj/item/storage/box/handcuffs,
+ /obj/item/ammo_box/magazine/smgm9mm,
+ /obj/item/clothing/accessory/holster,
+ /obj/item/gun/projectile/automatic/proto
+ )
+ bio_chips = list(
+ /obj/item/bio_chip/mindshield
+ )
+ cybernetic_implants = list(
+ /obj/item/organ/internal/cyberimp/arm/baton,
+ /obj/item/organ/internal/cyberimp/eyes/hud/security
+ )
+ var/id_icon = "syndie"
+
+/datum/outfit/admin/srt/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ if(visualsOnly)
+ return
+
+ var/obj/item/card/id/I = H.wear_id
+ if(istype(I))
+ apply_to_card(I, H, get_centcom_access("Emergency Response Team Member"), "Special Response Team Member")
+ I.assignment = "Emergency Response Team Officer"
+ H.sec_hud_set_ID()
+
+/obj/item/clothing/under/solgov/srt
+ name = "marine uniform"
+ desc = "A comfortable and durable combat uniform"
+
+/obj/item/storage/belt/military/assault/srt/populate_contents()
+ new /obj/item/reagent_containers/spray/pepper(src)
+ new /obj/item/flash(src)
+ new /obj/item/grenade/flashbang(src)
+ new /obj/item/restraints/legcuffs/bola/energy(src)
+ new /obj/item/ammo_box/magazine/smgm9mm(src)
+ new /obj/item/ammo_box/magazine/smgm9mm(src)
+ update_icon()
+
+// MARK: ERT
+/* Commander */
+/datum/outfit/job/centcom/response_team/commander/amber
+ glasses = /obj/item/clothing/glasses/hud/security/sunglasses
+
+/* Engineer */
+/datum/outfit/job/centcom/response_team/engineer/amber
+ suit = /obj/item/clothing/suit/space/ert_engineer
+ head = /obj/item/clothing/head/helmet/space/ert_engineer
+
+// MARK: Skrell
+/datum/outfit/admin/sdtf
+ name = "Skrellian Defence Task Forces Marine"
+ uniform = /obj/item/clothing/under/solgov/srt
+ back = /obj/item/mod/control/pre_equipped/exclusive/skrell_raskinta
+ belt = /obj/item/melee/vibroblade
+ glasses = /obj/item/clothing/glasses/night
+ gloves = /obj/item/clothing/gloves/combat
+ shoes = /obj/item/clothing/shoes/combat
+ l_ear = /obj/item/radio/headset/skrellian
+ id = /obj/item/card/id
+ l_hand = /obj/item/gun/energy/gun/skrell_carbine/elite
+ r_pocket = /obj/item/reagent_containers/hypospray/autoinjector/nt_emergency/skrell
+ l_pocket = /obj/item/tank/internals/emergency_oxygen/double
+ mask = /obj/item/clothing/mask/gas/swat
+ backpack_contents = list(
+ /obj/item/storage/box/skrell,
+ /obj/item/storage/box/smoke_grenades,
+ /obj/item/grenade/plastic/c4 = 2,
+ /obj/item/storage/box/handcuffs,
+ /obj/item/clothing/accessory/holster,
+ /obj/item/gun/energy/gun/skrell_pistol
+ )
+ cybernetic_implants = list(
+ /obj/item/organ/internal/cyberimp/chest/nutriment/plus,
+ /obj/item/organ/internal/cyberimp/brain/anti_drop,
+ /obj/item/organ/internal/cyberimp/eyes/hud/medical,
+ )
+ var/is_sardaukar = FALSE
+
+/datum/outfit/admin/sdtf/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ if(visualsOnly)
+ return
+
+ H.add_language("Skrellian")
+ H.set_default_language(GLOB.all_languages["Skrellian"])
+
+ var/obj/item/card/id/I = H.wear_id
+ if(istype(I))
+ var/applied_rank = is_sardaukar ? "Emperor Guard" : "SDTF Raskinta Katish"
+ apply_to_card(I, H, list(ACCESS_MAINT_TUNNELS), applied_rank, /obj/item/card/id/away/old/med::icon_state)
+ H.sec_hud_set_ID()
+
+/datum/outfit/admin/sdtf/rifleman
+ name = "Skrellian Defence Task Forces Officer"
+ l_hand = /obj/item/gun/projectile/automatic/sniper_rifle/skrell_rifle
+ belt = /obj/item/storage/belt/military/assault/skrell
+ suit_store = /obj/item/melee/vibroblade
+ backpack_contents = list(
+ /obj/item/storage/box/skrell,
+ /obj/item/gun/energy/gun/skrell_carbine/elite,
+ /obj/item/storage/box/smoke_grenades,
+ /obj/item/grenade/plastic/c4 = 2,
+ /obj/item/clothing/accessory/holster,
+ /obj/item/gun/energy/gun/skrell_pistol
+ )
+
+/datum/outfit/admin/sdtf/sardaukar
+ name = "Skrellian Defence Task Forces Emperor Guard"
+ l_hand = /obj/item/gun/projectile/automatic/sniper_rifle/skrell_rifle/elite
+ belt = /obj/item/storage/belt/military/assault/skrell_elite
+ back = /obj/item/mod/control/pre_equipped/exclusive/skrell_sardaukars
+ r_pocket = /obj/item/reagent_containers/hypospray/combat/nanites
+ suit_store = /obj/item/melee/vibroblade/sardaukar
+ backpack_contents = list(
+ /obj/item/gun/energy/gun/skrell_carbine/elite,
+ /obj/item/storage/box/skrell,
+ /obj/item/storage/box/smoke_grenades,
+ /obj/item/grenade/plastic/c4 = 2,
+ /obj/item/clothing/accessory/holster,
+ /obj/item/cqc_manual,
+ /obj/item/shield/energy,
+ /obj/item/gun/energy/gun/skrell_pistol
+ )
+ cybernetic_implants = list(
+ /obj/item/organ/internal/cyberimp/chest/nutriment/plus,
+ /obj/item/organ/internal/cyberimp/brain/anti_drop,
+ /obj/item/organ/internal/cyberimp/eyes/hud/medical,
+ /obj/item/organ/internal/cyberimp/brain/sensory_enhancer,
+ /obj/item/organ/internal/cyberimp/brain/anti_stam
+ )
+ is_sardaukar = TRUE
+
+/obj/item/radio/headset/skrellian
+ name = "skrellian bowman headset"
+ desc = "Used by SDFT forces. Protects ears from flashbangs."
+ flags = EARBANGPROTECT
+ origin_tech = "syndicate=3"
+ icon_state = "com_headset_alt"
+ item_state = "com_headset_alt"
+ ks1type = /obj/item/encryptionkey/skrell
+ requires_tcomms = FALSE
+
+/obj/item/encryptionkey/skrell
+ name = "skrellian encryption key"
+ icon_state = "cypherkey"
+ channels = list("Special Ops" = 1, "Security" = 1, "Command" = 1)
+ origin_tech = "syndicate=4"
+
+/obj/item/reagent_containers/hypospray/autoinjector/nt_emergency/skrell
+ name = "nanites emergency autoinjector"
+ desc = "Одноразовый автоинжектор с нанитами."
+ list_reagents = list("nanites" = 10)
+
+/obj/item/storage/box/skrell
+ name = "boxed survival kit"
+ desc = "A standard issue SDTF survival kit."
+ icon = 'modular_ss220/objects/icons/boxes.dmi'
+ icon_state = "skrell_box"
+
+/obj/item/storage/box/skrell/populate_contents()
+ new /obj/item/tank/internals/emergency_oxygen/engi(src)
+ new /obj/item/crowbar/small(src)
+ new /obj/item/flashlight/flare(src)
+ new /obj/item/kitchen/knife/combat(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/nt_emergency/skrell(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/nt_emergency/skrell(src)
+
+/obj/item/storage/belt/military/assault/skrell/populate_contents()
+ new /obj/item/ammo_box/magazine/skrell_magazine(src)
+ new /obj/item/ammo_box/magazine/skrell_magazine(src)
+ new /obj/item/ammo_box/magazine/skrell_magazine(src)
+ new /obj/item/ammo_box/magazine/skrell_magazine(src)
+ new /obj/item/ammo_box/magazine/skrell_magazine(src)
+ new /obj/item/restraints/legcuffs/bola/energy(src)
+
+/obj/item/storage/belt/military/assault/skrell_elite/populate_contents()
+ new /obj/item/ammo_box/magazine/skrell_magazine/skrell_magazine_elite(src)
+ new /obj/item/ammo_box/magazine/skrell_magazine/skrell_magazine_elite(src)
+ new /obj/item/ammo_box/magazine/skrell_magazine/skrell_magazine_elite(src)
+ new /obj/item/ammo_box/magazine/skrell_magazine/skrell_magazine_elite(src)
+ new /obj/item/ammo_box/magazine/skrell_magazine/skrell_magazine_elite(src)
+ new /obj/item/restraints/legcuffs/bola/energy(src)
diff --git a/modular_ss220/phrases/_phrases.dm b/modular_ss220/phrases/_phrases.dm
new file mode 100644
index 000000000000..53357f8ea857
--- /dev/null
+++ b/modular_ss220/phrases/_phrases.dm
@@ -0,0 +1,4 @@
+/datum/modpack/phrases
+ name = "Пак фраз"
+ desc = "Вносим разнообразие для крикунов, вендоматов и цитирований."
+ author = "PhantomRU"
diff --git a/modular_ss220/phrases/_phrases.dme b/modular_ss220/phrases/_phrases.dme
new file mode 100644
index 000000000000..3a8abd9db6f8
--- /dev/null
+++ b/modular_ss220/phrases/_phrases.dme
@@ -0,0 +1,4 @@
+#include "_phrases.dm"
+
+#include "code/mobs_phrases.dm"
+#include "code/vending_phrases.dm"
diff --git a/modular_ss220/phrases/code/mobs_phrases.dm b/modular_ss220/phrases/code/mobs_phrases.dm
new file mode 100644
index 000000000000..d9051651756e
--- /dev/null
+++ b/modular_ss220/phrases/code/mobs_phrases.dm
@@ -0,0 +1,156 @@
+/datum/mutation/disability/tourettes/on_life(mob/living/carbon/human/H)
+ . = ..()
+ if(rand(0, 10000) == 0)
+ H.say("Ублюдок, мать твою, а ну иди сюда говно собачье, решил ко мне лезть? Ты, засранец вонючий, мать твою, а? Ну иди сюда, попробуй меня трахнуть, я тебя сам трахну ублюдок, онанист чертов, будь ты проклят, иди идиот, трахать тебя и всю семью, говно собачье, жлоб вонючий, дерьмо, сука, падла, иди сюда, мерзавец, негодяй, гад, иди сюда ты - говно, жопа!")
+
+/mob/living/carbon/human/handle_disabilities()
+ . = ..()
+ if(getBrainLoss() >= 60 && stat != DEAD)
+ if(prob(3))
+ var/list/crazysay = list(
+ "Я НЕПОБЕДИМ!!!",
+ "Я НЕУЯЗВИМ!!!",
+ "Я НЕОСТАНОВИМ!!!",
+ "Я КОРОЛЬ [pick("ЯЩЕРИЦ", "МОЛЕЙ", "ВУЛЬП", "КЛОУНОВ", "СТАНЦИИ", "ЗВЕРЕЙ", "БЕЗ КОРОНЫ", "ЦК", "ТСФ", "ССП", "СИНДИКАТА")]!!!",
+ "Ха-ха, не догонишь!",
+ "Че вылупился?!",
+ "ААААА ЗАХЛОПНИСЬ!!!",
+ "ХВАТИТ ГОВОРИТЬ!!!",
+ "КАК ВЫ МНЕ ВСЕ НАДОЕЛИ!!!",
+ "СЛИШКОМ ШУМНО!!!",
+ "КАК ПРОЙТИ В БИБЛИОТЕКУ?!",
+ "ВОССЛАВЬ СОЛНЦЕ!",
+ "МНЕ БОРЩ БЕЗ СВЕКЛЫ!",
+ "Я люблю пельмени без начинки.",
+ "Я люблю ананасовую пиццу.",
+ "Самое вкусное в пицце - бортики!",
+ "Я ХОЧУ [pick("СЕБЯ", "ТЕБЯ", "ПОНИ", "ЭТО", "ЕГО", "КУШАТЬ", "ПИТЬ", "ПИСЯТЬ", "НЕ ХОЧУ", "РАДУЖНЫЙ КАРАНДАШ", "ИЗМЕНИТЬ ТЕБЕ", "ОРАТЬ",
+ "[pick("УДАРИТЬ", "ОБНЯТЬ", "ПОЦЕЛОВАТЬ", "ЗАДУШИТЬ", "ПОГЛАДИТЬ", "НАКРИЧАТЬ НА", "ИЗБАВИТЬ ОТ СТРАДАНИЙ", "ПОСЛАТЬ")] [pick(
+ "ТЕБЯ", "СЕБЯ", "КЛОУНА", "МИМА", "ЩИТКУРА", "ОФИЦЕРА", "ПОВАРА", "МЕДИКА", "КОРОВУ", "САНЮ")]")]!",
+ // вспоминаем мемы
+ "ЗДОРОВЕННЫЙ ЯЗЬ!!!",
+ "ЙААААААААЗЬ!",
+ "ЯЯЯЯЯЯЯЗЬ!",
+ "АННИГИЛЯТОРНАЯ ПУШКА!",
+ "КУРВА КОСМОБОБЁР!",
+ "ЭТО КОСМОБОБЁР!",
+ "Денег нет, но я держусь!",
+ "КАК ТЕБЕ ТАКОЕ, ИЛОН СПАСК?",
+ "НО Я ЖЕ ЛЮБЛЮ ТЕБЯ!",
+ "ВРАЧА, ВРАЧА, ПОЗОВИТЕ ВРАЧА!",
+ "У неё преждеродовые начались. Мы не можем ей помочь.",
+ "ТЫ УКРАЛ МОЁ СЕРДЕЧКО!",
+ // Проклятые мемы
+ "Наташа вставай, мы всё уронили!",
+ "ПРЕВЕД!",
+ "ПРЕВЕЕЕЕД!",
+ "ПРЕВЕД МЕДВЕД!",
+ "УЧИТЕ ОЛБАНСКИЙ ЯЗЫК!",
+ "ржунимагу",
+ "пацталом",
+ "многабукаф",
+ "стопицот",
+ "ЖЫВТОНЕ ЧОЧО УПЯЧКА!!!",
+ "УПЯЧКА УПЯЧКА!!!",
+ "ШЯЧЛО ПОПЯЧТСА!!!",
+ "ПОПЯЧТСА!!!",
+ "Я идиот! Убейте меня кто-нибудь!",
+ "УПЯЧКА!",
+ "Я ДУРАК У МЕНЯ СПРАВКА ЕСТЬ!",
+ "Мне борщ с капустой, но не красный!",
+ "Котлетки... С пюрешкой!..",
+ "шлакоблокунь",
+ "MINE LAVALAND CRAFT ЭТО МОЯ ЖИЗНЬ!!!",
+ "Ну умер я и умер, че бубнить то.",
+ "Ты на станцию прилетел - косарь отдал!",
+ "БРАТИШКА, Я ТЕБЕ ПОКУШАТЬ ПРИНЕС!",
+ "ГДЕ ПРУФЫ, БИЛЛИ?!",
+ "ЭТО НОРМА!",
+ "ЭТО НЕ НОРМА!",
+ "ЭТО НИХУЯ НЕ НОРМА!",
+ "Ты втираешь мне какую-то дичь!",
+ "ЭТО ОБМАН ЧТОБЫ НАБРАТЬ КЛАССЫ!",
+ "ЭТО БУДЕТ ФИАСКО!",
+ "ЭТО ФИАСКО, БРАТАН!",
+ "ЧИВО",
+ "ЧИВО БЛЯТ?",
+ // Будь проклято онеме
+ "В ЭЛЬФИЙСКОЙ ПЕСНЕ НЕ БЫЛО ЭЛЬФОВ!!!",
+ "БОКУ НО ПИКО НЕ В БОКУ!",
+ "КОВБОЙ БИБОП НЕ КОВБОЙ И НЕ БИБОП!",
+ "ЭТОТ ГЛУПЫЙ СВИН НЕ ПОНИМАЕТ МЕЧТЫ ДЕВОЧКИ ЗАЙКИ!",
+ // А теперь цитаты настоящего пацана с брейндамагом.
+ "Не важно кто - важно кто!",
+ "Если волк молчит - то лучше его не перебивать!",
+ "Не важно кто слабее - важно кто сильный!",
+ "Вы меня не поправляйте, я вам не трусы.",
+ "Лучше быть последним-первым, чем первым-последним.",
+ "Лучше иметь друга, чем друг друга.",
+ "Моего друга сбила машина и он больше мне не друг, ведь друзья на дороге не валяются.",
+ "Побеждать по жизни могут только победители.",
+ "Безумно можно быть первым!",
+ "Если предали один раз - то это только первый раз. Если предали еще - то это второй.",
+ "Сделал дело - дело сделано.",
+ "Не важно в какой жопе ты находишься, главное чтобы в твоей жопе никто не находился!",
+ "Срать вечно.",
+ "Одна ошибка и ты ошибся!",
+ "Поссать без пука, это как поесть шашлык без лука!",
+ "Если хочешь идти - иди.",
+ "Если хочешь забыть - забудь.",
+ "Жи ши пиши от души.",
+ "Клади навоз густо - в амбаре будет не пусто.",
+ "Лучше с пацанами на подике, чем с чертями на шаттле.",
+ "Я ЗАПРЕЩАЮ ВАМ СРАТЬ!",
+ "Безумно можно.",
+ "Живи, кайфуй, гуляй, играй, упал - вставай, наглей, ругай, чужих роняй, NTOS обновляй, картошка, суп, пельмени, чай.",
+ // возвращаемся к дебильным фразам
+ "СЛАВА КРЫСИНОМУ СУПЕРСАТАНЕ!!!",
+ "ХОНК КРЫСБАР!!!",
+ "Я ПОЖАЛУЮСЬ НА ТЕБЯ В КОСМИЧЕСКОЕ СПОРТЛОТО!",
+ "СССП ПРИДИ ПОРЯДОК НАВЕДИ!",
+ "СЛАВА? КТО ТАКОЙ СЛАВА!?",
+ "Я МАШИНА",
+ "Я в своем познании настолько преисполнился...",
+ "Я в своем познании настолько преисполнился, что как будто бы уже сто триллионов миллиардов лет проживаю на триллионах и триллионах таких же станций, понимаешь?",
+ "ЧТО ЭТО НА ПОТОЛКЕ?!",
+ "ОНО СМОТРИТ НА МЕНЯ!!!",
+ "ГЛАЗА НА ПОТОЛКЕ!!!",
+ "ЧТО ЭТО ЗА РОЖА НА ПОТОЛКЕ?!",
+ "ГДЕ НАШ ПОТОЛОК?!",
+ "КУДА ВЫ ДЕЛИ ПОТОЛОК?!",
+ "А где потолок?!",
+ "ОЙ ДОГОНЮ!",
+ "АЙ НЕ ДОГОНИШЬ!",
+ "НЕ СМОТРИТЕ НА МЕНЯ!",
+ "ВСЕ СМОТРИТЕ НА МЕНЯ!",
+ "СМОТРИТЕ, СМОТРИТЕ НА МЕНЯ!",
+ "ПРЕКРАТИТЬ ХУЙНЮ!",
+ "ОГУЗКИ, ОГРЫЗКИ!",
+ "Я ЗНАКОМ С КОРОНОПРИНЦЕМ!",
+ "МОЙ ПАПА ГЛАВНЫЙ [pick("НА ЦК", "У ССП", "У ТСФ", "У СИНДИКАТА", "БАНДЮГАН", "И УВАЖАЕМЫЙ ЧЕЛОВЕК", "ОТЕЦ")]!!!",
+ "Мама мыла раму...",
+ "Ыыыы...",
+ "Ээээ...",
+ "ААА ААААА ААААААААА!!!",
+ "У меня слюна потекла...",
+ "Вытрите мою слюну!..",
+ "Мне нужна присыпка...",
+ "КОГДА ДОБАВЯТ ПОДЫ?!",
+
+ )
+ if(prob(95))
+ say(pick(crazysay))
+ else
+ var/list/flipsay = list(
+ "Зацени сальтуху!",
+ "Ща ебану сальтуху!",
+ "Сальтуха!",
+ "ЗАЦЕНИ ЧЕ МОГУ!!!",
+ "Опля!",
+ "Але ОП!",
+ "Волки в цирке не выступают - а делают сальтуху!",
+ "ЗАЦЕНИ!",
+ "А ТЫ ТАК СМОЖЕШЬ?!",
+ )
+ say(pick(flipsay))
+ emote("flip")
diff --git a/modular_ss220/phrases/code/vending_phrases.dm b/modular_ss220/phrases/code/vending_phrases.dm
new file mode 100644
index 000000000000..3754d1d443a9
--- /dev/null
+++ b/modular_ss220/phrases/code/vending_phrases.dm
@@ -0,0 +1,100 @@
+
+/obj/machinery/economy/vending/boozeomat/Initialize(mapload)
+ . = ..()
+ slogan_list |= list(
+ "Пригуби - не медли!",
+ "Жизнь плоха без бухла!",
+ "Чтобы пить - здоровым надо быть!",
+ "Насыпать вам немного сухого вина?",
+ "Всего лишь 26 литров пива достаточно взрослому человеку для покрытия дневной потребности в кальции.",
+ "Самая трезвая мысль за весь день - это мысль о выпивке!",
+ "Не говори НЕТ алкоголю. Он всеравно не услышит!",
+ "Инициатор ваших отношений - алкоголь!",
+ "Шотландская пословица: «Пошли дурака за скотчем, он и принесет липкую ленту».",
+ "50 грамм муравьев можно послать за бутылкой водки!",
+ "После бутылки коньяка беседа превращается в утечку информации.",
+ "Лечись пивом, мёдом и корицей. Такой вот метод неплохой! Если ты еще не бухой!",
+ "Не важно откуда ты, главное куда налил!",
+ "Ты не у себя дома, тебя не ждет гора посуды и бардак, а значит можно и выпить!",
+ "А ведь с кем только ни поведёшься, чтобы набраться!",
+ "Открывая колу - прикупите виски!",
+ "Вам виски прямые, косые, в бутылке?",
+ "Лучший проверенный телепорт и машина времени со старых времен!",
+ "Вирус водкой не убить, но можно напугать!",
+ "1 стопка водки в день - отгонит продавца яблоками!",
+ "Я знаю, что может быть лучше похмелья — похмелье на работе!",
+ "Проводим биатлон: пока бежишь за водкой, по пути стреляешь сигареты!",
+ )
+
+/obj/machinery/economy/vending/cigarette/Initialize(mapload)
+ . = ..()
+ slogan_list |= list(
+ "Обслужите даме рот!",
+ "Сигаретку, спичку, коробок?",
+ "На заметку. Люди, покупающие сигареты поштучно, не знают, что курение убивает.",
+ "Кури - убей в себе коня!",
+ "Ты уже бросаешь? Тогда начни вновь курить!",
+ "Сегодня мужчина считается джентльменом, если перед поцелуем он вынимает сигарету изо рта.",
+ "Если есть в кармане пачка сигарет - значит всё не так уж плохо на сегодняшний день!",
+ "И билет на самолёт с серебристым крылом, что, взлетая, оставляет земле лишь тень.",
+ "Что мне больше всего нравится в работе - это перекуры!",
+ "Ты можешь не прикасаться к сигарете, рюмке, женщине. Пока тебе не стукнет 18!",
+ "Если стрелять, то максимум сигареты. Если взрывать, то минимум танцпол!",
+ "Пока у человека есть сигареты - он многое вынесет.",
+ "Гаси свою вспышку гнева разжигая сигарету!",
+ "Окурок — это сигарета с богатым жизненным опытом.",
+ "Водка, хлеб, сигареты — без этого люди не проживут, мы этим предприятиям помогаем!", // реальная цитата Лукашенко
+ "В своей нелёгкой жизни, я два «безбашенных» поступка совершил. Не закурил от беса сигарету и тату на тело не набил!",
+ "Проводим биатлон: пока бежишь за водкой, по пути стреляешь сигареты!",
+ )
+
+/obj/machinery/economy/vending/syndicigs/Initialize(mapload)
+ . = ..()
+ // тоже самое
+ slogan_list |= list(
+ "Обслужите даме рот!",
+ "Сигаретку, спичку, коробок?",
+ "Минздраву на заметку. Люди, покупающие сигареты поштучно, не знают, что курение убивает.",
+ "Кури - убей в себе коня!",
+ "Ты уже бросаешь? Тогда начни вновь курить!",
+ "Сегодня мужчина считается джентльменом, если перед поцелуем он вынимает сигарету изо рта.",
+ "Если есть в кармане пачка сигарет - значит всё не так уж плохо на сегодняшний день!",
+ "И билет на самолёт с серебристым крылом, что, взлетая, оставляет земле лишь тень.",
+ "Что мне больше всего нравится в работе - это перекуры!",
+ "Своим здоровьем и долголетием я обязан тому, что ни разу не прикоснулся ни к сигарете, ни к рюмке, ни к женщине, пока мне не стукнуло десять.",
+ "Если стрелять, то максимум сигареты. Если взрывать, то минимум танцпол!",
+ "Пока у человека есть сигареты - он многое вынесет.",
+ "Гаси свою вспышку гнева разжигая сигарету!",
+ "Окурок — это сигарета с богатым жизненным опытом.",
+ "Жалей, что не закурил от беса сигарету и тату на тело не набил!",
+ "Проводим биатлон: пока бежишь за водкой, по пути стреляешь сигареты!",
+ )
+
+/obj/machinery/economy/vending/snack/Initialize(mapload)
+ . = ..()
+ slogan_list |= list(
+ "Один мальчик прожил без еды три года, потому что бутерброды — это не еда.",
+ "Заедай весь стресс!",
+ "Самая чистая и простая любовь — это любовь к еде.",
+ "Сыр – это труп молока.",
+ "Нет плохих блюд, есть плохо приготовленные.",
+ "Чаще аппетит приходит во время отсутствия еды.",
+ "Курица — это не птица, курица — это еда такая.",
+ "Назло врагам, съешь ужин сам.",
+ "Курица — существо, которое едят либо до его рождения, либо после его смерти.",
+ )
+
+/obj/machinery/economy/vending/syndisnack/Initialize(mapload)
+ . = ..()
+ // тоже самое
+ slogan_list |= list(
+ "Один мальчик прожил без еды три года, потому что бутерброды — это не еда.",
+ "Смертность от хачапури намного выше, чем смертность от харакири.",
+ "Самая чистая и простая любовь — это любовь к еде.",
+ "Сыр – это труп молока.",
+ "Нет плохих блюд, есть плохо приготовленные.",
+ "Чаще аппетит приходит во время отсутствия еды.",
+ "Курица — это не птица, курица — это еда такая.",
+ "Назло врагам, съешь ужин сам.",
+ "Курица — существо, которое едят либо до его рождения, либо после его смерти.",
+ )
diff --git a/modular_ss220/pixel_shift/_pixel_shift.dm b/modular_ss220/pixel_shift/_pixel_shift.dm
new file mode 100644
index 000000000000..477168b29ce6
--- /dev/null
+++ b/modular_ss220/pixel_shift/_pixel_shift.dm
@@ -0,0 +1,4 @@
+/datum/modpack/pixel_shift
+ name = "Pixel Shift"
+ desc = "Позволяет двигаться по-пиксельно в пределах турфа"
+ author = "larentoun"
diff --git a/modular_ss220/pixel_shift/_pixel_shift.dme b/modular_ss220/pixel_shift/_pixel_shift.dme
new file mode 100644
index 000000000000..358bedbd1246
--- /dev/null
+++ b/modular_ss220/pixel_shift/_pixel_shift.dme
@@ -0,0 +1,8 @@
+#include "_pixel_shift.dm"
+
+#include "code/_pixel_shift_defines.dm"
+#include "code/layer_shift.dm"
+#include "code/pixel_shift_component.dm"
+#include "code/pixel_shift_keybind.dm"
+#include "code/pixel_shift_mob.dm"
+#include "code/~pixel_shift_defines.dm"
diff --git a/modular_ss220/pixel_shift/code/_pixel_shift_defines.dm b/modular_ss220/pixel_shift/code/_pixel_shift_defines.dm
new file mode 100644
index 000000000000..23bcff0827dc
--- /dev/null
+++ b/modular_ss220/pixel_shift/code/_pixel_shift_defines.dm
@@ -0,0 +1,2 @@
+#define COMSIG_KB_MOB_PIXEL_SHIFT_DOWN "keybinding_mob_pixel_shift_down"
+#define COMSIG_KB_MOB_PIXEL_SHIFT_UP "keybinding_mob_pixel_shift_up"
diff --git a/modular_ss220/pixel_shift/code/layer_shift.dm b/modular_ss220/pixel_shift/code/layer_shift.dm
new file mode 100644
index 000000000000..3be3824c06fd
--- /dev/null
+++ b/modular_ss220/pixel_shift/code/layer_shift.dm
@@ -0,0 +1,36 @@
+#define MOB_LAYER_SHIFT_INCREMENT 0.01
+#define MOB_LAYER_SHIFT_MIN 3.95
+//#define MOB_LAYER 4 // This is a byond standard define
+#define MOB_LAYER_SHIFT_MAX 4.05
+
+/mob/living/verb/layershift_up()
+ set name = "Shift Layer Upwards"
+ set category = "IC"
+
+ if(incapacitated())
+ to_chat(src, span_warning("You can't do that right now!"))
+ return
+
+ if(layer >= MOB_LAYER_SHIFT_MAX)
+ to_chat(src, span_warning("You cannot increase your layer priority any further."))
+ return
+
+ layer += MOB_LAYER_SHIFT_INCREMENT
+ var/layer_priority = round((layer - MOB_LAYER) * 100, 1) // Just for text feedback
+ to_chat(src, span_notice("Your layer priority is now [layer_priority]."))
+
+/mob/living/verb/layershift_down()
+ set name = "Shift Layer Downwards"
+ set category = "IC"
+
+ if(incapacitated())
+ to_chat(src, span_warning("You can't do that right now!"))
+ return
+
+ if(layer <= MOB_LAYER_SHIFT_MIN)
+ to_chat(src, span_warning("You cannot decrease your layer priority any further."))
+ return
+
+ layer -= MOB_LAYER_SHIFT_INCREMENT
+ var/layer_priority = round((layer - MOB_LAYER) * 100, 1) // Just for text feedback
+ to_chat(src, span_notice("Your layer priority is now [layer_priority]."))
diff --git a/modular_ss220/pixel_shift/code/pixel_shift_component.dm b/modular_ss220/pixel_shift/code/pixel_shift_component.dm
new file mode 100644
index 000000000000..ad2055219623
--- /dev/null
+++ b/modular_ss220/pixel_shift/code/pixel_shift_component.dm
@@ -0,0 +1,99 @@
+#define MAXIMUM_PIXEL_SHIFT 12
+#define PASSABLE_SHIFT_THRESHOLD 8
+
+/datum/component/pixel_shift
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+ /// Whether the mob is pixel shifted or not
+ var/is_shifted = FALSE
+ /// If we are in the shifting setting.
+ var/shifting = TRUE
+ /// Takes the four cardinal direction defines. Any atoms moving into this atom's tile will be allowed to from the added directions.
+ var/passthroughable = NONE
+
+/datum/component/pixel_shift/Initialize(...)
+ . = ..()
+ if(!isliving(parent) || isAI(parent))
+ return COMPONENT_INCOMPATIBLE
+
+/datum/component/pixel_shift/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_KB_MOB_PIXEL_SHIFT_DOWN, PROC_REF(pixel_shift_down))
+ RegisterSignal(parent, COMSIG_KB_MOB_PIXEL_SHIFT_UP, PROC_REF(pixel_shift_up))
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(unpixel_shift))
+ RegisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_IMMOBILIZED), PROC_REF(unpixel_shift))
+ RegisterSignal(parent, COMSIG_LIVING_PROCESS_SPACEMOVE, PROC_REF(pre_move_check))
+ RegisterSignal(parent, COMSIG_LIVING_CAN_PASS, PROC_REF(check_passable))
+
+/datum/component/pixel_shift/UnregisterFromParent()
+ UnregisterSignal(parent, COMSIG_KB_MOB_PIXEL_SHIFT_DOWN)
+ UnregisterSignal(parent, COMSIG_KB_MOB_PIXEL_SHIFT_UP)
+ UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)
+ UnregisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_IMMOBILIZED))
+ UnregisterSignal(parent, COMSIG_LIVING_PROCESS_SPACEMOVE)
+ UnregisterSignal(parent, COMSIG_LIVING_CAN_PASS)
+
+/datum/component/pixel_shift/proc/pre_move_check(mob/source, movement_dir)
+ SIGNAL_HANDLER
+ if(shifting)
+ pixel_shift(source, movement_dir)
+ return COMPONENT_BLOCK_SPACEMOVE
+
+/datum/component/pixel_shift/proc/check_passable(mob/source, atom/movable/mover, target, height)
+ SIGNAL_HANDLER
+ var/mob/living/carbon/human/owner = parent
+ if(!istype(mover, /obj/item/projectile) && !mover.throwing && passthroughable & get_dir(owner, mover))
+ return COMPONENT_LIVING_PASSABLE
+
+/datum/component/pixel_shift/proc/pixel_shift_down()
+ SIGNAL_HANDLER
+ shifting = TRUE
+ return COMSIG_KB_ACTIVATED
+
+/datum/component/pixel_shift/proc/pixel_shift_up()
+ SIGNAL_HANDLER
+ shifting = FALSE
+
+/datum/component/pixel_shift/proc/unpixel_shift()
+ SIGNAL_HANDLER
+ passthroughable = NONE
+ if(is_shifted)
+ var/mob/living/owner = parent
+ owner.pixel_x = owner.get_standard_pixel_x_offset()
+ owner.pixel_y = owner.get_standard_pixel_y_offset()
+ qdel(src)
+
+/datum/component/pixel_shift/proc/pixel_shift(mob/target, direction)
+ var/mob/living/owner = parent
+ if(HAS_TRAIT(owner, TRAIT_RESTRAINED) || HAS_TRAIT(owner, TRAIT_IMMOBILIZED) || length(owner.grabbed_by) || owner.stat != CONSCIOUS)
+ return
+ passthroughable = NONE
+ switch(direction)
+ if(NORTH)
+ if(owner.pixel_y < MAXIMUM_PIXEL_SHIFT + initial(owner.pixel_y))
+ owner.pixel_y++
+ is_shifted = TRUE
+ if(EAST)
+ if(owner.pixel_x < MAXIMUM_PIXEL_SHIFT + initial(owner.pixel_x))
+ owner.pixel_x++
+ is_shifted = TRUE
+ if(SOUTH)
+ if(owner.pixel_y > -MAXIMUM_PIXEL_SHIFT + initial(owner.pixel_y))
+ owner.pixel_y--
+ is_shifted = TRUE
+ if(WEST)
+ if(owner.pixel_x > -MAXIMUM_PIXEL_SHIFT + initial(owner.pixel_x))
+ owner.pixel_x--
+ is_shifted = TRUE
+
+ // Yes, I know this sets it to true for everything if more than one is matched.
+ // Movement doesn't check diagonals, and instead just checks EAST or WEST, depending on where you are for those.
+ if(owner.pixel_y - initial(owner.pixel_y) > PASSABLE_SHIFT_THRESHOLD)
+ passthroughable |= EAST | SOUTH | WEST
+ else if(owner.pixel_y - initial(owner.pixel_y) < -PASSABLE_SHIFT_THRESHOLD)
+ passthroughable |= NORTH | EAST | WEST
+ if(owner.pixel_x - initial(owner.pixel_x) > PASSABLE_SHIFT_THRESHOLD)
+ passthroughable |= NORTH | SOUTH | WEST
+ else if(owner.pixel_x - initial(owner.pixel_x) < -PASSABLE_SHIFT_THRESHOLD)
+ passthroughable |= NORTH | EAST | SOUTH
+
+#undef MAXIMUM_PIXEL_SHIFT
+#undef PASSABLE_SHIFT_THRESHOLD
diff --git a/modular_ss220/pixel_shift/code/pixel_shift_keybind.dm b/modular_ss220/pixel_shift/code/pixel_shift_keybind.dm
new file mode 100644
index 000000000000..b845107ae2ef
--- /dev/null
+++ b/modular_ss220/pixel_shift/code/pixel_shift_keybind.dm
@@ -0,0 +1,14 @@
+/datum/keybinding/living/pixel_shift
+ keys = list("B")
+ name = "Pixel Shift"
+ category = KB_CATEGORY_MOVEMENT
+
+/datum/keybinding/living/pixel_shift/down(client/user)
+ . = ..()
+ if(SEND_SIGNAL(user.mob, COMSIG_KB_MOB_PIXEL_SHIFT_DOWN) & COMSIG_KB_ACTIVATED)
+ return
+ user.mob.add_pixel_shift_component()
+
+/datum/keybinding/living/pixel_shift/up(client/user)
+ . = ..()
+ SEND_SIGNAL(user.mob, COMSIG_KB_MOB_PIXEL_SHIFT_UP)
diff --git a/modular_ss220/pixel_shift/code/pixel_shift_mob.dm b/modular_ss220/pixel_shift/code/pixel_shift_mob.dm
new file mode 100644
index 000000000000..1180d44cf9a4
--- /dev/null
+++ b/modular_ss220/pixel_shift/code/pixel_shift_mob.dm
@@ -0,0 +1,13 @@
+/mob/proc/add_pixel_shift_component()
+ return
+
+/mob/living/add_pixel_shift_component()
+ AddComponent(/datum/component/pixel_shift)
+
+/mob/living/silicon/ai/add_pixel_shift_component()
+ return
+
+/datum/species/moth/spec_Process_Spacemove(mob/living/carbon/human/H)
+ . = ..()
+ if(has_gravity(H))
+ return FALSE
diff --git a/modular_ss220/pixel_shift/code/~pixel_shift_defines.dm b/modular_ss220/pixel_shift/code/~pixel_shift_defines.dm
new file mode 100644
index 000000000000..bb4bb97b64dd
--- /dev/null
+++ b/modular_ss220/pixel_shift/code/~pixel_shift_defines.dm
@@ -0,0 +1,2 @@
+#undef COMSIG_KB_MOB_PIXEL_SHIFT_DOWN
+#undef COMSIG_KB_MOB_PIXEL_SHIFT_UP
diff --git a/modular_ss220/preferences/_preferences.dm b/modular_ss220/preferences/_preferences.dm
new file mode 100644
index 000000000000..13404d8e8a5a
--- /dev/null
+++ b/modular_ss220/preferences/_preferences.dm
@@ -0,0 +1,4 @@
+/datum/modpack/preferences
+ name = "Кастомные настройки"
+ desc = "Игровые настройки, разработанные для проекта"
+ author = "Maxiemar"
diff --git a/modular_ss220/preferences/_preferences.dme b/modular_ss220/preferences/_preferences.dme
new file mode 100644
index 000000000000..4a65419c8dd1
--- /dev/null
+++ b/modular_ss220/preferences/_preferences.dme
@@ -0,0 +1,4 @@
+#include "_preferences.dm"
+
+#include "code/preferences.dm"
+#include "code/preferences_toggles.dm"
diff --git a/modular_ss220/preferences/code/preferences.dm b/modular_ss220/preferences/code/preferences.dm
new file mode 100644
index 000000000000..cc4df2865aa0
--- /dev/null
+++ b/modular_ss220/preferences/code/preferences.dm
@@ -0,0 +1,59 @@
+/datum/preferences
+ var/toggles220 = TOGGLES_220_DEFAULT
+
+/datum/preferences/load_preferences(datum/db_query/query)
+ . = ..()
+ if(!.)
+ return
+
+ return load_custom_preferences()
+
+/datum/preferences/save_preferences(client/C)
+ . = ..()
+ if(!.)
+ return
+
+ return save_custom_preferences(C)
+
+/datum/preference_toggle/set_toggles(client/user)
+ var/datum/preferences/our_prefs = user.prefs
+ switch(preftoggle_toggle)
+ if(PREFTOGGLE_TOGGLE220)
+ our_prefs.toggles220 ^= preftoggle_bitflag
+ to_chat(user, "[(our_prefs.toggles220 & preftoggle_bitflag) ? enable_message : disable_message]")
+ . = ..()
+
+/datum/preferences/proc/load_custom_preferences()
+ var/datum/db_query/preferences_query = SSdbcore.NewQuery({"SELECT
+ toggles
+ FROM player_220
+ WHERE ckey=:ckey"}, list(
+ "ckey" = parent.ckey
+ ))
+
+ if(!preferences_query.warn_execute())
+ qdel(preferences_query)
+ return FALSE
+
+ while(preferences_query.NextRow())
+ toggles220 = preferences_query.item[1]
+
+ toggles220 = sanitize_integer(toggles220, 0, TOGGLES_220_TOTAL, initial(toggles220))
+
+ qdel(preferences_query)
+ return TRUE
+
+/datum/preferences/proc/save_custom_preferences(client/C)
+ var/datum/db_query/query = SSdbcore.NewQuery({"UPDATE player_220 SET
+ toggles=:toggles
+ WHERE ckey=:ckey"}, list(
+ "toggles" = num2text(toggles220, CEILING(log(10, (TOGGLES_220_TOTAL)), 1)),
+ "ckey" = C.ckey,
+ ))
+
+ if(!query.warn_execute())
+ qdel(query)
+ return FALSE
+
+ qdel(query)
+ return TRUE
diff --git a/modular_ss220/preferences/code/preferences_toggles.dm b/modular_ss220/preferences/code/preferences_toggles.dm
new file mode 100644
index 000000000000..473738f2bdc0
--- /dev/null
+++ b/modular_ss220/preferences/code/preferences_toggles.dm
@@ -0,0 +1,9 @@
+/datum/preference_toggle/toggle_credits
+ name = "Показывать титры"
+ description = "Показывать титры по окончании раунда"
+ preftoggle_bitflag = PREFTOGGLE_220_WATCH_CREDITS
+ preftoggle_toggle = PREFTOGGLE_TOGGLE220
+ preftoggle_category = PREFTOGGLE_CATEGORY_LIVING
+ enable_message = "Вы будете видеть титры в конце раундов."
+ disable_message = "Вы не будете видеть титры в конце раундов."
+ blackbox_message = "Toggle Credits"
diff --git a/modular_ss220/prime_only/_prime.dm b/modular_ss220/prime_only/_prime.dm
new file mode 100644
index 000000000000..18b003263ed0
--- /dev/null
+++ b/modular_ss220/prime_only/_prime.dm
@@ -0,0 +1,13 @@
+/datum/modpack/prime_only
+ name = "Эксклюзивы прайма"
+ desc = "Всё что попросили стримеры эксклюзивно для прайма."
+ author = "Все кто сюда полез."
+
+/datum/modpack/prime_only/pre_initialize()
+ . = ..()
+
+/datum/modpack/prime_only/initialize()
+ . = ..()
+
+/datum/modpack/prime_only/post_initialize()
+ . = ..()
diff --git a/modular_ss220/prime_only/_prime.dme b/modular_ss220/prime_only/_prime.dme
new file mode 100644
index 000000000000..901850d569ec
--- /dev/null
+++ b/modular_ss220/prime_only/_prime.dme
@@ -0,0 +1,12 @@
+#include "_prime.dm"
+
+#include "code/anakonda.dm"
+#include "code/cattleprod.dm"
+#include "code/clothing/under.dm"
+#include "code/megafauna.dm"
+#include "code/objects.dm"
+#include "code/outfit.dm"
+#include "code/tts_seeds.dm"
+#include "code/vending.dm"
+#include "code/crematorium.dm"
+#include "code/shuttle_gib.dm"
diff --git a/modular_ss220/prime_only/code/anakonda.dm b/modular_ss220/prime_only/code/anakonda.dm
new file mode 100644
index 000000000000..4b7cc11f0e3a
--- /dev/null
+++ b/modular_ss220/prime_only/code/anakonda.dm
@@ -0,0 +1,7 @@
+/obj/structure/displaycase/hos
+ start_showpiece_type = /obj/item/gun/projectile/revolver/reclinable/anaconda
+
+/obj/structure/closet/secure_closet/hos/populate_contents()
+ . = ..()
+ for(var/i in 1 to 3)
+ new /obj/item/ammo_box/speed_loader_d44(src)
diff --git a/modular_ss220/prime_only/code/cattleprod.dm b/modular_ss220/prime_only/code/cattleprod.dm
new file mode 100644
index 000000000000..2a71b5f76849
--- /dev/null
+++ b/modular_ss220/prime_only/code/cattleprod.dm
@@ -0,0 +1,2 @@
+/obj/item/melee/baton/cattleprod
+ w_class = WEIGHT_CLASS_NORMAL
diff --git a/modular_ss220/prime_only/code/clothing/under.dm b/modular_ss220/prime_only/code/clothing/under.dm
new file mode 100644
index 000000000000..488977d08724
--- /dev/null
+++ b/modular_ss220/prime_only/code/clothing/under.dm
@@ -0,0 +1,33 @@
+// Explorer's outfits
+/obj/item/clothing/under/rank/cargo/expedition_prime
+ name = "navy expedition uniform"
+ desc = "Экспедиционная форма военного образца с опознавательными знаками Нанотрейзен."
+ armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 20, ACID = 20)
+ icon = 'modular_ss220/prime_only/icons/object/under.dmi'
+ icon_state = "expedition_prime_navy"
+ item_state = "expedition_prime_navy"
+ item_color = "expedition_prime_navy"
+ sprite_sheets = list(
+ "Human" = 'modular_ss220/prime_only/icons/mob/under.dmi',
+ "Vox" = 'modular_ss220/prime_only/icons/mob/species/vox/under/cargo.dmi',
+ "Drask" = 'modular_ss220/prime_only/icons/mob/species/drask/under/cargo.dmi',
+ "Kidan" = 'modular_ss220/prime_only/icons/mob/species/kidan/under/cargo.dmi',
+ )
+
+/obj/item/clothing/under/rank/cargo/expedition_prime/green
+ name = "green expedition uniform"
+ icon_state = "expedition_prime_green"
+ item_state = "expedition_prime_green"
+ item_color = "expedition_prime_green"
+
+/obj/item/clothing/under/rank/cargo/expedition_prime/tan
+ name = "tan expedition uniform"
+ icon_state = "expedition_prime_tan"
+ item_state = "expedition_prime_tan"
+ item_color = "expedition_prime_tan"
+
+/obj/item/clothing/under/rank/cargo/expedition_prime/grey
+ name = "grey expedition uniform"
+ icon_state = "expedition_prime_grey"
+ item_state = "expedition_prime_grey"
+ item_color = "expedition_prime_grey"
diff --git a/modular_ss220/prime_only/code/crematorium.dm b/modular_ss220/prime_only/code/crematorium.dm
new file mode 100644
index 000000000000..7551b999d7c4
--- /dev/null
+++ b/modular_ss220/prime_only/code/crematorium.dm
@@ -0,0 +1,9 @@
+/obj/structure/crematorium/ex_act(severity)
+ switch(severity)
+ if(EXPLODE_DEVASTATE)
+ obj_break()
+ if(EXPLODE_HEAVY)
+ take_damage(150)
+ if(EXPLODE_LIGHT)
+ take_damage(50)
+
diff --git a/modular_ss220/prime_only/code/megafauna.dm b/modular_ss220/prime_only/code/megafauna.dm
new file mode 100644
index 000000000000..e0099694939a
--- /dev/null
+++ b/modular_ss220/prime_only/code/megafauna.dm
@@ -0,0 +1,4 @@
+/mob/living/simple_animal/hostile/megafauna/drop_loot()
+ if(length(loot) && prob(50))
+ for(var/item in loot)
+ new item(get_turf(src))
diff --git a/modular_ss220/prime_only/code/objects.dm b/modular_ss220/prime_only/code/objects.dm
new file mode 100644
index 000000000000..9356f0a73176
--- /dev/null
+++ b/modular_ss220/prime_only/code/objects.dm
@@ -0,0 +1,209 @@
+#define LEGENDARY_SWORDS_CKEY_WHITELIST list("mooniverse")
+
+/obj/item/melee/rapier/cane_rapier
+ name = "Трость-рапира"
+ desc = "Стилизованная под трость рапира, чье элегантное и обоюдоострое лезвие усажено на роскошно украшенную рукоять. Одни лишь инкрустированные в неё драгоценные камни стоят как целая звездная система."
+ icon = 'modular_ss220/prime_only/icons/saber.dmi'
+ icon_state = "trrapier"
+ item_state = "trrapier"
+ force = 25
+ lefthand_file = 'modular_ss220/prime_only/icons/saber_left.dmi'
+ righthand_file = 'modular_ss220/prime_only/icons/saber_right.dmi'
+
+/obj/item/storage/belt/rapier/cane_rapier
+ name = "Трость-рапира"
+ desc = "Ножны стилизованной под трость рапиры. Их корпус вырезан из черного дерева и щедро украшен позолотой. Их владелец обладает неоспоримый богатством и властью в известной Галактике."
+ icon_state = "trsheath"
+ item_state = "trsheath"
+ icon = 'modular_ss220/prime_only/icons/saber.dmi'
+ lefthand_file = 'modular_ss220/prime_only/icons/saber_left.dmi'
+ righthand_file = 'modular_ss220/prime_only/icons/saber_right.dmi'
+ can_hold = list(/obj/item/melee/rapier/cane_rapier)
+
+/obj/item/storage/belt/rapier/cane_rapier/populate_contents()
+ new /obj/item/melee/rapier/cane_rapier(src)
+ update_icon()
+
+/obj/item/dualsaber/legendary_saber
+ name = "Злоба"
+ desc = "\"Злоба\" - один из легендарных энергетических мечей Галактики. Словно источая мистическую энергию, \"Злоба\" является олицетворением самой Тьмы, вызывающей трепет и ужас врагов её владельца. Гладкая и простая рукоять меча не может похвастаться орнаментами, узорами или древними рунами, но способна выплескивать рванный энергетический клинок кроваво-красного света, словно кричащий о непокорности и ярости своего владельца. Некоторые истории гласят, что в этом клинке прибывает сама темная сущность могущества и бесконечного гнева, готовая исполнить волю своего хозяина даже за пределами пространства и времени. \n Создатель: Согда К'Трим. Текущий владелец: Миднайт Блэк."
+ icon = 'modular_ss220/prime_only/icons/saber.dmi'
+ lefthand_file = 'modular_ss220/prime_only/icons/saber_left.dmi'
+ righthand_file = 'modular_ss220/prime_only/icons/saber_right.dmi'
+ icon_state = "mid_dualsaber0"
+ blade_color = "midnight"
+ colormap = LIGHT_COLOR_RED
+ wieldsound = 'modular_ss220/prime_only/sound/weapons/mid_saberon.ogg'
+ unwieldsound = 'modular_ss220/prime_only/sound/weapons/mid_saberoff.ogg'
+ var/saber_name = "mid"
+ var/hit_wield = 'modular_ss220/prime_only/sound/weapons/mid_saberhit.ogg'
+ var/hit_unwield = "swing_hit"
+ var/ranged = FALSE
+ var/power = 1
+ var/refusal_text = "Злоба неподвластна твоей воле, усмрить её сможет лишь сильнейший."
+ var/datum/enchantment/enchant = new/datum/enchantment/dash
+
+/obj/item/dualsaber/legendary_saber/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/ckey_and_role_locked_pickup, TRUE, LEGENDARY_SWORDS_CKEY_WHITELIST, pickup_damage = 10, refusal_text = refusal_text)
+
+/obj/item/dualsaber/legendary_saber/update_icon_state()
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
+ icon_state = "[saber_name]_dualsaber[blade_color]1"
+ set_light(brightness_on, l_color=colormap)
+ else
+ icon_state = "[saber_name]_dualsaber0"
+ set_light(0)
+
+/obj/item/dualsaber/legendary_saber/on_wield(obj/item/source, mob/living/carbon/user)
+ if(user && HAS_TRAIT(user, TRAIT_HULK))
+ to_chat(user, "You lack the grace to wield this!")
+ return COMPONENT_TWOHANDED_BLOCK_WIELD
+
+ hitsound = hit_wield
+ w_class = w_class_on
+
+/obj/item/dualsaber/legendary_saber/on_unwield()
+ hitsound = hit_unwield
+ w_class = initial(w_class)
+
+/obj/item/dualsaber/legendary_saber/sorrow_catcher
+ name = "Ловец Скорби"
+ desc = "\"Ловец Скорби\" (Второе название \"Плакса\") - один из легендарных энергетических мечей Галактики. Он символизирует не только силу власти и могущества, но и является предметом гордости своего обладателя. Искусно выполненный клинок излучает мягкий голубой свет, словно призывая к миру и согласию, но при этом скрывает в себе силу и решимость защитить своего хозяина любой ценой. Рукоять меча сконструирована строго и со вкусом, создана из темного металла с матовым покрытием и украшена фреской логотипа NT. \"Ловец Скорби\" имеет специфический звук, отдалённо напоминающий женский плач. Поэтому, немногие очевидцы гнева его хозяина дали мечу второе название - \"Плакса.\" \n Создатель: Гаскон-Валлен-Деламот. Текущий владелец: Билл Громов."
+ icon_state = "gr_dualsaber0"
+ blade_color = "gromov"
+ refusal_text = "Ну, заплачь."
+ colormap = LIGHT_COLOR_LIGHT_CYAN
+ saber_name = "gr"
+ wieldsound = 'modular_ss220/prime_only/sound/weapons/gr_saberon.ogg'
+ unwieldsound = 'modular_ss220/prime_only/sound/weapons/gr_saberoff.ogg'
+ hit_wield = 'modular_ss220/prime_only/sound/weapons/gr_saberhit.ogg'
+
+/obj/item/dualsaber/legendary_saber/flame
+ name = "Пламя"
+ desc = "\"Пламя\" - один из легендарных энергетических мечей Галактики. Он отражает неумолимую справедливость и рьяность характера своего хозяина. В противоречие грозному названию, эфес меча представляет собой аккуратное и \"нежное\" произведение искусства - отполированная нарезная титановая основа завершается золотым навершием, а декоративная гарда выполнен в виде раскрывшегося бутона. Энергетический клинок источает яркий фиолетовый свет, несущий очищение и упокоение своим врагам. Рукоять меча крайне хорошо сбалансирована и отдает дань аристократическим традициям человеческого прошлого. \n Создатель: Гаскон-Валлен-Деламот. Текущий владелец: Шарлотта Дитерхис."
+ icon_state = "sh_dualsaber0"
+ blade_color = "sharlotta"
+ refusal_text = "Кровь и свет принадлежат лишь одному."
+ colormap = LIGHT_COLOR_LAVENDER
+ saber_name = "sh"
+ wieldsound = 'modular_ss220/prime_only/sound/weapons/sh_saberon.ogg'
+ unwieldsound = 'modular_ss220/prime_only/sound/weapons/sh_saberoff.ogg'
+ hit_wield = 'modular_ss220/prime_only/sound/weapons/sh_saberhit.ogg'
+
+/obj/item/dualsaber/legendary_saber/devotion
+ name = "Верность клятве"
+ desc = "\"Верность Клятве\" - один из легендарных энергетических мечей Галактики. Этот меч в первую очередь является сакральным символом, связывающий своего владельца вечной Клятвой. Его украшенную древними иероглифами человеческой расы рукоять покрывает хромированный сатин, а двойное изумрудно-зелёное лезвие меча требует от своего хозяина виртуозности и мастерства в обращении, в то же время являясь испытанием доблести, чести и силы духа. Одна из историй этого артефакта гласит, что в свечении клинка отражается душа его создателя - Арканона, который проводил долгие годы в изоляции в попытках создать что-то большее, чем просто оружие. \n Создатель: Арканон. Текущий владелец: Хель Кириэн."
+ icon_state = "kir_dualsaber0"
+ blade_color = "kirien"
+ refusal_text = "Только достойный узрит свет."
+ colormap = LIGHT_COLOR_PURE_GREEN
+ saber_name = "kir"
+ wieldsound = 'modular_ss220/prime_only/sound/weapons/kir_saberon.ogg'
+ unwieldsound = 'modular_ss220/prime_only/sound/weapons/kir_saberoff.ogg'
+ hit_wield = 'modular_ss220/prime_only/sound/weapons/kir_saberhit.ogg'
+
+/obj/item/dualsaber/legendary_saber/sister
+ name = "Сестра"
+ desc = "\"Сестра\" - один из легендарных энергетических мечей Галактики. Являясь \"старшей\" парной частью еще одного легендарного меча - \"Ловца Бегущих\", это оружие представляет собой удивительный артефакт с глубокой историей и мистическими свойствами. Его лезвие излучает мягкий золотой свет, который извечно является символом мудрости и мощи. \"Сестра\" - это не просто меч, а символ верности высшим идеалам, дающий своему хозяину силу и решимость. Форма рукояти отсылает к оружию Справедливых Рыцарей древней человеческой истории и обладает строгим стилем, дополняющим своего владельца. Всю свою историю этот меч являлся желанным объектом многих великих существ, но \"Сестра\" способна поистине раскрыться лишь в руках того, кто искренне верит в силу справедливости и не понаслышке знает что такое честь и доблесть. \n Создатель: Коникс`Хеллькикс. Текущий Владелец: Мунивёрс Нормандия."
+ icon_state = "norm_dualsaber0"
+ blade_color = "normandy"
+ refusal_text = "Ты не принадлежишь сестре, верни её законному владельцу."
+ colormap = LIGHT_COLOR_HOLY_MAGIC
+ saber_name = "norm"
+ wieldsound = 'modular_ss220/prime_only/sound/weapons/norm_saberon.ogg'
+ unwieldsound = 'modular_ss220/prime_only/sound/weapons/norm_saberoff.ogg'
+ hit_wield = 'modular_ss220/prime_only/sound/weapons/norm_saberhit.ogg'
+
+/obj/item/dualsaber/legendary_saber/flee_catcher
+ name = "Ловец Бегущих"
+ desc = "\"Ловец Бегущих\" - один из легендарных энергетических мечей Галактики. Являясь \"младшей\" парной частью еще одного легендарного меча - \"Сестры\", это оружие представляет собой более грубое и практичное творение. Корпус рукояти, изобилующий царапинами и потёртостями, говорит о тяжелой истории меча. Одной из традиций владельцев этого оружия является рисование под кнопкой включения отметок в виде белых жетонов, коих уже насчитывается семь штук. Рядом с самым первым жетоном выгравирована надпись : \"2361. А.М.\" \n Цвет клинка ярко-желтый, его рукоять удлинена для комфортного боя как одной, так и двумя руками, навершие Типа \"P\" покрыто золотом и обладает специальным разъёмом для подключения своей старшей \"Сестры\", а гарда представляет собой два закругленных декоративных отростка. Из старых легенд известно, что строптивый и бурный характер меча могли сдержать лишь настоящие мастера, которые использовали хаотичный, но адаптивный под врага стиль боя. \n Создатель: Коникс`Хеллькикс. Текущий Владелец: Мунивёрс Нормандия, в последствии был передан Рицу Келли."
+ icon_state = "kel_dualsaber0"
+ blade_color = "kelly"
+ refusal_text = "Ловец бегущих не слушается тебя, кажется он хочет вернуться к хозяину."
+ colormap = LIGHT_COLOR_HOLY_MAGIC
+ saber_name = "kel"
+ wieldsound = 'modular_ss220/prime_only/sound/weapons/kel_saberon.ogg'
+ unwieldsound = 'modular_ss220/prime_only/sound/weapons/kel_saberoff.ogg'
+ hit_wield = 'modular_ss220/prime_only/sound/weapons/kel_saberhit.ogg'
+
+/obj/item/dualsaber/legendary_saber/afterattack__legacy__attackchain(atom/target, mob/user, proximity_flag, click_parameters)
+ . = ..()
+ enchant?.on_legendary_hit(target, user, proximity_flag, src)
+
+/obj/item/dualsaber/legendary_saber/proc/add_enchantment(new_enchant, mob/living/user, intentional = TRUE)
+ var/datum/enchantment/E = new new_enchant
+ enchant = E
+ E.on_gain(src, user)
+ E.power *= power
+ if(intentional)
+ SSblackbox.record_feedback("nested tally", "saber_enchants", 1, list("[E.name]"))
+
+/datum/enchantment/dash/proc/charge(mob/living/user, atom/chargeat, obj/item/dualsaber/legendary_saber/S)
+ if(on_leap_cooldown)
+ return
+ if(!chargeat)
+ return
+ var/turf/destination_turf = get_turf(chargeat)
+
+ if(!destination_turf)
+ return
+ var/list/targets = list()
+ for(var/atom/target in destination_turf.contents)
+ targets += target
+ charging = TRUE
+
+ var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(user.loc, user)
+ animate(D, alpha = 0, color = "#271e77", transform = matrix()*1, time = anim_time, loop = anim_loop)
+
+ var/i
+ for(i=0, i<5, i++)
+ spawn(i * 9 MILLISECONDS)
+ step_to(user, destination_turf , 1, movespeed)
+ var/obj/effect/temp_visual/decoy/D2 = new /obj/effect/temp_visual/decoy(user.loc, user)
+ animate(D2, alpha = 0, color = "#271e77", transform = matrix()*1, time = anim_time, loop = anim_loop)
+
+ spawn(45 MILLISECONDS)
+ if(get_dist(user, destination_turf) > 1)
+ return
+ charge_end(targets, user, S)
+
+/datum/enchantment/dash/proc/charge_end(list/targets = list(), mob/living/user, obj/item/dualsaber/legendary_saber/S)
+ charging = FALSE
+
+ for(var/mob/living/L in targets)
+ if(!(L == user))
+ user.apply_damage(-40, STAMINA)
+ S.melee_attack_chain(user, L)
+
+/datum/enchantment/dash
+ name = "Рывок"
+ desc = "Этот клинок несёт владельца прямо к цели. Никто не уйдёт."
+ ranged = TRUE
+ var/movespeed = 0.8
+ var/on_leap_cooldown = FALSE
+ var/charging = FALSE
+ var/anim_time = 3 DECISECONDS
+ var/anim_loop = 3 DECISECONDS
+
+/datum/enchantment/proc/on_legendary_hit(mob/living/target, mob/living/user, proximity, obj/item/dualsaber/legendary_saber/S)
+ if(world.time < cooldown)
+ return FALSE
+ if(!istype(target))
+ return FALSE
+ if(target.stat == DEAD)
+ return FALSE
+ if(!ranged && !proximity)
+ return FALSE
+ cooldown = world.time + initial(cooldown)
+ return TRUE
+
+/datum/enchantment/dash/on_legendary_hit(mob/living/target, mob/living/user, proximity, obj/item/dualsaber/legendary_saber/S)
+ if(proximity) // don't put it on cooldown if adjacent
+ return
+ . = ..()
+ if(!.)
+ return
+
+ if(HAS_TRAIT(S, TRAIT_WIELDED))
+ charge(user, target, S)
diff --git a/modular_ss220/prime_only/code/outfit.dm b/modular_ss220/prime_only/code/outfit.dm
new file mode 100644
index 000000000000..ab60576132b5
--- /dev/null
+++ b/modular_ss220/prime_only/code/outfit.dm
@@ -0,0 +1,6 @@
+// Explorer's outfits
+/datum/outfit/job/explorer
+ uniform = /obj/item/clothing/under/rank/cargo/expedition_prime
+ head = /obj/item/clothing/head/soft/black
+ backpack = /obj/item/storage/backpack
+ satchel = /obj/item/storage/backpack/satchel_norm
diff --git a/modular_ss220/prime_only/code/shuttle_gib.dm b/modular_ss220/prime_only/code/shuttle_gib.dm
new file mode 100644
index 000000000000..337cca3e900c
--- /dev/null
+++ b/modular_ss220/prime_only/code/shuttle_gib.dm
@@ -0,0 +1,87 @@
+#define SHUTTLE_ROADKILL_TELEPORTATION_RANGE 24
+
+/obj/docking_port/mobile/roadkill(list/L0, list/L1, dir)
+ for(var/i in 1 to length(L0))
+ var/turf/T0 = L0[i]
+ var/turf/T1 = L1[i]
+ if(!T0 || !T1)
+ continue
+
+ for(var/atom/movable/AM in T1)
+ if(AM.pulledby)
+ AM.pulledby.stop_pulling()
+ if(AM.flags_2 & IMMUNE_TO_SHUTTLECRUSH_2)
+ if(istype(AM, /obj/machinery/atmospherics/supermatter_crystal))
+ var/obj/machinery/atmospherics/supermatter_crystal/bakoom = AM
+ addtimer(CALLBACK(bakoom, TYPE_PROC_REF(/obj/machinery/atmospherics/supermatter_crystal, explode), bakoom.combined_gas, bakoom.power, bakoom.gasmix_power_ratio), 1 SECONDS)
+ continue
+ // Your mech will not save you.
+ if(ismecha(AM))
+ var/obj/mecha/mech = AM
+ if(mech.occupant)
+ INVOKE_ASYNC(mech, TYPE_PROC_REF(/obj/mecha, get_out_and_die))
+ continue // It's required to avoid qdeling of mech in case of space turf. Non space turf are handled by get_out_and_die() proc
+ if(ismob(AM))
+ var/mob/M = AM
+ if(M.buckled)
+ M.buckled.unbuckle_mob(M, force = TRUE)
+ if(isliving(AM))
+ if(roadkill_living(AM))
+ continue
+ else if(lance_docking) //corrupt the child, destroy them all
+ if(!AM.simulated)
+ continue
+ if(istype(AM, /mob/dead))
+ continue
+ if(istype(AM, /obj/item/organ))
+ continue
+ if(istype(AM, /obj/effect/landmark))
+ continue
+ if(istype(AM, /obj/docking_port))
+ continue
+ qdel(AM, force = TRUE)
+
+ // Move unanchored atoms
+ if(!AM.anchored && !ismob(AM))
+ step(AM, dir)
+ else
+ if(AM.simulated) // Don't qdel lighting overlays, they are static
+ qdel(AM)
+
+/obj/docking_port/mobile/proc/roadkill_living(mob/living/target)
+ if(target.incorporeal_move || target.status_flags & GODMODE)
+ return TRUE // Calls 'continue'
+ target.stop_pulling()
+ if(isspaceturf(get_turf(target)))
+ target.visible_message(
+ span_warning("[target] иcчезает в спышке блюспейс излучения в тот момент, когда шаттл материализуется в нашем пространстве!"),
+ span_userdanger("Вы чувствуете, будто вас сейчас стошнит. Блюспейс прыжок шаттла телепортировал вас в другое место!")
+ )
+ do_teleport(target, get_turf(target), SHUTTLE_ROADKILL_TELEPORTATION_RANGE, sound_in = 'sound/effects/phasein.ogg')
+ return TRUE // Calls 'continue' to avoid qdeling of mob
+ else
+ target.visible_message(
+ span_warning("Тело [target] разрывается на куски от приземлившегося шаттла!"),
+ span_userdanger("Вы чувствуете, как ваше тело раздавило огромным весом прилетевшего шаттла!")
+ )
+ target.gib()
+
+/obj/mecha/get_out_and_die()
+ var/mob/living/pilot = occupant
+ if(isspaceturf(get_turf(src)))
+ pilot.visible_message(
+ span_warning("[src] иcчезает в спышке блюспейс излучения в тот момент, когда шаттл материализуется в нашем пространстве!"),
+ span_userdanger("Вы чувствуете, будто вас сейчас стошнит. Блюспейс прыжок шаттла телепортировал вас в другое место!")
+ )
+ do_teleport(src, get_turf(src), SHUTTLE_ROADKILL_TELEPORTATION_RANGE, sound_in = 'sound/effects/phasein.ogg')
+ else
+ pilot.visible_message(
+ span_warning("Тело [pilot] разрывается на куски от приземлившегося шаттла!"),
+ span_userdanger("Вы чувствуете, как ваше тело раздавило огромным весом прилетевшего шаттла!")
+ )
+ go_out(TRUE)
+ if(iscarbon(pilot))
+ pilot.gib()
+ qdel(src)
+
+#undef SHUTTLE_ROADKILL_TELEPORTATION_RANGE
diff --git a/modular_ss220/prime_only/code/tts_seeds.dm b/modular_ss220/prime_only/code/tts_seeds.dm
new file mode 100644
index 000000000000..1f786529bbb8
--- /dev/null
+++ b/modular_ss220/prime_only/code/tts_seeds.dm
@@ -0,0 +1,5 @@
+/datum/tts_seed/silero/emperor
+ required_donator_level = 5
+
+/datum/tts_seed/silero/ulfric
+ required_donator_level = 5
diff --git a/modular_ss220/prime_only/code/vending.dm b/modular_ss220/prime_only/code/vending.dm
new file mode 100644
index 000000000000..b8c8803de6d0
--- /dev/null
+++ b/modular_ss220/prime_only/code/vending.dm
@@ -0,0 +1,20 @@
+// New item list for the expedition vendomat
+
+/obj/machinery/economy/vending/exploredrobe/Initialize(mapload)
+ var/list/new_products = list(
+ /obj/item/clothing/under/rank/cargo/expedition_prime = 5,
+ /obj/item/clothing/under/rank/cargo/expedition_prime/green = 5,
+ /obj/item/clothing/under/rank/cargo/expedition_prime/tan = 5,
+ /obj/item/clothing/under/rank/cargo/expedition_prime/grey = 5,
+ )
+ var/list/new_prices = list(
+ /obj/item/clothing/under/rank/cargo/expedition_prime = 50,
+ /obj/item/clothing/under/rank/cargo/expedition_prime/green = 50,
+ /obj/item/clothing/under/rank/cargo/expedition_prime/tan = 50,
+ /obj/item/clothing/under/rank/cargo/expedition_prime/grey = 50,
+ )
+ new_products |= products
+ products = new_products
+ new_prices |= prices
+ prices = new_prices
+ . = ..()
diff --git a/modular_ss220/prime_only/icons/mob/species/drask/under/cargo.dmi b/modular_ss220/prime_only/icons/mob/species/drask/under/cargo.dmi
new file mode 100644
index 000000000000..906e263d9f91
Binary files /dev/null and b/modular_ss220/prime_only/icons/mob/species/drask/under/cargo.dmi differ
diff --git a/modular_ss220/prime_only/icons/mob/species/kidan/under/cargo.dmi b/modular_ss220/prime_only/icons/mob/species/kidan/under/cargo.dmi
new file mode 100644
index 000000000000..a12b0d954de0
Binary files /dev/null and b/modular_ss220/prime_only/icons/mob/species/kidan/under/cargo.dmi differ
diff --git a/modular_ss220/prime_only/icons/mob/species/vox/under/cargo.dmi b/modular_ss220/prime_only/icons/mob/species/vox/under/cargo.dmi
new file mode 100644
index 000000000000..7313d77fd465
Binary files /dev/null and b/modular_ss220/prime_only/icons/mob/species/vox/under/cargo.dmi differ
diff --git a/modular_ss220/prime_only/icons/mob/under.dmi b/modular_ss220/prime_only/icons/mob/under.dmi
new file mode 100644
index 000000000000..858e8f1dc81e
Binary files /dev/null and b/modular_ss220/prime_only/icons/mob/under.dmi differ
diff --git a/modular_ss220/prime_only/icons/object/under.dmi b/modular_ss220/prime_only/icons/object/under.dmi
new file mode 100644
index 000000000000..f0a2c816b39e
Binary files /dev/null and b/modular_ss220/prime_only/icons/object/under.dmi differ
diff --git a/modular_ss220/prime_only/icons/saber.dmi b/modular_ss220/prime_only/icons/saber.dmi
new file mode 100644
index 000000000000..865585635b20
Binary files /dev/null and b/modular_ss220/prime_only/icons/saber.dmi differ
diff --git a/modular_ss220/prime_only/icons/saber_left.dmi b/modular_ss220/prime_only/icons/saber_left.dmi
new file mode 100644
index 000000000000..193066e6e799
Binary files /dev/null and b/modular_ss220/prime_only/icons/saber_left.dmi differ
diff --git a/modular_ss220/prime_only/icons/saber_right.dmi b/modular_ss220/prime_only/icons/saber_right.dmi
new file mode 100644
index 000000000000..8fe5a07ed2aa
Binary files /dev/null and b/modular_ss220/prime_only/icons/saber_right.dmi differ
diff --git a/modular_ss220/prime_only/sound/weapons/gr_saberhit.ogg b/modular_ss220/prime_only/sound/weapons/gr_saberhit.ogg
new file mode 100644
index 000000000000..b62f85013148
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/gr_saberhit.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/gr_saberoff.ogg b/modular_ss220/prime_only/sound/weapons/gr_saberoff.ogg
new file mode 100644
index 000000000000..725e6e7086b9
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/gr_saberoff.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/gr_saberon.ogg b/modular_ss220/prime_only/sound/weapons/gr_saberon.ogg
new file mode 100644
index 000000000000..4f9d0809f4d3
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/gr_saberon.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/kel_saberhit.ogg b/modular_ss220/prime_only/sound/weapons/kel_saberhit.ogg
new file mode 100644
index 000000000000..123702da3cbe
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/kel_saberhit.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/kel_saberoff.ogg b/modular_ss220/prime_only/sound/weapons/kel_saberoff.ogg
new file mode 100644
index 000000000000..945f116e16ed
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/kel_saberoff.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/kel_saberon.ogg b/modular_ss220/prime_only/sound/weapons/kel_saberon.ogg
new file mode 100644
index 000000000000..968cf93ca83d
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/kel_saberon.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/kir_saberhit.ogg b/modular_ss220/prime_only/sound/weapons/kir_saberhit.ogg
new file mode 100644
index 000000000000..ace06b88cb64
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/kir_saberhit.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/kir_saberoff.ogg b/modular_ss220/prime_only/sound/weapons/kir_saberoff.ogg
new file mode 100644
index 000000000000..502793d721a6
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/kir_saberoff.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/kir_saberon.ogg b/modular_ss220/prime_only/sound/weapons/kir_saberon.ogg
new file mode 100644
index 000000000000..98c5055656eb
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/kir_saberon.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/mid_saberhit.ogg b/modular_ss220/prime_only/sound/weapons/mid_saberhit.ogg
new file mode 100644
index 000000000000..3df8a9e39728
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/mid_saberhit.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/mid_saberoff.ogg b/modular_ss220/prime_only/sound/weapons/mid_saberoff.ogg
new file mode 100644
index 000000000000..eb838064f875
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/mid_saberoff.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/mid_saberon.ogg b/modular_ss220/prime_only/sound/weapons/mid_saberon.ogg
new file mode 100644
index 000000000000..0e5df9291376
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/mid_saberon.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/norm_saberhit.ogg b/modular_ss220/prime_only/sound/weapons/norm_saberhit.ogg
new file mode 100644
index 000000000000..4b763238fd19
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/norm_saberhit.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/norm_saberoff.ogg b/modular_ss220/prime_only/sound/weapons/norm_saberoff.ogg
new file mode 100644
index 000000000000..5470dd8bf5db
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/norm_saberoff.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/norm_saberon.ogg b/modular_ss220/prime_only/sound/weapons/norm_saberon.ogg
new file mode 100644
index 000000000000..a1a85d25428d
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/norm_saberon.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/sh_saberhit.ogg b/modular_ss220/prime_only/sound/weapons/sh_saberhit.ogg
new file mode 100644
index 000000000000..ce0bb4d0c931
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/sh_saberhit.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/sh_saberoff.ogg b/modular_ss220/prime_only/sound/weapons/sh_saberoff.ogg
new file mode 100644
index 000000000000..2457b5a064e8
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/sh_saberoff.ogg differ
diff --git a/modular_ss220/prime_only/sound/weapons/sh_saberon.ogg b/modular_ss220/prime_only/sound/weapons/sh_saberon.ogg
new file mode 100644
index 000000000000..71097422ea7f
Binary files /dev/null and b/modular_ss220/prime_only/sound/weapons/sh_saberon.ogg differ
diff --git a/modular_ss220/pt_monitor/_pt_monitor.dm b/modular_ss220/pt_monitor/_pt_monitor.dm
new file mode 100644
index 000000000000..b6145fa522b8
--- /dev/null
+++ b/modular_ss220/pt_monitor/_pt_monitor.dm
@@ -0,0 +1,4 @@
+/datum/modpack/pt_monitor
+ name = "Pressure Temperature monitor"
+ desc = "График изменения температуры и давления. С любовью, для SS220"
+ author = "VentelR, Desunovu"
diff --git a/modular_ss220/pt_monitor/_pt_monitor.dme b/modular_ss220/pt_monitor/_pt_monitor.dme
new file mode 100644
index 000000000000..e9b13759ca7c
--- /dev/null
+++ b/modular_ss220/pt_monitor/_pt_monitor.dme
@@ -0,0 +1,3 @@
+#include "_pt_monitor.dm"
+
+#include "code/items/pt_monitor.dm"
diff --git a/modular_ss220/pt_monitor/code/items/pt_monitor.dm b/modular_ss220/pt_monitor/code/items/pt_monitor.dm
new file mode 100644
index 000000000000..1a4a97e024da
--- /dev/null
+++ b/modular_ss220/pt_monitor/code/items/pt_monitor.dm
@@ -0,0 +1,125 @@
+#define SENSOR_PRESSURE (1<<0)
+#define SENSOR_TEMPERATURE (1<<1)
+#define NO_DATA_VALUE null
+#define MAX_RECORD_SIZE 20
+#define RECORD_INTERVAL 3 SECONDS
+#define LONG_RECORD_INTERVAL 30 SECONDS
+#define LAZYINITLISTSIZED(L, N) if(!L) L = new/list(N)
+#define ADD_TO_HISTORY(history_list, measurement) \
+ history_list += measurement; \
+ if(length(history_list) > MAX_RECORD_SIZE) history_list.Cut(1, 2)
+
+/datum/design/pt_monitor
+ name = "Console Board (Atmospheric Graph Monitor)"
+ desc ="Позволяет распечатать плату, для создания Atmospheric Graph Monitor."
+ id = "pt_monitor"
+ req_tech = list("programming" = 2, "engineering" = 3)
+ build_type = IMPRINTER
+ materials = list(MAT_GLASS = 1000)
+ build_path = /obj/item/circuitboard/pt_monitor
+ category = list("Computer Boards")
+
+/obj/item/circuitboard/pt_monitor
+ board_name = "Atmospheric Graph Monitor"
+ icon_state = "engineering"
+ build_path = /obj/machinery/computer/general_air_control/pt_monitor
+ origin_tech = "programming=2;engineering=3"
+
+/obj/machinery/computer/general_air_control/pt_monitor
+ name = "Atmospheric graph monitoring console"
+ desc = "Используется для мониторинга давления и температуры с помощью подключаемых мультитулом датчиков."
+ icon = 'modular_ss220/pt_monitor/icons/pt_monitor.dmi'
+ icon_screen = "screen"
+ icon_keyboard = "atmos_key"
+ circuit = /obj/item/circuitboard/pt_monitor
+
+ var/next_record_time = 0
+ var/next_long_record_time = 0
+
+/obj/machinery/computer/general_air_control/pt_monitor/proc/init_history_lists()
+ for(var/sensor_name in sensor_name_data_map)
+ LAZYINITLISTSIZED(sensor_name_data_map[sensor_name]["pressure_history"], MAX_RECORD_SIZE)
+ LAZYINITLISTSIZED(sensor_name_data_map[sensor_name]["temperature_history"], MAX_RECORD_SIZE)
+ LAZYINITLISTSIZED(sensor_name_data_map[sensor_name]["long_pressure_history"], MAX_RECORD_SIZE)
+ LAZYINITLISTSIZED(sensor_name_data_map[sensor_name]["long_temperature_history"], MAX_RECORD_SIZE)
+
+/obj/machinery/computer/general_air_control/pt_monitor/LateInitialize()
+ . = ..()
+ init_history_lists()
+
+/obj/machinery/computer/general_air_control/pt_monitor/ui_interact(mob/user, datum/tgui/ui = null)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "AtmosGraphMonitor", name)
+ ui.open()
+
+/obj/machinery/computer/general_air_control/pt_monitor/configure_sensors(mob/living/user, obj/item/multitool/M)
+ . = ..()
+ init_history_lists()
+
+/obj/machinery/computer/general_air_control/pt_monitor/refresh_sensors()
+ var/log_long_record = FALSE
+ var/current_time = world.time
+
+ if(current_time < next_record_time)
+ return
+ next_record_time = current_time + RECORD_INTERVAL
+
+ if(current_time >= next_long_record_time)
+ log_long_record = TRUE
+ next_long_record_time = current_time + LONG_RECORD_INTERVAL
+
+ for(var/sensor_name in sensor_name_uid_map)
+ var/obj/machinery/atmospherics/atmos_sensor = locateUID(sensor_name_uid_map[sensor_name])
+ // Проверка что сенсор существует
+ if(QDELETED(atmos_sensor))
+ sensor_name_uid_map -= sensor_name
+ sensor_name_data_map -= sensor_name
+ continue
+
+ var/list/sensor_data = sensor_name_data_map[sensor_name]
+ var/list/sensor_pressure_history = sensor_data["pressure_history"]
+ var/list/sensor_temperature_history = sensor_data["temperature_history"]
+ var/list/sensor_long_pressure_history = sensor_data["long_pressure_history"]
+ var/list/sensor_long_temperature_history = sensor_data["long_temperature_history"]
+ var/current_pressure
+ var/current_temperature
+
+ if(istype(atmos_sensor, /obj/machinery/atmospherics/air_sensor))
+ var/obj/machinery/atmospherics/air_sensor/sensor = atmos_sensor
+ var/turf/sensor_turf = get_turf(sensor)
+ var/datum/gas_mixture/air_sample = sensor_turf.get_readonly_air()
+ current_pressure = (sensor.output & SENSOR_PRESSURE) ? air_sample.return_pressure() : NO_DATA_VALUE
+ current_temperature = (sensor.output & SENSOR_TEMPERATURE) ? air_sample.temperature() : NO_DATA_VALUE
+ else if(istype(atmos_sensor, /obj/machinery/atmospherics/meter))
+ var/obj/machinery/atmospherics/meter/the_meter = atmos_sensor
+ if(the_meter.target)
+ var/datum/gas_mixture/meter_air_sample = the_meter.target.return_obj_air()
+ current_pressure = meter_air_sample ? meter_air_sample.return_pressure() : NO_DATA_VALUE
+ current_temperature = meter_air_sample ? meter_air_sample.temperature() : NO_DATA_VALUE
+ else
+ sensor_name_uid_map -= sensor_name
+ sensor_name_data_map -= sensor_name
+ CRASH("Sensor of unexpected type was found: [atmos_sensor.type]")
+
+ ADD_TO_HISTORY(sensor_pressure_history, current_pressure)
+ ADD_TO_HISTORY(sensor_temperature_history, current_temperature)
+
+ if(log_long_record)
+ ADD_TO_HISTORY(sensor_long_pressure_history, current_pressure)
+ ADD_TO_HISTORY(sensor_long_temperature_history, current_temperature)
+
+/obj/machinery/computer/general_air_control/pt_monitor/process()
+ if(!is_operational() || length(sensor_name_uid_map) < 1)
+ return
+
+ refresh_all()
+
+#undef SENSOR_PRESSURE
+#undef SENSOR_TEMPERATURE
+#undef NO_DATA_VALUE
+#undef MAX_RECORD_SIZE
+#undef RECORD_INTERVAL
+#undef LONG_RECORD_INTERVAL
+#undef LAZYINITLISTSIZED
+#undef ADD_TO_HISTORY
diff --git a/modular_ss220/pt_monitor/icons/pt_monitor.dmi b/modular_ss220/pt_monitor/icons/pt_monitor.dmi
new file mode 100644
index 000000000000..fd639c2750ee
Binary files /dev/null and b/modular_ss220/pt_monitor/icons/pt_monitor.dmi differ
diff --git a/modular_ss220/queue/_queue.dm b/modular_ss220/queue/_queue.dm
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/modular_ss220/queue/_queue.dme b/modular_ss220/queue/_queue.dme
new file mode 100644
index 000000000000..c60847861410
--- /dev/null
+++ b/modular_ss220/queue/_queue.dme
@@ -0,0 +1,5 @@
+#include "_queue.dm"
+
+#include "code/new_player_procs.dm"
+#include "code/queue_bypass.dm"
+#include "code/overflow_configuration.dm"
diff --git a/modular_ss220/queue/code/new_player_procs.dm b/modular_ss220/queue/code/new_player_procs.dm
new file mode 100644
index 000000000000..366682a85c98
--- /dev/null
+++ b/modular_ss220/queue/code/new_player_procs.dm
@@ -0,0 +1,36 @@
+/mob/new_player/Login()
+ . = ..()
+
+ if(!SSdbcore.IsConnected())
+ return
+
+ if(SSqueue.queue_enabled)
+ if(client?.ckey in SSqueue.queue_bypass_list)
+ return
+
+ if(client?.holder)
+ SSqueue.queue_bypass_list |= ckey
+ return
+
+ if(client.donator_level >= 3)
+ SSqueue.queue_bypass_list |= ckey
+ return
+
+ if(length(GLOB.clients) < SSqueue.queue_threshold)
+ SSqueue.queue_bypass_list |= ckey
+ return
+
+ src << link(GLOB.configuration.overflow.overflow_server_location)
+
+/mob/new_player/Logout()
+ . = ..()
+
+ if(SSqueue.queue_enabled)
+ addtimer(CALLBACK(SSqueue, TYPE_PROC_REF(/datum/controller/subsystem/queue, reserve_queue_slot), last_known_ckey), GLOB.configuration.overflow.reservation_time)
+
+
+/datum/controller/subsystem/queue/proc/reserve_queue_slot(reserved_ckey)
+ if(reserved_ckey in GLOB.player_list)
+ return
+
+ queue_bypass_list.Remove(reserved_ckey)
diff --git a/modular_ss220/queue/code/overflow_configuration.dm b/modular_ss220/queue/code/overflow_configuration.dm
new file mode 100644
index 000000000000..f9282a5e34d1
--- /dev/null
+++ b/modular_ss220/queue/code/overflow_configuration.dm
@@ -0,0 +1,7 @@
+/datum/configuration_section/overflow_configuration
+ var/reservation_time = 1 MINUTES
+
+/datum/configuration_section/overflow_configuration/load_data(list/data)
+ . = ..()
+
+ CONFIG_LOAD_NUM(reservation_time, data["reservation_time"])
diff --git a/modular_ss220/queue/code/queue_bypass.dm b/modular_ss220/queue/code/queue_bypass.dm
new file mode 100644
index 000000000000..0cfa19707ab1
--- /dev/null
+++ b/modular_ss220/queue/code/queue_bypass.dm
@@ -0,0 +1,17 @@
+/datum/world_topic_handler/queue_bypass
+ topic_key = "queue_bypass"
+ requires_commskey = TRUE
+
+/datum/world_topic_handler/queue_bypass/execute(list/input, key_valid)
+ var/ckey_check = input["ckey_check"]
+
+ if(!ckey_check)
+ return json_encode(list("error" = "No ckey supplied"))
+
+ var/list/output_data = list()
+ output_data["queue_enabled"] = SSqueue.queue_enabled
+
+ if(SSqueue.queue_enabled)
+ SSqueue.queue_bypass_list |= ckey_check
+
+ return json_encode(output_data)
diff --git a/modular_ss220/redis220/_redis220.dm b/modular_ss220/redis220/_redis220.dm
new file mode 100644
index 000000000000..34f6a9f70964
--- /dev/null
+++ b/modular_ss220/redis220/_redis220.dm
@@ -0,0 +1,4 @@
+/datum/modpack/redis220
+ name = "Custon redis events"
+ desc = "Handles custom events using redis"
+ author = "furior"
diff --git a/modular_ss220/redis220/_redis220.dme b/modular_ss220/redis220/_redis220.dme
new file mode 100644
index 000000000000..23e1d93068f3
--- /dev/null
+++ b/modular_ss220/redis220/_redis220.dme
@@ -0,0 +1,4 @@
+#include "_redis220.dm"
+
+#include "code/news.dm"
+#include "code/tgs_deploy_bandaid.dm"
diff --git a/modular_ss220/redis220/code/news.dm b/modular_ss220/redis220/code/news.dm
new file mode 100644
index 000000000000..247fbd066505
--- /dev/null
+++ b/modular_ss220/redis220/code/news.dm
@@ -0,0 +1,28 @@
+/datum/feed_channel/add_message(datum/feed_message/M)
+ . = ..()
+ if(!M.author_ckey)
+ return
+ var/list/data = M.serialize() + list(
+ "publish_realtime" = world.realtime,
+ "publish_time" = time2text(ROUND_TIME, "hh:mm:ss", 0),
+ "channel_name" = channel_name,
+ "round_id" = GLOB.round_id,
+ "server" = "[world.internet_address]:[world.port]",
+ "security_level" = SSsecurity_level.get_current_level_as_text()
+ )
+ SSredis.publish("byond.news", json_encode(data))
+
+/datum/feed_message/serialize()
+ . = ..()
+ . += list(
+ "author" = author,
+ "author_ckey" = author_ckey,
+ "title" = title,
+ "body" = body,
+ "img" = img ? icon2base64(icon(img, frame = 1)) : null,
+ "censor_flags" = censor_flags,
+ "admin_locked" = admin_locked,
+ "view_count" = view_count,
+ "publish_time" = publish_time
+ )
+ return .
diff --git a/modular_ss220/redis220/code/tgs_deploy_bandaid.dm b/modular_ss220/redis220/code/tgs_deploy_bandaid.dm
new file mode 100644
index 000000000000..d26810d81dca
--- /dev/null
+++ b/modular_ss220/redis220/code/tgs_deploy_bandaid.dm
@@ -0,0 +1,7 @@
+/datum/tgs_event_handler/impl/HandleEvent(event_code, ...)
+ . = ..()
+ if(event_code != TGS_EVENT_DEPLOYMENT_COMPLETE)
+ return
+
+ SSredis.disconnect()
+ SSredis.connect()
diff --git a/modular_ss220/robolimbs/_robolimbs.dm b/modular_ss220/robolimbs/_robolimbs.dm
new file mode 100644
index 000000000000..315ac4ceba07
--- /dev/null
+++ b/modular_ss220/robolimbs/_robolimbs.dm
@@ -0,0 +1,4 @@
+/datum/modpack/robolimbs
+ name = "Новые протезы"
+ desc = "Новые протезы и головы."
+ author = "sirstaniya"
diff --git a/modular_ss220/robolimbs/_robolimbs.dme b/modular_ss220/robolimbs/_robolimbs.dme
new file mode 100644
index 000000000000..e94a95f54836
--- /dev/null
+++ b/modular_ss220/robolimbs/_robolimbs.dme
@@ -0,0 +1,3 @@
+#include "_robolimbs.dm"
+
+#include "code/robolimbs.dm"
diff --git a/modular_ss220/robolimbs/code/robolimbs.dm b/modular_ss220/robolimbs/code/robolimbs.dm
new file mode 100644
index 000000000000..fca894d0656f
--- /dev/null
+++ b/modular_ss220/robolimbs/code/robolimbs.dm
@@ -0,0 +1,41 @@
+/datum/robolimb/etaminindustry
+ company = "Etamin Industry Gold On Black"
+ desc = "Модель протезированной конечности от Этамин Индастрис."
+ icon = 'modular_ss220/robolimbs/icons/etaminindustry_main.dmi'
+ has_subtypes = 1
+
+/datum/robolimb/etaminindustry/etaminindustry_alt1
+ company = "Etamin Industry Elite Series"
+ icon = 'modular_ss220/robolimbs/icons/etaminindustry_alt1.dmi'
+ parts = list("head")
+ selectable = 0
+ has_subtypes = null
+
+/datum/robolimb/etaminindustry/etaminindustry_alt2
+ company = "Etamin Industry SharpShooter Series"
+ icon = 'modular_ss220/robolimbs/icons/etaminindustry_alt2.dmi'
+ parts = list("head")
+ selectable = 0
+ has_subtypes = null
+
+/datum/robolimb/etaminindustry/etaminindustry_alt3
+ company = "Etamin Industry King Series"
+ icon = 'modular_ss220/robolimbs/icons/etaminindustry_alt3.dmi'
+ parts = list("head")
+ selectable = 0
+ has_subtypes = null
+
+/datum/sprite_accessory/body_markings/head/optics/etamin
+ icon = 'modular_ss220/robolimbs/icons/ei_optic.dmi'
+ name = "EI Optics"
+ species_allowed = list("Machine")
+ icon_state = "ei_standart"
+ models_allowed = list("Etamin Industry King Series")
+
+/datum/sprite_accessory/body_markings/head/optics/etamin/alt1
+ name = "EI Optics Alt"
+ icon_state = "ei_alt1"
+
+/datum/sprite_accessory/body_markings/head/optics/etamin/alt2
+ name = "EI Optics Alt 2"
+ icon_state = "ei_alt2"
diff --git a/modular_ss220/robolimbs/icons/ei_optic.dmi b/modular_ss220/robolimbs/icons/ei_optic.dmi
new file mode 100644
index 000000000000..7bacb663e3c4
Binary files /dev/null and b/modular_ss220/robolimbs/icons/ei_optic.dmi differ
diff --git a/modular_ss220/robolimbs/icons/etaminindustry_alt1.dmi b/modular_ss220/robolimbs/icons/etaminindustry_alt1.dmi
new file mode 100644
index 000000000000..954a1f564a36
Binary files /dev/null and b/modular_ss220/robolimbs/icons/etaminindustry_alt1.dmi differ
diff --git a/modular_ss220/robolimbs/icons/etaminindustry_alt2.dmi b/modular_ss220/robolimbs/icons/etaminindustry_alt2.dmi
new file mode 100644
index 000000000000..6751d10bb663
Binary files /dev/null and b/modular_ss220/robolimbs/icons/etaminindustry_alt2.dmi differ
diff --git a/modular_ss220/robolimbs/icons/etaminindustry_alt3.dmi b/modular_ss220/robolimbs/icons/etaminindustry_alt3.dmi
new file mode 100644
index 000000000000..5fd296307dc5
Binary files /dev/null and b/modular_ss220/robolimbs/icons/etaminindustry_alt3.dmi differ
diff --git a/modular_ss220/robolimbs/icons/etaminindustry_main.dmi b/modular_ss220/robolimbs/icons/etaminindustry_main.dmi
new file mode 100644
index 000000000000..ebc784b9f843
Binary files /dev/null and b/modular_ss220/robolimbs/icons/etaminindustry_main.dmi differ
diff --git a/modular_ss220/screentip_change/_screentip_change.dm b/modular_ss220/screentip_change/_screentip_change.dm
new file mode 100644
index 000000000000..f58f36c3dd42
--- /dev/null
+++ b/modular_ss220/screentip_change/_screentip_change.dm
@@ -0,0 +1,4 @@
+/datum/modpack/screentip_change
+ name = "Сдвиг Screentip вверх"
+ desc = "Меняет местоположение Screentip, чтобы они были выше."
+ author = "larentoun"
diff --git a/modular_ss220/screentip_change/_screentip_change.dme b/modular_ss220/screentip_change/_screentip_change.dme
new file mode 100644
index 000000000000..5a38ceff2ee6
--- /dev/null
+++ b/modular_ss220/screentip_change/_screentip_change.dme
@@ -0,0 +1,3 @@
+#include "_screentip_change.dm"
+
+#include "code/screentip.dm"
diff --git a/modular_ss220/screentip_change/code/screentip.dm b/modular_ss220/screentip_change/code/screentip.dm
new file mode 100644
index 000000000000..4b6c5c5522e2
--- /dev/null
+++ b/modular_ss220/screentip_change/code/screentip.dm
@@ -0,0 +1,2 @@
+/atom/movable/screen/screentip
+ maptext_y = -25
diff --git a/modular_ss220/sechailer/code/sechailer.dm b/modular_ss220/sechailer/code/sechailer.dm
new file mode 100644
index 000000000000..d4217afafb77
--- /dev/null
+++ b/modular_ss220/sechailer/code/sechailer.dm
@@ -0,0 +1,106 @@
+GLOBAL_LIST_EMPTY(sechailers)
+
+/datum/action/item_action/dispatch
+ name = "Signal Dispatch"
+ desc = "Открывает колесо быстрого выбора для сообщения о преступлениях, включая ваше текущее местоположение."
+ button_overlay_icon_state = "dispatch"
+ button_overlay_icon = 'modular_ss220/sechailer/icons/sechailer.dmi'
+ use_itemicon = FALSE
+
+/obj/item/clothing/mask/gas/sechailer
+ var/obj/item/radio/radio // For dispatch to work
+ var/dispatch_cooldown = 25 SECONDS
+ var/on_cooldown = FALSE
+ var/emped = FALSE
+ var/static/list/available_dispatch_messages = list(
+ "502 (Убийство)",
+ "101 (Сопротивление Аресту)",
+ "308 (Вторжение)",
+ "305 (Мятеж)",
+ "402 (Нападение на Офицера)")
+ actions_types = list(/datum/action/item_action/dispatch, /datum/action/item_action/halt, /datum/action/item_action/adjust, /datum/action/item_action/selectphrase)
+
+/obj/item/clothing/mask/gas/sechailer/hos
+ actions_types = list(/datum/action/item_action/dispatch, /datum/action/item_action/halt, /datum/action/item_action/selectphrase)
+
+/obj/item/clothing/mask/gas/sechailer/warden
+ actions_types = list(/datum/action/item_action/dispatch, /datum/action/item_action/halt, /datum/action/item_action/selectphrase)
+
+/obj/item/clothing/mask/gas/sechailer/swat
+ actions_types = list(/datum/action/item_action/dispatch, /datum/action/item_action/halt, /datum/action/item_action/selectphrase)
+
+/obj/item/clothing/mask/gas/sechailer/blue
+ actions_types = list(/datum/action/item_action/dispatch, /datum/action/item_action/halt, /datum/action/item_action/selectphrase)
+
+/obj/item/clothing/mask/gas/sechailer/Destroy()
+ qdel(radio)
+ GLOB.sechailers -= src
+ . = ..()
+
+/obj/item/clothing/mask/gas/sechailer/Initialize(mapload)
+ . = ..()
+ GLOB.sechailers += src
+ radio = new /obj/item/radio(src)
+ radio.listening = FALSE
+ radio.config(list("Security" = 0))
+ radio.follow_target = src
+
+/obj/item/clothing/mask/gas/sechailer/proc/dispatch(mob/user)
+ for(var/option in available_dispatch_messages)
+ available_dispatch_messages[option] = image(icon = 'modular_ss220/sechailer/icons/menu.dmi', icon_state = option)
+ var/message = show_radial_menu(user, src, available_dispatch_messages)
+ var/location_name = get_location_name(src, TRUE) // get_location_name works better as Affected says
+
+ if(!message)
+ return
+ if(on_cooldown)
+ var/list/cooldown_info = list("Ожидайте. Система оповещения ")
+ if(emped)
+ cooldown_info += "в защитном режиме, "
+ else
+ cooldown_info += "перезаряжается, "
+ // Cooldown not updating realtime, and i don't want to rewrite it just for the sake of it
+ cooldown_info += "примерное время восстановления: [dispatch_cooldown / 10] секунд."
+ to_chat(user, span_notice(cooldown_info.Join()))
+ return
+
+ on_cooldown = TRUE
+ addtimer(CALLBACK(src, PROC_REF(reboot)), dispatch_cooldown)
+ // This code if fucking hell, but it works as intended
+ for(var/atom/movable/hailer in GLOB.sechailers)
+ var/security_channel_found = FALSE
+ if(!hailer.loc || !ismob(hailer.loc))
+ continue
+ // Check if mob has a radio, then check if the radio has the right channels
+ for(var/obj/item/radio/my_radio in user)
+ for(var/chan in 1 to length(my_radio.channels))
+ var/channel_name = my_radio.channels[chan]
+ if(channel_name == DEPARTMENT_SECURITY)
+ security_channel_found = TRUE
+ break
+ if(security_channel_found)
+ radio.autosay("Центр, Код [message], офицер [user] запрашивает помощь в [location_name].", "Система Оповещения", DEPARTMENT_SECURITY, list(z))
+ playsound(hailer.loc, 'modular_ss220/sechailer/sound/dispatch_please_respond.ogg', 55, FALSE)
+ break
+ else
+ to_chat(user, span_warning("Внимание: Невозможно установить соединение с каналом службы безопасности, требуется подключение!"))
+ playsound(hailer.loc, 'modular_ss220/sechailer/sound/radio_static.ogg', 30, TRUE)
+
+/obj/item/clothing/mask/gas/sechailer/proc/reboot()
+ on_cooldown = FALSE
+ emped = FALSE
+
+/obj/item/clothing/mask/gas/sechailer/ui_action_click(mob/user, actiontype)
+ . = ..()
+ if(actiontype == /datum/action/item_action/dispatch)
+ dispatch(user)
+
+/obj/item/clothing/mask/gas/sechailer/emp_act(severity)
+ if(on_cooldown)
+ return
+ on_cooldown = TRUE
+ emped = TRUE
+ addtimer(CALLBACK(src, PROC_REF(reboot)), dispatch_cooldown)
+ if(ishuman(loc))
+ var/mob/living/carbon/human/user = loc
+ to_chat(user, span_userdanger("Обнаружен электромагнитный импульс, система оповещения отключена для сохранения работоспособности..."))
diff --git a/modular_ss220/sechailer/icons/menu.dmi b/modular_ss220/sechailer/icons/menu.dmi
new file mode 100644
index 000000000000..aee00ca952b2
Binary files /dev/null and b/modular_ss220/sechailer/icons/menu.dmi differ
diff --git a/modular_ss220/sechailer/icons/sechailer.dmi b/modular_ss220/sechailer/icons/sechailer.dmi
new file mode 100644
index 000000000000..444b3fb5d2a1
Binary files /dev/null and b/modular_ss220/sechailer/icons/sechailer.dmi differ
diff --git a/modular_ss220/sechailer/sechailer.dme b/modular_ss220/sechailer/sechailer.dme
new file mode 100644
index 000000000000..94e707c5220e
--- /dev/null
+++ b/modular_ss220/sechailer/sechailer.dme
@@ -0,0 +1,9 @@
+#ifndef MODPACK_HAILER
+#define MODPACK_HAILER
+
+#endif
+
+// BEGIN INCLUDE
+#include "code/sechailer.dm"
+// END_INCLUDE
+
diff --git a/modular_ss220/sechailer/sound/dispatch_please_respond.ogg b/modular_ss220/sechailer/sound/dispatch_please_respond.ogg
new file mode 100644
index 000000000000..83ea06d476a3
Binary files /dev/null and b/modular_ss220/sechailer/sound/dispatch_please_respond.ogg differ
diff --git a/modular_ss220/sechailer/sound/radio_static.ogg b/modular_ss220/sechailer/sound/radio_static.ogg
new file mode 100644
index 000000000000..8bc2eebb26f1
Binary files /dev/null and b/modular_ss220/sechailer/sound/radio_static.ogg differ
diff --git a/modular_ss220/security_redalert_accesses/_security_redalert_accesses.dm b/modular_ss220/security_redalert_accesses/_security_redalert_accesses.dm
new file mode 100644
index 000000000000..6345aa707683
--- /dev/null
+++ b/modular_ss220/security_redalert_accesses/_security_redalert_accesses.dm
@@ -0,0 +1,4 @@
+/datum/modpack/security_redalert_accesses
+ name = "Доступы СБ в красный код"
+ desc = "Добавляет доступы СБ в красный код."
+ author = "dj-34, Vallat, larentoun"
diff --git a/modular_ss220/security_redalert_accesses/_security_redalert_accesses.dme b/modular_ss220/security_redalert_accesses/_security_redalert_accesses.dme
new file mode 100644
index 000000000000..a9767b62bfbf
--- /dev/null
+++ b/modular_ss220/security_redalert_accesses/_security_redalert_accesses.dme
@@ -0,0 +1,4 @@
+#include "_security_redalert_accesses.dm"
+
+#include "code/security_redalert_accesses.dm"
+#include "code/security_redalert_element.dm"
diff --git a/modular_ss220/security_redalert_accesses/code/security_redalert_accesses.dm b/modular_ss220/security_redalert_accesses/code/security_redalert_accesses.dm
new file mode 100644
index 000000000000..7c1e21c9dd0b
--- /dev/null
+++ b/modular_ss220/security_redalert_accesses/code/security_redalert_accesses.dm
@@ -0,0 +1,8 @@
+/obj/item/card/id/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/red_alert_access)
+
+/obj/item/card/id/GetAccess()
+ var/list/current_access = ..()
+ . = current_access.Copy()
+ SEND_SIGNAL(src, COMSIG_ID_GET_ACCESS, .)
diff --git a/modular_ss220/security_redalert_accesses/code/security_redalert_element.dm b/modular_ss220/security_redalert_accesses/code/security_redalert_element.dm
new file mode 100644
index 000000000000..d949616271ee
--- /dev/null
+++ b/modular_ss220/security_redalert_accesses/code/security_redalert_element.dm
@@ -0,0 +1,33 @@
+/datum/element/red_alert_access
+
+/datum/element/red_alert_access/Attach(datum/target, list/access = list())
+ . = ..()
+ if(!istype(target, /obj/item/card/id))
+ return ELEMENT_INCOMPATIBLE
+ RegisterSignal(target, COMSIG_ID_GET_ACCESS, PROC_REF(add_access))
+ RegisterSignal(target, COMSIG_PARENT_EXAMINE, PROC_REF(examine))
+
+/datum/element/red_alert_access/Detach(obj/item/card/id/source, force)
+ UnregisterSignal(source, COMSIG_ID_GET_ACCESS)
+ UnregisterSignal(source, COMSIG_PARENT_EXAMINE)
+ return ..()
+
+/datum/element/red_alert_access/proc/add_access(obj/item/card/id/source, list/new_access = list())
+ SIGNAL_HANDLER
+ if(!should_give_access(source.access))
+ return
+ var/static/list/red_alert_access = get_region_accesses(REGION_ALL) - get_region_accesses(REGION_COMMAND)
+ new_access |= red_alert_access
+
+/datum/element/red_alert_access/proc/examine(obj/item/card/id/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER
+ if(!should_give_access(source.access))
+ return
+ examine_list += span_notice("Мигает красная лампочка с надписью \"Расширенный доступ\".")
+
+/datum/element/red_alert_access/proc/should_give_access(list/access)
+ if(SSsecurity_level.current_security_level.number_level <= SEC_LEVEL_BLUE)
+ return FALSE
+ if(!has_access(list(), list(ACCESS_SECURITY), access))
+ return FALSE
+ return TRUE
diff --git a/modular_ss220/shuttles/_shuttles.dm b/modular_ss220/shuttles/_shuttles.dm
new file mode 100644
index 000000000000..83f76af94d50
--- /dev/null
+++ b/modular_ss220/shuttles/_shuttles.dm
@@ -0,0 +1,4 @@
+/datum/modpack/shuttles
+ name = "Shuttles Modpack"
+ desc = "Изменения нашей карты ЦК левела под новые шаттлы от SS13 Paradise."
+ author = "konu_shi"
diff --git a/modular_ss220/shuttles/_shuttles.dme b/modular_ss220/shuttles/_shuttles.dme
new file mode 100644
index 000000000000..f2cbc7bf1023
--- /dev/null
+++ b/modular_ss220/shuttles/_shuttles.dme
@@ -0,0 +1,5 @@
+#include "_shuttles.dm"
+
+#include "code/ferry_shuttles.dm"
+#include "code/lance_shuttle.dm"
+#include "code/nanotrasen_drop_pod.dm"
diff --git a/modular_ss220/shuttles/code/ferry_shuttles.dm b/modular_ss220/shuttles/code/ferry_shuttles.dm
new file mode 100644
index 000000000000..3649fbc7e447
--- /dev/null
+++ b/modular_ss220/shuttles/code/ferry_shuttles.dm
@@ -0,0 +1,35 @@
+/datum/map_template/shuttle/ferry/clown
+ prefix = "_maps/map_files220/shuttles/"
+ suffix = "clown"
+ name = "clown ferry"
+ description = "Персональный шаттл клоунов, выращенный из бананов!"
+
+/datum/map_template/shuttle/ferry/convoy
+ prefix = "_maps/map_files220/shuttles/"
+ suffix = "convoy"
+ name = "prisoner convoy ferry"
+ description = "Шаттл для конвоирования заключенных."
+
+/datum/map_template/shuttle/ferry/medical
+ prefix = "_maps/map_files220/shuttles/"
+ suffix = "medical"
+ name = "medical ferry"
+ description = "Шаттл содержащий в себе немного медикаментов и операционную. В целом, всё необходимое для поддержания жизни пациента."
+
+/datum/map_template/shuttle/ferry/tsf
+ prefix = "_maps/map_files220/shuttles/"
+ suffix = "tsf"
+ name = "TSF ferry"
+ description = "Шаттл ТСФ, предназначенный для безопасной переброски личного состава в самые опасные уголки космоса."
+
+/datum/map_template/shuttle/ferry/ussp
+ prefix = "_maps/map_files220/shuttles/"
+ suffix = "ussp"
+ name = "USSP ferry"
+ description = "Шаттл СССП. В основном используется ячейкой дипломатов СССП."
+
+/datum/map_template/shuttle/ferry/vip
+ prefix = "_maps/map_files220/shuttles/"
+ suffix = "vip"
+ name = "VIP ferry"
+ description = "Шаттл, используемый для перевозки привилегированных лиц различных корпораций."
diff --git a/modular_ss220/shuttles/code/lance_shuttle.dm b/modular_ss220/shuttles/code/lance_shuttle.dm
new file mode 100644
index 000000000000..27a4c97cfae6
--- /dev/null
+++ b/modular_ss220/shuttles/code/lance_shuttle.dm
@@ -0,0 +1,28 @@
+/datum/map_template/shuttle/emergency/lance/preload()
+ message_admins("Preloading [name]!")
+ var/obj/docking_port/stationary/CCport
+ CCport = SSshuttle.getDock("emergency_away")
+ CCport.setDir(4)
+ CCport.forceMove(locate(117, 80, 1))
+ CCport.height = 50
+ CCport.dheight = 0
+ CCport.width = 19
+ CCport.dwidth = 9
+ var/obj/docking_port/stationary/CCtransit
+ CCtransit = SSshuttle.getDock("emergency_transit")
+ CCtransit.setDir(2)
+ CCtransit.forceMove(locate(179, 166, 1))
+ CCtransit.height = 50
+ CCtransit.dheight = 0
+ CCtransit.width = 19
+ CCtransit.dwidth = 9
+ var/obj/docking_port/stationary/syndicate
+ syndicate = SSshuttle.getDock("emergency_syndicate")
+ syndicate.setDir(8)
+ syndicate.forceMove(locate(91, 159, 1))
+ syndicate.height = 50
+ syndicate.dheight = 0
+ syndicate.width = 19
+ syndicate.dwidth = 9
+ qdel(SSshuttle.getDock("emergency_home"), TRUE)
+ SSshuttle.emergency_locked_in = TRUE
diff --git a/modular_ss220/shuttles/code/nanotrasen_drop_pod.dm b/modular_ss220/shuttles/code/nanotrasen_drop_pod.dm
new file mode 100644
index 000000000000..f37fbec2ff1b
--- /dev/null
+++ b/modular_ss220/shuttles/code/nanotrasen_drop_pod.dm
@@ -0,0 +1,79 @@
+/* Nanotrasen Shuttles */
+// This is actually don't work for now and only need for Drop Pod
+/obj/machinery/computer/shuttle/nanotrasen
+ name = "nanotrasen shuttle terminal"
+ icon_screen = "syndishuttle"
+ icon_keyboard = "syndie_key"
+ req_access = list(ACCESS_CENT_SPECOPS_COMMANDER)
+ bubble_icon = "syndibot"
+ circuit = /obj/item/circuitboard/shuttle/nanotrasen
+ shuttleId = "nanotrasen"
+ possible_destinations = "syndicate_away;syndicate_z5;syndicate_z3;syndicate_ne;syndicate_nw;syndicate_n;syndicate_se;syndicate_sw;syndicate_s;syndicate_custom"
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ flags = NODECONSTRUCT
+
+/obj/machinery/computer/shuttle/nanotrasen/recall
+ name = "nanotrasen shuttle recall terminal"
+ circuit = /obj/item/circuitboard/shuttle/nanotrasen/recall
+ possible_destinations = "syndicate_away"
+
+// Nanotrasen Drop Pod
+/obj/machinery/computer/shuttle/nanotrasen/drop_pod
+ name = "nanotrasen assault pod control"
+ icon = 'icons/obj/terminals.dmi'
+ icon_state = "syndie_assault_pod"
+ req_access = list(ACCESS_CENT_SPECOPS_COMMANDER)
+ circuit = /obj/item/circuitboard/shuttle/nanotrasen/drop_pod
+ shuttleId = "nt_drop_pod"
+ possible_destinations = null
+ /// Is it possible to force sent a drop pod? (for admin shitspawns)
+ var/allow_force_sent = FALSE
+ /// To prevent spamming
+ var/next_request
+
+/obj/machinery/computer/shuttle/nanotrasen/drop_pod/can_call_shuttle(user, action)
+ if(action == "move")
+ if(world.time < next_request)
+ var/wait_time = round((next_request - world.time) / 10, 1)
+ to_chat(user, span_warning("Подождите ещё [wait_time] [wait_time == 1 ? "секунду" : "секунд"] перед использованием!"))
+ return
+ // 20 seconds cooldown before use
+ next_request = world.time + 20 SECONDS
+ if(z != level_name_to_num(CENTCOMM))
+ to_chat(user, span_warning("Дроп Под может лететь только в одну сторону!"))
+ return FALSE
+ if(!allow_force_sent && SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_EPSILON)
+ to_chat(user, span_warning("Дроп Под доступен при коде не ниже «Epsilon»!"))
+ return FALSE
+ return ..()
+
+/obj/machinery/computer/shuttle/nanotrasen/drop_pod/vv_edit_var(var_name, var_value)
+ if(var_name == "allow_force_sent")
+ var/confirm = tgui_alert(usr, "Отправка Дроп Пода в последующем будет невозможна, вы уверены?", "Подтверждение", list("Да", "Нет"))
+ if(confirm != "Да")
+ return FALSE
+ return ..()
+
+/* Docking Ports */
+/obj/docking_port/mobile/assault_pod/nanotrasen
+ id = "nt_drop_pod"
+
+/obj/docking_port/mobile/assault_pod/nanotrasen/request()
+ // No launching pods that have already launched
+ if(z == initial(src.z))
+ return ..()
+
+/* Circuits */
+/obj/item/circuitboard/shuttle/nanotrasen/recall
+ board_name = "Nanotrasen Shuttle Recall Terminal"
+ icon_state = "generic"
+ build_path = /obj/machinery/computer/shuttle/nanotrasen/recall
+
+/obj/item/circuitboard/shuttle/nanotrasen/drop_pod
+ board_name = "Nanotrasen Drop Pod"
+ icon_state = "generic"
+ build_path = /obj/machinery/computer/shuttle/nanotrasen/drop_pod
+
+/* Specific Shuttle Items */
+/obj/item/assault_pod/nanotrasen
+ shuttle_id = "nt_drop_pod"
diff --git a/modular_ss220/silicons/_silicons.dm b/modular_ss220/silicons/_silicons.dm
new file mode 100644
index 000000000000..1a7edaf2bfb5
--- /dev/null
+++ b/modular_ss220/silicons/_silicons.dm
@@ -0,0 +1,4 @@
+/datum/modpack/silicons
+ name = "Silicons Modpack"
+ desc = "Изменения для синтетиков."
+ author = "PhantomRU"
diff --git a/modular_ss220/silicons/_silicons.dme b/modular_ss220/silicons/_silicons.dme
new file mode 100644
index 000000000000..0a7a9880f3f6
--- /dev/null
+++ b/modular_ss220/silicons/_silicons.dme
@@ -0,0 +1,8 @@
+#include "_silicons.dm"
+
+#include "code/items/gripper.dm"
+#include "code/items/rlf.dm"
+#include "code/mechfabricator_designs.dm"
+#include "code/robot_items.dm"
+#include "code/robot_modules.dm"
+#include "code/robot_upgrades.dm"
diff --git a/modular_ss220/silicons/code/items/gripper.dm b/modular_ss220/silicons/code/items/gripper.dm
new file mode 100644
index 000000000000..61f9b320148e
--- /dev/null
+++ b/modular_ss220/silicons/code/items/gripper.dm
@@ -0,0 +1,45 @@
+/obj/item/gripper/engineering/Initialize(mapload)
+ . = ..()
+ can_hold |= list(
+ /obj/item/mounted/frame/light_fixture,
+ /obj/item/mounted/frame/apc_frame,
+ /obj/item/mounted/frame/alarm_frame,
+ /obj/item/mounted/frame/firealarm,
+ /obj/item/mounted/frame/display/newscaster_frame,
+ /obj/item/mounted/frame/intercom,
+ /obj/item/mounted/frame/extinguisher,
+ /obj/item/mounted/frame/light_switch,
+ /obj/item/flash,
+ )
+
+/obj/item/gripper/medical
+ actions_types = list(/datum/action/item_action/drop_gripped_item)
+ can_hold = list(
+ /obj/item/organ,
+ /obj/item/reagent_containers/iv_bag,
+ /obj/item/robot_parts,
+ /obj/item/stack/sheet/mineral/plasma, // For repair plasmemes
+ /obj/item/mmi,
+ /obj/item/reagent_containers/pill,
+ /obj/item/reagent_containers/patch,
+ /obj/item/reagent_containers/drinks,
+ /obj/item/reagent_containers/glass,
+ /obj/item/reagent_containers/syringe,
+ )
+
+/obj/item/gripper/medical/attack_self__legacy__attackchain(mob/user)
+ return
+
+/obj/item/gripper/service/Initialize(mapload)
+ . = ..()
+ can_hold |= list(
+ /obj/item/card,
+ /obj/item/camera_film,
+ /obj/item/disk/data,
+ /obj/item/disk/design_disk,
+ /obj/item/disk/plantgene,
+ )
+
+/obj/structure/morgue/attack_ai(mob/user)
+ add_hiddenprint(user)
+ return attack_hand(user)
diff --git a/modular_ss220/silicons/code/items/rlf.dm b/modular_ss220/silicons/code/items/rlf.dm
new file mode 100644
index 000000000000..176c16c5c094
--- /dev/null
+++ b/modular_ss220/silicons/code/items/rlf.dm
@@ -0,0 +1,61 @@
+/obj/item/rlf
+ name = "Rapid Lollipop Fabricator"
+ desc = "A device used to rapidly deploy lollipop."
+ icon = 'modular_ss220/silicons/icons/robot_tools.dmi'
+ icon_state = "rlf"
+
+/obj/item/rlf/afterattack__legacy__attackchain(atom/A, mob/user as mob, proximity)
+ if(!proximity)
+ return
+ if(!isrobot(user))
+ return
+ if(!iscarbon(A))
+ return
+ var/mob/living/carbon/receiver = A
+ if(receiver.stat != CONSCIOUS)
+ to_chat(user, span_warning("[receiver] can't accept any items because they're not conscious!"))
+ return
+ if(!user.Adjacent(receiver))
+ to_chat(user, span_warning("You need to be closer to [receiver] to offer them lollipop."))
+ return
+ if(!receiver.client)
+ to_chat(user, span_warning("You offer lollipop to [receiver], but they don't seem to respond..."))
+ return
+ var/obj/item/I = new /obj/item/food/candy/sucker/lollipop
+ receiver.throw_alert("take item [I.UID()]", /atom/movable/screen/alert/take_item/RLF, alert_args = list(user, receiver, I))
+ to_chat(user, span_info("You offer lollipop to [receiver]."))
+
+/atom/movable/screen/alert/take_item/RLF/Click(location, control, params)
+ var/mob/living/receiver = locateUID(receiver_UID)
+ if(receiver.stat != CONSCIOUS)
+ return
+ var/obj/item/food/candy/sucker/I = locateUID(item_UID)
+ if(receiver.r_hand && receiver.l_hand)
+ to_chat(receiver, span_warning("You need to have your hands free to accept [I]!"))
+ return
+ var/mob/living/giver = locateUID(giver_UID)
+ if(!isrobot(giver))
+ return
+ if(!giver.Adjacent(receiver))
+ to_chat(receiver, span_warning("You need to stay in reaching distance of [giver] to take [I]!"))
+ return
+ UnregisterSignal(I, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))
+ var/mob/living/silicon/robot/borg = giver
+ borg.cell.charge -= 500
+ I.forceMove(get_turf(giver))
+ receiver.put_in_hands(I)
+ I.add_fingerprint(receiver)
+ I.on_give(giver, receiver)
+ receiver.visible_message(span_notice("[giver] handed [I] to [receiver]."))
+ receiver.clear_alert("take item [item_UID]")
+
+/obj/item/food/candy/sucker/lollipop
+ name = "lollipop"
+ desc = "For being such a courage patient!"
+ icon_state = "sucker"
+ filling_color = "#60A584"
+ list_reagents = list("sugar" = 4)
+
+/obj/item/food/candy/sucker/lollipop/New()
+ . = ..()
+ icon_state = pick("sucker_blue", "sucker_green", "sucker_orange", "sucker_purple", "sucker_red", "sucker_yellow")
diff --git a/modular_ss220/silicons/code/mechfabricator_designs.dm b/modular_ss220/silicons/code/mechfabricator_designs.dm
new file mode 100644
index 000000000000..29023eee66e8
--- /dev/null
+++ b/modular_ss220/silicons/code/mechfabricator_designs.dm
@@ -0,0 +1,19 @@
+/datum/design/borg_upgrade_storageincreaser
+ name = "Engineer Cyborg Upgrade (Storage Increaser)"
+ id = "borg_upgrade_storageincreaser"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/storageincreaser
+ req_tech = list("bluespace" = 5, "materials" = 7, "engineering" = 5)
+ materials = list(MAT_METAL=15000, MAT_BLUESPACE=2000, MAT_SILVER=6000)
+ construction_time = 120
+ category = list("Cyborg Upgrade Modules")
+
+/datum/design/borg_upgrade_hypospray
+ name = "Medical Cyborg Upgrade (Upgraded Hypospray)"
+ id = "borg_upgrade_hypospray"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/hypospray
+ req_tech = list("biotech" = 7, "materials" = 7)
+ materials = list(MAT_METAL=15000, MAT_URANIUM=2000, MAT_DIAMOND=5000, MAT_SILVER=10000)
+ construction_time = 120
+ category = list("Cyborg Upgrade Modules")
diff --git a/modular_ss220/silicons/code/robot_items.dm b/modular_ss220/silicons/code/robot_items.dm
new file mode 100644
index 000000000000..fe161092be2a
--- /dev/null
+++ b/modular_ss220/silicons/code/robot_items.dm
@@ -0,0 +1,49 @@
+/* Engineer */
+// Небольшой багфикс "непрозрачного открытого шлюза"
+/obj/structure/inflatable/door/operate()
+ . = ..()
+ opacity = FALSE
+
+/* Medical */
+/obj/item/reagent_containers/borghypo/basic/Initialize(mapload)
+ . = ..()
+ reagent_ids |= list("sal_acid", "charcoal")
+
+/obj/item/reagent_containers/borghypo/basic/upgraded
+ name = "Upgraded Medical Hypospray"
+ desc = "Upgraded medical hypospray, capable of providing standart medical treatment."
+ reagent_ids = list("salglu_solution", "epinephrine", "spaceacillin", "sal_acid",
+ "charcoal", "hydrocodone", "mannitol", "salbutamol", "styptic_powder")
+ total_reagents = 60
+ maximum_reagents = 60
+
+/* Service */
+/obj/item/rsf/attack_self__legacy__attackchain(mob/user)
+ if(..() && power_mode >= 3000)
+ power_mode /= 2
+
+/obj/item/eftpos/cyborg
+ name = "Silicon EFTPOS"
+ desc = "Проведите ID картой для оплаты налогов."
+ transaction_purpose = "Оплата счета от робота."
+
+/obj/item/eftpos/cyborg/Initialize(mapload)
+ . = ..()
+ transaction_purpose = "Оплата счета от [usr.name]."
+
+/obj/item/eftpos/ui_act(action, list/params, datum/tgui/ui)
+ var/mob/living/user = ui.user
+
+ switch(action)
+ if("toggle_lock")
+ if(transaction_locked)
+ if(!check_user_position(user))
+ return
+ transaction_locked = FALSE
+ transaction_paid = FALSE
+ else if(linked_account)
+ transaction_locked = TRUE
+ else
+ to_chat(user, span_warning("[bicon(src)]No account connected to send transactions to.<"))
+ return TRUE
+ . = ..()
diff --git a/modular_ss220/silicons/code/robot_modules.dm b/modular_ss220/silicons/code/robot_modules.dm
new file mode 100644
index 000000000000..1cb0986ad617
--- /dev/null
+++ b/modular_ss220/silicons/code/robot_modules.dm
@@ -0,0 +1,91 @@
+// Drone
+/obj/item/robot_module/drone/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/holosign_creator/atmos,
+ )
+
+// Robots
+/obj/item/robot_module/engineering/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/lightreplacer/cyborg,
+ /obj/item/inflatable/cyborg,
+ /obj/item/inflatable/cyborg/door,
+ /obj/item/gps/cyborg,
+ )
+
+/obj/item/robot_module/medical/Initialize(mapload)
+ . = ..()
+ basic_modules.Remove(/obj/item/reagent_containers/borghypo)
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ /obj/item/rlf,
+ /obj/item/reagent_containers/borghypo/basic,
+ )
+
+/obj/item/robot_module/butler/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ /obj/item/eftpos/cyborg,
+ )
+
+/obj/item/robot_module/janitor/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ )
+
+/obj/item/robot_module/security/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ )
+
+// Syndicate
+/obj/item/robot_module/syndicate_medical/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ /obj/item/rlf,
+ )
+
+/obj/item/robot_module/syndicate_saboteur/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gripper/engineering,
+ /obj/item/holosign_creator/atmos,
+ )
+
+
+// Admin Spawns
+/obj/item/robot_module/deathsquad/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ /obj/item/pinpointer/operative/nad,
+ )
+
+/obj/item/robot_module/destroyer/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ /obj/item/pinpointer,
+ /obj/item/pinpointer/operative/nad,
+ )
+
+/obj/item/robot_module/combat/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ /obj/item/pinpointer/operative/nad,
+ )
+
+// Aliens
+/obj/item/robot_module/alien/hunter/Initialize(mapload)
+ . = ..()
+ basic_modules |= list(
+ /obj/item/gps/cyborg,
+ /obj/item/pinpointer/operative/nad,
+ )
diff --git a/modular_ss220/silicons/code/robot_upgrades.dm b/modular_ss220/silicons/code/robot_upgrades.dm
new file mode 100644
index 000000000000..61cf1fa92aa6
--- /dev/null
+++ b/modular_ss220/silicons/code/robot_upgrades.dm
@@ -0,0 +1,38 @@
+/obj/item/borg/upgrade/storageincreaser
+ name = "storage increaser"
+ desc = "Improves cyborg storage with bluespace technology to store more medicines"
+ icon_state = "cyborg_upgrade2"
+ origin_tech = "bluespace=4;materials=5;engineering=3"
+ require_module = TRUE
+ var/max_energy_multiplication = 3
+ var/recharge_rate_multiplication = 2
+
+/obj/item/borg/upgrade/storageincreaser/do_install(mob/living/silicon/robot/R)
+ for(var/obj/item/borg/upgrade/storageincreaser/U in R.contents)
+ to_chat(R, span_notice("A [name] unit is already installed!"))
+ to_chat(usr, span_notice("There's no room for another [name] unit!"))
+ return FALSE
+
+ for(var/datum/robot_storage/energy/ES in R.module.storages)
+ // ОФФы решили не делать деактиватор, поэтому против абуза сбрасываем.
+ ES.max_amount = initial(ES.max_amount)
+ ES.recharge_rate = initial(ES.recharge_rate)
+ ES.amount = initial(ES.max_amount)
+
+ // Modifier
+ ES.max_amount *= max_energy_multiplication
+ ES.recharge_rate *= recharge_rate_multiplication
+ ES.amount = ES.max_amount
+
+ return TRUE
+
+/obj/item/borg/upgrade/hypospray
+ name = "cyborg hypospray upgrade"
+ desc = "Adds and replaces some reagents with better ones"
+ icon_state = "cyborg_upgrade2"
+ origin_tech = "biotech=6;materials=5"
+ require_module = TRUE
+ module_type = /obj/item/robot_module/medical
+ items_to_replace = list(
+ /obj/item/reagent_containers/borghypo/basic = /obj/item/reagent_containers/borghypo/basic/upgraded
+ )
diff --git a/modular_ss220/silicons/icons/robot_tools.dmi b/modular_ss220/silicons/icons/robot_tools.dmi
new file mode 100644
index 000000000000..8eb41028d935
Binary files /dev/null and b/modular_ss220/silicons/icons/robot_tools.dmi differ
diff --git a/modular_ss220/sm_space_drop/code/paper_sm_info.dm b/modular_ss220/sm_space_drop/code/paper_sm_info.dm
new file mode 100644
index 000000000000..e90566cabd89
--- /dev/null
+++ b/modular_ss220/sm_space_drop/code/paper_sm_info.dm
@@ -0,0 +1,20 @@
+/// Инструкция пользование системы сброса СМ
+/obj/item/paper/sm_paper
+ name = "\proper инструкция по использованию СБСКС"
+ info = {"
Инструкция по использованию Системы Быстрого Сброса Кристалла Суперматерии
+ 1. Ни при каких обстоятельствах не нажимать на кнопку ради проверки ее работоспособности.
+
+ 2. Решение о сбросе кристалла может принимать СЕ, или его ВРиО и выше.
+
+ 3. Если целостность кристалла равна 10 или менее процентов, должен быть произведен сброс кристалла в кратчайшее время.
+
+ 4. В случае отсутствия СЕ и до назначения его ВРиО, решение о сбросе кристалла принимает капитан.
+
+ 5. Создание помехи при необходимости сброса кристалла квалифицируется статьей 400 Космического Закона.
+
+ Поздравляю! Теперь в случае вероятности взрыва кристалла Суперматерии, вы в состоянии сохранить целостность станции.
+
+ ПРИМЕЧАНИЕ: Кнопка сброса СМ находится в его буферной зоне на правой стене.
+
+