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:
Fluffy
2024-09-23 10:12:57 +00:00
committed by GitHub
parent 914f69dcc8
commit c24b4c7097
203 changed files with 2925 additions and 1590 deletions
+2
View File
@@ -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)
. = ..()
+40 -12
View File
@@ -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)
+2 -1
View File
@@ -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()
+4
View File
@@ -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
+122 -31
View File
@@ -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
+11 -9
View File
@@ -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
+24 -28
View File
@@ -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)
+5 -1
View File
@@ -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