mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-25 05:51:56 +01:00
Projectile refactoring madness (#19878)
Refactored the projectile code, mostly in line with TG's now. Refactored various procs that are used or depends on it. Projectiles can now ricochet if enabled to. Damage falloffs with distance. Homing projectiles can now have accuracy falloff with distance. Projectiles have a maximum range. Muzzle flash is configurable per projectile. Impact effect of the projectile is configurable per projectile. Accuracy decreases with distance. Projectiles work with signals and emits them, for easy hooking up from other parts of the code. Meatshielding is now less effective . Impact sound is now configurable per projectile. High risk.
This commit is contained in:
@@ -184,6 +184,8 @@ note dizziness decrements automatically in the mob's Life() proc.
|
||||
|
||||
// either attack_item OR attack_image should be used. if both are used, attack_image will be the one chosen
|
||||
/mob/do_attack_animation(atom/A, var/atom/attack_item, var/image/attack_image)
|
||||
set waitfor = FALSE
|
||||
|
||||
var/initial_pixel_x = get_standard_pixel_x()
|
||||
var/initial_pixel_y = get_standard_pixel_y()
|
||||
..(A, attack_item, attack_image, initial_pixel_x, initial_pixel_y)
|
||||
|
||||
@@ -28,28 +28,48 @@
|
||||
sleeping = 0
|
||||
willfully_sleeping = FALSE
|
||||
|
||||
/mob/living/carbon/bullet_act(var/obj/projectile/P, var/def_zone)
|
||||
..(P, def_zone)
|
||||
var/show_ssd
|
||||
/mob/living/carbon/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
//Carbon have blood, so when hit with sufficient force, they bleed; this shows the effect of bleeding when hit by a projectile
|
||||
if(hitting_projectile.damage_type == DAMAGE_BRUTE && hitting_projectile.damage > 5) //weak hits shouldn't make you gush blood
|
||||
var/splatter_color = COLOR_HUMAN_BLOOD
|
||||
if (src.species && src.get_blood_color())
|
||||
splatter_color = src.get_blood_color()
|
||||
|
||||
var/splatter_dir = hitting_projectile.starting ? get_dir(hitting_projectile.starting, get_turf(src)) : dir
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(get_turf(src), splatter_dir, splatter_color)
|
||||
|
||||
var/mob/living/carbon/human/H
|
||||
if(ishuman(src))
|
||||
H = src
|
||||
show_ssd = H.species.show_ssd
|
||||
if(H && show_ssd && !client && !teleop)
|
||||
if(H.bg)
|
||||
visible_message(SPAN_DANGER("[P] hit [src] waking [get_pronoun("him")] up!"))
|
||||
if(H.health / H.maxHealth < 0.5)
|
||||
H.bg.awaken_impl(TRUE)
|
||||
sleeping = 0
|
||||
willfully_sleeping = FALSE
|
||||
else
|
||||
to_chat(H, SPAN_DANGER("You sense great disturbance to your physical body!"))
|
||||
else if(!vr_mob)
|
||||
visible_message(SPAN_DANGER("[P] hit [src], but they do not respond... Maybe they have S.S.D?"))
|
||||
else if(client && willfully_sleeping)
|
||||
visible_message(SPAN_DANGER("[P] hit [src] waking [get_pronoun("him")] up!"))
|
||||
sleeping = 0
|
||||
willfully_sleeping = FALSE
|
||||
|
||||
if(hitting_projectile.damage > 0)
|
||||
if(H && H.species.show_ssd && !client && !teleop)
|
||||
if(H.bg)
|
||||
if(!hitting_projectile.do_not_log)
|
||||
visible_message(SPAN_DANGER("[hitting_projectile] hit [src] waking [get_pronoun("him")] up!"))
|
||||
|
||||
if(H.health / H.maxHealth < 0.5)
|
||||
H.bg.awaken_impl(TRUE)
|
||||
sleeping = 0
|
||||
willfully_sleeping = FALSE
|
||||
else
|
||||
if(!hitting_projectile.do_not_log)
|
||||
to_chat(H, SPAN_DANGER("You sense great disturbance to your physical body!"))
|
||||
|
||||
else if(!vr_mob)
|
||||
if(!hitting_projectile.do_not_log)
|
||||
visible_message(SPAN_DANGER("[hitting_projectile] hit [src], but they do not respond... Maybe they have S.S.D?"))
|
||||
|
||||
else if(client && willfully_sleeping)
|
||||
if(!hitting_projectile.do_not_log)
|
||||
visible_message(SPAN_DANGER("[hitting_projectile] hit [src] waking [get_pronoun("him")] up!"))
|
||||
|
||||
sleeping = 0
|
||||
willfully_sleeping = FALSE
|
||||
|
||||
/mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/hit_zone)
|
||||
var/show_ssd
|
||||
|
||||
@@ -72,7 +72,7 @@ Exercise Verbs
|
||||
|
||||
var/list/extremities = list(BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG)
|
||||
for(var/zone in extremities)
|
||||
if(!get_organ(zone, TRUE))
|
||||
if(!get_organ(zone))
|
||||
to_chat(src, SPAN_WARNING("You can't do pushups with missing limbs."))
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -2105,14 +2105,14 @@
|
||||
return BULLET_IMPACT_METAL
|
||||
return BULLET_IMPACT_MEAT
|
||||
|
||||
/mob/living/carbon/human/bullet_impact_visuals(var/obj/projectile/P, var/def_zone, var/damage, var/blocked_ratio)
|
||||
..()
|
||||
if(blocked_ratio > 0.7)
|
||||
/mob/living/carbon/human/bullet_impact_visuals(obj/projectile/impacting_projectile, def_zone, damage, blocked)
|
||||
. = ..()
|
||||
if(blocked > 70)
|
||||
return
|
||||
switch(get_bullet_impact_effect_type(def_zone))
|
||||
if(BULLET_IMPACT_MEAT)
|
||||
if(P.damage_type == DAMAGE_BRUTE)
|
||||
var/hit_dir = get_dir(P.starting, src)
|
||||
if(impacting_projectile.damage_type == DAMAGE_BRUTE)
|
||||
var/hit_dir = get_dir(impacting_projectile.starting, src)
|
||||
var/obj/effect/decal/cleanable/blood/B = blood_splatter(get_step(src, hit_dir), src, 1, hit_dir)
|
||||
B.icon_state = pick("dir_splatter_1","dir_splatter_2")
|
||||
var/scale = min(1, round(damage / 50, 0.2))
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
// Should this all be in Touch()?
|
||||
if(istype(H))
|
||||
if(H != src && check_shields(0, null, H, H.zone_sel.selecting, H.name))
|
||||
if(H != src && (check_shields(0, null, H, H.zone_sel.selecting, H.name) != BULLET_ACT_HIT))
|
||||
H.do_attack_animation(src)
|
||||
return 0
|
||||
|
||||
@@ -549,7 +549,7 @@
|
||||
user.attack_log += "\[[time_stamp()]\] <span class='warning'>attacked [src.name] ([src.ckey])</span>"
|
||||
src.attack_log += "\[[time_stamp()]\] <font color='orange'>was attacked by [user.name] ([user.ckey])</font>"
|
||||
user.do_attack_animation(src)
|
||||
if(damage < 15 && check_shields(damage, null, user, null, "\the [user]"))
|
||||
if(damage < 15 && (check_shields(damage, null, user, null, "\the [user]") == BULLET_ACT_HIT))
|
||||
return
|
||||
|
||||
visible_message(SPAN_DANGER("[user] has [attack_message] [src]!"))
|
||||
|
||||
@@ -408,18 +408,33 @@ This function restores all organs.
|
||||
return 0
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/get_organ(var/zone, var/allow_no_result = FALSE)
|
||||
/**
|
||||
* Get an organ depending on the zone
|
||||
*
|
||||
* * zone - One of the `BP_*` defines
|
||||
*
|
||||
* Returns an `/obj/item/organ` corresponding to the `zone`, or null if the organ doesn't exist
|
||||
*/
|
||||
/mob/living/carbon/human/proc/get_organ(zone)
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
RETURN_TYPE(/obj/item/organ)
|
||||
|
||||
//This allows us to maintain the proc purity, though it kinda looks stupid
|
||||
var/zone_to_get
|
||||
|
||||
if(!zone)
|
||||
if(allow_no_result)
|
||||
return
|
||||
else
|
||||
zone = BP_CHEST
|
||||
if (zone in list(BP_EYES, BP_MOUTH))
|
||||
zone = BP_HEAD
|
||||
return organs_by_name[zone]
|
||||
stack_trace("WARNING: get_organ() called with no zone! Defaulting to BP_CHEST, but it won't be supported anymore in the future!")
|
||||
zone_to_get = BP_CHEST
|
||||
|
||||
if(zone in list(BP_EYES, BP_MOUTH))
|
||||
zone_to_get = BP_HEAD
|
||||
|
||||
if(!zone_to_get)
|
||||
zone_to_get = zone
|
||||
|
||||
if(zone_to_get in organs_by_name)
|
||||
return organs_by_name[zone_to_get]
|
||||
|
||||
/mob/living/carbon/human/apply_damage(damage = 0, damagetype = DAMAGE_BRUTE, def_zone, blocked, used_weapon, damage_flags = 0, armor_pen, silent = FALSE)
|
||||
if (invisibility == INVISIBILITY_LEVEL_TWO && back && (istype(back, /obj/item/rig)))
|
||||
@@ -427,7 +442,7 @@ This function restores all organs.
|
||||
to_chat(src, SPAN_DANGER("You are now visible."))
|
||||
set_invisibility(0)
|
||||
|
||||
var/obj/item/organ/external/organ = isorgan(def_zone) ? def_zone : get_organ(def_zone, TRUE)
|
||||
var/obj/item/organ/external/organ = isorgan(def_zone) ? def_zone : (isnull(def_zone) ? get_organ(BP_CHEST) : get_organ(def_zone))
|
||||
if(!organ)
|
||||
if(!def_zone)
|
||||
if(damage_flags & DAMAGE_FLAG_DISPERSED)
|
||||
|
||||
@@ -8,48 +8,38 @@ emp_act
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/carbon/human/bullet_act(var/obj/projectile/P, var/def_zone)
|
||||
var/species_check = src.species.bullet_act(P, def_zone, src)
|
||||
|
||||
/mob/living/carbon/human/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
var/species_check = src.species.bullet_act(hitting_projectile, def_zone, src)
|
||||
if(species_check)
|
||||
return species_check
|
||||
|
||||
if(!is_physically_disabled())
|
||||
var/deflection_chance = check_martial_deflection_chance()
|
||||
if(prob(deflection_chance))
|
||||
visible_message(SPAN_WARNING("\The [src] deftly dodges \the [P]!"), SPAN_NOTICE("You deftly dodge \the [P]!"))
|
||||
visible_message(SPAN_WARNING("\The [src] deftly dodges \the [hitting_projectile]!"), SPAN_NOTICE("You deftly dodge \the [hitting_projectile]!"))
|
||||
playsound(src, /singleton/sound_category/bulletflyby_sound, 75, TRUE)
|
||||
return PROJECTILE_DODGED
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
|
||||
def_zone = check_zone(def_zone)
|
||||
if(!has_organ(def_zone))
|
||||
return PROJECTILE_FORCE_MISS //if they don't have the organ in question then the projectile just passes by.
|
||||
return BULLET_ACT_FORCE_PIERCE //if they don't have the organ in question then the projectile just passes by.
|
||||
|
||||
//Shields
|
||||
var/shield_check = check_shields(P.damage, P, null, def_zone, "the [P.name]")
|
||||
if(shield_check)
|
||||
if(shield_check < 0)
|
||||
return shield_check
|
||||
else
|
||||
P.on_hit(src, 100, def_zone)
|
||||
return 100
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
var/obj/item/organ/external/organ = get_organ(def_zone)
|
||||
|
||||
// Tell clothing we're wearing that it got hit by a bullet/laser/etc
|
||||
var/list/clothing = get_clothing_list_organ(organ)
|
||||
for(var/obj/item/clothing/C in clothing)
|
||||
C.clothing_impact(P, P.damage)
|
||||
C.clothing_impact(hitting_projectile, hitting_projectile.damage)
|
||||
|
||||
//Shrapnel
|
||||
if(!(species.flags & NO_EMBED) && P.can_embed())
|
||||
var/armor = get_blocked_ratio(def_zone, DAMAGE_BRUTE, P.damage_flags(), armor_pen = P.armor_penetration, damage = P.damage)*100
|
||||
if(prob(20 + max(P.damage + P.embed_chance - armor, -10)))
|
||||
P.do_embed(organ)
|
||||
|
||||
var/blocked = ..(P, def_zone)
|
||||
|
||||
return blocked
|
||||
if(!(species.flags & NO_EMBED) && hitting_projectile.can_embed())
|
||||
var/armor = get_blocked_ratio(def_zone, DAMAGE_BRUTE, hitting_projectile.damage_flags(), armor_pen = hitting_projectile.armor_penetration, damage = hitting_projectile.damage)*100
|
||||
if(prob(20 + max(hitting_projectile.damage + hitting_projectile.embed_chance - armor, -10)))
|
||||
hitting_projectile.do_embed(organ)
|
||||
|
||||
/mob/living/carbon/human/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon, var/damage_flags)
|
||||
var/obj/item/organ/external/affected = get_organ(check_zone(def_zone))
|
||||
@@ -161,7 +151,7 @@ emp_act
|
||||
return gear
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/proc/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
|
||||
/mob/living/carbon/human/check_shields(damage, atom/damage_source, mob/attacker, def_zone, attack_text = "the attack")
|
||||
for(var/obj/item/shield in list(l_hand, r_hand, wear_suit, back))
|
||||
if(!shield)
|
||||
continue
|
||||
@@ -170,10 +160,9 @@ emp_act
|
||||
if(!shield.can_shield_back())
|
||||
continue
|
||||
is_on_back = TRUE
|
||||
. = shield.handle_shield(src, is_on_back, damage, damage_source, attacker, def_zone, attack_text)
|
||||
if(.)
|
||||
return
|
||||
return FALSE
|
||||
return shield.handle_shield(src, is_on_back, damage, damage_source, attacker, def_zone, attack_text)
|
||||
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
/mob/living/carbon/human/emp_act(severity)
|
||||
. = ..()
|
||||
@@ -209,7 +198,7 @@ emp_act
|
||||
visible_message(SPAN_DANGER("[user] misses [src] with \the [I]!"))
|
||||
return
|
||||
|
||||
if(check_shields(I.force, I, user, target_zone, "the [I.name]"))
|
||||
if(check_shields(I.force, I, user, target_zone, "the [I.name]") != BULLET_ACT_HIT)
|
||||
return
|
||||
|
||||
var/obj/item/organ/external/affecting = get_organ(hit_zone)
|
||||
@@ -334,7 +323,7 @@ emp_act
|
||||
if(isobj(hitting_atom))
|
||||
var/obj/O = hitting_atom
|
||||
|
||||
if(in_throw_mode && !get_active_hand() && throwingdatum.speed <= THROWFORCE_SPEED_DIVISOR) //empty active hand and we're in throw mode
|
||||
if(in_throw_mode && !get_active_hand() && throwingdatum?.speed <= THROWFORCE_SPEED_DIVISOR) //empty active hand and we're in throw mode
|
||||
if(canmove && !restrained())
|
||||
if(isturf(O.loc))
|
||||
put_in_active_hand(O)
|
||||
@@ -343,7 +332,9 @@ emp_act
|
||||
return
|
||||
|
||||
var/dtype = O.damtype
|
||||
var/throw_damage = O.throwforce*(throwingdatum.speed/THROWFORCE_SPEED_DIVISOR)
|
||||
var/throw_damage = O.throwforce
|
||||
if(throwingdatum)
|
||||
throw_damage *= (throwingdatum.speed/THROWFORCE_SPEED_DIVISOR)
|
||||
|
||||
var/zone
|
||||
if (istype(O.throwing?.thrower?.resolve(), /mob/living))
|
||||
@@ -361,10 +352,8 @@ emp_act
|
||||
|
||||
if(zone && O.throwing?.thrower?.resolve() != src)
|
||||
var/shield_check = check_shields(throw_damage, O, throwing?.thrower?.resolve(), zone, "[O]")
|
||||
if(shield_check == PROJECTILE_FORCE_MISS)
|
||||
if(shield_check != BULLET_ACT_HIT)
|
||||
zone = null
|
||||
else if(shield_check)
|
||||
return
|
||||
|
||||
if(!zone)
|
||||
visible_message(SPAN_NOTICE("\The [O] misses [src] narrowly!"))
|
||||
@@ -409,7 +398,10 @@ emp_act
|
||||
if(isitem(O))
|
||||
var/obj/item/I = O
|
||||
mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR
|
||||
var/momentum = throwingdatum.speed*mass
|
||||
|
||||
var/momentum = 0
|
||||
if(throwingdatum)
|
||||
momentum = throwingdatum.speed*mass
|
||||
|
||||
if(O.throwing?.thrower?.resolve() && momentum >= THROWNOBJ_KNOCKBACK_SPEED)
|
||||
var/dir = get_dir(O.throwing?.thrower?.resolve(), src)
|
||||
|
||||
@@ -408,7 +408,7 @@ var/global/list/golem_types = list(
|
||||
P.firer = H
|
||||
P.old_style_target(locate(new_x, new_y, P.z))
|
||||
|
||||
return -1 // complete projectile permutation
|
||||
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
|
||||
|
||||
/datum/species/golem/glass/handle_death(var/mob/living/carbon/human/H)
|
||||
for(var/i in 1 to 5)
|
||||
@@ -614,7 +614,7 @@ var/global/list/golem_types = list(
|
||||
P.firer = H
|
||||
P.old_style_target(locate(new_x, new_y, P.z))
|
||||
|
||||
return -1 // complete projectile permutation
|
||||
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
|
||||
|
||||
/datum/species/golem/marble
|
||||
name = SPECIES_GOLEM_MARBLE
|
||||
|
||||
@@ -104,7 +104,7 @@ GLOBAL_LIST_EMPTY(sparring_attack_cache)
|
||||
target.visible_message(SPAN_WARNING("[target] looks like [target.get_pronoun("he")] [target.get_pronoun("is")] in pain!"),
|
||||
SPAN_WARNING("[(target.gender=="female") ? "Oh god that hurt!" : "Oh no, that REALLY hurt!"]"))
|
||||
|
||||
target.apply_effects(stutter = attack_damage * 2, agony = attack_damage* 3, blocked = armor)
|
||||
target.apply_effects(stutter = attack_damage * 2, agony = attack_damage* 3, blocked = (armor * 100))
|
||||
if(BP_L_LEG, BP_L_FOOT, BP_R_LEG, BP_R_FOOT)
|
||||
if(!target.lying)
|
||||
if(pain_message)
|
||||
|
||||
@@ -246,10 +246,9 @@
|
||||
..(-abs(amount)) // Heals them
|
||||
return
|
||||
|
||||
/mob/living/carbon/slime/bullet_act(var/obj/projectile/Proj)
|
||||
/mob/living/carbon/slime/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
attacked += 10
|
||||
..(Proj)
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/slime/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
*/
|
||||
|
||||
/mob/living/proc/apply_damage(damage = 0, damagetype = DAMAGE_BRUTE, def_zone, blocked, used_weapon, damage_flags = 0, armor_pen, silent = FALSE)
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
if(!damage)
|
||||
return FALSE
|
||||
|
||||
@@ -54,7 +56,7 @@
|
||||
*
|
||||
* * effect - The amount of effect to apply, a number
|
||||
* * effect_type - An effect eg. `STUN`, `WEAKEN`; see `code\__DEFINES\damage_organs.dm` for relative defines
|
||||
* * blocked - The amount of effect that was blocked, eg. by armor, a number, percentage
|
||||
* * blocked - The **percentage** of effect that was blocked, eg. by armor, a number
|
||||
*
|
||||
* Returns `TRUE` if the effect was applied, `FALSE` otherwise
|
||||
*/
|
||||
@@ -111,18 +113,44 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Convenience proc to apply effects to a mob
|
||||
*
|
||||
* * blocked - The **percentage** of effects that was blocked, eg. by armor, a number
|
||||
*
|
||||
* Returns `TRUE` if the effects were not completely blocked, `FALSE` otherwise
|
||||
*/
|
||||
/mob/living/proc/apply_effects(stun = 0, weaken = 0, paralyze = 0, irradiate = 0, stutter = 0, eyeblur = 0, drowsy = 0, agony = 0, incinerate = 0, blocked = 0)
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
/mob/living/proc/apply_effects(var/stun = 0, var/weaken = 0, var/paralyze = 0, var/irradiate = 0, var/stutter = 0, var/eyeblur = 0, var/drowsy = 0, var/agony = 0, var/incinerate = 0, var/blocked = 0)
|
||||
if(blocked >= 2) return 0
|
||||
if(stun) apply_effect(stun, STUN, blocked)
|
||||
if(weaken) apply_effect(weaken, WEAKEN, blocked)
|
||||
if(paralyze) apply_effect(paralyze, PARALYZE, blocked)
|
||||
if(stutter) apply_effect(stutter, STUTTER, blocked)
|
||||
if(eyeblur) apply_effect(eyeblur, EYE_BLUR, blocked)
|
||||
if(drowsy) apply_effect(drowsy, DROWSY, blocked)
|
||||
if(agony) apply_effect(agony, DAMAGE_PAIN, blocked)
|
||||
if(incinerate) apply_effect(incinerate, INCINERATE, blocked)
|
||||
return 1
|
||||
if(blocked >= 100)
|
||||
return FALSE
|
||||
|
||||
if(stun)
|
||||
apply_effect(stun, STUN, blocked)
|
||||
|
||||
if(weaken)
|
||||
apply_effect(weaken, WEAKEN, blocked)
|
||||
|
||||
if(paralyze)
|
||||
apply_effect(paralyze, PARALYZE, blocked)
|
||||
|
||||
if(stutter)
|
||||
apply_effect(stutter, STUTTER, blocked)
|
||||
|
||||
if(eyeblur)
|
||||
apply_effect(eyeblur, EYE_BLUR, blocked)
|
||||
|
||||
if(drowsy)
|
||||
apply_effect(drowsy, DROWSY, blocked)
|
||||
|
||||
if(agony)
|
||||
apply_effect(agony, DAMAGE_PAIN, blocked)
|
||||
|
||||
if(incinerate)
|
||||
apply_effect(incinerate, INCINERATE, blocked)
|
||||
|
||||
return TRUE
|
||||
|
||||
// overridden by human
|
||||
/mob/living/proc/apply_radiation(var/rads)
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
handle_status_effects()
|
||||
|
||||
if(stat != DEAD)
|
||||
aura_check(AURA_TYPE_LIFE)
|
||||
if(LAZYLEN(auras))
|
||||
aura_check(AURA_TYPE_LIFE)
|
||||
if(!InStasis())
|
||||
//Mutations and radiation
|
||||
handle_mutations_and_radiation()
|
||||
|
||||
@@ -1067,3 +1067,7 @@ default behaviour is:
|
||||
|
||||
/mob/living/get_speech_bubble_state_modifier()
|
||||
return isSynthetic() ? "robot" : ..()
|
||||
|
||||
///Performs the aftereffects of blocking a projectile.
|
||||
/mob/living/proc/block_projectile_effects()
|
||||
return
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
var/datum/component/armor/armor_datum = armor
|
||||
. = armor_datum.apply_damage_modifications(arglist(.))
|
||||
|
||||
/mob/living/check_projectile_armor(def_zone, obj/projectile/impacting_projectile, is_silent)
|
||||
if(impacting_projectile.damage > 0) // Run the block computation if we did damage or if we only use armor for effects (nodamage)
|
||||
//Since we get a ratio from this and we need a percentage, we multiply by 100 to get the percentage
|
||||
return (get_blocked_ratio(def_zone, impacting_projectile.damage_type, impacting_projectile.damage_flags(), impacting_projectile.armor_penetration, impacting_projectile.damage) * 100)
|
||||
return 0
|
||||
|
||||
/mob/living/proc/get_blocked_ratio(def_zone, damage_type, damage_flags, armor_pen, damage)
|
||||
var/list/armors = get_armors_by_zone(def_zone, damage_type, damage_flags)
|
||||
. = 0
|
||||
@@ -23,36 +29,113 @@
|
||||
if(armor)
|
||||
. += armor
|
||||
|
||||
/mob/living/bullet_act(var/obj/projectile/P, var/def_zone, var/used_weapon = null)
|
||||
/**
|
||||
* Determines if the mob has a shield, and what to do with it
|
||||
*
|
||||
* Returns one of the `BULLET_ACT_*` defines
|
||||
*
|
||||
* `BULLET_ACT_HIT` if the shield didn't block the hit,
|
||||
* `BULLET_ACT_BLOCK` if the shield blocked the hit,
|
||||
* `BULLET_ACT_FORCE_PIERCE` if the shield avoided the mob from being hit, but whatever hit it wasn't stopped (eg. a bullet that doesn't hit the mob, but gets deflected)
|
||||
*/
|
||||
/mob/living/proc/check_shields(damage, atom/damage_source, mob/attacker, def_zone, attack_text)
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
//Being hit while using a cloaking device
|
||||
var/obj/item/cloaking_device/C = locate(/obj/item/cloaking_device) in src
|
||||
if(C && C.active)
|
||||
C.attack_self(src)//Should shut it off
|
||||
update_icon()
|
||||
to_chat(src, SPAN_NOTICE("Your [C.name] was disrupted!"))
|
||||
Stun(2)
|
||||
/mob/living/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
//Being hit while using a deadman switch
|
||||
if(istype(get_active_hand(),/obj/item/device/assembly/signaler))
|
||||
var/obj/item/device/assembly/signaler/signaler = get_active_hand()
|
||||
if(signaler.deadman && prob(80))
|
||||
log_and_message_admins("has triggered a signaler deadman's switch")
|
||||
src.visible_message(SPAN_WARNING("[src] triggers their deadman's switch!"))
|
||||
signaler.signal()
|
||||
/*#############################################
|
||||
THINGS THAT CAN AVOID THE MOB BEING HIT
|
||||
OR ALTER THE DAMAGE WE TAKE
|
||||
#############################################*/
|
||||
|
||||
//Armor
|
||||
var/damage = P.damage
|
||||
var/flags = P.damage_flags()
|
||||
var/blocked
|
||||
|
||||
//Auras, essentially magic and encompassing around us, gets checked first
|
||||
if(!src.aura_check(AURA_TYPE_BULLET, hitting_projectile, def_zone, piercing_hit))
|
||||
blocked = 100
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
|
||||
|
||||
//Shields, in front of us (hopefully), check the bullet before it reaches us
|
||||
var/shield_check = check_shields(hitting_projectile.damage, hitting_projectile, hitting_projectile.firer, def_zone, "the [hitting_projectile.name]")
|
||||
if(shield_check != BULLET_ACT_HIT)
|
||||
hitting_projectile.on_hit(src, 100, def_zone)
|
||||
return shield_check
|
||||
|
||||
|
||||
//Armor, right above our skin, can soften the hit
|
||||
|
||||
// we need a second, silent armor check to actually know how much to reduce damage taken, as opposed to
|
||||
// on [/atom/proc/bullet_act] where it's just to pass it to the projectile's on_hit().
|
||||
blocked = check_projectile_armor(def_zone, hitting_projectile, is_silent = TRUE)
|
||||
|
||||
var/damage = hitting_projectile.damage //We use a supporting variable to store the damage, since we can alter it below
|
||||
//If it's anti material vulnerable, apply the anti-material potential factor
|
||||
if(is_anti_materiel_vulnerable())
|
||||
damage = P.damage * P.anti_materiel_potential
|
||||
var/damaged
|
||||
if(!P.nodamage)
|
||||
damaged = apply_damage(damage, P.damage_type, def_zone, damage_flags = P.damage_flags(), used_weapon = P, armor_pen = P.armor_penetration)
|
||||
if(damaged || P.nodamage) // Run the block computation if we did damage or if we only use armor for effects (nodamage)
|
||||
. = get_blocked_ratio(def_zone, P.damage_type, flags, P.armor_penetration, P.damage)
|
||||
bullet_impact_visuals(P, def_zone, damage, .)
|
||||
P.on_hit(src, ., def_zone)
|
||||
damage = hitting_projectile.damage * hitting_projectile.anti_materiel_potential
|
||||
|
||||
/*##################################
|
||||
OK WE ARE BEING HIT NOW IF
|
||||
WE HAVE REACHED THIS POINT
|
||||
##################################*/
|
||||
|
||||
//If the projectile has damage and it's not completely blocked, apply it
|
||||
if(damage > 0 && blocked < 100)
|
||||
//Apply the damage to the living mob
|
||||
apply_damage(damage, hitting_projectile.damage_type, def_zone, blocked, used_weapon = hitting_projectile, damage_flags = hitting_projectile.damage_flags(), used_weapon = hitting_projectile, armor_pen = hitting_projectile.armor_penetration)
|
||||
|
||||
/*### START Other effects of being hit and damaged ###*/
|
||||
|
||||
//Being hit while using a cloaking device
|
||||
var/obj/item/cloaking_device/C = locate(/obj/item/cloaking_device) in src
|
||||
if(C && C.active)
|
||||
C.attack_self(src)//Should shut it off
|
||||
update_icon()
|
||||
to_chat(src, SPAN_NOTICE("Your [C.name] was disrupted!"))
|
||||
Stun(2)
|
||||
|
||||
//Being hit while using a deadman switch
|
||||
var/obj/item/device/assembly/signaler/signaler = get_active_hand()
|
||||
if(istype(signaler))
|
||||
if(signaler.deadman && prob(80))
|
||||
log_and_message_admins("has triggered a signaler deadman's switch")
|
||||
src.visible_message(SPAN_WARNING("[src] triggers their deadman's switch!"))
|
||||
signaler.signal()
|
||||
|
||||
/*### END Other effects of being hit and damaged ###*/
|
||||
|
||||
bullet_impact_visuals(hitting_projectile, def_zone, damage, blocked)
|
||||
|
||||
//Messages related to being hit (not necessarily damaged)
|
||||
if(!hitting_projectile.do_not_log)
|
||||
var/impacted_organ = get_organ_name_from_zone(def_zone)
|
||||
|
||||
//If the projectile was blocked and it's not at point blank range, then it missed
|
||||
if(blocked >= 100 && !hitting_projectile.point_blank)
|
||||
src.visible_message(SPAN_NOTICE("\The [hitting_projectile] misses [src] narrowly!"))
|
||||
playsound(src, /singleton/sound_category/bulletflyby_sound, 50, 1)
|
||||
|
||||
//Otherwise it hit
|
||||
else
|
||||
|
||||
//If the projectile is suppressed, give a message only to the mob, and a smaller one
|
||||
if(hitting_projectile.suppressed)
|
||||
to_chat(src, SPAN_DANGER("You've been hit in the [impacted_organ] by \a [hitting_projectile]!"))
|
||||
|
||||
//Otherwise announce it as a visible message, and make it larger
|
||||
else
|
||||
//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
|
||||
src.visible_message(SPAN_DANGER("\The [src] is hit by \a [hitting_projectile] in the [impacted_organ]!"),
|
||||
SPAN_DANGER(FONT_LARGE("You are hit by \a [hitting_projectile] in the [impacted_organ]!")))
|
||||
|
||||
|
||||
if(blocked < 100)
|
||||
return BULLET_ACT_HIT
|
||||
else
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
/mob/living/proc/get_flash_protection(ignore_inherent = FALSE)
|
||||
return FLASH_PROTECTION_NONE
|
||||
@@ -68,8 +151,7 @@
|
||||
return TRUE
|
||||
. = TRUE
|
||||
var/list/newargs = args - args[1]
|
||||
for(var/a in auras)
|
||||
var/obj/aura/aura = a
|
||||
for(var/obj/aura/aura as anything in auras)
|
||||
var/result = 0
|
||||
switch(type)
|
||||
if(AURA_TYPE_WEAPON)
|
||||
@@ -85,9 +167,18 @@
|
||||
if(result & AURA_CANCEL)
|
||||
break
|
||||
|
||||
//For visuals, blood splatters and so on.
|
||||
/mob/living/proc/bullet_impact_visuals(var/obj/projectile/P, var/def_zone, var/damage, var/blocked_ratio)
|
||||
var/list/impact_sounds = LAZYACCESS(P.impact_sounds, get_bullet_impact_effect_type(def_zone))
|
||||
/**
|
||||
* For visuals, blood splatters and so on
|
||||
*
|
||||
* * impacting_projectile - The `/obj/projectile` that hit the mob
|
||||
* * def_zone - The zone that the projectile hit the mob in, use the defines
|
||||
* * damage - The amount of damage the projectile did
|
||||
* * blocked - The **percentage** of damage that was blocked, eg. by armor, a number
|
||||
*/
|
||||
/mob/living/proc/bullet_impact_visuals(obj/projectile/impacting_projectile, def_zone, damage, blocked)
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
var/list/impact_sounds = LAZYACCESS(impacting_projectile.impact_sounds, get_bullet_impact_effect_type(def_zone))
|
||||
if(length(impact_sounds))
|
||||
playsound(src, pick(impact_sounds), 75)
|
||||
|
||||
|
||||
@@ -567,11 +567,13 @@
|
||||
/mob/living/silicon/robot/restrained()
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/robot/bullet_act(var/obj/projectile/Proj)
|
||||
..(Proj)
|
||||
if(prob(75) && Proj.damage > 0)
|
||||
/mob/living/silicon/robot/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if(prob(75) && hitting_projectile.damage > 0)
|
||||
spark_system.queue()
|
||||
return 2
|
||||
|
||||
/mob/living/silicon/robot/attackby(obj/item/attacking_item, mob/user)
|
||||
if(istype(attacking_item, /obj/item/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
|
||||
|
||||
@@ -138,17 +138,19 @@
|
||||
/mob/living/silicon/IsAdvancedToolUser()
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/bullet_act(obj/projectile/Proj)
|
||||
if(!Proj.nodamage)
|
||||
switch(Proj.damage_type)
|
||||
if(DAMAGE_BRUTE)
|
||||
adjustBruteLoss(Proj.damage)
|
||||
if(DAMAGE_BURN)
|
||||
adjustFireLoss(Proj.damage)
|
||||
/mob/living/silicon/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
SHOULD_CALL_PARENT(FALSE) //More shitcode
|
||||
|
||||
Proj.on_hit(src, 100)
|
||||
if(hitting_projectile.damage > 0)
|
||||
switch(hitting_projectile.damage_type)
|
||||
if(DAMAGE_BRUTE)
|
||||
adjustBruteLoss(hitting_projectile.damage)
|
||||
if(DAMAGE_BURN)
|
||||
adjustFireLoss(hitting_projectile.damage)
|
||||
|
||||
hitting_projectile.on_hit(src, 100)
|
||||
updatehealth()
|
||||
return 100
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
/mob/living/silicon/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0)
|
||||
return FALSE
|
||||
|
||||
@@ -22,23 +22,25 @@
|
||||
resistance = 10
|
||||
construct_spells = list(/spell/aoe_turf/conjure/forcewall/lesser)
|
||||
|
||||
/mob/living/simple_animal/construct/armored/bullet_act(var/obj/projectile/P)
|
||||
if(istype(P, /obj/projectile/energy) || istype(P, /obj/projectile/beam))
|
||||
var/reflectchance = 80 - round(P.damage / 3)
|
||||
/mob/living/simple_animal/construct/armored/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if(istype(hitting_projectile, /obj/projectile/energy) || istype(hitting_projectile, /obj/projectile/beam))
|
||||
var/reflectchance = 80 - round(hitting_projectile.damage / 3)
|
||||
if(prob(reflectchance))
|
||||
adjustBruteLoss(P.damage * 0.3)
|
||||
visible_message(SPAN_DANGER("\The [P.name] gets reflected by \the [src]'s shell!"), \
|
||||
SPAN_DANGER("\The [P.name] gets reflected by \the [src]'s shell!"))
|
||||
adjustBruteLoss(hitting_projectile.damage * 0.3)
|
||||
visible_message(SPAN_DANGER("\The [hitting_projectile.name] gets reflected by \the [src]'s shell!"), \
|
||||
SPAN_DANGER("\The [hitting_projectile.name] gets reflected by \the [src]'s shell!"))
|
||||
|
||||
// Find a turf near or on the original location to bounce to
|
||||
if(P.starting)
|
||||
var/new_x = P.starting.x + text2num(pickweight(list("0" = 1, "1" = 1, "2" = 3, "3" = 2))) * pick(1, -1)
|
||||
var/new_y = P.starting.y + text2num(pickweight(list("0" = 1, "1" = 1, "2" = 3, "3" = 2))) * pick(1, -1)
|
||||
if(hitting_projectile.starting)
|
||||
var/new_x = hitting_projectile.starting.x + text2num(pickweight(list("0" = 1, "1" = 1, "2" = 3, "3" = 2))) * pick(1, -1)
|
||||
var/new_y = hitting_projectile.starting.y + text2num(pickweight(list("0" = 1, "1" = 1, "2" = 3, "3" = 2))) * pick(1, -1)
|
||||
|
||||
// redirect the projectile
|
||||
P.firer = src
|
||||
P.old_style_target(locate(new_x, new_y, P.z))
|
||||
hitting_projectile.firer = src
|
||||
hitting_projectile.old_style_target(locate(new_x, new_y, hitting_projectile.z))
|
||||
|
||||
return -1 // complete projectile permutation
|
||||
|
||||
return (..(P))
|
||||
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
|
||||
|
||||
@@ -239,10 +239,13 @@
|
||||
unburrow()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/ice_catcher/bullet_act(obj/projectile/P, def_zone)
|
||||
/mob/living/simple_animal/ice_catcher/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if(burrowed && (stat != DEAD))
|
||||
unburrow()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/ice_catcher/death(gibbed)
|
||||
..()
|
||||
|
||||
@@ -185,9 +185,12 @@
|
||||
. = ..()
|
||||
set_flee_target(src.loc)
|
||||
|
||||
/mob/living/simple_animal/cat/bullet_act(var/obj/projectile/proj)
|
||||
/mob/living/simple_animal/cat/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
set_flee_target(proj.firer? proj.firer : src.loc)
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
set_flee_target(hitting_projectile.firer? hitting_projectile.firer : src.loc)
|
||||
|
||||
/mob/living/simple_animal/cat/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
. = ..()
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
/mob/living/simple_animal/hostile/plasmageist/ex_act(severity)
|
||||
return
|
||||
|
||||
/obj/projectile/beam/tesla/plasmageist/on_impact(atom/target)
|
||||
/obj/projectile/beam/tesla/plasmageist/on_hit(atom/target, blocked, def_zone)
|
||||
. = ..()
|
||||
if(isliving(target))
|
||||
explosion(target, -1, 0, 2)
|
||||
|
||||
@@ -273,13 +273,16 @@
|
||||
anger++
|
||||
instant_aggro(1)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/bullet_act(obj/projectile/P, def_zone)//Teleport around when shot, so its harder to burst it down with a carbine
|
||||
//Teleport around when shot, so its harder to burst it down with a carbine
|
||||
/mob/living/simple_animal/hostile/bear/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
var/healthbefore = health
|
||||
..()
|
||||
spawn(1)
|
||||
if (health < healthbefore)
|
||||
instant_aggro()
|
||||
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if (health < healthbefore)
|
||||
instant_aggro()
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/ex_act(var/severity = 2.0)
|
||||
var/healthbefore = health
|
||||
@@ -508,9 +511,13 @@
|
||||
forceMove(target)
|
||||
spark_system.queue()
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/spatial/bullet_act(obj/projectile/P, def_zone)//Teleport around when shot, so its harder to burst it down with a carbine
|
||||
..(P, def_zone)
|
||||
if (prob(P.damage*1.5))//Bear has a good chance of teleporting when shot, making it harder to burst down
|
||||
//Teleport around when shot, so its harder to burst it down with a carbine
|
||||
/mob/living/simple_animal/hostile/bear/spatial/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if (prob(hitting_projectile.damage*1.5))//Bear has a good chance of teleporting when shot, making it harder to burst down
|
||||
teleport_tactical()
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/spatial/FoundTarget()
|
||||
|
||||
@@ -308,11 +308,13 @@ ABSTRACT_TYPE(/mob/living/simple_animal/hostile/commanded)
|
||||
change_stance(HOSTILE_STANCE_IDLE)
|
||||
audible_emote("[pick(sad_emote)].",0)
|
||||
|
||||
/mob/living/simple_animal/hostile/commanded/bullet_act(var/obj/projectile/P, var/def_zone)
|
||||
..()
|
||||
/mob/living/simple_animal/hostile/commanded/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
// We forgive our master
|
||||
if (ismob(P.firer) && P.firer == master)
|
||||
if (ismob(hitting_projectile.firer) && hitting_projectile.firer == master)
|
||||
target_mob = null
|
||||
change_stance(HOSTILE_STANCE_IDLE)
|
||||
audible_emote("[pick(sad_emote)].",0)
|
||||
|
||||
@@ -81,11 +81,11 @@
|
||||
else
|
||||
return "blood_overlay_armed"
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebot/bullet_act(var/obj/projectile/Proj)
|
||||
if(istype(Proj, /obj/projectile/bullet/pistol/hivebotspike) || istype(Proj, /obj/projectile/beam/hivebot))
|
||||
return PROJECTILE_CONTINUE
|
||||
/mob/living/simple_animal/hostile/hivebot/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
if(istype(hitting_projectile, /obj/projectile/bullet/pistol/hivebotspike) || istype(hitting_projectile, /obj/projectile/beam/hivebot))
|
||||
return BULLET_ACT_BLOCK
|
||||
else
|
||||
return ..(Proj)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebot/death()
|
||||
..(null,"blows apart!")
|
||||
@@ -194,10 +194,14 @@
|
||||
has_exploded = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(burst)), 20)
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebot/bomber/bullet_act(var/obj/projectile/Proj)
|
||||
if(istype(Proj, /obj/projectile/bullet/pistol/hivebotspike) || istype(Proj, /obj/projectile/beam/hivebot))
|
||||
return PROJECTILE_CONTINUE
|
||||
/mob/living/simple_animal/hostile/hivebot/bomber/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
if(istype(hitting_projectile, /obj/projectile/bullet/pistol/hivebotspike) || istype(hitting_projectile, /obj/projectile/beam/hivebot))
|
||||
return BULLET_ACT_BLOCK
|
||||
else if(!has_exploded)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
has_exploded = TRUE
|
||||
burst()
|
||||
|
||||
|
||||
@@ -208,11 +208,11 @@
|
||||
/mob/living/simple_animal/hostile/hivebotbeacon/AirflowCanMove(n)
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebotbeacon/bullet_act(var/obj/projectile/Proj)
|
||||
if(istype(Proj, /obj/projectile/bullet/pistol/hivebotspike) || istype(Proj, /obj/projectile/beam/hivebot))
|
||||
return PROJECTILE_CONTINUE
|
||||
/mob/living/simple_animal/hostile/hivebotbeacon/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
if(istype(hitting_projectile, /obj/projectile/bullet/pistol/hivebotspike) || istype(hitting_projectile, /obj/projectile/beam/hivebot))
|
||||
return BULLET_ACT_BLOCK
|
||||
else
|
||||
..(Proj)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebotbeacon/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
@@ -72,11 +72,11 @@
|
||||
/mob/living/simple_animal/hostile/retaliate/hivebotharvester/AirflowCanMove(n)
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/hivebotharvester/bullet_act(var/obj/projectile/Proj)
|
||||
if(istype(Proj, /obj/projectile/bullet/pistol/hivebotspike) || istype(Proj, /obj/projectile/beam/hivebot))
|
||||
return PROJECTILE_CONTINUE
|
||||
/mob/living/simple_animal/hostile/retaliate/hivebotharvester/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
if(istype(hitting_projectile, /obj/projectile/bullet/pistol/hivebotspike) || istype(hitting_projectile, /obj/projectile/beam/hivebot))
|
||||
return BULLET_ACT_BLOCK
|
||||
else
|
||||
return ..(Proj)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/hivebotharvester/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
@@ -118,10 +118,13 @@ ABSTRACT_TYPE(/mob/living/simple_animal/hostile)
|
||||
change_stance(HOSTILE_STANCE_ATTACKING)
|
||||
visible_message(SPAN_WARNING("\The [src] gets taunted by \the [H] and begins to retaliate!"))
|
||||
|
||||
/mob/living/simple_animal/hostile/bullet_act(var/obj/projectile/P, var/def_zone)
|
||||
..()
|
||||
if (ismob(P.firer) && target_mob != P.firer)
|
||||
target_mob = P.firer
|
||||
/mob/living/simple_animal/hostile/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if (ismob(hitting_projectile.firer) && target_mob != hitting_projectile.firer)
|
||||
target_mob = hitting_projectile.firer
|
||||
change_stance(HOSTILE_STANCE_ATTACK)
|
||||
|
||||
/mob/living/simple_animal/hostile/handle_attack_by(var/mob/user)
|
||||
@@ -373,11 +376,9 @@ ABSTRACT_TYPE(/mob/living/simple_animal/hostile)
|
||||
if(target == start)
|
||||
return
|
||||
|
||||
var/obj/projectile/A = new projectiletype(user.loc)
|
||||
playsound(user, projectilesound, 100, 1)
|
||||
if(!A) return
|
||||
var/def_zone = get_exposed_defense_zone(target)
|
||||
A.launch_projectile(target, def_zone)
|
||||
// var/def_zone = get_exposed_defense_zone(target)
|
||||
|
||||
fire_projectile(/obj/projectile, target, projectilesound, firer = user)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/DestroySurroundings(var/bypass_prob = FALSE)
|
||||
if(ON_ATTACK_COOLDOWN(src))
|
||||
|
||||
@@ -67,7 +67,9 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/projectile/beam/cavern/on_hit(var/atom/target, var/blocked = 0)
|
||||
/obj/projectile/beam/cavern/on_hit(atom/target, blocked, def_zone)
|
||||
. = ..()
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/M = target
|
||||
var/shock_damage = rand(10,20)
|
||||
|
||||
@@ -361,7 +361,7 @@
|
||||
/obj/projectile/energy/thoughtbubble
|
||||
name = "psionic blast"
|
||||
icon_state = "ion"
|
||||
nodamage = TRUE
|
||||
damage = 0
|
||||
agony = 20
|
||||
check_armor = "energy"
|
||||
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
|
||||
@@ -391,10 +391,10 @@
|
||||
"You've got a bad feeling about this."
|
||||
)
|
||||
|
||||
/obj/projectile/energy/thoughtbubble/on_impact(var/atom/A)
|
||||
..()
|
||||
if(istype(A, /mob/living))
|
||||
var/mob/living/L = A
|
||||
/obj/projectile/energy/thoughtbubble/on_hit(atom/target, blocked, def_zone)
|
||||
. = ..()
|
||||
if(istype(target, /mob/living))
|
||||
var/mob/living/L = target
|
||||
if(L.reagents)
|
||||
var/madhouse = pick(/singleton/reagent/drugs/psilocybin,/singleton/reagent/drugs/mindbreaker,/singleton/reagent/drugs/impedrezene,/singleton/reagent/drugs/cryptobiolin,/singleton/reagent/soporific,/singleton/reagent/mutagen)
|
||||
var/madhouse_verbal_component = pick(thoughts)
|
||||
|
||||
@@ -227,7 +227,11 @@
|
||||
has_exploded = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(explode)), 5)
|
||||
|
||||
/mob/living/simple_animal/hostile/carp/bloater/bullet_act(var/obj/projectile/Proj)
|
||||
/mob/living/simple_animal/hostile/carp/bloater/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if(!has_exploded)
|
||||
has_exploded = TRUE
|
||||
explode()
|
||||
|
||||
@@ -78,13 +78,16 @@
|
||||
visible_message(SPAN_WARNING("[user] gently taps [src] with the [attacking_item]."))
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(var/obj/projectile/Proj)
|
||||
if(!Proj) return
|
||||
if(prob(65))
|
||||
src.health -= Proj.damage
|
||||
else
|
||||
visible_message(SPAN_DANGER("[src] blocks [Proj] with its shield!"))
|
||||
return 0
|
||||
/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
if(prob(35))
|
||||
visible_message(SPAN_DANGER("[src] blocks [hitting_projectile] with its shield!"))
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
src.health -= hitting_projectile.damage
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/melee/space
|
||||
|
||||
@@ -61,10 +61,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/vannatusk/proc/fire_spike(var/mob/living/target_mob)
|
||||
visible_message(SPAN_DANGER("\The [src] fires a spike at [target_mob]!"))
|
||||
playsound(get_turf(src), 'sound/weapons/bloodyslice.ogg', 50, 1)
|
||||
var/obj/projectile/bonedart/A = new /obj/projectile/bonedart(get_turf(src))
|
||||
var/def_zone = get_exposed_defense_zone(target_mob)
|
||||
A.launch_projectile(target_mob, def_zone)
|
||||
fire_projectile(/obj/projectile/bonedart, target_mob, 'sound/weapons/bloodyslice.ogg', firer = src)
|
||||
|
||||
/obj/item/bone_dart/vannatusk
|
||||
name = "bone dart"
|
||||
|
||||
@@ -38,14 +38,14 @@
|
||||
else
|
||||
return list("???")
|
||||
|
||||
/mob/living/simple_animal/illusion/bullet_act(obj/projectile/P)
|
||||
if(!P)
|
||||
return
|
||||
/mob/living/simple_animal/illusion/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
if(!hitting_projectile)
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
if(realistic)
|
||||
return ..()
|
||||
|
||||
return PROJECTILE_FORCE_MISS
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
/mob/living/simple_animal/illusion/attack_hand(mob/living/carbon/human/M)
|
||||
if(!realistic)
|
||||
|
||||
@@ -254,8 +254,11 @@
|
||||
return
|
||||
|
||||
//Bullets
|
||||
/mob/living/simple_animal/parrot/bullet_act(var/obj/projectile/Proj)
|
||||
..()
|
||||
/mob/living/simple_animal/parrot/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if(!stat && !client)
|
||||
if(parrot_state == PARROT_PERCH)
|
||||
parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
|
||||
@@ -265,7 +268,6 @@
|
||||
parrot_been_shot += 5
|
||||
icon_state = "parrot_fly"
|
||||
drop_held_item(0)
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -654,10 +654,13 @@
|
||||
if(ismob(throwingdatum.thrower?.resolve()))
|
||||
handle_attack_by(throwingdatum.thrower.resolve())
|
||||
|
||||
/mob/living/simple_animal/bullet_act(obj/projectile/P, def_zone)
|
||||
/mob/living/simple_animal/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
. = ..()
|
||||
if(ismob(P.firer))
|
||||
handle_attack_by(P.firer)
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if(ismob(hitting_projectile.firer))
|
||||
handle_attack_by(hitting_projectile.firer)
|
||||
|
||||
/mob/living/simple_animal/apply_damage(damage = 0, damagetype = DAMAGE_BRUTE, def_zone, blocked, used_weapon, damage_flags = 0, armor_pen, silent = FALSE)
|
||||
. = ..()
|
||||
@@ -965,12 +968,12 @@
|
||||
/mob/living/simple_animal/get_digestion_product()
|
||||
return /singleton/reagent/nutriment
|
||||
|
||||
/mob/living/simple_animal/bullet_impact_visuals(var/obj/projectile/P, var/def_zone, var/damage)
|
||||
..()
|
||||
/mob/living/simple_animal/bullet_impact_visuals(obj/projectile/impacting_projectile, def_zone, damage, blocked)
|
||||
. = ..()
|
||||
switch(get_bullet_impact_effect_type(def_zone))
|
||||
if(BULLET_IMPACT_MEAT)
|
||||
if(P.damage_type == DAMAGE_BRUTE)
|
||||
var/hit_dir = get_dir(P.starting, src)
|
||||
if(impacting_projectile.damage_type == DAMAGE_BRUTE)
|
||||
var/hit_dir = get_dir(impacting_projectile.starting, src)
|
||||
var/obj/effect/decal/cleanable/blood/B = blood_splatter(get_step(src, hit_dir), src, 1, hit_dir)
|
||||
B.icon_state = pick("dir_splatter_1","dir_splatter_2")
|
||||
B.basecolor = blood_type
|
||||
|
||||
@@ -276,6 +276,14 @@ var/list/global/organ_rel_size = list(
|
||||
BP_R_FOOT = 10
|
||||
)
|
||||
|
||||
///Find the mob at the bottom of a buckle chain
|
||||
/mob/proc/lowest_buckled_mob()
|
||||
. = src
|
||||
//buckled -> buckled_to from TG
|
||||
if(buckled_to && ismob(buckled_to))
|
||||
var/mob/Buckled = buckled_to
|
||||
. = Buckled.lowest_buckled_mob()
|
||||
|
||||
/proc/check_zone(zone)
|
||||
if(!zone)
|
||||
return BP_CHEST
|
||||
@@ -286,36 +294,24 @@ var/list/global/organ_rel_size = list(
|
||||
zone = BP_HEAD
|
||||
return zone
|
||||
|
||||
// Returns zone with a certain probability. If the probability fails, or no zone is specified, then a random body part is chosen.
|
||||
// Do not use this if someone is intentionally trying to hit a specific body part.
|
||||
// Use get_zone_with_miss_chance() for that.
|
||||
/proc/ran_zone(zone, probability)
|
||||
if (zone)
|
||||
/**
|
||||
* Return the zone or randomly, another valid zone
|
||||
*
|
||||
* _Do not use this if someone is intentionally trying to hit a specific body part - use get_zone_with_miss_chance() for that_
|
||||
*
|
||||
* probability controls the chance it chooses the passed in zone, or another random zone
|
||||
* defaults to 80
|
||||
*/
|
||||
/proc/ran_zone(zone, probability = 80, list/weighted_list)
|
||||
if(prob(probability))
|
||||
zone = check_zone(zone)
|
||||
if (prob(probability))
|
||||
return zone
|
||||
else
|
||||
zone = pick_weight(weighted_list ? weighted_list : organ_rel_size) //Slightly different from TG, we have a list with organ sizes
|
||||
return zone
|
||||
|
||||
var/ran_zone = zone
|
||||
while (ran_zone == zone)
|
||||
ran_zone = pick (
|
||||
organ_rel_size[BP_HEAD]; BP_HEAD,
|
||||
organ_rel_size[BP_CHEST]; BP_CHEST,
|
||||
organ_rel_size[BP_GROIN]; BP_GROIN,
|
||||
organ_rel_size[BP_L_ARM]; BP_L_ARM,
|
||||
organ_rel_size[BP_R_ARM]; BP_R_ARM,
|
||||
organ_rel_size[BP_L_LEG]; BP_L_LEG,
|
||||
organ_rel_size[BP_R_LEG]; BP_R_LEG,
|
||||
organ_rel_size[BP_L_HAND]; BP_L_HAND,
|
||||
organ_rel_size[BP_R_HAND]; BP_R_HAND,
|
||||
organ_rel_size[BP_L_FOOT]; BP_L_FOOT,
|
||||
organ_rel_size[BP_R_FOOT]; BP_R_FOOT
|
||||
)
|
||||
|
||||
return ran_zone
|
||||
|
||||
// Emulates targetting a specific body part, and miss chances
|
||||
// May return null if missed
|
||||
// miss_chance_mod may be negative.
|
||||
/// Emulates targetting a specific body part, and miss chances
|
||||
/// May return null if missed
|
||||
/// miss_chance_mod may be negative.
|
||||
/proc/get_zone_with_miss_chance(zone, var/mob/target, var/miss_chance_mod = 0, var/ranged_attack=0, var/point_blank = FALSE)
|
||||
zone = check_zone(zone)
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
/mob/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(air_group || (height==0)) return 1
|
||||
if(air_group || (height==0))
|
||||
return TRUE
|
||||
|
||||
if(mover?.movement_type & PHASING)
|
||||
return TRUE
|
||||
|
||||
if(ismob(mover))
|
||||
var/mob/moving_mob = mover
|
||||
|
||||
Reference in New Issue
Block a user