diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 3f535278a7569..45b08e2fcb258 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1005,4 +1005,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait given when a mob is currently in invisimin mode #define TRAIT_INVISIMIN "invisimin" +///Trait given when a mob has been tipped +#define TRAIT_MOB_TIPPED "mob_tipped" + // END TRAIT DEFINES diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 06745be77c501..946924883c033 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -269,6 +269,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_MIND_TEMPORARILY_GONE" = TRAIT_MIND_TEMPORARILY_GONE, "TRAIT_MINDSHIELD" = TRAIT_MINDSHIELD, "TRAIT_MOB_BREEDER" = TRAIT_MOB_BREEDER, + "TRAIT_MOB_TIPPED" = TRAIT_MOB_TIPPED, "TRAIT_MORBID" = TRAIT_MORBID, "TRAIT_MULTIZ_SUIT_SENSORS" = TRAIT_MULTIZ_SUIT_SENSORS, "TRAIT_MUSICIAN" = TRAIT_MUSICIAN, diff --git a/code/datums/components/tippable.dm b/code/datums/components/tippable.dm index ee1f2c4054739..fa2ac331ce13a 100644 --- a/code/datums/components/tippable.dm +++ b/code/datums/components/tippable.dm @@ -231,10 +231,11 @@ is_tipped = new_status if(is_tipped) tipped_mob.transform = turn(tipped_mob.transform, 180) - ADD_TRAIT(tipped_mob, TRAIT_IMMOBILIZED, TIPPED_OVER) - else - tipped_mob.transform = turn(tipped_mob.transform, -180) - REMOVE_TRAIT(tipped_mob, TRAIT_IMMOBILIZED, TIPPED_OVER) + tipped_mob.add_traits(list(TRAIT_MOB_TIPPED, TRAIT_IMMOBILIZED), TIPPED_OVER) + return + + tipped_mob.transform = turn(tipped_mob.transform, -180) + tipped_mob.remove_traits(list(TRAIT_MOB_TIPPED, TRAIT_IMMOBILIZED), TIPPED_OVER) /** * Accepts "roleplay" in the form of emotes, which removes a quarter of the remaining time left to untip ourself. diff --git a/code/datums/elements/hat_wearer.dm b/code/datums/elements/hat_wearer.dm index 75fc6a6c67785..504a93f688ea6 100644 --- a/code/datums/elements/hat_wearer.dm +++ b/code/datums/elements/hat_wearer.dm @@ -6,16 +6,24 @@ argument_hash_start_idx = 2 ///offsets of hats we will wear var/list/offsets + ///signals to remove the hat on + var/list/remove_hat_signals + ///traits we check before adding the hat + var/traits_prevent_checks -/datum/element/hat_wearer/Attach(datum/target, offsets = list()) +/datum/element/hat_wearer/Attach(datum/target, offsets = list(), remove_hat_signals = list(), traits_prevent_checks = list()) . = ..() if (!isliving(target)) return ELEMENT_INCOMPATIBLE src.offsets = offsets + src.traits_prevent_checks = traits_prevent_checks RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_overlays_updated)) RegisterSignal(target, COMSIG_ATOM_EXITED, PROC_REF(exited)) RegisterSignal(target, COMSIG_ATOM_ENTERED, PROC_REF(on_entered)) RegisterSignal(target, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attack_by)) + if(!length(remove_hat_signals)) + return + RegisterSignals(target, remove_hat_signals, PROC_REF(remove_hat)) /datum/element/hat_wearer/Detach(datum/target) var/obj/item/hat = (locate(/obj/item/clothing/head) in target) @@ -27,6 +35,8 @@ COMSIG_ATOM_ENTERED, COMSIG_ATOM_ATTACKBY, )) + if(length(remove_hat_signals)) + UnregisterSignal(target, remove_hat_signals) return ..() /datum/element/hat_wearer/proc/on_overlays_updated(atom/source, list/overlays) @@ -60,8 +70,15 @@ /datum/element/hat_wearer/proc/on_attack_by(atom/movable/source, obj/item/item, mob/living/attacker) SIGNAL_HANDLER + if(!istype(item, /obj/item/clothing/head)) return + + for(var/trait_check in traits_prevent_checks) + if(HAS_TRAIT(source, trait_check)) + source.balloon_alert(attacker, "not possible right now!") + return COMPONENT_NO_AFTERATTACK + INVOKE_ASYNC(src, PROC_REF(place_hat), source, item, attacker) return COMPONENT_NO_AFTERATTACK @@ -70,3 +87,11 @@ source.balloon_alert(attacker, "must stay still!") return item.forceMove(source) + +/datum/element/hat_wearer/proc/remove_hat(atom/movable/source) + SIGNAL_HANDLER + + var/obj/our_hat = locate(/obj/item/clothing/head) in source + if(isnull(our_hat)) + return + our_hat.forceMove(source.drop_location()) diff --git a/code/modules/mob/living/basic/bots/_bots.dm b/code/modules/mob/living/basic/bots/_bots.dm index ba7b1b417a2cf..4db1a52432e3d 100644 --- a/code/modules/mob/living/basic/bots/_bots.dm +++ b/code/modules/mob/living/basic/bots/_bots.dm @@ -735,11 +735,16 @@ GLOBAL_LIST_INIT(command_strings, list( . = ..() if(!. || isnull(client)) return FALSE + REMOVE_TRAIT(src, TRAIT_NO_GLIDE, INNATE_TRAIT) + speed = 2 + diag_hud_set_botmode() /mob/living/basic/bot/Logout() . = ..() bot_reset() + speed = initial(speed) + ADD_TRAIT(src, TRAIT_NO_GLIDE, INNATE_TRAIT) /mob/living/basic/bot/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE) . = ..() diff --git a/code/modules/mob/living/basic/bots/medbot/medbot.dm b/code/modules/mob/living/basic/bots/medbot/medbot.dm index 0c50a2187ff63..af040a7d11046 100644 --- a/code/modules/mob/living/basic/bots/medbot/medbot.dm +++ b/code/modules/mob/living/basic/bots/medbot/medbot.dm @@ -135,10 +135,17 @@ pre_tipped_callback = CALLBACK(src, PROC_REF(pre_tip_over)), \ post_tipped_callback = CALLBACK(src, PROC_REF(after_tip_over)), \ post_untipped_callback = CALLBACK(src, PROC_REF(after_righted))) + var/static/list/hat_offsets = list(4,-9) - AddElement(/datum/element/hat_wearer, offsets = hat_offsets) - RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) + var/static/list/remove_hat = list(SIGNAL_ADDTRAIT(TRAIT_MOB_TIPPED)) + var/static/list/prevent_checks = list(TRAIT_MOB_TIPPED) + AddElement(/datum/element/hat_wearer,\ + offsets = hat_offsets,\ + remove_hat_signals = remove_hat,\ + traits_prevent_checks = prevent_checks,\ + ) + RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) if(!HAS_TRAIT(SSstation, STATION_TRAIT_MEDBOT_MANIA) || !mapload || !is_station_level(z)) return skin = "advanced" @@ -162,10 +169,11 @@ if(HAS_TRAIT(src, TRAIT_INCAPACITATED)) icon_state = "[base_icon_state]a" return + var/stationary_mode = !!(medical_mode_flags & MEDBOT_STATIONARY_MODE) if(mode == BOT_HEALING) - icon_state = "[base_icon_state]s[medical_mode_flags & MEDBOT_STATIONARY_MODE]" + icon_state = "[base_icon_state]s[stationary_mode]" return - icon_state = "[base_icon_state][medical_mode_flags & MEDBOT_STATIONARY_MODE ? 2 : 1]" //Bot has yellow light to indicate stationary mode. + icon_state = "[base_icon_state][stationary_mode ? 2 : 1]" //Bot has yellow light to indicate stationary mode. /mob/living/basic/bot/medbot/update_overlays() . = ..() @@ -278,6 +286,12 @@ if(prob(10)) speak("PSYCH ALERT: Crewmember [user.name] recorded displaying antisocial tendencies torturing bots in [get_area(src)]. Please schedule psych evaluation.", radio_channel) +/mob/living/basic/bot/medbot/explode() + var/atom/our_loc = drop_location() + drop_part(medkit_type, our_loc) + drop_part(health_analyzer, our_loc) + return ..() + /* * Proc used in a callback for after this medibot is righted, either by themselves or by a mob, by the tippable component. * @@ -320,7 +334,7 @@ return var/modified_heal_amount = heal_amount var/done_healing = FALSE - if(damage_type_healer == BRUTE && medkit_type == /obj/item/storage/medkit/brute) + if(damage_type_healer == BRUTE && medkit_type == /obj/item/storage/medkit/brute) modified_heal_amount *= 1.1 if(bot_access_flags & BOT_COVER_EMAGGED) patient.reagents?.add_reagent(/datum/reagent/toxin/chloralhydrate, 5) @@ -335,12 +349,12 @@ log_combat(src, patient, "tended the wounds of", "internal tools") if(patient.get_current_damage_of_type(damage_type_healer) <= heal_threshold) done_healing = TRUE + patient.visible_message(span_notice("[src] tends the wounds of [patient]!"), "[span_infoplain(span_green("[src] tends your wounds!"))]") - //Go into idle only when we're done + update_bot_mode(new_mode = BOT_IDLE) if(done_healing) visible_message(span_infoplain("[src] places its tools back into itself.")) to_chat(src, "[patient] is now healthy!") - update_bot_mode(new_mode = BOT_IDLE) //If player-controlled, call them to heal again here for continous player healing else if(!isnull(client)) melee_attack(patient)