Add GCI radar

This commit is contained in:
Justin Nicholson 2018-11-03 21:16:51 -07:00
parent bbba81a080
commit 75a3133d83
22 changed files with 4170 additions and 1228 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
<PropertyList>
<path>towerSnowy1.ac</path>
<path>gci-tower.ac</path>
<model>
<path>Aircraft/tower/Models/smoke.xml</path>

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

285
gci-radar/Nasal/damage.nas Normal file
View File

@ -0,0 +1,285 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
var TRUE = 1;
var FALSE = 0;
var hp = 80;
var hp_max = hp;
var cannon_types = {
" M70 rocket hit": 0.25, #135mm
" M55 cannon shell hit": 0.10, # 30mm
" KCA cannon shell hit": 0.10, # 30mm
" Gun Splash On ": 0.10, # 30mm
" M61A1 shell hit": 0.05, # 20mm
" GAU-8/A hit": 0.10, # 30mm
" BK27 cannon hit": 0.07, # 27mm
" GSh-30 hit": 0.10, # 30mm
" GSh-23 hit": 0.065,# 23mm
" 7.62 hit": 0.005,# 7.62mm
" 50 BMG hit": 0.015,# 12.7mm
" S-5 rocket hit": 0.20, #55mm
};
var warhead_lbs = {
"AGM-65": 126.00,
"AGM-84": 488.00,
"AGM-88": 146.00,
"AGM65": 200.00,
"ALARM": 450.00,
"AM39-Exocet": 364.00,
"AS-37-Martel": 330.00,
"AS30L": 529.00,
"Exocet": 364.00,
"FAB-100": 92.59,
"FAB-250": 202.85,
"FAB-500": 564.38,
"GBU-12": 190.00,
"GBU-24": 945.00,
"GBU-31": 945.00,
"GBU12": 190.00,
"GBU16": 450.00,
"HVAR": 7.50,#P51
"KAB-500": 564.38,
"Kh-25MP": 197.53,
"Kh-66": 244.71,
"KN-06": 315.00,
"LAU-68": 10.00,
"M317": 145.00,
"M71": 200.00,
"M71R": 200.00,
"M90": 500.00,
"MK-82": 192.00,
"MK-83": 445.00,
"MK-84": 945.00,
"OFAB-100": 92.59,
"RB-04E": 661.00,
"RB-05A": 353.00,
"RB-15F": 440.92,
"RB-75": 126.00,
"RN-14T": 800.00, #fictional, thermobaeric replacement for the RN-24 nuclear bomb
"RN-18T": 1200.00, #fictional, thermobaeric replacement for the RN-28 nuclear bomb
"RS-2US": 28.66,
"S-21": 245.00,
"S-24": 271.00,
"S530D": 66.00,
"SCALP": 992.00,
"Sea Eagle": 505.00,
"SeaEagle": 505.00,
"STORMSHADOW": 850.00,
"ZB-250": 236.99,
"ZB-500": 473.99,
};
var incoming_listener = func {
var history = getprop("/sim/multiplay/chat-history");
var hist_vector = split("\n", history);
if (size(hist_vector) > 0) {
var last = hist_vector[size(hist_vector)-1];
var last_vector = split(":", last);
var author = last_vector[0];
var callsign = getprop("sim/multiplay/callsign");
if (size(last_vector) > 1 and author != callsign) {
# not myself
#print("not me");
var m2000 = FALSE;
if (find(" at " ~ callsign ~ ". Release ", last_vector[1]) != -1) {
# a m2000 is firing at us
m2000 = TRUE;
}
if (last_vector[1] == " FOX2 at" or last_vector[1] == " aim7 at" or last_vector[1] == " aim9 at"
or last_vector[1] == " aim120 at" or last_vector[1] == " RB-24J fired at" or last_vector[1] == " RB-74 fired at"
or last_vector[1] == " RB-71 fired at" or last_vector[1] == " RB-15F fired at"
or last_vector[1] == " RB-99 fired at" or m2000 == TRUE) {
# air2air being fired
if (size(last_vector) > 2 or m2000 == TRUE) {
#print("Missile launch detected at"~last_vector[2]~" from "~author);
if (m2000 == TRUE or last_vector[2] == " "~callsign) {
# its being fired at me
#print("Incoming!");
var enemy = getCallsign(author);
if (enemy != nil) {
#print("enemy identified");
var bearingNode = enemy.getNode("radar/bearing-deg");
if (bearingNode != nil) {
#print("bearing to enemy found");
var bearing = bearingNode.getValue();
var heading = getprop("orientation/heading-deg");
var clock = bearing - heading;
while(clock < 0) {
clock = clock + 360;
}
while(clock > 360) {
clock = clock - 360;
}
#print("incoming from "~clock);
if (clock >= 345 or clock < 15) {
playIncomingSound("12");
} elsif (clock >= 15 and clock < 45) {
playIncomingSound("1");
} elsif (clock >= 45 and clock < 75) {
playIncomingSound("2");
} elsif (clock >= 75 and clock < 105) {
playIncomingSound("3");
} elsif (clock >= 105 and clock < 135) {
playIncomingSound("4");
} elsif (clock >= 135 and clock < 165) {
playIncomingSound("5");
} elsif (clock >= 165 and clock < 195) {
playIncomingSound("6");
} elsif (clock >= 195 and clock < 225) {
playIncomingSound("7");
} elsif (clock >= 225 and clock < 255) {
playIncomingSound("8");
} elsif (clock >= 255 and clock < 285) {
playIncomingSound("9");
} elsif (clock >= 285 and clock < 315) {
playIncomingSound("10");
} elsif (clock >= 315 and clock < 345) {
playIncomingSound("11");
} else {
playIncomingSound("");
}
return;
}
}
}
}
} elsif (1 == 1) { # mirage: getprop("/controls/armament/mp-messaging")
# latest version of failure manager and taking damage enabled
#print("damage enabled");
var last1 = split(" ", last_vector[1]);
if(size(last1) > 2 and last1[size(last1)-1] == "exploded" ) {
#print("missile hitting someone");
if (size(last_vector) > 3 and last_vector[3] == " "~callsign) {
#print("that someone is me!");
var type = last1[1];
if (type == "Matra" or type == "Sea") {
for (var i = 2; i < size(last1)-1; i += 1) {
type = type~" "~last1[i];
}
}
var number = split(" ", last_vector[2]);
var distance = num(number[1]);
#print(type~"|");
if(distance != nil) {
var dist = distance;
#check distance w/ if statement here
if (contains(warhead_lbs, type)) {
#maxDist = maxDamageDistFromWarhead(warhead_lbs[type]);
} else {
return;
}
if (type == "M90" and distance < 300) {
var failed = fail_systems(warhead_lbs[type]/2);
return;
} elsif (distance < 150) {
var prob = 1;
if ( distance > 50 ) {
distance = distance - 50;
prob = 1 - (distance/100);
}
}
var failed = fail_systems(warhead_lbs[type] * prob);
#ar percent = 100 * probability;
#printf("Took %.1f%% damage from %s missile at %0.1f meters. %s systems was hit", percent,type,dist,failed);
}
}
} elsif (cannon_types[last_vector[1]] != nil) {
# cannon hitting someone
print("cannon");
if (size(last_vector) > 2 and last_vector[2] == " "~callsign) {
print("cannon hit us");
var last3 = split(" ", last_vector[3]);
#print("last3[2]: " ~ last3[2]);
#print("last3[1]: " ~ last3[1]);
if(size(last3) > 2) {
if ( last3[2] == "hits" ) {
var hit_count = num(last3[1]);
}
} else {
var hit_count = 4;
}
var damaged_sys = 0;
var probability = cannon_types[last_vector[1]];
for (var i = 1; i <= hit_count; i = i + 1) {
var failed = fail_systems(probability);
damaged_sys = damaged_sys + failed;
}
# that someone is me!
#print("hitting me");
printf("Took %.1f%% damage from cannon! %s systems was hit.", probability*hit_count*100, damaged_sys);
}
}
}
}
}
}
var maxDamageDistFromWarhead = func (lbs) {
# very simple
var dist = 7*math.sqrt(lbs);
return dist;
}
var fail_systems = func (damage) {
hp = hp - damage;
print("HP: " ~ hp ~ "/" ~ hp_max);
if ( hp < 0 ) {
setprop("/carrier/sunk/",1);
setprop("/sim/multiplay/generic/int[0]",1);
}
};
var playIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 1);
settimer(func {stopIncomingSound(clock);},3);
}
var stopIncomingSound = func (clock) {
setprop("sound/incoming"~clock, 0);
}
var callsign_struct = {};
var getCallsign = func (callsign) {
var node = callsign_struct[callsign];
return node;
}
var processCallsigns = func () {
callsign_struct = {};
var players = props.globals.getNode("ai/models").getChildren();
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();
callsign_struct[callsign] = player;
}
}
settimer(processCallsigns, 1.5);
}
processCallsigns();
var logTime = func{
#log time and date for outputing ucsv files for converting into KML files for google earth.
if (getprop("logging/log[0]/enabled") == TRUE and getprop("sim/time/utc/year") != nil) {
var date = getprop("sim/time/utc/year")~"/"~getprop("sim/time/utc/month")~"/"~getprop("sim/time/utc/day");
var time = getprop("sim/time/utc/hour")~":"~getprop("sim/time/utc/minute")~":"~getprop("sim/time/utc/second");
setprop("logging/date-log", date);
setprop("logging/time-log", time);
}
}
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);

498
gci-radar/Nasal/gci.nas Normal file
View File

