diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 7caf7b32229..f032c3f4f12 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -341,6 +341,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_DEL_ON_SPACE_DUMP "del_on_hyperspace_leave" /// We can walk up or around cliffs, or at least we don't fall off of it #define TRAIT_CLIFF_WALKER "cliff_walker" +/// This means the user is currently holding/wearing a "tactical camouflage" item (like a potted plant). +#define TRAIT_TACTICALLY_CAMOUFLAGED "tactically_camouflaged" /// Gets double arcade prizes #define TRAIT_GAMERGOD "gamer-god" #define TRAIT_GIANT "giant" @@ -632,6 +634,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Used by the honkspam element to avoid spamming the sound. Amusing considering its name. #define TRAIT_HONKSPAMMING "trait_honkspamming" +/// Required by the waddling element since there are multiple sources of it. +#define TRAIT_WADDLING "trait_waddling" ///Used for managing KEEP_TOGETHER in [/atom/var/appearance_flags] #define TRAIT_KEEP_TOGETHER "keep-together" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 1f944f8629e..3cb993fa399 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -64,6 +64,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_UNIQUE_IMMERSE" = TRAIT_UNIQUE_IMMERSE, "TRAIT_VOIDSTORM_IMMUNE" = TRAIT_VOIDSTORM_IMMUNE, "TRAIT_WAS_RENAMED" = TRAIT_WAS_RENAMED, + "TRAIT_WADDLING" = TRAIT_WADDLING, "TRAIT_WEATHER_IMMUNE" = TRAIT_WEATHER_IMMUNE, "TRAIT_CHASM_STOPPER" = TRAIT_CHASM_STOPPER, ), @@ -449,6 +450,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_TACKLING_FRAIL_ATTACKER" = TRAIT_TACKLING_FRAIL_ATTACKER, "TRAIT_TACKLING_TAILED_DEFENDER" = TRAIT_TACKLING_TAILED_DEFENDER, "TRAIT_TACKLING_WINGED_ATTACKER" = TRAIT_TACKLING_WINGED_ATTACKER, + "TRAIT_TACTICALLY_CAMOUFLAGED" = TRAIT_TACTICALLY_CAMOUFLAGED, "TRAIT_TAGGER" = TRAIT_TAGGER, "TRAIT_TEMPORARY_BODY" = TRAIT_TEMPORARY_BODY, "TRAIT_TENACIOUS" = TRAIT_TENACIOUS, diff --git a/code/datums/ai/objects/vending_machines/vending_machine_controller.dm b/code/datums/ai/objects/vending_machines/vending_machine_controller.dm index cd779b7d691..50523db946c 100644 --- a/code/datums/ai/objects/vending_machines/vending_machine_controller.dm +++ b/code/datums/ai/objects/vending_machines/vending_machine_controller.dm @@ -14,7 +14,7 @@ return AI_CONTROLLER_INCOMPATIBLE var/obj/machinery/vending/vendor_pawn = new_pawn vendor_pawn.tiltable = FALSE //Not manually tiltable by hitting it anymore. We are now aggressively doing it ourselves. - vendor_pawn.AddElement(/datum/element/waddling) + vendor_pawn.AddElementTrait(TRAIT_WADDLING, REF(src), /datum/element/waddling) vendor_pawn.AddElement(/datum/element/footstep, FOOTSTEP_OBJ_MACHINE, 1, -6, sound_vary = TRUE) vendor_pawn.squish_damage = 15 return ..() //Run parent at end @@ -22,7 +22,7 @@ /datum/ai_controller/vending_machine/UnpossessPawn(destroy) var/obj/machinery/vending/vendor_pawn = pawn vendor_pawn.tiltable = TRUE - vendor_pawn.RemoveElement(/datum/element/waddling) + REMOVE_TRAIT(vendor_pawn, TRAIT_WADDLING, REF(src)) vendor_pawn.squish_damage = initial(vendor_pawn.squish_damage) RemoveElement(/datum/element/footstep, FOOTSTEP_OBJ_MACHINE, 1, -6, sound_vary = TRUE) return ..() //Run parent at end diff --git a/code/datums/components/tactical.dm b/code/datums/components/tactical.dm index e8e54926949..e0f131258e7 100644 --- a/code/datums/components/tactical.dm +++ b/code/datums/components/tactical.dm @@ -1,5 +1,8 @@ +///A simple component that replacess the user's appearance with that of the parent item when equipped. /datum/component/tactical + ///The allowed slot(s) for the effect. var/allowed_slot + ///A cached of where the item is currently equipped. var/current_slot /datum/component/tactical/Initialize(allowed_slot) @@ -11,50 +14,63 @@ /datum/component/tactical/RegisterWithParent() RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(modify)) RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(unmodify)) + RegisterSignal(parent, COMSIG_ATOM_UPDATED_ICON, PROC_REF(tactical_update)) + var/obj/item/item = parent + if(ismob(item.loc)) + var/mob/holder = item.loc + modify(item, holder, holder.get_slot_by_item(item)) /datum/component/tactical/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED)) + UnregisterSignal(parent, list( + COMSIG_ITEM_EQUIPPED, + COMSIG_ITEM_DROPPED, + COMSIG_ATOM_UPDATED_ICON, + )) unmodify() /datum/component/tactical/Destroy() unmodify() return ..() -/datum/component/tactical/proc/on_z_move(datum/source) - SIGNAL_HANDLER - var/obj/item/master = parent - if(!ismob(master.loc)) - return - var/old_slot = current_slot - unmodify(master, master.loc) - modify(master, master.loc, old_slot) - /datum/component/tactical/proc/modify(obj/item/source, mob/user, slot) SIGNAL_HANDLER if(allowed_slot && !(slot & allowed_slot)) - unmodify() + if(current_slot) + unmodify(source, user) return + if(current_slot) //If the current slot is set, this means the icon was updated or the item changed z-levels. + user.remove_alt_appearance("sneaking_mission[REF(src)]") + else + RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(tactical_update)) + current_slot = slot var/obj/item/master = parent - var/image/I = image(icon = master.icon, icon_state = master.icon_state, loc = user) - I.copy_overlays(master) - I.override = TRUE - source.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission", I) - I.layer = ABOVE_MOB_LAYER - RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_z_move)) + var/image/image = image(master, loc = user) + image.copy_overlays(master) + image.override = TRUE + image.layer = ABOVE_MOB_LAYER + image.plane = FLOAT_PLANE + source.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission[REF(src)]", image) /datum/component/tactical/proc/unmodify(obj/item/source, mob/user) SIGNAL_HANDLER - var/obj/item/master = source || parent + var/obj/item/master = parent if(!user) if(!ismob(master.loc)) return user = master.loc - user.remove_alt_appearance("sneaking_mission") + user.remove_alt_appearance("sneaking_mission[REF(src)]") current_slot = null UnregisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED) + +/datum/component/tactical/proc/tactical_update(datum/source) + SIGNAL_HANDLER + var/obj/item/master = parent + if(!ismob(master.loc)) + return + modify(master, master.loc, current_slot) diff --git a/code/datums/elements/_element.dm b/code/datums/elements/_element.dm index bcafc83497c..b2e021ad2be 100644 --- a/code/datums/elements/_element.dm +++ b/code/datums/elements/_element.dm @@ -28,7 +28,7 @@ if(element_flags & ELEMENT_DETACH_ON_HOST_DESTROY) RegisterSignal(target, COMSIG_QDELETING, PROC_REF(OnTargetDelete), override = TRUE) -/datum/element/proc/OnTargetDelete(datum/source, force) +/datum/element/proc/OnTargetDelete(datum/source) SIGNAL_HANDLER Detach(source) @@ -75,3 +75,29 @@ ele.Detach(arglist(arguments)) else ele.Detach(src) + +/** + * Used to manage (typically non_bespoke) elements with multiple sources through traits + * so we don't have to make them a components again. + * The element will be later removed once all trait sources are gone, there's no need of a + * "RemoveElementTrait" counterpart. + */ +/datum/proc/AddElementTrait(trait, source, datum/element/eletype, ...) + if(!ispath(eletype, /datum/element)) + CRASH("AddElementTrait called, but [eletype] is not of a /datum/element path") + ADD_TRAIT(src, trait, source) + if(HAS_TRAIT_NOT_FROM(src, trait, source)) + return + var/list/arguments = list(eletype) + /// 3 is the length of fixed args of this proc, any further one is passed down to AddElement. + if(length(args) > 3) + arguments += args.Copy(4) + /// We actually pass down a copy of the arguments since it's manipulated by the end of the proc. + _AddElement(arguments.Copy()) + var/datum/ele = SSdcs.GetElement(arguments) + ele.RegisterSignal(src, SIGNAL_REMOVETRAIT(trait), TYPE_PROC_REF(/datum/element, _detach_on_trait_removed)) + +/datum/element/proc/_detach_on_trait_removed(datum/source, trait) + SIGNAL_HANDLER + Detach(source) + UnregisterSignal(source, SIGNAL_REMOVETRAIT(trait)) diff --git a/code/datums/elements/waddling.dm b/code/datums/elements/waddling.dm index c51a1759768..e63d0329bb6 100644 --- a/code/datums/elements/waddling.dm +++ b/code/datums/elements/waddling.dm @@ -4,6 +4,8 @@ . = ..() if(!ismovable(target)) return ELEMENT_INCOMPATIBLE + if(!HAS_TRAIT(target, TRAIT_WADDLING)) + stack_trace("[type] added to [target] without adding TRAIT_WADDLING first. Please use AddElementTrait instead.") RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(Waddle)) /datum/element/waddling/Detach(datum/source) diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index f58ea90211d..97f9c29491e 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -14,11 +14,19 @@ var/deceptive = FALSE /// What cutout datum we spawn at the start? Uses the name, not the path. var/starting_cutout + /// Reference to the tactical component that should be deleted when the cutout is toppled. + var/datum/component/tactical/tacticool /obj/item/cardboard_cutout/Initialize(mapload) . = ..() if(starting_cutout) return INITIALIZE_HINT_LATELOAD + if(!pushed_over) + AddComponent(/datum/component/tactical) + +/obj/item/cardboard_cutout/Destroy() + tacticool = null + return ..() /obj/item/cardboard_cutout/LateInitialize() ASSERT(!isnull(starting_cutout)) @@ -33,6 +41,8 @@ ASSERT(!isnull(cutout), "No cutout found with name [starting_cutout]") cutout.apply(src) + if(!pushed_over) + tacticool = AddComponent(/datum/component/tactical) //ATTACK HAND IGNORING PARENT RETURN VALUE /obj/item/cardboard_cutout/attack_hand(mob/living/user, list/modifiers) @@ -42,12 +52,22 @@ playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) push_over() +/obj/item/cardboard_cutout/equipped(mob/living/user, slot) + . = ..() + //Because of the tactical element, the user won't tilt left and right, but it'll still hop. + user.AddElementTrait(TRAIT_WADDLING, REF(src), /datum/element/waddling) + +/obj/item/cardboard_cutout/dropped(mob/living/user) + . = ..() + REMOVE_TRAIT(user, TRAIT_WADDLING, REF(src)) + /obj/item/cardboard_cutout/proc/push_over() appearance = initial(appearance) desc = "[initial(desc)] It's been pushed over." icon_state = "cutout_pushed_over" remove_atom_colour(FIXED_COLOUR_PRIORITY) pushed_over = TRUE + QDEL_NULL(tacticool) /obj/item/cardboard_cutout/attack_self(mob/living/user) if(!pushed_over) @@ -57,6 +77,7 @@ icon = initial(icon) icon_state = initial(icon_state) //This resets a cutout to its blank state - this is intentional to allow for resetting pushed_over = FALSE + tacticool = AddComponent(/datum/component/tactical) /obj/item/cardboard_cutout/attackby(obj/item/I, mob/living/user, params) if(istype(I, /obj/item/toy/crayon)) @@ -100,7 +121,7 @@ for (var/datum/cardboard_cutout/cutout_subtype as anything in subtypesof(/datum/cardboard_cutout)) var/datum/cardboard_cutout/cutout = get_cardboard_cutout_instance(cutout_subtype) appearances_by_name[cutout.name] = cutout - possible_appearances[cutout.name] = image(icon = cutout.applied_appearance) + possible_appearances[cutout.name] = image(icon = cutout.preview_appearance) var/new_appearance = show_radial_menu(user, src, possible_appearances, custom_check = CALLBACK(src, PROC_REF(check_menu), user, crayon), radius = 36, require_near = TRUE) if(!new_appearance) @@ -144,19 +165,16 @@ return FALSE return TRUE -// Cutouts always face forward -/obj/item/cardboard_cutout/setDir(newdir) - SHOULD_CALL_PARENT(FALSE) - return - /obj/item/cardboard_cutout/adaptive //Purchased by Syndicate agents, these cutouts are indistinguishable from normal cutouts but aren't discolored when their appearance is changed deceptive = TRUE /datum/cardboard_cutout /// Name of the cutout, used for radial selection and the global list. var/name = "Boardjak" - /// The appearance we apply to the cardboard cutout. - var/mutable_appearance/applied_appearance = null + /// The appearance of the cardboard cutout that we show in the radial menu. + var/mutable_appearance/preview_appearance + /// A flat appearance, with only one direction, that we apply to the cardboard cutout. + var/image/applied_appearance /// The base name we actually give to to the cardboard cutout. Can be overridden in get_name(). var/applied_name = "boardjak" /// The desc we give to the cardboard cutout. @@ -179,9 +197,9 @@ /datum/cardboard_cutout/New() . = ..() if(direct_icon) - applied_appearance = mutable_appearance(direct_icon, direct_icon_state) + preview_appearance = mutable_appearance(direct_icon, direct_icon_state) else - applied_appearance = get_dynamic_human_appearance(outfit, species, mob_spawner, l_hand, r_hand, animated = FALSE) + preview_appearance = get_dynamic_human_appearance(outfit, species, mob_spawner, l_hand, r_hand, animated = FALSE) /// This proc returns the name that the cardboard cutout item will use. /datum/cardboard_cutout/proc/get_name() @@ -189,9 +207,14 @@ /// This proc sets the cardboard cutout item's vars. /datum/cardboard_cutout/proc/apply(obj/item/cardboard_cutout/cutouts) + if(isnull(applied_appearance)) + applied_appearance = image(fcopy_rsc(getFlatIcon(preview_appearance, no_anim = TRUE))) + applied_appearance.plane = cutouts.plane + applied_appearance.layer = cutouts.layer cutouts.appearance = applied_appearance cutouts.name = get_name() cutouts.desc = applied_desc + cutouts.update_appearance() //forces an update on the tactical comp's appearance. /datum/cardboard_cutout/assistant name = "Assistant" diff --git a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm index 31600b03354..514ab36ed66 100644 --- a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm +++ b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm @@ -404,7 +404,7 @@ . = ..() if (!.) return - owner.AddElement(/datum/element/waddling) + owner.AddElementTrait(TRAIT_WADDLING, TRAIT_STATUS_EFFECT(id), /datum/element/waddling) ADD_TRAIT(owner, TRAIT_NO_SLIP_WATER, TRAIT_STATUS_EFFECT(id)) slipperiness = owner.AddComponent(\ /datum/component/slippery,\ @@ -418,8 +418,7 @@ return owner.body_position == LYING_DOWN /datum/status_effect/golem/bananium/on_remove() - REMOVE_TRAIT(owner, TRAIT_NO_SLIP_WATER, TRAIT_STATUS_EFFECT(id)) - owner.RemoveElement(/datum/element/waddling) + owner.remove_traits(owner, list(TRAIT_WADDLING, TRAIT_NO_SLIP_WATER), TRAIT_STATUS_EFFECT(id)) QDEL_NULL(slipperiness) return ..() diff --git a/code/modules/clothing/shoes/clown.dm b/code/modules/clothing/shoes/clown.dm index 37270f47f6c..d8d4d56fdc2 100644 --- a/code/modules/clothing/shoes/clown.dm +++ b/code/modules/clothing/shoes/clown.dm @@ -20,13 +20,13 @@ . = ..() if(slot & ITEM_SLOT_FEET) if(enabled_waddle) - user.AddElement(/datum/element/waddling) + user.AddElementTrait(TRAIT_WADDLING, SHOES_TRAIT, /datum/element/waddling) if(is_clown_job(user.mind?.assigned_role)) user.add_mood_event("clownshoes", /datum/mood_event/clownshoes) /obj/item/clothing/shoes/clown_shoes/dropped(mob/living/user) . = ..() - user.RemoveElement(/datum/element/waddling) + REMOVE_TRAIT(user, TRAIT_WADDLING, SHOES_TRAIT) if(is_clown_job(user.mind?.assigned_role)) user.clear_mood_event("clownshoes") diff --git a/code/modules/clothing/shoes/costume.dm b/code/modules/clothing/shoes/costume.dm index 1a3e9b0b2be..1e15f25e1f6 100644 --- a/code/modules/clothing/shoes/costume.dm +++ b/code/modules/clothing/shoes/costume.dm @@ -128,8 +128,8 @@ /obj/item/clothing/shoes/ducky_shoes/equipped(mob/living/user, slot) . = ..() if(slot & ITEM_SLOT_FEET) - user.AddElement(/datum/element/waddling) + user.AddElementTrait(TRAIT_WADDLING, SHOES_TRAIT, /datum/element/waddling) /obj/item/clothing/shoes/ducky_shoes/dropped(mob/living/user) . = ..() - user.RemoveElement(/datum/element/waddling) + REMOVE_TRAIT(user, TRAIT_WADDLING, SHOES_TRAIT) diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index 1a713ec04f8..88c2b9496a9 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -49,7 +49,7 @@ ai_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, emotes) //im not putting dynamic humans or whatever its called here because this is the base path of nonhuman clownstrosities if(waddles) - AddElement(/datum/element/waddling) + AddElementTrait(TRAIT_WADDLING, INNATE_TRAIT, /datum/element/waddling) if(length(loot)) loot = string_list(loot) AddElement(/datum/element/death_drops, loot) diff --git a/code/modules/mob/living/basic/farm_animals/pony.dm b/code/modules/mob/living/basic/farm_animals/pony.dm index df8f3a1fd4e..7795ec630e6 100644 --- a/code/modules/mob/living/basic/farm_animals/pony.dm +++ b/code/modules/mob/living/basic/farm_animals/pony.dm @@ -40,7 +40,7 @@ AddElement(/datum/element/pet_bonus, "whickers.") AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/ai_flee_while_injured) - AddElement(/datum/element/waddling) + AddElementTrait(TRAIT_WADDLING, INNATE_TRAIT, /datum/element/waddling) AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/apple), tame_chance = 25, bonus_tame_chance = 15, after_tame = CALLBACK(src, PROC_REF(tamed)), unique = unique_tamer) /mob/living/basic/pony/proc/tamed(mob/living/tamer) diff --git a/code/modules/mob/living/basic/pets/penguin.dm b/code/modules/mob/living/basic/pets/penguin.dm index 671c2cf30c1..e8e2a038c0e 100644 --- a/code/modules/mob/living/basic/pets/penguin.dm +++ b/code/modules/mob/living/basic/pets/penguin.dm @@ -23,7 +23,7 @@ AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/ai_flee_while_injured) AddElement(/datum/element/pet_bonus, "honks happily!") - AddElement(/datum/element/waddling) + AddElementTrait(TRAIT_WADDLING, INNATE_TRAIT, /datum/element/waddling) if(!can_lay_eggs) return AddComponent(\ diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm index 3602d5e8a99..be83d3e058f 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm @@ -52,7 +52,7 @@ RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) RegisterSignal(src, COMSIG_MOB_LOGIN, PROC_REF(on_login)) - AddElement(/datum/element/waddling) + AddElementTrait(TRAIT_WADDLING, INNATE_TRAIT, /datum/element/waddling) AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/door_pryer, pry_time = 5 SECONDS, interaction_key = REGALRAT_INTERACTION) AddComponent(\ diff --git a/code/modules/mod/modules/modules_service.dm b/code/modules/mod/modules/modules_service.dm index 5381a26e88b..e6e4a01c664 100644 --- a/code/modules/mod/modules/modules_service.dm +++ b/code/modules/mod/modules/modules_service.dm @@ -70,13 +70,13 @@ /obj/item/mod/module/waddle/on_suit_activation() mod.boots.AddComponent(/datum/component/squeak, list('sound/effects/footstep/clownstep1.ogg'=1,'sound/effects/footstep/clownstep2.ogg'=1), 50, falloff_exponent = 20) //die off quick please - mod.wearer.AddElement(/datum/element/waddling) + mod.wearer.AddElementTrait(TRAIT_WADDLING, MOD_TRAIT, /datum/element/waddling) if(is_clown_job(mod.wearer.mind?.assigned_role)) mod.wearer.add_mood_event("clownshoes", /datum/mood_event/clownshoes) /obj/item/mod/module/waddle/on_suit_deactivation(deleting = FALSE) if(!deleting) qdel(mod.boots.GetComponent(/datum/component/squeak)) - mod.wearer.RemoveElement(/datum/element/waddling) + REMOVE_TRAIT(mod.wearer, TRAIT_WADDLING, MOD_TRAIT) if(is_clown_job(mod.wearer.mind?.assigned_role)) mod.wearer.clear_mood_event("clownshoes") diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm index d0255d5a060..76d8751dc5d 100644 --- a/code/modules/surgery/organs/internal/ears/_ears.dm +++ b/code/modules/surgery/organs/internal/ears/_ears.dm @@ -93,15 +93,13 @@ /obj/item/organ/internal/ears/penguin/on_mob_insert(mob/living/carbon/human/ear_owner) . = ..() - if(istype(ear_owner)) - to_chat(ear_owner, span_notice("You suddenly feel like you've lost your balance.")) - ear_owner.AddElement(/datum/element/waddling) + to_chat(ear_owner, span_notice("You suddenly feel like you've lost your balance.")) + ear_owner.AddElementTrait(TRAIT_WADDLING, ORGAN_TRAIT, /datum/element/waddling) /obj/item/organ/internal/ears/penguin/on_mob_remove(mob/living/carbon/human/ear_owner) . = ..() - if(istype(ear_owner)) - to_chat(ear_owner, span_notice("Your sense of balance comes back to you.")) - ear_owner.RemoveElement(/datum/element/waddling) + to_chat(ear_owner, span_notice("Your sense of balance comes back to you.")) + REMOVE_TRAIT(ear_owner, TRAIT_WADDLING, ORGAN_TRAIT) /obj/item/organ/internal/ears/cybernetic name = "basic cybernetic ears" diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index 032a054a77c..37f6eb7efa5 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -179,7 +179,7 @@ to_chat(user, span_danger("You scramble [src]'s child safety lock, and a panel with six colorful buttons appears!")) initialize_controller_action_type(/datum/action/vehicle/sealed/roll_the_dice, VEHICLE_CONTROL_DRIVE) initialize_controller_action_type(/datum/action/vehicle/sealed/cannon, VEHICLE_CONTROL_DRIVE) - AddElement(/datum/element/waddling) + AddElementTrait(TRAIT_WADDLING, INNATE_TRAIT, /datum/element/waddling) return TRUE /obj/vehicle/sealed/car/clowncar/atom_destruction(damage_flag)