Ballistics v2 draft

This commit is contained in:
Cadyn
2020-10-31 12:21:21 -07:00
parent 241e386284
commit b3ba48084f
6 changed files with 294 additions and 1 deletions

View File

@@ -0,0 +1,246 @@
#define BULLET_AP_DIVISOR 200
#define AP_DIVISOR 4152
#define ARMOR_Y_INTERCEPT 0.2
#define ARMOR_SLOPE 0.017
#define PENETRATION_PROBABILITY_EXP_BASE 2
#define PENETRATION_PROBABILITY_EXP_MULT 30
#define BULLET_DEFLECTED_PAIN_DIVISOR 5000
#define BULLET_DEFLECTED_BULLET_DIVISOR 70
#define BULLET_DEFLECTED_MELEE_DIVISOR 280
#define SKIN_LOSS_COEFFICIENT 61
#define ARMOR_LOSS_COEFFICIENT 200
#define ARMOR_LOSS_MIN_MULT 0.5
#define ARMOR_LOSS_MIN_ARMOR 20
#define INTERNAL_LOSS_COEFFICIENT 250
#define ORGAN_LOSS_COEFFICIENT 350
#define ORGAN_LEAVE_EARLY list("l_arm", "r_arm", "l_hand", "r_hand", "l_foot", "r_foot")
#define HIT_ORGAN_CHANCE_VITALS 90
#define HIT_VITAL_ORGAN_CHANCE 30
#define BONE_HIT_CHANCE list("torso" = 0.2, "groin" = 0.2, "l_foot" = 0.8, "r_foot" = 0.8, "l_leg" = 0.35, "r_leg" = 0.35, "l_arm" = 0.65, "r_arm" = 0.65, "l_hand" = 0.8, "r_hand" = 0.8)
#define BONE_HIT_CHANCE_UNENCASED 45
#define BONE_HIT_CHANCE_ENCASED 80
#define BONE_JOULES_PERHP_AVG 30
#define BONE_JOULES_PERHP_DEV 10
#define BONE_HP_AVG 25
#define PROB_LEAVE_EARLY_FIRST 20
#define PROB_LEAVE_EARLY_SECOND 40
#define GAUSSIAN_RANDOM(vars...) ((-2*log(rand()))**0.5 * cos(6.28318530718*rand()))
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// CADYN'S BALLISTICS ////////////////////////////////////////////////////////////////////////// ORIGINAL FROM CHOMPSTATION ////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/mob/living/proc/handle_ballistics(var/obj/item/projectile/bullet/P, var/def_zone)
var/ballistic_armor = getarmor(def_zone, "bullet")
var/melee_armor = getarmor(def_zone, "melee")
var/obj/item/organ/external/hit_organ
var/mob/living/carbon/human/H = src
if(istype(H))
hit_organ = H.get_organ(def_zone)
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(!prob(penetration_chance)) //Boo-hoo we got deflected. Do boring agony/bruises stuff.
var/pain_hit = hit_organ ? "into your [hit_organ]" : "into you"
var/hurt_value = P.velocity * P.grains / (BULLET_DEFLECTED_PAIN_DIVISOR * (1 + ballistic_armor/70 + melee_armor/280)) //Better armor spreads out the energy better.
var/hurt_value_pain = hurt_value ** 1.5
var/hurt_value_bruise = max(0,hurt_value-5)
var/absorber = ballistic_armor ? "armor" : "body" //There is a super tiny chance that small rounds can get deflected without armor, so this is just incase.
to_chat(src,"<span class='warning'>You feel the energy of the bullet painfully transfered [pain_hit] as your [absorber] deflects it!</span>")
apply_damage(hurt_value_pain,HALLOSS,def_zone)
if(hurt_value_bruise)
apply_damage(hurt_value_bruise,BRUTE,def_zone)
P.sub_velocity(P.velocity)
return 2
else //Now the FUN begins
var/area_over_mass = P.diam * P.diam / P.grains
//Most of these calculations don't involve energies because I'm treating flesh and organic tissue as a fluid since it's squishy and stuff.
//Since drag is proportional to velocity, we can do things on an m*v basis instead of an mv^2 basis.
//Obviously bones are more solid, so we do actual energy calculations for that.
var/energy_dumped_organic = 0
var/vel_lost_armor = ballistic_armor >= ARMOR_LOSS_MIN_ARMOR ? ARMOR_LOSS_COEFFICIENT * area_over_mass * ((1 + ARMOR_LOSS_MIN_MULT) - penetration_chance) : 0
P.sub_velocity(vel_lost_armor)
var/energy_past = P.energy
var/internal_loss = INTERNAL_LOSS_COEFFICIENT * area_over_mass
var/vel_lost_skin = SKIN_LOSS_COEFFICIENT * area_over_mass
P.sub_velocity(vel_lost_skin + internal_loss)
energy_dumped_organic += (energy_past - P.energy)
if(prob(PROB_LEAVE_EARLY_FIRST) || !P.velocity)
energy_to_damage(energy_dumped_organic)
return 1
if(hit_organ)
return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor)
else
return general_handle_ballistics(P,def_zone,energy_dumped_organic,internal_loss,ballistic_armor)
/mob/living/proc/organ_handle_ballistics(var/obj/item/projectile/bullet/P,var/obj/item/organ/external/hit_organ,var/energy_dumped_organic,var/internal_loss,var/ballistic_armor)
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
if(hit_organ.encased)
bone_chance = BONE_HIT_CHANCE_ENCASED
else
bone_chance = BONE_HIT_CHANCE[hit_organ.organ_tag]
if(prob(bone_chance))
var/energy_to_fracture = max(300, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*BONE_JOULES_PERHP_DEV + BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic)
return 2
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(!(hit_organ & ORGAN_BROKEN))
hit_organ.fracture()
if(hit_organ.internal_organs.len && P.velocity > area_over_mass*ORGAN_LOSS_COEFFICIENT && prob(90))
energy_past = P.energy
P.sub_velocity(internal_loss)
damage_organ_energy(energy_past - P.energy, pick(hit_organ.internal_organs))
if(!P.velocity)
energy_to_damage(energy_dumped_organic)
return 2
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += P.energy
if(!P.velocity || (hit_organ.organ_tag in ORGAN_LEAVE_EARLY) || prob(PROB_LEAVE_EARLY_SECOND))
energy_to_damage(energy_dumped_organic)
return P.velocity ? -1 : 2
if(prob(bone_chance))
var/energy_to_fracture = max(300, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*BONE_JOULES_PERHP_DEV + BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic)
return 2
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(!(hit_organ & ORGAN_BROKEN))
hit_organ.fracture()
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += P.energy
if(!P.velocity)
energy_to_damage(energy_dumped_organic)
return 2
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
energy_to_damage(energy_dumped_organic)
return -1
else
return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor)
/mob/living/proc/general_handle_ballistics(var/obj/item/projectile/bullet/P,var/def_zone,var/energy_dumped_organic,var/internal_loss,var/ballistic_armor)
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
if(prob(bone_chance))
var/energy_to_fracture = max(300, BONE_HP_AVG * (GAUSSIAN_RANDOM()*BONE_JOULES_PERHP_DEV + BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic)
return 2
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(P.velocity > area_over_mass * ORGAN_LOSS_COEFFICIENT && prob(HIT_VITAL_ORGAN_CHANCE))
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += (energy_past - P.energy) * 2
if(!P.velocity)
energy_to_damage(energy_dumped_organic)
return 2
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += P.energy
if(!P.velocity || (def_zone in ORGAN_LEAVE_EARLY) || prob(PROB_LEAVE_EARLY_SECOND))
energy_to_damage(energy_dumped_organic)
return P.velocity ? -1 : 2
if(prob(bone_chance))
var/energy_to_fracture = max(300, BONE_HP_AVG * (GAUSSIAN_RANDOM()*BONE_JOULES_PERHP_DEV + BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic)
return 2
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += P.energy
if(!P.velocity)
energy_to_damage(energy_dumped_organic)
return 2
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
energy_to_damage(energy_dumped_organic)
return -1
else
return general_handle_ballistics(P,def_zone,energy_dumped_organic,internal_loss,ballistic_armor)
/mob/living/proc/damage_organ_energy(var/energy,var/obj/item/organ/internal/target)
log_and_message_admins("damage_organ_energy([energy])")
return
/mob/living/proc/energy_to_damage(var/energy)
log_and_message_admins("energy_to_damage([energy])")
return
/mob/living/proc/armor_penetration_probability(var/armor, var/obj/item/projectile/bullet/P)
var/bullet_ap_value = (1+((P.armor_penetration)/BULLET_AP_DIVISOR))
var/ap_value = P.velocity * bullet_ap_value * (P.grains / P.diam)**(2/3) / AP_DIVISOR
var/armor_value = ARMOR_Y_INTERCEPT + ARMOR_SLOPE * armor
var/penetration_chance = 100 / (1 + PENETRATION_PROBABILITY_EXP_BASE**(-PENETRATION_PROBABILITY_EXP_MULT*(ap_value - armor_value)))
return penetration_chance
/mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone)
if(P.check_armour == "bullet")
return handle_ballistics(P,def_zone)
else
return ..()
#undef BULLET_AP_DIVISOR
#undef AP_DIVISOR
#undef ARMOR_Y_INTERCEPT
#undef ARMOR_SLOPE
#undef PENETRATION_PROBABILITY_EXP_BASE
#undef PENETRATION_PROBABILITY_EXP_MULT
#undef BULLET_DEFLECTED_PAIN_DIVISOR
#undef BULLET_DEFLECTED_BULLET_DIVISOR
#undef BULLET_DEFLECTED_MELEE_DIVISOR
#undef SKIN_LOSS_COEFFICIENT
#undef ARMOR_LOSS_COEFFICIENT
#undef ARMOR_LOSS_MIN_MULT
#undef ARMOR_LOSS_MIN_ARMOR
#undef INTERNAL_LOSS_COEFFICIENT
#undef ORGAN_LOSS_COEFFICIENT
#undef ORGAN_LEAVE_EARLY
#undef HIT_ORGAN_CHANCE_VITALS
#undef HIT_VITAL_ORGAN_CHANCE
#undef BONE_HIT_CHANCE
#undef BONE_HIT_CHANCE_UNENCASED
#undef BONE_HIT_CHANCE_ENCASED
#undef BONE_JOULES_PERHP_AVG
#undef BONE_JOULES_PERHP_DEV
#undef BONE_HP_AVG
#undef PROB_LEAVE_EARLY_FIRST
#undef PROB_LEAVE_EARLY_SECOND

View File

@@ -105,6 +105,7 @@
bolt_name="charging handle"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY | CHAMBER_ON_RELOAD
bolt_release = null
muzzle_velocity = 853
/obj/item/weapon/gun/projectile/revolvingrifle
manual_chamber = FALSE

View File

@@ -14,6 +14,10 @@
#define BOLT_CASING_EJECTED 16
#define BOLT_CASING_CHAMBERED 32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// CADYN'S BALLISTICS ////////////////////////////////////////////////////////////////////////// ORIGINAL FROM CHOMPSTATION ////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/item/weapon/gun/projectile
var/manual_chamber = TRUE
var/auto_loading_type = CLOSED_BOLT | LOCK_MANUAL_LOCK | LOCK_SLAPPABLE
@@ -21,6 +25,7 @@
var/bolt_open = FALSE
var/bolt_locked = FALSE
var/bolt_release = "bolt release"
var/muzzle_velocity = 500 // meters per second
/obj/item/weapon/gun/projectile/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0)
if(fire_anim)
@@ -415,4 +420,11 @@
set category = "Object"
set src in view(1)
switch_firemodes(usr)
switch_firemodes(usr)
/obj/item/weapon/gun/projectile/process_accuracy(obj/projectile, mob/living/user, atom/target, var/burst, var/held_twohanded)
. = ..()
var/obj/item/projectile/bullet/P = projectile
if(!istype(P))
return
P.velocity = muzzle_velocity

