Updated damage code.

This commit is contained in:
Nikolai V Chr 2019-04-14 09:39:21 +02:00
parent 350a6cabd0
commit 94be8f7439
9 changed files with 2241 additions and 890 deletions

View File

@ -1,29 +1,59 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
#
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
#
# Authors: Nikolai V. Chr. and Pinto (with improvement by Onox)
#
#
############################ Config ######################################################################################
var full_damage_dist_m = 3;# Can vary from aircraft to aircraft depending on how many failure modes it has.
# Many modes (like Viggen) ought to have lower number like zero.
# Few modes (like F-14) ought to have larger number such as 3.
# For assets this should be average radius of the asset.
var use_hitpoints_instead_of_failure_modes_bool = 1;# mainly used by assets that don't have failure modes.
var hp_max = 80;# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
var hitable_by_air_munitions = 0; # if anti-air can do damage
var hitable_by_cannon = 1; # if cannon can do damage
var hitable_by_ground_munitions = 1;# if anti-ground/marine can do damage
var is_fleet = 0; # Is really 7 ships, 3 of which has offensive missiles.
##########################################################################################################################
##
## TODO:
## Include mechanics for hitting fleet
## Move all to emesary
##
var TRUE = 1;
var FALSE = 0;
var hp = 80;
var hp_max = hp;
var hp = hp_max;
var cannon_types = {
" M70 rocket hit": 0.25, #135mm
" M55 cannon shell hit": 0.10, # 30mm
" KCA cannon shell hit": 0.10, # 30mm
" Gun Splash On ": 0.10, # 30mm
" M61A1 shell hit": 0.05, # 20mm
" GAU-8/A hit": 0.10, # 30mm
" BK27 cannon hit": 0.07, # 27mm
" GSh-30 hit": 0.10, # 30mm
" GSh-23 hit": 0.065,# 23mm
" 7.62 hit": 0.005,# 7.62mm
" 50 BMG hit": 0.015,# 12.7mm
" S-5 rocket hit": 0.20, #55mm
};
#
# 0.20 means a direct hit will disable 20% of the failure modes on average.
# or, 0.20 also means a direct hit can do 20 hitpoints damage.
#
" M70 rocket hit": 0.250, #135mm
" S-5 rocket hit": 0.200, # 55mm
" M55 cannon shell hit": 0.100, # 30mm
" KCA cannon shell hit": 0.100, # 30mm
" Gun Splash On ": 0.100, # 30mm
" GSh-30 hit": 0.100, # 30mm
" GAU-8/A hit": 0.100, # 30mm
" BK27 cannon hit": 0.070, # 27mm
" GSh-23 hit": 0.065, # 23mm
" M61A1 shell hit": 0.050, # 20mm
" 50 BMG hit": 0.015, # 12.7mm (non-explosive)
" 7.62 hit": 0.005, # 7.62mm (non-explosive)
};
# lbs of warheads is explosive+fragmentation+fuse, so total warhead mass.
var warhead_lbs = {
# Anti-ground/marine warheads (sorted alphabetically)
"AGM-65": 126.00,
"AGM-84": 488.00,
"AGM-88": 146.00,
@ -34,7 +64,7 @@ var warhead_lbs = {
"AM39-Exocet": 364.00,
"AS-37-Martel": 330.00,
"AS30L": 529.00,
"CBU-87": 128.00,
"CBU-87": 10.00,# bomblet warhead. Mix of armour piecing and HE.
"Exocet": 364.00,
"FAB-100": 92.59,
"FAB-250": 202.85,
@ -48,12 +78,10 @@ var warhead_lbs = {
"KAB-500": 564.38,
"Kh-25MP": 197.53,
"Kh-66": 244.71,
"KN-06": 315.00,
"LAU-68": 10.00,
"M317": 145.00,
"M71": 200.00,
"M71R": 200.00,
"M90": 500.00,
"M90": 3.00,# bomblet warhead.
"MK-82": 192.00,
"MK-83": 445.00,
"MK-84": 945.00,
@ -66,8 +94,7 @@ var warhead_lbs = {
"RN-18T": 1200.00, #fictional, thermobaeric replacement for the RN-28 nuclear bomb
"RS-2US": 28.66,
"S-21": 245.00,
"S-24": 271.00,
"S530D": 66.00,
"S-24": 271.00,
"SCALP": 992.00,
"Sea Eagle": 505.00,
"SeaEagle": 505.00,
@ -76,6 +103,82 @@ var warhead_lbs = {
"ZB-500": 473.99,
};
var warhead_air_lbs = {
# Anti-air warheads (sorted alphabetically)
"aim-120": 44.00,
"AIM-120": 44.00,
"AIM-54": 135.00,
"aim-7": 88.00,
"AIM-7": 88.00,
"aim-9": 20.80,
"AIM-9": 20.80,
"AIM120": 44.00,
"AIM132": 22.05,
"AIM9": 20.80,
"KN-06": 315.00,
"M317": 145.00,
"Magic-2": 27.00,
"Matra MICA": 30.00,
"Matra R550 Magic 2": 27.00,
"MATRA-R530": 55.00,
"MatraMica": 30.00,
"MatraMicaIR": 30.00,
"MatraR550Magic2": 27.00,
"Meteor": 55.00,
"MICA-EM": 30.00,
"MICA-IR": 30.00,
"R-13M": 16.31,
"R-27R1": 85.98,
"R-27T1": 85.98,
"R-3R": 16.31,
"R-3S": 16.31,
"R-55": 20.06,
"R-60": 6.60,
"R-60M": 7.70,
"R-73E": 16.31,
"R-77": 49.60,
"R74": 16.00,
"RB-05A": 353.00,
"RB-24": 20.80,
"RB-24J": 20.80,
"RB-71": 88.00,
"RB-74": 20.80,
"RB-99": 44.00,
"S530D": 66.00,
};
var cluster = {
# cluster munition list
"M90": nil,
"CBU-87": nil,
};
var fireMsgs = {
# F14
" FOX3 at": nil, # radar
" FOX2 at": nil, # heat
" FOX1 at": nil, # semi-radar
# Generic
" Fox 1 at": nil, # semi-radar
" Fox 2 at": nil, # heat
" Fox 3 at": nil, # radar
" Greyhound at": nil, # cruise missile
" Bombs away at": nil, # bombs
" Bruiser at": nil, # anti-ship
" Rifle at": nil, # TV guided
" Sniper at": nil, # anti-radiation
# SAM, fleet and missile frigate
" Bird away at": nil, # G/A
# F15
" aim7 at": nil,
" aim9 at": nil,
" aim120 at": nil,
};
var incoming_listener = func {
var history = getprop("/sim/multiplay/chat-history");
var hist_vector = split("\n", history);
@ -93,67 +196,10 @@ var incoming_listener = func {
# a m2000 is firing at us
m2000 = TRUE;
}
if (last_vector[1] == " FOX2 at" or last_vector[1] == " aim7 at" or last_vector[1] == " aim9 at"
or last_vector[1] == " aim120 at" or last_vector[1] == " RB-24J fired at" or last_vector[1] == " RB-74 fired at"
or last_vector[1] == " RB-71 fired at" or last_vector[1] == " RB-15F fired at"
or last_vector[1] == " RB-99 fired at" or m2000 == TRUE) {
if (contains(fireMsgs, last_vector[1]) or m2000 == TRUE) {
# air2air being fired
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
} elsif (1 == 1) { # mirage: getprop("/controls/armament/mp-messaging")
# latest version of failure manager and taking damage enabled
#print("damage enabled");
warn(last_vector,m2000,callsign,author);
} elsif (getprop("payload/armament/msg")) {
var last1 = split(" ", last_vector[1]);
if(size(last1) > 2 and last1[size(last1)-1] == "exploded" ) {
#print("missile hitting someone");
@ -171,64 +217,113 @@ var incoming_listener = func {
if(distance != nil) {
var dist = distance;
#check distance w/ if statement here
if (contains(cluster, type)) {
# cluster munition
var lbs = warhead_lbs[type];
var maxDist = maxDamageDistFromWarhead(lbs);
var distance = math.max(0,rand()*2-full_damage_dist_m);#being 0 to 2 meters from a bomblet on average.
var diff = maxDist-distance;
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(probability, hp_max);
var percent = 100 * prob;
printf("Took %.1f%% damage from %s clusterbomb at %0.1f meters from bomblet. %s systems was hit", percent,type,distance,failed);
nearby_explosion();
return;
}
distance = math.max(distance-full_damage_dist_m, 0);
if (contains(warhead_lbs, type)) {
#maxDist = maxDamageDistFromWarhead(warhead_lbs[type]);
var maxDist = 0;# distance where the explosion dont hurt us anymore
var lbs = 0;
if (hitable_by_ground_munitions and contains(warhead_lbs, type)) {
lbs = warhead_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
} elsif (hitable_by_air_munitions and contains(warhead_air_lbs, type)) {
lbs = warhead_air_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);
} else {
return;
}
var prob = 1;
if (type == "M90" and distance < 300) {
var failed = fail_systems(warhead_lbs[type]/2);
return;
} elsif (distance < 150) {
if ( distance > 50 ) {
distance = distance - 50;
prob = 1 - (distance/100);
}
var diff = maxDist-distance;
if (diff < 0) {
diff = 0;
}
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(warhead_lbs[type] * prob);
#ar percent = 100 * probability;
#printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
var failed = fail_systems(probability, hp_max);
var percent = 100 * probability;
printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
nearby_explosion();
####
# I don't remember all the considerations that went into our original warhead damage model.
# But looking at the formula it looks like they all do 100% damage at 0 meter hit,
# and warhead size is only used to determine the decrease of damage with distance increase.
# It sorta gets the job done though, so I am hesitant to advocate that warheads above a certain
# size should give 100% damage for some distance, and that warheads smaller than certain size should
# not give 100% damage even on direct hit.
# Anyway, for hitpoint based assets, this is now the case. Maybe we should consider to also do something
# similar for failure mode based aircraft. ~Nikolai
####
## example 1: ##
# 300 lbs warhead, 50 meters distance
# maxDist=52
# diff = 52-50 = 2
# diff^2 = 4
# prob = 4/2700 = 0.15%
## example 2: ##
# 300 lbs warhead, 25 meters distance
# maxDist=52
# diff = 52-25 = 27
# diff^2 = 729
# prob = 729/2700 = 27%
}
}
} elsif (cannon_types[last_vector[1]] != nil) {
# cannon hitting someone
print("cannon");
} elsif (hitable_by_cannon and cannon_types[last_vector[1]] != nil) {
if (size(last_vector) > 2 and last_vector[2] == " "~callsign) {
print("cannon hit us");
#"Leto: Gun Splash On : SA-11"
#"Leto: KCA cannon shell hit: SA-11: 4 hits:..."
if (size(last_vector) < 4) {
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
#print("last3[2]: " ~ last3[2]);
#print("last3[1]: " ~ last3[1]);
if(size(last3) > 2) {
if ( last3[2] == "hits" ) {
var hit_count = num(last3[1]);
var last3 = split(" ", last_vector[3]);
if(size(last3) > 2 and size(last3[2]) > 2 and last3[2] == "hits" ) {
var probability = cannon_types[last_vector[1]];
var hit_count = num(last3[1]);
if (hit_count != nil) {
var damaged_sys = 0;
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
damaged_sys = damaged_sys + failed;
}
printf("Took %.1f%% x %2d damage from cannon! %s systems was hit.", probability*100, hit_count, damaged_sys);
nearby_explosion();
}
} else {
var hit_count = 4;
var probability = cannon_types[last_vector[1]];
#print("probability: " ~ probability);
var failed = fail_systems(probability * 3);# Old messages is assumed to be 3 hits
printf("Took %.1f%% x 3 damage from cannon! %s systems was hit.", probability*100, failed);
nearby_explosion();
}
var damaged_sys = 0;
var probability = cannon_types[last_vector[1]];
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
# damaged_sys = damaged_sys + failed;
}
# that someone is me!
#print("hitting me");
#printf("Took %.1f%% damage from cannon! %s systems was hit.", probability*hit_count*100, damaged_sys);
}
}
}
@ -237,24 +332,132 @@ var incoming_listener = func {
}
var maxDamageDistFromWarhead = func (lbs) {
# very simple
var dist = 7*math.sqrt(lbs);
# Calc at what distance the warhead will do zero damage every time.
var dist = 3*math.sqrt(lbs);
return dist;
}
var fail_systems = func (damage) {
hp = hp - damage;
print("HP: " ~ hp ~ "/" ~ hp_max);
setprop("sam/damage", math.max(0,100*hp/hp_max));
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);
setprop("/sim/multiplay/generic/int[2]",1);
setprop("/sim/multiplay/generic/int[0]",1);
setprop("/sim/messages/copilot", "SAM dead.");
}
var fail_systems = func (probability, factor = 100) {#this factor needs tuning after all asset hitpoints have been evaluated.
if (fleet) {
return fail_fleet_systems(probability, factor);
} elsif (use_hitpoints_instead_of_failure_modes_bool) {
hp -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP: %d/%d", hp, hp_max);
setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);#we are dead
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/multiplay/generic/int[0]",1);#smoke on
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
}
return -1;
} else {
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
var failed = 0;
foreach(var failure_mode_id; mode_list) {
if (rand() < probability) {
FailureMgr.set_failure_level(failure_mode_id, 1);
failed += 1;
}
}
return failed;
}
};
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
var fail_fleet_systems = func (probability, factor) {
var no = 7;
while (no > 6 or hp_f[no] < 0) {
no = int(rand()*7);
if (hp_f[no] < 0) {
if (rand() > 0.9) {
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
print("HP["~no~"]: " ~ hp_f[no] ~ "/" ~ hp_max);
return;
}
}
}
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP[%d]: %d/%d", no, hp_f[no], hp_max);
#setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp_f[no] < 0 ) {
setprop("/sim/multiplay/generic/bool["~(no+40)~"]",1);
armament.defeatSpamFilter("So you sank one of our ships, we will get you for that!");
if (!getprop("/carrier/disabled") and hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0) {
setprop("/carrier/disabled",1);
armament.defeatSpamFilter("Captain our offensive capability is crippled!");
}
if (hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0 and hp_f[3]<0 and hp_f[4]<0 and hp_f[5]<0 and hp_f[6]<0) {
setprop("/carrier/sunk",1);
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
armament.defeatSpamFilter("S.O.S. Heeelp");
} else {
armament.defeatSpamFilter("This is not over yet..");
}
}
return -1;
};
var warn = func (last_vector,m2000,callsign,author) {
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
}
var playIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 1);
settimer(func {stopIncomingSound(clock);},3);
@ -264,6 +467,20 @@ var stopIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 0);
}
var nearby_explosion = func {
setprop("damage/sounds/nearby-explode-on", 0);
settimer(nearby_explosion_a, 0);
}
var nearby_explosion_a = func {
setprop("damage/sounds/nearby-explode-on", 1);
settimer(nearby_explosion_b, 0.5);
}
var nearby_explosion_b = func {
setprop("damage/sounds/nearby-explode-on", 0);
}
var callsign_struct = {};
var getCallsign = func (callsign) {
var node = callsign_struct[callsign];
@ -279,20 +496,25 @@ var processCallsigns = func () {
callsign_struct[callsign] = player;
}
}
settimer(processCallsigns, 1.5);
settimer(processCallsigns, 5);
}
processCallsigns();
var logTime = func{
#log time and date for outputing ucsv files for converting into KML files for google earth.
if (getprop("logging/log[0]/enabled") == TRUE and getprop("sim/time/utc/year") != nil) {
var date = getprop("sim/time/utc/year")~"/"~getprop("sim/time/utc/month")~"/"~getprop("sim/time/utc/day");
var time = getprop("sim/time/utc/hour")~":"~getprop("sim/time/utc/minute")~":"~getprop("sim/time/utc/second");
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setprop("logging/date-log", date);
setprop("logging/time-log", time);
# prevent flooding the pilots screen with failure modes that fail when getting hit.
setprop("/sim/failure-manager/display-on-screen", FALSE);
var re_init = func {
# repair the aircraft at relocation to another airport.
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
foreach(var failure_mode_id; mode_list) {
FailureMgr.set_failure_level(failure_mode_id, 0);
}
}
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setlistener("/sim/signals/reinit", re_init, 0, 0);

View File

@ -1,29 +1,59 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
#
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
#
# Authors: Nikolai V. Chr. and Pinto (with improvement by Onox)
#
#
############################ Config ######################################################################################
var full_damage_dist_m =20;# Can vary from aircraft to aircraft depending on how many failure modes it has.
# Many modes (like Viggen) ought to have lower number like zero.
# Few modes (like F-14) ought to have larger number such as 3.
# For assets this should be average radius of the asset.
var use_hitpoints_instead_of_failure_modes_bool = 1;# mainly used by assets that don't have failure modes.
var hp_max =200;# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
var hitable_by_air_munitions = 0; # if anti-air can do damage
var hitable_by_cannon = 1; # if cannon can do damage
var hitable_by_ground_munitions = 1;# if anti-ground/marine can do damage
var is_fleet = 0; # Is really 7 ships, 3 of which has offensive missiles.
##########################################################################################################################
##
## TODO:
## Include mechanics for hitting fleet
## Move all to emesary
##
var TRUE = 1;
var FALSE = 0;
var hp = 200;
var hp_max = hp;
var hp = hp_max;
var cannon_types = {
" M70 rocket hit": 0.25, #135mm
" M55 cannon shell hit": 0.10, # 30mm
" KCA cannon shell hit": 0.10, # 30mm
" Gun Splash On ": 0.10, # 30mm
" M61A1 shell hit": 0.05, # 20mm
" GAU-8/A hit": 0.10, # 30mm
" BK27 cannon hit": 0.07, # 27mm
" GSh-30 hit": 0.10, # 30mm
" GSh-23 hit": 0.065,# 23mm
" 7.62 hit": 0.005,# 7.62mm
" 50 BMG hit": 0.015,# 12.7mm
" S-5 rocket hit": 0.20, #55mm
};
#
# 0.20 means a direct hit will disable 20% of the failure modes on average.
# or, 0.20 also means a direct hit can do 20 hitpoints damage.
#
" M70 rocket hit": 0.250, #135mm
" S-5 rocket hit": 0.200, # 55mm
" M55 cannon shell hit": 0.100, # 30mm
" KCA cannon shell hit": 0.100, # 30mm
" Gun Splash On ": 0.100, # 30mm
" GSh-30 hit": 0.100, # 30mm
" GAU-8/A hit": 0.100, # 30mm
" BK27 cannon hit": 0.070, # 27mm
" GSh-23 hit": 0.065, # 23mm
" M61A1 shell hit": 0.050, # 20mm
" 50 BMG hit": 0.015, # 12.7mm (non-explosive)
" 7.62 hit": 0.005, # 7.62mm (non-explosive)
};
# lbs of warheads is explosive+fragmentation+fuse, so total warhead mass.
var warhead_lbs = {
# Anti-ground/marine warheads (sorted alphabetically)
"AGM-65": 126.00,
"AGM-84": 488.00,
"AGM-88": 146.00,
@ -34,7 +64,7 @@ var warhead_lbs = {
"AM39-Exocet": 364.00,
"AS-37-Martel": 330.00,
"AS30L": 529.00,
"CBU-87": 128.00,
"CBU-87": 10.00,# bomblet warhead. Mix of armour piecing and HE.
"Exocet": 364.00,
"FAB-100": 92.59,
"FAB-250": 202.85,
@ -48,12 +78,10 @@ var warhead_lbs = {
"KAB-500": 564.38,
"Kh-25MP": 197.53,
"Kh-66": 244.71,
"KN-06": 315.00,
"LAU-68": 10.00,
"M317": 145.00,
"M71": 200.00,
"M71R": 200.00,
"M90": 500.00,
"M90": 3.00,# bomblet warhead.
"MK-82": 192.00,
"MK-83": 445.00,
"MK-84": 945.00,
@ -66,8 +94,7 @@ var warhead_lbs = {
"RN-18T": 1200.00, #fictional, thermobaeric replacement for the RN-28 nuclear bomb
"RS-2US": 28.66,
"S-21": 245.00,
"S-24": 271.00,
"S530D": 66.00,
"S-24": 271.00,
"SCALP": 992.00,
"Sea Eagle": 505.00,
"SeaEagle": 505.00,
@ -76,6 +103,82 @@ var warhead_lbs = {
"ZB-500": 473.99,
};
var warhead_air_lbs = {
# Anti-air warheads (sorted alphabetically)
"aim-120": 44.00,
"AIM-120": 44.00,
"AIM-54": 135.00,
"aim-7": 88.00,
"AIM-7": 88.00,
"aim-9": 20.80,
"AIM-9": 20.80,
"AIM120": 44.00,
"AIM132": 22.05,
"AIM9": 20.80,
"KN-06": 315.00,
"M317": 145.00,
"Magic-2": 27.00,
"Matra MICA": 30.00,
"Matra R550 Magic 2": 27.00,
"MATRA-R530": 55.00,
"MatraMica": 30.00,
"MatraMicaIR": 30.00,
"MatraR550Magic2": 27.00,
"Meteor": 55.00,
"MICA-EM": 30.00,
"MICA-IR": 30.00,
"R-13M": 16.31,
"R-27R1": 85.98,
"R-27T1": 85.98,
"R-3R": 16.31,
"R-3S": 16.31,
"R-55": 20.06,
"R-60": 6.60,
"R-60M": 7.70,
"R-73E": 16.31,
"R-77": 49.60,
"R74": 16.00,
"RB-05A": 353.00,
"RB-24": 20.80,
"RB-24J": 20.80,
"RB-71": 88.00,
"RB-74": 20.80,
"RB-99": 44.00,
"S530D": 66.00,
};
var cluster = {
# cluster munition list
"M90": nil,
"CBU-87": nil,
};
var fireMsgs = {
# F14
" FOX3 at": nil, # radar
" FOX2 at": nil, # heat
" FOX1 at": nil, # semi-radar
# Generic
" Fox 1 at": nil, # semi-radar
" Fox 2 at": nil, # heat
" Fox 3 at": nil, # radar
" Greyhound at": nil, # cruise missile
" Bombs away at": nil, # bombs
" Bruiser at": nil, # anti-ship
" Rifle at": nil, # TV guided
" Sniper at": nil, # anti-radiation
# SAM, fleet and missile frigate
" Bird away at": nil, # G/A
# F15
" aim7 at": nil,
" aim9 at": nil,
" aim120 at": nil,
};
var incoming_listener = func {
var history = getprop("/sim/multiplay/chat-history");
var hist_vector = split("\n", history);
@ -93,67 +196,10 @@ var incoming_listener = func {
# a m2000 is firing at us
m2000 = TRUE;
}
if (last_vector[1] == " FOX2 at" or last_vector[1] == " aim7 at" or last_vector[1] == " aim9 at"
or last_vector[1] == " aim120 at" or last_vector[1] == " RB-24J fired at" or last_vector[1] == " RB-74 fired at"
or last_vector[1] == " RB-71 fired at" or last_vector[1] == " RB-15F fired at"
or last_vector[1] == " RB-99 fired at" or m2000 == TRUE) {
if (contains(fireMsgs, last_vector[1]) or m2000 == TRUE) {
# air2air being fired
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
} elsif (1==1) { # mirage: getprop("/controls/armament/mp-messaging")
# latest version of failure manager and taking damage enabled
#print("damage enabled");
warn(last_vector,m2000,callsign,author);
} elsif (getprop("payload/armament/msg")) {
var last1 = split(" ", last_vector[1]);
if(size(last1) > 2 and last1[size(last1)-1] == "exploded" ) {
#print("missile hitting someone");
@ -171,61 +217,113 @@ var incoming_listener = func {
if(distance != nil) {
var dist = distance;
#check distance w/ if statement here
if (contains(cluster, type)) {
# cluster munition
var lbs = warhead_lbs[type];
var maxDist = maxDamageDistFromWarhead(lbs);
var distance = math.max(0,rand()*2-full_damage_dist_m);#being 0 to 2 meters from a bomblet on average.
var diff = maxDist-distance;
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(probability, hp_max);
var percent = 100 * prob;
printf("Took %.1f%% damage from %s clusterbomb at %0.1f meters from bomblet. %s systems was hit", percent,type,distance,failed);
nearby_explosion();
return;
}
distance = math.max(distance-full_damage_dist_m, 0);
if (contains(warhead_lbs, type)) {
#maxDist = maxDamageDistFromWarhead(warhead_lbs[type]);
var maxDist = 0;# distance where the explosion dont hurt us anymore
var lbs = 0;
if (hitable_by_ground_munitions and contains(warhead_lbs, type)) {
lbs = warhead_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
} elsif (hitable_by_air_munitions and contains(warhead_air_lbs, type)) {
lbs = warhead_air_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);
} else {
return;
}
if (type == "M90" and distance < 300) {
var failed = fail_systems(warhead_lbs[type]/2);
return;
} elsif (distance < 150) {
var prob = 1;
if ( distance > 50 ) {
distance = distance - 50;
prob = 1 - (distance/100);
}
var diff = maxDist-distance;
if (diff < 0) {
diff = 0;
}
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(warhead_lbs[type] * prob);
#ar percent = 100 * probability;
#printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
var failed = fail_systems(probability, hp_max);
var percent = 100 * probability;
printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
nearby_explosion();
####
# I don't remember all the considerations that went into our original warhead damage model.
# But looking at the formula it looks like they all do 100% damage at 0 meter hit,
# and warhead size is only used to determine the decrease of damage with distance increase.
# It sorta gets the job done though, so I am hesitant to advocate that warheads above a certain
# size should give 100% damage for some distance, and that warheads smaller than certain size should
# not give 100% damage even on direct hit.
# Anyway, for hitpoint based assets, this is now the case. Maybe we should consider to also do something
# similar for failure mode based aircraft. ~Nikolai
####
## example 1: ##
# 300 lbs warhead, 50 meters distance
# maxDist=52
# diff = 52-50 = 2
# diff^2 = 4
# prob = 4/2700 = 0.15%
## example 2: ##
# 300 lbs warhead, 25 meters distance
# maxDist=52
# diff = 52-25 = 27
# diff^2 = 729
# prob = 729/2700 = 27%
}
}
} elsif (cannon_types[last_vector[1]] != nil) {
# cannon hitting someone
print("cannon");
} elsif (hitable_by_cannon and cannon_types[last_vector[1]] != nil) {
if (size(last_vector) > 2 and last_vector[2] == " "~callsign) {
print("cannon hit us");
if (size(last_vector) < 4) {
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
#print("last3[2]: " ~ last3[2]);
#print("last3[1]: " ~ last3[1]);
if(size(last3) > 2) {
if ( last3[2] == "hits" ) {
var hit_count = num(last3[1]);
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
if(size(last3) > 2 and size(last3[2]) > 2 and last3[2] == "hits" ) {
var probability = cannon_types[last_vector[1]];
var hit_count = num(last3[1]);
if (hit_count != nil) {
var damaged_sys = 0;
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
damaged_sys = damaged_sys + failed;
}
printf("Took %.1f%% x %2d damage from cannon! %s systems was hit.", probability*100, hit_count, damaged_sys);
nearby_explosion();
}
} else {
var hit_count = 4;
var probability = cannon_types[last_vector[1]];
#print("probability: " ~ probability);
var failed = fail_systems(probability * 3);# Old messages is assumed to be 3 hits
printf("Took %.1f%% x 3 damage from cannon! %s systems was hit.", probability*100, failed);
nearby_explosion();
}
var damaged_sys = 0;
var probability = cannon_types[last_vector[1]];
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
#damaged_sys = damaged_sys + failed;
}
# that someone is me!
#print("hitting me");
#printf("Took %.1f%% damage from cannon! %s systems was hit.", probability*hit_count*100, damaged_sys);
}
}
}
@ -234,22 +332,132 @@ var incoming_listener = func {
}
var maxDamageDistFromWarhead = func (lbs) {
# very simple
var dist = 7*math.sqrt(lbs);
# Calc at what distance the warhead will do zero damage every time.
var dist = 3*math.sqrt(lbs);
return dist;
}
var fail_systems = func (damage) {
hp = hp - damage;
print("HP: " ~ hp ~ "/" ~ hp_max);
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);
setprop("/sim/multiplay/generic/int[0]",1);
}
var fail_systems = func (probability, factor = 100) {#this factor needs tuning after all asset hitpoints have been evaluated.
if (fleet) {
return fail_fleet_systems(probability, factor);
} elsif (use_hitpoints_instead_of_failure_modes_bool) {
hp -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP: %d/%d", hp, hp_max);
setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);#we are dead
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/multiplay/generic/int[0]",1);#smoke on
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
}
return -1;
} else {
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
var failed = 0;
foreach(var failure_mode_id; mode_list) {
if (rand() < probability) {
FailureMgr.set_failure_level(failure_mode_id, 1);
failed += 1;
}
}
return failed;
}
};
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
var fail_fleet_systems = func (probability, factor) {
var no = 7;
while (no > 6 or hp_f[no] < 0) {
no = int(rand()*7);
if (hp_f[no] < 0) {
if (rand() > 0.9) {
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
print("HP["~no~"]: " ~ hp_f[no] ~ "/" ~ hp_max);
return;
}
}
}
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP[%d]: %d/%d", no, hp_f[no], hp_max);
#setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp_f[no] < 0 ) {
setprop("/sim/multiplay/generic/bool["~(no+40)~"]",1);
armament.defeatSpamFilter("So you sank one of our ships, we will get you for that!");
if (!getprop("/carrier/disabled") and hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0) {
setprop("/carrier/disabled",1);
armament.defeatSpamFilter("Captain our offensive capability is crippled!");
}
if (hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0 and hp_f[3]<0 and hp_f[4]<0 and hp_f[5]<0 and hp_f[6]<0) {
setprop("/carrier/sunk",1);
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
armament.defeatSpamFilter("S.O.S. Heeelp");
} else {
armament.defeatSpamFilter("This is not over yet..");
}
}
return -1;
};
var warn = func (last_vector,m2000,callsign,author) {
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
}
var playIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 1);
settimer(func {stopIncomingSound(clock);},3);
@ -259,6 +467,20 @@ var stopIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 0);
}
var nearby_explosion = func {
setprop("damage/sounds/nearby-explode-on", 0);
settimer(nearby_explosion_a, 0);
}
var nearby_explosion_a = func {
setprop("damage/sounds/nearby-explode-on", 1);
settimer(nearby_explosion_b, 0.5);
}
var nearby_explosion_b = func {
setprop("damage/sounds/nearby-explode-on", 0);
}
var callsign_struct = {};
var getCallsign = func (callsign) {
var node = callsign_struct[callsign];
@ -274,20 +496,25 @@ var processCallsigns = func () {
callsign_struct[callsign] = player;
}
}
settimer(processCallsigns, 1.5);
settimer(processCallsigns, 5);
}
processCallsigns();
var logTime = func{
#log time and date for outputing ucsv files for converting into KML files for google earth.
if (getprop("logging/log[0]/enabled") == TRUE and getprop("sim/time/utc/year") != nil) {
var date = getprop("sim/time/utc/year")~"/"~getprop("sim/time/utc/month")~"/"~getprop("sim/time/utc/day");
var time = getprop("sim/time/utc/hour")~":"~getprop("sim/time/utc/minute")~":"~getprop("sim/time/utc/second");
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setprop("logging/date-log", date);
setprop("logging/time-log", time);
# prevent flooding the pilots screen with failure modes that fail when getting hit.
setprop("/sim/failure-manager/display-on-screen", FALSE);
var re_init = func {
# repair the aircraft at relocation to another airport.
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
foreach(var failure_mode_id; mode_list) {
FailureMgr.set_failure_level(failure_mode_id, 0);
}
}
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setlistener("/sim/signals/reinit", re_init, 0, 0);

View File

@ -1,5 +1,5 @@
#
# Install: Include this code into an aircraft to make it damageable. (remember to add it to the -set file)
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
#
# Authors: Nikolai V. Chr. and Pinto (with improvement by Onox)
#
@ -33,8 +33,8 @@ var hp = hp_max;
var cannon_types = {
#
# 0.20 means a direct hit will disable 20% of the failure modes in average.
# 0.20 also means a direct hit will do 20 hitpoints damage.
# 0.20 means a direct hit will disable 20% of the failure modes on average.
# or, 0.20 also means a direct hit can do 20 hitpoints damage.
#
" M70 rocket hit": 0.250, #135mm
" S-5 rocket hit": 0.200, # 55mm
@ -64,7 +64,7 @@ var warhead_lbs = {
"AM39-Exocet": 364.00,
"AS-37-Martel": 330.00,
"AS30L": 529.00,
"CBU-87": 3.00,# bomblet warhead.
"CBU-87": 10.00,# bomblet warhead. Mix of armour piecing and HE.
"Exocet": 364.00,
"FAB-100": 92.59,
"FAB-250": 202.85,

View File

@ -1,30 +1,59 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
#
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
#
# Authors: Nikolai V. Chr. and Pinto (with improvement by Onox)
#
#
############################ Config ######################################################################################
var full_damage_dist_m =20;# Can vary from aircraft to aircraft depending on how many failure modes it has.
# Many modes (like Viggen) ought to have lower number like zero.
# Few modes (like F-14) ought to have larger number such as 3.
# For assets this should be average radius of the asset.
var use_hitpoints_instead_of_failure_modes_bool = 1;# mainly used by assets that don't have failure modes.
var hp_max = 200;# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
var hitable_by_air_munitions = 0; # if anti-air can do damage
var hitable_by_cannon = 1; # if cannon can do damage
var hitable_by_ground_munitions = 1;# if anti-ground/marine can do damage
var is_fleet = 1; # Is really 7 ships, 3 of which has offensive missiles.
##########################################################################################################################
##
## TODO:
## Include mechanics for hitting fleet
## Move all to emesary
##
var TRUE = 1;
var FALSE = 0;
var hp_max = 200;
var hp = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
var hp = hp_max;
var cannon_types = {
" M70 rocket hit": 0.25, #135mm
" M55 cannon shell hit": 0.10, # 30mm
" KCA cannon shell hit": 0.10, # 30mm
" Gun Splash On ": 0.10, # 30mm
" M61A1 shell hit": 0.05, # 20mm
" GAU-8/A hit": 0.10, # 30mm
" BK27 cannon hit": 0.07, # 27mm
" GSh-30 hit": 0.10, # 30mm
" GSh-23 hit": 0.065,# 23mm
" 7.62 hit": 0.005,# 7.62mm
" 50 BMG hit": 0.015,# 12.7mm
" S-5 rocket hit": 0.20, #55mm
};
#
# 0.20 means a direct hit will disable 20% of the failure modes on average.
# or, 0.20 also means a direct hit can do 20 hitpoints damage.
#
" M70 rocket hit": 0.250, #135mm
" S-5 rocket hit": 0.200, # 55mm
" M55 cannon shell hit": 0.100, # 30mm
" KCA cannon shell hit": 0.100, # 30mm
" Gun Splash On ": 0.100, # 30mm
" GSh-30 hit": 0.100, # 30mm
" GAU-8/A hit": 0.100, # 30mm
" BK27 cannon hit": 0.070, # 27mm
" GSh-23 hit": 0.065, # 23mm
" M61A1 shell hit": 0.050, # 20mm
" 50 BMG hit": 0.015, # 12.7mm (non-explosive)
" 7.62 hit": 0.005, # 7.62mm (non-explosive)
};
# lbs of warheads is explosive+fragmentation+fuse, so total warhead mass.
var warhead_lbs = {
# Anti-ground/marine warheads (sorted alphabetically)
"AGM-65": 126.00,
"AGM-84": 488.00,
"AGM-88": 146.00,
@ -35,7 +64,7 @@ var warhead_lbs = {
"AM39-Exocet": 364.00,
"AS-37-Martel": 330.00,
"AS30L": 529.00,
"CBU-87": 128.00,
"CBU-87": 10.00,# bomblet warhead. Mix of armour piecing and HE.
"Exocet": 364.00,
"FAB-100": 92.59,
"FAB-250": 202.85,
@ -49,12 +78,10 @@ var warhead_lbs = {
"KAB-500": 564.38,
"Kh-25MP": 197.53,
"Kh-66": 244.71,
"KN-06": 315.00,
"LAU-68": 10.00,
"M317": 145.00,
"M71": 200.00,
"M71R": 200.00,
"M90": 500.00,
"M90": 3.00,# bomblet warhead.
"MK-82": 192.00,
"MK-83": 445.00,
"MK-84": 945.00,
@ -67,8 +94,7 @@ var warhead_lbs = {
"RN-18T": 1200.00, #fictional, thermobaeric replacement for the RN-28 nuclear bomb
"RS-2US": 28.66,
"S-21": 245.00,
"S-24": 271.00,
"S530D": 66.00,
"S-24": 271.00,
"SCALP": 992.00,
"Sea Eagle": 505.00,
"SeaEagle": 505.00,
@ -77,6 +103,82 @@ var warhead_lbs = {
"ZB-500": 473.99,
};
var warhead_air_lbs = {
# Anti-air warheads (sorted alphabetically)
"aim-120": 44.00,
"AIM-120": 44.00,
"AIM-54": 135.00,
"aim-7": 88.00,
"AIM-7": 88.00,
"aim-9": 20.80,
"AIM-9": 20.80,
"AIM120": 44.00,
"AIM132": 22.05,
"AIM9": 20.80,
"KN-06": 315.00,
"M317": 145.00,
"Magic-2": 27.00,
"Matra MICA": 30.00,
"Matra R550 Magic 2": 27.00,
"MATRA-R530": 55.00,
"MatraMica": 30.00,
"MatraMicaIR": 30.00,
"MatraR550Magic2": 27.00,
"Meteor": 55.00,
"MICA-EM": 30.00,
"MICA-IR": 30.00,
"R-13M": 16.31,
"R-27R1": 85.98,
"R-27T1": 85.98,
"R-3R": 16.31,
"R-3S": 16.31,
"R-55": 20.06,
"R-60": 6.60,
"R-60M": 7.70,
"R-73E": 16.31,
"R-77": 49.60,
"R74": 16.00,
"RB-05A": 353.00,
"RB-24": 20.80,
"RB-24J": 20.80,
"RB-71": 88.00,
"RB-74": 20.80,
"RB-99": 44.00,
"S530D": 66.00,
};
var cluster = {
# cluster munition list
"M90": nil,
"CBU-87": nil,
};
var fireMsgs = {
# F14
" FOX3 at": nil, # radar
" FOX2 at": nil, # heat
" FOX1 at": nil, # semi-radar
# Generic
" Fox 1 at": nil, # semi-radar
" Fox 2 at": nil, # heat
" Fox 3 at": nil, # radar
" Greyhound at": nil, # cruise missile
" Bombs away at": nil, # bombs
" Bruiser at": nil, # anti-ship
" Rifle at": nil, # TV guided
" Sniper at": nil, # anti-radiation
# SAM, fleet and missile frigate
" Bird away at": nil, # G/A
# F15
" aim7 at": nil,
" aim9 at": nil,
" aim120 at": nil,
};
var incoming_listener = func {
var history = getprop("/sim/multiplay/chat-history");
var hist_vector = split("\n", history);
@ -94,67 +196,10 @@ var incoming_listener = func {
# a m2000 is firing at us
m2000 = TRUE;
}
if (last_vector[1] == " FOX2 at" or last_vector[1] == " aim7 at" or last_vector[1] == " aim9 at"
or last_vector[1] == " aim120 at" or last_vector[1] == " RB-24J fired at" or last_vector[1] == " RB-74 fired at"
or last_vector[1] == " RB-71 fired at" or last_vector[1] == " RB-15F fired at"
or last_vector[1] == " RB-99 fired at" or m2000 == TRUE) {
if (contains(fireMsgs, last_vector[1]) or m2000 == TRUE) {
# air2air being fired
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
} elsif (1 == 1) { # mirage: getprop("/controls/armament/mp-messaging")
# latest version of failure manager and taking damage enabled
#print("damage enabled");
warn(last_vector,m2000,callsign,author);
} elsif (getprop("payload/armament/msg")) {
var last1 = split(" ", last_vector[1]);
if(size(last1) > 2 and last1[size(last1)-1] == "exploded" ) {
#print("missile hitting someone");
@ -172,61 +217,113 @@ var incoming_listener = func {
if(distance != nil) {
var dist = distance;
#check distance w/ if statement here
if (contains(cluster, type)) {
# cluster munition
var lbs = warhead_lbs[type];
var maxDist = maxDamageDistFromWarhead(lbs);
var distance = math.max(0,rand()*2-full_damage_dist_m);#being 0 to 2 meters from a bomblet on average.
var diff = maxDist-distance;
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(probability, hp_max);
var percent = 100 * prob;
printf("Took %.1f%% damage from %s clusterbomb at %0.1f meters from bomblet. %s systems was hit", percent,type,distance,failed);
nearby_explosion();
return;
}
distance = math.max(distance-full_damage_dist_m, 0);
if (contains(warhead_lbs, type)) {
#maxDist = maxDamageDistFromWarhead(warhead_lbs[type]);
var maxDist = 0;# distance where the explosion dont hurt us anymore
var lbs = 0;
if (hitable_by_ground_munitions and contains(warhead_lbs, type)) {
lbs = warhead_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
} elsif (hitable_by_air_munitions and contains(warhead_air_lbs, type)) {
lbs = warhead_air_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);
} else {
return;
}
var prob = 1;
if (type == "M90" and distance < 300) {
var failed = fail_systems(warhead_lbs[type]/2);
return;
} elsif (distance < 150) {
if ( distance > 50 ) {
distance = distance - 50;
prob = 1 - (distance/100);
}
var diff = maxDist-distance;
if (diff < 0) {
diff = 0;
}
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(warhead_lbs[type] * prob);
#ar percent = 100 * probability;
#printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
var failed = fail_systems(probability, hp_max);
var percent = 100 * probability;
printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
nearby_explosion();
####
# I don't remember all the considerations that went into our original warhead damage model.
# But looking at the formula it looks like they all do 100% damage at 0 meter hit,
# and warhead size is only used to determine the decrease of damage with distance increase.
# It sorta gets the job done though, so I am hesitant to advocate that warheads above a certain
# size should give 100% damage for some distance, and that warheads smaller than certain size should
# not give 100% damage even on direct hit.
# Anyway, for hitpoint based assets, this is now the case. Maybe we should consider to also do something
# similar for failure mode based aircraft. ~Nikolai
####
## example 1: ##
# 300 lbs warhead, 50 meters distance
# maxDist=52
# diff = 52-50 = 2
# diff^2 = 4
# prob = 4/2700 = 0.15%
## example 2: ##
# 300 lbs warhead, 25 meters distance
# maxDist=52
# diff = 52-25 = 27
# diff^2 = 729
# prob = 729/2700 = 27%
}
}
} elsif (cannon_types[last_vector[1]] != nil) {
# cannon hitting someone
print("cannon");
} elsif (hitable_by_cannon and cannon_types[last_vector[1]] != nil) {
if (size(last_vector) > 2 and last_vector[2] == " "~callsign) {
print("cannon hit us");
if (size(last_vector) < 4) {
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
#print("last3[2]: " ~ last3[2]);
#print("last3[1]: " ~ last3[1]);
if(size(last3) > 2) {
if ( last3[2] == "hits" ) {
var hit_count = num(last3[1]);
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
if(size(last3) > 2 and size(last3[2]) > 2 and last3[2] == "hits" ) {
var probability = cannon_types[last_vector[1]];
var hit_count = num(last3[1]);
if (hit_count != nil) {
var damaged_sys = 0;
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
damaged_sys = damaged_sys + failed;
}
printf("Took %.1f%% x %2d damage from cannon! %s systems was hit.", probability*100, hit_count, damaged_sys);
nearby_explosion();
}
} else {
var hit_count = 4;
var probability = cannon_types[last_vector[1]];
#print("probability: " ~ probability);
var failed = fail_systems(probability * 3);# Old messages is assumed to be 3 hits
printf("Took %.1f%% x 3 damage from cannon! %s systems was hit.", probability*100, failed);
nearby_explosion();
}
var damaged_sys = 0;
var probability = cannon_types[last_vector[1]];
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
#damaged_sys = damaged_sys + failed;
}
# that someone is me!
#print("hitting me");
#printf("Took %.1f%% damage from cannon! %s systems was hit.", probability*hit_count*100, damaged_sys);
}
}
}
@ -235,44 +332,131 @@ var incoming_listener = func {
}
var maxDamageDistFromWarhead = func (lbs) {
# very simple
var dist = 7*math.sqrt(lbs);
# Calc at what distance the warhead will do zero damage every time.
var dist = 3*math.sqrt(lbs);
return dist;
}
var fail_systems = func (damage) {
var fail_systems = func (probability, factor = 100) {#this factor needs tuning after all asset hitpoints have been evaluated.
if (fleet) {
return fail_fleet_systems(probability, factor);
} elsif (use_hitpoints_instead_of_failure_modes_bool) {
hp -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP: %d/%d", hp, hp_max);
setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);#we are dead
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/multiplay/generic/int[0]",1);#smoke on
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
}
return -1;
} else {
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
var failed = 0;
foreach(var failure_mode_id; mode_list) {
if (rand() < probability) {
FailureMgr.set_failure_level(failure_mode_id, 1);
failed += 1;
}
}
return failed;
}
};
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
var fail_fleet_systems = func (probability, factor) {
var no = 7;
while (no > 6 or hp[no] < 0) {
while (no > 6 or hp_f[no] < 0) {
no = int(rand()*7);
if (hp[no] < 0) {
if (rand() > 0.8) {
if (hp_f[no] < 0) {
if (rand() > 0.9) {
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
hp[no] = hp[no] - damage;
print("HP["~no~"]: " ~ hp[no] ~ "/" ~ hp_max);
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
print("HP["~no~"]: " ~ hp_f[no] ~ "/" ~ hp_max);
return;
}
}
}
hp[no] = hp[no] - damage;
print("HP["~no~"]: " ~ hp[no] ~ "/" ~ hp_max);
if ( hp[no] < 0 ) {
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP[%d]: %d/%d", no, hp_f[no], hp_max);
#setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp_f[no] < 0 ) {
setprop("/sim/multiplay/generic/bool["~(no+40)~"]",1);
armament.defeatSpamFilter("So you sank one of our ships, we will get you for that!");
if (!getprop("/carrier/disabled") and hp[0]<0 and hp[1]<0 and hp[2]<0) {
if (!getprop("/carrier/disabled") and hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0) {
setprop("/carrier/disabled",1);
armament.defeatSpamFilter("Captain our offensive capability is crippled!");
}
if (hp[0]<0 and hp[1]<0 and hp[2]<0 and hp[3]<0 and hp[4]<0 and hp[5]<0 and hp[6]<0) {
if (hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0 and hp_f[3]<0 and hp_f[4]<0 and hp_f[5]<0 and hp_f[6]<0) {
setprop("/carrier/sunk",1);
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
armament.defeatSpamFilter("S.O.S. Heeelp");
} else {
armament.defeatSpamFilter("This is not over yet..");
}
}
return -1;
};
var warn = func (last_vector,m2000,callsign,author) {
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
};
}
var playIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 1);
@ -283,6 +467,20 @@ var stopIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 0);
}
var nearby_explosion = func {
setprop("damage/sounds/nearby-explode-on", 0);
settimer(nearby_explosion_a, 0);
}
var nearby_explosion_a = func {
setprop("damage/sounds/nearby-explode-on", 1);
settimer(nearby_explosion_b, 0.5);
}
var nearby_explosion_b = func {
setprop("damage/sounds/nearby-explode-on", 0);
}
var callsign_struct = {};
var getCallsign = func (callsign) {
var node = callsign_struct[callsign];
@ -298,20 +496,25 @@ var processCallsigns = func () {
callsign_struct[callsign] = player;
}
}
settimer(processCallsigns, 1.5);
settimer(processCallsigns, 5);
}
processCallsigns();
var logTime = func{
#log time and date for outputing ucsv files for converting into KML files for google earth.
if (getprop("logging/log[0]/enabled") == TRUE and getprop("sim/time/utc/year") != nil) {
var date = getprop("sim/time/utc/year")~"/"~getprop("sim/time/utc/month")~"/"~getprop("sim/time/utc/day");
var time = getprop("sim/time/utc/hour")~":"~getprop("sim/time/utc/minute")~":"~getprop("sim/time/utc/second");
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setprop("logging/date-log", date);
setprop("logging/time-log", time);
# prevent flooding the pilots screen with failure modes that fail when getting hit.
setprop("/sim/failure-manager/display-on-screen", FALSE);
var re_init = func {
# repair the aircraft at relocation to another airport.
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
foreach(var failure_mode_id; mode_list) {
FailureMgr.set_failure_level(failure_mode_id, 0);
}
}
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setlistener("/sim/signals/reinit", re_init, 0, 0);

View File

@ -1,30 +1,59 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
#
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
#
# Authors: Nikolai V. Chr. and Pinto (with improvement by Onox)
#
#
############################ Config ######################################################################################
var full_damage_dist_m =10;# Can vary from aircraft to aircraft depending on how many failure modes it has.
# Many modes (like Viggen) ought to have lower number like zero.
# Few modes (like F-14) ought to have larger number such as 3.
# For assets this should be average radius of the asset.
var use_hitpoints_instead_of_failure_modes_bool = 1;# mainly used by assets that don't have failure modes.
var hp_max = 80;# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
var hitable_by_air_munitions = 0; # if anti-air can do damage
var hitable_by_cannon = 1; # if cannon can do damage
var hitable_by_ground_munitions = 1;# if anti-ground/marine can do damage
var is_fleet = 0; # Is really 7 ships, 3 of which has offensive missiles.
##########################################################################################################################
##
## TODO:
## Include mechanics for hitting fleet
## Move all to emesary
##
var TRUE = 1;
var FALSE = 0;
var hp = 80;
var hp_max = hp;
var hp = hp_max;
var cannon_types = {
" M70 rocket hit": 0.25, #135mm
" M55 cannon shell hit": 0.10, # 30mm
" KCA cannon shell hit": 0.10, # 30mm
" Gun Splash On ": 0.10, # 30mm
" M61A1 shell hit": 0.05, # 20mm
" GAU-8/A hit": 0.10, # 30mm
" BK27 cannon hit": 0.07, # 27mm
" GSh-30 hit": 0.10, # 30mm
" GSh-23 hit": 0.065,# 23mm
" 7.62 hit": 0.005,# 7.62mm
" 50 BMG hit": 0.015,# 12.7mm
" S-5 rocket hit": 0.20, #55mm
};
#
# 0.20 means a direct hit will disable 20% of the failure modes on average.
# or, 0.20 also means a direct hit can do 20 hitpoints damage.
#
" M70 rocket hit": 0.250, #135mm
" S-5 rocket hit": 0.200, # 55mm
" M55 cannon shell hit": 0.100, # 30mm
" KCA cannon shell hit": 0.100, # 30mm
" Gun Splash On ": 0.100, # 30mm
" GSh-30 hit": 0.100, # 30mm
" GAU-8/A hit": 0.100, # 30mm
" BK27 cannon hit": 0.070, # 27mm
" GSh-23 hit": 0.065, # 23mm
" M61A1 shell hit": 0.050, # 20mm
" 50 BMG hit": 0.015, # 12.7mm (non-explosive)
" 7.62 hit": 0.005, # 7.62mm (non-explosive)
};
# lbs of warheads is explosive+fragmentation+fuse, so total warhead mass.
var warhead_lbs = {
# Anti-ground/marine warheads (sorted alphabetically)
"AGM-65": 126.00,
"AGM-84": 488.00,
"AGM-88": 146.00,
@ -35,7 +64,7 @@ var warhead_lbs = {
"AM39-Exocet": 364.00,
"AS-37-Martel": 330.00,
"AS30L": 529.00,
"CBU-87": 128.00,
"CBU-87": 10.00,# bomblet warhead. Mix of armour piecing and HE.
"Exocet": 364.00,
"FAB-100": 92.59,
"FAB-250": 202.85,
@ -49,12 +78,10 @@ var warhead_lbs = {
"KAB-500": 564.38,
"Kh-25MP": 197.53,
"Kh-66": 244.71,
"KN-06": 315.00,
"LAU-68": 10.00,
"M317": 145.00,
"M71": 200.00,
"M71R": 200.00,
"M90": 500.00,
"M90": 3.00,# bomblet warhead.
"MK-82": 192.00,
"MK-83": 445.00,
"MK-84": 945.00,
@ -67,8 +94,7 @@ var warhead_lbs = {
"RN-18T": 1200.00, #fictional, thermobaeric replacement for the RN-28 nuclear bomb
"RS-2US": 28.66,
"S-21": 245.00,
"S-24": 271.00,
"S530D": 66.00,
"S-24": 271.00,
"SCALP": 992.00,
"Sea Eagle": 505.00,
"SeaEagle": 505.00,
@ -77,6 +103,82 @@ var warhead_lbs = {
"ZB-500": 473.99,
};
var warhead_air_lbs = {
# Anti-air warheads (sorted alphabetically)
"aim-120": 44.00,
"AIM-120": 44.00,
"AIM-54": 135.00,
"aim-7": 88.00,
"AIM-7": 88.00,
"aim-9": 20.80,
"AIM-9": 20.80,
"AIM120": 44.00,
"AIM132": 22.05,
"AIM9": 20.80,
"KN-06": 315.00,
"M317": 145.00,
"Magic-2": 27.00,
"Matra MICA": 30.00,
"Matra R550 Magic 2": 27.00,
"MATRA-R530": 55.00,
"MatraMica": 30.00,
"MatraMicaIR": 30.00,
"MatraR550Magic2": 27.00,
"Meteor": 55.00,
"MICA-EM": 30.00,
"MICA-IR": 30.00,
"R-13M": 16.31,
"R-27R1": 85.98,
"R-27T1": 85.98,
"R-3R": 16.31,
"R-3S": 16.31,
"R-55": 20.06,
"R-60": 6.60,
"R-60M": 7.70,
"R-73E": 16.31,
"R-77": 49.60,
"R74": 16.00,
"RB-05A": 353.00,
"RB-24": 20.80,
"RB-24J": 20.80,
"RB-71": 88.00,
"RB-74": 20.80,
"RB-99": 44.00,
"S530D": 66.00,
};
var cluster = {
# cluster munition list
"M90": nil,
"CBU-87": nil,
};
var fireMsgs = {
# F14
" FOX3 at": nil, # radar
" FOX2 at": nil, # heat
" FOX1 at": nil, # semi-radar
# Generic
" Fox 1 at": nil, # semi-radar
" Fox 2 at": nil, # heat
" Fox 3 at": nil, # radar
" Greyhound at": nil, # cruise missile
" Bombs away at": nil, # bombs
" Bruiser at": nil, # anti-ship
" Rifle at": nil, # TV guided
" Sniper at": nil, # anti-radiation
# SAM, fleet and missile frigate
" Bird away at": nil, # G/A
# F15
" aim7 at": nil,
" aim9 at": nil,
" aim120 at": nil,
};
var incoming_listener = func {
var history = getprop("/sim/multiplay/chat-history");
var hist_vector = split("\n", history);
@ -85,6 +187,7 @@ var incoming_listener = func {
var last_vector = split(":", last);
var author = last_vector[0];
var callsign = getprop("sim/multiplay/callsign");
callsign = size(callsign) < 8 ? callsign : left(callsign,7);
if (size(last_vector) > 1 and author != callsign) {
# not myself
#print("not me");
@ -93,67 +196,10 @@ var incoming_listener = func {
# a m2000 is firing at us
m2000 = TRUE;
}
if (last_vector[1] == " FOX2 at" or last_vector[1] == " aim7 at" or last_vector[1] == " aim9 at"
or last_vector[1] == " aim120 at" or last_vector[1] == " RB-24J fired at" or last_vector[1] == " RB-74 fired at"
or last_vector[1] == " RB-71 fired at" or last_vector[1] == " RB-15F fired at"
or last_vector[1] == " RB-99 fired at" or m2000 == TRUE) {
if (contains(fireMsgs, last_vector[1]) or m2000 == TRUE) {
# air2air being fired
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
} elsif (1 == 1) { # mirage: getprop("/controls/armament/mp-messaging")
# latest version of failure manager and taking damage enabled
#print("damage enabled");
warn(last_vector,m2000,callsign,author);
} elsif (getprop("payload/armament/msg")) {
var last1 = split(" ", last_vector[1]);
if(size(last1) > 2 and last1[size(last1)-1] == "exploded" ) {
#print("missile hitting someone");
@ -171,56 +217,113 @@ var incoming_listener = func {
if(distance != nil) {
var dist = distance;
#check distance w/ if statement here
if (contains(cluster, type)) {
# cluster munition
var lbs = warhead_lbs[type];
var maxDist = maxDamageDistFromWarhead(lbs);
var distance = math.max(0,rand()*2-full_damage_dist_m);#being 0 to 2 meters from a bomblet on average.
var diff = maxDist-distance;
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(probability, hp_max);
var percent = 100 * prob;
printf("Took %.1f%% damage from %s clusterbomb at %0.1f meters from bomblet. %s systems was hit", percent,type,distance,failed);
nearby_explosion();
return;
}
distance = math.max(distance-full_damage_dist_m, 0);
if (contains(warhead_lbs, type)) {
#maxDist = maxDamageDistFromWarhead(warhead_lbs[type]);
var maxDist = 0;# distance where the explosion dont hurt us anymore
var lbs = 0;
if (hitable_by_ground_munitions and contains(warhead_lbs, type)) {
lbs = warhead_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
} elsif (hitable_by_air_munitions and contains(warhead_air_lbs, type)) {
lbs = warhead_air_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);
} else {
return;
}
if (type == "M90" and distance < 300) {
var failed = fail_systems(warhead_lbs[type]/2);
return;
} elsif (distance < 150) {
var prob = 1;
if ( distance > 50 ) {
distance = distance - 50;
prob = 1 - (distance/100);
}
var diff = maxDist-distance;
if (diff < 0) {
diff = 0;
}
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(warhead_lbs[type] * prob);
#ar percent = 100 * probability;
#printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
var failed = fail_systems(probability, hp_max);
var percent = 100 * probability;
printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
nearby_explosion();
####
# I don't remember all the considerations that went into our original warhead damage model.
# But looking at the formula it looks like they all do 100% damage at 0 meter hit,
# and warhead size is only used to determine the decrease of damage with distance increase.
# It sorta gets the job done though, so I am hesitant to advocate that warheads above a certain
# size should give 100% damage for some distance, and that warheads smaller than certain size should
# not give 100% damage even on direct hit.
# Anyway, for hitpoint based assets, this is now the case. Maybe we should consider to also do something
# similar for failure mode based aircraft. ~Nikolai
####
## example 1: ##
# 300 lbs warhead, 50 meters distance
# maxDist=52
# diff = 52-50 = 2
# diff^2 = 4
# prob = 4/2700 = 0.15%
## example 2: ##
# 300 lbs warhead, 25 meters distance
# maxDist=52
# diff = 52-25 = 27
# diff^2 = 729
# prob = 729/2700 = 27%
}
}
} elsif (cannon_types[last_vector[1]] != nil) {
# cannon hitting someone
print("cannon");
} elsif (hitable_by_cannon and cannon_types[last_vector[1]] != nil) {
if (size(last_vector) > 2 and last_vector[2] == " "~callsign) {
print("cannon hit us");
var last3 = split(" ", last_vector[3]);
#print("last3[2]: " ~ last3[2]);
#print("last3[1]: " ~ last3[1]);
if(size(last3) > 2) {
if ( last3[2] == "hits" ) {
var hit_count = num(last3[1]);
if (size(last_vector) < 4) {
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
if(size(last3) > 2 and size(last3[2]) > 2 and last3[2] == "hits" ) {
var probability = cannon_types[last_vector[1]];
var hit_count = num(last3[1]);
if (hit_count != nil) {
var damaged_sys = 0;
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
damaged_sys = damaged_sys + failed;
}
printf("Took %.1f%% x %2d damage from cannon! %s systems was hit.", probability*100, hit_count, damaged_sys);
nearby_explosion();
}
} else {
var hit_count = 4;
var probability = cannon_types[last_vector[1]];
#print("probability: " ~ probability);
var failed = fail_systems(probability * 3);# Old messages is assumed to be 3 hits
printf("Took %.1f%% x 3 damage from cannon! %s systems was hit.", probability*100, failed);
nearby_explosion();
}
var damaged_sys = 0;
var probability = cannon_types[last_vector[1]];
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
#damaged_sys = damaged_sys + failed;
}
# that someone is me!
#print("hitting me");
#printf("Took %.1f%% damage from cannon! %s systems was hit.", probability*hit_count*100, damaged_sys);
}
}
}
@ -229,22 +332,132 @@ var incoming_listener = func {
}
var maxDamageDistFromWarhead = func (lbs) {
# very simple
var dist = 7*math.sqrt(lbs);
# Calc at what distance the warhead will do zero damage every time.
var dist = 3*math.sqrt(lbs);
return dist;
}
var fail_systems = func (damage) {
hp = hp - damage;
print("HP: " ~ hp ~ "/" ~ hp_max);
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);
setprop("/sim/multiplay/generic/int[0]",1);
}
var fail_systems = func (probability, factor = 100) {#this factor needs tuning after all asset hitpoints have been evaluated.
if (fleet) {
return fail_fleet_systems(probability, factor);
} elsif (use_hitpoints_instead_of_failure_modes_bool) {
hp -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP: %d/%d", hp, hp_max);
setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);#we are dead
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/multiplay/generic/int[0]",1);#smoke on
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
}
return -1;
} else {
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
var failed = 0;
foreach(var failure_mode_id; mode_list) {
if (rand() < probability) {
FailureMgr.set_failure_level(failure_mode_id, 1);
failed += 1;
}
}
return failed;
}
};
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
var fail_fleet_systems = func (probability, factor) {
var no = 7;
while (no > 6 or hp_f[no] < 0) {
no = int(rand()*7);
if (hp_f[no] < 0) {
if (rand() > 0.9) {
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
print("HP["~no~"]: " ~ hp_f[no] ~ "/" ~ hp_max);
return;
}
}
}
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP[%d]: %d/%d", no, hp_f[no], hp_max);
#setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp_f[no] < 0 ) {
setprop("/sim/multiplay/generic/bool["~(no+40)~"]",1);
armament.defeatSpamFilter("So you sank one of our ships, we will get you for that!");
if (!getprop("/carrier/disabled") and hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0) {
setprop("/carrier/disabled",1);
armament.defeatSpamFilter("Captain our offensive capability is crippled!");
}
if (hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0 and hp_f[3]<0 and hp_f[4]<0 and hp_f[5]<0 and hp_f[6]<0) {
setprop("/carrier/sunk",1);
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
armament.defeatSpamFilter("S.O.S. Heeelp");
} else {
armament.defeatSpamFilter("This is not over yet..");
}
}
return -1;
};
var warn = func (last_vector,m2000,callsign,author) {
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
}
var playIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 1);
settimer(func {stopIncomingSound(clock);},3);
@ -254,6 +467,20 @@ var stopIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 0);
}
var nearby_explosion = func {
setprop("damage/sounds/nearby-explode-on", 0);
settimer(nearby_explosion_a, 0);
}
var nearby_explosion_a = func {
setprop("damage/sounds/nearby-explode-on", 1);
settimer(nearby_explosion_b, 0.5);
}
var nearby_explosion_b = func {
setprop("damage/sounds/nearby-explode-on", 0);
}
var callsign_struct = {};
var getCallsign = func (callsign) {
var node = callsign_struct[callsign];
@ -269,20 +496,25 @@ var processCallsigns = func () {
callsign_struct[callsign] = player;
}
}
settimer(processCallsigns, 1.5);
settimer(processCallsigns, 5);
}
processCallsigns();
var logTime = func{
#log time and date for outputing ucsv files for converting into KML files for google earth.
if (getprop("logging/log[0]/enabled") == TRUE and getprop("sim/time/utc/year") != nil) {
var date = getprop("sim/time/utc/year")~"/"~getprop("sim/time/utc/month")~"/"~getprop("sim/time/utc/day");
var time = getprop("sim/time/utc/hour")~":"~getprop("sim/time/utc/minute")~":"~getprop("sim/time/utc/second");
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setprop("logging/date-log", date);
setprop("logging/time-log", time);
# prevent flooding the pilots screen with failure modes that fail when getting hit.
setprop("/sim/failure-manager/display-on-screen", FALSE);
var re_init = func {
# repair the aircraft at relocation to another airport.
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
foreach(var failure_mode_id; mode_list) {
FailureMgr.set_failure_level(failure_mode_id, 0);
}
}
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setlistener("/sim/signals/reinit", re_init, 0, 0);

View File

@ -102,6 +102,12 @@
<carrier>
<sunk type="bool">false</sunk>
</carrier>
<payload>
<armament>
<msg type="bool">true</msg>
</armament>
</payload>
<nasal>
<damage> <file>Aircraft/gci-radar/Nasal/damage.nas</file> </damage>

View File

@ -1,29 +1,59 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
#
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
#
# Authors: Nikolai V. Chr. and Pinto (with improvement by Onox)
#
#
############################ Config ######################################################################################
var full_damage_dist_m = 2;# Can vary from aircraft to aircraft depending on how many failure modes it has.
# Many modes (like Viggen) ought to have lower number like zero.
# Few modes (like F-14) ought to have larger number such as 3.
# For assets this should be average radius of the asset.
var use_hitpoints_instead_of_failure_modes_bool = 1;# mainly used by assets that don't have failure modes.
var hp_max = 5;# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
var hitable_by_air_munitions = 0; # if anti-air can do damage
var hitable_by_cannon = 1; # if cannon can do damage
var hitable_by_ground_munitions = 1;# if anti-ground/marine can do damage
var is_fleet = 0; # Is really 7 ships, 3 of which has offensive missiles.
##########################################################################################################################
##
## TODO:
## Include mechanics for hitting fleet
## Move all to emesary
##
var TRUE = 1;
var FALSE = 0;
var hp = 5;
var hp_max = hp;
var hp = hp_max;
var cannon_types = {
" M70 rocket hit": 0.25, #135mm
" M55 cannon shell hit": 0.10, # 30mm
" KCA cannon shell hit": 0.10, # 30mm
" Gun Splash On ": 0.10, # 30mm
" M61A1 shell hit": 0.05, # 20mm
" GAU-8/A hit": 0.10, # 30mm
" BK27 cannon hit": 0.07, # 27mm
" GSh-30 hit": 0.10, # 30mm
" GSh-23 hit": 0.065,# 23mm
" 7.62 hit": 0.005,# 7.62mm
" 50 BMG hit": 0.015,# 12.7mm
" S-5 rocket hit": 0.20, #55mm
};
#
# 0.20 means a direct hit will disable 20% of the failure modes on average.
# or, 0.20 also means a direct hit can do 20 hitpoints damage.
#
" M70 rocket hit": 0.250, #135mm
" S-5 rocket hit": 0.200, # 55mm
" M55 cannon shell hit": 0.100, # 30mm
" KCA cannon shell hit": 0.100, # 30mm
" Gun Splash On ": 0.100, # 30mm
" GSh-30 hit": 0.100, # 30mm
" GAU-8/A hit": 0.100, # 30mm
" BK27 cannon hit": 0.070, # 27mm
" GSh-23 hit": 0.065, # 23mm
" M61A1 shell hit": 0.050, # 20mm
" 50 BMG hit": 0.015, # 12.7mm (non-explosive)
" 7.62 hit": 0.005, # 7.62mm (non-explosive)
};
# lbs of warheads is explosive+fragmentation+fuse, so total warhead mass.
var warhead_lbs = {
# Anti-ground/marine warheads (sorted alphabetically)
"AGM-65": 126.00,
"AGM-84": 488.00,
"AGM-88": 146.00,
@ -34,7 +64,7 @@ var warhead_lbs = {
"AM39-Exocet": 364.00,
"AS-37-Martel": 330.00,
"AS30L": 529.00,
"CBU-87": 128.00,
"CBU-87": 10.00,# bomblet warhead. Mix of armour piecing and HE.
"Exocet": 364.00,
"FAB-100": 92.59,
"FAB-250": 202.85,
@ -48,12 +78,10 @@ var warhead_lbs = {
"KAB-500": 564.38,
"Kh-25MP": 197.53,
"Kh-66": 244.71,
"KN-06": 315.00,
"LAU-68": 10.00,
"M317": 145.00,
"M71": 200.00,
"M71R": 200.00,
"M90": 500.00,
"M90": 3.00,# bomblet warhead.
"MK-82": 192.00,
"MK-83": 445.00,
"MK-84": 945.00,
@ -66,8 +94,7 @@ var warhead_lbs = {
"RN-18T": 1200.00, #fictional, thermobaeric replacement for the RN-28 nuclear bomb
"RS-2US": 28.66,
"S-21": 245.00,
"S-24": 271.00,
"S530D": 66.00,
"S-24": 271.00,
"SCALP": 992.00,
"Sea Eagle": 505.00,
"SeaEagle": 505.00,
@ -76,6 +103,82 @@ var warhead_lbs = {
"ZB-500": 473.99,
};
var warhead_air_lbs = {
# Anti-air warheads (sorted alphabetically)
"aim-120": 44.00,
"AIM-120": 44.00,
"AIM-54": 135.00,
"aim-7": 88.00,
"AIM-7": 88.00,
"aim-9": 20.80,
"AIM-9": 20.80,
"AIM120": 44.00,
"AIM132": 22.05,
"AIM9": 20.80,
"KN-06": 315.00,
"M317": 145.00,
"Magic-2": 27.00,
"Matra MICA": 30.00,
"Matra R550 Magic 2": 27.00,
"MATRA-R530": 55.00,
"MatraMica": 30.00,
"MatraMicaIR": 30.00,
"MatraR550Magic2": 27.00,
"Meteor": 55.00,
"MICA-EM": 30.00,
"MICA-IR": 30.00,
"R-13M": 16.31,
"R-27R1": 85.98,
"R-27T1": 85.98,
"R-3R": 16.31,
"R-3S": 16.31,
"R-55": 20.06,
"R-60": 6.60,
"R-60M": 7.70,
"R-73E": 16.31,
"R-77": 49.60,
"R74": 16.00,
"RB-05A": 353.00,
"RB-24": 20.80,
"RB-24J": 20.80,
"RB-71": 88.00,
"RB-74": 20.80,
"RB-99": 44.00,
"S530D": 66.00,
};
var cluster = {
# cluster munition list
"M90": nil,
"CBU-87": nil,
};
var fireMsgs = {
# F14
" FOX3 at": nil, # radar
" FOX2 at": nil, # heat
" FOX1 at": nil, # semi-radar
# Generic
" Fox 1 at": nil, # semi-radar
" Fox 2 at": nil, # heat
" Fox 3 at": nil, # radar
" Greyhound at": nil, # cruise missile
" Bombs away at": nil, # bombs
" Bruiser at": nil, # anti-ship
" Rifle at": nil, # TV guided
" Sniper at": nil, # anti-radiation
# SAM, fleet and missile frigate
" Bird away at": nil, # G/A
# F15
" aim7 at": nil,
" aim9 at": nil,
" aim120 at": nil,
};
var incoming_listener = func {
var history = getprop("/sim/multiplay/chat-history");
var hist_vector = split("\n", history);
@ -93,67 +196,10 @@ var incoming_listener = func {
# a m2000 is firing at us
m2000 = TRUE;
}
if (last_vector[1] == " FOX2 at" or last_vector[1] == " aim7 at" or last_vector[1] == " aim9 at"
or last_vector[1] == " aim120 at" or last_vector[1] == " RB-24J fired at" or last_vector[1] == " RB-74 fired at"
or last_vector[1] == " RB-71 fired at" or last_vector[1] == " RB-15F fired at"
or last_vector[1] == " RB-99 fired at" or m2000 == TRUE) {
if (contains(fireMsgs, last_vector[1]) or m2000 == TRUE) {
# air2air being fired
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
} elsif (1 == 1) { # mirage: getprop("/controls/armament/mp-messaging")
# latest version of failure manager and taking damage enabled
#print("damage enabled");
warn(last_vector,m2000,callsign,author);
} elsif (getprop("payload/armament/msg")) {
var last1 = split(" ", last_vector[1]);
if(size(last1) > 2 and last1[size(last1)-1] == "exploded" ) {
#print("missile hitting someone");
@ -171,60 +217,113 @@ var incoming_listener = func {
if(distance != nil) {
var dist = distance;
#check distance w/ if statement here
if (contains(cluster, type)) {
# cluster munition
var lbs = warhead_lbs[type];
var maxDist = maxDamageDistFromWarhead(lbs);
var distance = math.max(0,rand()*2-full_damage_dist_m);#being 0 to 2 meters from a bomblet on average.
var diff = maxDist-distance;
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(probability, hp_max);
var percent = 100 * prob;
printf("Took %.1f%% damage from %s clusterbomb at %0.1f meters from bomblet. %s systems was hit", percent,type,distance,failed);
nearby_explosion();
return;
}
distance = math.max(distance-full_damage_dist_m, 0);
if (contains(warhead_lbs, type)) {
#maxDist = maxDamageDistFromWarhead(warhead_lbs[type]);
var maxDist = 0;# distance where the explosion dont hurt us anymore
var lbs = 0;
if (hitable_by_ground_munitions and contains(warhead_lbs, type)) {
lbs = warhead_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
} elsif (hitable_by_air_munitions and contains(warhead_air_lbs, type)) {
lbs = warhead_air_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);
} else {
return;
}
var prob = 1;
if (type == "M90" and distance < 300) {
var failed = fail_systems(warhead_lbs[type]/2);
return;
} elsif (distance < 150) {
if ( distance > 50 ) {
distance = distance - 50;
prob = 1 - (distance/100);
}
var diff = maxDist-distance;
if (diff < 0) {
diff = 0;
}
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
fail_systems(warhead_lbs[type] * prob);
#ar percent = 100 * probability;
#printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
var failed = fail_systems(probability, hp_max);
var percent = 100 * probability;
printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
nearby_explosion();
####
# I don't remember all the considerations that went into our original warhead damage model.
# But looking at the formula it looks like they all do 100% damage at 0 meter hit,
# and warhead size is only used to determine the decrease of damage with distance increase.
# It sorta gets the job done though, so I am hesitant to advocate that warheads above a certain
# size should give 100% damage for some distance, and that warheads smaller than certain size should
# not give 100% damage even on direct hit.
# Anyway, for hitpoint based assets, this is now the case. Maybe we should consider to also do something
# similar for failure mode based aircraft. ~Nikolai
####
## example 1: ##
# 300 lbs warhead, 50 meters distance
# maxDist=52
# diff = 52-50 = 2
# diff^2 = 4
# prob = 4/2700 = 0.15%
## example 2: ##
# 300 lbs warhead, 25 meters distance
# maxDist=52
# diff = 52-25 = 27
# diff^2 = 729
# prob = 729/2700 = 27%
}
}
} elsif (cannon_types[last_vector[1]] != nil) {
# cannon hitting someone
print("cannon");
} elsif (hitable_by_cannon and cannon_types[last_vector[1]] != nil) {
if (size(last_vector) > 2 and last_vector[2] == " "~callsign) {
print("cannon hit us");
if (size(last_vector) < 4) {
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
#print("last3[2]: " ~ last3[2]);
#print("last3[1]: " ~ last3[1]);
if(size(last3) > 2) {
if ( last3[2] == "hits" ) {
var hit_count = num(last3[1]);
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
if(size(last3) > 2 and size(last3[2]) > 2 and last3[2] == "hits" ) {
var probability = cannon_types[last_vector[1]];
var hit_count = num(last3[1]);
if (hit_count != nil) {
var damaged_sys = 0;
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
damaged_sys = damaged_sys + failed;
}
printf("Took %.1f%% x %2d damage from cannon! %s systems was hit.", probability*100, hit_count, damaged_sys);
nearby_explosion();
}
} else {
var hit_count = 4;
var probability = cannon_types[last_vector[1]];
#print("probability: " ~ probability);
var failed = fail_systems(probability * 3);# Old messages is assumed to be 3 hits
printf("Took %.1f%% x 3 damage from cannon! %s systems was hit.", probability*100, failed);
nearby_explosion();
}
var damaged_sys = 0;
var probability = cannon_types[last_vector[1]];
for (var i = 1; i <= hit_count; i = i + 1) {
fail_systems(probability);
}
# that someone is me!
#print("hitting me");
printf("Took %.1f%% damage from cannon! %s systems was hit.", probability*hit_count*100, damaged_sys);
}
}
}
@ -233,22 +332,132 @@ var incoming_listener = func {
}
var maxDamageDistFromWarhead = func (lbs) {
# very simple
var dist = 7*math.sqrt(lbs);
# Calc at what distance the warhead will do zero damage every time.
var dist = 3*math.sqrt(lbs);
return dist;
}
var fail_systems = func (damage) {
hp = hp - damage;
print("HP: " ~ hp ~ "/" ~ hp_max);
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);
setprop("/sim/multiplay/generic/int[0]",1);
}
var fail_systems = func (probability, factor = 100) {#this factor needs tuning after all asset hitpoints have been evaluated.
if (fleet) {
return fail_fleet_systems(probability, factor);
} elsif (use_hitpoints_instead_of_failure_modes_bool) {
hp -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP: %d/%d", hp, hp_max);
setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);#we are dead
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/multiplay/generic/int[0]",1);#smoke on
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
}
return -1;
} else {
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
var failed = 0;
foreach(var failure_mode_id; mode_list) {
if (rand() < probability) {
FailureMgr.set_failure_level(failure_mode_id, 1);
failed += 1;
}
}
return failed;
}
};
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
var fail_fleet_systems = func (probability, factor) {
var no = 7;
while (no > 6 or hp_f[no] < 0) {
no = int(rand()*7);
if (hp_f[no] < 0) {
if (rand() > 0.9) {
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
print("HP["~no~"]: " ~ hp_f[no] ~ "/" ~ hp_max);
return;
}
}
}
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP[%d]: %d/%d", no, hp_f[no], hp_max);
#setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp_f[no] < 0 ) {
setprop("/sim/multiplay/generic/bool["~(no+40)~"]",1);
armament.defeatSpamFilter("So you sank one of our ships, we will get you for that!");
if (!getprop("/carrier/disabled") and hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0) {
setprop("/carrier/disabled",1);
armament.defeatSpamFilter("Captain our offensive capability is crippled!");
}
if (hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0 and hp_f[3]<0 and hp_f[4]<0 and hp_f[5]<0 and hp_f[6]<0) {
setprop("/carrier/sunk",1);
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
armament.defeatSpamFilter("S.O.S. Heeelp");
} else {
armament.defeatSpamFilter("This is not over yet..");
}
}
return -1;
};
var warn = func (last_vector,m2000,callsign,author) {
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
}
var playIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 1);
settimer(func {stopIncomingSound(clock);},3);
@ -258,6 +467,20 @@ var stopIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 0);
}
var nearby_explosion = func {
setprop("damage/sounds/nearby-explode-on", 0);
settimer(nearby_explosion_a, 0);
}
var nearby_explosion_a = func {
setprop("damage/sounds/nearby-explode-on", 1);
settimer(nearby_explosion_b, 0.5);
}
var nearby_explosion_b = func {
setprop("damage/sounds/nearby-explode-on", 0);
}
var callsign_struct = {};
var getCallsign = func (callsign) {
var node = callsign_struct[callsign];
@ -273,20 +496,25 @@ var processCallsigns = func () {
callsign_struct[callsign] = player;
}
}
settimer(processCallsigns, 1.5);
settimer(processCallsigns, 5);
}
processCallsigns();
var logTime = func{
#log time and date for outputing ucsv files for converting into KML files for google earth.
if (getprop("logging/log[0]/enabled") == TRUE and getprop("sim/time/utc/year") != nil) {
var date = getprop("sim/time/utc/year")~"/"~getprop("sim/time/utc/month")~"/"~getprop("sim/time/utc/day");
var time = getprop("sim/time/utc/hour")~":"~getprop("sim/time/utc/minute")~":"~getprop("sim/time/utc/second");
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setprop("logging/date-log", date);
setprop("logging/time-log", time);
# prevent flooding the pilots screen with failure modes that fail when getting hit.
setprop("/sim/failure-manager/display-on-screen", FALSE);
var re_init = func {
# repair the aircraft at relocation to another airport.
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
foreach(var failure_mode_id; mode_list) {
FailureMgr.set_failure_level(failure_mode_id, 0);
}
}
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setlistener("/sim/signals/reinit", re_init, 0, 0);

View File

@ -127,6 +127,12 @@
</property-rule>
</systems>
</sim>
<payload>
<armament>
<msg type="bool">true</msg>
</armament>
</payload>
<nasal>
<carrier>

View File

@ -1,29 +1,59 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
#
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
#
# Authors: Nikolai V. Chr. and Pinto (with improvement by Onox)
#
#
############################ Config ######################################################################################
var full_damage_dist_m =20;# Can vary from aircraft to aircraft depending on how many failure modes it has.
# Many modes (like Viggen) ought to have lower number like zero.
# Few modes (like F-14) ought to have larger number such as 3.
# For assets this should be average radius of the asset.
var use_hitpoints_instead_of_failure_modes_bool = 1;# mainly used by assets that don't have failure modes.
var hp_max =200;# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
var hitable_by_air_munitions = 0; # if anti-air can do damage
var hitable_by_cannon = 1; # if cannon can do damage
var hitable_by_ground_munitions = 1;# if anti-ground/marine can do damage
var is_fleet = 0; # Is really 7 ships, 3 of which has offensive missiles.
##########################################################################################################################
##
## TODO:
## Include mechanics for hitting fleet
## Move all to emesary
##
var TRUE = 1;
var FALSE = 0;
var hp = 200;
var hp_max = hp;
var hp = hp_max;
var cannon_types = {
" M70 rocket hit": 0.25, #135mm
" M55 cannon shell hit": 0.10, # 30mm
" KCA cannon shell hit": 0.10, # 30mm
" Gun Splash On ": 0.10, # 30mm
" M61A1 shell hit": 0.05, # 20mm
" GAU-8/A hit": 0.10, # 30mm
" BK27 cannon hit": 0.07, # 27mm
" GSh-30 hit": 0.10, # 30mm
" GSh-23 hit": 0.065,# 23mm
" 7.62 hit": 0.005,# 7.62mm
" 50 BMG hit": 0.015,# 12.7mm
" S-5 rocket hit": 0.20, #55mm
};
#
# 0.20 means a direct hit will disable 20% of the failure modes on average.
# or, 0.20 also means a direct hit can do 20 hitpoints damage.
#
" M70 rocket hit": 0.250, #135mm
" S-5 rocket hit": 0.200, # 55mm
" M55 cannon shell hit": 0.100, # 30mm
" KCA cannon shell hit": 0.100, # 30mm
" Gun Splash On ": 0.100, # 30mm
" GSh-30 hit": 0.100, # 30mm
" GAU-8/A hit": 0.100, # 30mm
" BK27 cannon hit": 0.070, # 27mm
" GSh-23 hit": 0.065, # 23mm
" M61A1 shell hit": 0.050, # 20mm
" 50 BMG hit": 0.015, # 12.7mm (non-explosive)
" 7.62 hit": 0.005, # 7.62mm (non-explosive)
};
# lbs of warheads is explosive+fragmentation+fuse, so total warhead mass.
var warhead_lbs = {
# Anti-ground/marine warheads (sorted alphabetically)
"AGM-65": 126.00,
"AGM-84": 488.00,
"AGM-88": 146.00,
@ -34,7 +64,7 @@ var warhead_lbs = {
"AM39-Exocet": 364.00,
"AS-37-Martel": 330.00,
"AS30L": 529.00,
"CBU-87": 128.00,
"CBU-87": 10.00,# bomblet warhead. Mix of armour piecing and HE.
"Exocet": 364.00,
"FAB-100": 92.59,
"FAB-250": 202.85,
@ -48,12 +78,10 @@ var warhead_lbs = {
"KAB-500": 564.38,
"Kh-25MP": 197.53,
"Kh-66": 244.71,
"KN-06": 315.00,
"LAU-68": 10.00,
"M317": 145.00,
"M71": 200.00,
"M71R": 200.00,
"M90": 500.00,
"M90": 3.00,# bomblet warhead.
"MK-82": 192.00,
"MK-83": 445.00,
"MK-84": 945.00,
@ -66,8 +94,7 @@ var warhead_lbs = {
"RN-18T": 1200.00, #fictional, thermobaeric replacement for the RN-28 nuclear bomb
"RS-2US": 28.66,
"S-21": 245.00,
"S-24": 271.00,
"S530D": 66.00,
"S-24": 271.00,
"SCALP": 992.00,
"Sea Eagle": 505.00,
"SeaEagle": 505.00,
@ -76,6 +103,82 @@ var warhead_lbs = {
"ZB-500": 473.99,
};
var warhead_air_lbs = {
# Anti-air warheads (sorted alphabetically)
"aim-120": 44.00,
"AIM-120": 44.00,
"AIM-54": 135.00,
"aim-7": 88.00,
"AIM-7": 88.00,
"aim-9": 20.80,
"AIM-9": 20.80,
"AIM120": 44.00,
"AIM132": 22.05,
"AIM9": 20.80,
"KN-06": 315.00,
"M317": 145.00,
"Magic-2": 27.00,
"Matra MICA": 30.00,
"Matra R550 Magic 2": 27.00,
"MATRA-R530": 55.00,
"MatraMica": 30.00,
"MatraMicaIR": 30.00,
"MatraR550Magic2": 27.00,
"Meteor": 55.00,
"MICA-EM": 30.00,
"MICA-IR": 30.00,
"R-13M": 16.31,
"R-27R1": 85.98,
"R-27T1": 85.98,
"R-3R": 16.31,
"R-3S": 16.31,
"R-55": 20.06,
"R-60": 6.60,
"R-60M": 7.70,
"R-73E": 16.31,
"R-77": 49.60,
"R74": 16.00,
"RB-05A": 353.00,
"RB-24": 20.80,
"RB-24J": 20.80,
"RB-71": 88.00,
"RB-74": 20.80,
"RB-99": 44.00,
"S530D": 66.00,
};
var cluster = {
# cluster munition list
"M90": nil,
"CBU-87": nil,
};
var fireMsgs = {
# F14
" FOX3 at": nil, # radar
" FOX2 at": nil, # heat
" FOX1 at": nil, # semi-radar
# Generic
" Fox 1 at": nil, # semi-radar
" Fox 2 at": nil, # heat
" Fox 3 at": nil, # radar
" Greyhound at": nil, # cruise missile
" Bombs away at": nil, # bombs
" Bruiser at": nil, # anti-ship
" Rifle at": nil, # TV guided
" Sniper at": nil, # anti-radiation
# SAM, fleet and missile frigate
" Bird away at": nil, # G/A
# F15
" aim7 at": nil,
" aim9 at": nil,
" aim120 at": nil,
};
var incoming_listener = func {
var history = getprop("/sim/multiplay/chat-history");
var hist_vector = split("\n", history);
@ -93,67 +196,10 @@ var incoming_listener = func {
# a m2000 is firing at us
m2000 = TRUE;
}
if (last_vector[1] == " FOX2 at" or last_vector[1] == " aim7 at" or last_vector[1] == " aim9 at"
or last_vector[1] == " aim120 at" or last_vector[1] == " RB-24J fired at" or last_vector[1] == " RB-74 fired at"
or last_vector[1] == " RB-71 fired at" or last_vector[1] == " RB-15F fired at"
or last_vector[1] == " RB-99 fired at" or m2000 == TRUE) {
if (contains(fireMsgs, last_vector[1]) or m2000 == TRUE) {
# air2air being fired
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
} elsif (1 == 1) { # mirage: getprop("/controls/armament/mp-messaging")
# latest version of failure manager and taking damage enabled
#print("damage enabled");
warn(last_vector,m2000,callsign,author);
} elsif (getprop("payload/armament/msg")) {
var last1 = split(" ", last_vector[1]);
if(size(last1) > 2 and last1[size(last1)-1] == "exploded" ) {
#print("missile hitting someone");
@ -171,61 +217,113 @@ var incoming_listener = func {
if(distance != nil) {
var dist = distance;
#check distance w/ if statement here
if (contains(cluster, type)) {
# cluster munition
var lbs = warhead_lbs[type];
var maxDist = maxDamageDistFromWarhead(lbs);
var distance = math.max(0,rand()*2-full_damage_dist_m);#being 0 to 2 meters from a bomblet on average.
var diff = maxDist-distance;
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(probability, hp_max);
var percent = 100 * prob;
printf("Took %.1f%% damage from %s clusterbomb at %0.1f meters from bomblet. %s systems was hit", percent,type,distance,failed);
nearby_explosion();
return;
}
distance = math.max(distance-full_damage_dist_m, 0);
if (contains(warhead_lbs, type)) {
#maxDist = maxDamageDistFromWarhead(warhead_lbs[type]);
var maxDist = 0;# distance where the explosion dont hurt us anymore
var lbs = 0;
if (hitable_by_ground_munitions and contains(warhead_lbs, type)) {
lbs = warhead_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
} elsif (hitable_by_air_munitions and contains(warhead_air_lbs, type)) {
lbs = warhead_air_lbs[type];
maxDist = maxDamageDistFromWarhead(lbs);
} else {
return;
}
var prob = 1;
if (type == "M90" and distance < 300) {
var failed = fail_systems(warhead_lbs[type]/2);
return;
} elsif (distance < 150) {
if ( distance > 50 ) {
distance = distance - 50;
prob = 1 - (distance/100);
}
var diff = maxDist-distance;
if (diff < 0) {
diff = 0;
}
diff = diff * diff;
var probability = diff / (maxDist*maxDist);
if (use_hitpoints_instead_of_failure_modes_bool) {
var hpDist = maxDamageDistFromWarhead(hp_max);
probability = (maxDist/hpDist)*probability;
}
var failed = fail_systems(warhead_lbs[type] * prob);
#ar percent = 100 * probability;
#printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
var failed = fail_systems(probability, hp_max);
var percent = 100 * probability;
printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
nearby_explosion();
####
# I don't remember all the considerations that went into our original warhead damage model.
# But looking at the formula it looks like they all do 100% damage at 0 meter hit,
# and warhead size is only used to determine the decrease of damage with distance increase.
# It sorta gets the job done though, so I am hesitant to advocate that warheads above a certain
# size should give 100% damage for some distance, and that warheads smaller than certain size should
# not give 100% damage even on direct hit.
# Anyway, for hitpoint based assets, this is now the case. Maybe we should consider to also do something
# similar for failure mode based aircraft. ~Nikolai
####
## example 1: ##
# 300 lbs warhead, 50 meters distance
# maxDist=52
# diff = 52-50 = 2
# diff^2 = 4
# prob = 4/2700 = 0.15%
## example 2: ##
# 300 lbs warhead, 25 meters distance
# maxDist=52
# diff = 52-25 = 27
# diff^2 = 729
# prob = 729/2700 = 27%
}
}
} elsif (cannon_types[last_vector[1]] != nil) {
# cannon hitting someone
print("cannon");
} elsif (hitable_by_cannon and cannon_types[last_vector[1]] != nil) {
if (size(last_vector) > 2 and last_vector[2] == " "~callsign) {
print("cannon hit us");
if (size(last_vector) < 4) {
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
#print("last3[2]: " ~ last3[2]);
#print("last3[1]: " ~ last3[1]);
if(size(last3) > 2) {
if ( last3[2] == "hits" ) {
var hit_count = num(last3[1]);
# msg is either missing number of hits, or has no trailing dots from spam filter.
print('"'~last~'" is not a legal hit message, tell the shooter to upgrade his OPRF plane :)');
return;
}
var last3 = split(" ", last_vector[3]);
if(size(last3) > 2 and size(last3[2]) > 2 and last3[2] == "hits" ) {
var probability = cannon_types[last_vector[1]];
var hit_count = num(last3[1]);
if (hit_count != nil) {
var damaged_sys = 0;
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
damaged_sys = damaged_sys + failed;
}
printf("Took %.1f%% x %2d damage from cannon! %s systems was hit.", probability*100, hit_count, damaged_sys);
nearby_explosion();
}
} else {
var hit_count = 4;
var probability = cannon_types[last_vector[1]];
#print("probability: " ~ probability);
var failed = fail_systems(probability * 3);# Old messages is assumed to be 3 hits
printf("Took %.1f%% x 3 damage from cannon! %s systems was hit.", probability*100, failed);
nearby_explosion();
}
var damaged_sys = 0;
var probability = cannon_types[last_vector[1]];
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
#damaged_sys = damaged_sys + failed;
}
# that someone is me!
#print("hitting me");
#printf("Took %.1f%% damage from cannon! %s systems was hit.", probability*hit_count*100, damaged_sys);
}
}
}
@ -234,22 +332,132 @@ var incoming_listener = func {
}
var maxDamageDistFromWarhead = func (lbs) {
# very simple
var dist = 7*math.sqrt(lbs);
# Calc at what distance the warhead will do zero damage every time.
var dist = 3*math.sqrt(lbs);
return dist;
}
var fail_systems = func (damage) {
hp = hp - damage;
print("HP: " ~ hp ~ "/" ~ hp_max);
if ( hp < 0 ) {
setprop("/sim/multiplay/generic/int[2]",1);
setprop("/carrier/sunk/",1);
}
var fail_systems = func (probability, factor = 100) {#this factor needs tuning after all asset hitpoints have been evaluated.
if (fleet) {
return fail_fleet_systems(probability, factor);
} elsif (use_hitpoints_instead_of_failure_modes_bool) {
hp -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP: %d/%d", hp, hp_max);
setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);#we are dead
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/multiplay/generic/int[0]",1);#smoke on
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
}
return -1;
} else {
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
var failed = 0;
foreach(var failure_mode_id; mode_list) {
if (rand() < probability) {
FailureMgr.set_failure_level(failure_mode_id, 1);
failed += 1;
}
}
return failed;
}
};
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
var fail_fleet_systems = func (probability, factor) {
var no = 7;
while (no > 6 or hp_f[no] < 0) {
no = int(rand()*7);
if (hp_f[no] < 0) {
if (rand() > 0.9) {
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
print("HP["~no~"]: " ~ hp_f[no] ~ "/" ~ hp_max);
return;
}
}
}
hp_f[no] -= factor * probability*(0.75+rand()*0.25);# from 75 to 100% damage
printf("HP[%d]: %d/%d", no, hp_f[no], hp_max);
#setprop("sam/damage", math.max(0,100*hp/hp_max));#used in HUD
if ( hp_f[no] < 0 ) {
setprop("/sim/multiplay/generic/bool["~(no+40)~"]",1);
armament.defeatSpamFilter("So you sank one of our ships, we will get you for that!");
if (!getprop("/carrier/disabled") and hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0) {
setprop("/carrier/disabled",1);
armament.defeatSpamFilter("Captain our offensive capability is crippled!");
}
if (hp_f[0]<0 and hp_f[1]<0 and hp_f[2]<0 and hp_f[3]<0 and hp_f[4]<0 and hp_f[5]<0 and hp_f[6]<0) {
setprop("/carrier/sunk",1);
setprop("/sim/multiplay/generic/int[2]",1);#radar off
setprop("/sim/messages/copilot", getprop("sim/multiplay/callsign")~" dead.");
armament.defeatSpamFilter("S.O.S. Heeelp");
} else {
armament.defeatSpamFilter("This is not over yet..");
}
}
return -1;
};
var warn = func (last_vector,m2000,callsign,author) {
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
}
var playIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 1);
settimer(func {stopIncomingSound(clock);},3);
@ -259,6 +467,20 @@ var stopIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 0);
}
var nearby_explosion = func {
setprop("damage/sounds/nearby-explode-on", 0);
settimer(nearby_explosion_a, 0);
}
var nearby_explosion_a = func {
setprop("damage/sounds/nearby-explode-on", 1);
settimer(nearby_explosion_b, 0.5);
}
var nearby_explosion_b = func {
setprop("damage/sounds/nearby-explode-on", 0);
}
var callsign_struct = {};
var getCallsign = func (callsign) {
var node = callsign_struct[callsign];
@ -274,20 +496,25 @@ var processCallsigns = func () {
callsign_struct[callsign] = player;
}
}
settimer(processCallsigns, 1.5);
settimer(processCallsigns, 5);
}
processCallsigns();
var logTime = func{
#log time and date for outputing ucsv files for converting into KML files for google earth.
if (getprop("logging/log[0]/enabled") == TRUE and getprop("sim/time/utc/year") != nil) {
var date = getprop("sim/time/utc/year")~"/"~getprop("sim/time/utc/month")~"/"~getprop("sim/time/utc/day");
var time = getprop("sim/time/utc/hour")~":"~getprop("sim/time/utc/minute")~":"~getprop("sim/time/utc/second");
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setprop("logging/date-log", date);
setprop("logging/time-log", time);
# prevent flooding the pilots screen with failure modes that fail when getting hit.
setprop("/sim/failure-manager/display-on-screen", FALSE);
var re_init = func {
# repair the aircraft at relocation to another airport.
var failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
foreach(var failure_mode_id; mode_list) {
FailureMgr.set_failure_level(failure_mode_id, 0);
}
}
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);
setlistener("/sim/signals/reinit", re_init, 0, 0);