@ -0,0 +1,498 @@
# (c) 2018 pinto
# license: gplv2+
# v0.1 - just a very basic proof of concept at this point.
# will only report the closest bad guy, does no threat assessment.
# todo:
# test
# toggle radar on/off
# all the other requests that a gci can do (only handles BRAA right now)
##########################################
### Variables
##########################################
# prop_watch is a mp[x] boolean property set by that aircraft designer. the plane sets this to 1 when it wants to receive BRAA
# if the plane is not on the enemy list, and is one of the first ~10 to
# request a BRAA, then it will receive it.
var damage_prop = props.globals.getNode("/carrier/sunk");
var prop_watch = {
"MiG-21bis": [0,1,2],
"MiG-21MF-75": [0,1,2],
"QF-4E": [0,1,2]
};
var radar_stations = [
"gci",
"frigate",
];
var update_rate = 10; #how often the message should update in seconds
var hostile_radius = 300000; #max distance to check against, in meters
var true = 1;
var false = 0;
# request types
var NONE = 0;
var PICTURE = 1;
var BOGEYDOPE = 2;
var CUTOFF = 3;
var PENDING = 0;
var SENDING = 1;
var SENT = 2;
var output_prop = 0;
var radar_tx_output_prop = 11;
var enemy_node = props.globals.getNode("/enemies");
var player_node = props.globals.getNode("/ai/models");
var opfor_switch = props.globals.getNode("/enemies/opfor-switch"); # targets all non-opfor
var friend_switch = props.globals.getNode("/enemies/friend-switch"); # targets all opfor
##########################################
### Objects
##########################################
var gci_contact = {
new: func(c, class) {
var m = {parents:[gci_contact]};
m.time_from_last_message = 0;
m.node = c;
m.model = remove_suffix(remove_suffix(split(".", split("/", c.getNode("sim/model/path").getValue())[-1])[0], "-model"), "-anim");
m.valid = c.getNode("valid");
m.callsign = c.getNode("callsign").getValue();
if ( contains(prop_watch, m.model) ) {
m.picture_node = c.getNode("sim/multiplay/generic/bool["~prop_watch[m.model][0]~"]");
m.bogeydope_node = c.getNode("sim/multiplay/generic/bool["~prop_watch[m.model][1]~"]");
m.cutoff_node = c.getNode("sim/multiplay/generic/bool["~prop_watch[m.model][2]~"]");
} else {
m.picture_node = -1;
m.bogeydope_node = -1;
m.cutoff_node = -1;
}
m.is_radar_station = find_match(m.model,radar_stations);
m.contact = radar_logic.Contact.new(c,class);
m.foe = false;
m.match = false;
m.request = NONE;
m.last_request = NONE;
m.request_status = PENDING;
m.msg_queue = [];
if (m.is_radar_station) {
m.radar_station_process_send();
} else {
m.process_send();
}
return m;
},
getValid: func() {
if (me.valid.getNode() == 0 and me.callsign != me.node.getNode("callsign").getValue()) {
return 0;
} else {
return 1;
}
},
check_foe: func() {
me.foe = false;
if (opfor_switch.getValue() == true ) {
if (left(string.lc(me.callsign),5) != "opfor") {
me.foe = true;
}
} elsif (friend_switch.getValue() == true) {
if (left(string.lc(me.callsign),5) == "opfor") {
me.foe = true;
}
} else {
foreach (var cs; enemy_node.getChildren()) {
if (me.callsign == cs.getValue()) {
me.foe = true;
break;
}
}
}
return me.foe;
},
update_request: func() {
if (me.picture_node == -1) {
return;
}
#print("updating info");
if (me.picture_node.getValue() == true) {
me.request = PICTURE;
} elsif (me.bogeydope_node.getValue() == true) {
me.request = BOGEYDOPE;
} elsif (me.cutoff_node.getValue() == true) {
me.request = CUTOFF;
} else {
me.request = NONE;
}
},
check_node: func() {
#print('checking node');
if (me.picture_node == -1){
#print('watch node is -1');
return false;
} elsif (me.check_foe() == true) {
#print('check_foe is true');
return false;
} elsif (me.request == NONE) {
#print('node is false');
return false;
} elsif (systime() - me.time_from_last_message < update_rate) {
#print("update failed");
return false;
} elsif (me.request_status == SENT) {
return false;
} else {
me.time_from_last_message = systime();
return true;
}
},
process_send: func() {
# messages are first in, first out order
# updates every 1.5 seconds
#print('in process_send()');
if (damage_prop.getValue() == 0) {
me.update_request();
#print('rqst: ' ~ me.request);
#print('last: ' ~ me.last_request);
#print('stat: ' ~ me.request_status);
#print('queue size: ' ~ size(me.msg_queue));
if (me.request == NONE) {
#print('setting request to none');
me.request_status = PENDING;
} elsif (me.request != NONE and me.request_status == PENDING and me.request_status != SENT and size(me.msg_queue) > 0) {
#print('setting status to sending');
me.request_status = SENDING;
} elsif (me.request_status == SENDING and size(me.msg_queue) == 0) {
#print('setting status to sent');
me.request_status = SENT;
}
if (me.request == NONE or me.request_status == SENT) {
#print('emptying queue');
me.msg_queue = [];
}
if (me.request != me.last_request) {
#print('setting status to pending and emptying queue');
me.request_status = PENDING;
me.msg_queue = [];
}
me.last_request = me.request;
if (size(me.msg_queue) > 0 and me.request_status == SENDING) {
#print("msg_queue: " ~ debug.dump(me.msg_queue));
setprop("/sim/multiplay/generic/string["~output_prop~"]",me.msg_queue[0]);
output_prop = output_prop > 9 ? 0 : output_prop + 1;
me.msg_queue = purge_from_vector(me.msg_queue,0);
}
}
settimer(func(){me.process_send();},1.3);
},
radar_station_process_send: func() {
# messages are first in, first out order
# updates every 1.5 seconds
#print('in process_send()');
if (size(me.msg_queue) > 0 and damage_prop.getValue() == 0) {
#print("msg_queue: " ~ debug.dump(me.msg_queue));
setprop("/sim/multiplay/generic/string["~radar_tx_output_prop~"]",me.msg_queue[0]);
radar_tx_output_prop = radar_tx_output_prop >= 16 ? 11 : radar_tx_output_prop + 1;
me.msg_queue = purge_from_vector(me.msg_queue,0);
}
settimer(func(){me.radar_station_process_send();},1.3);
},
};
##########################################
### Functions
##########################################
# gather up all contacts, so we can iterate over them
var cx_master_list = [];
var gather_contacts = func() {
# first we need to clean the contact list
for (var i = 0; i < size(cx_master_list); i = i + 1) {
if (cx_master_list[i] == nil) { break; }
if (!cx_master_list[i].getValid()) {
cx_master_list = purge_from_vector(cx_master_list, i);
}
}
var matching = false;
foreach(var mp; player_node.getChildren("multiplayer")) {
if (mp.getNode("valid").getValue() == 1) {
matching = false;
foreach(var cx; cx_master_list) {
if ( mp.getPath() == cx.contact.getNode().getPath() ) {
matching = true;
break;
}
}
if (matching == false) {
cx = gci_contact.new(mp,0);
print("adding contact: " ~ cx.contact.get_Callsign());
append(cx_master_list,cx);
}
}
}
}
var check_requests = func(){
foreach (var cx; cx_master_list) {
if (cx.check_foe() == true or cx.check_node() == false) { continue; }
if (size(cx.msg_queue) > 0) { continue; } # msg queue should be reset or emptied when request changes.
if (cx.request == NONE) {
#print('reqest is none in check_requests');
continue;
} elsif (cx.request == PICTURE) {
var blue_coords = [];
var opfor_coords = [];
var match = false;
append(blue_coords, cx.contact.get_Coord());
foreach (var check; cx_master_list) {
if (!check_visible(check)) { continue; }
match = false;
if (check.check_foe()) {
foreach (var coord; opfor_coords) {
if (coord.distance_to(check.contact.get_Coord()) < 3 * NM2M) {
match = true;
break;
}
}
if (!match) { append(opfor_coords,check.contact.get_Coord()); }
} else {
foreach (var coord; blue_coords) {
if (coord.distance_to(check.contact.get_Coord()) < 3 * NM2M) {
match = true;
break;
}
}
if (!match) { append(blue_coords,check.contact.get_Coord()); }
}
if (!match) {
#send message
var bearing = math.round(cx.contact.get_Coord().course_to(check.contact.get_Coord()),1);
var range = math.round(check.contact.get_Coord().distance_to(cx.contact.get_Coord()));
var altitude = math.round(check.contact.get_altitude(),1);
# requestor-callsign:unique-message-id:2:bearing:range:altitude:[BLUFOR=0|OPFOR=1]
append(cx.msg_queue, cx.callsign ~ ":" ~ get_random() ~ ":2:" ~ bearing ~ ":" ~ range ~ ":" ~ altitude ~ ":" ~ check.check_foe());
}
}
if (size(cx.msg_queue) == 0) {
append(cx.msg_queue, cx.callsign ~ ":" ~ get_random() ~ ":1:n:n:n:n");
} else {
append(cx.msg_queue, cx.callsign ~ ":" ~ get_random() ~ ":0:d:d:d:d");
}
} elsif (cx.request == BOGEYDOPE) {
min_dist = hostile_radius;
closest = nil;
#print('checking bogey dope');
foreach (var check; cx_master_list) {
if (!check.check_foe()) { continue; }
var dist = cx.contact.get_Coord().distance_to(check.contact.get_Coord());
if ( dist > min_dist) { continue; }
if (!check_visible(check)) { continue; }
min_dist = dist;
closest = check;
}
if (closest != nil) {
var bearing = math.round(cx.contact.get_Coord().course_to(closest.contact.get_Coord()),1);
var range = math.round(closest.contact.get_Coord().distance_to(cx.contact.get_Coord()));
var altitude = math.round(closest.contact.get_altitude(),1);
var aspect = math.round(math.periodic(-180,180,closest.contact.get_heading() - closest.contact.get_Coord().course_to(cx.contact.get_Coord())));
append(cx.msg_queue, cx.callsign ~ ":" ~ get_random() ~ ":3:" ~ bearing ~ ":" ~ range ~ ":" ~ altitude ~ ":" ~ aspect);
} else {
append(cx.msg_queue, cx.callsign ~ ":" ~ get_random() ~ ":1:n:n:n:n");
}
} elsif (cx.request == CUTOFF) {
min_dist = hostile_radius;
closest = nil;
foreach (var check; cx_master_list) {
if (!check.check_foe()) { continue; }
var dist = cx.contact.get_Coord().distance_to(check.contact.get_Coord());
if ( dist > min_dist) { continue; }
if (!check_visible(check)) { continue; }
min_dist = dist;
closest = check;
}
if (closest != nil) {
var bogey_speed = closest.contact.speed.getValue();
var cx_speed = cx.contact.speed.getValue();
var bogey_heading = closest.contact.heading.getValue();
var bearing = cx.contact.get_Coord().course_to(closest.contact.get_Coord());
var range = closest.contact.get_Coord().distance_to(cx.contact.get_Coord());
var altitude = math.round(closest.contact.get_altitude(),1);
var aspect = math.round(math.periodic(-180,180,closest.contact.get_heading() - closest.contact.get_Coord().course_to(cx.contact.get_Coord())));
# get_intercept(bearing, dist_m, runnerHeading, runnerSpeed, chaserSpeed)
var info = get_intercept(bearing, range, bogey_heading, bogey_speed * KT2MPS, cx_speed * KT2MPS);
if (info == nil) {
append(cx.msg_queue, cx.callsign ~ ":" ~ get_random() ~ ":1:n:n:n:n");
} else {
append(cx.msg_queue, cx.callsign ~ ":" ~ get_random() ~ ":4:" ~ int(info[1]) ~ ":" ~ int(info[0]) ~ ":" ~ altitude ~ ":" ~ aspect);
}
} else {
append(cx.msg_queue, cx.callsign ~ ":" ~ get_random() ~ ":1:n:n:n:n");
}
}
}
}
var cx_data_transmit = func(){
#print('transmitting');
foreach (var cx; cx_master_list) {
if (!cx.is_radar_station) { continue; }
if (size(cx.msg_queue) > 0) { continue; }
if (cx.check_foe()) { continue; }
foreach (var tx; cx_master_list) {
if (tx != cx) {
append(cx.msg_queue,cx.callsign ~ ":" ~ get_random() ~ ":" ~ tx.callsign);
}
}
}
}
var data_receive_callsigns = [];
var cx_data_receive = func() {
# clean out old data (15 seconds)
var time = systime();
var new_vec = [];
foreach (var rx; data_receive_callsigns){
if (time - rx[1] < 15) {
append(new_vec,rx);
}
}
data_receive_callsigns = new_vec;
foreach (var cx; cx_master_list) {
for (var i = 11; i <= 15; i = i + 1) {
var msg = getprop(cx.node.getPath() ~ "/sim/multiplay/generic/string["~i~"]");
if (msg == "") { continue; }
if (msg == nil) { continue; }
msg = split(":",msg);
if (msg[0] != getprop("/sim/multiplay/callsign")) { continue; };
if (find_match(msg[2], data_receive_callsigns)) { continue; }
#print("adding cs to received list");
append(data_receive_callsigns,[msg[2],systime()]);
}
}
}
var check_visible = func(check) {
foreach(var rx; data_receive_callsigns) {
if (rx[0] == check.callsign) {
return true;
}
}
if (radar_logic.isNotBehindTerrain(check.node) == false){ return false; }
var target_heading = check.contact.heading.getValue();
var relative_bearing = math.abs(geo.normdeg180(check.contact.get_Coord().course_to(geo.aircraft_position()) - target_heading));
var target_radial_airspeed = (-1 * ( ( relative_bearing / 90 ) - 1 ) ) * check.node.getNode("velocities/true-airspeed-kt").getValue();
if ( math.abs(target_radial_airspeed) < 20 ) { return false; } # i.e. notching, landed aircraft
return true;
}
var iter = 0;
var main_loop = func() {
#print("looping");
if (getprop("/carrier/sunk/") == 0) {
if (iter == 0) {
gather_contacts();
cx_data_transmit();
}
cx_data_receive();
check_requests();
}
iter = iter >= 7 ? 0 : iter + 1;
settimer(func(){main_loop();},1);
}
var get_intercept = func(bearing, dist_m, runnerHeading, runnerSpeed, chaserSpeed) {
# from Leto
# needs: bearing, dist_m, runnerHeading, runnerSpeed, chaserSpeed
# dist_m > 0 and chaserSpeed > 0
#var bearing = 184;var dist_m=31000;var runnerHeading=186;var runnerSpeed= 200;var chaserSpeed=250;
var trigAngle = 90-bearing;
var RunnerPosition = [dist_m*math.cos(trigAngle*D2R), dist_m*math.sin(trigAngle*D2R),0];
var ChaserPosition = [0,0,0];
var VectorFromRunner = vector.Math.minus(ChaserPosition, RunnerPosition);
var runner_heading = 90-runnerHeading;
var RunnerVelocity = [runnerSpeed*math.cos(runner_heading*D2R), runnerSpeed*math.sin(runner_heading*D2R),0];
var a = chaserSpeed * chaserSpeed - runnerSpeed * runnerSpeed;
var b = 2 * vector.Math.dotProduct(VectorFromRunner, RunnerVelocity);
var c = -dist_m * dist_m;
if ((b*b-4*a*c)<0) {
# intercept not possible
return nil;
}
var t1 = (-b+math.sqrt(b*b-4*a*c))/(2*a);
var t2 = (-b-math.sqrt(b*b-4*a*c))/(2*a);
var timeToIntercept = 0;
if (t1 > 0 and t2 > 0) {
timeToIntercept = math.min(t1, t2);
} else {
timeToIntercept = math.max(t1, t2);
}
var InterceptPosition = vector.Math.plus(RunnerPosition, vector.Math.product(timeToIntercept, RunnerVelocity));
var ChaserVelocity = vector.Math.product(1/timeToIntercept, vector.Math.minus(InterceptPosition, ChaserPosition));
var interceptAngle = vector.Math.angleBetweenVectors([0,1,0], ChaserVelocity);
var interceptHeading = geo.normdeg(ChaserVelocity[0]<0?-interceptAngle:interceptAngle);
#print("output:");
#print("time: " ~ timeToIntercept);
#print("heading: " ~ interceptHeading);
return [timeToIntercept, interceptHeading];
}
var purge_from_vector = func(vec, idx = nil, val = nil) {
if (idx == nil and val == nil) { return vec; }
var new_vec = [];
for (var i = 0; i < size(vec); i = i + 1) {
if ((idx != nil and i == idx) or (val != nil and val == vec[i])) { continue; }
append(new_vec, vec[i]);
}
return new_vec;
}
var get_random = func() {
return int(rand() * 9999)
}
var find_match = func(val,vec) {
if (size(vec) == 0) {
return 0;
}
foreach (var a; vec) {
#print(a);
if (a == val) { return 1; }
}
return 0;
}
var remove_suffix = func(s, x) {
var len = size(x);
if (substr(s, -len) == x)
return substr(s, 0, size(s) - len);
return s;
}
main_loop();

