From b3ba48084f1ae69b8b991fa7fa4555d13137b752 Mon Sep 17 00:00:00 2001 From: Cadyn Date: Sat, 31 Oct 2020 12:21:21 -0700 Subject: [PATCH 1/6] Ballistics v2 draft --- code/modules/mob/living/bullet_act_ch.dm | 246 ++++++++++++++++++ .../guns/projectile/ballistics_ch.dm | 1 + .../modules/projectiles/guns/projectile_ch.dm | 14 +- code/modules/projectiles/projectile.dm | 7 + .../projectiles/projectile/bullets_ch.dm | 25 ++ vorestation.dme | 2 + 6 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 code/modules/mob/living/bullet_act_ch.dm create mode 100644 code/modules/projectiles/projectile/bullets_ch.dm diff --git a/code/modules/mob/living/bullet_act_ch.dm b/code/modules/mob/living/bullet_act_ch.dm new file mode 100644 index 0000000000..c322c0bde9 --- /dev/null +++ b/code/modules/mob/living/bullet_act_ch.dm @@ -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,"You feel the energy of the bullet painfully transfered [pain_hit] as your [absorber] deflects it!") + 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 \ No newline at end of file diff --git a/code/modules/projectiles/guns/projectile/ballistics_ch.dm b/code/modules/projectiles/guns/projectile/ballistics_ch.dm index 2669b9fbe7..07b9ee4b5e 100644 --- a/code/modules/projectiles/guns/projectile/ballistics_ch.dm +++ b/code/modules/projectiles/guns/projectile/ballistics_ch.dm @@ -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 diff --git a/code/modules/projectiles/guns/projectile_ch.dm b/code/modules/projectiles/guns/projectile_ch.dm index dc5c9fa78b..dae6585aa8 100644 --- a/code/modules/projectiles/guns/projectile_ch.dm +++ b/code/modules/projectiles/guns/projectile_ch.dm @@ -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) \ No newline at end of file + 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 \ No newline at end of file diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 6cd885f0c1..cb4993c92a 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -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 diff --git a/code/modules/projectiles/projectile/bullets_ch.dm b/code/modules/projectiles/projectile/bullets_ch.dm new file mode 100644 index 0000000000..94a8d2a5e2 --- /dev/null +++ b/code/modules/projectiles/projectile/bullets_ch.dm @@ -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 \ No newline at end of file diff --git a/vorestation.dme b/vorestation.dme index f7d21bbc79..34d0e549a8 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -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" From 67499d28c5b5ea407694152ca05dd83176a786ad Mon Sep 17 00:00:00 2001 From: Cadyn Date: Mon, 2 Nov 2020 18:03:47 -0800 Subject: [PATCH 2/6] Ballistics v2 draft v2 Introducing debugging messages and actually working ballistics --- .../{bullet_act_ch.dm => zbullet_act_ch.dm} | 116 ++++++++++++++---- .../projectiles/projectile/bullets_ch.dm | 4 +- vorestation.dme | 2 +- 3 files changed, 95 insertions(+), 27 deletions(-) rename code/modules/mob/living/{bullet_act_ch.dm => zbullet_act_ch.dm} (59%) diff --git a/code/modules/mob/living/bullet_act_ch.dm b/code/modules/mob/living/zbullet_act_ch.dm similarity index 59% rename from code/modules/mob/living/bullet_act_ch.dm rename to code/modules/mob/living/zbullet_act_ch.dm index c322c0bde9..ed45118223 100644 --- a/code/modules/mob/living/bullet_act_ch.dm +++ b/code/modules/mob/living/zbullet_act_ch.dm @@ -8,6 +8,8 @@ #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 #define SKIN_LOSS_COEFFICIENT 61 #define ARMOR_LOSS_COEFFICIENT 200 @@ -15,11 +17,8 @@ #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 @@ -29,6 +28,9 @@ #define PROB_LEAVE_EARLY_FIRST 20 #define PROB_LEAVE_EARLY_SECOND 40 +#define ENERGY_DAMAGE_FLESH_FACTOR 0.02 +#define ENERGY_DAMAGE_ORGAN_FACTOR 0.03 + #define GAUSSIAN_RANDOM(vars...) ((-2*log(rand()))**0.5 * cos(6.28318530718*rand())) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -36,19 +38,32 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /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] + log_and_message_admins("Added [int_organ] with value [input[ref_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/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/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. @@ -59,6 +74,7 @@ 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. @@ -76,74 +92,95 @@ 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) + 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) +/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/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] + 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(300, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*BONE_JOULES_PERHP_DEV + 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) 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 & ORGAN_BROKEN)) + if(!(hit_organ.status & ORGAN_BROKEN)) + log_and_message_admins("Fracturing [hit_organ]") hit_organ.fracture() - - if(hit_organ.internal_organs.len && P.velocity > area_over_mass*ORGAN_LOSS_COEFFICIENT && prob(90)) + 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, pick(hit_organ.internal_organs)) + damage_organ_energy(energy_past - P.energy, pickweight(updated_organ_weight[hit_organ])) if(!P.velocity) + log_and_message_admins("Organ stopped bullet.") energy_to_damage(energy_dumped_organic) 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 += P.energy - if(!P.velocity || (hit_organ.organ_tag in ORGAN_LEAVE_EARLY) || prob(PROB_LEAVE_EARLY_SECOND)) + if(!P.velocity || (hit_organ.organ_tag in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND)) energy_to_damage(energy_dumped_organic) 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(300, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*BONE_JOULES_PERHP_DEV + 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) 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 & ORGAN_BROKEN)) + 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 += P.energy if(!P.velocity) + log_and_message_admins("Internal_loss 3 stopped bullet") energy_to_damage(energy_dumped_organic) 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) return -1 else - return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor) + log_and_message_admins("Projectile continuing inside body") + return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor,updated_organ_weight) /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(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(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! @@ -165,7 +202,7 @@ 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)) + if(!P.velocity || (def_zone in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND)) energy_to_damage(energy_dumped_organic) return P.velocity ? -1 : 2 @@ -194,11 +231,15 @@ 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])") + var/damage = round(energy*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) - log_and_message_admins("energy_to_damage([energy])") +/mob/living/proc/energy_to_damage(var/energy,var/obj/item/organ/external/def_zone) + var/damage = round(energy*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) @@ -209,11 +250,38 @@ return penetration_chance /mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone) + log_and_message_admins("bullet_act_ch") if(P.check_armour == "bullet") + 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) ) + #undef BULLET_AP_DIVISOR #undef AP_DIVISOR #undef ARMOR_Y_INTERCEPT @@ -231,16 +299,16 @@ #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 ENERGY_DAMAGE_FLESH_FACTOR +#undef ENERGY_DAMAGE_ORGAN_FACTOR + #undef PROB_LEAVE_EARLY_FIRST #undef PROB_LEAVE_EARLY_SECOND \ No newline at end of file diff --git a/code/modules/projectiles/projectile/bullets_ch.dm b/code/modules/projectiles/projectile/bullets_ch.dm index 94a8d2a5e2..57e0dc09d1 100644 --- a/code/modules/projectiles/projectile/bullets_ch.dm +++ b/code/modules/projectiles/projectile/bullets_ch.dm @@ -8,12 +8,12 @@ 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) + energy = 0.5 * 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) + energy = 0.5 * velocity * velocity * (grains / GRAINS_PER_KG) /obj/item/projectile/bullet/proc/sub_energy(var/amount) energy = max(0,energy - amount) diff --git a/vorestation.dme b/vorestation.dme index 34d0e549a8..b649de3e0d 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2610,7 +2610,6 @@ #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" @@ -2628,6 +2627,7 @@ #include "code\modules\mob\living\logout.dm" #include "code\modules\mob\living\say.dm" #include "code\modules\mob\living\status_indicators.dm" +#include "code\modules\mob\living\zbullet_act_ch.dm" #include "code\modules\mob\living\bot\bot.dm" #include "code\modules\mob\living\bot\bot_vr.dm" #include "code\modules\mob\living\bot\cleanbot.dm" From 6fa317794b61b62b8d5290901b059e975060c7b7 Mon Sep 17 00:00:00 2001 From: Cadyn Date: Thu, 5 Nov 2020 16:44:47 -0800 Subject: [PATCH 3/6] Cadyn's ballistic Overhauls V2 Finale --- code/modules/mob/living/zbullet_act_ch.dm | 193 +++++++------- .../modules/mob/living/zzballistic_test_ch.dm | 236 ++++++++++++++++++ .../guns/projectile/ballistics_ch.dm | 138 +++++++++- .../modules/projectiles/guns/projectile_ch.dm | 19 +- .../projectiles/projectile/bullets_ch.dm | 173 ++++++++++++- vorestation.dme | 1 + 6 files changed, 639 insertions(+), 121 deletions(-) create mode 100644 code/modules/mob/living/zzballistic_test_ch.dm diff --git a/code/modules/mob/living/zbullet_act_ch.dm b/code/modules/mob/living/zbullet_act_ch.dm index ed45118223..4122080548 100644 --- a/code/modules/mob/living/zbullet_act_ch.dm +++ b/code/modules/mob/living/zbullet_act_ch.dm @@ -11,25 +11,29 @@ #define BULLET_DEFLECTED_PAIN_EXPONENT 1.5 #define BULLET_DEFLECTED_BRUISE_SUBTRACT 5 -#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 +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 30 +#define HIT_VITAL_ORGAN_CHANCE 35 #define BONE_HIT_CHANCE_UNENCASED 45 #define BONE_HIT_CHANCE_ENCASED 80 -#define BONE_JOULES_PERHP_AVG 30 -#define BONE_JOULES_PERHP_DEV 10 +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 -#define ENERGY_DAMAGE_FLESH_FACTOR 0.02 -#define ENERGY_DAMAGE_ORGAN_FACTOR 0.03 +GLOBAL_VAR_INIT(ENERGY_DAMAGE_FLESH_FACTOR,0.03) +GLOBAL_VAR_INIT(ENERGY_DAMAGE_ORGAN_FACTOR,0.035) #define GAUSSIAN_RANDOM(vars...) ((-2*log(rand()))**0.5 * cos(6.28318530718*rand())) @@ -52,13 +56,12 @@ 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] - log_and_message_admins("Added [int_organ] with value [input[ref_int_organ]]") if(input.len) updated_organ_weight[ref_ext_organ] = input - log_and_message_admins("Beginning handle_ballistics") + //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") + //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. @@ -74,31 +77,35 @@ P.sub_velocity(P.velocity) return 2 else //Now the FUN begins - log_and_message_admins("Bullet penetrated") + //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 >= ARMOR_LOSS_MIN_ARMOR ? ARMOR_LOSS_COEFFICIENT * area_over_mass * ((1 + ARMOR_LOSS_MIN_MULT) - penetration_chance) : 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 = INTERNAL_LOSS_COEFFICIENT * area_over_mass - var/vel_lost_skin = SKIN_LOSS_COEFFICIENT * area_over_mass + 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) + 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]") + //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.") + //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 @@ -106,87 +113,91 @@ 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]") + //log_and_message_admins("Bone hit chance is [bone_chance], organ is [hit_organ]") 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)) - log_and_message_admins("Bone hit, bone_chance1. energy_to_fracture = [energy_to_fracture]") + 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) + //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.") + //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]") + //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]") + //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.") + //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, pickweight(updated_organ_weight[hit_organ])) + 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) + //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]") + //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 += P.energy + 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) + 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]") + //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(300, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*BONE_JOULES_PERHP_DEV + BONE_JOULES_PERHP_AVG)) - log_and_message_admins("Bone hit, bone_chance1. energy_to_fracture = [energy_to_fracture]") + 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) + //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.") + //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]") + //log_and_message_admins("Fracturing [hit_organ]") hit_organ.fracture() energy_past = P.energy P.sub_velocity(internal_loss) - energy_dumped_organic += P.energy + 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) + //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]") + //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) + //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") - return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor,updated_organ_weight) + //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(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(300, BONE_HP_AVG * (GAUSSIAN_RANDOM()*BONE_JOULES_PERHP_DEV + BONE_JOULES_PERHP_AVG)) + 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) + energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone) return 2 else P.sub_energy(energy_to_fracture) @@ -195,23 +206,23 @@ 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 + energy_dumped_organic += (energy_past - P.energy) * 1.5 if(!P.velocity) - energy_to_damage(energy_dumped_organic) + energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone) return 2 energy_past = P.energy P.sub_velocity(internal_loss) - energy_dumped_organic += P.energy + 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) + energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone) 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)) + 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) + energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone) return 2 else P.sub_energy(energy_to_fracture) @@ -219,26 +230,29 @@ energy_past = P.energy P.sub_velocity(internal_loss) - energy_dumped_organic += P.energy + energy_dumped_organic += energy_past - P.energy if(!P.velocity) - energy_to_damage(energy_dumped_organic) + 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) + energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone) return -1 else - return general_handle_ballistics(P,def_zone,energy_dumped_organic,internal_loss,ballistic_armor) + 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*ENERGY_DAMAGE_ORGAN_FACTOR) - log_and_message_admins("damage_organ_energy([energy]) : [target].take_damage([damage])") + 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/obj/item/organ/external/def_zone) - var/damage = round(energy*ENERGY_DAMAGE_FLESH_FACTOR) - log_and_message_admins("energy_to_damage([energy]) : apply_damage([damage], BRUTE, [def_zone])") +/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 @@ -250,12 +264,13 @@ return penetration_chance /mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone) - log_and_message_admins("bullet_act_ch") - if(P.check_armour == "bullet") - log_and_message_admins("is bullet") + //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") + //log_and_message_admins("is not bullet") return ..() /mob/living @@ -282,33 +297,3 @@ /*Xeno organs*/ O_EGG = 25) ), \ "organ_hit_chance" = list(BP_HEAD = 95, BP_TORSO = 90, BP_GROIN = 90) ) -#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 HIT_VITAL_ORGAN_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 ENERGY_DAMAGE_FLESH_FACTOR -#undef ENERGY_DAMAGE_ORGAN_FACTOR - -#undef PROB_LEAVE_EARLY_FIRST -#undef PROB_LEAVE_EARLY_SECOND \ No newline at end of file diff --git a/code/modules/mob/living/zzballistic_test_ch.dm b/code/modules/mob/living/zzballistic_test_ch.dm new file mode 100644 index 0000000000..e81b8a6411 --- /dev/null +++ b/code/modules/mob/living/zzballistic_test_ch.dm @@ -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,iYou feel the energy of the bullet painfully transfered [pain_hit] as your [absorber] deflects it!") + 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) diff --git a/code/modules/projectiles/guns/projectile/ballistics_ch.dm b/code/modules/projectiles/guns/projectile/ballistics_ch.dm index 07b9ee4b5e..8e68f38a37 100644 --- a/code/modules/projectiles/guns/projectile/ballistics_ch.dm +++ b/code/modules/projectiles/guns/projectile/ballistics_ch.dm @@ -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" 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" 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,83 +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 + 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 @@ -120,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" \ No newline at end of file +/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. \ No newline at end of file diff --git a/code/modules/projectiles/guns/projectile_ch.dm b/code/modules/projectiles/guns/projectile_ch.dm index dae6585aa8..b2491f796a 100644 --- a/code/modules/projectiles/guns/projectile_ch.dm +++ b/code/modules/projectiles/guns/projectile_ch.dm @@ -427,4 +427,21 @@ var/obj/item/projectile/bullet/P = projectile if(!istype(P)) return - P.velocity = muzzle_velocity \ No newline at end of file + 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) \ No newline at end of file diff --git a/code/modules/projectiles/projectile/bullets_ch.dm b/code/modules/projectiles/projectile/bullets_ch.dm index 57e0dc09d1..84c4055386 100644 --- a/code/modules/projectiles/projectile/bullets_ch.dm +++ b/code/modules/projectiles/projectile/bullets_ch.dm @@ -2,13 +2,16 @@ /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 = 0.5 * velocity * velocity * (grains / GRAINS_PER_KG) + energy_add + sub_energy(0) return ..() /obj/item/projectile/bullet/proc/sub_velocity(var/amount) @@ -19,7 +22,169 @@ energy = max(0,energy - amount) velocity = sqrt(2*energy/(grains / GRAINS_PER_KG)) -/obj/item/projectile/bullet/rifle/a762 +//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 + 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 - velocity = 700 - grains = 123 \ No newline at end of file + 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 \ No newline at end of file diff --git a/vorestation.dme b/vorestation.dme index b649de3e0d..fc35edbe7a 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2628,6 +2628,7 @@ #include "code\modules\mob\living\say.dm" #include "code\modules\mob\living\status_indicators.dm" #include "code\modules\mob\living\zbullet_act_ch.dm" +#include "code\modules\mob\living\zzballistic_test_ch.dm" #include "code\modules\mob\living\bot\bot.dm" #include "code\modules\mob\living\bot\bot_vr.dm" #include "code\modules\mob\living\bot\cleanbot.dm" From e3953467d803226ae98cebf4757ea4c0830d443f Mon Sep 17 00:00:00 2001 From: cadyn Date: Fri, 6 Nov 2020 20:56:21 -0800 Subject: [PATCH 4/6] make buckshot not destroy walls instantly --- code/modules/projectiles/projectile/bullets_ch.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/projectiles/projectile/bullets_ch.dm b/code/modules/projectiles/projectile/bullets_ch.dm index 84c4055386..3cfb2cbdfe 100644 --- a/code/modules/projectiles/projectile/bullets_ch.dm +++ b/code/modules/projectiles/projectile/bullets_ch.dm @@ -70,6 +70,7 @@ 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 From d5d50d90bf7a3216f709fc60e3dee7d18558f845 Mon Sep 17 00:00:00 2001 From: cadyn <35672377+cadyn@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:49:33 -0800 Subject: [PATCH 5/6] charging_handle to charging handle reee --- code/modules/projectiles/guns/projectile/ballistics_ch.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/projectiles/guns/projectile/ballistics_ch.dm b/code/modules/projectiles/guns/projectile/ballistics_ch.dm index 8e68f38a37..913f5bf209 100644 --- a/code/modules/projectiles/guns/projectile/ballistics_ch.dm +++ b/code/modules/projectiles/guns/projectile/ballistics_ch.dm @@ -18,7 +18,7 @@ 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 muzzle_velocity = 960 //Prototype PU-21(https://en.wikipedia.org/wiki/IP-2) @@ -58,7 +58,7 @@ //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. @@ -240,4 +240,4 @@ /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. \ No newline at end of file + muzzle_velocity = 830 //Actual gun. From 29645e04e132c7b8c3c819ab92f469eae8896081 Mon Sep 17 00:00:00 2001 From: cadyn <35672377+cadyn@users.noreply.github.com> Date: Tue, 10 Nov 2020 15:15:16 -0800 Subject: [PATCH 6/6] adding #ifndef for gaussian_random --- code/modules/mob/living/zbullet_act_ch.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/mob/living/zbullet_act_ch.dm b/code/modules/mob/living/zbullet_act_ch.dm index 4122080548..62e1aab582 100644 --- a/code/modules/mob/living/zbullet_act_ch.dm +++ b/code/modules/mob/living/zbullet_act_ch.dm @@ -35,7 +35,9 @@ GLOBAL_VAR_INIT(HOLLOW_POINT_CONVERSION_EFF,1.15) 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 ////////