diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index f6888aabfba..c01ce110652 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -513,6 +513,10 @@ // from /client/proc/change_view() : (new_size) #define COMSIG_VIEW_SET "view_set" +/// Source: /mob/proc/ClickOn(atom/A, params) +#define COMSIG_MOB_PRE_UNARMED_ATTACK "mob_pre_unarmed_attack" + #define COMPONENT_CANCEL_UNARMED_ATTACK (1<<0) + // /mob/living signals ///from base of mob/living/resist() (/mob/living) @@ -1117,6 +1121,10 @@ ///from base of [/datum/element/light_eater/proc/devour]: (atom/eaten_light) #define COMSIG_LIGHT_EATER_DEVOUR "light_eater_devour" +// /datum/element/reagent_attack +/// Source: /datum/element/reagent_attack/proc/inject(atom/source, mob/living/carbon/target), sends ANYWAY +#define COMSIG_REAGENT_INJECTED "reagent_inject" + // datum/element/reagent_attack, mob/source, mob/living/carbon/target, reagent_id, reagent_amount, target_zone // /datum/element/movetype_handler signals /// Called when the floating anim has to be temporarily stopped and restarted later: (timer) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 05573f539c5..884ea1451b5 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -154,6 +154,8 @@ if(W) W.melee_attack_chain(src, A, params) else + if(SEND_SIGNAL(src, COMSIG_MOB_PRE_UNARMED_ATTACK, A, params) & COMPONENT_CANCEL_UNARMED_ATTACK) + return if(ismob(A)) changeNext_move(CLICK_CD_MELEE) UnarmedAttack(A, 1) @@ -171,6 +173,8 @@ if(W) W.melee_attack_chain(src, A, params) else + if(SEND_SIGNAL(src, COMSIG_MOB_PRE_UNARMED_ATTACK, A, params) & COMPONENT_CANCEL_UNARMED_ATTACK) + return if(ismob(A)) changeNext_move(CLICK_CD_MELEE) UnarmedAttack(A, 1) diff --git a/code/datums/elements/reagent_attack.dm b/code/datums/elements/reagent_attack.dm new file mode 100644 index 00000000000..9c924181dc3 --- /dev/null +++ b/code/datums/elements/reagent_attack.dm @@ -0,0 +1,74 @@ +/datum/element/reagent_attack + element_flags = ELEMENT_BESPOKE + id_arg_index = 2 + /// Which reagent we will inject + var/reagent_id + /// How much reagent we will inject + var/reagent_amount + /// Will we inject anyway or check can_inject + var/piercing + /// Limitation of our reagent in target + var/reagent_limit + /// Override zones over item or mob + var/allowed_zones + +/datum/element/reagent_attack/Attach(atom/source, reagent_id, reagent_amount, piercing, reagent_limit, list/allowed_zones) + . = ..() + + if(!isitem(source) || !ismob(source)) + return ELEMENT_INCOMPATIBLE + + src.reagent_id = reagent_id + src.reagent_amount = reagent_amount + src.piercing = piercing + src.reagent_limit = reagent_limit + src.allowed_zones = allowed_zones + + if(isitem(source)) + RegisterSignal(source, COMSIG_ITEM_ATTACK, PROC_REF(item_attack)) + + if(ismob(attaker)) + RegisterSignal(source, COMSIG_MOB_PRE_UNARMED_ATTACK, PROC_REF(mob_attack)) + +/datum/element/reagent_attack/Detach(atom/source) + . = ..() + + if(isitem(source)) + UnregisterSignal(source, COMSIG_ITEM_ATTACK) + + if(ismob(source)) + UnregisterSignal(source, COMSIG_MOB_PRE_UNARMED_ATTACK) + +/datum/element/reagent_attack/proc/item_attack(mob/target, mob/living/user, params, def_zone) + SIGNAL_HANDLER + + var/picked_zone = allowed_zones ? pick(allowed_zones) : def_zone + if(!can_inject(target, picked_zone)) + return + + INVOKE_ASYNC(src, PROC_REF(inject), user, target, picked_zone) + +/datum/element/reagent_attack/proc/mob_attack(mob/source, mob/target, params) + SIGNAL_HANDLER + + var/picked_zone = allowed_zones ? pick(allowed_zones) : source.zone_selected + if(!can_inject(target, picked_zone)) + return + + INVOKE_ASYNC(src, PROC_REF(inject), source, target, picked_zone) + +/datum/element/reagent_attack/proc/can_inject(mob/living/carbon/target, target_zone) + if(!istype(target)) + return FALSE + if(reagent_limit && target.reagents.has_reagent(reagent_id, reagent_limit)) + return FALSE + if(!piercing && !target.can_inject(null, FALSE, target_zone, FALSE)) + return FALSE + return TRUE + +/datum/element/reagent_attack/proc/inject(atom/source, mob/living/carbon/target, target_zone) + if(reagent_id && reagent_amount) + target.reagents.add_reagent(reagent_id, reagent_amount) + SEND_SIGNAL(source, COMSIG_REAGENT_INJECTED, source, target, reagent_id, reagent_amount, target_zone) // custom injections! + return + 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 01989df7e66..c550616d81c 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -39,20 +39,10 @@ talk_sound = list('sound/creatures/spider_talk1.ogg', 'sound/creatures/spider_talk2.ogg') damaged_sound = list('sound/creatures/spider_attack1.ogg', 'sound/creatures/spider_attack2.ogg') gold_core_spawnable = HOSTILE_SPAWN - var/venom_per_bite = 0 // While the /poison/ type path remains as-is for consistency reasons, we're really talking about venom, not poison. var/busy = 0 footstep_type = FOOTSTEP_MOB_CLAW AI_delay_max = 0.5 SECONDS -/mob/living/simple_animal/hostile/poison/giant_spider/AttackingTarget() - // This is placed here, NOT on /poison, because the other subtypes of /poison/ already override AttackingTarget() completely, and as such it would do nothing but confuse people there. - . = ..() - if(. && venom_per_bite > 0 && iscarbon(target) && (!client || a_intent == INTENT_HARM)) - var/mob/living/carbon/C = target - var/inject_target = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD) - if(C.can_inject(null, FALSE, inject_target, FALSE)) - C.reagents.add_reagent("spidertoxin", venom_per_bite) - /mob/living/simple_animal/hostile/poison/giant_spider/get_spacemove_backup(moving_direction, continuous_move) . = ..() // If we don't find any normal thing to use, attempt to use any nearby spider structure instead. @@ -72,10 +62,13 @@ health = 40 melee_damage_lower = 5 melee_damage_upper = 10 - venom_per_bite = 30 var/atom/cocoon_target var/fed = 0 +/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Initialize(mapload) + . = ..() + AddElement(/datum/element/reagent_attack, "spidertoxin", 30, FALSE, null, list(BODY_ZONE_CHEST, BODY_ZONE_HEAD)) + //hunters have the most poison and move the fastest, so they can find prey /mob/living/simple_animal/hostile/poison/giant_spider/hunter desc = "Furry and dark purple, it makes you shudder to look at it. This one has sparkling purple eyes." @@ -86,9 +79,11 @@ health = 120 melee_damage_lower = 10 melee_damage_upper = 20 - venom_per_bite = 10 move_to_delay = 5 +/mob/living/simple_animal/hostile/poison/giant_spider/hunter/Initialize(mapload) + . = ..() + AddElement(/datum/element/reagent_attack, "spidertoxin", 10, FALSE, null, list(BODY_ZONE_CHEST, BODY_ZONE_HEAD)) /mob/living/simple_animal/hostile/poison/giant_spider/handle_automated_movement() //Hacky and ugly. . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/widow.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/widow.dm index 0e5b72c0b2f..8091b000887 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/widow.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/widow.dm @@ -34,6 +34,23 @@ tts_seed = "Karastamper" spider_intro_text = "Будучи Вдовой Ужаса, ваша цель - внести хаос на поле боя при помощи своих плевков, вы также смертоносны вблизи и с каждым укусом вводите в противников опасный яд. Несмотря на скорость и смертоносность, вы довольно хрупки, поэтому не стоит атаковать тяжело вооружённых противников!" +/mob/living/simple_animal/hostile/poison/terror_spider/widow/Initialize(mapload) + . = ..() + AddElement(/datum/element/reagent_attack, "terror_black_toxin", null, FALSE, 100) + RegisterSignal(src, COMSIG_REAGENT_INJECTED, PROC_REF(on_inject)) + +/mob/living/simple_animal/hostile/poison/terror_spider/widow/proc/on_inject(datum/source, mob/source, mob/living/carbon/target, reagent_id, reagent_amount, target_zone) + SIGNAL_HANDLER + + if(HAS_TRAIT(target, TRAIT_INCAPACITATED)) + target.reagents.add_reagent("terror_black_toxin", 33) // inject our special poison + visible_message(span_danger("[src] buries its long fangs deep into the [target_zone] of [target]!")) + return + + target.reagents.add_reagent("terror_black_toxin", 20) + visible_message(span_danger("[src] pierces armour and buries its long fangs deep into the [target_zone] of [target]!")) + return + /mob/living/simple_animal/hostile/poison/terror_spider/widow/spider_specialattack(mob/living/carbon/human/L, poisonable) . = ..() if(!.) @@ -41,15 +58,6 @@ L.AdjustSilence(10 SECONDS) if(!poisonable) return TRUE - if(L.reagents.has_reagent("terror_black_toxin", 100)) - return TRUE - var/inject_target = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD) - if(HAS_TRAIT(L, TRAIT_INCAPACITATED) || L.can_inject(null, FALSE, inject_target, FALSE)) - L.reagents.add_reagent("terror_black_toxin", 33) // inject our special poison - visible_message(span_danger("[src] buries its long fangs deep into the [inject_target] of [target]!")) - else - L.reagents.add_reagent("terror_black_toxin", 20) - visible_message(span_danger("[src] pierces armour and buries its long fangs deep into the [inject_target] of [target]!")) if(!ckey && (!(target in enemies) || L.reagents.has_reagent("terror_black_toxin", 60))) step_away(src, L) step_away(src, L) diff --git a/paradise.dme b/paradise.dme index 01a9f271ec1..d0f9836ee64 100644 --- a/paradise.dme +++ b/paradise.dme @@ -534,6 +534,7 @@ #include "code\datums\elements\connect_loc.dm" #include "code\datums\elements\falling_hazard.dm" #include "code\datums\elements\footstep.dm" +#include "code\datums\elements\reagent_attack.dm" #include "code\datums\elements\give_turf_traits.dm" #include "code\datums\elements\light_blocking.dm" #include "code\datums\elements\movetype_handler.dm"