View File

@ -0,0 +1,450 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
var encode3bits = func(first, second, third) {
var integer = first;
integer = integer + 2 * second;
integer = integer + 4 * third;
return integer;
}
var versionString = getprop("sim/version/flightgear");
var version = split(".", versionString);
var major = num(version[0]);
var minor = num(version[1]);
var pica = num(version[2]);
var pickingMethod = 0;
if ((major == 2017 and minor == 2 and pica >= 1) or (major == 2017 and minor > 2) or major > 2017) {
pickingMethod = 1;
}
var FALSE = 0;
var TRUE = 1;
var AIR = 0;
var MARINE = 1;
var SURFACE = 2;
var ORDNANCE = 3;
var Contact = {
# For now only used in guided missiles, to make it compatible with Mirage 2000-5.
new: func(c, class) {
var obj = { parents : [Contact]};
#debug.benchmark("radar process1", func {
obj.rdrProp = c.getNode("radar");
obj.oriProp = c.getNode("orientation");
obj.velProp = c.getNode("velocities");
obj.posProp = c.getNode("position");
obj.heading = obj.oriProp.getNode("true-heading-deg");
#});
#debug.benchmark("radar process2", func {
obj.alt = obj.posProp.getNode("altitude-ft");
obj.lat = obj.posProp.getNode("latitude-deg");
obj.lon = obj.posProp.getNode("longitude-deg");
#});
#debug.benchmark("radar process3", func {
#As it is a geo.Coord object, we have to update lat/lon/alt ->and alt is in meters
obj.coord = geo.Coord.new();
obj.coord.set_latlon(obj.lat.getValue(), obj.lon.getValue(), obj.alt.getValue() * FT2M);
#});
#debug.benchmark("radar process4", func {
obj.pitch = obj.oriProp.getNode("pitch-deg");
obj.roll = obj.oriProp.getNode("roll-deg");
obj.speed = obj.velProp.getNode("true-airspeed-kt");
obj.vSpeed = obj.velProp.getNode("vertical-speed-fps");
obj.callsign = c.getNode("callsign", 1);
obj.shorter = c.getNode("model-shorter");
obj.orig_callsign = obj.callsign.getValue();
obj.name = c.getNode("name");
obj.sign = c.getNode("sign",1);
obj.valid = c.getNode("valid");
obj.painted = c.getNode("painted");
obj.unique = c.getNode("unique");
obj.validTree = 0;
#});
#debug.benchmark("radar process5", func {
#obj.transponderID = c.getNode("instrumentation/transponder/transmitted-id");
#});
#debug.benchmark("radar process6", func {
obj.acType = c.getNode("sim/model/ac-type");
obj.type = c.getName();
obj.index = c.getIndex();
obj.string = "ai/models/" ~ obj.type ~ "[" ~ obj.index ~ "]";
obj.shortString = obj.type ~ "[" ~ obj.index ~ "]";
#});
#debug.benchmark("radar process7", func {
obj.range = obj.rdrProp.getNode("range-nm");
obj.bearing = obj.rdrProp.getNode("bearing-deg");
obj.elevation = obj.rdrProp.getNode("elevation-deg");
#});
obj.deviation = nil;
obj.node = c;
obj.class = class;
obj.polar = [0,0];
obj.cartesian = [0,0];
return obj;
},
isValid: func () {
var valid = me.valid.getValue();
if (valid == nil) {
valid = FALSE;
}
if (me.callsign.getValue() != me.orig_callsign) {
valid = FALSE;
}
return valid;
},
isPainted: func () {
if (me.painted == nil) {
me.painted = me.node.getNode("painted");
}
if (me.painted == nil) {
return nil;
}
var p = me.painted.getValue();
return p;
},
getUnique: func () {
if (me.unique == nil) {
me.unique = me.node.getNode("unique");
}
if (me.unique == nil) {
return nil;
}
var u = me.unique.getValue();
return u;
},
getElevation: func() {
var e = 0;
e = me.elevation.getValue();
if(e == nil or e == 0) {
# AI/MP has no radar properties
var self = geo.aircraft_position();
me.get_Coord();
var angleInv = clamp(self.distance_to(me.coord)/self.direct_distance_to(me.coord), -1, 1);
e = (self.alt()>me.coord.alt()?-1:1)*math.acos(angleInv)*R2D;
}
return e;
},
getNode: func () {
return me.node;
},
getFlareNode: func () {
return me.node.getNode("rotors/main/blade[3]/flap-deg");
},
getChaffNode: func () {
return me.node.getNode("rotors/main/blade[3]/position-deg");
},
setPolar: func(dist, angle) {
me.polar = [dist,angle];
},
setCartesian: func(x, y) {
me.cartesian = [x,y];
},
remove: func(){
if(me.validTree != 0){
me.validTree.setValue(0);
}
},
get_Coord: func(){
me.coord.set_latlon(me.lat.getValue(), me.lon.getValue(), me.alt.getValue() * FT2M);
var TgTCoord = geo.Coord.new(me.coord);
return TgTCoord;
},
get_Callsign: func(){
var n = me.callsign.getValue();
if(n != "" and n != nil) {
return n;
}
if (me.name == nil) {
me.name = me.getNode().getNode("name");
}
if (me.name == nil) {
n = "";
} else {
n = me.name.getValue();
}
if(n != "" and n != nil) {
return n;
}
n = me.sign.getValue();
if(n != "" and n != nil) {
return n;
}
return "UFO";
},
get_model: func(){
var n = "";
if (me.shorter == nil) {
me.shorter = me.node.getNode("model-shorter");
}
if (me.shorter != nil) {
n = me.shorter.getValue();
}
if(n != "" and n != nil) {
return n;
}
n = me.sign.getValue();
if(n != "" and n != nil) {
return n;
}
if (me.name == nil) {
me.name = me.getNode().getNode("name");
}
if (me.name == nil) {
n = "";
} else {
n = me.name.getValue();
}
if(n != "" and n != nil) {
return n;
}
return me.get_Callsign();
},
get_Speed: func(){
# return true airspeed
var n = me.speed.getValue();
return n;
},
get_Longitude: func(){
var n = me.lon.getValue();
return n;
},
get_Latitude: func(){
var n = me.lat.getValue();
return n;
},
get_Pitch: func(){
var n = me.pitch.getValue();
return n;
},
isVirtual: func(){
return 0;
},
get_Roll: func(){
var n = me.roll.getValue();
return n;
},
get_heading : func(){
var n = me.heading.getValue();
if(n == nil)
{
n = 0;
}
return n;
},
get_bearing: func(){
var n = 0;
n = me.bearing.getValue();
if(n == nil or n == 0) {
# AI/MP has no radar properties
n = me.get_bearing_from_Coord(geo.aircraft_position());
}
return n;
},
get_bearing_from_Coord: func(MyAircraftCoord){
me.get_Coord();
var myBearing = 0;
if(me.coord.is_defined()) {
myBearing = MyAircraftCoord.course_to(me.coord);
}
return myBearing;
},
get_reciprocal_bearing: func(){
return geo.normdeg(me.get_bearing() + 180);
},
get_deviation: func(true_heading_ref, coord){
me.deviation = - deviation_normdeg(true_heading_ref, me.get_bearing_from_Coord(coord));
return me.deviation;
},
get_altitude: func(){
#Return Alt in feet
return me.alt.getValue();
},
get_Elevation_from_Coord: func(MyAircraftCoord) {
me.get_Coord();
var value = (me.coord.alt() - MyAircraftCoord.alt()) / me.coord.direct_distance_to(MyAircraftCoord);
if (math.abs(value) > 1) {
# warning this else will fail if logged in as observer and see aircraft on other side of globe
return 0;
}
var myPitch = math.asin(value) * R2D;
return myPitch;
},
get_total_elevation_from_Coord: func(own_pitch, MyAircraftCoord){
var myTotalElevation = - deviation_normdeg(own_pitch, me.get_Elevation_from_Coord(MyAircraftCoord));
return myTotalElevation;
},
get_total_elevation: func(own_pitch) {
me.deviation = - deviation_normdeg(own_pitch, me.getElevation());
return me.deviation;
},
get_range: func() {
var r = 0;
if(me.range == nil or me.range.getValue() == nil or me.range.getValue() == 0) {
# AI/MP has no radar properties
me.get_Coord();
r = me.coord.direct_distance_to(geo.aircraft_position()) * M2NM;
} else {
r = me.range.getValue();
}
return r;
},
get_range_from_Coord: func(MyAircraftCoord) {
var myCoord = me.get_Coord();
var myDistance = 0;
if(myCoord.is_defined()) {
myDistance = MyAircraftCoord.direct_distance_to(myCoord) * M2NM;
}
return myDistance;
},
get_type: func () {
return me.class;
},
get_cartesian: func() {
return me.cartesian;
},
get_polar: func() {
return me.polar;
},
};
var isNotBehindTerrain = func( mp ) {
###########
var pos = mp.getNode("position");
var alt = pos.getNode("altitude-ft").getValue();
var lat = pos.getNode("latitude-deg").getValue();
var lon = pos.getNode("longitude-deg").getValue();
if(alt == nil or lat == nil or lon == nil) {
return isVisible = 0;
}
var aircraftPos = geo.Coord.new().set_latlon(lat, lon, alt*0.3048);
#################
if (pickingMethod == 1) {
var myPos = geo.aircraft_position();
myPos.set_latlon(myPos.lat(),myPos.lon(),myPos.alt()+50);
var xyz = {"x":myPos.x(), "y":myPos.y(), "z":myPos.z()};
var dir = {"x":aircraftPos.x()-myPos.x(), "y":aircraftPos.y()-myPos.y(), "z":aircraftPos.z()-myPos.z()};
# Check for terrain between own aircraft and other:
v = get_cart_ground_intersection(xyz, dir);
if (v == nil) {
return 1;
#printf("No terrain, planes has clear view of each other");
} else {
var terrain = geo.Coord.new();
terrain.set_latlon(v.lat, v.lon, v.elevation);
var maxDist = myPos.direct_distance_to(aircraftPos);
var terrainDist = myPos.direct_distance_to(terrain);
if (terrainDist < maxDist) {
#printf("terrain found between SAM and aircraft %.1f meter away.", terrainDist);
return 0;
} else {
#print("The planes has clear view of each other");
return 1;
}
}
} else {
var isVisible = 0;
var MyCoord = geo.aircraft_position();
# Because there is no terrain on earth that can be between these 2
if(MyCoord.alt() < 8900 and aircraftPos.alt() < 8900)
{
# Temporary variable
# A (our plane) coord in meters
var a = MyCoord.x();
var b = MyCoord.y();
var c = MyCoord.z();
# B (target) coord in meters
var d = aircraftPos.x();
var e = aircraftPos.y();
var f = aircraftPos.z();
var difa = d - a;
var difb = e - b;
var difc = f - c;
# direct Distance in meters
var myDistance = math.sqrt( math.pow((d-a),2) + math.pow((e-b),2) + math.pow((f-c),2)); #calculating distance ourselves to avoid another call to geo.nas (read: speed, probably).
var Aprime = geo.Coord.new();
# Here is to limit FPS drop on very long distance
var L = 500;
if(myDistance > 50000)
{
L = myDistance / 15;
}
var step = L;
var maxLoops = int(myDistance / L);
isVisible = 1;
# This loop will make travel a point between us and the target and check if there is terrain
for(var i = 1 ; i <= maxLoops ; i += 1)
{
#calculate intermediate step
#basically dividing the line into maxLoops number of steps, and checking at each step
#to ascii-art explain it:
# |us|----------|step 1|-----------|step 2|--------|step 3|----------|them|
#there will be as many steps as there is i
#every step will be equidistant
#also, if i == 0 then the first step will be our plane
var x = ((difa/(maxLoops+1))*i)+a;
var y = ((difb/(maxLoops+1))*i)+b;
var z = ((difc/(maxLoops+1))*i)+c;
#print("i:" ~ i ~ "|x,y,z | " ~ x ~ "," ~ y ~ "," ~ z);
Aprime.set_xyz(x,y,z);
var AprimeTerrainAlt = geo.elevation(Aprime.lat(), Aprime.lon());
if(AprimeTerrainAlt == nil)
{
AprimeTerrainAlt = 0;
}
if(AprimeTerrainAlt > Aprime.alt())
{
#print("behind terrain");
return 0;
}
}
}
else
{
isVisible = 1;
}
return isVisible;
}
}

