Merge pull request #788 from cadyn/ballistics-v2

Ballistics v2
This commit is contained in:
Razgriz
2020-11-11 19:32:40 -07:00
committed by GitHub
7 changed files with 896 additions and 14 deletions
+301
View File
@@ -0,0 +1,301 @@
#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 BULLET_DEFLECTED_PAIN_EXPONENT 1.5
#define BULLET_DEFLECTED_BRUISE_SUBTRACT 5
GLOBAL_VAR_INIT(SKIN_LOSS_COEFFICIENT,16)
GLOBAL_VAR_INIT(ARMOR_LOSS_COEFFICIENT,150)
GLOBAL_VAR_INIT(ARMOR_LOSS_MIN_MULT,0.5)
GLOBAL_VAR_INIT(ARMOR_LOSS_MIN_ARMOR,20)
GLOBAL_VAR_INIT(INTERNAL_LOSS_COEFFICIENT,195)
#define ORGAN_LOSS_COEFFICIENT 350
#define HIT_VITAL_ORGAN_CHANCE 35
#define BONE_HIT_CHANCE_UNENCASED 45
#define BONE_HIT_CHANCE_ENCASED 80
GLOBAL_VAR_INIT(BONE_JOULES_PERHP_AVG,2)
GLOBAL_VAR_INIT(BONE_JOULES_PERHP_DEV,1)
GLOBAL_VAR_INIT(BONE_JOULES_MIN,100)
#define BONE_HP_AVG 25
GLOBAL_VAR_INIT(HOLLOW_POINT_VELLOSS_BONUS,2.35)
GLOBAL_VAR_INIT(HOLLOW_POINT_CONVERSION_EFF,1.15)
#define PROB_LEAVE_EARLY_FIRST 20
#define PROB_LEAVE_EARLY_SECOND 40
GLOBAL_VAR_INIT(ENERGY_DAMAGE_FLESH_FACTOR,0.03)
GLOBAL_VAR_INIT(ENERGY_DAMAGE_ORGAN_FACTOR,0.035)
#ifndef GAUSSIAN_RANDOM
#define GAUSSIAN_RANDOM(vars...) ((-2*log(rand()))**0.5 * cos(6.28318530718*rand()))
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// CADYN'S BALLISTICS ////////////////////////////////////////////////////////////////////////// ORIGINAL FROM CHOMPSTATION ////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/mob/living/proc/handle_ballistics(var/obj/item/projectile/bullet/P, var/def_zone)
var/list/updated_organ_weight = list()
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)
for(var/ext_organ in ballistic_variables["organ_hit_weight"])
var/list/input = list()
var/obj/item/organ/external/ref_ext_organ = H.get_organ(ext_organ)
for(var/int_organ in ballistic_variables["organ_hit_weight"][ext_organ])
var/ref_int_organ = H.internal_organs_by_name[int_organ]
if(ref_ext_organ && ref_int_organ && (ref_int_organ in ref_ext_organ.internal_organs))
input[ref_int_organ] = ballistic_variables["organ_hit_weight"][ext_organ][int_organ]
if(input.len)
updated_organ_weight[ref_ext_organ] = input
//log_and_message_admins("Beginning handle_ballistics")
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(!prob(penetration_chance)) //Boo-hoo we got deflected. Do boring agony/bruises stuff.
//log_and_message_admins("Bullet deflected")
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/BULLET_DEFLECTED_BULLET_DIVISOR + melee_armor/BULLET_DEFLECTED_MELEE_DIVISOR)) //Better armor spreads out the energy better.
var/hurt_value_pain = hurt_value ** BULLET_DEFLECTED_PAIN_EXPONENT
var/hurt_value_bruise = max(0,hurt_value-BULLET_DEFLECTED_BRUISE_SUBTRACT)
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
//log_and_message_admins("Bullet penetrated")
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/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
var/vel_loss_multiplier = P.hollow_point ? GLOB.HOLLOW_POINT_VELLOSS_BONUS : 1
var/energy_dumped_organic = 0
var/vel_lost_armor = ballistic_armor >= GLOB.ARMOR_LOSS_MIN_ARMOR ? GLOB.ARMOR_LOSS_COEFFICIENT * area_over_mass * ((1 + GLOB.ARMOR_LOSS_MIN_MULT) - penetration_chance/100) : 0
P.sub_velocity(vel_lost_armor)
var/energy_past = P.energy
var/internal_loss = vel_loss_multiplier * GLOB.INTERNAL_LOSS_COEFFICIENT * area_over_mass
var/vel_lost_skin = vel_loss_multiplier * GLOB.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 * conversion_efficiency,def_zone)
return 1
if(hit_organ)
//log_and_message_admins("organ_handle_ballistics called. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor,updated_organ_weight)
else
//log_and_message_admins("general_handle_ballistics called.")
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/list/updated_organ_weight)
var/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
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 = ballistic_variables["bone_chance_unencased"][hit_organ.organ_tag]
//log_and_message_admins("Bone hit chance is [bone_chance], organ is [hit_organ]")
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
//log_and_message_admins("Bone hit, bone_chance1. energy_to_fracture = [energy_to_fracture]")
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)
//log_and_message_admins("Insufficient projectile energy. Stopping projectile.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
else
//log_and_message_admins("Sufficient projectile energy to pass through bone.")
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.status & ORGAN_BROKEN))
//log_and_message_admins("Fracturing [hit_organ]")
hit_organ.fracture()
//log_and_message_admins("Bone checking done. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
if(hit_organ.internal_organs.len && P.velocity > area_over_mass*ORGAN_LOSS_COEFFICIENT && prob(ballistic_variables["organ_hit_chance"][hit_organ.organ_tag]) && updated_organ_weight[hit_organ] && updated_organ_weight[hit_organ].len)
//log_and_message_admins("Organ was hit by bullet.")
energy_past = P.energy
P.sub_velocity(internal_loss)
damage_organ_energy((energy_past - P.energy) * conversion_efficiency, pickweight(updated_organ_weight[hit_organ]))
if(!P.velocity)
//log_and_message_admins("Organ stopped bullet.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
//log_and_message_admins("Organ check done, hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (hit_organ.organ_tag in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return P.velocity ? -1 : 2
//log_and_message_admins("Internal_loss 2 stopped bullet")
//log_and_message_admins("Internal_loss 2 completed, hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
//log_and_message_admins("Bone hit, bone_chance1. energy_to_fracture = [energy_to_fracture]")
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)
//log_and_message_admins("Insufficient projectile energy. Stopping projectile.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
else
//log_and_message_admins("Sufficient projectile energy to pass through bone.")
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.status & ORGAN_BROKEN))
//log_and_message_admins("Fracturing [hit_organ]")
hit_organ.fracture()
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity)
//log_and_message_admins("Internal_loss 3 stopped bullet")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
//log_and_message_admins("Internal_loss 3 completed. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
//log_and_message_admins("Projectile exiting.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return -1
else
//log_and_message_admins("Projectile continuing inside body")
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
/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/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
//if(def_zone in ballistic_variables["bone_chance_unencased"])
//bone_chance = ballistic_variables["bone_chance_unencased"][def_zone]
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, BONE_HP_AVG * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.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 * conversion_efficiency,def_zone)
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) * 1.5
if(!P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (def_zone in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return P.velocity ? -1 : 2
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, BONE_HP_AVG * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.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 * conversion_efficiency,def_zone)
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 += energy_past - P.energy
if(!P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return -1
else
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
/mob/living/proc/damage_organ_energy(var/energy,var/obj/item/organ/internal/target)
var/damage = round(energy*GLOB.ENERGY_DAMAGE_ORGAN_FACTOR)
//log_and_message_admins("damage_organ_energy([energy]) : [target].take_damage([damage])")
target.take_damage(damage)
return
/mob/living/proc/energy_to_damage(var/energy,var/def_zone)
var/damage = round(energy*GLOB.ENERGY_DAMAGE_FLESH_FACTOR)
//log_and_message_admins("energy_to_damage([energy]) : apply_damage([damage], BRUTE, [def_zone])")
apply_damage(damage, BRUTE, def_zone)
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)
//log_and_message_admins("bullet_act_ch")
var/obj/item/projectile/bullet/B = P
if(P.check_armour == "bullet" && istype(B) && !B.old_bullet_act)
//log_and_message_admins("is bullet")
return handle_ballistics(P,def_zone)
else
//log_and_message_admins("is not bullet")
return ..()
/mob/living
var/list/ballistic_variables = list(\
"bone_chance_unencased" = list(BP_HEAD = 5, BP_TORSO = 20, BP_GROIN = 20, BP_L_FOOT = 80, BP_R_FOOT = 80, BP_L_LEG = 35, BP_R_LEG = 35, BP_L_ARM = 65, BP_R_ARM = 65, BP_L_HAND = 80, BP_R_HAND = 80), \
"organ_leave_early" = list("l_arm", "r_arm", "l_hand", "r_hand", "l_foot", "r_foot"), \
"organ_hit_weight" = list(\
BP_HEAD = list(\
/*Standard organs*/O_BRAIN = 90, O_EYES = 5, \
/*Diona organs*/O_RESPONSE = 10, O_RESPONSE = 15, O_GBLADDER = 15, \
/*Replicant organs*/O_VRLINK = 20, \
/*Xeno organs*/O_ACID = 10, O_RESIN = 10), \
BP_TORSO = list(\
/*Standard organs*/O_HEART = 5, O_LUNGS = 50, O_SPLEEN = 15, O_VOICE = 10, \
/*Synth organs*/O_CELL = 5, O_PUMP = 15, O_HEATSINK = 35, O_CYCLER = 15, O_DIAGNOSTIC = 10, \
/*Promethean organs*/O_REGBRUTE = 20, O_REGBURN = 20, O_REGOXY = 20, O_REGTOX = 20, \
/*Diona organs*/O_STRATA = 35, O_BRAIN = 20, O_NUTRIENT = 10, \
/*Replicant organs*/O_AREJECT = 35, \
/*Xeno organs*/O_PLASMA = 10, O_HIVE = 10), \
BP_GROIN = list(\
/*Standard organs*/O_INTESTINES = 50, O_STOMACH = 20, O_LIVER = 20, O_KIDNEYS = 15, O_APPENDIX = 5, \
/*Diona organs*/O_POLYP = 10, O_ANCHOR = 15, \
/*Replicant organs*/O_VENTC = 20, \
/*Xeno organs*/ O_EGG = 25) ), \
"organ_hit_chance" = list(BP_HEAD = 95, BP_TORSO = 90, BP_GROIN = 90) )
@@ -0,0 +1,236 @@
#define BULLET_PENETRATED 1<<0
#define BULLET_BONECHECK1_TRUE 1<<1
#define BULLET_ORGANCHECK_TRUE 1<<2
#define BULLET_BONECHECK2_TRUE 1<<3
#define BULLET_PASSED_LEAVE_EARLY 1<<4
#define BULLET_PASSED_BONECHECK1 1<<5
#define BULLET_PASSED_ORGANCHECK 1<<6
#define BULLET_PASSED_INTERNALCHECK2 1<<7
#define BULLET_PASSED_BONECHECK2 1<<8
#define BULLET_PASSED_INTERNALCHECK3 1<<9
#define BULLET_TESTS 150
/mob/living/carbon/human/monkey/testerboyo
name = "testerboyo"
var/the_big_armor = 0
/mob/living/carbon/human/monkey/testerboyo/getarmor(var/def_zone,var/type)
return the_big_armor
/proc/test_all_ballistics()
var/mob/living/carbon/human/monkey/testerboyo/tester = new()
var/obj/item/projectile/bullet/pistol/test1 = new()
var/obj/item/projectile/bullet/pistol/ap/test2 = new()
var/obj/item/projectile/bullet/pistol/hp/test3 = new()
var/obj/item/projectile/bullet/pistol/medium/test4 = new()
var/obj/item/projectile/bullet/pistol/medium/ap/test5 = new()
var/obj/item/projectile/bullet/pistol/medium/hp/test6 = new()
var/obj/item/projectile/bullet/pistol/strong/test7 = new()
var/obj/item/projectile/bullet/shotgun/test8 = new()
var/obj/item/projectile/bullet/shotgun/buckshot/test9 = new()
var/obj/item/projectile/bullet/rifle/a762/test10 = new()
var/obj/item/projectile/bullet/rifle/a762/ap/test11 = new()
var/obj/item/projectile/bullet/rifle/a762/hp/test12 = new()
var/obj/item/projectile/bullet/rifle/a545/test13 = new()
var/obj/item/projectile/bullet/rifle/a545/ap/test14 = new()
var/obj/item/projectile/bullet/rifle/a545/hp/test15 = new()
var/obj/item/projectile/bullet/rifle/a145/test16 = new()
var/obj/item/projectile/bullet/rifle/a145/highvel/test17 = new()
var/obj/item/projectile/bullet/rifle/a44rifle/test18 = new()
var/obj/item/projectile/bullet/rifle/a95/test19 = new()
var/obj/item/projectile/bullet/rifle/a762/lmg/test20 = new()
test_ballistics(test1,tester)
test_ballistics(test2,tester)
test_ballistics(test3,tester)
test_ballistics(test4,tester)
test_ballistics(test5,tester)
test_ballistics(test6,tester)
test_ballistics(test7,tester)
test_ballistics(test8,tester)
test_ballistics(test9,tester)
test_ballistics(test10,tester)
test_ballistics(test11,tester)
test_ballistics(test12,tester)
test_ballistics(test13,tester)
test_ballistics(test14,tester)
test_ballistics(test15,tester)
test_ballistics(test16,tester)
test_ballistics(test17,tester)
test_ballistics(test18,tester)
test_ballistics(test19,tester)
test_ballistics(test20,tester)
qdel(tester)
qdel(test1)
qdel(test2)
qdel(test3)
qdel(test4)
qdel(test5)
qdel(test6)
qdel(test7)
qdel(test8)
qdel(test9)
qdel(test10)
qdel(test11)
qdel(test12)
qdel(test13)
qdel(test14)
qdel(test15)
qdel(test16)
qdel(test17)
qdel(test18)
qdel(test19)
qdel(test20)
/proc/test_ballistics(var/obj/item/projectile/bullet/P,var/mob/living/carbon/human/monkey/testerboyo/tester)
var/list/data = list()
for(var/armor_level in list(0,5,10,20,50,80))
data["[armor_level]"] = list()
data["[armor_level]"]["average"] = list()
tester.the_big_armor = armor_level
var/bp_num = 0
for(var/body_part in list(BP_TORSO,BP_HEAD,BP_R_LEG,BP_R_ARM,BP_R_HAND))
bp_num++
data["[armor_level]"][body_part] = list()
for(var/i = 0,i<BULLET_TESTS,i++)
P.velocity = initial(P.velocity)
P.sub_velocity(0)
var/out = tester.handle_ballistics(P,body_part)
for(var/x = 0,x<10,x++)
var/input = (out["chex"] & (1<<x)) ? 1 : 0
data["[armor_level]"][body_part]["[x]"] += input
data["[armor_level]"]["average"]["[x]"] += input
data["[armor_level]"][body_part]["10"] += out["energy"]
data["[armor_level]"][body_part]["10"] /= BULLET_TESTS
data["[armor_level]"]["average"]["10"] += data["[armor_level]"][body_part]["10"]
for(var/x = 0,x<11,x++)
data["[armor_level]"]["average"]["[x]"] /= bp_num
for(var/entry in data["[armor_level]"])
var/string_to_send = "[P.type]: Armor level [armor_level]: [entry]:"
for(var/x = 0,x<11,x++)
string_to_send += " [x]:[data["[armor_level]"][entry]["[x]"]]"
log_and_message_admins(string_to_send)
/proc/lazy_return_testing(var/chex,var/energy)
return list("chex" = chex, "energy" = energy)
/mob/living/carbon/human/monkey/testerboyo/handle_ballistics(var/obj/item/projectile/bullet/P, var/def_zone)
var/chex = 0
var/list/updated_organ_weight = list()
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)
for(var/ext_organ in ballistic_variables["organ_hit_weight"])
var/list/input = list()
var/obj/item/organ/external/ref_ext_organ = H.get_organ(ext_organ)
for(var/int_organ in ballistic_variables["organ_hit_weight"][ext_organ])
var/ref_int_organ = H.internal_organs_by_name[int_organ]
if(ref_ext_organ && ref_int_organ && (ref_int_organ in ref_ext_organ.internal_organs))
input[ref_int_organ] = ballistic_variables["organ_hit_weight"][ext_organ][int_organ]
if(input.len)
updated_organ_weight[ref_ext_organ] = input
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/BULLET_DEFLECTED_BULLET_DIVISOR + melee_armor/BULLET_DEFLECTED_MELEE_DIVISOR)) //Better armor spreads out the energy better.
var/hurt_value_pain = hurt_value ** BULLET_DEFLECTED_PAIN_EXPONENT
var/hurt_value_bruise = max(0,hurt_value-BULLET_DEFLECTED_BRUISE_SUBTRACT)
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 lazy_return_testing(chex,0)
else //Now the FUN begins
chex |= BULLET_PENETRATED
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/conversion_efficiency = P.hollow_point ? 0.925 : 1
var/vel_loss_multiplier = P.hollow_point ? GLOB.HOLLOW_POINT_VELLOSS_BONUS : 1
var/energy_dumped_organic = 0
var/vel_lost_armor = ballistic_armor >= GLOB.ARMOR_LOSS_MIN_ARMOR ? GLOB.ARMOR_LOSS_COEFFICIENT * area_over_mass * ((1 + GLOB.ARMOR_LOSS_MIN_MULT) - penetration_chance/100) : 0
P.sub_velocity(vel_lost_armor)
var/energy_past = P.energy
var/internal_loss = vel_loss_multiplier * GLOB.INTERNAL_LOSS_COEFFICIENT * area_over_mass
var/vel_lost_skin = vel_loss_multiplier * GLOB.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)
return lazy_return_testing(chex,energy_dumped_organic)
if(hit_organ)
chex |= BULLET_PASSED_LEAVE_EARLY
return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor,updated_organ_weight,chex)
else
return general_handle_ballistics(P,def_zone,energy_dumped_organic,internal_loss,ballistic_armor)
/mob/living/carbon/human/monkey/testerboyo/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/list/updated_organ_weight,var/chex)
//var/conversion_efficiency = P.hollow_point ? 0.8 : 1
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 = ballistic_variables["bone_chance_unencased"][hit_organ.organ_tag]
if(prob(bone_chance))
chex |= BULLET_BONECHECK1_TRUE
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.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)
return lazy_return_testing(chex,energy_dumped_organic)
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += energy_to_fracture / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
chex |= BULLET_PASSED_BONECHECK1
if(hit_organ.internal_organs.len && P.velocity > area_over_mass*ORGAN_LOSS_COEFFICIENT && prob(ballistic_variables["organ_hit_chance"][hit_organ.organ_tag]) && updated_organ_weight[hit_organ] && updated_organ_weight[hit_organ].len)
chex |= BULLET_ORGANCHECK_TRUE
energy_past = P.energy
P.sub_velocity(internal_loss)
if(!P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_ORGANCHECK
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (hit_organ.organ_tag in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_INTERNALCHECK2
if(prob(bone_chance))
chex |= BULLET_BONECHECK2_TRUE
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.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)
return lazy_return_testing(chex,energy_dumped_organic)
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += energy_to_fracture / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
chex |= BULLET_PASSED_BONECHECK2
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_INTERNALCHECK3
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
return lazy_return_testing(chex,energy_dumped_organic)
else
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
@@ -2,30 +2,80 @@
/obj/item/weapon/gun/projectile/automatic
bolt_name="charging handle"
/obj/item/weapon/gun/projectile/automatic/mini_uzi
auto_loading_type = OPEN_BOLT
/obj/item/weapon/gun/projectile/automatic/advanced_smg
muzzle_velocity = 390 //Based off MPX
/obj/item/weapon/gun/projectile/automatic/tommygun
auto_loading_type = OPEN_BOLT
/obj/item/weapon/gun/projectile/automatic/c20r
muzzle_velocity = 285 //Based off UMP-45, since apparently this 10mm smg fires .45 ftw. May be fixed in future updates.
/obj/item/weapon/gun/projectile/automatic/sts35
muzzle_velocity = 900 //Based off AK-74
/obj/item/weapon/gun/projectile/automatic/wt550
muzzle_velocity = 375 //Guestimation
/obj/item/weapon/gun/projectile/automatic/z8
muzzle_velocity = 750 //Based off HK417 16 in barrel.
/obj/item/weapon/gun/projectile/automatic/l6_saw
bolt_name="charging_handle"
bolt_name="charging handle"
auto_loading_type = OPEN_BOLT
bolt_release = null
muzzle_velocity = 960 //Prototype PU-21(https://en.wikipedia.org/wiki/IP-2)
/obj/item/weapon/gun/projectile/automatic/as24
muzzle_velocity = 470 //Temporary, might be changed.
/obj/item/weapon/gun/projectile/automatic/mini_uzi
auto_loading_type = OPEN_BOLT
muzzle_velocity = 280 //Mac-10 .45
/obj/item/weapon/gun/projectile/automatic/p90 //Finally a gun that exists irl. oh wait fuck they decided to chamber the p90 in 9mm kms
muzzle_velocity = 397 //Guestimation. Will hopefully be able to replace with actual 5.7mm at some point.
/obj/item/weapon/gun/projectile/automatic/tommygun //Phew, an actual gun that fires the correct cartridge.
auto_loading_type = OPEN_BOLT
muzzle_velocity = 285
/obj/item/weapon/gun/projectile/automatic/bullpup
muzzle_velocity = 880 //7.62 NATO Bullpup was unsurprisingly difficult to find https://en.wikipedia.org/wiki/Kel-Tec_RFB
/obj/item/weapon/gun/projectile/automatic/combatsmg
muzzle_velocity = 370 //Guestimation
//automatic_vr.dm
/obj/item/weapon/gun/projectile/automatic/battlerifle
muzzle_velocity = 370 //Not a real rifle or cartridge. Guestimating.
/obj/item/weapon/gun/projectile/automatic/pdw
muzzle_velocity = 390 //MPX
/obj/item/weapon/gun/projectile/automatic/stg
muzzle_velocity = 685 //STG-44
/obj/item/weapon/gun/projectile/automatic/sol
muzzle_velocity = 380 //Guestimation
//automatic_yw.dm
/obj/item/weapon/gun/projectile/automatic/mg42
bolt_name="charging_handle"
bolt_name="charging handle"
auto_loading_type = OPEN_BOLT
bolt_release = null
muzzle_velocity = 740 //Real gun.
//boltaction.dm
/obj/item/weapon/gun/projectile/shotgun/pump/rifle
muzzle_velocity = 860 //Guestimation
//caseless.dm
/obj/item/weapon/gun/projectile/caseless
bolt_name="charging handle"
muzzle_velocity = 380 //Based of 9mm, because this fires 9mm projectiles. Will be fixed in future updates, likely.
//contender.dm
/obj/item/weapon/gun/projectile/contender
/obj/item/weapon/gun/projectile/contender //To be updated to use .357
manual_chamber = FALSE
muzzle_velocity = 370
//dartgun.dm
/obj/item/weapon/gun/projectile/dartgun
@@ -34,82 +84,144 @@
//pistol.dm
/obj/item/weapon/gun/projectile/colt
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 253 //M1911
/obj/item/weapon/gun/projectile/sec
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 253 //M1911
/obj/item/weapon/gun/projectile/silenced
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 240 //Guestimation, minus velocity for suppressor
/obj/item/weapon/gun/projectile/deagle
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 430 //Guestimation, everyone uses .50AE lol
/obj/item/weapon/gun/projectile/gyropistol
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
/obj/item/weapon/gun/projectile/pistol
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 300 //P365
/obj/item/weapon/gun/projectile/pirate
manual_chamber = FALSE
/obj/item/weapon/gun/projectile/derringer
manual_chamber = FALSE
muzzle_velocity = 350 //Guestimation
/obj/item/weapon/gun/projectile/luger
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 350 //Luger
/obj/item/weapon/gun/projectile/p92x
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 370
//pistol_vr.dm
/obj/item/weapon/gun/projectile/lamia
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 400 //Guestimation
/obj/item/weapon/gun/projectile/giskard
/obj/item/weapon/gun/projectile/giskard //To be updated to .380
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 300 //Guestimation
//pistol_yw.dm
/obj/item/weapon/gun/projectile/automatic/glock
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 375 //Actual gun.
/obj/item/weapon/gun/projectile/ppk
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 310 //Guestimation since PPK doesn't fire 9mm
/obj/item/weapon/gun/projectile/m2024
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 260 //Guestimation
/obj/item/weapon/gun/projectile/fluff/m1911
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 253 //M1911
//revolver.dm
/obj/item/weapon/gun/projectile/revolver
/obj/item/weapon/gun/projectile/revolver //To be updated to use .375
manual_chamber = FALSE
muzzle_velocity = 330 //Guestimation
/obj/item/weapon/gun/projectile/revolver/detective //To be updated to use .38
muzzle_velocity = 350 //Guestimation
/obj/item/weapon/gun/projectile/revolver/detective45 //Awful.
muzzle_velocity = 230 //Guestimation
/obj/item/weapon/gun/projectile/revolver/deckard //To be updated to use .38
muzzle_velocity = 365
/obj/item/weapon/gun/projectile/revolver/judge
muzzle_velocity = 440 //Temporary
/obj/item/weapon/gun/projectile/revolver/lemat
muzzle_velocity = 365
/obj/item/weapon/gun/projectile/revolver/webley
muzzle_velocity = 340 //Guestimation
/obj/item/weapon/gun/projectile/revolver/consul
muzzle_velocity = 350 //Guestimation
/obj/item/weapon/gun/projectile/revolver/nova
muzzle_velocity = 330 //Guestimation
/obj/item/weapon/gun/projectile/revolver/cerberus
muzzle_velocity = 340 //Guestimation
//semiauto.dm
/obj/item/weapon/gun/projectile/garand
/obj/item/weapon/gun/projectile/garand //To be updated to use .30 springfield.
bolt_name="charging handle"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY | CHAMBER_ON_RELOAD
bolt_release = null
muzzle_velocity = 853 //Actual gun.
/obj/item/weapon/gun/projectile/revolvingrifle
manual_chamber = FALSE
muzzle_velocity = 500 //Guestimation from leveraction .44 minus some for being a revolver.
//shotgun.dm
/obj/item/weapon/gun/projectile/shotgun
muzzle_velocity = 470 //Temporary
/obj/item/weapon/gun/projectile/shotgun/pump
manual_chamber = FALSE
@@ -119,10 +231,13 @@
//shotgun_yw.dm
/obj/item/weapon/gun/projectile/revolvershotgun
manual_chamber = FALSE
muzzle_velocity = 470 //Temporary
//sniper.dm
/obj/item/weapon/gun/projectile/heavysniper
manual_chamber = FALSE
muzzle_velocity = 1132 //Istiglal IST-14.5 anti-materiel rifle
/obj/item/weapon/gun/projectile/SVD
bolt_name = "charging handle"
/obj/item/weapon/gun/projectile/SVD //To be updated to use actual 7.62x54 instead of 7.62 NATO
bolt_name = "charging handle"
muzzle_velocity = 830 //Actual gun.
+30 -1
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,28 @@
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
//Special ammo handling bullshit
/obj/item/weapon/gun/projectile/pirate/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.sub_velocity(P.velocity * 0.3) //Yeah, a gun that supposedly shoots any bullet is gonna be pretty shit.
/obj/item/weapon/gun/projectile/revolver/lemat/process_accuracy(obj/projectile, mob/living/user, atom/target, var/burst, var/held_twohanded)
. = ..()
var/obj/item/projectile/bullet/P = projectile
P.velocity = initial(P.velocity)
if(!istype(P))
return
P.sub_velocity(P.velocity - 35)
+7
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
@@ -0,0 +1,191 @@
#define GRAINS_PER_KG 15432.4
/obj/item/projectile/bullet
var/diam = 9 //mm
var/energy_add = 0
var/velocity = 500 //Meters per second
var/hollow_point = FALSE
var/grains = 115 //I hope the unit is obvious
var/energy //Joules
var/old_bullet_act = FALSE
/obj/item/projectile/bullet/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0)
energy = 0.5 * velocity * velocity * (grains / GRAINS_PER_KG) + energy_add
sub_energy(0)
return ..()
/obj/item/projectile/bullet/proc/sub_velocity(var/amount)
velocity = max(0,velocity - amount)
energy = 0.5 * 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))
//Pistol projectiles
/obj/item/projectile/bullet/pistol //9x19mm
diam = 9
grains = 108
velocity = 381
/obj/item/projectile/bullet/pistol/ap
grains = 66
energy_add = 893
velocity = 595
armor_penetration = 25
/obj/item/projectile/bullet/pistol/hp
grains = 131
velocity = 350
energy_add = -96.18
hollow_point = TRUE
armor_penetration = -50
/obj/item/projectile/bullet/pistol/medium //.45
diam = 11.43
grains = 230
velocity = 295
/obj/item/projectile/bullet/pistol/medium/ap
grains = 173
energy_add = 374
velocity = 347
armor_penetration = 25
/obj/item/projectile/bullet/pistol/medium/hp
grains = 230
velocity = 286
armor_penetration = -50
/obj/item/projectile/bullet/pistol/strong //.357 and .44 are grouped because ftw
grains = 240
velocity = 360
//Shotgun projectiles
/obj/item/projectile/bullet/shotgun //Slug
grains = 657
velocity = 489
armor_penetration = -50 //Slugs needed a nerf. Will probably fix the stats for shotguns in general in future updates.
/obj/item/projectile/bullet/shotgun/buckshot //#00 Buckshot
damage = 5
name = "buckshot pellet"
diam = 8.38
grains = 53.8
velocity = 489
armor_penetration = -30
/obj/item/projectile/bullet/shotgun/buckshot/shell
use_submunitions = TRUE
submunition_spread_max = 67.5
submunitions = list(/obj/item/projectile/bullet/shotgun/buckshot = 8)
/obj/item/ammo_casing/a12g/pellet
name = "shotgun buckshot shell"
desc = "A 12 gauge buckshot shell."
icon_state = "gshell"
projectile_type = /obj/item/projectile/bullet/shotgun/buckshot/shell
//Rifle projectiles
/obj/item/projectile/bullet/rifle
armor_penetration = 0 //No. Rifle rounds don't get extra AP by default, their nature already makes them more armor penetrating.
/obj/item/projectile/bullet/rifle/a762 //7.62x51 NATO
diam = 7.62
grains = 147
velocity = 850
/obj/item/projectile/bullet/rifle/a762/ap
grains = 150.5
velocity = 854.6
armor_penetration = 50
/obj/item/projectile/bullet/rifle/a762/hp
grains = 175
energy_add = -539.978
velocity = 792
armor_penetration = -50
hollow_point = TRUE
/obj/item/projectile/bullet/rifle/a545
diam = 5.45
grains = 53
velocity = 880
/obj/item/projectile/bullet/rifle/a545/ap
grains = 57
velocity = 890
armor_penetration = 50
/obj/item/projectile/bullet/rifle/a545/hp
hollow_point = TRUE
armor_penetration = -50
/obj/item/projectile/bullet/rifle/a145 // 14.5×114mm
grains = 921
velocity = 1000
/obj/item/projectile/bullet/rifle/a145/highvel
grains = 700
energy_add = 9979
velocity = 1200
/obj/item/projectile/bullet/rifle/a44rifle
diam = 10.9
grains = 240
velocity = 536.448
/obj/item/projectile/bullet/rifle/a95 //I hate you. There is no real world analog for 9.5x40mm, I will guestimate from the 9x39mm russian round and give it some bonus for future points or whatever
diam = 9.5
grains = 310
velocity = 365
/obj/item/projectile/bullet/rifle/a762/lmg //This is actually 7.92x57 ffs
diam = 7.92
grains = 181
velocity = 820
//Various "We're not dealing with this shit because of how bad it is" (Some of these may be implemented into the new system with later updates)
/obj/item/projectile/bullet/magnetic
old_bullet_act = TRUE
/obj/item/projectile/bullet/pellet
old_bullet_act = TRUE
/obj/item/projectile/bullet/pellet/shotgun/flak
old_bullet_act = TRUE
/obj/item/projectile/bullet/rifle/a762/hunter
old_bullet_act = TRUE
/obj/item/projectile/bullet/rifle/a545/hunter
old_bullet_act = TRUE
/obj/item/projectile/bullet/suffocationbullet
old_bullet_act = TRUE
/obj/item/projectile/bullet/cyanideround
old_bullet_act = TRUE
/obj/item/projectile/bullet/burstbullet
old_bullet_act = TRUE
/obj/item/projectile/bullet/incendiary
old_bullet_act = TRUE
/obj/item/projectile/bullet/practice
old_bullet_act = TRUE
/obj/item/projectile/bullet/blank
old_bullet_act = TRUE
/obj/item/projectile/bullet/srmrocket
old_bullet_act = TRUE
/obj/item/projectile/bullet/chemdart
old_bullet_act = TRUE
/obj/item/projectile/bullet/gyro
old_bullet_act = TRUE