mirror of
https://github.com/l0k1/oprf_assets.git
synced 2026-09-12 10:29:28 +00:00
Update to latest vector, missile-code and damage.
This commit is contained in:
+72
-106
@@ -1,64 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2015 onox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
|
||||
<environment>
|
||||
<in-to-wind type="bool">false</in-to-wind>
|
||||
</environment>
|
||||
|
||||
<carrier>
|
||||
<fdm>
|
||||
<settings>
|
||||
<!-- The maximum bank angle during full rudder deflection -->
|
||||
<bank-limit type="double">15.0</bank-limit>
|
||||
|
||||
<!-- Frequency and overshoot of the oscillator used to
|
||||
simulate heeling (roll).
|
||||
-->
|
||||
<heel-frequency type="double">0.5</heel-frequency>
|
||||
<heel-overshoot type="double">4.0</heel-overshoot>
|
||||
|
||||
<!-- Frequency and overshoot of the oscillator used to
|
||||
simulate trimming (pitch).
|
||||
-->
|
||||
<trim-frequency type="double">0.32</trim-frequency>
|
||||
<trim-overshoot type="double">0.45</trim-overshoot>
|
||||
|
||||
<!-- The speed of the waves plus speed of the ship in knots
|
||||
which generates the maximum overshoot of the trim
|
||||
oscillation.
|
||||
-->
|
||||
<max-trim-oscillation-wave-kt type="double">30.0</max-trim-oscillation-wave-kt>
|
||||
|
||||
<!-- The speed of the waves in knots which generates the
|
||||
maximum overshoot of the heel oscillation.
|
||||
-->
|
||||
<max-heel-oscillation-wave-kt type="double">20.0</max-heel-oscillation-wave-kt>
|
||||
|
||||
<movement type="bool">true</movement>
|
||||
</settings>
|
||||
</fdm>
|
||||
</carrier>
|
||||
|
||||
<sim>
|
||||
<author>pinto</author>
|
||||
<author>pinto, Nikolai V. Chr.</author>
|
||||
<description>BUK-M2</description>
|
||||
<long-description>BUK-M2 is a modern Russian self-propelled surface to air missile system.</long-description>
|
||||
<status>alpha</status>
|
||||
@@ -114,6 +59,36 @@
|
||||
<z-offset-max-m type="float">2000.0</z-offset-max-m>
|
||||
</current-view>
|
||||
|
||||
<view n="200">
|
||||
<name>Follow</name>
|
||||
<type>lookat</type>
|
||||
<internal>false</internal>
|
||||
<config>
|
||||
<!--<from-model type="bool">true</from-model>
|
||||
<from-model-idx type="int">0</from-model-idx>-->
|
||||
<eye-fixed type="bool">true</eye-fixed>
|
||||
<target-lat-deg-path>rotors/main/blade[0]/flap-deg</target-lat-deg-path>
|
||||
<target-lon-deg-path>rotors/main/blade[1]/flap-deg</target-lon-deg-path>
|
||||
<target-alt-ft-path>rotors/main/blade[2]/position-deg</target-alt-ft-path>
|
||||
<eye-lat-deg-path>/position/latitude-deg</eye-lat-deg-path>
|
||||
<eye-lon-deg-path>/position/longitude-deg</eye-lon-deg-path>
|
||||
<eye-alt-ft-path>/position/altitude-ft</eye-alt-ft-path>
|
||||
<!--<eye-heading-deg-path>/orientation/heading-deg</eye-heading-deg-path>
|
||||
<eye-pitch-deg-path>/orientation/pitch-deg</eye-pitch-deg-path>
|
||||
<eye-roll-deg-path>/orientation/roll-deg</eye-roll-deg-path>-->
|
||||
<eye-heading-deg-path>/orientation/heading-deg</eye-heading-deg-path>
|
||||
<eye-pitch-deg>0</eye-pitch-deg>
|
||||
<eye-roll-deg>0</eye-roll-deg>
|
||||
<x-offset-m>50</x-offset-m>
|
||||
<y-offset-m>50</y-offset-m>
|
||||
<z-offset-m>25</z-offset-m>
|
||||
<default-field-of-view-deg>70</default-field-of-view-deg>
|
||||
<limits>
|
||||
<enabled type="bool">false</enabled>
|
||||
</limits>
|
||||
</config>
|
||||
</view>
|
||||
|
||||
<hud>
|
||||
<path n="1">Aircraft/BUK-M2/Hud/hud.xml</path>
|
||||
<visibility n="1">true</visibility>
|
||||
@@ -126,24 +101,13 @@
|
||||
<auto-position type="bool">true</auto-position>
|
||||
</tower>
|
||||
|
||||
<systems>
|
||||
<autopilot>
|
||||
<path>Systems/fbw.xml</path>
|
||||
</autopilot>
|
||||
<autopilot>
|
||||
<path>Systems/fdm.xml</path>
|
||||
</autopilot>
|
||||
|
||||
<property-rule n="100">
|
||||
<path>Systems/views.xml</path>
|
||||
</property-rule>
|
||||
</systems>
|
||||
<multiplay>
|
||||
<visibility-range-nm type="int">500</visibility-range-nm>
|
||||
<generic>
|
||||
<int n="0" type="int">0</int>
|
||||
<int n="2" type="int">0</int>
|
||||
<string n="6" type="string"></string><!-- string 6 used by radar lock RWR warning -->
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
</multiplay>
|
||||
|
||||
@@ -152,31 +116,7 @@
|
||||
<menu n="100">
|
||||
<label>BUK-M2</label>
|
||||
<enabled type="bool">true</enabled>
|
||||
<item>
|
||||
<label>Reload</label>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
<script>
|
||||
fire_control.reload();
|
||||
</script>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Targets</label>
|
||||
<name>enemies</name>
|
||||
<binding>
|
||||
<command>dialog-show</command>
|
||||
<dialog-name>enemies</dialog-name>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Priority</label>
|
||||
<name>enemies</name>
|
||||
<binding>
|
||||
<command>dialog-show</command>
|
||||
<dialog-name>priority</dialog-name>
|
||||
</binding>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<label>Event Log</label>
|
||||
<binding>
|
||||
@@ -254,9 +194,33 @@
|
||||
<lbs>50</lbs>
|
||||
</opt>
|
||||
</weight>
|
||||
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">2.25</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">80</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/BUK-M2/Models/Armament/Weapons/</models>
|
||||
<modelsUseCase type="bool">true</modelsUseCase>
|
||||
<modelsUpperCase type="bool">true</modelsUpperCase>
|
||||
<MP-lat type="string">rotors/main/blade[0]/flap-deg</MP-lat>
|
||||
<MP-lon type="string">rotors/main/blade[1]/flap-deg</MP-lon>
|
||||
<MP-alt type="string">rotors/main/blade[2]/flap-deg</MP-alt>
|
||||
<MP-alt-ft type="string">rotors/main/blade[2]/position-deg</MP-alt-ft>
|
||||
<hit-interpolation type="bool">true</hit-interpolation>
|
||||
<gnd-launch type="bool">true</gnd-launch>
|
||||
<pylon-offset type="int">1</pylon-offset>
|
||||
<pylon-stations>controls/armament</pylon-stations>
|
||||
<station-name type="string">station</station-name>
|
||||
<msg type="bool">true</msg>
|
||||
<damage type="bool">true</damage>
|
||||
<enable-craters type="bool">true</enable-craters>
|
||||
@@ -266,6 +230,7 @@
|
||||
<MAW-bearing type="double">0</MAW-bearing>
|
||||
<MAW-active type="bool">false</MAW-active>
|
||||
<spike type="bool">false</spike>
|
||||
<!-- speed: Mach 4 length: 5.5m -->
|
||||
</armament>
|
||||
</payload>
|
||||
|
||||
@@ -279,6 +244,7 @@
|
||||
</blade>
|
||||
<blade n="2">
|
||||
<flap-deg type="double">0</flap-deg>
|
||||
<position-deg type="double">0</position-deg>
|
||||
</blade>
|
||||
</main>
|
||||
</rotors>
|
||||
@@ -298,18 +264,18 @@
|
||||
</sam>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">Leto</e1>
|
||||
<e2 userarchive="y" type="string">swamp</e2>
|
||||
<e3 userarchive="y" type="string">pinto</e3>
|
||||
<e4 userarchive="y" type="string">fb237</e4>
|
||||
<e5 userarchive="y" type="string">Wilco-1</e5>
|
||||
<e6 userarchive="y" type="string">Kokos</e6>
|
||||
<e7 userarchive="y" type="string">J-Mav16</e7>
|
||||
<e8 userarchive="y" type="string">S</e8>
|
||||
<e9 userarchive="y" type="string">Raider1</e9>
|
||||
<e10 userarchive="y" type="string">Slobb</e10>
|
||||
<e11 userarchive="y" type="string">5H1N0B1</e11>
|
||||
<e12 userarchive="y" type="string">SNOWY1</e12>
|
||||
<e1 userarchive="y" type="string">target1</e1>
|
||||
<e2 userarchive="y" type="string">target2</e2>
|
||||
<e3 userarchive="y" type="string">target3</e3>
|
||||
<e4 userarchive="y" type="string">target4</e4>
|
||||
<e5 userarchive="y" type="string">target5</e5>
|
||||
<e6 userarchive="y" type="string">target6</e6>
|
||||
<e7 userarchive="y" type="string">target7</e7>
|
||||
<e8 userarchive="y" type="string">target8</e8>
|
||||
<e9 userarchive="y" type="string">target9</e9>
|
||||
<e10 userarchive="y" type="string">targetA</e10>
|
||||
<e11 userarchive="y" type="string">targetB</e11>
|
||||
<e12 userarchive="y" type="string">targetC</e12>
|
||||
</enemies>
|
||||
|
||||
<priority type="int">0</priority>
|
||||
|
||||
@@ -210,89 +210,7 @@
|
||||
|
||||
<nasal>
|
||||
<load><![CDATA[
|
||||
var self = cmdarg();
|
||||
|
||||
|
||||
var skip = 0;
|
||||
var lat = self.getNode("rotors/main/blade[0]/flap-deg");
|
||||
var lon = self.getNode("rotors/main/blade[1]/flap-deg");
|
||||
var alt = self.getNode("rotors/main/blade[2]/flap-deg");
|
||||
if (alt == nil or alt.getValue() == nil) {
|
||||
skip = 1;
|
||||
}
|
||||
|
||||
var objs = {};
|
||||
|
||||
var loop = func () {
|
||||
|
||||
if(alt.getValue() != 0) {
|
||||
var objModel = objs["first"];
|
||||
if (objModel == nil) {
|
||||
# create model
|
||||
#print("creating missile");
|
||||
var n = props.globals.getNode("models", 1);
|
||||
var i = 0;
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("model", i, 0) == nil) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
objModel = n.getChild("model", i, 1);
|
||||
|
||||
objModel.getNode("elevation",1).setDoubleValue(0);
|
||||
objModel.getNode("latitude",1).setDoubleValue(0);
|
||||
objModel.getNode("longitude",1).setDoubleValue(0);
|
||||
objModel.getNode("elevation-ft-prop",1).setValue(objModel.getPath()~"/elevation");
|
||||
objModel.getNode("latitude-deg-prop",1).setValue(objModel.getPath()~"/latitude");
|
||||
objModel.getNode("longitude-deg-prop",1).setValue(objModel.getPath()~"/longitude");
|
||||
objModel.getNode("heading-deg",1).setDoubleValue(0);
|
||||
objModel.getNode("pitch-deg",1).setDoubleValue(0);
|
||||
objModel.getNode("roll-deg",1).setDoubleValue(0);
|
||||
objModel.getNode("path",1).setValue("Aircraft/JA37/Models/Armament/Weapons/MP_missile/mp_missile.xml");
|
||||
|
||||
var loadNode = objModel.getNode("load", 1);
|
||||
loadNode.setBoolValue(1);
|
||||
|
||||
objs["first"] = objModel;
|
||||
loadNode.remove();
|
||||
}
|
||||
}
|
||||
var exist = 0;
|
||||
if(alt.getValue() != 0) {
|
||||
exist = 1;
|
||||
|
||||
var objModel = objs["first"];
|
||||
if (objModel == nil) {
|
||||
print("error: did not find mp missile.");
|
||||
return;
|
||||
}# else {
|
||||
# print("found a missile!");
|
||||
#}
|
||||
objModel.getNode("latitude").setDoubleValue(lat.getValue());
|
||||
objModel.getNode("longitude").setDoubleValue(lon.getValue());
|
||||
objModel.getNode("elevation").setDoubleValue(alt.getValue()*M2FT);
|
||||
|
||||
}
|
||||
if (exist == 0) {
|
||||
# remove model
|
||||
var objModel = objs["first"];
|
||||
if (objModel != nil) {
|
||||
objModel.remove();
|
||||
delete(objs, "first");
|
||||
}
|
||||
}
|
||||
|
||||
if (self.getNode("valid") == 0 or self.getNode("valid") == nil) {
|
||||
return;
|
||||
}
|
||||
settimer(loop, 0.05);
|
||||
}
|
||||
|
||||
if (skip == 0) {
|
||||
loop();
|
||||
}
|
||||
|
||||
]]>
|
||||
]]>
|
||||
</load>
|
||||
</nasal>
|
||||
|
||||
|
||||
+220
-87
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (with improvement by Onox)
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
############################ Config ########################################################################################
|
||||
var full_damage_dist_m = 2.5;# Can vary from aircraft to aircraft depending on how many failure modes it has.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -66,7 +68,7 @@ var shells = {
|
||||
|
||||
var warheads = {
|
||||
# [id,lbs,anti surface,cluster,(name)]
|
||||
"AGM-65": [ 0, 126.00,1,0],
|
||||
"AGM-65B": [ 0, 126.00,1,0],
|
||||
"AGM-84": [ 1, 488.00,1,0],
|
||||
"AGM-88": [ 2, 146.00,1,0],
|
||||
"MK-82SE": [ 3, 192.00,1,0],# snake eye
|
||||
@@ -75,12 +77,12 @@ var warheads = {
|
||||
"AGM-158": [ 6, 1000.00,1,0],
|
||||
"ALARM": [ 7, 450.00,1,0],
|
||||
"AM 39 Exocet": [ 8, 364.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],# Also : AJ 168 Martel
|
||||
"AS30L": [10, 529.00,1,0],
|
||||
"BL755": [11, 100.00,1,1],# 800lb bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-87": [12, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-105": [13, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"AJ 168 Martel": [14, 330.00,1,0],
|
||||
"AS 37 Armat": [14, 330.00,1,0],
|
||||
"FAB-100": [15, 92.59,1,0],
|
||||
"FAB-250": [16, 202.85,1,0],
|
||||
"FAB-500": [17, 564.38,1,0],
|
||||
@@ -88,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -124,14 +126,14 @@ var warheads = {
|
||||
"AIM-7F": [55, 88.00,0,0],
|
||||
"AGM-62": [56, 2000.00,1,0],
|
||||
"AIM-9L": [57, 20.80,0,0],
|
||||
"d-7": [58, 44.00,0,0],#deprecated
|
||||
"AGM-65D": [58, 126.00,1,0],
|
||||
"AIM-132": [59, 22.05,0,0],
|
||||
"d-8": [60, 20.80,0,0],#deprecated
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1176,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
+162
-18
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.93
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -13,6 +13,8 @@ var Math = {
|
||||
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
|
||||
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
|
||||
#
|
||||
# Cartesian is right-handed coord system.
|
||||
#
|
||||
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
|
||||
|
||||
convertCoords: func (x,y,z) {
|
||||
@@ -37,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -55,9 +59,27 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
|
||||
me.mag = 1;
|
||||
call(func {me.mag = math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2))},nil,nil,var err =[]);#strange bug in Nasal can sometimes mess up sqrt
|
||||
return me.mag;
|
||||
},
|
||||
|
||||
# dot product of 2 vectors
|
||||
@@ -65,8 +87,20 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
@@ -74,15 +108,34 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
# rotate a vector. Order: yaw, pitch
|
||||
yawPitchVector: func (yaw, pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.pitchM, me.yawM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
return me.multiplyMatrixWithVector(me.pitchM, vector);
|
||||
},
|
||||
|
||||
# multiply 3x3 matrix with vector
|
||||
multiplyMatrixWithVector: func (matrix, vector) {
|
||||
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
|
||||
@@ -107,10 +160,10 @@ var Math = {
|
||||
|
||||
# matrix for pitching
|
||||
pitchMatrix: func (pitch) {
|
||||
pitch = pitch * D2R;
|
||||
return [math.cos(pitch),0,-math.sin(pitch),
|
||||
pitch = -pitch * D2R;
|
||||
return [math.cos(pitch),0,math.sin(pitch),
|
||||
0,1,0,
|
||||
math.sin(pitch),0,math.cos(pitch)];
|
||||
-math.sin(pitch),0,math.cos(pitch)];
|
||||
},
|
||||
|
||||
# matrix for yawing
|
||||
@@ -126,7 +179,8 @@ var Math = {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
@@ -144,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -242,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -268,7 +369,7 @@ var Math = {
|
||||
|
||||
# print vector to console
|
||||
format: func (v) {
|
||||
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
|
||||
return sprintf("(%.2f, %.2f, %.2f)",v[0],v[1],v[2]);
|
||||
},
|
||||
|
||||
# make vector length 1.0
|
||||
@@ -288,6 +389,20 @@ var Math = {
|
||||
|
||||
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
|
||||
},
|
||||
|
||||
interpolateVector: func (start, end, fraction) {
|
||||
me.xx = (start[0]*(1-fraction) +end[0]*fraction);
|
||||
me.yy = (start[1]*(1-fraction) +end[1]*fraction);
|
||||
me.zz = (start[2]*(1-fraction) +end[2]*fraction);
|
||||
|
||||
return [me.xx, me.yy, me.zz];
|
||||
},
|
||||
|
||||
# move distance 'along' from start towards end. Total dist from start to end is dist.
|
||||
alongVector: func (start, end, dist, along) {
|
||||
me.fraction = along/dist;
|
||||
return me.interpolateVector(start, end, me.fraction);
|
||||
},
|
||||
|
||||
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
|
||||
orthogonalProjection: func(vec, ref){
|
||||
@@ -319,9 +434,9 @@ var Math = {
|
||||
#| 0 cos(roll) -sin(roll) |
|
||||
#| 0 sin(roll) cos(roll) |
|
||||
#
|
||||
#| cos(pitch) 0 -sin(pitch) |
|
||||
#| 0 1 0 |
|
||||
#| sin(pitch) 0 cos(pitch) |
|
||||
#| cos(-pitch) 0 sin(-pitch) |
|
||||
#| 0 1 0 |
|
||||
#| -sin(-pitch) 0 cos(-pitch) |
|
||||
#
|
||||
#| cos(yaw) -sin(yaw) 0 |
|
||||
#| sin(yaw) cos(yaw) 0 |
|
||||
@@ -336,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
+17
-6
@@ -58,7 +58,7 @@
|
||||
</carrier>
|
||||
|
||||
<sim include="Sim/views.xml">
|
||||
<author>pinto and onox</author>
|
||||
<author>pinto, Nikolai V. Chr., onox</author>
|
||||
<description>Frigate</description>
|
||||
<status>alpha</status>
|
||||
<aircraft-version>0.1</aircraft-version>
|
||||
@@ -123,6 +123,7 @@
|
||||
<multiplay>
|
||||
<generic>
|
||||
<int n="0" type="int">0</int>
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
</multiplay>
|
||||
|
||||
@@ -227,7 +228,20 @@
|
||||
<lbs>50</lbs>
|
||||
</opt>
|
||||
</weight>
|
||||
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">20</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">200</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/Frigate/Models/emesary/</models>
|
||||
<msg type="bool">true</msg>
|
||||
@@ -239,6 +253,7 @@
|
||||
<MAW-bearing type="double">0</MAW-bearing>
|
||||
<MAW-active type="bool">false</MAW-active>
|
||||
<spike type="bool">false</spike>
|
||||
|
||||
</armament>
|
||||
</payload>
|
||||
|
||||
@@ -259,8 +274,4 @@
|
||||
</gci>
|
||||
</nasal>
|
||||
|
||||
<input>
|
||||
<mice include="Sim/mice.xml"/>
|
||||
</input>
|
||||
|
||||
</PropertyList>
|
||||
|
||||
+220
-87
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (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.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -66,7 +68,7 @@ var shells = {
|
||||
|
||||
var warheads = {
|
||||
# [id,lbs,anti surface,cluster,(name)]
|
||||
"AGM-65": [ 0, 126.00,1,0],
|
||||
"AGM-65B": [ 0, 126.00,1,0],
|
||||
"AGM-84": [ 1, 488.00,1,0],
|
||||
"AGM-88": [ 2, 146.00,1,0],
|
||||
"MK-82SE": [ 3, 192.00,1,0],# snake eye
|
||||
@@ -75,12 +77,12 @@ var warheads = {
|
||||
"AGM-158": [ 6, 1000.00,1,0],
|
||||
"ALARM": [ 7, 450.00,1,0],
|
||||
"AM 39 Exocet": [ 8, 364.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],# Also : AJ 168 Martel
|
||||
"AS30L": [10, 529.00,1,0],
|
||||
"BL755": [11, 100.00,1,1],# 800lb bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-87": [12, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-105": [13, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"AJ 168 Martel": [14, 330.00,1,0],
|
||||
"AS 37 Armat": [14, 330.00,1,0],
|
||||
"FAB-100": [15, 92.59,1,0],
|
||||
"FAB-250": [16, 202.85,1,0],
|
||||
"FAB-500": [17, 564.38,1,0],
|
||||
@@ -88,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -124,14 +126,14 @@ var warheads = {
|
||||
"AIM-7F": [55, 88.00,0,0],
|
||||
"AGM-62": [56, 2000.00,1,0],
|
||||
"AIM-9L": [57, 20.80,0,0],
|
||||
"d-7": [58, 44.00,0,0],#deprecated
|
||||
"AGM-65D": [58, 126.00,1,0],
|
||||
"AIM-132": [59, 22.05,0,0],
|
||||
"d-8": [60, 20.80,0,0],#deprecated
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1176,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
+162
-18
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.93
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -13,6 +13,8 @@ var Math = {
|
||||
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
|
||||
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
|
||||
#
|
||||
# Cartesian is right-handed coord system.
|
||||
#
|
||||
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
|
||||
|
||||
convertCoords: func (x,y,z) {
|
||||
@@ -37,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -55,9 +59,27 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
|
||||
me.mag = 1;
|
||||
call(func {me.mag = math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2))},nil,nil,var err =[]);#strange bug in Nasal can sometimes mess up sqrt
|
||||
return me.mag;
|
||||
},
|
||||
|
||||
# dot product of 2 vectors
|
||||
@@ -65,8 +87,20 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
@@ -74,15 +108,34 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
# rotate a vector. Order: yaw, pitch
|
||||
yawPitchVector: func (yaw, pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.pitchM, me.yawM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
return me.multiplyMatrixWithVector(me.pitchM, vector);
|
||||
},
|
||||
|
||||
# multiply 3x3 matrix with vector
|
||||
multiplyMatrixWithVector: func (matrix, vector) {
|
||||
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
|
||||
@@ -107,10 +160,10 @@ var Math = {
|
||||
|
||||
# matrix for pitching
|
||||
pitchMatrix: func (pitch) {
|
||||
pitch = pitch * D2R;
|
||||
return [math.cos(pitch),0,-math.sin(pitch),
|
||||
pitch = -pitch * D2R;
|
||||
return [math.cos(pitch),0,math.sin(pitch),
|
||||
0,1,0,
|
||||
math.sin(pitch),0,math.cos(pitch)];
|
||||
-math.sin(pitch),0,math.cos(pitch)];
|
||||
},
|
||||
|
||||
# matrix for yawing
|
||||
@@ -126,7 +179,8 @@ var Math = {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
@@ -144,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -242,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -268,7 +369,7 @@ var Math = {
|
||||
|
||||
# print vector to console
|
||||
format: func (v) {
|
||||
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
|
||||
return sprintf("(%.2f, %.2f, %.2f)",v[0],v[1],v[2]);
|
||||
},
|
||||
|
||||
# make vector length 1.0
|
||||
@@ -288,6 +389,20 @@ var Math = {
|
||||
|
||||
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
|
||||
},
|
||||
|
||||
interpolateVector: func (start, end, fraction) {
|
||||
me.xx = (start[0]*(1-fraction) +end[0]*fraction);
|
||||
me.yy = (start[1]*(1-fraction) +end[1]*fraction);
|
||||
me.zz = (start[2]*(1-fraction) +end[2]*fraction);
|
||||
|
||||
return [me.xx, me.yy, me.zz];
|
||||
},
|
||||
|
||||
# move distance 'along' from start towards end. Total dist from start to end is dist.
|
||||
alongVector: func (start, end, dist, along) {
|
||||
me.fraction = along/dist;
|
||||
return me.interpolateVector(start, end, me.fraction);
|
||||
},
|
||||
|
||||
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
|
||||
orthogonalProjection: func(vec, ref){
|
||||
@@ -319,9 +434,9 @@ var Math = {
|
||||
#| 0 cos(roll) -sin(roll) |
|
||||
#| 0 sin(roll) cos(roll) |
|
||||
#
|
||||
#| cos(pitch) 0 -sin(pitch) |
|
||||
#| 0 1 0 |
|
||||
#| sin(pitch) 0 cos(pitch) |
|
||||
#| cos(-pitch) 0 sin(-pitch) |
|
||||
#| 0 1 0 |
|
||||
#| -sin(-pitch) 0 cos(-pitch) |
|
||||
#
|
||||
#| cos(yaw) -sin(yaw) 0 |
|
||||
#| sin(yaw) cos(yaw) 0 |
|
||||
@@ -336,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
@@ -1,22 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2015 onox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
|
||||
</PropertyList>
|
||||
|
||||
+30
-17
@@ -257,7 +257,20 @@
|
||||
<lbs>50</lbs>
|
||||
</opt>
|
||||
</weight>
|
||||
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">5</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">80</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/MIM-104D/Models/Armament/Weapons/</models>
|
||||
<modelsUseCase type="bool">true</modelsUseCase>
|
||||
@@ -295,17 +308,17 @@
|
||||
<all-aspect type="bool">true</all-aspect>
|
||||
|
||||
<FCS-field-deg type="int">360</FCS-field-deg>
|
||||
<seeker-field-deg type="int">400</seeker-field-deg><!-- since launched vertical, it cannot be too small -->
|
||||
<seeker-field-deg type="int">400</seeker-field-deg>
|
||||
<max-g type="int">25</max-g>
|
||||
<thrust-lbf-stage-1 type="double">15000</thrust-lbf-stage-1>
|
||||
<thrust-lbf-stage-2 type="double">0</thrust-lbf-stage-2> <!-- max 2000 m/s speed, 93 NM range -->
|
||||
<thrust-lbf-stage-2 type="double">0</thrust-lbf-stage-2> <!-- -->
|
||||
<stage-1-duration-sec type="double">12</stage-1-duration-sec>
|
||||
<stage-gap-duration-sec type="double">0</stage-gap-duration-sec>
|
||||
<stage-2-duration-sec type="double">0</stage-2-duration-sec>
|
||||
|
||||
<weight-warhead-lbs>185</weight-warhead-lbs>
|
||||
<weight-fuel-lbm>1000</weight-fuel-lbm> <!-- -->
|
||||
<drag-coeff type="double">0.10</drag-coeff> <!-- max 2000 m/s speed, 93 NM range -->
|
||||
<drag-coeff type="double">0.10</drag-coeff> <!-- -->
|
||||
|
||||
<arming-time-sec type="double">2</arming-time-sec>
|
||||
<min-speed-for-guiding-mach type="double">0.45</min-speed-for-guiding-mach>
|
||||
@@ -365,19 +378,19 @@
|
||||
<damage type="double">100</damage>
|
||||
</sam>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">Leto</e1>
|
||||
<e2 userarchive="y" type="string">swamp</e2>
|
||||
<e3 userarchive="y" type="string">pinto</e3>
|
||||
<e4 userarchive="y" type="string">fb237</e4>
|
||||
<e5 userarchive="y" type="string">Wilco-1</e5>
|
||||
<e6 userarchive="y" type="string">Kokos</e6>
|
||||
<e7 userarchive="y" type="string">J-Mav16</e7>
|
||||
<e8 userarchive="y" type="string">S</e8>
|
||||
<e9 userarchive="y" type="string">Raider1</e9>
|
||||
<e10 userarchive="y" type="string">Slobb</e10>
|
||||
<e11 userarchive="y" type="string">5H1N0B1</e11>
|
||||
<e12 userarchive="y" type="string">SNOWY1</e12>
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">target1</e1>
|
||||
<e2 userarchive="y" type="string">target2</e2>
|
||||
<e3 userarchive="y" type="string">target3</e3>
|
||||
<e4 userarchive="y" type="string">target4</e4>
|
||||
<e5 userarchive="y" type="string">target5</e5>
|
||||
<e6 userarchive="y" type="string">target6</e6>
|
||||
<e7 userarchive="y" type="string">target7</e7>
|
||||
<e8 userarchive="y" type="string">target8</e8>
|
||||
<e9 userarchive="y" type="string">target9</e9>
|
||||
<e10 userarchive="y" type="string">targetA</e10>
|
||||
<e11 userarchive="y" type="string">targetB</e11>
|
||||
<e12 userarchive="y" type="string">targetC</e12>
|
||||
</enemies>
|
||||
|
||||
<priority type="int">0</priority>
|
||||
|
||||
+213
-80
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (with improvement by Onox)
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
############################ Config ########################################################################################
|
||||
var full_damage_dist_m = 5;# Can vary from aircraft to aircraft depending on how many failure modes it has.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1171,21 +1295,22 @@ var code_ct = func () {
|
||||
if (getprop("payload/armament/msg")) {
|
||||
setprop("sim/rendering/redout/enabled", TRUE);
|
||||
#call(func{fgcommand('dialog-close', multiplayer.dialog.dialog.prop())},nil,var err= []);# props.Node.new({"dialog-name": "location-in-air"}));
|
||||
#call(func{multiplayer.dialog.del();},nil,var err= []);
|
||||
call(func{multiplayer.dialog.del();},nil,var err= []);
|
||||
if (!getprop("gear/gear[0]/wow")) {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
@@ -52,7 +52,8 @@ var PositionUpdater = func () {
|
||||
# Set new position
|
||||
setprop("/position/latitude-deg", position.lat());
|
||||
setprop("/position/longitude-deg", position.lon());
|
||||
setprop("/position/altitude-ft", getprop("/position/ground-elev-ft"));
|
||||
var elev = geo.elevation(position.lat(),position.lon());
|
||||
if (elev != nil) setprop("/position/altitude-ft", elev*M2FT);
|
||||
|
||||
|
||||
if ( getprop("/carrier/sunk") == 0 ) {
|
||||
|
||||
+371
-296
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.97
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -39,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -85,21 +87,24 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
@@ -119,6 +124,12 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
@@ -187,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -285,13 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -398,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
@@ -8,7 +8,7 @@
|
||||
<type>spin</type>
|
||||
<object-name>Cube</object-name>
|
||||
<property>/sim/multiplay/online</property>
|
||||
<factor>5.0</factor>
|
||||
<factor>20.0</factor>
|
||||
<axis>
|
||||
<x1-m> 3.95612 </x1-m>
|
||||
<y1-m> 0 </y1-m>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<PropertyList>
|
||||
|
||||
<path>FlapLid_mast.ac</path>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>FlapLid.001</object-name>
|
||||
<property>sim/multiplay/generic/float[8]</property>
|
||||
<factor>-1.0</factor>
|
||||
<offset-deg>180</offset-deg>
|
||||
<axis>
|
||||
<x1-m> 3.95612 </x1-m>
|
||||
<y1-m> -0.000003 </y1-m>
|
||||
<z1-m> 19.88614 </z1-m>
|
||||
<x2-m> 3.95612 </x2-m>
|
||||
<y2-m> -0.000003 </y2-m>
|
||||
<z2-m> 20.88614 </z2-m>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<nasal>
|
||||
<load><![CDATA[
|
||||
]]>
|
||||
</load>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
||||
@@ -119,7 +119,7 @@
|
||||
</animation-->
|
||||
|
||||
<model>
|
||||
<path>FlapLid_mast.ac</path>
|
||||
<path>FlapLid_mast.xml</path>
|
||||
<name>flaplid</name>
|
||||
<offsets>
|
||||
<x-m> 0</x-m>
|
||||
|
||||
+220
-87
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (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.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -66,7 +68,7 @@ var shells = {
|
||||
|
||||
var warheads = {
|
||||
# [id,lbs,anti surface,cluster,(name)]
|
||||
"AGM-65": [ 0, 126.00,1,0],
|
||||
"AGM-65B": [ 0, 126.00,1,0],
|
||||
"AGM-84": [ 1, 488.00,1,0],
|
||||
"AGM-88": [ 2, 146.00,1,0],
|
||||
"MK-82SE": [ 3, 192.00,1,0],# snake eye
|
||||
@@ -75,12 +77,12 @@ var warheads = {
|
||||
"AGM-158": [ 6, 1000.00,1,0],
|
||||
"ALARM": [ 7, 450.00,1,0],
|
||||
"AM 39 Exocet": [ 8, 364.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],# Also : AJ 168 Martel
|
||||
"AS30L": [10, 529.00,1,0],
|
||||
"BL755": [11, 100.00,1,1],# 800lb bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-87": [12, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-105": [13, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"AJ 168 Martel": [14, 330.00,1,0],
|
||||
"AS 37 Armat": [14, 330.00,1,0],
|
||||
"FAB-100": [15, 92.59,1,0],
|
||||
"FAB-250": [16, 202.85,1,0],
|
||||
"FAB-500": [17, 564.38,1,0],
|
||||
@@ -88,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -124,14 +126,14 @@ var warheads = {
|
||||
"AIM-7F": [55, 88.00,0,0],
|
||||
"AGM-62": [56, 2000.00,1,0],
|
||||
"AIM-9L": [57, 20.80,0,0],
|
||||
"d-7": [58, 44.00,0,0],#deprecated
|
||||
"AGM-65D": [58, 126.00,1,0],
|
||||
"AIM-132": [59, 22.05,0,0],
|
||||
"d-8": [60, 20.80,0,0],#deprecated
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1176,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
+71
-2
@@ -18,7 +18,7 @@
|
||||
#with("updateloop");
|
||||
|
||||
# Number of iterations per second
|
||||
var frequency = 60.0;
|
||||
var frequency = 10.0;
|
||||
|
||||
# Change in heading per second at full rudder deflection
|
||||
var heading_ps = 0.5;
|
||||
@@ -33,6 +33,75 @@ setprop("/carrier/roll-offset",0);
|
||||
setprop("/carrier/sunk",0);
|
||||
|
||||
var PositionUpdater = func () {
|
||||
var position = geo.aircraft_position();
|
||||
var elev0 = geo.elevation(position.lat(),position.lon());
|
||||
|
||||
if (elev0 == nil) elev0 = 0;
|
||||
|
||||
var geodPos = aircraftToCart({x:0, y:50, z: 0});
|
||||
var co = geo.Coord.new();
|
||||
co.set_xyz(geodPos.x, geodPos.y, geodPos.z);
|
||||
var elev = geo.elevation(co.lat(),co.lon());
|
||||
if (elev != nil) {
|
||||
setprop("sim/multiplay/generic/float[10]", elev-elev0);
|
||||
setprop("controls/armament/station[1]/offsets/z-m", elev-elev0+3.8);
|
||||
setprop("controls/armament/station[2]/offsets/z-m", elev-elev0+3.8);
|
||||
setprop("controls/armament/station[3]/offsets/z-m", elev-elev0+3.8);
|
||||
setprop("controls/armament/station[4]/offsets/z-m", elev-elev0+3.8);
|
||||
} else {
|
||||
setprop("sim/multiplay/generic/float[10]", 0);
|
||||
setprop("controls/armament/station[1]/offsets/z-m", 3.8);
|
||||
setprop("controls/armament/station[2]/offsets/z-m", 3.8);
|
||||
setprop("controls/armament/station[3]/offsets/z-m", 3.8);
|
||||
setprop("controls/armament/station[4]/offsets/z-m", 3.8);
|
||||
}
|
||||
|
||||
geodPos = aircraftToCart({x:40, y:-40, z: 0});
|
||||
co = geo.Coord.new();
|
||||
co.set_xyz(geodPos.x, geodPos.y, geodPos.z);
|
||||
elev = geo.elevation(co.lat(),co.lon());
|
||||
if (elev != nil) {
|
||||
setprop("sim/multiplay/generic/float[11]", elev-elev0);
|
||||
} else {
|
||||
setprop("sim/multiplay/generic/float[11]", 0);
|
||||
}
|
||||
|
||||
# not used:
|
||||
geodPos = aircraftToCart({x:0, y:-40, z: 0});
|
||||
co = geo.Coord.new();
|
||||
co.set_xyz(geodPos.x, geodPos.y, geodPos.z);
|
||||
elev = geo.elevation(co.lat(),co.lon());
|
||||
if (elev != nil) {
|
||||
setprop("sim/multiplay/generic/float[12]", elev-elev0);
|
||||
} else {
|
||||
setprop("sim/multiplay/generic/float[12]", 0);
|
||||
}
|
||||
|
||||
geodPos = aircraftToCart({x:-40, y:-40, z: 0});
|
||||
co = geo.Coord.new();
|
||||
co.set_xyz(geodPos.x, geodPos.y, geodPos.z);
|
||||
elev = geo.elevation(co.lat(),co.lon());
|
||||
if (elev != nil) {
|
||||
setprop("sim/multiplay/generic/float[13]", elev-elev0);
|
||||
} else {
|
||||
setprop("sim/multiplay/generic/float[13]", 0);
|
||||
}
|
||||
|
||||
# not used:
|
||||
geodPos = aircraftToCart({x:40, y:40, z: 0});
|
||||
co = geo.Coord.new();
|
||||
co.set_xyz(geodPos.x, geodPos.y, geodPos.z);
|
||||
elev = geo.elevation(co.lat(),co.lon());
|
||||
if (elev != nil) {
|
||||
setprop("sim/multiplay/generic/float[14]", elev-elev0);
|
||||
} else {
|
||||
setprop("sim/multiplay/generic/float[14]", 0);
|
||||
}
|
||||
|
||||
|
||||
settimer( PositionUpdater, 1/frequency );
|
||||
return;
|
||||
|
||||
|
||||
var position = geo.aircraft_position();
|
||||
|
||||
@@ -75,4 +144,4 @@ var PositionUpdater = func () {
|
||||
|
||||
};
|
||||
|
||||
#PositionUpdater();
|
||||
PositionUpdater();
|
||||
+162
-18
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.93
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -13,6 +13,8 @@ var Math = {
|
||||
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
|
||||
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
|
||||
#
|
||||
# Cartesian is right-handed coord system.
|
||||
#
|
||||
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
|
||||
|
||||
convertCoords: func (x,y,z) {
|
||||
@@ -37,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -55,9 +59,27 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
|
||||
me.mag = 1;
|
||||
call(func {me.mag = math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2))},nil,nil,var err =[]);#strange bug in Nasal can sometimes mess up sqrt
|
||||
return me.mag;
|
||||
},
|
||||
|
||||
# dot product of 2 vectors
|
||||
@@ -65,8 +87,20 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
@@ -74,15 +108,34 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
# rotate a vector. Order: yaw, pitch
|
||||
yawPitchVector: func (yaw, pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.pitchM, me.yawM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
return me.multiplyMatrixWithVector(me.pitchM, vector);
|
||||
},
|
||||
|
||||
# multiply 3x3 matrix with vector
|
||||
multiplyMatrixWithVector: func (matrix, vector) {
|
||||
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
|
||||
@@ -107,10 +160,10 @@ var Math = {
|
||||
|
||||
# matrix for pitching
|
||||
pitchMatrix: func (pitch) {
|
||||
pitch = pitch * D2R;
|
||||
return [math.cos(pitch),0,-math.sin(pitch),
|
||||
pitch = -pitch * D2R;
|
||||
return [math.cos(pitch),0,math.sin(pitch),
|
||||
0,1,0,
|
||||
math.sin(pitch),0,math.cos(pitch)];
|
||||
-math.sin(pitch),0,math.cos(pitch)];
|
||||
},
|
||||
|
||||
# matrix for yawing
|
||||
@@ -126,7 +179,8 @@ var Math = {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
@@ -144,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -242,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -268,7 +369,7 @@ var Math = {
|
||||
|
||||
# print vector to console
|
||||
format: func (v) {
|
||||
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
|
||||
return sprintf("(%.2f, %.2f, %.2f)",v[0],v[1],v[2]);
|
||||
},
|
||||
|
||||
# make vector length 1.0
|
||||
@@ -288,6 +389,20 @@ var Math = {
|
||||
|
||||
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
|
||||
},
|
||||
|
||||
interpolateVector: func (start, end, fraction) {
|
||||
me.xx = (start[0]*(1-fraction) +end[0]*fraction);
|
||||
me.yy = (start[1]*(1-fraction) +end[1]*fraction);
|
||||
me.zz = (start[2]*(1-fraction) +end[2]*fraction);
|
||||
|
||||
return [me.xx, me.yy, me.zz];
|
||||
},
|
||||
|
||||
# move distance 'along' from start towards end. Total dist from start to end is dist.
|
||||
alongVector: func (start, end, dist, along) {
|
||||
me.fraction = along/dist;
|
||||
return me.interpolateVector(start, end, me.fraction);
|
||||
},
|
||||
|
||||
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
|
||||
orthogonalProjection: func(vec, ref){
|
||||
@@ -319,9 +434,9 @@ var Math = {
|
||||
#| 0 cos(roll) -sin(roll) |
|
||||
#| 0 sin(roll) cos(roll) |
|
||||
#
|
||||
#| cos(pitch) 0 -sin(pitch) |
|
||||
#| 0 1 0 |
|
||||
#| sin(pitch) 0 cos(pitch) |
|
||||
#| cos(-pitch) 0 sin(-pitch) |
|
||||
#| 0 1 0 |
|
||||
#| -sin(-pitch) 0 cos(-pitch) |
|
||||
#
|
||||
#| cos(yaw) -sin(yaw) 0 |
|
||||
#| sin(yaw) cos(yaw) 0 |
|
||||
@@ -336,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
+45
-143
@@ -1,64 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2015 onox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
|
||||
<environment>
|
||||
<in-to-wind type="bool">false</in-to-wind>
|
||||
</environment>
|
||||
|
||||
<carrier>
|
||||
<fdm>
|
||||
<settings>
|
||||
<!-- The maximum bank angle during full rudder deflection -->
|
||||
<bank-limit type="double">15.0</bank-limit>
|
||||
|
||||
<!-- Frequency and overshoot of the oscillator used to
|
||||
simulate heeling (roll).
|
||||
-->
|
||||
<heel-frequency type="double">0.5</heel-frequency>
|
||||
<heel-overshoot type="double">4.0</heel-overshoot>
|
||||
|
||||
<!-- Frequency and overshoot of the oscillator used to
|
||||
simulate trimming (pitch).
|
||||
-->
|
||||
<trim-frequency type="double">0.32</trim-frequency>
|
||||
<trim-overshoot type="double">0.45</trim-overshoot>
|
||||
|
||||
<!-- The speed of the waves plus speed of the ship in knots
|
||||
which generates the maximum overshoot of the trim
|
||||
oscillation.
|
||||
-->
|
||||
<max-trim-oscillation-wave-kt type="double">30.0</max-trim-oscillation-wave-kt>
|
||||
|
||||
<!-- The speed of the waves in knots which generates the
|
||||
maximum overshoot of the heel oscillation.
|
||||
-->
|
||||
<max-heel-oscillation-wave-kt type="double">20.0</max-heel-oscillation-wave-kt>
|
||||
|
||||
<movement type="bool">true</movement>
|
||||
</settings>
|
||||
</fdm>
|
||||
</carrier>
|
||||
|
||||
<sim>
|
||||
<author>pinto</author>
|
||||
<author>pinto, Nikolai V. Chr., onox</author>
|
||||
<description>S-300</description>
|
||||
<long-description>S-300 (SA-10) is a Russian self-propelled surface to air missile system.</long-description>
|
||||
<status>alpha</status>
|
||||
@@ -94,11 +39,6 @@
|
||||
<splash type="bool">true</splash>
|
||||
<path>gui/1.png</path>
|
||||
</preview>
|
||||
<preview>
|
||||
<type>exterior</type>
|
||||
<splash type="bool">true</splash>
|
||||
<path>gui/2.png</path>
|
||||
</preview>
|
||||
</previews>
|
||||
|
||||
<current-view>
|
||||
@@ -129,7 +69,7 @@
|
||||
</limits>
|
||||
</config>
|
||||
</view>
|
||||
<view n="102">
|
||||
<view n="200">
|
||||
<name>Follow</name>
|
||||
<type>lookat</type>
|
||||
<internal>false</internal>
|
||||
@@ -173,24 +113,13 @@
|
||||
<auto-position type="bool">true</auto-position>
|
||||
</tower>
|
||||
|
||||
<systems>
|
||||
<autopilot>
|
||||
<path>Systems/fbw.xml</path>
|
||||
</autopilot>
|
||||
<autopilot>
|
||||
<path>Systems/fdm.xml</path>
|
||||
</autopilot>
|
||||
|
||||
<property-rule n="100">
|
||||
<path>Systems/views.xml</path>
|
||||
</property-rule>
|
||||
</systems>
|
||||
<multiplay>
|
||||
<visibility-range-nm type="int">500</visibility-range-nm>
|
||||
<generic>
|
||||
<int n="0" type="int">0</int>
|
||||
<int n="2" type="int">0</int>
|
||||
<string n="6" type="string"></string><!-- string 6 used by radar lock RWR warning -->
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
</multiplay>
|
||||
|
||||
@@ -199,51 +128,7 @@
|
||||
<menu n="100">
|
||||
<label>S-300</label>
|
||||
<enabled type="bool">true</enabled>
|
||||
<item>
|
||||
<label>Reload</label>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
<script>
|
||||
fire_control.reload();
|
||||
</script>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Targets</label>
|
||||
<name>enemies</name>
|
||||
<binding>
|
||||
<command>dialog-show</command>
|
||||
<dialog-name>enemies</dialog-name>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Priority</label>
|
||||
<name>enemies</name>
|
||||
<binding>
|
||||
<command>dialog-show</command>
|
||||
<dialog-name>priority</dialog-name>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Relocate to cursor last click</label>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
<script>
|
||||
setprop("position/latitude-deg",getprop("sim/input/click/latitude-deg"));
|
||||
setprop("position/longitude-deg",getprop("sim/input/click/longitude-deg"));
|
||||
setprop("position/altitude-ft",getprop("sim/input/click/elevation-ft"));
|
||||
</script>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Print log to console</label>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
<script>
|
||||
damage.printDamageLog();
|
||||
</script>
|
||||
</binding>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<label>Event Log</label>
|
||||
<binding>
|
||||
@@ -274,39 +159,33 @@
|
||||
|
||||
<controls>
|
||||
<armament>
|
||||
<station-select type="int">0</station-select>
|
||||
<trigger type="bool">false</trigger>
|
||||
<station n="1">
|
||||
<offsets>
|
||||
<x-m type="double"> -5.63782</x-m>
|
||||
<y-m type="double"> -1.1407</y-m>
|
||||
<y-m type="double"> 48.8593</y-m>
|
||||
<z-m type="double"> 3.8</z-m>
|
||||
</offsets>
|
||||
<trigger type="bool">false</trigger>
|
||||
</station>
|
||||
<station n="2">
|
||||
<offsets>
|
||||
<x-m type="double"> -6.53782</x-m>
|
||||
<y-m type="double"> -0.540702</y-m>
|
||||
<y-m type="double"> 49.4593</y-m>
|
||||
<z-m type="double"> 3.8</z-m>
|
||||
</offsets>
|
||||
<trigger type="bool">false</trigger>
|
||||
</station>
|
||||
<station n="3">
|
||||
<offsets>
|
||||
<x-m type="double"> -5.63782</x-m>
|
||||
<y-m type="double"> 1.1407</y-m>
|
||||
<y-m type="double"> 51.1407</y-m>
|
||||
<z-m type="double"> 3.8</z-m>
|
||||
</offsets>
|
||||
<trigger type="bool">false</trigger>
|
||||
</station>
|
||||
<station n="4">
|
||||
<offsets>
|
||||
<x-m type="double"> -6.53782</x-m>
|
||||
<y-m type="double"> 0.540702</y-m>
|
||||
<y-m type="double"> 50.540702</y-m>
|
||||
<z-m type="double"> 3.8</z-m>
|
||||
</offsets>
|
||||
<trigger type="bool">false</trigger>
|
||||
</station>
|
||||
</armament>
|
||||
</controls>
|
||||
@@ -321,9 +200,32 @@
|
||||
<lbs>50</lbs>
|
||||
</opt>
|
||||
</weight>
|
||||
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">3</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">80</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/S-300/Models/Armament/Weapons/</models>
|
||||
<modelsUseCase type="bool">true</modelsUseCase>
|
||||
<modelsUpperCase type="bool">true</modelsUpperCase>
|
||||
<MP-lat type="string">rotors/main/blade[0]/flap-deg</MP-lat>
|
||||
<MP-lon type="string">rotors/main/blade[1]/flap-deg</MP-lon>
|
||||
<MP-alt type="string">rotors/main/blade[2]/flap-deg</MP-alt>
|
||||
<MP-alt-ft type="string">rotors/main/blade[2]/position-deg</MP-alt-ft>
|
||||
<gnd-launch type="bool">true</gnd-launch>
|
||||
<pylon-offset type="int">1</pylon-offset>
|
||||
<pylon-stations>controls/armament</pylon-stations>
|
||||
<station-name type="string">station</station-name>
|
||||
<msg type="bool">true</msg>
|
||||
<damage type="bool">true</damage>
|
||||
<enable-craters type="bool">true</enable-craters>
|
||||
@@ -368,19 +270,19 @@
|
||||
<damage type="double">100</damage>
|
||||
</sam>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">Leto</e1>
|
||||
<e2 userarchive="y" type="string">swamp</e2>
|
||||
<e3 userarchive="y" type="string">pinto</e3>
|
||||
<e4 userarchive="y" type="string">fb237</e4>
|
||||
<e5 userarchive="y" type="string">Wilco-1</e5>
|
||||
<e6 userarchive="y" type="string">Kokos</e6>
|
||||
<e7 userarchive="y" type="string">J-Mav16</e7>
|
||||
<e8 userarchive="y" type="string">S</e8>
|
||||
<e9 userarchive="y" type="string">Raider1</e9>
|
||||
<e10 userarchive="y" type="string">Slobb</e10>
|
||||
<e11 userarchive="y" type="string">5H1N0B1</e11>
|
||||
<e12 userarchive="y" type="string">SNOWY1</e12>
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">target1</e1>
|
||||
<e2 userarchive="y" type="string">target2</e2>
|
||||
<e3 userarchive="y" type="string">target3</e3>
|
||||
<e4 userarchive="y" type="string">target4</e4>
|
||||
<e5 userarchive="y" type="string">target5</e5>
|
||||
<e6 userarchive="y" type="string">target6</e6>
|
||||
<e7 userarchive="y" type="string">target7</e7>
|
||||
<e8 userarchive="y" type="string">target8</e8>
|
||||
<e9 userarchive="y" type="string">target9</e9>
|
||||
<e10 userarchive="y" type="string">targetA</e10>
|
||||
<e11 userarchive="y" type="string">targetB</e11>
|
||||
<e12 userarchive="y" type="string">targetC</e12>
|
||||
</enemies>
|
||||
|
||||
<priority type="int">0</priority>
|
||||
|
||||
+212
-79
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (with improvement by Onox)
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
############################ Config ########################################################################################
|
||||
var full_damage_dist_m = 2.25;# Can vary from aircraft to aircraft depending on how many failure modes it has.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1176,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
+371
-296
File diff suppressed because it is too large
Load Diff
+90
-8
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.97
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -39,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -85,21 +87,24 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
@@ -119,6 +124,12 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
@@ -187,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -285,13 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -398,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
+14
-1
@@ -240,7 +240,20 @@
|
||||
</controls>
|
||||
|
||||
<payload>
|
||||
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">2.25</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">80</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/S-75/Models/Armament/Weapons/</models>
|
||||
<modelsUseCase type="bool">true</modelsUseCase>
|
||||
|
||||
+228
-84
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (with improvement by Onox)
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
############################ Config ########################################################################################
|
||||
var full_damage_dist_m = 4;# Can vary from aircraft to aircraft depending on how many failure modes it has.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -162,9 +164,42 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
@@ -225,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -257,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -268,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -290,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -298,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -311,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -320,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -346,10 +382,9 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = getprop("sim/multiplay/callsign");
|
||||
callsign = size(callsign) < 8 ? callsign : left(callsign,7);
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
if (!radarOn) return emesary.Transmitter.ReceiptStatus_OK;# this should be little more complex later
|
||||
var heading = getprop("orientation/heading-deg");
|
||||
@@ -380,8 +415,28 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
var callsign = getprop("sim/multiplay/callsign");
|
||||
callsign = size(callsign) < 8 ? callsign : left(callsign,7);
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
if (m28_auto) mig28.engagedBy(notification.Callsign);
|
||||
@@ -426,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -439,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -458,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -469,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -609,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -617,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -627,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -646,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -670,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -713,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -739,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -813,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -821,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -841,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -849,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -860,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -867,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -884,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -894,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -906,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -920,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1008,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1042,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1056,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1081,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1140,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1153,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1174,21 +1295,22 @@ var code_ct = func () {
|
||||
if (getprop("payload/armament/msg")) {
|
||||
setprop("sim/rendering/redout/enabled", TRUE);
|
||||
#call(func{fgcommand('dialog-close', multiplayer.dialog.dialog.prop())},nil,var err= []);# props.Node.new({"dialog-name": "location-in-air"}));
|
||||
#call(func{multiplayer.dialog.del();},nil,var err= []);
|
||||
call(func{multiplayer.dialog.del();},nil,var err= []);
|
||||
if (!getprop("gear/gear[0]/wow")) {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1206,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1244,6 +1367,20 @@ var printDamageLog = func {
|
||||
print();
|
||||
}
|
||||
|
||||
var processCallsign = func (callsign) {
|
||||
# Convert the callsign to one that emesary can work with.
|
||||
var l = size(callsign);
|
||||
callsign = l < 8?callsign:left(callsign, 7);
|
||||
var newCallsign = "";
|
||||
for(var ii = 0; ii < l; ii += 1) {
|
||||
var ev = emesary.TransferString.getalphanumericchar(substr(callsign,ii,1));
|
||||
if (ev != nil) {
|
||||
newCallsign ~= ev;
|
||||
}
|
||||
}
|
||||
return newCallsign;
|
||||
}
|
||||
|
||||
#TODO testing:
|
||||
|
||||
var writeDamageLog = func {
|
||||
@@ -1271,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
@@ -53,7 +53,7 @@ var missile_name = "m3m9";
|
||||
var missile_brevity = "3M9";
|
||||
var missile_max_distance = 18; #max distance of target in nm when it will fire
|
||||
var missile_min_distance = 0.5; #minimum distance in nm when it will fire
|
||||
var lockon_time = 28; #time in seconds it takes to lock on and get a firing solution on a target
|
||||
var lockon_time = 24; #time in seconds it takes to lock on and get a firing solution on a target
|
||||
var fire_minimum_interval = 7;# time since last track was initiated till a new can be initiated
|
||||
var same_target_max_missiles = 2;# max number of missiles in air against same target
|
||||
|
||||
|
||||
+395
-306
File diff suppressed because it is too large
Load Diff
+91
-9
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.97
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -39,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -85,21 +87,24 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
@@ -119,6 +124,12 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
@@ -187,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -285,13 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -397,4 +450,33 @@ var Math = {
|
||||
#
|
||||
#
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
+28
-15
@@ -238,7 +238,20 @@
|
||||
<lbs>50</lbs>
|
||||
</opt>
|
||||
</weight>
|
||||
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">4</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">80</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/SA-6/Models/Armament/Weapons/</models>
|
||||
<modelsUseCase type="bool">true</modelsUseCase>
|
||||
@@ -263,7 +276,7 @@
|
||||
<m3m9>
|
||||
<type-id type="int">96</type-id>
|
||||
<short-name type="string">3M9</short-name>
|
||||
<long-name type="string">Anti Aircraft Guided Missile</long-name>
|
||||
<long-name type="string">3M9M3 Surface to Air Missile</long-name>
|
||||
<max-fire-range-nm type="int">18</max-fire-range-nm>
|
||||
<cross-section-sqft type="double">1.42</cross-section-sqft>
|
||||
<weight-launch-lbs>1333</weight-launch-lbs><!-- https://missilery.info/missile/kub -->
|
||||
@@ -343,19 +356,19 @@
|
||||
<damage type="double">100</damage>
|
||||
</sam>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">Leto</e1>
|
||||
<e2 userarchive="y" type="string">swamp</e2>
|
||||
<e3 userarchive="y" type="string">pinto</e3>
|
||||
<e4 userarchive="y" type="string">fb237</e4>
|
||||
<e5 userarchive="y" type="string">Wilco-1</e5>
|
||||
<e6 userarchive="y" type="string">Kokos</e6>
|
||||
<e7 userarchive="y" type="string">J-Mav16</e7>
|
||||
<e8 userarchive="y" type="string">S</e8>
|
||||
<e9 userarchive="y" type="string">Raider1</e9>
|
||||
<e10 userarchive="y" type="string">Slobb</e10>
|
||||
<e11 userarchive="y" type="string">5H1N0B1</e11>
|
||||
<e12 userarchive="y" type="string">SNOWY1</e12>
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">target1</e1>
|
||||
<e2 userarchive="y" type="string">target2</e2>
|
||||
<e3 userarchive="y" type="string">target3</e3>
|
||||
<e4 userarchive="y" type="string">target4</e4>
|
||||
<e5 userarchive="y" type="string">target5</e5>
|
||||
<e6 userarchive="y" type="string">target6</e6>
|
||||
<e7 userarchive="y" type="string">target7</e7>
|
||||
<e8 userarchive="y" type="string">target8</e8>
|
||||
<e9 userarchive="y" type="string">target9</e9>
|
||||
<e10 userarchive="y" type="string">targetA</e10>
|
||||
<e11 userarchive="y" type="string">targetB</e11>
|
||||
<e12 userarchive="y" type="string">targetC</e12>
|
||||
</enemies>
|
||||
|
||||
<priority type="int">0</priority>
|
||||
|
||||
+238
-99
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (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.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -37,24 +39,30 @@ var shells = {
|
||||
# 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": [0,0.250], #135mm
|
||||
"S-5 rocket": [1,0.200], # 55mm
|
||||
"M55 shell": [2,0.100], # 30mm
|
||||
"KCA shell": [3,0.100], # 30mm
|
||||
"GSh-30": [4,0.100], # 30mm mig29/su27
|
||||
"GAU-8/A": [5,0.100], # 30mm
|
||||
"Mk3Z": [6,0.100], # 30mm Jaguar
|
||||
"BK27": [7,0.070], # 27mm
|
||||
"GSh-23": [8,0.065], # 23mm
|
||||
"M61A1 shell": [9,0.050], # 20mm F14, F15, F16
|
||||
"50 BMG": [10,0.015], # 12.7mm (non-explosive)
|
||||
# Damage roughly proportional to projectile weight.
|
||||
# If weight isn't listed here, it was estimated from dimensions (proportional to diameter^2 * length).
|
||||
# Approximate formulae for cannons:
|
||||
# damage ~ weight / 3.6 (in g)
|
||||
# or damage ~ diameter^2 * length / 1.6e6 (in mm)
|
||||
#
|
||||
"M70 rocket": [0,0.500], # 135mm, ~5kg warhead
|
||||
"S-5 rocket": [1,0.200], # 55mm, ~1-2kg warhead
|
||||
"M55 shell": [2,0.060], # 30x113mm, 220g
|
||||
"KCA shell": [3,0.100], # 30x173mm, 360g
|
||||
"GSh-30": [4,0.095], # 30x165mm mig29/su27
|
||||
"GAU-8/A": [5,0.100], # 30x173mm, 360g
|
||||
"Mk3Z": [6,0.060], # 30x113mm Jaguar, 220g
|
||||
"BK27": [7,0.070], # 27x145mm, 270g
|
||||
"GSh-23": [8,0.040], # 23x115mm,
|
||||
"M61A1 shell": [9,0.030], # 20x102mm F14, F15, F16, 100g
|
||||
"50 BMG": [10,0.015], # 12.7mm (non-explosive)
|
||||
"7.62": [11,0.005], # 7.62mm (non-explosive)
|
||||
"Hydra-70": [12,0.250], # F-16/A-6 LAU-68 and LAU-61
|
||||
"SNEB": [13,0.250], # Jaguar
|
||||
"DEFA 554": [14,0.100], # 30mm Mirage
|
||||
"20mm APDS": [15,0.050], # CIWS
|
||||
"LAU-10": [16,0.225], # 127mm
|
||||
};
|
||||
"Hydra-70": [12,0.500], # 70mm, F-16/A-6 LAU-68 and LAU-61, ~4-6kg warhead
|
||||
"SNEB": [13,0.500], # 68mm, Jaguar
|
||||
"DEFA 554": [14,0.060], # 30x113mm Mirage, 220g
|
||||
"20mm APDS": [15,0.030], # CIWS
|
||||
"LAU-10": [16,0.500], # 127mm, ~4-7kg warhead
|
||||
};
|
||||
|
||||
# lbs of warheads is explosive+fragmentation+fuse, so total warhead mass.
|
||||
|
||||
@@ -82,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -123,9 +131,9 @@ var warheads = {
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -156,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -218,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -250,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -261,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -283,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -291,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -304,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -313,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -339,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -372,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -417,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -430,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -449,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -460,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -600,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -608,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -618,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -637,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -661,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -704,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -730,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -804,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -812,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -832,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -840,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -851,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -858,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -875,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -885,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -897,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -911,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -999,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1033,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1047,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1072,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1131,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1144,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1170,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1197,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1276,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
+60
-44
@@ -23,29 +23,31 @@ print("loading fdm");
|
||||
var frequency = 60.0;
|
||||
|
||||
# Change in heading per second at full rudder deflection
|
||||
var heading_ps = 0.5;
|
||||
var heading_ps = 20;
|
||||
|
||||
time_last = 0;
|
||||
sim_speed = 1;
|
||||
var time_last = 0;
|
||||
var sim_speed = 1;
|
||||
|
||||
var distance = 0;
|
||||
|
||||
var speed = 15;
|
||||
|
||||
setprop("/carrier/pitch-deg",0);
|
||||
setprop("/carrier/pitch-offset",0);
|
||||
setprop("/carrier/roll-deg",0);
|
||||
setprop("/carrier/roll-offset",0);
|
||||
setprop("/carrier/sunk",0);
|
||||
var arrived = 0;
|
||||
setprop("/orientation/pitch-deg", 0);
|
||||
|
||||
#var arrived = 0;
|
||||
var PositionUpdater = func () {
|
||||
|
||||
settimer( PositionUpdater, 1/frequency );
|
||||
|
||||
var position = geo.aircraft_position();
|
||||
|
||||
if ( arrived == 0 and getprop("/carrier/sunk") == 0 and getprop("/autopilot/route-manager/wp-last/dist") != nil and getprop("/autopilot/route-manager/wp-last/dist") < 1 ) {
|
||||
setprop("/sim/multiplay/chat",getprop("sim/multiplay/callsign") ~ " has arrived safely!");
|
||||
print("arrived");
|
||||
arrived = 1;
|
||||
#if ( arrived == 0 and getprop("/carrier/sunk") == 0 and getprop("/autopilot/route-manager/wp-last/dist") != nil and getprop("/autopilot/route-manager/wp-last/dist") < 1 ) {
|
||||
#setprop("/sim/multiplay/chat",getprop("sim/multiplay/callsign") ~ " has arrived safely!");
|
||||
# print("arrived");
|
||||
# arrived = 1;
|
||||
#return;
|
||||
}
|
||||
#}
|
||||
|
||||
var time_now = getprop("/sim/time/elapsed-sec");
|
||||
var dt = (time_now - time_last) * sim_speed;
|
||||
@@ -53,47 +55,61 @@ var PositionUpdater = func () {
|
||||
|
||||
time_last = time_now;
|
||||
|
||||
#var heading = getprop("/orientation/heading-deg");
|
||||
#var speed = getprop("/velocities/groundspeed-kt");
|
||||
var rudder = getprop("/surface-positions/rudder-pos-norm");
|
||||
|
||||
if ( getprop("/carrier/sunk") == 0 and getprop("/autopilot/route-manager/active") == 1 ) {
|
||||
|
||||
#for event
|
||||
var speed = 25;
|
||||
|
||||
var cur_waypoint = getprop("/autopilot/route-manager/current-wp");
|
||||
var cur_wp_lon = getprop("/autopilot/route-manager/route/wp[" ~ cur_waypoint ~ "]/longitude-deg");
|
||||
var cur_wp_lat = getprop("/autopilot/route-manager/route/wp[" ~ cur_waypoint ~ "]/latitude-deg");
|
||||
var rm_destination = geo.Coord.new().set_latlon(cur_wp_lat,cur_wp_lon);
|
||||
|
||||
|
||||
var heading = position.course_to(rm_destination);
|
||||
|
||||
var distance = speed * globals.KT2MPS * dt;
|
||||
position.apply_course_distance(heading, distance);
|
||||
|
||||
# Set new position
|
||||
setprop("/position/latitude-deg", position.lat());
|
||||
setprop("/position/longitude-deg", position.lon());
|
||||
var g_alt = getprop("/position/ground-elev-ft")+1;
|
||||
if (cur_waypoint > -1) {
|
||||
var cur_wp_lon = getprop("/autopilot/route-manager/route/wp[" ~ cur_waypoint ~ "]/longitude-deg");
|
||||
var cur_wp_lat = getprop("/autopilot/route-manager/route/wp[" ~ cur_waypoint ~ "]/latitude-deg");
|
||||
var rm_destination = geo.Coord.new().set_latlon(cur_wp_lat,cur_wp_lon);
|
||||
|
||||
var heading = getprop("/orientation/heading-deg");
|
||||
|
||||
var course = position.course_to(rm_destination);
|
||||
|
||||
distance = speed * KT2MPS * dt;
|
||||
|
||||
var turn_max = heading_ps * dt;
|
||||
|
||||
var turn = math.clamp(geo.normdeg180(course-heading),-turn_max,turn_max);
|
||||
|
||||
heading += turn;
|
||||
|
||||
heading = geo.normdeg(heading);
|
||||
|
||||
position.apply_course_distance(heading, distance);
|
||||
|
||||
|
||||
|
||||
# Set new position
|
||||
setprop("/position/latitude-deg", position.lat());
|
||||
setprop("/position/longitude-deg", position.lon());
|
||||
|
||||
setprop("/orientation/heading-deg", heading);
|
||||
setprop("velocities/groundspeed-kt",speed);
|
||||
} else {
|
||||
setprop("velocities/groundspeed-kt",0);
|
||||
}
|
||||
var g_alt = geo.elevation(position.lat(),position.lon());#getprop("/position/ground-elev-ft");
|
||||
if (g_alt == nil) g_alt = 0;
|
||||
g_alt *= M2FT;
|
||||
|
||||
var alt_diff = g_alt - getprop("/position/altitude-ft");
|
||||
|
||||
var pitch = math.atan2(alt_diff, distance*M2FT)*R2D;
|
||||
|
||||
setprop("/orientation/pitch-deg", pitch);
|
||||
|
||||
setprop("/position/altitude-ft",g_alt);
|
||||
|
||||
|
||||
|
||||
|
||||
# Update heading
|
||||
var course = heading + rudder * heading_ps * dt;
|
||||
setprop("/orientation/heading-deg", course);
|
||||
setprop("velocities/groundspeed-kt",speed);
|
||||
} else {
|
||||
setprop("velocities/groundspeed-kt",0);
|
||||
}
|
||||
|
||||
#set pitch
|
||||
setprop("/orientation/pitch-deg",getprop("/carrier/pitch-deg") + getprop("/carrier/pitch-offset"));
|
||||
|
||||
|
||||
#set roll
|
||||
setprop("/orientation/roll-deg",getprop("/carrier/roll-deg") + getprop("/carrier/roll-offset"));
|
||||
setprop("/orientation/roll-deg", 0);
|
||||
|
||||
};
|
||||
|
||||
|
||||
+162
-18
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.93
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -13,6 +13,8 @@ var Math = {
|
||||
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
|
||||
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
|
||||
#
|
||||
# Cartesian is right-handed coord system.
|
||||
#
|
||||
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
|
||||
|
||||
convertCoords: func (x,y,z) {
|
||||
@@ -37,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -55,9 +59,27 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
|
||||
me.mag = 1;
|
||||
call(func {me.mag = math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2))},nil,nil,var err =[]);#strange bug in Nasal can sometimes mess up sqrt
|
||||
return me.mag;
|
||||
},
|
||||
|
||||
# dot product of 2 vectors
|
||||
@@ -65,8 +87,20 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
@@ -74,15 +108,34 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
# rotate a vector. Order: yaw, pitch
|
||||
yawPitchVector: func (yaw, pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.pitchM, me.yawM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
return me.multiplyMatrixWithVector(me.pitchM, vector);
|
||||
},
|
||||
|
||||
# multiply 3x3 matrix with vector
|
||||
multiplyMatrixWithVector: func (matrix, vector) {
|
||||
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
|
||||
@@ -107,10 +160,10 @@ var Math = {
|
||||
|
||||
# matrix for pitching
|
||||
pitchMatrix: func (pitch) {
|
||||
pitch = pitch * D2R;
|
||||
return [math.cos(pitch),0,-math.sin(pitch),
|
||||
pitch = -pitch * D2R;
|
||||
return [math.cos(pitch),0,math.sin(pitch),
|
||||
0,1,0,
|
||||
math.sin(pitch),0,math.cos(pitch)];
|
||||
-math.sin(pitch),0,math.cos(pitch)];
|
||||
},
|
||||
|
||||
# matrix for yawing
|
||||
@@ -126,7 +179,8 @@ var Math = {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
@@ -144,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -242,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -268,7 +369,7 @@ var Math = {
|
||||
|
||||
# print vector to console
|
||||
format: func (v) {
|
||||
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
|
||||
return sprintf("(%.2f, %.2f, %.2f)",v[0],v[1],v[2]);
|
||||
},
|
||||
|
||||
# make vector length 1.0
|
||||
@@ -288,6 +389,20 @@ var Math = {
|
||||
|
||||
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
|
||||
},
|
||||
|
||||
interpolateVector: func (start, end, fraction) {
|
||||
me.xx = (start[0]*(1-fraction) +end[0]*fraction);
|
||||
me.yy = (start[1]*(1-fraction) +end[1]*fraction);
|
||||
me.zz = (start[2]*(1-fraction) +end[2]*fraction);
|
||||
|
||||
return [me.xx, me.yy, me.zz];
|
||||
},
|
||||
|
||||
# move distance 'along' from start towards end. Total dist from start to end is dist.
|
||||
alongVector: func (start, end, dist, along) {
|
||||
me.fraction = along/dist;
|
||||
return me.interpolateVector(start, end, me.fraction);
|
||||
},
|
||||
|
||||
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
|
||||
orthogonalProjection: func(vec, ref){
|
||||
@@ -319,9 +434,9 @@ var Math = {
|
||||
#| 0 cos(roll) -sin(roll) |
|
||||
#| 0 sin(roll) cos(roll) |
|
||||
#
|
||||
#| cos(pitch) 0 -sin(pitch) |
|
||||
#| 0 1 0 |
|
||||
#| sin(pitch) 0 cos(pitch) |
|
||||
#| cos(-pitch) 0 sin(-pitch) |
|
||||
#| 0 1 0 |
|
||||
#| -sin(-pitch) 0 cos(-pitch) |
|
||||
#
|
||||
#| cos(yaw) -sin(yaw) 0 |
|
||||
#| sin(yaw) cos(yaw) 0 |
|
||||
@@ -336,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
+66
-77
@@ -1,65 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
systems adapted from truck by onox
|
||||
|
||||
model by Jüttner Domokos aka Rudolf
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
|
||||
<environment>
|
||||
<in-to-wind type="bool">false</in-to-wind>
|
||||
</environment>
|
||||
|
||||
<carrier>
|
||||
<fdm>
|
||||
<settings>
|
||||
<!-- The maximum bank angle during full rudder deflection -->
|
||||
<bank-limit type="double">15.0</bank-limit>
|
||||
|
||||
<!-- Frequency and overshoot of the oscillator used to
|
||||
simulate heeling (roll).
|
||||
-->
|
||||
<heel-frequency type="double">0.5</heel-frequency>
|
||||
<heel-overshoot type="double">4.0</heel-overshoot>
|
||||
|
||||
<!-- Frequency and overshoot of the oscillator used to
|
||||
simulate trimming (pitch).
|
||||
-->
|
||||
<trim-frequency type="double">0.32</trim-frequency>
|
||||
<trim-overshoot type="double">0.45</trim-overshoot>
|
||||
|
||||
<!-- The speed of the waves plus speed of the ship in knots
|
||||
which generates the maximum overshoot of the trim
|
||||
oscillation.
|
||||
-->
|
||||
<max-trim-oscillation-wave-kt type="double">30.0</max-trim-oscillation-wave-kt>
|
||||
|
||||
<!-- The speed of the waves in knots which generates the
|
||||
maximum overshoot of the heel oscillation.
|
||||
-->
|
||||
<max-heel-oscillation-wave-kt type="double">20.0</max-heel-oscillation-wave-kt>
|
||||
|
||||
<movement type="bool">true</movement>
|
||||
</settings>
|
||||
</fdm>
|
||||
</carrier>
|
||||
|
||||
<sim> <!-- include="Sim/views.xml"> -->
|
||||
<author>pinto, onox, Rudolf</author>
|
||||
<sim>
|
||||
<author>Rudolf, pinto, Nikolai V. Chr., onox</author>
|
||||
<description>ZSU-23-4M "Shilka" AAA defence system</description>
|
||||
<status>alpha</status>
|
||||
<aircraft-version>0.1</aircraft-version>
|
||||
@@ -104,37 +55,34 @@
|
||||
</font>
|
||||
</hud>
|
||||
|
||||
<menubar include="Dialogs/menu.xml"/>
|
||||
<!--menubar include="Dialogs/menu.xml"/-->
|
||||
|
||||
<multiplay>
|
||||
<generic>
|
||||
<int n="0" type="int">0</int>
|
||||
<int n="1" type="int" alias="/controls/armament/trigger"/>
|
||||
<float n="0" type="double">0</float> <!-- Turret azimuth -->
|
||||
<float n="1" type="double">0</float> <!-- gun elevation -->
|
||||
<float n="2" type="double">0</float> <!-- radar azimuth -->
|
||||
<float n="3" type="double">0</float> <!-- radar elevation -->
|
||||
<int n="0" type="int">0</int>
|
||||
<int n="1" type="int" alias="/sim/multiplay/generic/bool[0]"/>
|
||||
<float n="0" type="double">0</float> <!-- Turret azimuth -->
|
||||
<float n="1" type="double">0</float> <!-- gun elevation -->
|
||||
<float n="2" type="double">0</float> <!-- radar azimuth -->
|
||||
<float n="3" type="double">0</float> <!-- radar elevation -->
|
||||
<bool n="0" type="bool">false</bool>
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
</multiplay>
|
||||
|
||||
<systems>
|
||||
<autopilot>
|
||||
<path>Systems/fbw.xml</path>
|
||||
</autopilot>
|
||||
<autopilot>
|
||||
<path>Systems/fdm.xml</path>
|
||||
</autopilot>
|
||||
<property-rule>
|
||||
<path>Systems/radar-pos.xml</path>\
|
||||
</property-rule>
|
||||
<property-rule>
|
||||
<path>Systems/radar-pos.xml</path>\
|
||||
</property-rule>
|
||||
|
||||
</systems>
|
||||
|
||||
|
||||
<menubar>
|
||||
<default>
|
||||
<menu n="100">
|
||||
<label>Truck</label>
|
||||
<label>ZSU-23</label>
|
||||
<enabled type="bool">true</enabled>
|
||||
|
||||
<item>
|
||||
<label>Event Log</label>
|
||||
<binding>
|
||||
@@ -242,9 +190,45 @@
|
||||
<trigger type="bool">0</trigger>
|
||||
</armament>
|
||||
</controls>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">target1</e1>
|
||||
<e2 userarchive="y" type="string">target2</e2>
|
||||
<e3 userarchive="y" type="string">target3</e3>
|
||||
<e4 userarchive="y" type="string">target4</e4>
|
||||
<e5 userarchive="y" type="string">target5</e5>
|
||||
<e6 userarchive="y" type="string">target6</e6>
|
||||
<e7 userarchive="y" type="string">target7</e7>
|
||||
<e8 userarchive="y" type="string">target8</e8>
|
||||
<e9 userarchive="y" type="string">target9</e9>
|
||||
<e10 userarchive="y" type="string">targetA</e10>
|
||||
<e11 userarchive="y" type="string">targetB</e11>
|
||||
<e12 userarchive="y" type="string">targetC</e12>
|
||||
</enemies>
|
||||
|
||||
<priority type="int">0</priority>
|
||||
<priority0 type="int">1</priority0>
|
||||
|
||||
<payload>
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">2</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">5</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<MP-lat type="string">rotors/main/blade[0]/flap-deg</MP-lat>
|
||||
<MP-lon type="string">rotors/main/blade[1]/flap-deg</MP-lon>
|
||||
<MP-alt type="string">rotors/main/blade[2]/flap-deg</MP-alt>
|
||||
<MP-alt-ft type="string">rotors/main/blade[2]/position-deg</MP-alt-ft>
|
||||
<models type="string">Aircraft/ZSU-23/Models/emesary/</models>
|
||||
<msg type="bool">true</msg>
|
||||
<enable-craters type="bool">true</enable-craters>
|
||||
@@ -265,14 +249,19 @@
|
||||
<carrier>
|
||||
<file>Aircraft/ZSU-23/Nasal/fdm.nas</file>
|
||||
</carrier>
|
||||
|
||||
<damage>
|
||||
<file>Aircraft/ZSU-23/Nasal/damage.nas</file>
|
||||
</damage>
|
||||
<vector>
|
||||
<file>Aircraft/ZSU-23/Nasal/vector.nas</file>
|
||||
</vector>
|
||||
<radar_logic>
|
||||
<file>Aircraft/ZSU-23/Nasal/radar-logic.nas</file>
|
||||
</radar_logic>
|
||||
<damage>
|
||||
<file>Aircraft/ZSU-23/Nasal/damage.nas</file>
|
||||
</damage>
|
||||
<fire_control>
|
||||
<file>Aircraft/ZSU-23/Nasal/fire-control.nas</file>
|
||||
</fire_control>
|
||||
</nasal>
|
||||
|
||||
<input>
|
||||
<mice include="Sim/mice.xml"/>
|
||||
</input>
|
||||
|
||||
</PropertyList>
|
||||
|
||||
+220
-87
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (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.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 = 900;# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -66,7 +68,7 @@ var shells = {
|
||||
|
||||
var warheads = {
|
||||
# [id,lbs,anti surface,cluster,(name)]
|
||||
"AGM-65": [ 0, 126.00,1,0],
|
||||
"AGM-65B": [ 0, 126.00,1,0],
|
||||
"AGM-84": [ 1, 488.00,1,0],
|
||||
"AGM-88": [ 2, 146.00,1,0],
|
||||
"MK-82SE": [ 3, 192.00,1,0],# snake eye
|
||||
@@ -75,12 +77,12 @@ var warheads = {
|
||||
"AGM-158": [ 6, 1000.00,1,0],
|
||||
"ALARM": [ 7, 450.00,1,0],
|
||||
"AM 39 Exocet": [ 8, 364.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],# Also : AJ 168 Martel
|
||||
"AS30L": [10, 529.00,1,0],
|
||||
"BL755": [11, 100.00,1,1],# 800lb bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-87": [12, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-105": [13, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"AJ 168 Martel": [14, 330.00,1,0],
|
||||
"AS 37 Armat": [14, 330.00,1,0],
|
||||
"FAB-100": [15, 92.59,1,0],
|
||||
"FAB-250": [16, 202.85,1,0],
|
||||
"FAB-500": [17, 564.38,1,0],
|
||||
@@ -88,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -124,14 +126,14 @@ var warheads = {
|
||||
"AIM-7F": [55, 88.00,0,0],
|
||||
"AGM-62": [56, 2000.00,1,0],
|
||||
"AIM-9L": [57, 20.80,0,0],
|
||||
"d-7": [58, 44.00,0,0],#deprecated
|
||||
"AGM-65D": [58, 126.00,1,0],
|
||||
"AIM-132": [59, 22.05,0,0],
|
||||
"d-8": [60, 20.80,0,0],#deprecated
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1176,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
+20
-20
@@ -42,26 +42,26 @@ var PositionUpdater = func () {
|
||||
var type = getprop("sim/multiplay/generic/int[17]");
|
||||
if (type != last_type) {
|
||||
if (damage.hp_max == damage.hp) {
|
||||
if (type == 0) {damage.hp_max=900;damage.hp=900;}
|
||||
if (type == 1) {damage.hp_max=500;damage.hp=500;}
|
||||
if (type == 2) {damage.hp_max=200;damage.hp=200;}
|
||||
if (type == 3) {damage.hp_max=300;damage.hp=300;}
|
||||
if (type == 4) {damage.hp_max=900;damage.hp=900;}
|
||||
if (type == 5) {damage.hp_max=1500;damage.hp=1500;}
|
||||
if (type == 6) {damage.hp_max=450;damage.hp=450;}
|
||||
if (type == 7) {damage.hp_max=0;damage.hp=0;}
|
||||
if (type == 8) {damage.hp_max=300;damage.hp=300;}
|
||||
if (type == 9) {damage.hp_max=300;damage.hp=300;}
|
||||
if (type == 10) {damage.hp_max=500;damage.hp=500;}
|
||||
if (type == 11) {damage.hp_max=200;damage.hp=200;}
|
||||
if (type == 12) {damage.hp_max=0;damage.hp=0;}
|
||||
if (type == 14) {damage.hp_max=600;damage.hp=600;}
|
||||
if (type == 15) {damage.hp_max=1400;damage.hp=1400;}
|
||||
if (type == 16) {damage.hp_max=100;damage.hp=100;}
|
||||
if (type == 17) {damage.hp_max=300;damage.hp=300;}
|
||||
if (type == 18) {damage.hp_max=50;damage.hp=50;}
|
||||
if (type == 19) {damage.hp_max=2500;damage.hp=2500;}
|
||||
if (type == 20) {damage.hp_max=300;damage.hp=300;}
|
||||
if (type == 0) {damage.hp_max=900;damage.hp=damage.hp_max;}
|
||||
if (type == 1) {damage.hp_max=500;damage.hp=damage.hp_max;}
|
||||
if (type == 2) {damage.hp_max=200;damage.hp=damage.hp_max;}
|
||||
if (type == 3) {damage.hp_max=300;damage.hp=damage.hp_max;}
|
||||
if (type == 4) {damage.hp_max=900;damage.hp=damage.hp_max;}
|
||||
if (type == 5) {damage.hp_max=1500;damage.hp=damage.hp_max;}
|
||||
if (type == 6) {damage.hp_max=450;damage.hp=damage.hp_max;}
|
||||
if (type == 7) {damage.hp_max=0;damage.hp=damage.hp_max;}
|
||||
if (type == 8) {damage.hp_max=300;damage.hp=damage.hp_max;}
|
||||
if (type == 9) {damage.hp_max=300;damage.hp=damage.hp_max;}
|
||||
if (type == 10) {damage.hp_max=500;damage.hp=damage.hp_max;}
|
||||
if (type == 11) {damage.hp_max=200;damage.hp=damage.hp_max;}
|
||||
if (type == 12) {damage.hp_max=0;damage.hp=damage.hp_max;}
|
||||
if (type == 14) {damage.hp_max=600;damage.hp=damage.hp_max;}
|
||||
if (type == 15) {damage.hp_max=1400;damage.hp=damage.hp_max;}
|
||||
if (type == 16) {damage.hp_max=100;damage.hp=damage.hp_max;}
|
||||
if (type == 17) {damage.hp_max=300;damage.hp=damage.hp_max;}
|
||||
if (type == 18) {damage.hp_max=50;damage.hp=damage.hp_max;}
|
||||
if (type == 19) {damage.hp_max=2500;damage.hp=damage.hp_max;}
|
||||
if (type == 20) {damage.hp_max=300;damage.hp=damage.hp_max;}
|
||||
last_type = type;
|
||||
} else {
|
||||
print("Can only switch type when not damaged!!");
|
||||
|
||||
+162
-18
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.93
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -13,6 +13,8 @@ var Math = {
|
||||
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
|
||||
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
|
||||
#
|
||||
# Cartesian is right-handed coord system.
|
||||
#
|
||||
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
|
||||
|
||||
convertCoords: func (x,y,z) {
|
||||
@@ -37,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -55,9 +59,27 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
|
||||
me.mag = 1;
|
||||
call(func {me.mag = math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2))},nil,nil,var err =[]);#strange bug in Nasal can sometimes mess up sqrt
|
||||
return me.mag;
|
||||
},
|
||||
|
||||
# dot product of 2 vectors
|
||||
@@ -65,8 +87,20 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
@@ -74,15 +108,34 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
# rotate a vector. Order: yaw, pitch
|
||||
yawPitchVector: func (yaw, pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.pitchM, me.yawM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
return me.multiplyMatrixWithVector(me.pitchM, vector);
|
||||
},
|
||||
|
||||
# multiply 3x3 matrix with vector
|
||||
multiplyMatrixWithVector: func (matrix, vector) {
|
||||
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
|
||||
@@ -107,10 +160,10 @@ var Math = {
|
||||
|
||||
# matrix for pitching
|
||||
pitchMatrix: func (pitch) {
|
||||
pitch = pitch * D2R;
|
||||
return [math.cos(pitch),0,-math.sin(pitch),
|
||||
pitch = -pitch * D2R;
|
||||
return [math.cos(pitch),0,math.sin(pitch),
|
||||
0,1,0,
|
||||
math.sin(pitch),0,math.cos(pitch)];
|
||||
-math.sin(pitch),0,math.cos(pitch)];
|
||||
},
|
||||
|
||||
# matrix for yawing
|
||||
@@ -126,7 +179,8 @@ var Math = {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
@@ -144,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -242,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -268,7 +369,7 @@ var Math = {
|
||||
|
||||
# print vector to console
|
||||
format: func (v) {
|
||||
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
|
||||
return sprintf("(%.2f, %.2f, %.2f)",v[0],v[1],v[2]);
|
||||
},
|
||||
|
||||
# make vector length 1.0
|
||||
@@ -288,6 +389,20 @@ var Math = {
|
||||
|
||||
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
|
||||
},
|
||||
|
||||
interpolateVector: func (start, end, fraction) {
|
||||
me.xx = (start[0]*(1-fraction) +end[0]*fraction);
|
||||
me.yy = (start[1]*(1-fraction) +end[1]*fraction);
|
||||
me.zz = (start[2]*(1-fraction) +end[2]*fraction);
|
||||
|
||||
return [me.xx, me.yy, me.zz];
|
||||
},
|
||||
|
||||
# move distance 'along' from start towards end. Total dist from start to end is dist.
|
||||
alongVector: func (start, end, dist, along) {
|
||||
me.fraction = along/dist;
|
||||
return me.interpolateVector(start, end, me.fraction);
|
||||
},
|
||||
|
||||
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
|
||||
orthogonalProjection: func(vec, ref){
|
||||
@@ -319,9 +434,9 @@ var Math = {
|
||||
#| 0 cos(roll) -sin(roll) |
|
||||
#| 0 sin(roll) cos(roll) |
|
||||
#
|
||||
#| cos(pitch) 0 -sin(pitch) |
|
||||
#| 0 1 0 |
|
||||
#| sin(pitch) 0 cos(pitch) |
|
||||
#| cos(-pitch) 0 sin(-pitch) |
|
||||
#| 0 1 0 |
|
||||
#| -sin(-pitch) 0 cos(-pitch) |
|
||||
#
|
||||
#| cos(yaw) -sin(yaw) 0 |
|
||||
#| sin(yaw) cos(yaw) 0 |
|
||||
@@ -336,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
@@ -1,22 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2015 onox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
|
||||
</PropertyList>
|
||||
|
||||
+16
-1
@@ -3,7 +3,7 @@
|
||||
<PropertyList>
|
||||
|
||||
<sim>
|
||||
<author>pinto</author>
|
||||
<author>pinto, Nikolai V. Chr., FGUK</author>
|
||||
<description>depot</description>
|
||||
<status>alpha</status>
|
||||
<aircraft-version>0.2</aircraft-version>
|
||||
@@ -50,6 +50,7 @@
|
||||
<int n="0" type="int">0</int>
|
||||
<int n="2" type="int">1</int>
|
||||
<int n="17" type="int">0</int>
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
</multiplay>
|
||||
|
||||
@@ -67,6 +68,20 @@
|
||||
</sim>
|
||||
|
||||
<payload>
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">10</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">900</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/depot/Models/emesary/</models>
|
||||
<msg type="bool">true</msg>
|
||||
|
||||
+220
-87
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (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.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -66,7 +68,7 @@ var shells = {
|
||||
|
||||
var warheads = {
|
||||
# [id,lbs,anti surface,cluster,(name)]
|
||||
"AGM-65": [ 0, 126.00,1,0],
|
||||
"AGM-65B": [ 0, 126.00,1,0],
|
||||
"AGM-84": [ 1, 488.00,1,0],
|
||||
"AGM-88": [ 2, 146.00,1,0],
|
||||
"MK-82SE": [ 3, 192.00,1,0],# snake eye
|
||||
@@ -75,12 +77,12 @@ var warheads = {
|
||||
"AGM-158": [ 6, 1000.00,1,0],
|
||||
"ALARM": [ 7, 450.00,1,0],
|
||||
"AM 39 Exocet": [ 8, 364.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],# Also : AJ 168 Martel
|
||||
"AS30L": [10, 529.00,1,0],
|
||||
"BL755": [11, 100.00,1,1],# 800lb bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-87": [12, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-105": [13, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"AJ 168 Martel": [14, 330.00,1,0],
|
||||
"AS 37 Armat": [14, 330.00,1,0],
|
||||
"FAB-100": [15, 92.59,1,0],
|
||||
"FAB-250": [16, 202.85,1,0],
|
||||
"FAB-500": [17, 564.38,1,0],
|
||||
@@ -88,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -124,14 +126,14 @@ var warheads = {
|
||||
"AIM-7F": [55, 88.00,0,0],
|
||||
"AGM-62": [56, 2000.00,1,0],
|
||||
"AIM-9L": [57, 20.80,0,0],
|
||||
"d-7": [58, 44.00,0,0],#deprecated
|
||||
"AGM-65D": [58, 126.00,1,0],
|
||||
"AIM-132": [59, 22.05,0,0],
|
||||
"d-8": [60, 20.80,0,0],#deprecated
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1176,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
+1
-1
@@ -77,7 +77,7 @@ var PositionUpdater = func () {
|
||||
# Set new position
|
||||
setprop("/position/latitude-deg", position.lat());
|
||||
setprop("/position/longitude-deg", position.lon());
|
||||
var g_alt = getprop("/position/ground-elev-ft")+1;
|
||||
var g_alt = getprop("/position/ground-elev-ft");
|
||||
setprop("/position/altitude-ft",g_alt);
|
||||
|
||||
# Update heading
|
||||
|
||||
+162
-18
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.93
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -13,6 +13,8 @@ var Math = {
|
||||
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
|
||||
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
|
||||
#
|
||||
# Cartesian is right-handed coord system.
|
||||
#
|
||||
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
|
||||
|
||||
convertCoords: func (x,y,z) {
|
||||
@@ -37,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -55,9 +59,27 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
|
||||
me.mag = 1;
|
||||
call(func {me.mag = math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2))},nil,nil,var err =[]);#strange bug in Nasal can sometimes mess up sqrt
|
||||
return me.mag;
|
||||
},
|
||||
|
||||
# dot product of 2 vectors
|
||||
@@ -65,8 +87,20 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
@@ -74,15 +108,34 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
# rotate a vector. Order: yaw, pitch
|
||||
yawPitchVector: func (yaw, pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.pitchM, me.yawM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
return me.multiplyMatrixWithVector(me.pitchM, vector);
|
||||
},
|
||||
|
||||
# multiply 3x3 matrix with vector
|
||||
multiplyMatrixWithVector: func (matrix, vector) {
|
||||
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
|
||||
@@ -107,10 +160,10 @@ var Math = {
|
||||
|
||||
# matrix for pitching
|
||||
pitchMatrix: func (pitch) {
|
||||
pitch = pitch * D2R;
|
||||
return [math.cos(pitch),0,-math.sin(pitch),
|
||||
pitch = -pitch * D2R;
|
||||
return [math.cos(pitch),0,math.sin(pitch),
|
||||
0,1,0,
|
||||
math.sin(pitch),0,math.cos(pitch)];
|
||||
-math.sin(pitch),0,math.cos(pitch)];
|
||||
},
|
||||
|
||||
# matrix for yawing
|
||||
@@ -126,7 +179,8 @@ var Math = {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
@@ -144,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -242,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -268,7 +369,7 @@ var Math = {
|
||||
|
||||
# print vector to console
|
||||
format: func (v) {
|
||||
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
|
||||
return sprintf("(%.2f, %.2f, %.2f)",v[0],v[1],v[2]);
|
||||
},
|
||||
|
||||
# make vector length 1.0
|
||||
@@ -288,6 +389,20 @@ var Math = {
|
||||
|
||||
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
|
||||
},
|
||||
|
||||
interpolateVector: func (start, end, fraction) {
|
||||
me.xx = (start[0]*(1-fraction) +end[0]*fraction);
|
||||
me.yy = (start[1]*(1-fraction) +end[1]*fraction);
|
||||
me.zz = (start[2]*(1-fraction) +end[2]*fraction);
|
||||
|
||||
return [me.xx, me.yy, me.zz];
|
||||
},
|
||||
|
||||
# move distance 'along' from start towards end. Total dist from start to end is dist.
|
||||
alongVector: func (start, end, dist, along) {
|
||||
me.fraction = along/dist;
|
||||
return me.interpolateVector(start, end, me.fraction);
|
||||
},
|
||||
|
||||
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
|
||||
orthogonalProjection: func(vec, ref){
|
||||
@@ -319,9 +434,9 @@ var Math = {
|
||||
#| 0 cos(roll) -sin(roll) |
|
||||
#| 0 sin(roll) cos(roll) |
|
||||
#
|
||||
#| cos(pitch) 0 -sin(pitch) |
|
||||
#| 0 1 0 |
|
||||
#| sin(pitch) 0 cos(pitch) |
|
||||
#| cos(-pitch) 0 sin(-pitch) |
|
||||
#| 0 1 0 |
|
||||
#| -sin(-pitch) 0 cos(-pitch) |
|
||||
#
|
||||
#| cos(yaw) -sin(yaw) 0 |
|
||||
#| sin(yaw) cos(yaw) 0 |
|
||||
@@ -336,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
+74
-36
@@ -60,7 +60,7 @@
|
||||
<disabled type="bool">false</disabled>
|
||||
</carrier>
|
||||
|
||||
<sim include="Sim/views.xml">
|
||||
<sim>
|
||||
<author>pinto, onox, Nikolai V. Chr., Alexis Bory, Detlef Faber, T. Henkel</author>
|
||||
<description>Fleet</description>
|
||||
<long-description>
|
||||
@@ -143,6 +143,7 @@
|
||||
<bool n="44" type="bool">false</bool>
|
||||
<bool n="45" type="bool">false</bool>
|
||||
<bool n="46" type="bool">false</bool>
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
</multiplay>
|
||||
<menubar>
|
||||
@@ -150,23 +151,7 @@
|
||||
<menu n="100">
|
||||
<label>Missile-frigate</label>
|
||||
<enabled type="bool">true</enabled>
|
||||
<item>
|
||||
<label>Reload</label>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
<script>
|
||||
fire_control.reload();
|
||||
</script>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Targets</label>
|
||||
<name>enemies</name>
|
||||
<binding>
|
||||
<command>dialog-show</command>
|
||||
<dialog-name>enemies</dialog-name>
|
||||
</binding>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<label>Event Log</label>
|
||||
<binding>
|
||||
@@ -194,6 +179,36 @@
|
||||
<path>enemies/e12</path>
|
||||
</aircraft-data>
|
||||
|
||||
<view n="200">
|
||||
<name>Follow</name>
|
||||
<type>lookat</type>
|
||||
<internal>false</internal>
|
||||
<config>
|
||||
<!--<from-model type="bool">true</from-model>
|
||||
<from-model-idx type="int">0</from-model-idx>-->
|
||||
<eye-fixed type="bool">true</eye-fixed>
|
||||
<target-lat-deg-path>rotors/main/blade[0]/flap-deg</target-lat-deg-path>
|
||||
<target-lon-deg-path>rotors/main/blade[1]/flap-deg</target-lon-deg-path>
|
||||
<target-alt-ft-path>rotors/main/blade[2]/position-deg</target-alt-ft-path>
|
||||
<eye-lat-deg-path>/position/latitude-deg</eye-lat-deg-path>
|
||||
<eye-lon-deg-path>/position/longitude-deg</eye-lon-deg-path>
|
||||
<eye-alt-ft-path>/position/altitude-ft</eye-alt-ft-path>
|
||||
<!--<eye-heading-deg-path>/orientation/heading-deg</eye-heading-deg-path>
|
||||
<eye-pitch-deg-path>/orientation/pitch-deg</eye-pitch-deg-path>
|
||||
<eye-roll-deg-path>/orientation/roll-deg</eye-roll-deg-path>-->
|
||||
<eye-heading-deg-path>/orientation/heading-deg</eye-heading-deg-path>
|
||||
<eye-pitch-deg>0</eye-pitch-deg>
|
||||
<eye-roll-deg>0</eye-roll-deg>
|
||||
<x-offset-m>50</x-offset-m>
|
||||
<y-offset-m>50</y-offset-m>
|
||||
<z-offset-m>25</z-offset-m>
|
||||
<default-field-of-view-deg>120</default-field-of-view-deg>
|
||||
<limits>
|
||||
<enabled type="bool">false</enabled>
|
||||
</limits>
|
||||
</config>
|
||||
</view>
|
||||
|
||||
</sim>
|
||||
|
||||
<!-- need to adjust this (probably) -->
|
||||
@@ -344,9 +359,33 @@
|
||||
<lbs>50</lbs>
|
||||
</opt>
|
||||
</weight>
|
||||
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">20</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">200</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">true</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/fleet/Models/Armament/Weapons/</models>
|
||||
<modelsUseCase type="bool">true</modelsUseCase>
|
||||
<modelsUpperCase type="bool">true</modelsUpperCase>
|
||||
<MP-lat type="string">rotors/main/blade[0]/flap-deg</MP-lat>
|
||||
<MP-lon type="string">rotors/main/blade[1]/flap-deg</MP-lon>
|
||||
<MP-alt type="string">rotors/main/blade[2]/flap-deg</MP-alt>
|
||||
<MP-alt-ft type="string">rotors/main/blade[2]/position-deg</MP-alt-ft>
|
||||
<hit-interpolation type="bool">true</hit-interpolation>
|
||||
<gnd-launch type="bool">true</gnd-launch>
|
||||
<pylon-offset type="int">1</pylon-offset>
|
||||
<pylon-stations>controls/armament</pylon-stations>
|
||||
<station-name type="string">station</station-name>
|
||||
<msg type="bool">true</msg>
|
||||
<damage type="bool">true</damage>
|
||||
<enable-craters type="bool">true</enable-craters>
|
||||
@@ -373,19 +412,22 @@
|
||||
</main>
|
||||
</rotors>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">Leto</e1>
|
||||
<e2 userarchive="y" type="string">swamp</e2>
|
||||
<e3 userarchive="y" type="string">pinto</e3>
|
||||
<e4 userarchive="y" type="string">fb237</e4>
|
||||
<e5 userarchive="y" type="string">Wilco-1</e5>
|
||||
<e6 userarchive="y" type="string">Kokos</e6>
|
||||
<e7 userarchive="y" type="string">J-Mav16</e7>
|
||||
<e8 userarchive="y" type="string">S</e8>
|
||||
<e9 userarchive="y" type="string">Raider1</e9>
|
||||
<e10 userarchive="y" type="string">Slobb</e10>
|
||||
<e11 userarchive="y" type="string">5H1N0B1</e11>
|
||||
<e12 userarchive="y" type="string">SNOWY1</e12>
|
||||
<priority type="int">0</priority>
|
||||
<priority0 type="int">1</priority0>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">target1</e1>
|
||||
<e2 userarchive="y" type="string">target2</e2>
|
||||
<e3 userarchive="y" type="string">target3</e3>
|
||||
<e4 userarchive="y" type="string">target4</e4>
|
||||
<e5 userarchive="y" type="string">target5</e5>
|
||||
<e6 userarchive="y" type="string">target6</e6>
|
||||
<e7 userarchive="y" type="string">target7</e7>
|
||||
<e8 userarchive="y" type="string">target8</e8>
|
||||
<e9 userarchive="y" type="string">target9</e9>
|
||||
<e10 userarchive="y" type="string">targetA</e10>
|
||||
<e11 userarchive="y" type="string">targetB</e11>
|
||||
<e12 userarchive="y" type="string">targetC</e12>
|
||||
</enemies>
|
||||
|
||||
<nasal>
|
||||
@@ -413,8 +455,4 @@
|
||||
</fire_control>
|
||||
</nasal>
|
||||
|
||||
<input>
|
||||
<mice include="Sim/mice.xml"/>
|
||||
</input>
|
||||
|
||||
</PropertyList>
|
||||
|
||||
+220
-87
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (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.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -66,7 +68,7 @@ var shells = {
|
||||
|
||||
var warheads = {
|
||||
# [id,lbs,anti surface,cluster,(name)]
|
||||
"AGM-65": [ 0, 126.00,1,0],
|
||||
"AGM-65B": [ 0, 126.00,1,0],
|
||||
"AGM-84": [ 1, 488.00,1,0],
|
||||
"AGM-88": [ 2, 146.00,1,0],
|
||||
"MK-82SE": [ 3, 192.00,1,0],# snake eye
|
||||
@@ -75,12 +77,12 @@ var warheads = {
|
||||
"AGM-158": [ 6, 1000.00,1,0],
|
||||
"ALARM": [ 7, 450.00,1,0],
|
||||
"AM 39 Exocet": [ 8, 364.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],# Also : AJ 168 Martel
|
||||
"AS30L": [10, 529.00,1,0],
|
||||
"BL755": [11, 100.00,1,1],# 800lb bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-87": [12, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-105": [13, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"AJ 168 Martel": [14, 330.00,1,0],
|
||||
"AS 37 Armat": [14, 330.00,1,0],
|
||||
"FAB-100": [15, 92.59,1,0],
|
||||
"FAB-250": [16, 202.85,1,0],
|
||||
"FAB-500": [17, 564.38,1,0],
|
||||
@@ -88,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -124,14 +126,14 @@ var warheads = {
|
||||
"AIM-7F": [55, 88.00,0,0],
|
||||
"AGM-62": [56, 2000.00,1,0],
|
||||
"AIM-9L": [57, 20.80,0,0],
|
||||
"d-7": [58, 44.00,0,0],#deprecated
|
||||
"AGM-65D": [58, 126.00,1,0],
|
||||
"AIM-132": [59, 22.05,0,0],
|
||||
"d-8": [60, 20.80,0,0],#deprecated
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1176,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
@@ -26,6 +26,7 @@ var prop_watch = {
|
||||
"JA37Di-Viggen": [20,21,22],
|
||||
"AJ37-Viggen": [20,21,22],
|
||||
"AJS37-Viggen": [20,21,22],
|
||||
"Jaguar-GR1": [20,21,22],
|
||||
};
|
||||
|
||||
var radar_stations = [
|
||||
|
||||
+162
-18
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.93
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -13,6 +13,8 @@ var Math = {
|
||||
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
|
||||
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
|
||||
#
|
||||
# Cartesian is right-handed coord system.
|
||||
#
|
||||
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
|
||||
|
||||
convertCoords: func (x,y,z) {
|
||||
@@ -37,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -55,9 +59,27 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
|
||||
me.mag = 1;
|
||||
call(func {me.mag = math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2))},nil,nil,var err =[]);#strange bug in Nasal can sometimes mess up sqrt
|
||||
return me.mag;
|
||||
},
|
||||
|
||||
# dot product of 2 vectors
|
||||
@@ -65,8 +87,20 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
@@ -74,15 +108,34 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
# rotate a vector. Order: yaw, pitch
|
||||
yawPitchVector: func (yaw, pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.pitchM, me.yawM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
return me.multiplyMatrixWithVector(me.pitchM, vector);
|
||||
},
|
||||
|
||||
# multiply 3x3 matrix with vector
|
||||
multiplyMatrixWithVector: func (matrix, vector) {
|
||||
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
|
||||
@@ -107,10 +160,10 @@ var Math = {
|
||||
|
||||
# matrix for pitching
|
||||
pitchMatrix: func (pitch) {
|
||||
pitch = pitch * D2R;
|
||||
return [math.cos(pitch),0,-math.sin(pitch),
|
||||
pitch = -pitch * D2R;
|
||||
return [math.cos(pitch),0,math.sin(pitch),
|
||||
0,1,0,
|
||||
math.sin(pitch),0,math.cos(pitch)];
|
||||
-math.sin(pitch),0,math.cos(pitch)];
|
||||
},
|
||||
|
||||
# matrix for yawing
|
||||
@@ -126,7 +179,8 @@ var Math = {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
@@ -144,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -242,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -268,7 +369,7 @@ var Math = {
|
||||
|
||||
# print vector to console
|
||||
format: func (v) {
|
||||
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
|
||||
return sprintf("(%.2f, %.2f, %.2f)",v[0],v[1],v[2]);
|
||||
},
|
||||
|
||||
# make vector length 1.0
|
||||
@@ -288,6 +389,20 @@ var Math = {
|
||||
|
||||
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
|
||||
},
|
||||
|
||||
interpolateVector: func (start, end, fraction) {
|
||||
me.xx = (start[0]*(1-fraction) +end[0]*fraction);
|
||||
me.yy = (start[1]*(1-fraction) +end[1]*fraction);
|
||||
me.zz = (start[2]*(1-fraction) +end[2]*fraction);
|
||||
|
||||
return [me.xx, me.yy, me.zz];
|
||||
},
|
||||
|
||||
# move distance 'along' from start towards end. Total dist from start to end is dist.
|
||||
alongVector: func (start, end, dist, along) {
|
||||
me.fraction = along/dist;
|
||||
return me.interpolateVector(start, end, me.fraction);
|
||||
},
|
||||
|
||||
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
|
||||
orthogonalProjection: func(vec, ref){
|
||||
@@ -319,9 +434,9 @@ var Math = {
|
||||
#| 0 cos(roll) -sin(roll) |
|
||||
#| 0 sin(roll) cos(roll) |
|
||||
#
|
||||
#| cos(pitch) 0 -sin(pitch) |
|
||||
#| 0 1 0 |
|
||||
#| sin(pitch) 0 cos(pitch) |
|
||||
#| cos(-pitch) 0 sin(-pitch) |
|
||||
#| 0 1 0 |
|
||||
#| -sin(-pitch) 0 cos(-pitch) |
|
||||
#
|
||||
#| cos(yaw) -sin(yaw) 0 |
|
||||
#| sin(yaw) cos(yaw) 0 |
|
||||
@@ -336,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
@@ -1,21 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2015 onox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
|
||||
|
||||
+15
-5
@@ -1,11 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<PropertyList>
|
||||
|
||||
<environment>
|
||||
<in-to-wind type="bool">false</in-to-wind>
|
||||
</environment>
|
||||
|
||||
<sim>
|
||||
<author>pinto</author>
|
||||
<description>gci</description>
|
||||
@@ -111,6 +106,7 @@
|
||||
<generic>
|
||||
<int n="0" type="int">0</int>
|
||||
<int n="2" type="int">0</int>
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
<!--<visibility-range-nm type="int">500</visibility-range-nm>-->
|
||||
</multiplay>
|
||||
@@ -121,6 +117,20 @@
|
||||
</carrier>
|
||||
|
||||
<payload>
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">10</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">80</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/gci-radar/Models/emesary/</models>
|
||||
<msg type="bool">true</msg>
|
||||
|
||||
+238
-99
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (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.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -37,24 +39,30 @@ var shells = {
|
||||
# 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": [0,0.250], #135mm
|
||||
"S-5 rocket": [1,0.200], # 55mm
|
||||
"M55 shell": [2,0.100], # 30mm
|
||||
"KCA shell": [3,0.100], # 30mm
|
||||
"GSh-30": [4,0.100], # 30mm mig29/su27
|
||||
"GAU-8/A": [5,0.100], # 30mm
|
||||
"Mk3Z": [6,0.100], # 30mm Jaguar
|
||||
"BK27": [7,0.070], # 27mm
|
||||
"GSh-23": [8,0.065], # 23mm
|
||||
"M61A1 shell": [9,0.050], # 20mm F14, F15, F16
|
||||
"50 BMG": [10,0.015], # 12.7mm (non-explosive)
|
||||
# Damage roughly proportional to projectile weight.
|
||||
# If weight isn't listed here, it was estimated from dimensions (proportional to diameter^2 * length).
|
||||
# Approximate formulae for cannons:
|
||||
# damage ~ weight / 3.6 (in g)
|
||||
# or damage ~ diameter^2 * length / 1.6e6 (in mm)
|
||||
#
|
||||
"M70 rocket": [0,0.500], # 135mm, ~5kg warhead
|
||||
"S-5 rocket": [1,0.200], # 55mm, ~1-2kg warhead
|
||||
"M55 shell": [2,0.060], # 30x113mm, 220g
|
||||
"KCA shell": [3,0.100], # 30x173mm, 360g
|
||||
"GSh-30": [4,0.095], # 30x165mm mig29/su27
|
||||
"GAU-8/A": [5,0.100], # 30x173mm, 360g
|
||||
"Mk3Z": [6,0.060], # 30x113mm Jaguar, 220g
|
||||
"BK27": [7,0.070], # 27x145mm, 270g
|
||||
"GSh-23": [8,0.040], # 23x115mm,
|
||||
"M61A1 shell": [9,0.030], # 20x102mm F14, F15, F16, 100g
|
||||
"50 BMG": [10,0.015], # 12.7mm (non-explosive)
|
||||
"7.62": [11,0.005], # 7.62mm (non-explosive)
|
||||
"Hydra-70": [12,0.250], # F-16/A-6 LAU-68 and LAU-61
|
||||
"SNEB": [13,0.250], # Jaguar
|
||||
"DEFA 554": [14,0.100], # 30mm Mirage
|
||||
"20mm APDS": [15,0.050], # CIWS
|
||||
"LAU-10": [16,0.225], # 127mm
|
||||
};
|
||||
"Hydra-70": [12,0.500], # 70mm, F-16/A-6 LAU-68 and LAU-61, ~4-6kg warhead
|
||||
"SNEB": [13,0.500], # 68mm, Jaguar
|
||||
"DEFA 554": [14,0.060], # 30x113mm Mirage, 220g
|
||||
"20mm APDS": [15,0.030], # CIWS
|
||||
"LAU-10": [16,0.500], # 127mm, ~4-7kg warhead
|
||||
};
|
||||
|
||||
# lbs of warheads is explosive+fragmentation+fuse, so total warhead mass.
|
||||
|
||||
@@ -82,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -123,9 +131,9 @@ var warheads = {
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -156,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -218,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -250,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -261,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -283,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -291,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -304,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -313,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -339,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -372,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -417,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -430,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -449,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -460,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -600,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -608,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -618,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -637,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -661,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -704,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -730,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -804,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -812,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -832,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -840,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -851,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -858,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -875,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -885,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -897,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -911,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -999,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1033,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1047,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1072,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1131,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1144,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1170,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1197,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1276,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
+66
-49
@@ -23,20 +23,22 @@ print("loading fdm");
|
||||
var frequency = 60.0;
|
||||
|
||||
# Change in heading per second at full rudder deflection
|
||||
var heading_ps = 0.5;
|
||||
var heading_ps = 20;
|
||||
|
||||
time_last = 0;
|
||||
sim_speed = 1;
|
||||
var time_last = 0;
|
||||
var sim_speed = 1;
|
||||
|
||||
var distance = 0;
|
||||
|
||||
var speed = 25;
|
||||
|
||||
setprop("/carrier/sunk",0);
|
||||
setprop("/orientation/pitch-deg", 0);
|
||||
|
||||
var arrived = 0;
|
||||
|
||||
var last_type = 0;
|
||||
|
||||
setprop("/carrier/pitch-deg",0);
|
||||
setprop("/carrier/pitch-offset",0);
|
||||
setprop("/carrier/roll-deg",0);
|
||||
setprop("/carrier/roll-offset",0);
|
||||
setprop("/carrier/sunk",0);
|
||||
var arrived = 0;
|
||||
var PositionUpdater = func () {
|
||||
|
||||
settimer( PositionUpdater, 1/frequency );
|
||||
@@ -47,7 +49,7 @@ var PositionUpdater = func () {
|
||||
setprop("/sim/multiplay/chat",getprop("sim/multiplay/callsign") ~ " has arrived safely!");
|
||||
print("arrived");
|
||||
arrived = 1;
|
||||
#return;
|
||||
return;
|
||||
}
|
||||
|
||||
var time_now = getprop("/sim/time/elapsed-sec");
|
||||
@@ -56,58 +58,70 @@ var PositionUpdater = func () {
|
||||
|
||||
time_last = time_now;
|
||||
|
||||
#var heading = getprop("/orientation/heading-deg");
|
||||
#var speed = getprop("/velocities/groundspeed-kt");
|
||||
var rudder = getprop("/surface-positions/rudder-pos-norm");
|
||||
|
||||
if ( getprop("/carrier/sunk") == 0 and getprop("/autopilot/route-manager/active") == 1 ) {
|
||||
|
||||
#for event
|
||||
|
||||
var cur_waypoint = getprop("/autopilot/route-manager/current-wp");
|
||||
var cur_wp_lon = getprop("/autopilot/route-manager/route/wp[" ~ cur_waypoint ~ "]/longitude-deg");
|
||||
var cur_wp_lat = getprop("/autopilot/route-manager/route/wp[" ~ cur_waypoint ~ "]/latitude-deg");
|
||||
var rm_destination = geo.Coord.new().set_latlon(cur_wp_lat,cur_wp_lon);
|
||||
|
||||
|
||||
var heading = position.course_to(rm_destination);
|
||||
|
||||
var distance = speed * globals.KT2MPS * dt;
|
||||
position.apply_course_distance(heading, distance);
|
||||
|
||||
# Set new position
|
||||
setprop("/position/latitude-deg", position.lat());
|
||||
setprop("/position/longitude-deg", position.lon());
|
||||
var g_alt = getprop("/position/ground-elev-ft")+1;
|
||||
if (cur_waypoint > -1) {
|
||||
var cur_wp_lon = getprop("/autopilot/route-manager/route/wp[" ~ cur_waypoint ~ "]/longitude-deg");
|
||||
var cur_wp_lat = getprop("/autopilot/route-manager/route/wp[" ~ cur_waypoint ~ "]/latitude-deg");
|
||||
var rm_destination = geo.Coord.new().set_latlon(cur_wp_lat,cur_wp_lon);
|
||||
|
||||
var heading = getprop("/orientation/heading-deg");
|
||||
|
||||
var course = position.course_to(rm_destination);
|
||||
|
||||
distance = speed * KT2MPS * dt;
|
||||
|
||||
var turn_max = heading_ps * dt;
|
||||
|
||||
var turn = math.clamp(geo.normdeg180(course-heading),-turn_max,turn_max);
|
||||
|
||||
heading += turn;
|
||||
|
||||
heading = geo.normdeg(heading);
|
||||
|
||||
position.apply_course_distance(heading, distance);
|
||||
|
||||
|
||||
|
||||
# Set new position
|
||||
setprop("/position/latitude-deg", position.lat());
|
||||
setprop("/position/longitude-deg", position.lon());
|
||||
|
||||
setprop("/orientation/heading-deg", heading);
|
||||
setprop("velocities/groundspeed-kt",speed);
|
||||
} else {
|
||||
setprop("velocities/groundspeed-kt",0);
|
||||
}
|
||||
var g_alt = geo.elevation(position.lat(),position.lon());#getprop("/position/ground-elev-ft");
|
||||
if (g_alt == nil) g_alt = 0;
|
||||
g_alt *= M2FT;
|
||||
|
||||
var alt_diff = g_alt - getprop("/position/altitude-ft");
|
||||
|
||||
var pitch = math.atan2(alt_diff, distance*M2FT)*R2D;
|
||||
|
||||
setprop("/orientation/pitch-deg", pitch);
|
||||
|
||||
setprop("/position/altitude-ft",g_alt);
|
||||
|
||||
|
||||
|
||||
|
||||
# Update heading
|
||||
var course = heading + rudder * heading_ps * dt;
|
||||
setprop("/orientation/heading-deg", course);
|
||||
setprop("velocities/groundspeed-kt",speed);
|
||||
} else {
|
||||
setprop("velocities/groundspeed-kt",0);
|
||||
}
|
||||
|
||||
#set pitch
|
||||
setprop("/orientation/pitch-deg",getprop("/carrier/pitch-deg") + getprop("/carrier/pitch-offset"));
|
||||
|
||||
|
||||
#set roll
|
||||
setprop("/orientation/roll-deg",getprop("/carrier/roll-deg") + getprop("/carrier/roll-offset"));
|
||||
|
||||
setprop("/orientation/roll-deg", 0);
|
||||
|
||||
var type = getprop("sim/multiplay/generic/int[17]");
|
||||
if (type != last_type) {
|
||||
if (damage.hp_max == damage.hp) {
|
||||
if (type == 0) {damage.hp_max=5;damage.hp=5;speed=25;}#humvee
|
||||
if (type == 1) {damage.hp_max=100;damage.hp=100;speed=15;}#tank
|
||||
if (type == 2) {damage.hp_max=75;damage.hp=75;speed=10;}#rocket launcher
|
||||
if (type == 3) {damage.hp_max=85;damage.hp=85;speed=20;}#small tank
|
||||
if (type == 4) {damage.hp_max=80;damage.hp=80;speed=20;}#APC (mine proected)
|
||||
if (type == 5) {damage.hp_max=75;damage.hp=75;speed=20;}#APC
|
||||
if (type == 0) {damage.hp_max=5;damage.hp=damage.hp_max;speed=25;}#humvee
|
||||
if (type == 1) {damage.hp_max=100;damage.hp=damage.hp_max;speed=15;}#tank
|
||||
if (type == 2) {damage.hp_max=75;damage.hp=damage.hp_max;speed=10;}#rocket launcher
|
||||
if (type == 3) {damage.hp_max=85;damage.hp=damage.hp_max;speed=20;}#small tank
|
||||
if (type == 4) {damage.hp_max=80;damage.hp=damage.hp_max;speed=20;}#APC (mine proected)
|
||||
if (type == 5) {damage.hp_max=75;damage.hp=damage.hp_max;speed=20;}#APC
|
||||
last_type = type;
|
||||
} else {
|
||||
print("Can only switch type when not damaged!!");
|
||||
@@ -117,4 +131,7 @@ var PositionUpdater = func () {
|
||||
|
||||
};
|
||||
|
||||
PositionUpdater();
|
||||
PositionUpdater();
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.94
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -39,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -57,6 +59,22 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
me.mag = 1;
|
||||
@@ -69,21 +87,24 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
@@ -95,6 +116,20 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
@@ -163,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -261,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -369,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
@@ -46,6 +46,7 @@
|
||||
<generic>
|
||||
<int n="0" type="int">0</int>
|
||||
<int n="17" type="int">0</int>
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
</multiplay>
|
||||
|
||||
@@ -75,6 +76,20 @@
|
||||
</sim>
|
||||
|
||||
<payload>
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">2</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">5</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/groundtarget/Models/emesary/</models>
|
||||
<msg type="bool">true</msg>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
<PropertyList>
|
||||
<description>USS SanAntonio</description>
|
||||
<author>Naval Postgraduate School SAVAGE project, Vivian Meazza, Heiko Schulz</author>
|
||||
<status>early-production</status>
|
||||
<author>Naval Postgraduate School SAVAGE project, Vivian Meazza, Heiko Schulz</author>
|
||||
<status>early-production</status>
|
||||
<path>LPD17.ac</path>
|
||||
<nasal>
|
||||
<load><![CDATA[
|
||||
@@ -92,15 +92,15 @@
|
||||
<property>surface-positions/elevators-pos-norm</property>
|
||||
<factor>-90.0</factor>
|
||||
<center>
|
||||
<x-m>94.936</x-m>
|
||||
<y-m>0.00</y-m>
|
||||
<z-m>3.968</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>0</x>
|
||||
<y>1</y>
|
||||
<z>0</z>
|
||||
</axis>
|
||||
<x-m>94.936</x-m>
|
||||
<y-m>0.00</y-m>
|
||||
<z-m>3.968</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>0</x>
|
||||
<y>1</y>
|
||||
<z>0</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
@@ -109,15 +109,15 @@
|
||||
<property>surface-positions/elevators-pos-norm</property>
|
||||
<factor>90.0</factor>
|
||||
<center>
|
||||
<x-m>93.243</x-m>
|
||||
<y-m>0.00</y-m>
|
||||
<z-m>-6.464</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>0</x>
|
||||
<y>1</y>
|
||||
<z>0</z>
|
||||
</axis>
|
||||
<x-m>93.243</x-m>
|
||||
<y-m>0.00</y-m>
|
||||
<z-m>-6.464</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>0</x>
|
||||
<y>1</y>
|
||||
<z>0</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<model>
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
#
|
||||
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
|
||||
# for damage to be recognised, the property /payload/armament/msg must be 1
|
||||
# if /payload/armament/spectator is 1 and damage off, missile trails, craters, flares,
|
||||
# and missile warnings will be received, but not actual damage.
|
||||
#
|
||||
# Authors: Nikolai V. Chr., Pinto and Richard (with improvement by Onox)
|
||||
# Authors: Nikolai V. Chr., Pinto, Colin Geniet and Richard (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.
|
||||
var full_damage_dist_m = getprop("payload/d-config/full_damage_dist_m");# 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 use_hitpoints_instead_of_failure_modes_bool = getprop("payload/d-config/use_hitpoints_instead_of_failure_modes_bool");# bool. mainly used by assets that don't have failure modes.
|
||||
var hp_max = getprop("payload/d-config/hp_max");# given a direct hit, how much pounds of warhead is needed to kill. Only used if hitpoints is enabled.
|
||||
var hitable_by_air_munitions = getprop("payload/d-config/hitable_by_air_munitions"); # if anti-air can do damage
|
||||
var hitable_by_cannon = getprop("payload/d-config/hitable_by_cannon"); # 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.
|
||||
var rwr_to_screen=0; # for aircraft that do not yet have proper RWR
|
||||
var tacview_supported=0; # For aircraft with tacview support
|
||||
var m28_auto=0; # only used by automats
|
||||
var mlw_max=2.25; #
|
||||
var auto_flare_caller = 0; # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
var is_fleet = getprop("payload/d-config/is_fleet"); # Is really 7 ships, 3 of which has offensive missiles.
|
||||
var rwr_to_screen=getprop("payload/d-config/rwr_to_screen"); # for aircraft that do not yet have proper RWR
|
||||
var rwr_audio_extended=getprop("payload/d-config/rwr_audio_extended"); # for aircraft that want seperate audio properties for different radar spikes.
|
||||
var tacview_supported=getprop("payload/d-config/tacview_supported"); # For aircraft with tacview support
|
||||
var m28_auto=getprop("payload/d-config/m28_auto"); # only used by automats
|
||||
var mlw_max=getprop("payload/d-config/mlw_max"); #
|
||||
var auto_flare_caller = getprop("payload/d-config/auto_flare_caller"); # If damage.nas should detect flare releases, or if function is called from somewhere in aircraft
|
||||
############################################################################################################################
|
||||
|
||||
var TRUE = 1;
|
||||
@@ -66,7 +68,7 @@ var shells = {
|
||||
|
||||
var warheads = {
|
||||
# [id,lbs,anti surface,cluster,(name)]
|
||||
"AGM-65": [ 0, 126.00,1,0],
|
||||
"AGM-65B": [ 0, 126.00,1,0],
|
||||
"AGM-84": [ 1, 488.00,1,0],
|
||||
"AGM-88": [ 2, 146.00,1,0],
|
||||
"MK-82SE": [ 3, 192.00,1,0],# snake eye
|
||||
@@ -75,12 +77,12 @@ var warheads = {
|
||||
"AGM-158": [ 6, 1000.00,1,0],
|
||||
"ALARM": [ 7, 450.00,1,0],
|
||||
"AM 39 Exocet": [ 8, 364.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],
|
||||
"AS 37 Martel": [ 9, 330.00,1,0],# Also : AJ 168 Martel
|
||||
"AS30L": [10, 529.00,1,0],
|
||||
"BL755": [11, 100.00,1,1],# 800lb bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-87": [12, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"CBU-105": [13, 100.00,1,1],# bomblet warhead. Mix of armour piecing and HE. 100 due to need to be able to kill buk-m2.
|
||||
"AJ 168 Martel": [14, 330.00,1,0],
|
||||
"AS 37 Armat": [14, 330.00,1,0],
|
||||
"FAB-100": [15, 92.59,1,0],
|
||||
"FAB-250": [16, 202.85,1,0],
|
||||
"FAB-500": [17, 564.38,1,0],
|
||||
@@ -88,7 +90,7 @@ var warheads = {
|
||||
"GBU-24": [19, 945.00,1,0],
|
||||
"GBU-31": [20, 945.00,1,0],
|
||||
"GBU-54": [21, 190.00,1,0],
|
||||
"GBU-10": [22, 2000.00,1,0],
|
||||
"GBU-10": [22, 945.00,1,0],
|
||||
"GBU-16": [23, 450.00,1,0],
|
||||
"HVAR": [24, 7.50,1,0],#P51
|
||||
"KAB-500": [25, 564.38,1,0],
|
||||
@@ -124,14 +126,14 @@ var warheads = {
|
||||
"AIM-7F": [55, 88.00,0,0],
|
||||
"AGM-62": [56, 2000.00,1,0],
|
||||
"AIM-9L": [57, 20.80,0,0],
|
||||
"d-7": [58, 44.00,0,0],#deprecated
|
||||
"AGM-65D": [58, 126.00,1,0],
|
||||
"AIM-132": [59, 22.05,0,0],
|
||||
"d-8": [60, 20.80,0,0],#deprecated
|
||||
"Apache AP": [60, 110.23,0,1],# Real mass of bomblet. (x 10). Anti runway.
|
||||
"KN-06": [61, 315.00,0,0],
|
||||
"9M317": [62, 145.00,0,0],
|
||||
"d9": [63, 27.00,0,0],#deprecated
|
||||
"GEM": [63, 185.00,0,0],#MIM-104D
|
||||
"R.550 Magic": [64, 26.45,0,0],# also called majic
|
||||
"d-0": [65, 30.00,0,0],#deprecated
|
||||
"5Ya23": [65, 414.00,0,0],#Volga-M
|
||||
"R.550 Magic 2": [66, 27.00,0,0],
|
||||
"R.530": [67, 55.00,0,0],
|
||||
"MK-82AIR": [68, 192.00,1,0],
|
||||
@@ -162,12 +164,46 @@ var warheads = {
|
||||
"pilot": [93, 0.00,1,0],# ejected pilot
|
||||
"BETAB-500ShP": [94, 1160.00,1,0],
|
||||
"Flare": [95, 0.00,0,0],
|
||||
"3M9": [96, 125.00,0,0],# 3M9 Missile used with 2K12/SA-6
|
||||
};
|
||||
|
||||
var AIR_RADAR = "air";
|
||||
|
||||
var radar_signatures = {
|
||||
"unknown-model": AIR_RADAR,
|
||||
"f-14b": AIR_RADAR,
|
||||
"F-14D": AIR_RADAR,
|
||||
"F-15C": AIR_RADAR,
|
||||
"F-15D": AIR_RADAR,
|
||||
"F-16": AIR_RADAR,
|
||||
"AJS37-Viggen": AIR_RADAR,
|
||||
"JA37Di-Viggen": AIR_RADAR,
|
||||
"m2000-5": AIR_RADAR,
|
||||
"m2000-5B": AIR_RADAR,
|
||||
"MiG-21bis": AIR_RADAR,
|
||||
"MiG-21MF-75": AIR_RADAR,
|
||||
"MiG-29": AIR_RADAR,
|
||||
"SU-27": AIR_RADAR,
|
||||
"EC-137R": AIR_RADAR,
|
||||
"RC-137R": AIR_RADAR,
|
||||
"E-8R": AIR_RADAR,
|
||||
"EC-137D": AIR_RADAR,
|
||||
"Mig-28": AIR_RADAR,
|
||||
"SA-6": AIR_RADAR,#Air radar tone chosen so that there is at least some lock tone until asset-specific is created
|
||||
"ZSU-23-4M": "gnd-23",
|
||||
"S-75": "gnd-02",
|
||||
"buk-m2": "gnd-11",
|
||||
"s-300": "gnd-20",
|
||||
"MIM104D": "gnd-p2",
|
||||
"missile_frigate": "gnd-nk",
|
||||
"fleet": "gnd-nk",
|
||||
};
|
||||
|
||||
|
||||
var id2warhead = [];
|
||||
var launched = {};# callsign: elapsed-sec
|
||||
var approached = {};# callsign: uniqueID
|
||||
var heavy_smoke = [61,62,63,65,92];
|
||||
var heavy_smoke = [61,62,63,65,92,96];
|
||||
|
||||
var k = keys(warheads);
|
||||
|
||||
@@ -224,12 +260,12 @@ var DamageRecipient =
|
||||
}
|
||||
#
|
||||
#
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# This will be where movement and damage notifications are received.
|
||||
# This can replace MP chat for damage notifications
|
||||
# and allow missile visibility globally (i.e. all suitable equipped models) have the possibility
|
||||
# to receive notifications from all other suitably equipped models.
|
||||
if (notification.NotificationType == "ArmamentInFlightNotification" or notification.NotificationType == "ObjectInFlightNotification") {
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# print("recv(d1): ",notification.NotificationType, " ", notification.Ident,
|
||||
# " UniqueIdentity=",notification.UniqueIdentity,
|
||||
# " Kind=",notification.Kind,
|
||||
# " SecondaryKind=",notification.SecondaryKind,
|
||||
@@ -256,10 +292,10 @@ var DamageRecipient =
|
||||
notification.Flags = 0;
|
||||
notification.RemoteCallsign = "";
|
||||
}
|
||||
if(getprop("payload/armament/msg") == 0 and notification.RemoteCallsign != notification.Callsign) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1 and notification.RemoteCallsign != notification.Callsign) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
|
||||
|
||||
var elapsed = getprop("sim/time/elapsed-sec");
|
||||
var ownPos = geo.aircraft_position();
|
||||
var bearing = ownPos.course_to(notification.Position);
|
||||
@@ -267,11 +303,11 @@ var DamageRecipient =
|
||||
var thrustOn = bits.test(notification.Flags, 1);
|
||||
var index = notification.SecondaryKind-21;
|
||||
var typ = id2warhead[index];
|
||||
|
||||
|
||||
if (notification.Kind == MOVE) {
|
||||
if (thrustOn or index == 93 or index == 95) {
|
||||
# visualize missile smoke trail
|
||||
|
||||
|
||||
var smoke = 1;
|
||||
if (index == 93) {
|
||||
smoke = 0;
|
||||
@@ -289,7 +325,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime(), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,smoke];
|
||||
|
||||
|
||||
} else {
|
||||
# the +1.5 is the update time that missiles send notifications out in
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
@@ -297,8 +333,8 @@ var DamageRecipient =
|
||||
} elsif (notification.Kind == DESTROY) {
|
||||
dynamics["noti_"~notification.Callsign~"_"~notification.UniqueIdentity] = [systime()-(time_before_delete-1.6), notification.Position.lat(), notification.Position.lon(), notification.Position.alt(), notification.u_fps, notification.Heading, notification.Pitch,-1]
|
||||
}
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") == "mpserver.opredflag.com") {
|
||||
|
||||
if (tacview_supported and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5(notification.Callsign~notification.UniqueIdentity),6);
|
||||
if (notification.Kind == DESTROY) {
|
||||
@@ -310,6 +346,7 @@ var DamageRecipient =
|
||||
var typp = typ[4]=="pilot"?"Parachutist":typ[4];
|
||||
var extra = typp=="Parachutist"?"|0|0|0":"";
|
||||
var extra2 = typ[2]==0?",Type=Weapon+Missile":",Type=Weapon+Bomb";
|
||||
extra2 = typ[4]=="Flare"?",Type=Flare":extra2;
|
||||
extra2 = typp=="Parachutist"?"":extra2;
|
||||
var color = radarOn?",Color=Red":",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
@@ -319,15 +356,15 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (notification.Kind == DESTROY) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
if (index == 95 or index == 93) {
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
|
||||
|
||||
# Missile launch warning:
|
||||
if (thrustOn) {
|
||||
var launch = launched[notification.Callsign~notification.UniqueIdentity];
|
||||
@@ -345,7 +382,7 @@ var DamageRecipient =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Missile approach warning:
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign != callsign) return emesary.Transmitter.ReceiptStatus_OK;
|
||||
@@ -378,6 +415,27 @@ var DamageRecipient =
|
||||
# debug.dump(notification);
|
||||
#
|
||||
#
|
||||
if (tacview_supported and tacview.starttime and getprop("sim/multiplay/txhost") != "mpserver.opredflag.com") {
|
||||
var node = getCallsign(notification.RemoteCallsign);
|
||||
if (node != nil and notification.SecondaryKind > 20) {
|
||||
# its a warhead
|
||||
var wh = id2warhead[notification.SecondaryKind - 21];
|
||||
var lbs = wh[1];
|
||||
var hitCoord = geo.Coord.new();
|
||||
hitCoord.set_latlon(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M+notification.RelativeAltitude);
|
||||
if (notification.Distance > math.abs(notification.RelativeAltitude)) {#just a sanity check
|
||||
hitCoord = hitCoord.apply_course_distance(notification.Bearing, math.sqrt(notification.Distance*notification.Distance-notification.RelativeAltitude*notification.RelativeAltitude));
|
||||
}
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(hitCoord.lat(),hitCoord.lon(),hitCoord.alt(), lbs*0.5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} elsif (node != nil and notification.SecondaryKind < 0) {
|
||||
# its a cannon or rocket
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.writeExplosion(node.getNode("position/latitude-deg").getValue(), node.getNode("position/longitude-deg").getValue(), node.getNode("position/altitude-ft").getValue()*FT2M, 5);
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
var callsign = processCallsign(getprop("sim/multiplay/callsign"));
|
||||
if (notification.RemoteCallsign == callsign and getprop("payload/armament/msg") == 1) {
|
||||
#damage enabled and were getting hit
|
||||
@@ -423,10 +481,10 @@ var DamageRecipient =
|
||||
}
|
||||
|
||||
var distance = math.max(dist-full_damage_dist_m, 0);
|
||||
|
||||
|
||||
var maxDist = 0;# distance where the explosion dont hurt us anymore
|
||||
var lbs = 0;
|
||||
|
||||
|
||||
if (wh[2] == 1) {
|
||||
lbs = wh[1];
|
||||
maxDist = maxDamageDistFromWarhead(lbs);#3*sqrt(lbs)
|
||||
@@ -436,15 +494,15 @@ var DamageRecipient =
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -455,7 +513,7 @@ var DamageRecipient =
|
||||
printf("Took %.1f%% damage from %s at %0.1f meters. %s systems was hit", percent,type,dist,failed);
|
||||
damageLog.push(sprintf("%s hit you with %s, %.1f meters distance.", notification.Callsign, type, dist));
|
||||
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,
|
||||
@@ -466,27 +524,27 @@ var DamageRecipient =
|
||||
# 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%
|
||||
}
|
||||
}
|
||||
}
|
||||
# }
|
||||
return emesary.Transmitter.ReceiptStatus_OK;
|
||||
}
|
||||
if (notification.NotificationType == "StaticNotification") {
|
||||
if(getprop("payload/armament/msg") == 0) {
|
||||
if(getprop("payload/armament/msg") == 0 and getprop("payload/armament/spectator") != 1) {
|
||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
if (notification.Kind == CREATE and getprop("payload/armament/enable-craters") == 1 and statics["obj_"~notification.UniqueIdentity] == nil) {
|
||||
@@ -606,7 +664,7 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.model = n.getChild("model", i, 1);
|
||||
|
||||
|
||||
n = props.globals.getNode("sim/emesary-models", 1);
|
||||
for (i = 0; 1==1; i += 1) {
|
||||
if (n.getChild("dynamic", i, 0) == nil) {
|
||||
@@ -614,9 +672,9 @@ var ModelManager = {
|
||||
}
|
||||
}
|
||||
m.ai = n.getChild("dynamic", i, 1);
|
||||
|
||||
|
||||
m.model.getNode("path", 1).setValue(path);
|
||||
|
||||
|
||||
# Create the AI position and orientation properties.
|
||||
m.lat = m.ai.getNode("position/latitude-deg", 1);
|
||||
m.lon = m.ai.getNode("position/longitude-deg", 1);
|
||||
@@ -624,14 +682,14 @@ var ModelManager = {
|
||||
m.heading= m.ai.getNode("orientation/true-heading-deg", 1);
|
||||
m.pitch = m.ai.getNode("orientation/pitch-deg", 1);
|
||||
m.roll = m.ai.getNode("orientation/roll-deg", 1);
|
||||
|
||||
|
||||
m.lat.setDoubleValue(lat);
|
||||
m.lon.setDoubleValue(lon);
|
||||
m.alt_ft.setDoubleValue(alt_ft);
|
||||
m.heading.setDoubleValue(heading);
|
||||
m.pitch.setDoubleValue(para?0:pitch);
|
||||
m.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
m.vLat = lat;
|
||||
m.vLon = lon;
|
||||
m.vAlt_ft = alt_ft;
|
||||
@@ -643,22 +701,22 @@ var ModelManager = {
|
||||
m.pAlt_ft = m.vAlt_ft;
|
||||
m.pHeading = m.vHeading;
|
||||
m.pPitch = m.vPitch;
|
||||
|
||||
|
||||
|
||||
|
||||
m.model.getNode("latitude-deg-prop", 1).setValue(m.lat.getPath());
|
||||
m.model.getNode("longitude-deg-prop", 1).setValue(m.lon.getPath());
|
||||
m.model.getNode("elevation-ft-prop", 1).setValue(m.alt_ft.getPath());
|
||||
m.model.getNode("heading-deg-prop", 1).setValue(m.heading.getPath());
|
||||
m.model.getNode("pitch-deg-prop", 1).setValue(m.pitch.getPath());
|
||||
m.model.getNode("roll-deg-prop", 1).setValue(m.roll.getPath());
|
||||
|
||||
|
||||
m.coord = geo.Coord.new();
|
||||
m.uBody_fps = 0;
|
||||
m.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
m.past = m.last;
|
||||
m.frametime = 0;
|
||||
m.delayTime = 0;
|
||||
|
||||
m.delayTime = 0;
|
||||
|
||||
return m;
|
||||
},
|
||||
moveRealtime: func (uBody_fps, dt, factor) {
|
||||
@@ -667,17 +725,17 @@ var ModelManager = {
|
||||
me.uBody_fps = uBody_fps;
|
||||
me.alt_dist = me.slant_ft*math.sin(me.vPitch*D2R);
|
||||
me.horiz_dist = me.slant_ft*math.cos(me.vPitch*D2R);
|
||||
|
||||
|
||||
me.coord.set_latlon(me.vLat, me.vLon, (me.vAlt_ft+me.alt_dist) * FT2M);
|
||||
|
||||
|
||||
me.coord = me.coord.apply_course_distance(me.vHeading, me.horiz_dist*FT2M);
|
||||
|
||||
|
||||
me.latlon = me.coord.latlon();
|
||||
|
||||
|
||||
me.vLat = me.latlon[0];
|
||||
me.vLon = me.latlon[1];
|
||||
me.vAlt_ft = me.latlon[2]*M2FT;
|
||||
|
||||
|
||||
me.lat.setDoubleValue(me.vLat);
|
||||
me.lon.setDoubleValue(me.vLon);
|
||||
me.alt_ft.setDoubleValue(me.vAlt_ft);
|
||||
@@ -710,20 +768,20 @@ var ModelManager = {
|
||||
translateDelayed: func (lat,lon,alt_ft,heading,pitch, para) {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
|
||||
|
||||
me.pLat = me.vLat;
|
||||
me.pLon = me.vLon;
|
||||
me.pAlt_ft = me.vAlt_ft;
|
||||
me.pHeading = me.vHeading;
|
||||
me.pPitch = me.vPitch;
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
me.vHeading = heading;
|
||||
me.vPitch = pitch;
|
||||
#me.vRoll = 0;
|
||||
|
||||
|
||||
me.past = me.last;
|
||||
me.last = [geo.Coord.new().set_latlon(lat,lon,alt_ft*FT2M).xyz(),systime()];
|
||||
me.delayTime = 0;
|
||||
@@ -736,7 +794,7 @@ var ModelManager = {
|
||||
me.heading.setDoubleValue(heading);
|
||||
me.pitch.setDoubleValue(para?0:pitch);
|
||||
#me.roll.setDoubleValue(0);
|
||||
|
||||
|
||||
me.vLat = lat;
|
||||
me.vLon = lon;
|
||||
me.vAlt_ft = alt_ft;
|
||||
@@ -810,7 +868,7 @@ var flare_sorter = func(a, b) {
|
||||
if(a[0] < b[0]){
|
||||
return -1; # A should before b in the returned vector
|
||||
}elsif(a[0] == b[0]){
|
||||
return 0; # A is equivalent to b
|
||||
return 0; # A is equivalent to b
|
||||
}else{
|
||||
return 1; # A should after b in the returned vector
|
||||
}
|
||||
@@ -818,9 +876,6 @@ var flare_sorter = func(a, b) {
|
||||
|
||||
var animate_flare = func {
|
||||
# Send out notifications about own flare positions every 0.4s
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
var stime = systime();
|
||||
# old flares
|
||||
var old_flares = [];
|
||||
@@ -838,6 +893,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
continue;
|
||||
}
|
||||
if (flares_sent < flares_max_process_per_loop) {
|
||||
@@ -846,7 +902,7 @@ var animate_flare = func {
|
||||
flare = [stime, flare[1], flare[2], flare[3], (flare[4]<flare_terminal_speed)?(flare[4]+flare_dt*9.83*0.5):(flare[4]-flare_dt*3), math.max(0,flare[5]-flare_dt*20), flare[6]];
|
||||
flare[2].apply_course_distance(flare[3], flare_dt*flare[5]);
|
||||
flare[2].set_alt(flare[2].alt()-flare_dt*flare[4]);
|
||||
|
||||
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
msg.Position = flare[2];
|
||||
@@ -857,6 +913,7 @@ var animate_flare = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
flares_sent += 1;
|
||||
}
|
||||
append(old_flares, flare);
|
||||
@@ -864,7 +921,7 @@ var animate_flare = func {
|
||||
flare_list = old_flares;
|
||||
if(auto_flare_caller) {
|
||||
auto_flare_released();
|
||||
}
|
||||
}
|
||||
}
|
||||
var flaretimer = maketimer(flare_update_time, animate_flare);
|
||||
flaretimer.start();
|
||||
@@ -881,9 +938,6 @@ var auto_flare_released = func {
|
||||
}
|
||||
|
||||
var flare_released = func {
|
||||
if (!getprop("payload/armament/msg")) {
|
||||
return;
|
||||
}
|
||||
# We released a flare. If you call this method manually, then make sure 'auto_flare_caller' is false.
|
||||
var stime = systime();
|
||||
var flare =[stime, stime,
|
||||
@@ -891,7 +945,7 @@ var flare_released = func {
|
||||
getprop("orientation/heading-deg"),
|
||||
FT2M*getprop("velocities/speed-down-fps"),
|
||||
FT2M*math.sqrt(getprop("velocities/speed-north-fps")*getprop("velocities/speed-north-fps")+getprop("velocities/speed-east-fps")*getprop("velocities/speed-east-fps")),
|
||||
int(rand()*200)-100];
|
||||
int(rand()*240)-120];
|
||||
append(flare_list, flare);
|
||||
var msg = notifications.ObjectInFlightNotification.new("ffly", flare[6], MOVE, 21+95);
|
||||
msg.Flags = 0;
|
||||
@@ -903,6 +957,30 @@ var flare_released = func {
|
||||
msg.Heading = 0;
|
||||
msg.u_fps = 0;
|
||||
notifications.objectBridgedTransmitter.NotifyAll(msg);
|
||||
recordOwnFlare(msg);
|
||||
}
|
||||
|
||||
var recordOwnFlare = func (msg) {
|
||||
if (tacview_supported) {
|
||||
if (tacview.starttime) {
|
||||
var tacID = left(md5("ownShip"~msg.UniqueIndex),6);
|
||||
if (msg.Kind == DESTROY) {
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",Visible=0\n-"~tacID~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
} else {
|
||||
var typp = "Flare";
|
||||
var extra = "";
|
||||
var extra2 = ",Type=Flare";
|
||||
var color = ",Color=Yellow";
|
||||
thread.lock(tacview.mutexWrite);
|
||||
tacview.write("#" ~ (systime() - tacview.starttime)~"\n");
|
||||
tacview.write(tacID~",T="~msg.Position.lon()~"|"~msg.Position.lat()~"|"~msg.Position.alt()~extra~",Name="~typp~color~extra2~"\n");
|
||||
thread.unlock(tacview.mutexWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#==================================================================
|
||||
@@ -917,11 +995,15 @@ setlistener("payload/armament/msg", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
setlistener("payload/armament/spectator", func {
|
||||
check_for_Request();
|
||||
},0,0);
|
||||
|
||||
var last_check = -65;
|
||||
|
||||
var check_for_Request = func {
|
||||
# This sends out a notification to ask other aircraft for all craters
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and getprop("payload/armament/msg") and systime()-last_check > 60) {
|
||||
if (getprop("payload/armament/enable-craters") == 1 and getprop("sim/multiplay/online") and (getprop("payload/armament/spectator") or getprop("payload/armament/msg")) and systime()-last_check > 60) {
|
||||
last_check = systime();
|
||||
var msg = notifications.StaticNotification.new("stat", int(rand()*15000000), REQUEST_ALL, 0);
|
||||
msg.IsDistinct = 0;
|
||||
@@ -1005,7 +1087,7 @@ var fail_systems = func (probability, factor = 100) {#this factor needs tuning a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
@@ -1039,7 +1121,7 @@ setlistener("/sim/signals/reinit", repairYasim);
|
||||
hp_f = [hp_max,hp_max,hp_max,hp_max,hp_max,hp_max,hp_max];
|
||||
|
||||
var fail_fleet_systems = func (probability, factor) {
|
||||
|
||||
|
||||
var sinking_ships = (hp_f[0]<0) + (hp_f[1]<0) + (hp_f[2]<0) + (hp_f[3]<0) + (hp_f[4]<0) + (hp_f[5]<0) + (hp_f[6]<0);
|
||||
var hit_sinking = 0;
|
||||
if (sinking_ships == 0) {
|
||||
@@ -1053,9 +1135,9 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("You shot one of our already sinking ships, you are just mean.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var no = 0;
|
||||
|
||||
|
||||
for (no=0; no < 7; no+=1) {
|
||||
if (hp_f[no] > 0) {
|
||||
break;
|
||||
@@ -1078,7 +1160,7 @@ var fail_fleet_systems = func (probability, factor) {
|
||||
armament.defeatSpamFilter("S.O.S. Heeelp");
|
||||
} else {
|
||||
armament.defeatSpamFilter("This is not over yet..");
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
@@ -1137,12 +1219,19 @@ var getCallsign = func (callsign) {
|
||||
|
||||
var MAW_elapsed = 0;
|
||||
|
||||
var radarSpikes = {};
|
||||
|
||||
foreach (key ; keys(radar_signatures)) {
|
||||
radarSpikes[radar_signatures[key]] = 0;
|
||||
}
|
||||
|
||||
var processCallsigns = func () {
|
||||
callsign_struct = {};
|
||||
var players = props.globals.getNode("ai/models").getChildren();
|
||||
var myCallsign = getprop("sim/multiplay/callsign");
|
||||
myCallsign = size(myCallsign) < 8 ? myCallsign : left(myCallsign,7);
|
||||
var painted = 0;
|
||||
var paint_list = [];
|
||||
foreach (var player; players) {
|
||||
if(player.getChild("valid") != nil and player.getChild("valid").getValue() == TRUE and player.getChild("callsign") != nil and player.getChild("callsign").getValue() != "" and player.getChild("callsign").getValue() != nil) {
|
||||
var callsign = player.getChild("callsign").getValue();
|
||||
@@ -1150,14 +1239,49 @@ var processCallsigns = func () {
|
||||
var str6 = player.getNode("sim/multiplay/generic/string[6]");
|
||||
if (str6 != nil and str6.getValue() != nil and str6.getValue() != "" and size(""~str6.getValue())==4 and left(md5(myCallsign),4) == str6.getValue()) {
|
||||
painted = 1;
|
||||
if (rwr_audio_extended) {
|
||||
append(paint_list, getModel(player.getNode("sim/model/path")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (getprop("sim/time/elapsed-sec")-MAW_elapsed > 1.1) {
|
||||
setprop("payload/armament/MAW-active", 0);# resets every 1.1 seconds without warning
|
||||
}
|
||||
|
||||
# spike handling:
|
||||
setprop("payload/armament/spike", painted);
|
||||
if (!rwr_audio_extended) return;
|
||||
var roundSpike = rand();
|
||||
foreach (var radarModel ; paint_list) {
|
||||
var ref = radar_signatures[radarModel];
|
||||
if (ref != nil) {
|
||||
radarSpikes[ref] = roundSpike;
|
||||
}
|
||||
}
|
||||
foreach(key ; keys(radarSpikes)) {
|
||||
if (radarSpikes[key] == roundSpike) {
|
||||
setprop("payload/armament/spike-"~key, 1);
|
||||
} else {
|
||||
setprop("payload/armament/spike-"~key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
var remove_suffix = func(str, suffix) {
|
||||
var len = size(suffix);
|
||||
if (substr(str, -len) == suffix) return substr(str, 0, size(str) - len);
|
||||
else return str;
|
||||
};
|
||||
var getModel = func (node) {
|
||||
if (node == nil) return "unknown-model";
|
||||
var value = node.getValue();
|
||||
if (value == nil or value == "") return "";
|
||||
var model = split(".", split("/", value)[-1])[0];
|
||||
model = remove_suffix(model, "-model");
|
||||
model = remove_suffix(model, "-anim");
|
||||
return model;
|
||||
}
|
||||
|
||||
processCallsignsTimer = maketimer(1.5, processCallsigns);
|
||||
processCallsignsTimer.simulatedTime = 1;
|
||||
processCallsignsTimer.start();
|
||||
@@ -1176,16 +1300,17 @@ var code_ct = func () {
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "WeightAndFuel"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "system-failures"}))},nil,var err2 = []);
|
||||
call(func{fgcommand('dialog-close', props.Node.new({"dialog-name": "instrument-failures"}))},nil,var err2 = []);
|
||||
}
|
||||
}
|
||||
setprop("sim/freeze/fuel",0);
|
||||
setprop("/sim/speed-up", 1);
|
||||
setprop("/gui/map/draw-traffic", 0);
|
||||
setprop("/sim/marker-pins/traffic", 0);
|
||||
setprop("/sim/gui/dialogs/map-canvas/draw-TFC", 0);
|
||||
#fgcommand("timeofday", props.Node.new({"timeofday": "real"}));
|
||||
#setprop("/sim/rendering/als-filters/use-filtering", 1);
|
||||
call(func{var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance();
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
interfaceController.stop();},nil,var err2=[]);
|
||||
}
|
||||
}
|
||||
code_ctTimer = maketimer(1, code_ct);
|
||||
code_ctTimer.simulatedTime = 1;
|
||||
@@ -1203,13 +1328,14 @@ code_ctTimer.start();
|
||||
var re_init = func (node) {
|
||||
# repair the aircraft
|
||||
if (node.getValue() == 0) return;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
stopLaunch();
|
||||
damageLog.push("Aircraft was repaired due to re-init.");
|
||||
}
|
||||
|
||||
@@ -1282,4 +1408,11 @@ setlistener("sim/signals/exit", writeDamageLog, 0, 0);
|
||||
#screen.property_display.add("payload/armament/MLW-bearing");
|
||||
#screen.property_display.add("payload/armament/MLW-count");
|
||||
#screen.property_display.add("payload/armament/MLW-launcher");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike");
|
||||
#screen.property_display.add("payload/armament/spike-air");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-20");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-02");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-11");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-23");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-p2");
|
||||
#screen.property_display.add("payload/armament/spike-gnd-nk");
|
||||
@@ -2,7 +2,7 @@ var Math = {
|
||||
#
|
||||
# Authors: Nikolai V. Chr, Axel Paccalin.
|
||||
#
|
||||
# Version 1.93
|
||||
# Version 2.01
|
||||
#
|
||||
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
|
||||
# FG struct. coords: +x = back, +y = right, +z = up.
|
||||
@@ -13,6 +13,8 @@ var Math = {
|
||||
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
|
||||
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
|
||||
#
|
||||
# Cartesian is right-handed coord system.
|
||||
#
|
||||
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
|
||||
|
||||
convertCoords: func (x,y,z) {
|
||||
@@ -37,14 +39,16 @@ var Math = {
|
||||
me.upamount = -me.end_dist_m;
|
||||
}
|
||||
me.tgt_coord.set_alt(coord.alt()+me.upamount);
|
||||
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
|
||||
me.geoVeccy = me.product(me.magnitudeVector(a), me.normalize([me.tgt_coord.x()-coord.x(),me.tgt_coord.y()-coord.y(),me.tgt_coord.z()-coord.z()]));
|
||||
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z(), "vector": me.geoVeccy};
|
||||
},
|
||||
|
||||
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
|
||||
#
|
||||
# Warning: If you input body velocities in fps the output will be in fps also. Likewise for mps.
|
||||
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
|
||||
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
|
||||
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
|
||||
return me.rollPitchYawVector(roll_deg, pitch_deg, yaw_deg, me.bodyVelocity);
|
||||
},
|
||||
|
||||
# angle between 2 vectors. Returns 0-180 degrees.
|
||||
@@ -55,9 +59,27 @@ var Math = {
|
||||
return R2D * math.acos(me.value);
|
||||
},
|
||||
|
||||
# Rodrigues' rotation formula. Use unitVectorAxis as axis, and rotate around it.
|
||||
rotateVectorAroundVector: func (a, unitVectorAxis, angle) {
|
||||
return me.plus(
|
||||
me.plus(
|
||||
me.product(math.cos(angle*D2R),a),
|
||||
me.product(math.sin(angle*D2R), me.crossProduct(unitVectorAxis,a))
|
||||
),
|
||||
me.product((1-math.cos(angle*D2R))*me.dotProduct(unitVectorAxis,a), unitVectorAxis)
|
||||
);
|
||||
},
|
||||
|
||||
#Rotate a certain amound of degrees towards 'towardsMe'.
|
||||
rotateVectorTowardsVector: func (a, towardsMe, angle) {
|
||||
return me.rotateVectorAroundVector(a, me.normalize(me.crossProduct(a, towardsMe)), angle);
|
||||
},
|
||||
|
||||
# length of vector
|
||||
magnitudeVector: func (a) {
|
||||
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
|
||||
me.mag = 1;
|
||||
call(func {me.mag = math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2))},nil,nil,var err =[]);#strange bug in Nasal can sometimes mess up sqrt
|
||||
return me.mag;
|
||||
},
|
||||
|
||||
# dot product of 2 vectors
|
||||
@@ -65,8 +87,20 @@ var Math = {
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
|
||||
},
|
||||
|
||||
# rotate a vector. Order: roll, pitch, yaw
|
||||
# rotate a vector. Order: roll, pitch, yaw (same as aircraft)
|
||||
#
|
||||
# The coordinate system is fixed during all the rolls.
|
||||
#
|
||||
rollPitchYawVector: func (roll, pitch, yaw, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (reverse of aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
@@ -74,15 +108,34 @@ var Math = {
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
|
||||
yawPitchRollVector: func (yaw, pitch, roll, vector) {
|
||||
me.rollM = me.rollMatrix(roll);
|
||||
# rotate a vector. Order: yaw, pitch
|
||||
yawPitchVector: func (yaw, pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
|
||||
me.rotation = me.multiplyMatrices(me.pitchM, me.yawM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch, yaw
|
||||
pitchYawVector: func (pitch, yaw, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
me.rotation = me.multiplyMatrices(me.yawM, me.pitchM);
|
||||
return me.multiplyMatrixWithVector(me.rotation, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: yaw
|
||||
yawVector: func (yaw, vector) {
|
||||
me.yawM = me.yawMatrix(yaw);
|
||||
return me.multiplyMatrixWithVector(me.yawM, vector);
|
||||
},
|
||||
|
||||
# rotate a vector. Order: pitch
|
||||
pitchVector: func (pitch, vector) {
|
||||
me.pitchM = me.pitchMatrix(pitch);
|
||||
return me.multiplyMatrixWithVector(me.pitchM, vector);
|
||||
},
|
||||
|
||||
# multiply 3x3 matrix with vector
|
||||
multiplyMatrixWithVector: func (matrix, vector) {
|
||||
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
|
||||
@@ -107,10 +160,10 @@ var Math = {
|
||||
|
||||
# matrix for pitching
|
||||
pitchMatrix: func (pitch) {
|
||||
pitch = pitch * D2R;
|
||||
return [math.cos(pitch),0,-math.sin(pitch),
|
||||
pitch = -pitch * D2R;
|
||||
return [math.cos(pitch),0,math.sin(pitch),
|
||||
0,1,0,
|
||||
math.sin(pitch),0,math.cos(pitch)];
|
||||
-math.sin(pitch),0,math.cos(pitch)];
|
||||
},
|
||||
|
||||
# matrix for yawing
|
||||
@@ -126,7 +179,8 @@ var Math = {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
@@ -144,6 +198,39 @@ var Math = {
|
||||
return [me.hdg, me.pitch];
|
||||
},
|
||||
|
||||
# vector to pitch
|
||||
cartesianToEulerPitch: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.pitch = math.atan2(vector[2],me.horz)*R2D;
|
||||
} else {
|
||||
me.pitch = vector[2]>=0?90:-90;
|
||||
}
|
||||
return me.pitch;
|
||||
},
|
||||
|
||||
# vector to heading
|
||||
cartesianToEulerHeading: func (vector) {
|
||||
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
||||
if (me.horz != 0) {
|
||||
me.div = math.clamp(-vector[1]/me.horz, -1, 1);
|
||||
me.hdg = math.asin(me.div)*R2D;
|
||||
|
||||
if (vector[0] < 0) {
|
||||
# south
|
||||
if (me.hdg >= 0) {
|
||||
me.hdg = 180-me.hdg;
|
||||
} else {
|
||||
me.hdg = -180-me.hdg;
|
||||
}
|
||||
}
|
||||
me.hdg = geo.normdeg(me.hdg);
|
||||
} else {
|
||||
me.hdg = 0;
|
||||
}
|
||||
return me.hdg;
|
||||
},
|
||||
|
||||
# gives an vector that points up from fuselage
|
||||
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
|
||||
me.yaw = yaw_deg * D2R;
|
||||
@@ -242,8 +329,22 @@ var Math = {
|
||||
|
||||
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
|
||||
projVectorOnPlane: func (planeNormal, vector) {
|
||||
if (me.magnitudeVector(planeNormal) == 0) return [0,0,0];#safety
|
||||
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
|
||||
},
|
||||
|
||||
# Project a onto ontoMe.
|
||||
projVectorOnVector: func (a, ontoMe) {
|
||||
if (me.magnitudeVector(ontoMe) == 0) return [0,0,0];#safety
|
||||
return me.product(me.dotProduct(a,ontoMe)/me.dotProduct(ontoMe,ontoMe), ontoMe);
|
||||
},
|
||||
|
||||
# Project a onto ontoMe and measure how long along ontoMe it goes, opposite will give negative number.
|
||||
scalarProjVectorOnVector: func (a, ontoMe) {
|
||||
me.ontoMeMag = me.magnitudeVector(ontoMe);
|
||||
if (me.ontoMeMag == 0) return 0;
|
||||
return me.dotProduct(a,ontoMe)/me.ontoMeMag;
|
||||
},
|
||||
|
||||
# unary - vector
|
||||
opposite: func (v){
|
||||
@@ -268,7 +369,7 @@ var Math = {
|
||||
|
||||
# print vector to console
|
||||
format: func (v) {
|
||||
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
|
||||
return sprintf("(%.2f, %.2f, %.2f)",v[0],v[1],v[2]);
|
||||
},
|
||||
|
||||
# make vector length 1.0
|
||||
@@ -288,6 +389,20 @@ var Math = {
|
||||
|
||||
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
|
||||
},
|
||||
|
||||
interpolateVector: func (start, end, fraction) {
|
||||
me.xx = (start[0]*(1-fraction) +end[0]*fraction);
|
||||
me.yy = (start[1]*(1-fraction) +end[1]*fraction);
|
||||
me.zz = (start[2]*(1-fraction) +end[2]*fraction);
|
||||
|
||||
return [me.xx, me.yy, me.zz];
|
||||
},
|
||||
|
||||
# move distance 'along' from start towards end. Total dist from start to end is dist.
|
||||
alongVector: func (start, end, dist, along) {
|
||||
me.fraction = along/dist;
|
||||
return me.interpolateVector(start, end, me.fraction);
|
||||
},
|
||||
|
||||
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
|
||||
orthogonalProjection: func(vec, ref){
|
||||
@@ -319,9 +434,9 @@ var Math = {
|
||||
#| 0 cos(roll) -sin(roll) |
|
||||
#| 0 sin(roll) cos(roll) |
|
||||
#
|
||||
#| cos(pitch) 0 -sin(pitch) |
|
||||
#| 0 1 0 |
|
||||
#| sin(pitch) 0 cos(pitch) |
|
||||
#| cos(-pitch) 0 sin(-pitch) |
|
||||
#| 0 1 0 |
|
||||
#| -sin(-pitch) 0 cos(-pitch) |
|
||||
#
|
||||
#| cos(yaw) -sin(yaw) 0 |
|
||||
#| sin(yaw) cos(yaw) 0 |
|
||||
@@ -336,3 +451,32 @@ var Math = {
|
||||
#
|
||||
|
||||
};
|
||||
|
||||
|
||||
var unitTest = {
|
||||
start: func {
|
||||
# 1: Simple test of rotation matrices and getting the input back in another way.
|
||||
var localDir = Math.pitchYawVector(-40, -75, [1,0,0]);
|
||||
me.eulerDir = Math.cartesianToEuler(localDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 75 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 2: Revert part of test #1
|
||||
var forwardDir = Math.yawPitchVector(75, 0, localDir);
|
||||
me.eulerDir = Math.cartesianToEuler(forwardDir);
|
||||
me.eulerDir[0] = me.eulerDir[0]==nil?0:geo.normdeg(me.eulerDir[0]);
|
||||
printf("Looking out of aircraft window at heading 0 and 40 degs down: %.4f heading %.4f pitch.",me.eulerDir[0],me.eulerDir[1]);
|
||||
# 3: Tougher test, try it different places on earth since earth is not sphere. At KXTA runway it gives 0.03% error in pitch.
|
||||
var someDir = Math.eulerToCartesian3X(-75, -40, 20);
|
||||
var myCoord = geo.aircraft_position();
|
||||
me.thousandVectorGeo = Math.vectorToGeoVector(someDir, myCoord).vector;# does not return magnitude with meaning, only its direction matters.
|
||||
me.thousandVectorGeo = Math.normalize(me.thousandVectorGeo);
|
||||
me.thousandVectorGeo = Math.product(100000, me.thousandVectorGeo);
|
||||
me.lookAt = geo.Coord.new().set_xyz(myCoord.x()+me.thousandVectorGeo[0], myCoord.y()+me.thousandVectorGeo[1], myCoord.z()+me.thousandVectorGeo[2]);
|
||||
printf("Looking out of aircraft window 100000m away heading 75 and 40 degs down: %.4f heading %.4f pitch %.4f meter.", myCoord.course_to(me.lookAt), Math.getPitch(myCoord, me.lookAt), myCoord.direct_distance_to(me.lookAt));
|
||||
# 4:
|
||||
var aircraft = Math.eulerToCartesian3X(-35, 72, 21);
|
||||
var aircraft2 = Math.rollPitchYawVector(21, 72, -35, [1,0,0]);
|
||||
printf("These two should be the same %s = %s",Math.format(aircraft),Math.format(aircraft2));
|
||||
},
|
||||
};
|
||||
#unitTest.start();
|
||||
@@ -59,7 +59,7 @@
|
||||
</carrier>
|
||||
|
||||
<sim include="Sim/views.xml">
|
||||
<author>pinto and onox</author>
|
||||
<author>pinto, Nikolai V. Chr., onox</author>
|
||||
<description>Missile Frigate</description>
|
||||
<status>alpha</status>
|
||||
<aircraft-version>0.1</aircraft-version>
|
||||
@@ -97,6 +97,36 @@
|
||||
|
||||
<chase-distance-m type="double" archive="y">-500.0</chase-distance-m>
|
||||
|
||||
<view n="200">
|
||||
<name>Follow</name>
|
||||
<type>lookat</type>
|
||||
<internal>false</internal>
|
||||
<config>
|
||||
<!--<from-model type="bool">true</from-model>
|
||||
<from-model-idx type="int">0</from-model-idx>-->
|
||||
<eye-fixed type="bool">true</eye-fixed>
|
||||
<target-lat-deg-path>rotors/main/blade[0]/flap-deg</target-lat-deg-path>
|
||||
<target-lon-deg-path>rotors/main/blade[1]/flap-deg</target-lon-deg-path>
|
||||
<target-alt-ft-path>rotors/main/blade[2]/position-deg</target-alt-ft-path>
|
||||
<eye-lat-deg-path>/position/latitude-deg</eye-lat-deg-path>
|
||||
<eye-lon-deg-path>/position/longitude-deg</eye-lon-deg-path>
|
||||
<eye-alt-ft-path>/position/altitude-ft</eye-alt-ft-path>
|
||||
<!--<eye-heading-deg-path>/orientation/heading-deg</eye-heading-deg-path>
|
||||
<eye-pitch-deg-path>/orientation/pitch-deg</eye-pitch-deg-path>
|
||||
<eye-roll-deg-path>/orientation/roll-deg</eye-roll-deg-path>-->
|
||||
<eye-heading-deg-path>/orientation/heading-deg</eye-heading-deg-path>
|
||||
<eye-pitch-deg>0</eye-pitch-deg>
|
||||
<eye-roll-deg>0</eye-roll-deg>
|
||||
<x-offset-m>50</x-offset-m>
|
||||
<y-offset-m>50</y-offset-m>
|
||||
<z-offset-m>25</z-offset-m>
|
||||
<default-field-of-view-deg>70</default-field-of-view-deg>
|
||||
<limits>
|
||||
<enabled type="bool">false</enabled>
|
||||
</limits>
|
||||
</config>
|
||||
</view>
|
||||
|
||||
<hud>
|
||||
<path n="1">Aircraft/missile-frigate/Hud/hud.xml</path>
|
||||
<visibility n="1">true</visibility>
|
||||
@@ -116,15 +146,16 @@
|
||||
<path>Aircraft/missile-frigate/autopilot.xml</path>
|
||||
</autopilot>
|
||||
|
||||
<property-rule n="100">
|
||||
<!--property-rule n="100">
|
||||
<path>Systems/views.xml</path>
|
||||
</property-rule>
|
||||
</property-rule-->
|
||||
</systems>
|
||||
<multiplay>
|
||||
<generic>
|
||||
<int n="0" alias="/carrier/sunk"/>
|
||||
<int n="2" type="int">0</int>
|
||||
<string n="6" type="string"></string><!-- string 6 used by radar lock RWR warning -->
|
||||
<string n="7" type="string"></string><!-- datalink -->
|
||||
</generic>
|
||||
</multiplay>
|
||||
<menubar>
|
||||
@@ -132,23 +163,7 @@
|
||||
<menu n="100">
|
||||
<label>Missile-frigate</label>
|
||||
<enabled type="bool">true</enabled>
|
||||
<item>
|
||||
<label>Reload</label>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
<script>
|
||||
fire_control.reload();
|
||||
</script>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Targets</label>
|
||||
<name>enemies</name>
|
||||
<binding>
|
||||
<command>dialog-show</command>
|
||||
<dialog-name>enemies</dialog-name>
|
||||
</binding>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<label>Event Log</label>
|
||||
<binding>
|
||||
@@ -262,9 +277,33 @@
|
||||
<lbs>50</lbs>
|
||||
</opt>
|
||||
</weight>
|
||||
|
||||
<d-config>
|
||||
<full_damage_dist_m type="double">20</full_damage_dist_m>
|
||||
<use_hitpoints_instead_of_failure_modes_bool type="bool">true</use_hitpoints_instead_of_failure_modes_bool>
|
||||
<hp_max type="double">200</hp_max>
|
||||
<hitable_by_air_munitions type="bool">false</hitable_by_air_munitions>
|
||||
<hitable_by_cannon type="bool">true</hitable_by_cannon>
|
||||
<is_fleet type="bool">false</is_fleet>
|
||||
<rwr_to_screen type="bool">false</rwr_to_screen>
|
||||
<rwr_audio_extended type="bool">false</rwr_audio_extended>
|
||||
<tacview_supported type="bool">false</tacview_supported>
|
||||
<m28_auto type="bool">false</m28_auto>
|
||||
<mlw_max type="double">2.25</mlw_max>
|
||||
<auto_flare_caller type="bool">false</auto_flare_caller>
|
||||
</d-config>
|
||||
<armament>
|
||||
<models type="string">Aircraft/missile-frigate/Models/Armament/Weapons/</models>
|
||||
<modelsUseCase type="bool">true</modelsUseCase>
|
||||
<modelsUpperCase type="bool">true</modelsUpperCase>
|
||||
<MP-lat type="string">rotors/main/blade[0]/flap-deg</MP-lat>
|
||||
<MP-lon type="string">rotors/main/blade[1]/flap-deg</MP-lon>
|
||||
<MP-alt type="string">rotors/main/blade[2]/flap-deg</MP-alt>
|
||||
<MP-alt-ft type="string">rotors/main/blade[2]/position-deg</MP-alt-ft>
|
||||
<hit-interpolation type="bool">true</hit-interpolation>
|
||||
<gnd-launch type="bool">true</gnd-launch>
|
||||
<pylon-offset type="int">1</pylon-offset>
|
||||
<pylon-stations>controls/armament</pylon-stations>
|
||||
<station-name type="string">station</station-name>
|
||||
<msg type="bool">true</msg>
|
||||
<damage type="bool">true</damage>
|
||||
<enable-craters type="bool">true</enable-craters>
|
||||
@@ -287,23 +326,27 @@
|
||||
</blade>
|
||||
<blade n="2">
|
||||
<flap-deg type="double">0</flap-deg>
|
||||
<position-deg type="double">0</position-deg>
|
||||
</blade>
|
||||
</main>
|
||||
</rotors>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">Leto</e1>
|
||||
<e2 userarchive="y" type="string">swamp</e2>
|
||||
<e3 userarchive="y" type="string">pinto</e3>
|
||||
<e4 userarchive="y" type="string">fb237</e4>
|
||||
<e5 userarchive="y" type="string">Wilco-1</e5>
|
||||
<e6 userarchive="y" type="string">Kokos</e6>
|
||||
<e7 userarchive="y" type="string">J-Mav16</e7>
|
||||
<e8 userarchive="y" type="string">S</e8>
|
||||
<e9 userarchive="y" type="string">Raider1</e9>
|
||||
<e10 userarchive="y" type="string">Slobb</e10>
|
||||
<e11 userarchive="y" type="string">5H1N0B1</e11>
|
||||
<e12 userarchive="y" type="string">SNOWY1</e12>
|
||||
<priority type="int">0</priority>
|
||||
<priority0 type="int">1</priority0>
|
||||
|
||||
<enemies>
|
||||
<e1 userarchive="y" type="string">target1</e1>
|
||||
<e2 userarchive="y" type="string">target2</e2>
|
||||
<e3 userarchive="y" type="string">target3</e3>
|
||||
<e4 userarchive="y" type="string">target4</e4>
|
||||
<e5 userarchive="y" type="string">target5</e5>
|
||||
<e6 userarchive="y" type="string">target6</e6>
|
||||
<e7 userarchive="y" type="string">target7</e7>
|
||||
<e8 userarchive="y" type="string">target8</e8>
|
||||
<e9 userarchive="y" type="string">target9</e9>
|
||||
<e10 userarchive="y" type="string">targetA</e10>
|
||||
<e11 userarchive="y" type="string">targetB</e11>
|
||||
<e12 userarchive="y" type="string">targetC</e12>
|
||||
</enemies>
|
||||
|
||||
<sam>
|
||||
@@ -353,8 +396,8 @@
|
||||
</fire_control>
|
||||
</nasal>
|
||||
|
||||
<input>
|
||||
<!--input>
|
||||
<mice include="Sim/mice.xml"/>
|
||||
</input>
|
||||
</input-->
|
||||
|
||||
</PropertyList>
|
||||
|
||||
Reference in New Issue
Block a user