303
gci-radar/Nasal/vector.nas Normal file
View File

@ -0,0 +1,303 @@
var Math = {
#
# Author: Nikolai V. Chr.
#
# Version 1.6
#
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
# FG struct. coords: +x = back, +y = right, +z = up.
#
# 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.
#
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
convertCoords: func (x,y,z) {
return [-x, -y, z];
},
convertAngles: func (heading,pitch,roll) {
return [-heading, pitch, roll];
},
# angle between 2 vectors. Returns 0-180 degrees.
angleBetweenVectors: func (a,b) {
a = me.normalize(a);
b = me.normalize(b);
me.value = me.clamp((me.dotProduct(a,b)/me.magnitudeVector(a))/me.magnitudeVector(b),-1,1);#just to be safe in case some floating point error makes it out of bounds
return R2D * math.acos(me.value);
},
# length of vector
magnitudeVector: func (a) {
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
},
# dot product of 2 vectors
dotProduct: func (a,b) {
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
},
# rotate a vector. Order: roll, pitch, yaw
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.multiplyMatrices(me.yawM, me.pitchM), me.rollM);
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);
me.pitchM = me.pitchMatrix(pitch);
me.yawM = me.yawMatrix(yaw);
me.rotation = me.multiplyMatrices(me.multiplyMatrices(me.rollM, me.pitchM), me.yawM);
return me.multiplyMatrixWithVector(me.rotation, vector);
},
# multiply 3x3 matrix with vector
multiplyMatrixWithVector: func (matrix, vector) {
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
matrix[3]*vector[0]+matrix[4]*vector[1]+matrix[5]*vector[2],
matrix[6]*vector[0]+matrix[7]*vector[1]+matrix[8]*vector[2]];
},
# multiply 2 3x3 matrices
multiplyMatrices: func (a,b) {
return [a[0]*b[0]+a[1]*b[3]+a[2]*b[6], a[0]*b[1]+a[1]*b[4]+a[2]*b[7], a[0]*b[2]+a[1]*b[5]+a[2]*b[8],
a[3]*b[0]+a[4]*b[3]+a[5]*b[6], a[3]*b[1]+a[4]*b[4]+a[5]*b[7], a[3]*b[2]+a[4]*b[5]+a[5]*b[8],
a[6]*b[0]+a[7]*b[3]+a[8]*b[6], a[6]*b[1]+a[7]*b[4]+a[8]*b[7], a[6]*b[2]+a[7]*b[5]+a[8]*b[8]];
},
# matrix for rolling
rollMatrix: func (roll) {
roll = roll * D2R;
return [1,0,0,
0,math.cos(roll),-math.sin(roll),
0,math.sin(roll), math.cos(roll)];
},
# matrix for pitching
pitchMatrix: func (pitch) {
pitch = pitch * D2R;
return [math.cos(pitch),0,-math.sin(pitch),
0,1,0,
math.sin(pitch),0,math.cos(pitch)];
},
# matrix for yawing
yawMatrix: func (yaw) {
yaw = yaw * D2R;
return [math.cos(yaw),-math.sin(yaw),0,
math.sin(yaw),math.cos(yaw),0,
0,0,1];
},
# vector to heading/pitch
cartesianToEuler: 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;
me.hdg = math.asin(-vector[1]/me.horz)*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.pitch = vector[2]>=0?90:-90;
me.hdg = nil;
}
return [me.hdg, me.pitch];
},
# gives an vector that points up from fuselage
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
me.yaw = yaw_deg * D2R;
me.pitch = pitch_deg * D2R;
me.roll = roll_deg * D2R;
me.x = -math.cos(me.yaw)*math.sin(me.pitch)*math.cos(me.roll) + math.sin(me.yaw)*math.sin(me.roll);
me.y = -math.sin(me.yaw)*math.sin(me.pitch)*math.cos(me.roll) - math.cos(me.yaw)*math.sin(me.roll);
me.z = math.cos(me.pitch)*math.cos(me.roll);#roll changed from sin to cos, since the rotation matrix is wrong
return [me.x,me.y,me.z];
},
# gives an vector that points forward from fuselage
eulerToCartesian3X: func (yaw_deg, pitch_deg, roll_deg) {
me.yaw = yaw_deg * D2R;
me.pitch = pitch_deg * D2R;
me.roll = roll_deg * D2R;
me.x = math.cos(me.yaw)*math.cos(me.pitch);
me.y = math.sin(me.yaw)*math.cos(me.pitch);
me.z = math.sin(me.pitch);
return [me.x,me.y,me.z];
},
# gives an vector that points left from fuselage
eulerToCartesian3Y: func (yaw_deg, pitch_deg, roll_deg) {
me.yaw = yaw_deg * D2R;
me.pitch = pitch_deg * D2R;
me.roll = roll_deg * D2R;
me.x = -math.cos(me.yaw)*math.sin(me.pitch)*math.sin(me.roll) - math.sin(me.yaw)*math.cos(me.roll);
me.y = -math.sin(me.yaw)*math.sin(me.pitch)*math.sin(me.roll) + math.cos(me.yaw)*math.cos(me.roll);
me.z = math.cos(me.pitch)*math.sin(me.roll);
return [me.x,me.y,me.z];
},
# same as eulerToCartesian3X, except it needs no roll
eulerToCartesian2: func (yaw_deg, pitch_deg) {
me.yaw = yaw_deg * D2R;
me.pitch = pitch_deg * D2R;
me.x = math.cos(me.pitch) * math.cos(me.yaw);
me.y = math.cos(me.pitch) * math.sin(me.yaw);
me.z = math.sin(me.pitch);
return [me.x,me.y,me.z];
},
#pitch from coord1 to coord2 in degrees (takes curvature of earth into effect.)
getPitch: func (coord1, coord2) {
if (coord1.lat() == coord2.lat() and coord1.lon() == coord2.lon()) {
if (coord2.alt() > coord1.alt()) {
return 90;
} elsif (coord2.alt() < coord1.alt()) {
return -90;
} else {
return 0;
}
}
if (coord1.alt() != coord2.alt()) {
me.d12 = coord1.direct_distance_to(coord2);
me.coord3 = geo.Coord.new(coord1);
me.coord3.set_alt(coord1.alt()-me.d12*0.5);# this will increase the area of the triangle so that rounding errors dont get in the way.
me.d13 = coord1.alt()-me.coord3.alt();
if (me.d12 == 0) {
# on top of each other, maybe rounding error..
return 0;
}
me.d32 = me.coord3.direct_distance_to(coord2);
if (math.abs(me.d13)+me.d32 < me.d12) {
# rounding errors somewhere..one triangle side is longer than other 2 sides combined.
return 0;
}
# standard formula for a triangle where all 3 side lengths are known:
me.len = (math.pow(me.d12, 2)+math.pow(me.d13,2)-math.pow(me.d32, 2))/(2 * me.d12 * math.abs(me.d13));
if (me.len < -1 or me.len > 1) {
# something went wrong, maybe rounding error..
return 0;
}
me.angle = R2D * math.acos(me.len);
me.pitch = -1* (90 - me.angle);
#printf("d12 %.4f d32 %.4f d13 %.4f len %.4f pitch %.4f angle %.4f", me.d12, me.d32, me.d13, me.len, me.pitch, me.angle);
return me.pitch;
} else {
# same altitude
me.nc = geo.Coord.new();
me.nc.set_xyz(0,0,0); # center of earth
me.radiusEarth = coord1.direct_distance_to(me.nc);# current distance to earth center
me.d12 = coord1.direct_distance_to(coord2);
# standard formula for a triangle where all 3 side lengths are known:
me.len = (math.pow(me.d12, 2)+math.pow(me.radiusEarth,2)-math.pow(me.radiusEarth, 2))/(2 * me.d12 * me.radiusEarth);
if (me.len < -1 or me.len > 1) {
# something went wrong, maybe rounding error..
return 0;
}
me.angle = R2D * math.acos(me.len);
me.pitch = -1* (90 - me.angle);
return me.pitch;
}
},
# 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) {
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
},
# vector a - vector b
minus: func (a, b) {
return [a[0]-b[0], a[1]-b[1], a[2]-b[2]];
},
# vector a + vector b
plus: func (a, b) {
return [a[0]+b[0], a[1]+b[1], a[2]+b[2]];
},
# float * vector
product: func (scalar, vector) {
return [scalar*vector[0], scalar*vector[1], scalar*vector[2]]
},
# print vector to console
format: func (v) {
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
},
# make vector length 1.0
normalize: func (v) {
me.mag = me.magnitudeVector(v);
return [v[0]/me.mag, v[1]/me.mag, v[2]/me.mag];
},
# rotation matrices
#
#
#| 1 0 0 |
#| 0 cos(roll) -sin(roll) |
#| 0 sin(roll) cos(roll) |
#
#| cos(pitch) 0 -sin(pitch) |
#| 0 1 0 |
#| sin(pitch) 0 cos(pitch) |
#
#| cos(yaw) -sin(yaw) 0 |
#| sin(yaw) cos(yaw) 0 |
#| 0 0 1 |
#
# combined matrix from yaw, pitch, roll:
#
#| cos(yaw)cos(pitch) -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll) -cos(yaw)sin(pitch)cos(roll)+sin(yaw)sin(roll)|
#| sin(yaw)cos(pitch) -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll) -sin(yaw)sin(pitch)cos(roll)-cos(yaw)sin(roll)|
#| sin(pitch) cos(pitch)sin(roll) cos(pitch)cos(roll)|
#
#
};
# Fix for geo.Coord: (not needed in FG 2017.4+)
geo.Coord.set_x = func(x) { me._cupdate(); me._pdirty = 1; me._x = x; me };
geo.Coord.set_y = func(y) { me._cupdate(); me._pdirty = 1; me._y = y; me };
geo.Coord.set_z = func(z) { me._cupdate(); me._pdirty = 1; me._z = z; me };
geo.Coord.set_lat = func(lat) { me._pupdate(); me._cdirty = 1; me._lat = lat * D2R; me };
geo.Coord.set_lon = func(lon) { me._pupdate(); me._cdirty = 1; me._lon = lon * D2R; me };
geo.Coord.set_alt = func(alt) { me._pupdate(); me._cdirty = 1; me._alt = alt; me };
geo.Coord.apply_course_distance2 = func(course, dist) {# this method in geo is not bad, just wanted to see if this way of doing it worked better.
me._pupdate();
course *= D2R;
var nc = geo.Coord.new();
nc.set_xyz(0,0,0); # center of earth
dist /= me.direct_distance_to(nc);# current distance to earth center
if (dist < 0.0) {
dist = abs(dist);
course = course - math.pi;
}
me._lat2 = math.asin(math.sin(me._lat) * math.cos(dist) + math.cos(me._lat) * math.sin(dist) * math.cos(course));
me._lon = me._lon + math.atan2(math.sin(course)*math.sin(dist)*math.cos(me._lat),math.cos(dist)-math.sin(me._lat)*math.sin(me._lat2));
while (me._lon <= -math.pi)
me._lon += math.pi*2;
while (me._lon > math.pi)
me._lon -= math.pi*2;
me._lat = me._lat2;
me._cdirty = 1;
me;
};

