From 4e1eb514b5a75a24a475a48afb3f8de5f3d7bace Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Wed, 15 Oct 2025 04:49:11 +0200 Subject: [PATCH] Flash and flasher refactor/rework (simple mobs no longer immune edition) (#93076) Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com> --- .../signals/signals_mob/signals_mob_main.dm | 8 +- .../components/can_flash_from_behind.dm | 4 +- code/game/machinery/flasher.dm | 17 +- code/modules/antagonists/brother/brother.dm | 8 +- .../antagonists/revolution/revolution.dm | 10 +- .../sentient_creature/sentient_creature.dm | 5 + code/modules/assembly/flash.dm | 169 ++++++++++-------- code/modules/mob/living/basic/drone/_drone.dm | 3 + code/modules/mob/living/carbon/carbon.dm | 12 -- code/modules/mob/living/living_defense.dm | 12 ++ .../mob/living/silicon/silicon_defense.dm | 3 + .../hostile/mining_mobs/elites/elite.dm | 40 +++-- 12 files changed, 164 insertions(+), 127 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index 6117c1c55d0..cabe8a2fcab 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -226,12 +226,12 @@ ///from living/flash_act(), when a mob is successfully flashed. #define COMSIG_MOB_FLASHED "mob_flashed" -/// from /obj/item/assembly/flash/flash_carbon, to the mob being flashed +/// from /obj/item/assembly/flash/flash_mob, to the mob being flashed #define COMSIG_MOB_FLASH_OVERRIDE_CHECK "mob_flash_override_check" /// Has the flash effect been overridden? #define FLASH_OVERRIDDEN (1<<0) /// from /obj/item/assembly/flash/flash_carbon, to the mob flashing another carbon -#define COMSIG_MOB_PRE_FLASHED_CARBON "mob_pre_flashed_carbon" +#define COMSIG_MOB_PRE_FLASHED_MOB "mob_pre_flashed_mob" /// Return to override deviation to be full deviation (fail the flash, usually) #define DEVIATION_OVERRIDE_FULL (1<<0) /// Return to override deviation to be partial deviation @@ -240,9 +240,9 @@ #define DEVIATION_OVERRIDE_NONE (1<<2) /// Return to stop the flash entirely #define STOP_FLASH (1<<3) -/// from /obj/item/assembly/flash/flash_carbon, to the mob flashing another carbon +/// from /obj/item/assembly/flash/flash_mob, to the mob flashing another carbon /// (mob/living/carbon/flashed, obj/item/assembly/flash/flash, deviation (from code/__DEFINES/mobs.dm)) -#define COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON "mob_success_flashed_carbon" +#define COMSIG_MOB_SUCCESSFUL_FLASHED_MOB "mob_success_flashed_mob" /// from mob/get_status_tab_items(): (list/items) #define COMSIG_MOB_GET_STATUS_TAB_ITEMS "mob_get_status_tab_items" diff --git a/code/datums/components/can_flash_from_behind.dm b/code/datums/components/can_flash_from_behind.dm index c443d160dfb..f375df20c98 100644 --- a/code/datums/components/can_flash_from_behind.dm +++ b/code/datums/components/can_flash_from_behind.dm @@ -10,10 +10,10 @@ return COMPONENT_INCOMPATIBLE /datum/component/can_flash_from_behind/RegisterWithParent() - RegisterSignal(parent, COMSIG_MOB_PRE_FLASHED_CARBON, PROC_REF(on_pre_flashed_carbon)) + RegisterSignal(parent, COMSIG_MOB_PRE_FLASHED_MOB, PROC_REF(on_pre_flashed_carbon)) /datum/component/can_flash_from_behind/UnregisterFromParent() - UnregisterSignal(parent, COMSIG_MOB_PRE_FLASHED_CARBON) + UnregisterSignal(parent, COMSIG_MOB_PRE_FLASHED_MOB) /datum/component/can_flash_from_behind/proc/on_pre_flashed_carbon(source, flashed, flash, deviation) SIGNAL_HANDLER diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 1d98eb41bcd..2fb6efb9d4b 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -16,7 +16,7 @@ var/flash_range = 2 //this is roughly the size of a brig cell. /// How strong Paralyze()'d targets are when flashed. - var/strength = 10 SECONDS + var/strength = 5 SECONDS COOLDOWN_DECLARE(flash_cooldown) /// Duration of time between flashes. @@ -120,8 +120,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/flasher, 26) if (get_dist(src, living_mob) > flash_range) continue - if(living_mob.flash_act(affect_silicon = TRUE)) - living_mob.log_message("was AOE flashed by an automated portable flasher", LOG_ATTACK) + if(bulb.flash_mob(living_mob, confusion_duration = strength * 1.5, extra_log = "by [src]")) living_mob.Paralyze(strength) flashed = TRUE @@ -161,7 +160,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/flasher, 26) icon = 'icons/obj/machines/sec.dmi' icon_state = "pflash1-p" base_icon_state = "pflash" - strength = 8 SECONDS + strength = 4 SECONDS anchored = FALSE density = TRUE ///Proximity monitor associated with this atom, needed for proximity checks. @@ -175,10 +174,12 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/flasher, 26) if(!COOLDOWN_FINISHED(src, flash_cooldown)) return - if(iscarbon(proximity_check_mob)) - var/mob/living/carbon/proximity_carbon = proximity_check_mob - if (proximity_carbon.move_intent != MOVE_INTENT_WALK && anchored) - flash() + if(!isliving(proximity_check_mob)) + return + + var/mob/living/proximity_living = proximity_check_mob + if (proximity_living.move_intent != MOVE_INTENT_WALK && anchored) + flash() /obj/machinery/flasher/portable/vv_edit_var(vname, vval) . = ..() diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 334dbf246fc..a20da754d4e 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -54,7 +54,7 @@ if (!istype(carbon_owner)) return carbon_owner.AddComponentFrom(REF(src), /datum/component/can_flash_from_behind) - RegisterSignal(carbon_owner, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON, PROC_REF(on_mob_successful_flashed_carbon)) + RegisterSignal(carbon_owner, COMSIG_MOB_SUCCESSFUL_FLASHED_MOB, PROC_REF(on_mob_successful_flashed_mob)) /// Take away the ability to add more brothers /datum/antagonist/brother/proc/remove_conversion_skills() @@ -62,12 +62,12 @@ return var/mob/living/carbon/carbon_owner = owner.current carbon_owner.RemoveComponentSource(REF(src), /datum/component/can_flash_from_behind) - UnregisterSignal(carbon_owner, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON) + UnregisterSignal(carbon_owner, COMSIG_MOB_SUCCESSFUL_FLASHED_MOB) -/datum/antagonist/brother/proc/on_mob_successful_flashed_carbon(mob/living/source, mob/living/carbon/flashed, obj/item/assembly/flash/flash) +/datum/antagonist/brother/proc/on_mob_successful_flashed_mob(mob/living/source, mob/living/flashed, obj/item/assembly/flash/flash) SIGNAL_HANDLER - if (flashed.stat == DEAD) + if (flashed.stat == DEAD || issilicon(flashed) || isdrone(flashed)) return if (flashed.stat != CONSCIOUS) diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index 5f538904073..94e5f0c0484 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -180,20 +180,20 @@ . = ..() var/mob/living/real_mob = mob_override || owner.current real_mob.AddComponentFrom(REF(src), /datum/component/can_flash_from_behind) - RegisterSignal(real_mob, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON, PROC_REF(on_flash_success)) + RegisterSignal(real_mob, COMSIG_MOB_SUCCESSFUL_FLASHED_MOB, PROC_REF(on_flash_success)) /datum/antagonist/rev/head/remove_innate_effects(mob/living/mob_override) . = ..() var/mob/living/real_mob = mob_override || owner.current real_mob.RemoveComponentSource(REF(src), /datum/component/can_flash_from_behind) - UnregisterSignal(real_mob, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON) + UnregisterSignal(real_mob, COMSIG_MOB_SUCCESSFUL_FLASHED_MOB) -/// Signal proc for [COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON]. +/// Signal proc for [COMSIG_MOB_SUCCESSFUL_FLASHED_MOB]. /// Bread and butter of revolution conversion, successfully flashing a carbon will make them a revolutionary -/datum/antagonist/rev/head/proc/on_flash_success(mob/living/source, mob/living/carbon/flashed, obj/item/assembly/flash/flash, deviation) +/datum/antagonist/rev/head/proc/on_flash_success(mob/living/source, mob/living/flashed, obj/item/assembly/flash/flash, deviation) SIGNAL_HANDLER - if(flashed.stat == DEAD) + if(flashed.stat == DEAD || issilicon(flashed) || isdrone(flashed)) return if(flashed.stat != CONSCIOUS) to_chat(source, span_warning("[flashed.p_They()] must be conscious before you can convert [flashed.p_them()]!")) diff --git a/code/modules/antagonists/sentient_creature/sentient_creature.dm b/code/modules/antagonists/sentient_creature/sentient_creature.dm index 48b149574f9..b2035471c46 100644 --- a/code/modules/antagonists/sentient_creature/sentient_creature.dm +++ b/code/modules/antagonists/sentient_creature/sentient_creature.dm @@ -23,6 +23,11 @@ var/mob/living/master = owner.enslaved_to?.resolve() if(master) owner.current.copy_languages(master, LANGUAGE_MASTER) + ADD_TRAIT(owner, TRAIT_UNCONVERTABLE, REF(src)) + return ..() + +/datum/antagonist/sentient_creature/on_removal() + REMOVE_TRAIT(owner, TRAIT_UNCONVERTABLE, REF(src)) return ..() /datum/antagonist/sentient_creature/ui_static_data(mob/user) diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index 8c8900cb025..bc28b4146ea 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -62,7 +62,7 @@ /obj/item/assembly/flash/proc/clown_check(mob/living/carbon/human/user) if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) - flash_carbon(user, user, confusion_duration = 15 SECONDS, targeted = FALSE) + flash_mob(user, user, confusion_duration = 15 SECONDS, targeted = FALSE) return FALSE return TRUE @@ -91,8 +91,8 @@ if(user) targets -= user to_chat(user, span_danger("[src] emits a blinding light!")) - for(var/mob/living/carbon/nearby_carbon in targets) - flash_carbon(nearby_carbon, user, confusion_duration, targeted = FALSE, generic_message = TRUE) + for(var/mob/living/nearby_living in targets) + flash_mob(nearby_living, user, confusion_duration, targeted = FALSE, generic_message = TRUE) return TRUE /obj/item/assembly/flash/proc/get_flash_targets(atom/target_loc, range = 3, override_vision_checks = FALSE) @@ -136,13 +136,13 @@ * * targeted - determines if it was aoe or targeted * * generic_message - checks if it should display default message. */ -/obj/item/assembly/flash/proc/flash_carbon(mob/living/carbon/flashed, mob/user, confusion_duration = 15 SECONDS, targeted = TRUE, generic_message = FALSE) +/obj/item/assembly/flash/proc/flash_mob(mob/living/flashed, mob/user, confusion_duration = 15 SECONDS, targeted = TRUE, generic_message = FALSE, extra_log = null) if(!istype(flashed)) - return + return FALSE if(user) - log_combat(user, flashed, "[targeted? "flashed(targeted)" : "flashed(AOE)"]", src) + log_combat(user, flashed, "[targeted? "flashed(targeted)" : "flashed(AOE)"] [extra_log]", src) else //caused by emp/remote signal - flashed.log_message("was [targeted? "flashed(targeted)" : "flashed(AOE)"]", LOG_ATTACK) + flashed.log_message("was [targeted? "flashed(targeted)" : "flashed(AOE)"] [extra_log]", LOG_ATTACK) if(generic_message && flashed != user) to_chat(flashed, span_danger("[src] emits a blinding light!")) @@ -150,9 +150,9 @@ var/deviation = calculate_deviation(flashed, user || src) if(user) - var/sigreturn = SEND_SIGNAL(user, COMSIG_MOB_PRE_FLASHED_CARBON, flashed, src, deviation) + var/sigreturn = SEND_SIGNAL(user, COMSIG_MOB_PRE_FLASHED_MOB, flashed, src, deviation) if(sigreturn & STOP_FLASH) - return + return FALSE if(sigreturn & DEVIATION_OVERRIDE_FULL) deviation = DEVIATION_FULL @@ -163,28 +163,50 @@ //If you face away from someone they shouldn't notice any effects. if(deviation == DEVIATION_FULL) - return + return FALSE - if(targeted) - var/flash_result = flashed.flash_act(1, 1) - if(flash_result == FLASH_COMPLETED) - return //Behavior was overwritten, so we just skip the flashy stunny part and go with the override behavior instead + var/flash_result = flashed.flash_act(1, override_blindness_check = targeted, affect_silicon = TRUE) + if(!flash_result) + if(targeted) + if(user) + visible_message(span_warning("[user] fails to blind [flashed] with the flash!"), span_danger("[user] fails to blind you with the flash!")) + else + to_chat(flashed, span_danger("[src] fails to blind you!")) + return FALSE - if(flash_result) - flashed.set_confusion_if_lower(confusion_duration * CONFUSION_STACK_MAX_MULTIPLIER) - visible_message(span_danger("[user] blinds [flashed] with the flash!"), span_userdanger("[user] blinds you with the flash!")) + flashed.adjust_confusion_up_to(confusion_duration, confusion_duration * CONFUSION_STACK_MAX_MULTIPLIER) + + if(!targeted) + return TRUE + + if(flash_result != FLASH_COMPLETED) //If the behavior was overwritten, we just skip the flashy stunny part and go with the override behavior instead + if(issilicon(flashed)) + if(flashed.is_blind()) + var/flash_duration = rand(8,12) SECONDS + flashed.Paralyze(flash_duration) + flashed.set_temp_blindness_if_lower(flash_duration) + if(user) + user.visible_message(span_warning("[user] overloads [flashed]'s sensors and computing with the flash!"), span_danger("You overload [flashed]'s sensors and computing with the flash!")) + else + to_chat(flashed, "[src] overloads your sensors and computing!") + else + flashed.set_temp_blindness_if_lower( (rand(5,15) SECONDS)) + if(user) + user.visible_message(span_warning("[user] blinds [flashed] with the flash!"), span_danger("You blind [flashed] with the flash!")) + else + to_chat(flashed, "you're blinded by [src]!") + else //easy way to make sure that you can only long stun someone who is facing in your direction flashed.adjustStaminaLoss(rand(80, 120) * (1 - (deviation * 0.5))) flashed.Knockdown(rand(25, 50) * (1 - (deviation * 0.5))) - SEND_SIGNAL(user, COMSIG_MOB_SUCCESSFUL_FLASHED_CARBON, flashed, src, deviation) + if(user) + visible_message(span_danger("[user] blinds [flashed] with the flash!"), span_userdanger("[user] blinds you with the flash!")) + else + to_chat(flashed, "you're blinded by [src]!") - else if(user) - visible_message(span_warning("[user] fails to blind [flashed] with the flash!"), span_danger("[user] fails to blind you with the flash!")) - else - to_chat(flashed, span_danger("[src] fails to blind you!")) - else - if(flashed.flash_act()) - flashed.set_confusion_if_lower(confusion_duration * CONFUSION_STACK_MAX_MULTIPLIER) + if(user) + SEND_SIGNAL(user, COMSIG_MOB_SUCCESSFUL_FLASHED_MOB, flashed, src, deviation) + return TRUE /** * Handles the directionality of the attack @@ -201,18 +223,24 @@ if(HAS_TRAIT(victim, TRAIT_SPINNING)) return DEVIATION_NONE + // I don't want to mess with cyborgs' deep-rooted weakness to flashes + if(issilicon(victim)) + return DEVIATION_NONE + if(iscarbon(victim)) var/mob/living/carbon/carbon_victim = victim if(carbon_victim.get_eye_protection() < FLASH_PROTECTION_SENSITIVE) // If we have really bad flash sensitivity, usually due to really sensitive eyes, we get flashed from all directions return DEVIATION_NONE + var/turf/attacker_turf = get_turf(attacker) + // Are they on the same tile? We'll return partial deviation. This may be someone flashing while lying down // or flashing someone they're stood on the same turf as, or a borg flashing someone buckled to them. - if(victim.loc == attacker.loc) + if(victim.loc == attacker_turf) return DEVIATION_PARTIAL // If the victim was looking at the attacker, this is the direction they'd have to be facing. - var/victim_to_attacker = get_dir(victim, attacker) + var/victim_to_attacker = get_dir(victim, attacker_turf) // The victim's dir is necessarily a cardinal value. var/victim_dir = victim.dir @@ -241,29 +269,15 @@ return FALSE . = TRUE - if(iscarbon(M)) - flash_carbon(M, user, confusion_duration = 5 SECONDS, targeted = TRUE) - return - if(issilicon(M)) - var/mob/living/silicon/robot/flashed_borgo = M - log_combat(user, flashed_borgo, "flashed", src) - update_icon(ALL, TRUE) - if(flashed_borgo.flash_act(affect_silicon = TRUE)) - if(flashed_borgo.is_blind()) - var/flash_duration = rand(8,12) SECONDS - flashed_borgo.Paralyze(flash_duration) - flashed_borgo.set_temp_blindness_if_lower(flash_duration) - user.visible_message(span_warning("[user] overloads [flashed_borgo]'s sensors and computing with the flash!"), span_danger("You overload [flashed_borgo]'s sensors and computing with the flash!")) - else - user.visible_message(span_warning("[user] blinds [flashed_borgo] with the flash!"), span_danger("You blind [flashed_borgo] with the flash!")) - flashed_borgo.set_temp_blindness_if_lower( (rand(5,15) SECONDS)) - flashed_borgo.set_confusion_if_lower(5 SECONDS * CONFUSION_STACK_MAX_MULTIPLIER) - else - user.visible_message(span_warning("[user] fails to blind [flashed_borgo] with the flash!"), span_warning("You fail to blind [flashed_borgo] with the flash!")) + if(!issilicon(M)) + flash_mob(M, user, confusion_duration = 5 SECONDS, targeted = TRUE) return + flash_silicon(M, user) user.visible_message(span_warning("[user] fails to blind [M] with the flash!"), span_warning("You fail to blind [M] with the flash!")) +/obj/item/assembly/flash/proc/flash_silicon(mob/living/silicon/silicon) + /obj/item/assembly/flash/attack_self(mob/living/carbon/user, flag = 0, emp = 0) if(holder) return FALSE @@ -354,42 +368,43 @@ /obj/item/assembly/flash/hypnotic/burn_out() return -/obj/item/assembly/flash/hypnotic/flash_carbon(mob/living/carbon/M, mob/user, confusion_duration = 15, targeted = TRUE, generic_message = FALSE) - if(!istype(M)) - return +/obj/item/assembly/flash/hypnotic/flash_mob(mob/living/flashed, mob/user, confusion_duration = 5 SECONDS, targeted = TRUE, generic_message = FALSE, extra_log = null) if(user) - log_combat(user, M, "[targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"]", src) + log_combat(user, flashed, "[targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"] [extra_log]", src) else //caused by emp/remote signal - M.log_message("was [targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"]", LOG_ATTACK) - if(generic_message && M != user) - to_chat(M, span_notice("[src] emits a soothing light...")) - if(targeted) - if(M.flash_act(1, 1)) - var/hypnosis = FALSE - if(M.hypnosis_vulnerable()) - hypnosis = TRUE + flashed.log_message("was [targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"] [extra_log]", LOG_ATTACK) + + if(generic_message && flashed != user) + to_chat(flashed, span_notice("[src] emits a soothing light...")) + + if(!flashed.flash_act(1, override_blindness_check = targeted, affect_silicon = TRUE)) + if(targeted) if(user) - user.visible_message(span_danger("[user] blinds [M] with the flash!"), span_danger("You hypno-flash [M]!")) - - if(!hypnosis) - to_chat(M, span_hypnophrase("The light makes you feel oddly relaxed...")) - M.adjust_confusion_up_to(10 SECONDS, 20 SECONDS) - M.adjust_dizzy_up_to(20 SECONDS, 40 SECONDS) - M.adjust_drowsiness_up_to(20 SECONDS, 40 SECONDS) - M.adjust_pacifism(10 SECONDS) + user.visible_message(span_warning("[user] fails to blind [flashed] with the flash!"), span_warning("You fail to hypno-flash [flashed]!")) else - M.apply_status_effect(/datum/status_effect/trance, 200, TRUE) + to_chat(flashed, span_danger("[src] fails to blind you!")) + return FALSE - else if(user) - user.visible_message(span_warning("[user] fails to blind [M] with the flash!"), span_warning("You fail to hypno-flash [M]!")) - else - to_chat(M, span_danger("[src] fails to blind you!")) + if(!targeted) + to_chat(flashed, span_notice("Such a pretty light...")) + flashed.adjust_confusion_up_to(confusion_duration, confusion_duration * 2 * CONFUSION_STACK_MAX_MULTIPLIER) + flashed.adjust_dizzy_up_to(8 SECONDS, 40 SECONDS) + flashed.adjust_drowsiness_up_to(8 SECONDS, 40 SECONDS) + flashed.adjust_pacifism(4 SECONDS) + return TRUE - else if(M.flash_act()) - to_chat(M, span_notice("Such a pretty light...")) - M.adjust_confusion_up_to(4 SECONDS, 20 SECONDS) - M.adjust_dizzy_up_to(8 SECONDS, 40 SECONDS) - M.adjust_drowsiness_up_to(8 SECONDS, 40 SECONDS) - M.adjust_pacifism(4 SECONDS) + if(user) + user.visible_message(span_danger("[user] blinds [flashed] with the flash!"), span_danger("You hypno-flash [flashed]!")) + else + to_chat(flashed, "You're blinded by [src]!") + + if(!flashed.hypnosis_vulnerable()) + to_chat(flashed, span_hypnophrase("The light makes you feel oddly relaxed...")) + flashed.adjust_confusion_up_to(confusion_duration * 2, confusion_duration * 2 * CONFUSION_STACK_MAX_MULTIPLIER) + flashed.adjust_dizzy_up_to(20 SECONDS, 40 SECONDS) + flashed.adjust_drowsiness_up_to(20 SECONDS, 40 SECONDS) + flashed.adjust_pacifism(10 SECONDS) + else + flashed.apply_status_effect(/datum/status_effect/trance, 200, TRUE) #undef CONFUSION_STACK_MAX_MULTIPLIER diff --git a/code/modules/mob/living/basic/drone/_drone.dm b/code/modules/mob/living/basic/drone/_drone.dm index 6ddaea0e51a..10d7ccc442a 100644 --- a/code/modules/mob/living/basic/drone/_drone.dm +++ b/code/modules/mob/living/basic/drone/_drone.dm @@ -295,3 +295,6 @@ if(built_in_camera?.can_use()) return TRUE return ..() + +/mob/living/basic/drone/hypnosis_vulnerable() + return FALSE //It obeys its laws diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 004dbedb06a..250e41f0e1a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1077,18 +1077,6 @@ /mob/living/carbon/can_resist() return bodyparts.len > 2 && ..() -/mob/living/carbon/proc/hypnosis_vulnerable() - if(HAS_MIND_TRAIT(src, TRAIT_UNCONVERTABLE)) - return FALSE - if(has_status_effect(/datum/status_effect/hallucination) || has_status_effect(/datum/status_effect/drugginess)) - return TRUE - if(IsSleeping() || IsUnconscious()) - return TRUE - if(HAS_TRAIT(src, TRAIT_DUMB)) - return TRUE - if(mob_mood.sanity < SANITY_UNSTABLE) - return TRUE - /mob/living/carbon/wash(clean_types) . = ..() // Wash equipped stuff that cannot be covered diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 8dcb36fec8a..3496ffabf3e 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -823,3 +823,15 @@ return SUCCESSFUL_BLOCK return FAILED_BLOCK + +/mob/living/proc/hypnosis_vulnerable() + if(HAS_MIND_TRAIT(src, TRAIT_UNCONVERTABLE)) + return FALSE + if(has_status_effect(/datum/status_effect/hallucination) || has_status_effect(/datum/status_effect/drugginess)) + return TRUE + if(IsSleeping() || IsUnconscious()) + return TRUE + if(HAS_TRAIT(src, TRAIT_DUMB)) + return TRUE + if(mob_mood && mob_mood.sanity < SANITY_UNSTABLE) + return TRUE diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index 6fb367dc223..25cdc81fda8 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -159,3 +159,6 @@ apply_status_effect(/datum/status_effect/borg_slow, damage_done / 60) #undef CYBORG_SLOWDOWN_THRESHOLD + +/mob/living/silicon/hypnosis_vulnerable() + return FALSE //It obeys its laws diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index e105ab56cd1..e796781cf4c 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -2,6 +2,9 @@ #define TUMOR_ACTIVE 1 #define TUMOR_PASSIVE 2 +// Makes the elite mob weaker on victory so they don't just go and trash the station with a dangerous, big health pool +#define ELITE_POST_BATTLE_HEALTH_MULTIPLIER 0.4 + //Elite mining mobs /mob/living/simple_animal/hostile/asteroid/elite name = "elite" @@ -30,6 +33,7 @@ . = ..() AddComponent(/datum/component/seethrough_mob) grant_actions_by_list(attack_action_types) + ADD_TRAIT(src, TRAIT_UNCONVERTABLE, INNATE_TRAIT) //You cannot convert them while they're battling. //Prevents elites from attacking members of their faction (can't hurt themselves either) and lets them mine rock with an attack despite not being able to smash walls. /mob/living/simple_animal/hostile/asteroid/elite/AttackingTarget(atom/attacked_target) @@ -226,7 +230,7 @@ While using this makes the system rely on OnFire, it still gives options for tim playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE) mychild.revive(HEAL_ALL) if(boosted) - mychild.maxHealth = mychild.maxHealth * 2 + mychild.maxHealth *= 1 / ELITE_POST_BATTLE_HEALTH_MULTIPLIER //we multiply it back to its original value mychild.health = mychild.maxHealth notify_ghosts( "\A [mychild] has been challenged in \the [get_area(src)]!", @@ -235,6 +239,7 @@ While using this makes the system rely on OnFire, it still gives options for tim notify_flags = NOTIFY_CATEGORY_NOFLASH, ) mychild.log_message("has been challenged by [key_name(activator)]!", LOG_GAME, color="#960000") + ADD_TRAIT(mychild, TRAIT_UNCONVERTABLE, INNATE_TRAIT) /obj/structure/elite_tumor/Initialize(mapload) . = ..() @@ -344,7 +349,7 @@ While using this makes the system rely on OnFire, it still gives options for tim mychild.revive(HEAL_ALL) if(boosted) times_won++ - mychild.maxHealth = mychild.maxHealth * 0.4 + mychild.maxHealth *= ELITE_POST_BATTLE_HEALTH_MULTIPLIER mychild.health = mychild.maxHealth if(times_won == 1) mychild.playsound_local(get_turf(mychild), 'sound/effects/magic.ogg', 40, 0) @@ -356,6 +361,8 @@ While using this makes the system rely on OnFire, it still gives options for tim Also, be weary of your fellow inhabitants, they likely won't be happy to see you!") to_chat(mychild, span_boldbig("Note that you are a lavaland monster, and thus not allied to the station. You should not cooperate or act friendly with any station crew unless under extreme circumstances!")) + REMOVE_TRAIT(mychild, TRAIT_UNCONVERTABLE, INNATE_TRAIT) + /obj/item/tumor_shard name = "tumor shard" desc = "A strange, sharp, crystal shard from an odd tumor on Lavaland. Stabbing the corpse of a lavaland elite with this will revive them, assuming their soul still lingers. Revived lavaland elites only have half their max health, but are completely loyal to their reviver." @@ -373,20 +380,21 @@ While using this makes the system rely on OnFire, it still gives options for tim if(!istype(interacting_with, /mob/living/simple_animal/hostile/asteroid/elite)) return NONE - var/mob/living/simple_animal/hostile/asteroid/elite/E = interacting_with - if(E.stat != DEAD || E.sentience_type != SENTIENCE_BOSS || !E.key) - user.visible_message(span_notice("It appears [E] is unable to be revived right now. Perhaps try again later.")) + var/mob/living/simple_animal/hostile/asteroid/elite/elite = interacting_with + if(elite.stat != DEAD || elite.sentience_type != SENTIENCE_BOSS || !elite.key) + user.visible_message(span_notice("It appears [elite] is unable to be revived right now. Perhaps try again later.")) return ITEM_INTERACT_BLOCKING - E.faction = list("[REF(user)]") - E.revive(HEAL_ALL) - user.visible_message(span_notice("[user] stabs [E] with [src], reviving it.")) - E.playsound_local(get_turf(E), 'sound/effects/magic.ogg', 40, 0) - to_chat(E, span_userdanger("You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.")) - to_chat(E, span_boldbig("Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!")) - E.maxHealth = E.maxHealth * 0.4 - E.health = E.maxHealth - E.desc = "[E.desc] However, this one appears to be less wild in nature, and calmer around people." - E.sentience_type = SENTIENCE_ORGANIC + elite.faction = list("[REF(user)]") + elite.revive(HEAL_ALL) + user.visible_message(span_notice("[user] stabs [elite] with [src], reviving it.")) + elite.playsound_local(get_turf(elite), 'sound/effects/magic.ogg', 40, 0) + to_chat(elite, span_userdanger("You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.")) + to_chat(elite, span_boldbig("Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!")) + elite.maxHealth *= ELITE_POST_BATTLE_HEALTH_MULTIPLIER + elite.health = elite.maxHealth + elite.desc = "[elite.desc] However, this one appears to be less wild in nature, and calmer around people." + elite.sentience_type = SENTIENCE_ORGANIC + REMOVE_TRAIT(elite, TRAIT_UNCONVERTABLE, INNATE_TRAIT) qdel(src) return ITEM_INTERACT_SUCCESS @@ -423,6 +431,8 @@ While using this makes the system rely on OnFire, it still gives options for tim if(mover == ourelite_ref.resolve() || mover == activator_ref.resolve()) return FALSE +#undef ELITE_POST_BATTLE_HEALTH_MULTIPLIER + #undef TUMOR_ACTIVE #undef TUMOR_INACTIVE #undef TUMOR_PASSIVE