From d80d064e7bb7eb8f542d43616f51274f1f9e54e6 Mon Sep 17 00:00:00 2001
From: Oxotnak <107066254+Oxotnak@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:46:23 +0300
Subject: [PATCH 1/6] GAS carry build late game (#4957)
* agro-grab
* noslip + tackle resist
* movespeed raise
* eyes slot + offset
* agrograb's qol spans
* faster scythes + remove comment
* no glasses actually + exceptions
* exceptions + icon name fix
* [Drish] fix huds nabber
* scythes_stop_standing
* aaa
* aaa2
* lategaming
* aaa2.1
* aaa1.1
* stash valid
* tabulation missed
* Update tff_modular/modules/nabbers/code/_nabbers.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* Update tff_modular/modules/nabbers/code/_nabbers.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* Update tff_modular/modules/nabbers/code/_nabbers.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* Update tff_modular/modules/nabbers/code/_nabbers.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* Update tff_modular/modules/nabbers/code/_nabbers.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* Update tff_modular/modules/nabbers/code/_nabbers.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* Update tff_modular/modules/nabbers/code/nabber_bolaimmunity.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* Update tff_modular/modules/nabbers/code/nabber_language.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* Update tff_modular/modules/nabbers/code/nabber_language.dm
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
* eyes fix
* qol, fix, blacklist update
* language fix
---------
Co-authored-by: SuperDrish <59139863+Microvolnovka19@users.noreply.github.com>
---
code/modules/clothing/glasses/hud.dm | 14 ++
code/modules/mob/living/living_say.dm | 12 ++
.../research/techweb/nodes/cyborg_nodes.dm | 1 +
.../modules/huds/code/glasses/HUD_Glasses.dm | 4 +
.../meson_scouter/code/meson_scouter.dm | 10 +-
tff_modular/modules/nabbers/code/_nabbers.dm | 178 +++++++++++++++++-
.../modules/nabbers/code/abilites/agrograb.dm | 25 +++
.../code/abilites/nabber_combat_effect.dm | 2 +-
.../code/abilites/nabber_welding_eyes.dm | 2 +-
.../nabbers/code/abilites/toggle_arms.dm | 55 ++++--
.../modules/nabbers/code/nabber_bodyparts.dm | 6 +
.../nabbers/code/nabber_bolaimmunity.dm | 57 ++++++
.../modules/nabbers/code/nabber_huds.dm | 90 +++++++++
.../modules/nabbers/code/nabber_language.dm | 122 ++++++++++++
.../modules/nabbers/code/nabber_organs.dm | 21 ++-
tgstation.dme | 4 +
16 files changed, 571 insertions(+), 32 deletions(-)
create mode 100644 tff_modular/modules/nabbers/code/abilites/agrograb.dm
create mode 100644 tff_modular/modules/nabbers/code/nabber_bolaimmunity.dm
create mode 100644 tff_modular/modules/nabbers/code/nabber_huds.dm
create mode 100644 tff_modular/modules/nabbers/code/nabber_language.dm
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index 332aba8a719..97ed81c630e 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -38,6 +38,7 @@
icon_state = "healthhud"
clothing_traits = list(TRAIT_MEDICAL_HUD)
glass_colour_type = /datum/client_colour/glass_colour/lightblue
+ species_exception = list(/datum/species/nabber) // FF ADDITION
/obj/item/clothing/glasses/hud/medsechud
name = "health scanner security HUD"
@@ -57,6 +58,7 @@
glass_colour_type = /datum/client_colour/glass_colour/lightgreen
actions_types = list(/datum/action/item_action/toggle_nv)
forced_glass_color = TRUE
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/health/night/update_icon_state()
. = ..()
@@ -82,6 +84,7 @@
flags_cover = GLASSESCOVERSEYES
tint = 1
glass_colour_type = /datum/client_colour/glass_colour/blue
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/health/sunglasses/Initialize(mapload)
. = ..()
@@ -98,6 +101,7 @@
icon_state = "diagnostichud"
clothing_traits = list(TRAIT_DIAGNOSTIC_HUD)
glass_colour_type = /datum/client_colour/glass_colour/lightorange
+ species_exception = list(/datum/species/nabber) // FF ADDITION
/obj/item/clothing/glasses/hud/diagnostic/night
name = "night vision diagnostic HUD"
@@ -111,6 +115,7 @@
glass_colour_type = /datum/client_colour/glass_colour/lightyellow
actions_types = list(/datum/action/item_action/toggle_nv)
forced_glass_color = TRUE
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/diagnostic/night/update_icon_state()
. = ..()
@@ -124,6 +129,7 @@
flash_protect = FLASH_PROTECTION_FLASH
flags_cover = GLASSESCOVERSEYES
tint = 1
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/diagnostic/sunglasses/Initialize(mapload)
. = ..()
@@ -140,12 +146,14 @@
icon_state = "securityhud"
clothing_traits = list(TRAIT_SECURITY_HUD)
glass_colour_type = /datum/client_colour/glass_colour/red
+ species_exception = list(/datum/species/nabber) // FF ADDITION
/obj/item/clothing/glasses/hud/security/chameleon
name = "chameleon security HUD"
desc = "A stolen security HUD integrated with Syndicate chameleon technology. Provides flash protection."
flash_protect = FLASH_PROTECTION_FLASH
actions_types = list(/datum/action/item_action/chameleon/change/glasses/no_preset)
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/security/sunglasses/eyepatch
name = "eyepatch HUD"
@@ -153,6 +161,7 @@
icon_state = "hudpatch"
base_icon_state = "hudpatch"
actions_types = list(/datum/action/item_action/flip)
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/security/sunglasses/eyepatch/attack_self(mob/user, modifiers)
. = ..()
@@ -167,6 +176,7 @@
flags_cover = GLASSESCOVERSEYES
tint = 1
glass_colour_type = /datum/client_colour/glass_colour/darkred
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/security/sunglasses/Initialize(mapload)
. = ..()
@@ -188,6 +198,7 @@
glass_colour_type = /datum/client_colour/glass_colour/lightred
actions_types = list(/datum/action/item_action/toggle_nv)
forced_glass_color = TRUE
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/security/night/update_icon_state()
. = ..()
@@ -206,6 +217,7 @@
attack_verb_simple = list("slice")
hitsound = 'sound/items/weapons/bladeslice.ogg'
sharpness = SHARP_EDGED
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/security/sunglasses/gars/giga
name = "giga HUD gar glasses"
@@ -213,6 +225,7 @@
icon_state = "gigagar_sec"
force = 12
throwforce = 12
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/toggle
name = "Toggle HUD"
@@ -251,6 +264,7 @@
color_cutoffs = list(25, 8, 5)
glass_colour_type = /datum/client_colour/glass_colour/red
clothing_traits = list(TRAIT_SECURITY_HUD)
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/toggle/thermal/attack_self(mob/user)
..()
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index c935989a580..e72899d482d 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -278,6 +278,18 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
if((SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_HEAR, args) & COMSIG_MOVABLE_CANCEL_HEARING) || !GET_CLIENT(src))
return FALSE
+// FLUFFY EDIT START Converts scrambled nabber's msg into emote for people
+ if(ispath(message_language, /datum/language/nabber) && speaker != src)
+ var/gbs_translation_check = translate_language(speaker, message_language, raw_message, spans, message_mods)
+ if(raw_message != gbs_translation_check)
+ message_mods[MODE_CUSTOM_SAY_EMOTE] = gbs_translation_check
+ message_mods[MODE_CUSTOM_SAY_ERASE_INPUT] = TRUE
+
+ if(ispath(message_language, /datum/language/nabber) && isnabber(src))
+ message_mods[MODE_CUSTOM_SAY_EMOTE] = null
+ message_mods[MODE_CUSTOM_SAY_ERASE_INPUT] = FALSE
+ // FLUFFY EDIT END
+
var/deaf_message
var/deaf_type
diff --git a/code/modules/research/techweb/nodes/cyborg_nodes.dm b/code/modules/research/techweb/nodes/cyborg_nodes.dm
index fad15b6f019..bc5b7efc0be 100644
--- a/code/modules/research/techweb/nodes/cyborg_nodes.dm
+++ b/code/modules/research/techweb/nodes/cyborg_nodes.dm
@@ -149,6 +149,7 @@
"implanter",
"locator",
"c38_trac",
+ "implant_gasspeech",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS)
announce_channels = list(RADIO_CHANNEL_SECURITY, RADIO_CHANNEL_MEDICAL)
diff --git a/modular_nova/modules/huds/code/glasses/HUD_Glasses.dm b/modular_nova/modules/huds/code/glasses/HUD_Glasses.dm
index 13d25055eb8..3945298af98 100644
--- a/modular_nova/modules/huds/code/glasses/HUD_Glasses.dm
+++ b/modular_nova/modules/huds/code/glasses/HUD_Glasses.dm
@@ -4,6 +4,7 @@
icon = 'modular_nova/modules/huds/icons/huds.dmi'
icon_state = "glasses_healthhud"
worn_icon = 'modular_nova/modules/huds/icons/hudeyes.dmi'
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/health/prescription/Initialize(mapload)
clothing_traits += list(TRAIT_NEARSIGHTED_CORRECTED)
@@ -15,6 +16,7 @@
icon = 'modular_nova/modules/huds/icons/huds.dmi'
icon_state = "glasses_diagnostichud"
worn_icon = 'modular_nova/modules/huds/icons/hudeyes.dmi'
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/diagnostic/prescription/Initialize(mapload)
clothing_traits += list(TRAIT_NEARSIGHTED_CORRECTED)
@@ -26,6 +28,7 @@
icon = 'modular_nova/modules/huds/icons/huds.dmi'
icon_state = "glasses_securityhud"
worn_icon = 'modular_nova/modules/huds/icons/hudeyes.dmi'
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/hud/security/prescription/Initialize(mapload)
clothing_traits += list(TRAIT_NEARSIGHTED_CORRECTED)
@@ -51,6 +54,7 @@
/obj/item/clothing/glasses/meson/prescription
name = "prescription optical meson scanner"
desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting conditions. This one has prescription lens fitted in."
+ species_exception = list() // FF ADDITION
/obj/item/clothing/glasses/meson/prescription/Initialize(mapload)
clothing_traits += list(TRAIT_NEARSIGHTED_CORRECTED)
diff --git a/modular_nova/modules/meson_scouter/code/meson_scouter.dm b/modular_nova/modules/meson_scouter/code/meson_scouter.dm
index 08931499aa3..3c6fd5792eb 100644
--- a/modular_nova/modules/meson_scouter/code/meson_scouter.dm
+++ b/modular_nova/modules/meson_scouter/code/meson_scouter.dm
@@ -1,4 +1,5 @@
/obj/item/clothing/glasses/meson
+ species_exception = list(/datum/species/nabber) // FF ADDITION
uses_advanced_reskins = TRUE
unique_reskin = list(
"Meson Glasses" = list(
@@ -11,12 +12,12 @@
RESKIN_ICON = 'modular_nova/modules/meson_scouter/icons/meson_scouter.dmi',
RESKIN_ICON_STATE = "meson_scouter",
RESKIN_WORN_ICON = 'modular_nova/modules/meson_scouter/icons/meson-scouter_mob.dmi',
- RESKIN_WORN_ICON_STATE = "meson_scouter"
),
)
/obj/item/clothing/glasses/meson/night/Initialize(mapload)
. = ..()
+ species_exception = list() // FF ADDITION
unique_reskin -= list(
"Meson Glasses" = list(
RESKIN_ICON = 'icons/obj/clothing/glasses.dmi',
@@ -34,6 +35,7 @@
/obj/item/clothing/glasses/meson/gar/Initialize(mapload)
. = ..()
+ species_exception = list() // FF ADDITION
unique_reskin -= list(
"Meson Glasses" = list(
RESKIN_ICON = 'icons/obj/clothing/glasses.dmi',
@@ -51,6 +53,7 @@
/obj/item/clothing/glasses/meson/prescription/Initialize(mapload)
. = ..()
+ species_exception = list() // FF ADDITION
unique_reskin -= list(
"Meson Glasses" = list(
RESKIN_ICON = 'icons/obj/clothing/glasses.dmi',
@@ -67,6 +70,7 @@
)
/obj/item/clothing/glasses/meson/engine
+ species_exception = list(/datum/species/nabber) // FF ADDITION
uses_advanced_reskins = TRUE
unique_reskin = list(
"Engine Glasses" = list(
@@ -83,6 +87,7 @@
/obj/item/clothing/glasses/meson/engine/tray/Initialize(mapload)
. = ..()
+ species_exception = list() // FF ADDITION
unique_reskin -= list(
"Engine Glasses" = list(
RESKIN_ICON = 'icons/obj/clothing/glasses.dmi',
@@ -98,6 +103,7 @@
/obj/item/clothing/glasses/meson/engine/shuttle/Initialize(mapload)
. = ..()
+ species_exception = list() // FF ADDITION
unique_reskin -= list(
"Engine Glasses" = list(
RESKIN_ICON = 'icons/obj/clothing/glasses.dmi',
@@ -113,6 +119,7 @@
/obj/item/clothing/glasses/meson/engine/atmos_imaging/Initialize(mapload)
. = ..()
+ species_exception = list() // FF ADDITION
unique_reskin -= list(
"Engine Glasses" = list(
RESKIN_ICON = 'icons/obj/clothing/glasses.dmi',
@@ -128,6 +135,7 @@
/obj/item/clothing/glasses/meson/engine/prescription/Initialize(mapload)
. = ..()
+ species_exception = list() // FF ADDITION
unique_reskin -= list(
"Engine Glasses" = list(
RESKIN_ICON = 'icons/obj/clothing/glasses.dmi',
diff --git a/tff_modular/modules/nabbers/code/_nabbers.dm b/tff_modular/modules/nabbers/code/_nabbers.dm
index cd906b2be98..a41e631eaac 100644
--- a/tff_modular/modules/nabbers/code/_nabbers.dm
+++ b/tff_modular/modules/nabbers/code/_nabbers.dm
@@ -16,21 +16,25 @@
TRAIT_MUTANT_COLORS,
TRAIT_NO_UNDERWEAR,
TRAIT_HARD_SOLES,
- TRAIT_NO_BLOOD_OVERLAY
+ TRAIT_NO_BLOOD_OVERLAY,
+ TRAIT_NO_SLIP_WATER,
+ TRAIT_BRAWLING_KNOCKDOWN_BLOCKED,
+ TRAIT_PERSONALSPACE, // Нет жопы :с
)
body_size_restricted = TRUE
digitigrade_customization = DIGITIGRADE_NEVER
- no_equip_flags = ITEM_SLOT_FEET | ITEM_SLOT_OCLOTHING | ITEM_SLOT_SUITSTORE | ITEM_SLOT_EYES
+ no_equip_flags = ITEM_SLOT_FEET | ITEM_SLOT_OCLOTHING | ITEM_SLOT_SUITSTORE | ITEM_SLOT_EYES | ITEM_SLOT_LEGCUFFED
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
mutanttongue = /obj/item/organ/internal/tongue/nabber
- always_customizable = FALSE
+ always_customizable = TRUE
hair_alpha = 0
facial_hair_alpha = 0
payday_modifier = 0.75
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT
+ species_cookie = /obj/item/food/grown/cabbage
bodytemp_heat_damage_limit = (BODYTEMP_HEAT_DAMAGE_LIMIT - 10)
mutantbrain = /obj/item/organ/internal/brain/nabber
- mutanteyes = /obj/item/organ/internal/eyes/robotic/nabber
+ mutanteyes = /obj/item/organ/internal/eyes/nabber
mutantlungs = /obj/item/organ/internal/lungs/nabber
mutantheart = /obj/item/organ/internal/heart/nabber
mutantliver = /obj/item/organ/internal/liver/nabber
@@ -56,6 +60,11 @@
var/datum/action/cooldown/toggle_arms/arms
var/datum/action/cooldown/optical_camouflage/camouflage
var/datum/action/cooldown/nabber_threat/threat_mod
+ placeholder_description = "Giant armoured serpentids (GAS), also known as Nabbers, or snake-bugs, are a massive predatory species who are trained by a company to work with humans. Physically, although they look intimidating, they're unlikely to harm a human except in times of great stress. If you see them getting their large attack arms ready, it's telling you to back off."
+ placeholder_lore = "https://fluffy-frontier.ru/osobye-rasy"
+
+ species_language_holder = /datum/language_holder/nabber
+ language_prefs_whitelist = list(/datum/language/nabber)
/datum/species/nabber/on_species_gain(mob/living/carbon/human/C, datum/species/old_species, pref_load)
. = ..()
@@ -66,9 +75,16 @@
threat_mod = new(C)
threat_mod.Grant(C)
- // Предохраняемся от получения проклятого квирка. Ломающего ГБС
- if(C.has_quirk(/datum/quirk/oversized))
- C.remove_quirk(/datum/quirk/oversized)
+ var/is_dummy = istype(C, /mob/living/carbon/human/dummy)
+
+ if(!is_dummy)
+ C.uncuff()
+ if(!C.legcuffed)
+ var/obj/item/restraints/legcuffs/gas_placeholder/anti_cuffs = new()
+ C.equip_to_slot(anti_cuffs, ITEM_SLOT_LEGCUFFED, initial = TRUE)
+
+ var/obj/item/implant/gas_sol_speaker/imp_in = new()
+ imp_in.implant(C)
/datum/species/nabber/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
. = ..()
@@ -77,6 +93,10 @@
threat_mod.Destroy()
/datum/species/nabber/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired)
+ // Вызываем это перед проверкой на смерть, чтобы даже у мёртвых ГБСов была заглушка
+ if(H.num_legs >= 2 && !H.legcuffed && !QDELETED(H))
+ var/obj/item/restraints/legcuffs/gas_placeholder/anti_cuffs = new()
+ H.equip_to_slot(anti_cuffs, ITEM_SLOT_LEGCUFFED, initial = TRUE)
. = ..()
if(isdead(H))
return
@@ -125,7 +145,7 @@
))
perk_descriptions += list(list(
- SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
+ SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "dna",
SPECIES_PERK_NAME = "Robust chitin",
SPECIES_PERK_DESC = "GAS possess durable chitinous exoskeletons and can withstand a lot of brute damage."
@@ -169,3 +189,145 @@
/mob/living/carbon/human/species/nabber
race = /datum/species/nabber
+
+/mob/living/carbon/human/Destroy()
+ if(isnabber(src) && !QDELETED(legcuffed))
+ QDEL_NULL(legcuffed)
+ . = ..()
+
+// Отображение для других наличия повреждений у голосового импланта
+/mob/living/carbon/human/examine(mob/user)
+ . = ..()
+
+ if(isnabber(src))
+ var/is_really_borked = FALSE
+ for(var/obj/item/implant/gas_sol_speaker/imp in implants)
+ var/is_borked = imp.emp_damage
+ if (is_borked > 0)
+ is_really_borked = TRUE
+ if(is_really_borked)
+ . += span_notice("[user.p_Their()] speech synthesizer emits constant silent white noise.") + "\n"
+
+// Не заковывается при наличии кос
+/mob/living/carbon/human/canBeHandcuffed()
+ if(isnabber(src))
+ var/obj/item/held = get_active_held_item()
+ var/obj/item/inactive = get_inactive_held_item()
+ if(istype((inactive || held), /obj/item/melee/nabber_blade))
+ return FALSE
+ . = ..()
+
+// В режиме кос агро грабы не будут замедлять
+/mob/living/carbon/human/add_movespeed_modifier(datum/movespeed_modifier/type_or_datum, update = TRUE)
+ if(isnabber(src) && type_or_datum == /datum/movespeed_modifier/grab_slowdown/aggressive)
+ var/datum/species/nabber/our_nabber = src.dna.species
+ var/datum/action/cooldown/toggle_arms/arms = our_nabber.arms
+ if(arms.button_icon_state == "arms_on")
+ return FALSE
+ return ..()
+
+// ЧС квирков
+/mob/living/carbon/human/add_quirk(datum/quirk/quirktype, client/override_client)
+ var/bad_nabber_quirks = list(
+ // негативные
+ /datum/quirk/oversized,
+ /datum/quirk/prosthetic_limb,
+ /datum/quirk/quadruple_amputee,
+ /datum/quirk/item_quirk/addict/junkie,
+ /datum/quirk/item_quirk/addict/smoker,
+ /datum/quirk/item_quirk/addict/alcoholic,
+ /datum/quirk/all_nighter,
+ /datum/quirk/item_quirk/allergic, // До введения системы дыхания
+ /datum/quirk/badback,
+ /datum/quirk/bighands,
+ /datum/quirk/item_quirk/blindness,
+ /datum/quirk/blooddeficiency,
+ /datum/quirk/body_purist,
+ /datum/quirk/item_quirk/brainproblems,
+ /datum/quirk/item_quirk/chronic_illness,
+ /datum/quirk/clumsy,
+ /datum/quirk/item_quirk/deafness,
+ /datum/quirk/item_quirk/family_heirloom,
+ /datum/quirk/item_quirk/food_allergic,
+ /datum/quirk/frail,
+ /datum/quirk/glass_jaw,
+ /datum/quirk/hemiplegic,
+ /datum/quirk/indebted,
+ /datum/quirk/insanity,
+ /datum/quirk/light_drinker,
+ /datum/quirk/mute,
+ /datum/quirk/item_quirk/nearsighted,
+ /datum/quirk/nonviolent,
+ /datum/quirk/numb,
+ /datum/quirk/nyctophobia,
+ /datum/quirk/paraplegic,
+ /datum/quirk/photophobia,
+ /datum/quirk/prosopagnosia,
+ /datum/quirk/pushover,
+ /datum/quirk/social_anxiety,
+ /datum/quirk/softspoken,
+ /datum/quirk/tin_man,
+ /datum/quirk/touchy,
+ /datum/quirk/narcolepsy,
+ /datum/quirk/fragile,
+ /datum/quirk/alexithymia,
+ // Нейтральные
+ /datum/quirk/item_quirk/bald,
+ /datum/quirk/item_quirk/borg_ready,
+ /datum/quirk/deviant_tastes,
+ /datum/quirk/foreigner,
+ /datum/quirk/gamer,
+ /datum/quirk/no_taste,
+ /datum/quirk/item_quirk/photographer,
+ /datum/quirk/pineapple_hater,
+ /datum/quirk/pineapple_liker,
+ /datum/quirk/snob,
+ /datum/quirk/transhumanist,
+ /datum/quirk/vegetarian,
+ /datum/quirk/canine_aspect,
+ /datum/quirk/feline_aspect,
+ /datum/quirk/avian_aspect,
+ /datum/quirk/water_aspect,
+ /datum/quirk/webbing_aspect,
+ /datum/quirk/floral_aspect,
+ /datum/quirk/ash_aspect,
+ /datum/quirk/sparkle_aspect,
+ /datum/quirk/excitable,
+ /datum/quirk/personalspace, // Встроен
+ /datum/quirk/item_quirk/joker,
+ /datum/quirk/overweight,
+ /datum/quirk/echolocation,
+ /datum/quirk/equipping/entombed,
+ /datum/quirk/hydra,
+ /datum/quirk/possessive,
+ /datum/quirk/kleptomaniac,
+ /datum/quirk/masochism,
+ /datum/quirk/sadism,
+ /datum/quirk/ropebunny,
+ /datum/quirk/rigger,
+ /datum/quirk/telepathic,
+ /datum/quirk/burr,
+ /datum/quirk/item_quirk/underworld_connections,
+ /datum/quirk/unsteady,
+ // Позитивные
+ /datum/quirk/alcohol_tolerance,
+ /datum/quirk/bilingual,
+ /datum/quirk/drunkhealing,
+ /datum/quirk/light_step, // Встроен
+ /datum/quirk/item_quirk/musician,
+ /datum/quirk/item_quirk/settler,
+ /datum/quirk/item_quirk/signer,
+ /datum/quirk/item_quirk/pet_owner,
+ /datum/quirk/skittish,
+ /datum/quirk/spacer_born,
+ /datum/quirk/item_quirk/spiritual,
+ /datum/quirk/hard_soles, // Встроен
+ /datum/quirk/linguist,
+ /datum/quirk/sharpclaws,
+ /datum/quirk/water_breathing,
+ /datum/quirk/no_appendix, // Нет аппендикса
+ /datum/quirk/shapeshifter,
+ )
+ if(isnabber(src) && (quirktype in bad_nabber_quirks))
+ return FALSE
+ . = ..()
diff --git a/tff_modular/modules/nabbers/code/abilites/agrograb.dm b/tff_modular/modules/nabbers/code/abilites/agrograb.dm
new file mode 100644
index 00000000000..8f043043e17
--- /dev/null
+++ b/tff_modular/modules/nabbers/code/abilites/agrograb.dm
@@ -0,0 +1,25 @@
+#define MARTIALART_NABBER "scythes grab"
+
+/datum/martial_art/nabber_grab
+ name = "scythes grab"
+ id = MARTIALART_NABBER
+
+/datum/martial_art/nabber_grab/grab_act(mob/living/attacker, mob/living/defender)
+ if(attacker == defender)
+ return MARTIAL_ATTACK_INVALID
+
+ var/old_grab_state = attacker.grab_state
+ defender.grabbedby(attacker, TRUE)
+ if(old_grab_state == GRAB_PASSIVE)
+ defender.drop_all_held_items()
+ attacker.setGrabState(GRAB_AGGRESSIVE) //Instant aggressive grab if on grab intent
+ log_combat(attacker, defender, "grabbed", addition="aggressively")
+ defender.visible_message(
+ span_warning("[attacker] grabs [defender] in his scythes!"),
+ span_userdanger("You're grabbed in scythes by [attacker]!"),
+ span_hear("You hear sounds of aggressive fondling!"),
+ COMBAT_MESSAGE_RANGE,
+ attacker,
+ )
+ to_chat(attacker, span_danger("You grab [defender] in your scythes!"))
+ return MARTIAL_ATTACK_SUCCESS
diff --git a/tff_modular/modules/nabbers/code/abilites/nabber_combat_effect.dm b/tff_modular/modules/nabbers/code/abilites/nabber_combat_effect.dm
index 8b64d239d3d..92f116940f6 100644
--- a/tff_modular/modules/nabbers/code/abilites/nabber_combat_effect.dm
+++ b/tff_modular/modules/nabbers/code/abilites/nabber_combat_effect.dm
@@ -51,7 +51,7 @@
/datum/movespeed_modifier/nabber_combat
blacklisted_movetypes = FLYING
- multiplicative_slowdown = -0.25
+ multiplicative_slowdown = -0.40
#undef NABBER_THREAT_ICON
#undef NABBER_THREAT_ICON_STATE
diff --git a/tff_modular/modules/nabbers/code/abilites/nabber_welding_eyes.dm b/tff_modular/modules/nabbers/code/abilites/nabber_welding_eyes.dm
index 1f6253a79e1..60a8dd241d3 100644
--- a/tff_modular/modules/nabbers/code/abilites/nabber_welding_eyes.dm
+++ b/tff_modular/modules/nabbers/code/abilites/nabber_welding_eyes.dm
@@ -2,7 +2,7 @@
name = "Toggle welding shield"
desc = "Toggle your eyes welding shield"
- var/obj/item/organ/internal/eyes/robotic/nabber/eyes
+ var/obj/item/organ/internal/eyes/nabber/eyes
/datum/action/toggle_welding/Trigger(trigger_flags)
. = ..()
diff --git a/tff_modular/modules/nabbers/code/abilites/toggle_arms.dm b/tff_modular/modules/nabbers/code/abilites/toggle_arms.dm
index f83866ad337..9d28e0bf5b1 100644
--- a/tff_modular/modules/nabbers/code/abilites/toggle_arms.dm
+++ b/tff_modular/modules/nabbers/code/abilites/toggle_arms.dm
@@ -1,3 +1,5 @@
+var/datum/martial_art/martial_to_learn = new /datum/martial_art/nabber_grab()
+
/obj/item/melee/nabber_blade
name = "Mantis arm"
desc = "A grotesque matn made out of bone and flesh that cleaves through people as a hot knife through butter."
@@ -46,12 +48,18 @@
desc = "Pump blood from manipulating arms into mantis arms, becoming a menace in close combat but loosing ability to interact."
cooldown_time = 5 SECONDS
+ var/obj/item/restraints/handcuffs/stored_handcuffs = null //Переменная для сохранения наручников
+
button_icon = 'tff_modular/modules/nabbers/icons/actions.dmi'
/datum/action/cooldown/toggle_arms/New(Target, original)
. = ..()
button_icon_state = "arms_off"
+/datum/action/cooldown/toggle_arms/Destroy()
+ stored_handcuffs = null
+ . = ..()
+
/datum/action/cooldown/toggle_arms/Activate(atom/target)
var/mob/living/carbon/human/nabber = owner
@@ -59,8 +67,9 @@
return FALSE
if(isdead(nabber) || nabber.incapacitated)
- nabber.balloon_alert(nabber, "Incapacitated!")
- return FALSE
+ if(!nabber.handcuffed)
+ nabber.balloon_alert(nabber, "Incapacitated!")
+ return FALSE
if(nabber.num_hands < 2)
nabber.balloon_alert(nabber, "Need both hands!")
@@ -89,11 +98,19 @@
nabber.visible_message(span_warning("[nabber] starts to pump blood into their mantis arms!"), span_warning("You start pumping blood into your mantis arms and emmitting defensive screech! Stay still!"), span_hear("You hear ramping up screech!"))
playsound(nabber, 'tff_modular/modules/nabbers/sounds/nabberscream.ogg', 70)
- if(!do_after(nabber, 5 SECONDS, nabber))
+ if(!do_after(nabber, 2 SECONDS, nabber, IGNORE_USER_LOC_CHANGE))
StartCooldown()
- nabber.balloon_alert(nabber, "Stand still!")
return FALSE
+ //"Сохраняет" наручники надетые на ГБСа в ЕГО ТЕЛО и позволяет пользоваться косами + открепляет его от стула и подобного
+ if(nabber.handcuffed)
+ stored_handcuffs = nabber.handcuffed
+ nabber.handcuffed.forceMove(nabber)
+ nabber.set_handcuffed(null)
+ if(nabber.buckled?.buckle_requires_restraints)
+ nabber.buckled.unbuckle_mob(nabber)
+ nabber.update_handcuffed()
+
nabber.balloon_alert(nabber, "Arms rised!")
nabber.visible_message(span_warning("[nabber] raised their mantis arms ready for combat!"), span_warning("You raise your mantis arms, ready for combat."), span_hear("You hear terrible a screech!"))
playsound(nabber, 'tff_modular/modules/nabbers/sounds/nabberscream.ogg', 70)
@@ -107,8 +124,9 @@
nabber.put_in_active_hand(active_hand)
nabber.put_in_inactive_hand(inactive_hand)
+ martial_to_learn.teach(nabber)
- RegisterSignal(owner, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(on_lose_hand))
+ RegisterSignal(owner, COMSIG_CARBON_POST_REMOVE_LIMB, PROC_REF(on_lose_hand))
button_icon_state = "arms_on"
nabber.update_action_buttons()
@@ -117,7 +135,10 @@
nabber.visible_message(span_notice("[nabber] starts to pump blood out their mantis arms!"), span_notice("You start pumping blood out your mantis arms. Stay still!"), span_hear("You hear ramping up screech!"))
- if(force)
+ if(force) //Типикал бьонд код
+ if(stored_handcuffs)
+ stored_handcuffs.forceMove(stored_handcuffs.drop_location())
+ stored_handcuffs = null
nabber.Stun(5 SECONDS)
for(var/obj/item/held in nabber.held_items)
if(istype(held, /obj/item/melee/nabber_blade))
@@ -128,8 +149,7 @@
nabber.balloon_alert(nabber, "Starting pumping blood out!")
- if(!do_after(nabber, 5 SECONDS, nabber))
- nabber.balloon_alert(nabber, "Stand still!")
+ if(!do_after(nabber, 2 SECONDS, nabber, IGNORE_USER_LOC_CHANGE))
return FALSE
playsound(nabber, 'tff_modular/modules/nabbers/sounds/nabberscream.ogg', 70)
@@ -137,17 +157,23 @@
if(istype(held, /obj/item/melee/nabber_blade))
qdel(held)
- UnregisterSignal(owner, COMSIG_CARBON_REMOVE_LIMB)
+ UnregisterSignal(owner, COMSIG_CARBON_POST_REMOVE_LIMB)
+ martial_to_learn.remove(nabber)
nabber.balloon_alert(nabber, "Arms down!")
button_icon_state = "arms_off"
nabber.update_action_buttons()
+ // Надевает наручники обратно если они были до перехода в косы
+ if(stored_handcuffs)
+ nabber.equip_to_slot(stored_handcuffs, ITEM_SLOT_HANDCUFFED)
+ stored_handcuffs = null
+
/datum/action/cooldown/toggle_arms/proc/on_lose_hand()
SIGNAL_HANDLER
var/mob/living/carbon/human/nabber = owner
- if(!(nabber.num_hands < 2))
- return FALSE
+ if(nabber.num_hands >= 2)
+ return FALSE
nabber.visible_message(span_notice("[nabber] starts to pump blood out their mantis arms!"), span_notice("You start pumping blood out your mantis arms. Stay still!"), span_hear("You hear ramping up screech!"))
playsound(nabber, 'tff_modular/modules/nabbers/sounds/nabberscream.ogg', 70)
@@ -157,5 +183,12 @@
if(istype(held, /obj/item/melee/nabber_blade))
qdel(held)
+ martial_to_learn.remove(nabber)
button_icon_state = "arms_off"
nabber.update_action_buttons()
+
+ if(stored_handcuffs)
+ stored_handcuffs.forceMove(stored_handcuffs.drop_location())
+ stored_handcuffs = null
+
+ UnregisterSignal(owner, COMSIG_CARBON_POST_REMOVE_LIMB)
diff --git a/tff_modular/modules/nabbers/code/nabber_bodyparts.dm b/tff_modular/modules/nabbers/code/nabber_bodyparts.dm
index 04587b7ae9b..65c059e9f10 100644
--- a/tff_modular/modules/nabbers/code/nabber_bodyparts.dm
+++ b/tff_modular/modules/nabbers/code/nabber_bodyparts.dm
@@ -30,6 +30,12 @@
feature_key = OFFSET_FACEMASK,
offset_y = list("north" = 7, "south" = 7, "east" = 7, "west" = 7),
)
+ worn_glasses_offset = new(
+ attached_part = src,
+ feature_key = OFFSET_GLASSES,
+ offset_y = list("north" = 10, "south" = 10, "east" = 10, "west" = 10),
+ offset_x = list("north" = 1, "south" = 1, "east" = 1, "west" = -1)
+ )
return ..()
diff --git a/tff_modular/modules/nabbers/code/nabber_bolaimmunity.dm b/tff_modular/modules/nabbers/code/nabber_bolaimmunity.dm
new file mode 100644
index 00000000000..ec6f41597b8
--- /dev/null
+++ b/tff_modular/modules/nabbers/code/nabber_bolaimmunity.dm
@@ -0,0 +1,57 @@
+/// Special type of legcuffs that do not affect movement or doesnt show up, but block other legcuffs
+/obj/item/restraints/legcuffs/gas_placeholder
+ name = "serpentid thick tail"
+ desc = "You should not see this."
+ gender = PLURAL
+ icon_state = NONE
+ inhand_icon_state = "nabber_r_leg"
+ lefthand_file = 'tff_modular/modules/nabbers/icons/bodyparts/nabber_parts_greyscale.dmi'
+ righthand_file = 'tff_modular/modules/nabbers/icons/bodyparts/nabber_parts_greyscale.dmi'
+ w_class = WEIGHT_CLASS_TINY
+ slowdown = 0
+ item_flags = DROPDEL | ABSTRACT
+
+/obj/item/restraints/legcuffs/gas_placeholder/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
+
+/obj/item/restraints/legcuffs/gas_placeholder/update_icon_state()
+ icon_state = NONE
+ return ..()
+
+/mob/living/carbon/human/cuff_resist(obj/item/cuffs, breakouttime = 1 MINUTES, cuff_break = 0)
+ if(isnabber(src))
+ if(istype(cuffs, /obj/item/restraints/legcuffs/gas_placeholder))
+ return FALSE
+ return ..()
+
+/mob/living/carbon/human/doUnEquip(obj/item/unequip_item, force, newloc, no_move, invdrop, silent)
+ if(isnabber(src))
+ if(istype(unequip_item, /obj/item/restraints/legcuffs/gas_placeholder))
+ return FALSE
+ return ..()
+
+/// У ГБСов этот слот всегда должен быть занять заглушкой, которую нельзя снять
+/mob/living/carbon/human/update_worn_legcuffs(update_obscured = TRUE)
+ if(isnabber(src))
+ return FALSE
+ else
+ return ..()
+
+/datum/species/nabber/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self, ignore_equipped, indirect_action)
+ if(slot == ITEM_SLOT_LEGCUFFED)
+ return FALSE
+ . = ..()
+
+// Это ужас
+/obj/item/restraints/legcuffs/gas_placeholder/canStrip(mob/stripper, mob/owner)
+ INVOKE_ASYNC(src, PROC_REF(touch_ze_bug), stripper, owner)
+ return ..()
+
+/obj/item/restraints/legcuffs/gas_placeholder/proc/touch_ze_bug(mob/stripper, mob/owner)
+ owner.visible_message(
+ span_purple("[stripper] лапает хвост ГБСа. Кажется зря."),
+ span_purple("[stripper] лапает мой хвост! Кажется зря."),
+ blind_message = span_hear("You hear lewd bug noises."),
+ )
+ playsound(get_turf(owner), 'modular_nova/modules/modular_items/lewd_items/sounds/vax2.ogg', 50, TRUE)
diff --git a/tff_modular/modules/nabbers/code/nabber_huds.dm b/tff_modular/modules/nabbers/code/nabber_huds.dm
new file mode 100644
index 00000000000..af7e5a9bd2c
--- /dev/null
+++ b/tff_modular/modules/nabbers/code/nabber_huds.dm
@@ -0,0 +1,90 @@
+#define NABBER_HUD_Y_SHIFT 12
+
+/mob/living/carbon/human/species/nabber/med_hud_set_status()
+ . = ..()
+ var/image/holder = hud_list?[STATUS_HUD]
+ if (isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/species/nabber/med_hud_set_health()
+ . = ..()
+ var/image/holder = hud_list?[HEALTH_HUD]
+ if (isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/species/nabber/sec_hud_set_ID()
+ . = ..()
+ var/image/holder = hud_list[ID_HUD]
+ if (isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+ var/image/permit_holder = hud_list[PERMIT_HUD]
+ if (isnull(permit_holder))
+ return
+ permit_holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/species/nabber/sec_hud_set_security_status()
+ . = ..()
+ var/image/holder = hud_list[WANTED_HUD]
+ if (isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/species/nabber/sec_hud_set_implants()
+ . = ..()
+ var/image/holder
+ for(var/i in (list(IMPSEC_FIRST_HUD, IMPLOYAL_HUD, IMPSEC_SECOND_HUD) & hud_list))
+ holder = hud_list[i]
+ if(isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/med_hud_set_status()
+ . = ..()
+ if(isnabber(src))
+ var/image/holder = hud_list?[STATUS_HUD]
+ if (isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/med_hud_set_health()
+ . = ..()
+ if(isnabber(src))
+ var/image/holder = hud_list?[HEALTH_HUD]
+ if (isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/sec_hud_set_ID()
+ . = ..()
+ if(isnabber(src))
+ var/image/holder = hud_list[ID_HUD]
+ if (isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+ var/image/permit_holder = hud_list[PERMIT_HUD]
+ if (isnull(permit_holder))
+ return
+ permit_holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/sec_hud_set_security_status()
+ . = ..()
+ if(isnabber(src))
+ var/image/holder = hud_list[WANTED_HUD]
+ if (isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+/mob/living/carbon/human/sec_hud_set_implants()
+ . = ..()
+ if(isnabber(src))
+ var/image/holder
+ for(var/i in (list(IMPSEC_FIRST_HUD, IMPLOYAL_HUD, IMPSEC_SECOND_HUD) & hud_list))
+ holder = hud_list[i]
+ if(isnull(holder))
+ return
+ holder.pixel_y += NABBER_HUD_Y_SHIFT
+
+#undef NABBER_HUD_Y_SHIFT
diff --git a/tff_modular/modules/nabbers/code/nabber_language.dm b/tff_modular/modules/nabbers/code/nabber_language.dm
new file mode 100644
index 00000000000..4f1dc00564c
--- /dev/null
+++ b/tff_modular/modules/nabbers/code/nabber_language.dm
@@ -0,0 +1,122 @@
+/datum/language/nabber
+ name = "Giant Armored Serpentid"
+ desc = "A complex language that contains various sounds and movements, spoken only by Serpentids."
+ key = "N"
+ syllables = null
+ special_characters = null
+ default_priority = 70
+
+ flags = NO_STUTTER | TONGUELESS_SPEECH
+ always_use_default_namelist = TRUE
+ icon_state = "animal"
+ secret = TRUE
+
+/datum/language/nabber/scramble(input)
+
+ var/scrambled_text = "[pick("ритмично", "коротко", "быстро", "громко", "мелодично", "монотонно", "резко", "характерно")] \
+ [pick("жужжит", "щёлкает", "верещит", "стрекочет")] \
+ [pick("пару раз" , "несколько раз", "три раза")]."
+
+ add_to_cache(input, scrambled_text)
+
+ return scrambled_text
+
+/datum/language_holder/nabber
+ understood_languages = list(
+ /datum/language/common = list(LANGUAGE_MIND),
+ /datum/language/nabber = list(LANGUAGE_MIND),
+ )
+ spoken_languages = list(
+ /datum/language/common = list(LANGUAGE_ATOM),
+ /datum/language/nabber = list(LANGUAGE_SPECIES),
+ )
+ selected_language = /datum/language/common
+
+/obj/item/implant/gas_sol_speaker
+ name = "sol speech synthesizer implant"
+ actions_types = null
+ // Implant gets damaged evevy emp_act(). If 0 - its fine. 1 - it stops working. Any more damage will give burn damage
+ // TODO: add more stages
+ var/emp_damage = 0
+
+/obj/item/implant/gas_sol_speaker/get_data()
+ return "Implant Specifications:
\
+ Name: Sol Government Giant Armored Serpentid Speech Synthesizer Beta v0.3
\
+ Life: Activates upon speech attempt.
\
+ Important Notes: Does not work on other species.
\
+