112
gci-radar/gci-set.xml Normal file
View File

@ -0,0 +1,112 @@
<?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>
<status>alpha</status>
<aircraft-version>0.1</aircraft-version>
<flight-model>null</flight-model>
<aero></aero>
<aircraft-operator></aircraft-operator>
<model>
<path>Aircraft/gci-radar/Models/gci.xml</path>
<always-show-in-MP type="bool">true</always-show-in-MP>
</model>
<presets>
<onground>true</onground>
</presets>
<menubar>
<default>
<menu n="100">
<label>GCI</label>
<enabled type="bool">true</enabled>
<item>
<label>Targets</label>
<name>enemies</name>
<binding>
<command>dialog-show</command>
<dialog-name>enemies</dialog-name>
</binding>
</item>
</menu>
</default>
</menubar>
<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>
<opfor-switch userarchive="y" type="bool">false</opfor-switch>
<friend-switch userarchive="y" type="bool">false</friend-switch>
</enemies>
<aircraft-data>
<!-- Properties that get saved to persist locally between FG sessions -->
<path>enemies/e1</path>
<path>enemies/e2</path>
<path>enemies/e3</path>
<path>enemies/e4</path>
<path>enemies/e5</path>
<path>enemies/e6</path>
<path>enemies/e7</path>
<path>enemies/e8</path>
<path>enemies/e9</path>
<path>enemies/e10</path>
<path>enemies/e11</path>
<path>enemies/e12</path>
<path>enemies/opfor-switch</path>
<path>enemies/friend-switch</path>
</aircraft-data>
<startup>
<splash-texture>Aircraft/gci-radar/splash1.png</splash-texture>
</startup>
<current-view>
<z-offset-dec-step type="double">0.0</z-offset-dec-step>
<z-offset-inc-step type="double">0.0</z-offset-inc-step>
<z-offset-min-m type="float">100.0</z-offset-min-m>
<z-offset-max-m type="float">2000.0</z-offset-max-m>
</current-view>
<multiplay>
<generic>
<int n="0" type="int">0</int>
</generic>
<visibility-range-nm type="int">500</visibility-range-nm>
</multiplay>
</sim>
<carrier>
<sunk type="bool">false</sunk>
</carrier>
<nasal>
<damage> <file>Aircraft/gci-radar/Nasal/damage.nas</file> </damage>
<radar_logic> <file>Aircraft/gci-radar/Nasal/radar-logic.nas</file> </radar_logic>
<gci> <file>Aircraft/gci-radar/Nasal/gci.nas</file> </gci>
<vector> <file>Aircraft/gci-radar/Nasal/vector.nas</file> </vector>
</nasal>
</PropertyList>

