diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 009c78bd35d..2eed5119a6c 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -360,6 +360,14 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
//Trait for customizable reagent holder
#define TRAIT_CUSTOMIZABLE_REAGENT_HOLDER "customizable_reagent_holder"
+/* Traits for ventcrawling.
+ * Both give access to ventcrawling, but *_NUDE requires the user to be
+ * wearing no clothes and holding no items. If both present, *_ALWAYS
+ * takes precedence.
+ */
+#define TRAIT_VENTCRAWLER_ALWAYS "ventcrawler_always"
+#define TRAIT_VENTCRAWLER_NUDE "ventcrawler_nude"
+
//Medical Categories for quirks
#define CAT_QUIRK_ALL 0
#define CAT_QUIRK_NOTES 1
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index dc94928cf6b..00397cc6bf9 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -127,7 +127,7 @@
if(affected_mob.mind && !is_monkey(affected_mob.mind))
add_monkey(affected_mob.mind)
affected_mob.monkeyize()
- affected_mob.ventcrawler = VENTCRAWLER_ALWAYS
+ ADD_TRAIT(affected_mob, TRAIT_VENTCRAWLER_ALWAYS, type)
/datum/disease/transformation/jungle_fever/stage_act()
diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm
index 248c2ec6fbf..79321103a10 100644
--- a/code/game/objects/structures/plasticflaps.dm
+++ b/code/game/objects/structures/plasticflaps.dm
@@ -62,7 +62,8 @@
return TRUE
var/mob/living/M = caller
- if(!M.ventcrawler && M.mob_size != MOB_SIZE_TINY)
+ var/ventcrawler = HAS_TRAIT(M, TRAIT_VENTCRAWLER_ALWAYS) || HAS_TRAIT(M, TRAIT_VENTCRAWLER_NUDE)
+ if(!ventcrawler && M.mob_size != MOB_SIZE_TINY)
return FALSE
var/atom/movable/M = caller
if(M?.pulling)
@@ -92,7 +93,9 @@
var/mob/living/M = A
if(M.buckled && istype(M.buckled, /mob/living/simple_animal/bot/mulebot)) // mulebot passenger gets a free pass.
return TRUE
- if(M.body_position == STANDING_UP && !M.ventcrawler && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass.
+
+ var/ventcrawler = HAS_TRAIT(M, TRAIT_VENTCRAWLER_ALWAYS) || HAS_TRAIT(M, TRAIT_VENTCRAWLER_NUDE)
+ if(M.body_position == STANDING_UP && !ventcrawler && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass.
return FALSE
/obj/structure/plasticflaps/deconstruct(disassembled = TRUE)
diff --git a/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm b/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm
index 8ac083f68b1..c4e1164d664 100644
--- a/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm
+++ b/code/modules/antagonists/abductor/equipment/glands/ventcrawl.dm
@@ -9,4 +9,4 @@
/obj/item/organ/heart/gland/ventcrawling/activate()
to_chat(owner, "You feel very stretchy.")
- owner.ventcrawler = VENTCRAWLER_ALWAYS
+ ADD_TRAIT(owner, TRAIT_VENTCRAWLER_ALWAYS, type)
diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm
index 532a8406547..c07166885e9 100644
--- a/code/modules/antagonists/morph/morph.dm
+++ b/code/modules/antagonists/morph/morph.dm
@@ -13,7 +13,6 @@
stop_automated_movement = 1
status_flags = CANPUSH
pass_flags = PASSTABLE
- ventcrawler = VENTCRAWLER_ALWAYS
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
maxHealth = 150
@@ -43,6 +42,10 @@
/mob/living/simple_animal/hostile/morph,
/obj/effect))
+/mob/living/simple_animal/hostile/morph/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/morph/examine(mob/user)
if(morphed)
. = form.examine(user)
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 6661c771424..80c33bcb38d 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -60,7 +60,7 @@
. = ..()
if(is_type_in_list(src, GLOB.ventcrawl_machinery) && isliving(user))
var/mob/living/L = user
- if(L.ventcrawler)
+ if(HAS_TRAIT(L, TRAIT_VENTCRAWLER_NUDE) || HAS_TRAIT(L, TRAIT_VENTCRAWLER_ALWAYS))
. += "Alt-click to crawl through it."
/obj/machinery/atmospherics/New(loc, process = TRUE, setdir)
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index 9e0a51ebbb6..9df9ae26043 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -4,7 +4,6 @@
gender = FEMALE //All xenos are girls!!
dna = null
faction = list(ROLE_ALIEN)
- ventcrawler = VENTCRAWLER_ALWAYS
sight = SEE_MOBS
see_in_dark = 4
verb_say = "hisses"
@@ -32,7 +31,8 @@
create_internal_organs()
- ADD_TRAIT(src, TRAIT_NEVER_WOUNDED, ROUNDSTART_TRAIT)
+ ADD_TRAIT(src, TRAIT_NEVER_WOUNDED, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
. = ..()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
index ba15f06583f..4f375fbf05d 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
@@ -2,7 +2,6 @@
//Common stuffs for Praetorian and Queen
icon = 'icons/mob/alienqueen.dmi'
status_flags = 0
- ventcrawler = VENTCRAWLER_NONE //pull over that ass too fat
pixel_x = -16
base_pixel_x = -16
bubble_icon = "alienroyal"
@@ -13,6 +12,11 @@
var/alt_inhands_file = 'icons/mob/alienqueen.dmi'
+/mob/living/carbon/alien/humanoid/royal/Initialize()
+ . = ..()
+ // as a wise man once wrote: "pull over that ass too fat"
+ REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/carbon/alien/humanoid/royal/can_inject()
return FALSE
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 787ba4b93f8..d4db440a635 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -801,19 +801,26 @@
/datum/species/golem/plastic
name = "Plastic Golem"
id = "plastic golem"
+ inherent_traits = list(
+ TRAIT_ADVANCEDTOOLUSER,
+ TRAIT_RESISTHEAT,
+ TRAIT_NOBREATH,
+ TRAIT_RESISTCOLD,
+ TRAIT_RESISTHIGHPRESSURE,
+ TRAIT_RESISTLOWPRESSURE,
+ TRAIT_NOFIRE,
+ TRAIT_CHUNKYFINGERS,
+ TRAIT_RADIMMUNE,
+ TRAIT_GENELESS,
+ TRAIT_PIERCEIMMUNE,
+ TRAIT_NODISMEMBER,
+ TRAIT_VENTCRAWLER_NUDE,
+ )
prefix = "Plastic"
special_names = list("Sheet", "Bag", "Bottle")
fixed_mut_color = "fffa"
info_text = "As a Plastic Golem, you are capable of ventcrawling and passing through plastic flaps as long as you are naked."
-/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- . = ..()
- C.ventcrawler = VENTCRAWLER_NUDE
-
-/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C)
- . = ..()
- C.ventcrawler = initial(C.ventcrawler)
-
/datum/species/golem/bronze
name = "Bronze Golem"
id = "bronze golem"
diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
index 136c3825934..90736c0d4a7 100644
--- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm
+++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
@@ -11,7 +11,7 @@
meat = /obj/item/food/meat/slab/monkey
knife_butcher_results = list(/obj/item/food/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
species_traits = list(HAS_FLESH,HAS_BONE,NO_UNDERWEAR,LIPS,NOEYESPRITES,NOBLOODOVERLAY,NOTRANSSTING, NOAUGMENTS)
- inherent_traits = list(TRAIT_MONKEYLIKE)
+ inherent_traits = list(TRAIT_MONKEYLIKE, TRAIT_VENTCRAWLER_NUDE)
no_equip = list(ITEM_SLOT_EARS, ITEM_SLOT_EYES, ITEM_SLOT_OCLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_FEET, ITEM_SLOT_ICLOTHING, ITEM_SLOT_SUITSTORE)
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN | SLIME_EXTRACT
liked_food = MEAT | FRUIT
@@ -42,7 +42,6 @@
/datum/species/monkey/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
. = ..()
- H.ventcrawler = VENTCRAWLER_NUDE
H.pass_flags |= PASSTABLE
H.butcher_results = knife_butcher_results
if(!H.dna.features["tail_monkey"] || H.dna.features["tail_monkey"] == "None")
@@ -55,7 +54,6 @@
/datum/species/monkey/on_species_loss(mob/living/carbon/C)
. = ..()
- C.ventcrawler = initial(C.ventcrawler)
C.pass_flags = initial(C.pass_flags)
C.butcher_results = null
C.dna.remove_mutation(RACEMUT)
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 3091f3bfc25..159170b5563 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -75,7 +75,6 @@
var/on_fire = FALSE ///The "Are we on fire?" var
var/fire_stacks = 0 ///Tracks how many stacks of fire we have on, max is usually 20
- var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always
var/limb_destroyer = 0 //1 Sets AI behavior that allows mobs to target and dismember limbs with their basic attack.
var/mob_size = MOB_SIZE_HUMAN
diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm
index b3862c61ab5..f6594fc5728 100644
--- a/code/modules/mob/living/login.dm
+++ b/code/modules/mob/living/login.dm
@@ -21,6 +21,7 @@
update_z(T.z)
//Vents
+ var/ventcrawler = HAS_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS) || HAS_TRAIT(src, TRAIT_VENTCRAWLER_NUDE)
if(ventcrawler)
to_chat(src, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.")
diff --git a/code/modules/mob/living/simple_animal/friendly/butterfly.dm b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
index c31165b5183..c12959fdc2d 100644
--- a/code/modules/mob/living/simple_animal/friendly/butterfly.dm
+++ b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
@@ -20,7 +20,6 @@
density = FALSE
is_flying_animal = TRUE
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BUG
gold_core_spawnable = FRIENDLY_SPAWN
@@ -33,6 +32,7 @@
. = ..()
var/newcolor = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
/mob/living/simple_animal/butterfly/bee_friendly()
return TRUE //treaty signed at the Beeneeva convention
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 34142870332..2eff2288e68 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -13,7 +13,6 @@
speak_chance = 1
turns_per_move = 5
see_in_dark = 6
- ventcrawler = VENTCRAWLER_ALWAYS
pass_flags = PASSTABLE
mob_size = MOB_SIZE_SMALL
mob_biotypes = MOB_ORGANIC|MOB_BEAST
@@ -49,6 +48,7 @@
. = ..()
add_verb(src, /mob/living/proc/toggle_resting)
add_cell_sample()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
/mob/living/simple_animal/pet/cat/add_cell_sample()
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CAT, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm
index 75449c32d84..33a3868c7f3 100644
--- a/code/modules/mob/living/simple_animal/friendly/crab.dm
+++ b/code/modules/mob/living/simple_animal/friendly/crab.dm
@@ -20,11 +20,14 @@
stop_automated_movement = 1
friendly_verb_continuous = "pinches"
friendly_verb_simple = "pinch"
- ventcrawler = VENTCRAWLER_ALWAYS
var/obj/item/inventory_head
var/obj/item/inventory_mask
gold_core_spawnable = FRIENDLY_SPAWN
+/mob/living/simple_animal/crab/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/crab/Life()
..()
//CRAB movement
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index 34c83f2facc..ec3cc37e826 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -52,7 +52,6 @@
maxbodytemp = 0
wander = 0
speed = 0
- ventcrawler = VENTCRAWLER_ALWAYS
healable = 0
density = FALSE
pass_flags = PASSTABLE | PASSMOB
@@ -144,6 +143,8 @@
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/drone/med_hud_set_health()
var/image/holder = hud_list[DIAG_HUD]
var/icon/I = icon(icon, icon_state, dir)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index 03e7150825e..c41649d4d39 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -153,7 +153,7 @@
to_chat(src, "Your onboard antivirus has initiated lockdown. Motor servos are impaired, ventilation access is denied, and your display reports that you are hacked to all nearby.")
hacked = TRUE
mind.special_role = "hacked drone"
- ventcrawler = VENTCRAWLER_NONE //Again, balance
+ REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
speed = 1 //gotta go slow
message_admins("[ADMIN_LOOKUPFLW(src)] became a hacked drone hellbent on destroying the station!")
else
@@ -168,7 +168,7 @@
to_chat(src, "Having been restored, your onboard antivirus reports the all-clear and you are able to perform all actions again.")
hacked = FALSE
mind.special_role = null
- ventcrawler = initial(ventcrawler)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
speed = initial(speed)
message_admins("[ADMIN_LOOKUPFLW(src)], a hacked drone, was restored to factory defaults!")
update_drone_icon_hacked()
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index 18989404203..a73b11b2b9f 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -258,7 +258,6 @@
attack_verb_simple = "kick"
health = 3
maxHealth = 3
- ventcrawler = VENTCRAWLER_ALWAYS
var/amount_grown = 0
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
@@ -273,6 +272,7 @@
pixel_x = base_pixel_x + rand(-6, 6)
pixel_y = base_pixel_y + rand(0, 10)
add_cell_sample()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
/mob/living/simple_animal/chick/add_cell_sample()
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CHICKEN, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
@@ -319,7 +319,6 @@
attack_verb_simple = "kick"
health = 15
maxHealth = 15
- ventcrawler = VENTCRAWLER_ALWAYS
var/eggsleft = 0
var/eggsFertile = TRUE
var/body_color
@@ -346,6 +345,8 @@
++chicken_count
add_cell_sample()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/chicken/add_cell_sample()
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CHICKEN, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm
index 1085c2d7614..7b53cbfa4ad 100644
--- a/code/modules/mob/living/simple_animal/friendly/lizard.dm
+++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm
@@ -18,7 +18,6 @@
response_disarm_simple = "shoo"
response_harm_continuous = "stomps on"
response_harm_simple = "stomp on"
- ventcrawler = VENTCRAWLER_ALWAYS
density = FALSE
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
@@ -30,6 +29,10 @@
pet_bonus = TRUE
pet_bonus_emote = "sticks its tongue out contentedly!"
+/mob/living/simple_animal/hostile/lizard/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/lizard/CanAttack(atom/the_target)//Can we actually attack a possible target?
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
return FALSE
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index cf661c43c4d..013eea16405 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -21,7 +21,6 @@
response_harm_continuous = "splats"
response_harm_simple = "splat"
density = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BEAST
@@ -42,6 +41,8 @@
icon_dead = "mouse_[body_color]_dead"
add_cell_sample()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/mouse/add_cell_sample()
AddElement(/datum/element/swabable, CELL_LINE_TABLE_MOUSE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 10)
diff --git a/code/modules/mob/living/simple_animal/friendly/snake.dm b/code/modules/mob/living/simple_animal/friendly/snake.dm
index 700625746f2..ad4ca315d65 100644
--- a/code/modules/mob/living/simple_animal/friendly/snake.dm
+++ b/code/modules/mob/living/simple_animal/friendly/snake.dm
@@ -30,7 +30,6 @@
response_harm_continuous = "steps on"
response_harm_simple = "step on"
faction = list("hostile")
- ventcrawler = VENTCRAWLER_ALWAYS
density = FALSE
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
@@ -42,6 +41,7 @@
/mob/living/simple_animal/hostile/retaliate/poison/snake/Initialize()
. = ..()
add_cell_sample()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
/mob/living/simple_animal/hostile/retaliate/poison/snake/add_cell_sample()
AddElement(/datum/element/swabable, CELL_LINE_TABLE_SNAKE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index 151ff34052e..6e7d1c7ab11 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -35,7 +35,6 @@
faction = list("hostile")
move_to_delay = 0
obj_damage = 0
- ventcrawler = VENTCRAWLER_ALWAYS
environment_smash = ENVIRONMENT_SMASH_NONE
mouse_opacity = MOUSE_OPACITY_OPAQUE
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
@@ -63,6 +62,7 @@
/mob/living/simple_animal/hostile/poison/bees/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
generate_bee_visuals()
AddComponent(/datum/component/swarming)
diff --git a/code/modules/mob/living/simple_animal/hostile/cockroach.dm b/code/modules/mob/living/simple_animal/hostile/cockroach.dm
index 54cb9b60e03..bd9c0c0485f 100644
--- a/code/modules/mob/living/simple_animal/hostile/cockroach.dm
+++ b/code/modules/mob/living/simple_animal/hostile/cockroach.dm
@@ -22,7 +22,6 @@
melee_damage_lower = 0
melee_damage_upper = 0
obj_damage = 0
- ventcrawler = VENTCRAWLER_ALWAYS
gold_core_spawnable = FRIENDLY_SPAWN
verb_say = "chitters"
verb_ask = "chitters inquisitively"
@@ -38,6 +37,8 @@
add_cell_sample()
make_squashable()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/cockroach/proc/make_squashable()
AddElement(/datum/element/squashable, squash_chance = 50, squash_damage = 1)
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 2ef13615e55..53ce73f5013 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -694,4 +694,7 @@
/mob/living/simple_animal/hostile/poison/giant_spider/viper/wizard
maxHealth = 80
health = 80
- ventcrawler = VENTCRAWLER_ALWAYS
+
+/mob/living/simple_animal/hostile/poison/giant_spider/viper/wizard/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
index c933901552f..850c9b6f974 100644
--- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm
+++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
@@ -20,10 +20,13 @@
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
speak_emote = list("squeaks")
- ventcrawler = VENTCRAWLER_ALWAYS
var/datum/mind/origin
var/egg_lain = 0
+/mob/living/simple_animal/hostile/headcrab/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/headcrab/proc/Infect(mob/living/carbon/victim)
var/obj/item/organ/body_egg/changeling_egg/egg = new(victim)
egg.Insert(victim)
diff --git a/code/modules/mob/living/simple_animal/hostile/killertomato.dm b/code/modules/mob/living/simple_animal/hostile/killertomato.dm
index db3373dba28..c43e8e916f1 100644
--- a/code/modules/mob/living/simple_animal/hostile/killertomato.dm
+++ b/code/modules/mob/living/simple_animal/hostile/killertomato.dm
@@ -22,10 +22,13 @@
attack_verb_continuous = "slams"
attack_verb_simple = "slam"
attack_sound = 'sound/weapons/punch1.ogg'
- ventcrawler = VENTCRAWLER_ALWAYS
faction = list("plants")
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 150
maxbodytemp = 500
gold_core_spawnable = HOSTILE_SPAWN
+
+/mob/living/simple_animal/hostile/killertomato/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 239a2375518..af2040c96a8 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -659,7 +659,6 @@
density = FALSE
is_flying_animal = TRUE
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
gold_core_spawnable = HOSTILE_SPAWN
verb_say = "warps"
@@ -686,6 +685,8 @@
var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
medsensor.add_hud_to(src)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/lightgeist/AttackingTarget()
if(isliving(target) && target != src)
var/mob/living/L = target
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
index 7eb185cffd3..b3e0cbdf8f1 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
@@ -27,7 +27,6 @@
friendly_verb_continuous = "pinches"
friendly_verb_simple = "pinch"
combat_mode = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
gold_core_spawnable = FRIENDLY_SPAWN
stat_attack = HARD_CRIT
gender = NEUTER
@@ -50,6 +49,8 @@
udder = new()
. = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/asteroid/gutlunch/CanAttack(atom/the_target) // Gutlunch-specific version of CanAttack to handle stupid stat_exclusive = true crap so we don't have to do it for literally every single simple_animal/hostile except the two that spawn in lavaland
if(isturf(the_target) || !the_target || the_target.type == /atom/movable/lighting_object) // bail out on invalids
return FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index 9b38f63ac72..7091c53bb4d 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -28,7 +28,6 @@
stat_attack = DEAD
mouse_opacity = MOUSE_OPACITY_ICON
speed = 1
- ventcrawler = VENTCRAWLER_ALWAYS
robust_searching = 1
unique_name = 1
speak_emote = list("squeaks")
@@ -66,6 +65,8 @@
health = maxHealth
. = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/mushroom/CanAttack(atom/the_target) // Mushroom-specific version of CanAttack to handle stupid attack_same = 2 crap so we don't have to do it for literally every single simple_animal/hostile because this shit never gets spawned
if(!the_target || isturf(the_target) || istype(the_target, /atom/movable/lighting_object))
return FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/ooze.dm b/code/modules/mob/living/simple_animal/hostile/ooze.dm
index f08a3365ad9..b7ebd6b74ef 100644
--- a/code/modules/mob/living/simple_animal/hostile/ooze.dm
+++ b/code/modules/mob/living/simple_animal/hostile/ooze.dm
@@ -7,7 +7,6 @@
icon_dead = "gelatinous_dead"
mob_biotypes = MOB_ORGANIC
pass_flags = PASSTABLE | PASSGRILLE
- ventcrawler = VENTCRAWLER_ALWAYS
gender = NEUTER
emote_see = list("jiggles", "bounces in place")
speak_emote = list("blorbles")
@@ -39,6 +38,8 @@
add_cell_sample()
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 0)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/ooze/attacked_by(obj/item/I, mob/living/user)
if(!check_edible(I))
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/regalrat.dm b/code/modules/mob/living/simple_animal/hostile/regalrat.dm
index 09e781cd168..b43b9e31584 100644
--- a/code/modules/mob/living/simple_animal/hostile/regalrat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/regalrat.dm
@@ -27,7 +27,6 @@
attack_verb_continuous = "slashes"
attack_verb_simple = "slash"
attack_sound = 'sound/weapons/punch1.ogg'
- ventcrawler = VENTCRAWLER_ALWAYS
unique_name = TRUE
faction = list("rat")
///The spell that the rat uses to scrounge up junk.
@@ -43,6 +42,8 @@
riot.Grant(src)
AddElement(/datum/element/waddling)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/regalrat/proc/get_player()
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Royal Rat, cheesey be his crown?", ROLE_SENTIENCE, null, FALSE, 100, POLL_IGNORE_SENTIENCE_POTION)
if(LAZYLEN(candidates) && !mind)
@@ -219,7 +220,6 @@
health = 15
butcher_results = list(/obj/item/food/meat/slab/mouse = 1)
density = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BEAST
@@ -229,6 +229,8 @@
. = ..()
SSmobs.cheeserats += src
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/rat/Destroy()
SSmobs.cheeserats -= src
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
index fa0967ff873..23e43baae15 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
@@ -26,7 +26,6 @@
attack_sound = 'sound/weapons/bite.ogg'
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
- ventcrawler = VENTCRAWLER_ALWAYS
mob_size = MOB_SIZE_TINY
is_flying_animal = TRUE
speak_emote = list("squeaks")
@@ -40,6 +39,7 @@
/mob/living/simple_animal/hostile/retaliate/bat/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
/mob/living/simple_animal/hostile/retaliate/bat/sgt_araneus //Despite being a bat for... reasons, this is now a spider, and is one of the HoS' pets.
name = "Sergeant Araneus"
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
index 8c265b08ed1..d7108653f79 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
@@ -124,7 +124,6 @@
emote_see = list("honks", "sweats", "jiggles", "contemplates its existence")
speak_chance = 5
dextrous = TRUE
- ventcrawler = VENTCRAWLER_ALWAYS
maxHealth = 140
health = 140
speed = -5
@@ -134,6 +133,10 @@
obj_damage = 5
loot = list(/obj/item/clothing/suit/hooded/bloated_human, /obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap)
+/mob/living/simple_animal/hostile/retaliate/clown/fleshclown/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/hostile/retaliate/clown/longface
name = "Longface"
desc = "Often found walking into the bar."
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
index bf049e69613..38f820f86d3 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
@@ -22,7 +22,6 @@
response_harm_continuous = "splats"
response_harm_simple = "splat"
density = FALSE
- ventcrawler = VENTCRAWLER_ALWAYS
faction = list("hostile")
attack_sound = 'sound/effects/reee.ogg'
butcher_results = list(/obj/item/food/nugget = 1)
@@ -33,6 +32,9 @@
/mob/living/simple_animal/hostile/retaliate/frog/Initialize()
. = ..()
+
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
if(prob(1))
name = "rare frog"
desc = "It seems a little smug."
diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm
index 1b2b51a494a..32c6e4a2895 100644
--- a/code/modules/mob/living/simple_animal/shade.dm
+++ b/code/modules/mob/living/simple_animal/shade.dm
@@ -34,11 +34,11 @@
loot = list(/obj/item/ectoplasm)
del_on_death = TRUE
initial_language_holder = /datum/language_holder/construct
- ventcrawler = VENTCRAWLER_ALWAYS
/mob/living/simple_animal/shade/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
/mob/living/simple_animal/shade/death()
if(deathmessage == initial(deathmessage))
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index fc0267c8048..bfb4df5a364 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -3,7 +3,6 @@
icon = 'icons/mob/slimes.dmi'
icon_state = "grey baby slime"
pass_flags = PASSTABLE | PASSGRILLE
- ventcrawler = VENTCRAWLER_ALWAYS
gender = NEUTER
var/is_adult = 0
var/docile = 0
@@ -105,6 +104,8 @@
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 0)
add_cell_sample()
+ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
+
/mob/living/simple_animal/slime/Destroy()
for (var/A in actions)
var/datum/action/AC = A
diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm
index a27e352fc15..49b4d12ec45 100644
--- a/code/modules/mob/living/ventcrawling.dm
+++ b/code/modules/mob/living/ventcrawling.dm
@@ -6,7 +6,9 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
//VENTCRAWLING
/mob/living/proc/handle_ventcrawl(atom/A)
- if(!ventcrawler || !Adjacent(A))
+ if(!Adjacent(A))
+ return
+ if(!HAS_TRAIT(src, TRAIT_VENTCRAWLER_NUDE) && !HAS_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS))
return
if(stat)
to_chat(src, "You must be conscious to do this!")
@@ -43,6 +45,8 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
if(vent_found)
break
+ // Being able to always ventcrawl trumps being only able to ventcrawl when wearing nothing
+ var/required_nudity = HAS_TRAIT(src, TRAIT_VENTCRAWLER_NUDE) && !HAS_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS)
if(vent_found)
var/datum/pipeline/vent_found_parent = vent_found.parents[1]
@@ -55,7 +59,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
if(!client)
return
- if(iscarbon(src) && ventcrawler == VENTCRAWLER_NUDE)
+ if(iscarbon(src) && required_nudity)
if(length(get_equipped_items(include_pockets = TRUE)) || get_num_held_items())
to_chat(src, "You can't crawl around in the ventilation ducts with items!")
return
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 6443a519f92..5cb7f7799fe 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -117,7 +117,8 @@
stuff_mob_in(target, user)
/obj/machinery/disposal/proc/stuff_mob_in(mob/living/target, mob/living/user)
- if(!iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves.
+ var/ventcrawler = HAS_TRAIT(user, TRAIT_VENTCRAWLER_ALWAYS) || HAS_TRAIT(user, TRAIT_VENTCRAWLER_NUDE)
+ if(!iscarbon(user) && !ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves.
if (iscyborg(user))
var/mob/living/silicon/robot/borg = user
if (!borg.model || !borg.model.canDispose)
diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm
index 3afa2fb88bf..674260d0546 100644
--- a/code/modules/spells/spell_types/shapeshift.dm
+++ b/code/modules/spells/spell_types/shapeshift.dm
@@ -53,28 +53,36 @@
M = Restore(M)
else
M = Shapeshift(M)
- if(M.movement_type & (VENTCRAWLING))
- if(!M.ventcrawler) //you're shapeshifting into something that can't fit into a vent
- var/obj/machinery/atmospherics/pipeyoudiein = M.loc
- var/datum/pipeline/ourpipeline
- var/pipenets = pipeyoudiein.returnPipenets()
- if(islist(pipenets))
- ourpipeline = pipenets[1]
- else
- ourpipeline = pipenets
+ // Are we currently ventcrawling?
+ if(!M.movement_type & (VENTCRAWLING))
+ return
- to_chat(M, "Casting [src] inside of [pipeyoudiein] quickly turns you into a bloody mush!")
- var/gibtype = /obj/effect/gibspawner/generic
- if(isalien(M))
- gibtype = /obj/effect/gibspawner/xeno
- for(var/obj/machinery/atmospherics/components/unary/possiblevent in range(10, get_turf(M)))
- if(possiblevent.parents.len && possiblevent.parents[1] == ourpipeline)
- new gibtype(get_turf(possiblevent))
- playsound(possiblevent, 'sound/effects/reee.ogg', 75, TRUE)
- priority_announce("We detected a pipe blockage around [get_area(get_turf(M))], please dispatch someone to investigate.", "Central Command")
- M.death()
- qdel(M)
- return
+ // Can our new form support ventcrawling?
+ var/ventcrawler = HAS_TRAIT(M, TRAIT_VENTCRAWLER_ALWAYS) || HAS_TRAIT(M, TRAIT_VENTCRAWLER_NUDE)
+ if(ventcrawler)
+ return
+
+ //you're shapeshifting into something that can't fit into a vent
+
+ var/obj/machinery/atmospherics/pipeyoudiein = M.loc
+ var/datum/pipeline/ourpipeline
+ var/pipenets = pipeyoudiein.returnPipenets()
+ if(islist(pipenets))
+ ourpipeline = pipenets[1]
+ else
+ ourpipeline = pipenets
+
+ to_chat(M, "Casting [src] inside of [pipeyoudiein] quickly turns you into a bloody mush!")
+ var/gibtype = /obj/effect/gibspawner/generic
+ if(isalien(M))
+ gibtype = /obj/effect/gibspawner/xeno
+ for(var/obj/machinery/atmospherics/components/unary/possiblevent in range(10, get_turf(M)))
+ if(possiblevent.parents.len && possiblevent.parents[1] == ourpipeline)
+ new gibtype(get_turf(possiblevent))
+ playsound(possiblevent, 'sound/effects/reee.ogg', 75, TRUE)
+ priority_announce("We detected a pipe blockage around [get_area(get_turf(M))], please dispatch someone to investigate.", "Central Command")
+ M.death()
+ qdel(M)
/**
* check_menu: Checks if we are allowed to interact with a radial menu