View File

@@ -581,6 +581,13 @@
if(check_penetrate(A))
passthrough = TRUE
penetrating--
//CHOMPEdit Begin
var/obj/item/projectile/bullet/this = src
if(istype(this))
if(!this.velocity)
passthrough = FALSE
penetrating = 0
//CHOMPEdit End
if(passthrough)
trajectory_ignore_forcemove = TRUE

View File

@@ -0,0 +1,25 @@
#define GRAINS_PER_KG 15432.4
/obj/item/projectile/bullet
var/diam = 9 //mm
var/velocity = 500 //Meters per second
var/hollow_point = FALSE
var/grains = 115 //I hope the unit is obvious
var/energy //Joules
/obj/item/projectile/bullet/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0)
energy = velocity * velocity * (grains / GRAINS_PER_KG)
return ..()
/obj/item/projectile/bullet/proc/sub_velocity(var/amount)
velocity = max(0,velocity - amount)
energy = velocity * velocity * (grains / GRAINS_PER_KG)
/obj/item/projectile/bullet/proc/sub_energy(var/amount)
energy = max(0,energy - amount)
velocity = sqrt(2*energy/(grains / GRAINS_PER_KG))
/obj/item/projectile/bullet/rifle/a762
diam = 7.62
velocity = 700
grains = 123

View File

@@ -2610,6 +2610,7 @@
#include "code\modules\mob\language\station_YW.dm"
#include "code\modules\mob\language\synthetic.dm"
#include "code\modules\mob\living\autohiss.dm"
#include "code\modules\mob\living\bullet_act_ch.dm"
#include "code\modules\mob\living\damage_procs.dm"
#include "code\modules\mob\living\death.dm"
#include "code\modules\mob\living\default_language.dm"
@@ -3496,6 +3497,7 @@
#include "code\modules\projectiles\projectile\beams_vr.dm"
#include "code\modules\projectiles\projectile\blob.dm"
#include "code\modules\projectiles\projectile\bullets.dm"
#include "code\modules\projectiles\projectile\bullets_ch.dm"
#include "code\modules\projectiles\projectile\bullets_vr.dm"
#include "code\modules\projectiles\projectile\change.dm"
#include "code\modules\projectiles\projectile\energy.dm"