BIN
gci-radar/gui/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
gci-radar/gui/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@ -0,0 +1,348 @@
<?xml version="1.0"?>
<PropertyList>
<name>enemies</name>
<modal>false</modal>
<layout>vbox</layout>
<draggable>true</draggable>
<resizable>true</resizable>
<width>250</width>
<height>550</height>
<group>
<layout>hbox</layout>
<empty><stretch>1</stretch></empty>
<text>
<label>Targets</label>
</text>
<empty><stretch>1</stretch></empty>
<button>
<pref-width>16</pref-width>
<pref-height>16</pref-height>
<legend></legend>
<default>1</default>
<keynum>27</keynum>
<border>2</border>
<binding>
<command>dialog-close</command>
</binding>
<binding>
<command>dialog-apply</command>
</binding>
</button>
</group>
<text>
<label>Callsigns:</label>
<height>25</height>
</text>
<input>
<width>250</width>
<height>25</height>
<label>1</label>
<property>enemies/e1</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>2</label>
<property>enemies/e2</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>3</label>
<property>enemies/e3</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>4</label>
<property>enemies/e4</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>5</label>
<property>enemies/e5</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>6</label>
<property>enemies/e6</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>7</label>
<property>enemies/e7</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>8</label>
<property>enemies/e8</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>9</label>
<property>enemies/e9</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>10</label>
<property>enemies/e10</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>11</label>
<property>enemies/e11</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<input>
<width>250</width>
<height>25</height>
<label>12</label>
<property>enemies/e12</property>
<live>true</live>
<halign>left</halign>
<binding>
<command>dialog-apply</command>
</binding>
<color>
<red>1</red>
<green>0.5</green>
<blue>0.5</blue>
</color>
<enable>
<not>
<property>enemies/opfor-switch</property>
</not>
<not>
<property>enemies/friend-switch</property>
</not>
</enable>
</input>
<checkbox>
<width>12</width>
<height>12</height>
<property>/enemies/opfor-switch</property>
<label>Target all non-OPFOR</label>
<binding>
<command>dialog-apply</command>
</binding>
</checkbox>
<checkbox>
<width>12</width>
<height>12</height>
<property>/enemies/friend-switch</property>
<label>Target all OPFOR</label>
<binding>
<command>dialog-apply</command>
</binding>
</checkbox>
</PropertyList>

View File

Before

Width:  |  Height:  |  Size: 823 KiB

After

Width:  |  Height:  |  Size: 823 KiB

View File

@ -1,330 +0,0 @@
<?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>
<name>control-panel</name>
<layout>vbox</layout>
<width>250</width>
<resizable>false</resizable>
<group>
<layout>hbox</layout>
<empty><stretch>true</stretch></empty>
<text>
<label>Control Panel</label>
</text>
<empty><stretch>true</stretch></empty>
<button>
<legend/>
<keynum>27</keynum>
<pref-width>16</pref-width>
<pref-height>16</pref-height>
<border>2</border>
<binding>
<command>dialog-close</command>
</binding>
</button>
</group>
<hrule/>
<group>
<layout>vbox</layout>
<padding>6</padding>
<text>
<label>Elevators</label>
</text>
<group>
<layout>table</layout>
<!-- 3rd -->
<text>
<row>0</row>
<col>1</col>
<label>3rd</label>
</text>
<!-- 3rd -->
<button>
<row>1</row>
<col>1</col>
<visible>
<property>/carrier/elevators/elevator[2]/at-flight-deck</property>
</visible>
<legend>FLIGHT DECK</legend>
<pref-width>100</pref-width>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
<property>/carrier/elevators/elevator[2]/at-flight-deck</property>
</binding>
</button>
<button>
<row>1</row>
<col>1</col>
<visible>
<not>
<property>/carrier/elevators/elevator[2]/at-flight-deck</property>
</not>
</visible>
<legend>HANGAR DECK</legend>
<pref-width>100</pref-width>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
<property>/carrier/elevators/elevator[2]/at-flight-deck</property>
</binding>
</button>
<!-- 2nd -->
<text>
<row>2</row>
<col>1</col>
<label>2nd</label>
</text>
<!-- 2nd -->
<button>
<row>3</row>
<col>1</col>
<visible>
<property>/carrier/elevators/elevator[1]/at-flight-deck</property>
</visible>
<legend>FLIGHT DECK</legend>
<pref-width>100</pref-width>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
<property>/carrier/elevators/elevator[1]/at-flight-deck</property>
</binding>
</button>
<button>
<row>3</row>
<col>1</col>
<visible>
<not>
<property>/carrier/elevators/elevator[1]/at-flight-deck</property>
</not>
</visible>
<legend>HANGAR DECK</legend>
<pref-width>100</pref-width>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
<property>/carrier/elevators/elevator[1]/at-flight-deck</property>
</binding>
</button>
<!-- 4th -->
<text>
<row>4</row>
<col>0</col>
<label>4th</label>
</text>
<!-- 1st -->
<text>
<row>4</row>
<col>1</col>
<label>1st</label>
</text>
<!-- 4th -->
<button>
<row>5</row>
<col>0</col>
<visible>
<property>/carrier/elevators/elevator[3]/at-flight-deck</property>
</visible>
<legend>FLIGHT DECK</legend>
<pref-width>100</pref-width>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
<property>/carrier/elevators/elevator[3]/at-flight-deck</property>
</binding>
</button>
<button>
<row>5</row>
<col>0</col>
<visible>
<not>
<property>/carrier/elevators/elevator[3]/at-flight-deck</property>
</not>
</visible>
<legend>HANGAR DECK</legend>
<pref-width>100</pref-width>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
<property>/carrier/elevators/elevator[3]/at-flight-deck</property>
</binding>
</button>
<!-- 1st -->
<button>
<row>5</row>
<col>1</col>
<visible>
<property>/carrier/elevators/elevator[0]/at-flight-deck</property>
</visible>
<legend>FLIGHT DECK</legend>
<pref-width>100</pref-width>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
<property>/carrier/elevators/elevator[0]/at-flight-deck</property>
</binding>
</button>
<button>
<row>5</row>
<col>1</col>
<visible>
<not>
<property>/carrier/elevators/elevator[0]/at-flight-deck</property>
</not>
</visible>
<legend>HANGAR DECK</legend>
<pref-width>100</pref-width>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
<property>/carrier/elevators/elevator[0]/at-flight-deck</property>
</binding>
</button>
</group>
</group>
<hrule/>
<group>
<layout>vbox</layout>
<padding>6</padding>
<text>
<label>Flight Deck</label>
</text>
<group>
<layout>vbox</layout>
<checkbox>
<halign>left</halign>
<label>Runway lighting</label>
<property>/controls/lighting/deck-lights</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
</binding>
</checkbox>
<checkbox>
<halign>left</halign>
<label>Antennas</label>
<property>/carrier/antennas/enabled</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
</binding>
</checkbox>
</group>
</group>
<hrule/>
<group>
<layout>vbox</layout>
<padding>6</padding>
<text>
<label>Debug</label>
</text>
<group>
<layout>vbox</layout>
<checkbox>
<halign>left</halign>
<label>Enable ship movememnt</label>
<property>/carrier/fdm/settings/movement</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
</binding>
</checkbox>
<checkbox>
<halign>left</halign>
<label>Show Phalanx aim points</label>
<property>/carrier/phalanx/settings/show-debug-aim</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
</binding>
</checkbox>
</group>
</group>
<hrule/>
<group>
<layout>hbox</layout>
<default-padding>6</default-padding>
<empty><stretch>true</stretch></empty>
<button>
<legend>Close</legend>
<default>true</default>
<binding>
<command>dialog-close</command>
</binding>
</button>
</group>
</PropertyList>

View File

@ -1,39 +0,0 @@
<?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>
<default>
<menu n="10">
<label>CVN-70</label>
<enabled type="bool">true</enabled>
<item>
<label>Control Panel</label>
<binding>
<command>dialog-show</command>
<dialog-name>control-panel</dialog-name>
</binding>
</item>
</menu>
</default>
</PropertyList>

View File

@ -1,563 +0,0 @@
AC3Db
MATERIAL "Color_M07" rgb 0.227 0.227 0.227 amb 1.000 1.000 1.000 emis 0.000 0.000 0.000 spec 0.500 0.500 0.500 shi 12 trans 0.000
MATERIAL "Color_M03" rgb 0.667 0.667 0.667 amb 1.000 1.000 1.000 emis 0.000 0.000 0.000 spec 0.500 0.500 0.500 shi 12 trans 0.000
MATERIAL "Translucent_Glass_Blue" rgb 0.392 0.584 0.929 amb 1.000 1.000 1.000 emis 0.000 0.000 0.000 spec 0.500 0.500 0.500 shi 12 trans 0.502
OBJECT world
name "Blender_exporter_v2.17__towerSnowy1.ac"
kids 5
OBJECT poly
name "door"
data 4
ID11
crease 40.0
numvert 4
2 2 0
1 0 0
2 0 0
1 2 0
numsurf 2
SURF 0X10
mat 0
refs 3
0 0 0
1 0 0
2 0 0
SURF 0X10
mat 0
refs 3
1 0 0
0 0 0
3 0 0
kids 0
OBJECT poly
name "floor"
data 4
ID33
crease 40.0
numvert 32
3.75 13 -7.25
4 12 -3
3.75 13 -2.75
4 12 -7
4 12 -7
3.75 13 -7.25
4 12 -3
3.75 13 -2.75
8.25 13 -2.75
4 12 -3
8 12 -3
3.75 13 -2.75
3.75 13 -2.75
8.25 13 -2.75
4 12 -3
8 12 -3
3.75 13 -7.25
8 12 -7
4 12 -7
8.25 13 -7.25
8.25 13 -7.25
3.75 13 -7.25
8 12 -7
4 12 -7
8 12 -3
8.25 13 -7.25
8.25 13 -2.75
8 12 -7
8 12 -7
8 12 -3
8.25 13 -7.25
8.25 13 -2.75
numsurf 16
SURF 0X10
mat 1
refs 3
0 0 0
1 0 0
2 0 0
SURF 0X10
mat 1
refs 3
1 0 0
0 0 0
3 0 0
SURF 0X10
mat 1
refs 3
4 0 0
5 0 0
6 0 0
SURF 0X10
mat 1
refs 3
7 0 0
6 0 0
5 0 0
SURF 0X10
mat 1
refs 3
8 0 0
9 0 0
10 0 0
SURF 0X10
mat 1
refs 3
9 0 0
8 0 0
11 0 0
SURF 0X10
mat 1
refs 3
12 0 0
13 0 0
14 0 0
SURF 0X10
mat 1
refs 3
15 0 0
14 0 0
13 0 0
SURF 0X10
mat 1
refs 3
16 0 0
17 0 0
18 0 0
SURF 0X10
mat 1
refs 3
17 0 0
16 0 0
19 0 0
SURF 0X10
mat 1
refs 3
20 0 0
21 0 0
22 0 0
SURF 0X10
mat 1
refs 3
23 0 0
22 0 0
21 0 0
SURF 0X10
mat 1
refs 3
24 0 0
25 0 0
26 0 0
SURF 0X10
mat 1
refs 3
25 0 0
24 0 0
27 0 0
SURF 0X10
mat 1
refs 3
28 0 0
29 0 0
30 0 0
SURF 0X10
mat 1
refs 3
31 0 0
30 0 0
29 0 0
kids 0
OBJECT poly
name "glass"
data 4
ID19
crease 40.0
numvert 32
3 16 -8
8.25 13 -7.25
3.75 13 -7.25
9 16 -8
9 16 -8
3 16 -8
8.25 13 -7.25
3.75 13 -7.25
8.25 13 -2.75
9 16 -8
9 16 -2
8.25 13 -7.25
8.25 13 -7.25
8.25 13 -2.75
9 16 -8
9 16 -2
3 16 -8
3.75 13 -2.75
3 16 -2
3.75 13 -7.25
3.75 13 -7.25
3 16 -8
3.75 13 -2.75
3 16 -2
9 16 -2
3.75 13 -2.75
8.25 13 -2.75
3 16 -2
3 16 -2
9 16 -2
3.75 13 -2.75
8.25 13 -2.75
numsurf 16
SURF 0X10
mat 2
refs 3
0 0 0
1 0 0
2 0 0
SURF 0X10
mat 2
refs 3
1 0 0
0 0 0
3 0 0
SURF 0X10
mat 2
refs 3
4 0 0
5 0 0
6 0 0
SURF 0X10
mat 2
refs 3
7 0 0
6 0 0
5 0 0
SURF 0X10
mat 2
refs 3
8 0 0
9 0 0
10 0 0
SURF 0X10
mat 2
refs 3
9 0 0
8 0 0
11 0 0
SURF 0X10
mat 2
refs 3
12 0 0
13 0 0
14 0 0
SURF 0X10
mat 2
refs 3
15 0 0
14 0 0
13 0 0
SURF 0X10
mat 2
refs 3
16 0 0
17 0 0
18 0 0
SURF 0X10
mat 2
refs 3
17 0 0
16 0 0
19 0 0
SURF 0X10
mat 2
refs 3
20 0 0
21 0 0
22 0 0
SURF 0X10
mat 2
refs 3
23 0 0
22 0 0
21 0 0
SURF 0X10
mat 2
refs 3
24 0 0
25 0 0
26 0 0
SURF 0X10
mat 2
refs 3
25 0 0
24 0 0
27 0 0
SURF 0X10
mat 2
refs 3
28 0 0
29 0 0
30 0 0
SURF 0X10
mat 2
refs 3
31 0 0
30 0 0
29 0 0
kids 0
OBJECT poly
name "roof"
data 4
ID27
crease 40.0
numvert 4
9 16 -2
3 16 -8
3 16 -2
9 16 -8
numsurf 2
SURF 0X10
mat 1
refs 3
0 0 0
1 0 0
2 0 0
SURF 0X10
mat 1
refs 3
1 0 0
0 0 0
3 0 0
kids 0
OBJECT poly
name "structure"
data 3
ID3
crease 40.0
numvert 48
8 0 -7
0 0 0
0 0 -7
1 0 0
2 0 0
8 0 0
8 3 0
2 0 0
8 0 0
2 2 0
1 2 0
0 0 0
1 0 0
0 3 0
0 3 -7
0 0 0
0 3 0
0 0 -7
0 3 -7
8 0 -7
0 0 -7
4 3 -7
8 12 -7
4 12 -7
8 0 -7
8 3 0
8 0 0
8 3 -3
8 12 -3
8 12 -7
0 3 0
4 3 -3
0 3 -7
8 3 0
8 3 -3
4 3 -7
4 12 -7
4 3 -3
4 12 -3
4 3 -7
8 12 -3
4 12 -7
4 12 -3
8 12 -7
8 12 -3
4 3 -3
8 3 -3
4 12 -3
numsurf 30
SURF 0X10
mat 1
refs 3
0 0 0
1 0 0
2 0 0
SURF 0X10
mat 1
refs 3
1 0 0
0 0 0
3 0 0
SURF 0X10
mat 1
refs 3
3 0 0
0 0 0
4 0 0
SURF 0X10
mat 1
refs 3
4 0 0
0 0 0
5 0 0
SURF 0X10
mat 1
refs 3
6 0 0
7 0 0
8 0 0
SURF 0X10
mat 1
refs 3
7 0 0
6 0 0
9 0 0
SURF 0X10
mat 1
refs 3
9 0 0
6 0 0
10 0 0
SURF 0X10
mat 1
refs 3
10 0 0
11 0 0
12 0 0
SURF 0X10
mat 1
refs 3
11 0 0
10 0 0
13 0 0
SURF 0X10
mat 1
refs 3
13 0 0
10 0 0
6 0 0
SURF 0X10
mat 1
refs 3
14 0 0
15 0 0
16 0 0
SURF 0X10
mat 1
refs 3
15 0 0
14 0 0
17 0 0
SURF 0X10
mat 1
refs 3
18 0 0
19 0 0
20 0 0
SURF 0X10
mat 1
refs 3
19 0 0
18 0 0
21 0 0
SURF 0X10
mat 1
refs 3
19 0 0
21 0 0
22 0 0
SURF 0X10
mat 1
refs 3
22 0 0
21 0 0
23 0 0
SURF 0X10
mat 1
refs 3
24 0 0
25 0 0
26 0 0
SURF 0X10
mat 1
refs 3
25 0 0
24 0 0
27 0 0
SURF 0X10
mat 1
refs 3
27 0 0
24 0 0
28 0 0
SURF 0X10
mat 1
refs 3
28 0 0
24 0 0
29 0 0
SURF 0X10
mat 1
refs 3
30 0 0
31 0 0
32 0 0
SURF 0X10
mat 1
refs 3
31 0 0
30 0 0
33 0 0
SURF 0X10
mat 1
refs 3
31 0 0
33 0 0
34 0 0
SURF 0X10
mat 1
refs 3
35 0 0
32 0 0
31 0 0
SURF 0X10
mat 1
refs 3
36 0 0
37 0 0
38 0 0
SURF 0X10
mat 1
refs 3
37 0 0
36 0 0
39 0 0
SURF 0X10
mat 1
refs 3
40 0 0
41 0 0
42 0 0
SURF 0X10
mat 1
refs 3
41 0 0
40 0 0
43 0 0
SURF 0X10
mat 1
refs 3
44 0 0
45 0 0
46 0 0
SURF 0X10
mat 1
refs 3
45 0 0
44 0 0
47 0 0
kids 0

View File

@ -1,126 +0,0 @@
var clamp = func(v, min, max) { v < min ? min : v > max ? max : v }
var TRUE = 1;
var FALSE = 0;
#
# Install: Include this code into an aircraft to make it damagable. (remember to add it to the -set file)
#
# Author: Nikolai V. Chr. (with some improvement by Onox and Pinto)
#
#
var cannon_types = {
" M70 rocket hit": 0.25, #135mm
" M55 cannon shell hit": 0.10, # 30mm
" KCA cannon shell hit": 0.10, # 30mm
" Gun Splash On ": 0.10, # 30mm
" M61A1 shell hit": 0.05, # 20mm
" GAU-8/A hit": 0.10, # 30mm
" BK27 cannon hit": 0.07, # 27mm
" GSh-30 hit": 0.10, # 30mm
" 7.62 hit": 0.30, #UH-1
" 50 BMG hit": 0.20, #p-47
};
var players = {
"pinto": 1,
"OPFOR77": 2,
"Leto": 1,
"swamp": 2,
};
var incoming_listener = func {
var history = getprop("/sim/multiplay/chat-history");
var hist_vector = split("\n", history);
if (size(hist_vector) > 0) {
var last = hist_vector[size(hist_vector)-1];
var last_vector = split(":", last);
var author = last_vector[0];
var callsign = getprop("sim/multiplay/callsign");
if (size(last_vector) > 1 and author != callsign) {
# not myself
#print("not me");
if (1==1) { # mirage: getprop("/controls/armament/mp-messaging")
# latest version of failure manager and taking damage enabled
#print("damage enabled");
var last1 = split(" ", last_vector[1]);
if (cannon_types[last_vector[1]] != nil) {
# cannon hitting someone
print("cannon");
if (size(last_vector) > 2 and last_vector[2] == " "~callsign) {
print("cannon hit us");
process_hit(author);
}
}
}
}
}
}
var last_update_time = "/aa_tower/last-update-time";
var owning_team = "/aa_tower/owning_team";
var score_team_1 = "/aa_tower/score-team-1";
var score_team_2 = "/aa_tower/score-team-2";
setprop(last_update_time, -1);
setprop(owning_team, 0);
setprop(score_team_1, 0);
setprop(score_team_2, 0);
var process_hit = func (perp) {
print("processing hit by: " ~ perp);
if ( players[perp] != nil ) {
if ( players[perp] != getprop(owning_team) ) {
setprop(last_update_time,systime());
setprop(owning_team, players[perp]);
setprop("/aa_tower/score-team-" ~ players[perp], getprop("/aa_tower/score-team-" ~ players[perp]) + 1);
setprop("/sim/multiplay/chat","Ownership transferred to team: " ~ players[perp]);
write_xml();
}
}
}
var update = func () {
var o_t = getprop(owning_team);
if(o_t > 0) {
if(systime() > getprop(last_update_time) + 300) {
print("Adding point to team: " ~ o_t);
setprop("/sim/multiplay/chat","Adding point to team: " ~ o_t);
setprop("/aa_tower/score-team-" ~ o_t, getprop("/aa_tower/score-team-" ~ o_t) + 1);
setprop(last_update_time, systime());
write_xml();
}
}
settimer(func(){update();},10);
}
update();
var twr_base = "/aa_tower/";
var filename_base = getprop("/sim/fg-home") ~ "/Export/tower-";
var write_xml = func() {
io.write_properties( path: filename_base ~ rand() ~ ".xml", prop: twr_base );
}
var callsign_struct = {};
var getCallsign = func (callsign) {
var node = callsign_struct[callsign];
return node;
}
var processCallsigns = func () {
callsign_struct = {};
var players = props.globals.getNode("ai/models").getChildren();
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();
callsign_struct[callsign] = player;
}
}
settimer(processCallsigns, 1.5);
}
processCallsigns();
setlistener("/sim/multiplay/chat-history", incoming_listener, 0, 0);

View File

@ -1,44 +0,0 @@
# 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/>.
#io.include("Aircraft/ExpansionPack/Nasal/init.nas");
#with("updateloop");
# Number of iterations per second
var frequency = 60.0;
# Change in heading per second at full rudder deflection
var heading_ps = 0.5;
time_last = 0;
sim_speed = 1;
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 PositionUpdater = func () {
# does a building need an FDM?
# nawwwwwww
settimer( PositionUpdater, 1/frequency );
};
PositionUpdater();

View File

@ -1,125 +0,0 @@
<?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>
<description>tower</description>
<status>alpha</status>
<aircraft-version>0.1</aircraft-version>
<flight-model>null</flight-model>
<aero>KPN-D</aero>
<aircraft-operator>KPN</aircraft-operator>
<model>
<path>Aircraft/tower/Models/tower.xml</path>
<!-- Uncloak weather balloons visiting Earth -->
<always-show-in-MP type="bool">true</always-show-in-MP>
</model>
<sound>
<path>Sounds/sound.xml</path>
</sound>
<presets>
<onground>true</onground>
</presets>
<startup>
<splash-texture>Aircraft/tower/splash1.png</splash-texture>
</startup>
<current-view>
<deck-park type="bool">true</deck-park>
<z-offset-dec-step type="double">0.0</z-offset-dec-step>
<z-offset-inc-step type="double">0.0</z-offset-inc-step>
<can-change-z-offset type="bool">false</can-change-z-offset>
<z-offset-min-m type="float">100.0</z-offset-min-m>
<z-offset-max-m type="float">2000.0</z-offset-max-m>
</current-view>
<systems>
<autopilot>
<path>Systems/fbw.xml</path>
</autopilot>
<autopilot>
<path>Systems/fdm.xml</path>
</autopilot>
</systems>
<multiplay>
<generic>
<int n="0" type="int">0</int>
</generic>
</multiplay>
</sim>
<nasal>
<carrier>
<file>Aircraft/tower/Nasal/fdm.nas</file>
</carrier>
<damage>
<file>Aircraft/tower/Nasal/damage.nas</file>
</damage>
</nasal>
</PropertyList>