MP Carrier fixes for loading
Generally this change proves that we probably don't need the MPCarrier model on the target system - because by using the fallback model to load the Nasal this will happen without needing the high detail models at all. To support this : - Added fallback models for all carriers (defined as AI scenarios) - Added logic to fallback models so that MP carriers load correctly - The model will still be the AI model. - MPCarriers.nas from MPCarrier/systems now in Aircraft/Generic
This commit is contained in:
parent
a23313176c
commit
d9ffc50011
11 changed files with 1169 additions and 0 deletions
|
@ -28,6 +28,7 @@
|
|||
551-600 Military large aircraft (tankers, transports)
|
||||
601-700 Helicopters
|
||||
701-800 Other
|
||||
801-900 Maritime
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
|
@ -181,4 +182,14 @@ AI model. We also want to load it in preference to the default glider because i
|
|||
then be invisible to other MP players who are not in a UFO themselves. -->
|
||||
<model n="712" type="string">Aircraft/ufo/Models/ufo.xml</model>
|
||||
|
||||
<model n="801" type="string">AI/Maritime/MP-Carriers/mp-nimitz-0.xml</model>
|
||||
<model n="802" type="string">AI/Maritime/MP-Carriers/mp-vinson-0.xml</model>
|
||||
<model n="803" type="string">AI/Maritime/MP-Carriers/mp-eisenhower-0.xml</model>
|
||||
<model n="804" type="string">AI/Maritime/MP-Carriers/mp-truman-0.xml</model>
|
||||
<model n="805" type="string">AI/Maritime/MP-Carriers/mp-clemenceau-0.xml</model>
|
||||
<model n="806" type="string">AI/Maritime/MP-Carriers/mp-foch-0.xml</model>
|
||||
<model n="807" type="string">AI/Maritime/MP-Carriers/mp-kuznetsov-0.xml</model>
|
||||
<model n="808" type="string">AI/Maritime/MP-Carriers/mp-liaoning-0.xml</model>
|
||||
<model n="809" type="string">AI/Maritime/MP-Carriers/mp-sanantonio-0.xml</model>
|
||||
|
||||
</PropertyList>
|
||||
|
|
60
AI/Maritime/MP-Carriers/mp-clemenceau-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-clemenceau-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Clemenceau fallback model. ID# 806
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Clemenceau(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/clemenceau-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Clemenceau",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Clemenceau(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 3); # 3 second delay should be sufficient
|
||||
print("MP Clemenceau(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Clemenceau(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
60
AI/Maritime/MP-Carriers/mp-eisenhower-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-eisenhower-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Eisenhower fallback model. ID# 803
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Eisenhower(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/eisenhower-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Eisenhower",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Eisenhower(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 3); # 3 second delay should be sufficient
|
||||
print("MP Eisenhower(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Eisenhower(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
60
AI/Maritime/MP-Carriers/mp-foch-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-foch-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Foch fallback model. ID# 807
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Foch(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/foch-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Foch",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Foch(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 3); # 3 second delay should be sufficient
|
||||
print("MP Foch(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Foch(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
60
AI/Maritime/MP-Carriers/mp-kuznetsov-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-kuznetsov-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Kuznetsov fallback model. ID# 808
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Kuznetsov(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/kuznetsov-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Kuznetsov",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Kuznetsov(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 3); # 3 second delay should be sufficient
|
||||
print("MP Kuznetsov(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Kuznetsov(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
60
AI/Maritime/MP-Carriers/mp-liaoning-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-liaoning-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Liaoning fallback model. ID# 809
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Liaoning(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/liaoning-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Liaoning",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Liaoning(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 3); # 3 second delay should be sufficient
|
||||
print("MP Liaoning(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Liaoning(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
60
AI/Maritime/MP-Carriers/mp-nimitz-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-nimitz-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Nimitz fallback model. ID# 801
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Nimitz(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/nimitz-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Nimitz",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Nimitz(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 15); # delay to prevent recursion.
|
||||
print("MP Nimitz(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Nimitz(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
60
AI/Maritime/MP-Carriers/mp-sanantonio-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-sanantonio-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Sanantonio fallback model. ID# 810
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Sanantonio(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/sanantonio-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Sanantonio",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Sanantonio(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 3); # 3 second delay should be sufficient
|
||||
print("MP Sanantonio(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Sanantonio(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
60
AI/Maritime/MP-Carriers/mp-truman-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-truman-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Truman fallback model. ID# 804
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Truman(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/truman-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Truman",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Truman(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 3); # 3 second delay should be sufficient
|
||||
print("MP Truman(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Truman(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
60
AI/Maritime/MP-Carriers/mp-vinson-0.xml
Normal file
60
AI/Maritime/MP-Carriers/mp-vinson-0.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Multiplayer carrier Vinson fallback model. ID# 805
|
||||
|
||||
This will connect the MP carrier to the AI carrier when the low detail model is loaded.
|
||||
Later on if the high detail model is also loaded it will be still be good
|
||||
because the logic is resilient enough not to trample over itself.
|
||||
|
||||
Copyright (C) 2021 : Richard Harrison rjh@zaretto.com
|
||||
Copyright (C) 2007 - 2016 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
|
||||
This file is released under the GPL license version 2 or later.
|
||||
-->
|
||||
<PropertyList>
|
||||
|
||||
<nasal>
|
||||
<load>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
# This logic connects the carrier to the AI carrier
|
||||
|
||||
var rplayer = cmdarg();
|
||||
print("MP Vinson(Fallback): LOAD " ~ rplayer.getPath());
|
||||
|
||||
# Load the main MPCarriers Nasal module if needed.
|
||||
if (!contains(globals, "MPCarriers")) {
|
||||
var base = "Aircraft/Generic/MPCarriers.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriers");
|
||||
}
|
||||
|
||||
# Create manager class.
|
||||
var manager = nil;
|
||||
var accept_callsign = "/sim/mp-carriers/vinson-callsign";
|
||||
|
||||
var init = func {
|
||||
# Initialize the callsign property if not done already.
|
||||
props.globals.initNode(accept_callsign, "", "STRING");
|
||||
|
||||
manager = MPCarriers.Manager.new(rplayer,
|
||||
"Vinson",
|
||||
props.globals.getNode(accept_callsign));
|
||||
print("MP Vinson(Fallback): " ~ rplayer.getPath() ~ " done.");
|
||||
}
|
||||
|
||||
settimer(init, 3); # 3 second delay should be sufficient
|
||||
print("MP Vinson(Fallback): " ~ rplayer.getPath() ~ " waiting.");
|
||||
##############################################################################
|
||||
]]>
|
||||
</load>
|
||||
<unload>
|
||||
<![CDATA[
|
||||
##############################################################################
|
||||
print("MP Vinson(Fallback): unload", cmdarg().getPath());
|
||||
if (manager != nil) manager.die();
|
||||
##############################################################################
|
||||
]]>
|
||||
</unload>
|
||||
</nasal>
|
||||
|
||||
</PropertyList>
|
618
Aircraft/Generic/MPCarriers.nas
Normal file
618
Aircraft/Generic/MPCarriers.nas
Normal file
|
@ -0,0 +1,618 @@
|
|||
###############################################################################
|
||||
##
|
||||
## Nasal module for connecting a local AI carrier to a MP player.
|
||||
##
|
||||
## Copyright (C) 2007 - 2012 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
## Copyright (C) 2009 Vivian Meazza
|
||||
## This file is licensed under the GPL license version 2 or later.
|
||||
##
|
||||
###############################################################################
|
||||
|
||||
# NOTE:
|
||||
# This module is intended to be loaded under the name MPCarriers.
|
||||
|
||||
# To see what is happening with multiplayer/ai carriers, look in
|
||||
# /ai/models/carrier[]/mp-control/.
|
||||
#
|
||||
|
||||
# If this is true, we auto-enable ai scenarios and auto-attach ai carriers to
|
||||
# mp carriers.
|
||||
#
|
||||
var g_auto_attach = props.globals.getNode("/sim/mp-carriers/auto-attach", 1);
|
||||
printf("g_auto_attach.getValue()=%s", g_auto_attach.getValue());
|
||||
|
||||
# Constants
|
||||
var lat = "position/latitude-deg";
|
||||
var lon = "position/longitude-deg";
|
||||
var alt = "position/altitude-ft";
|
||||
var c_heading = "orientation/true-heading-deg";
|
||||
var c_pitch = "orientation/pitch-deg";
|
||||
var c_roll = "orientation/roll-deg";
|
||||
var c_speed = "velocities/speed-kts";
|
||||
var x = "position/global-x";
|
||||
var y = "position/global-y";
|
||||
var z = "position/global-z";
|
||||
|
||||
#var c_control_speed = "controls/base-speed-kts";
|
||||
#var c_control_course = "controls/base-course-deg";
|
||||
var c_control_speed = "controls/tgt-speed-kts";
|
||||
var c_control_course = "controls/tgt-heading-degs";
|
||||
var c_wave_off_lights = "controls/flols/wave-off-lights";
|
||||
|
||||
|
||||
var c_control_mp_ctrl = "controls/mp-control";
|
||||
|
||||
var c_deck_elev = "controls/elevators";
|
||||
var c_deck_lights = "controls/lighting/deck-lights";
|
||||
var c_flood_lights = "controls/lighting/flood-lights-red-norm";
|
||||
var c_turn_to_launch_hdg = "controls/turn-to-launch-hdg";
|
||||
var c_turn_to_recvry_hdg = "controls/turn-to-recovery-hdg";
|
||||
var c_turn_to_base_co = "controls/turn-to-base-course";
|
||||
|
||||
|
||||
var mp_heading = "orientation/true-heading-deg";
|
||||
var mp_pitch = "orientation/pitch-deg";
|
||||
var mp_roll = "orientation/roll-deg";
|
||||
|
||||
# MP transmitted controls
|
||||
var mp_speed = "surface-positions/flap-pos-norm";
|
||||
var mp_rudder = "surface-positions/rudder-pos-norm";
|
||||
var mp_network = "sim/multiplay/generic/string[0]";
|
||||
var mp_message = "sim/multiplay/generic/string[2]";
|
||||
var mp_tgt_hdg = "sim/multiplay/generic/float[0]";
|
||||
var mp_tgt_spd = "sim/multiplay/generic/float[1]";
|
||||
var mp_turn_radius = "sim/multiplay/generic/float[2]";
|
||||
|
||||
# Controller parameters.
|
||||
var cross_course_gain = 0.2;
|
||||
var cross_course_fadeout = 100.0;
|
||||
var cross_course_limit = 20.0;
|
||||
|
||||
###############################################################################
|
||||
# Manager class for one model instance.
|
||||
var Manager = {};
|
||||
##################################################
|
||||
Manager.new = func (player = nil, carrier_name = nil, callsign = nil) {
|
||||
# e.g. carrier_name = 'Clemenceau'.
|
||||
printf("Manager.new(): player=%s carrier_name=%s callsign=%s",
|
||||
player, carrier_name, callsign);
|
||||
|
||||
if (g_auto_attach.getValue()) {
|
||||
# Look for matching ai scenario and enable it. We don't care if it is
|
||||
# already enabled - FGAIManager::loadScenarioCommand() will know to do
|
||||
# nothing.
|
||||
printf("Checking ai scenarios...");
|
||||
foreach (var n; props.globals.getNode("sim/ai/scenarios", 1).getChildren("scenario")) {
|
||||
var n_carrier_name = n.getValue("carrier/name");
|
||||
var n_scenario_id = n.getValue("id"); # e.g. clemenceau_demo.
|
||||
if (n_carrier_name != nil) {
|
||||
if (0) {
|
||||
printf(" %s: id=%s n_carrier_name=%s",
|
||||
n.getPath(),
|
||||
n_scenario_id,
|
||||
n_carrier_name
|
||||
);
|
||||
}
|
||||
if (n_carrier_name == carrier_name) {
|
||||
printf("calling load-scenario with id=%s", n_scenario_id);
|
||||
var args = props.Node.new( { name: n_scenario_id});
|
||||
var e = fgcommand("load-scenario", args);
|
||||
printf("fgcommand('load-scenario') returned e=%s", e);
|
||||
if (e) {
|
||||
# We have loaded scenario.
|
||||
gui.popupTip(sprintf("Have loaded AI senario: %s", n_scenario_id));
|
||||
}
|
||||
else {
|
||||
# Error, or scenario was already loaded.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Enabled scenarios are:");
|
||||
foreach (var n; props.globals.getNode("sim/ai", 1).getChildren("scenario")) {
|
||||
printf(" %s", n.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
var obj = { parents : [Manager],
|
||||
rplayer : player,
|
||||
carrier_name : carrier_name,
|
||||
carrier : nil,
|
||||
accept_callsign : callsign,
|
||||
callsign_listener : nil,
|
||||
FREEZE_DIST : 400.0,
|
||||
comms : nil,
|
||||
message : nil,
|
||||
loopid : 0 };
|
||||
|
||||
var carriers = props.globals.getNode("/ai/models").getChildren("carrier");
|
||||
|
||||
foreach(var c; carriers) {
|
||||
if (c.getNode("name").getValue() == carrier_name) {
|
||||
|
||||
obj.carrier = c;
|
||||
printf("Initializing carrier_name=%s player.getPath()=%s",
|
||||
carrier_name, player.getPath());
|
||||
obj.callsign_listener =
|
||||
setlistener(callsign,
|
||||
func { print("Callsign update");
|
||||
obj.start(); });
|
||||
MPCarriersNW.Manager_instances[player.getIndex()] = obj;
|
||||
obj.start();
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
printf("Failed to find carrier_name=%s. The relevant carrier AI scenario must be active", carrier_name);
|
||||
|
||||
return nil;
|
||||
}
|
||||
##################################################
|
||||
Manager.is_valid = func {
|
||||
return ((me.rplayer.getNode("valid") != nil) and
|
||||
me.rplayer.getNode("valid").getValue() and
|
||||
(me.rplayer.getNode("callsign") != nil));
|
||||
}
|
||||
##################################################
|
||||
Manager.is_active = func {
|
||||
var a = me.is_valid();
|
||||
var b = (me.rplayer.getNode("callsign") != nil);
|
||||
# FIXME: Sometimes the cmp() call here gets an invalid argument.
|
||||
var c = (cmp(me.rplayer.getNode("callsign").getValue(), me.accept_callsign.getValue()) == 0);
|
||||
if (g_auto_attach.getValue()) {
|
||||
# Always attach, regardless of callsign.
|
||||
c = 1;
|
||||
}
|
||||
return (a and b and c);
|
||||
}
|
||||
##################################################
|
||||
Manager.set_property = func (path, value) {
|
||||
if (!me.is_valid() or !me.is_active()) return;
|
||||
me.carrier.getNode(path).setValue(value);
|
||||
}
|
||||
##################################################
|
||||
Manager.update = func {
|
||||
var aircraft_pos = geo.aircraft_position();
|
||||
var carrier_pos = geo.Coord.new(aircraft_pos);
|
||||
|
||||
if (!me.is_valid()) {
|
||||
# This carrier player is not valid anymore.
|
||||
if (0) printf("calling me.die() because !me.is_valid()");
|
||||
me.die();
|
||||
return;
|
||||
}
|
||||
if (!me.is_active()) {
|
||||
# This carrier player is not the chosen one. Go idle.
|
||||
if (0) printf("calling me.stop(). me.is_valid()=%s me.rplayer.getNode('callsign').getValue()=%s me.accept_callsign.getValue()=%s",
|
||||
me.is_valid(),
|
||||
me.rplayer.getNode('callsign').getValue(),
|
||||
me.accept_callsign.getValue()
|
||||
);
|
||||
me.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
# LSO comms
|
||||
var message = me.rplayer.getNode(mp_message).getValue();
|
||||
if (message != ""){
|
||||
|
||||
if (message != me.message){
|
||||
setprop("/sim/messages/approach", message);
|
||||
}
|
||||
|
||||
me.message = message;
|
||||
}
|
||||
|
||||
# carrier_pos.set_latlon(me.carrier.getNode(lat).getValue(),
|
||||
# me.carrier.getNode(lon).getValue(),
|
||||
# me.carrier.getNode(alt).getValue());
|
||||
|
||||
carrier_pos.set_xyz(me.carrier.getNode(x).getValue(),
|
||||
me.carrier.getNode(y).getValue(),
|
||||
me.carrier.getNode(z).getValue());
|
||||
|
||||
# Compute the position and orientation error.
|
||||
var rplayer_pos = geo.Coord.new(carrier_pos);
|
||||
# rplayer_pos.set_latlon(me.rplayer.getNode(lat).getValue(),
|
||||
# me.rplayer.getNode(lon).getValue(),
|
||||
# me.rplayer.getNode(alt).getValue());
|
||||
|
||||
rplayer_pos.set_xyz(me.rplayer.getNode(x).getValue(),
|
||||
me.rplayer.getNode(y).getValue(),
|
||||
me.rplayer.getNode(z).getValue());
|
||||
|
||||
var master_course = normalize_course(me.rplayer.getNode(mp_heading).getValue());
|
||||
var master_speed = me.rplayer.getNode(mp_speed).getValue();
|
||||
var bearing_to_master = normalize_course(carrier_pos.course_to(rplayer_pos));
|
||||
var distance_to_master = carrier_pos.direct_distance_to(rplayer_pos);
|
||||
var v = D2R * normalize_course(bearing_to_master - master_course);
|
||||
var cross_track_error = distance_to_master * math.sin(v);
|
||||
var along_track_error = distance_to_master * math.cos(v);
|
||||
var master_tgt_hdg = as_num(me.rplayer.getNode(mp_tgt_hdg).getValue(),
|
||||
me.rplayer.getNode(mp_heading).getValue());
|
||||
var master_tgt_spd = as_num(me.rplayer.getNode(mp_tgt_spd).getValue(),
|
||||
me.rplayer.getNode(mp_speed).getValue());
|
||||
var master_turn_radius = as_num(me.rplayer.getNode(mp_turn_radius).getValue());
|
||||
|
||||
var diff = master_course - master_tgt_hdg;
|
||||
|
||||
if (diff > 180)
|
||||
diff -= 360;
|
||||
elsif (diff < -180)
|
||||
diff += 360;
|
||||
|
||||
me.carrier.getNode("mp-control/ai-mp-course-delta", 1).setValue(diff);
|
||||
|
||||
if ( diff < -1.0 or diff > 1.0){
|
||||
me.carrier.getNode("mp-control/ai-mp-course-delta-type", 1).setValue("major");
|
||||
# major course alteration - we'll just use target heading from
|
||||
# master until it's nearly complete
|
||||
# print("major turn" , diff);
|
||||
var set_course = master_tgt_hdg ;
|
||||
var correction = 0;
|
||||
|
||||
if (diff < 0){
|
||||
correction = -cross_track_error * M2FT;
|
||||
# print("stbd turn ", correction);
|
||||
} elsif (diff > 0){
|
||||
correction = cross_track_error * M2FT;
|
||||
# print("port turn ", correction);
|
||||
} else {
|
||||
correction = 0;
|
||||
# print("no turn ", correction);
|
||||
}
|
||||
|
||||
me.carrier.getNode("controls/turn-radius-ft", 1).setValue(master_turn_radius + correction);
|
||||
|
||||
} else {
|
||||
# Use Controller.
|
||||
me.carrier.getNode("mp-control/ai-mp-course-delta-type", 1).setValue("minor");
|
||||
me.carrier.getNode("controls/turn-radius-ft", 1).setValue(master_turn_radius);
|
||||
var set_course =
|
||||
normalize_course(180.0/math.pi *
|
||||
(math.abs(cross_track_error) < cross_course_fadeout ?
|
||||
math.pow
|
||||
(math.abs(cross_track_error/cross_course_fadeout),2) :
|
||||
1.0) *
|
||||
math.atan2(cross_course_gain * cross_track_error,
|
||||
along_track_error) +
|
||||
master_course);
|
||||
# Limit the course to +/-cross_course_limit degrees off the master's course.
|
||||
if (set_course - master_course > cross_course_limit) {
|
||||
set_course = normalize_course(master_course + cross_course_limit);
|
||||
} else if (set_course - master_course < -cross_course_limit) {
|
||||
set_course = normalize_course(master_course - cross_course_limit);
|
||||
}
|
||||
|
||||
}
|
||||
var spd_diff = master_speed - master_tgt_spd;
|
||||
|
||||
me.carrier.getNode("mp-control/ai-mp-speed-delta", 1).setValue(spd_diff);
|
||||
if ( spd_diff < -1 or spd_diff > 1){
|
||||
# major speed alteration - we'll just use target speed from
|
||||
# master until it's nearly complete
|
||||
me.carrier.getNode("mp-control/ai-mp-speed-delta-type", 1).setValue("major");
|
||||
var set_speed = master_tgt_spd +
|
||||
0.01 * along_track_error;
|
||||
if (set_speed > master_tgt_spd + 5.0) set_speed = master_tgt_spd + 5.0;
|
||||
if (set_speed < master_tgt_spd - 5.0) set_speed = master_tgt_spd - 5.0;
|
||||
} else {
|
||||
me.carrier.getNode("mp-control/ai-mp-speed-delta-type", 1).setValue("minor");
|
||||
var set_speed = master_speed +
|
||||
0.01 * along_track_error;
|
||||
if (set_speed > master_speed + 5.0) set_speed = master_speed + 5.0;
|
||||
if (set_speed < master_speed - 5.0) set_speed = master_speed - 5.0;
|
||||
}
|
||||
|
||||
# publish controller settings to /ai/models/carrier[]/mp-control/.
|
||||
#
|
||||
me.carrier.getNode("mp-control/bearing-to-master-rel-deg", 1).setValue(v);
|
||||
me.carrier.getNode("mp-control/bearing-to-master-deg", 1).setValue(bearing_to_master);
|
||||
me.carrier.getNode("mp-control/distance-to-master-m", 1).setValue(distance_to_master);
|
||||
me.carrier.getNode("mp-control/cross-track-error-m", 1).setValue(cross_track_error);
|
||||
me.carrier.getNode("mp-control/along-track-error-m", 1).setValue(along_track_error);
|
||||
me.carrier.getNode("mp-control/freeze-distance", 1).setValue(me.FREEZE_DIST);
|
||||
|
||||
me.carrier.getNode("mp-control/master-speed-kts", 1).setValue(master_speed);
|
||||
me.carrier.getNode("mp-control/master-course-deg", 1).setValue(master_course);
|
||||
|
||||
me.carrier.getNode("mp-control/set-speed-kts", 1).setValue(set_speed);
|
||||
me.carrier.getNode("mp-control/set-course-deg", 1).setValue(set_course);
|
||||
me.carrier.getNode("mp-control/tgt-hdg-deg", 1).setValue(sprintf ( "%03.1d", master_tgt_hdg));
|
||||
me.carrier.getNode("mp-control/tgt-spd-kts", 1).setValue(master_tgt_spd);
|
||||
me.carrier.getNode("mp-control/turn-radius-ft", 1).setValue(master_turn_radius);
|
||||
|
||||
# We latch ai and mp carrier positions if user aircraft is more than
|
||||
# me.FREEZE_DIST away from ai carrier, or if we are in replay mode.
|
||||
#
|
||||
var distance_aircraft_carrier = aircraft_pos.direct_distance_to(carrier_pos);
|
||||
var in_replay = props.globals.getValue("/sim/replay/replay-state");
|
||||
var do_latch = (distance_aircraft_carrier > me.FREEZE_DIST or in_replay);
|
||||
var distance_ai_to_mpcarrier = rplayer_pos.direct_distance_to(carrier_pos);
|
||||
|
||||
me.carrier.getNode("mp-control/aircraft-ai-distance", 1).setValue(distance_aircraft_carrier);
|
||||
me.carrier.getNode("mp-control/ai-mp-latched", do_latch);
|
||||
|
||||
if (do_latch) {
|
||||
# Latch the local AI carrier to the remote player's
|
||||
# location only when the local player is far enough away not
|
||||
# to suffer side effects.
|
||||
me.carrier.getNode(lat).setValue(me.rplayer.getNode(lat).getValue());
|
||||
me.carrier.getNode(lon).setValue(me.rplayer.getNode(lon).getValue());
|
||||
me.carrier.getNode(alt).setValue(me.rplayer.getNode(alt).getValue());
|
||||
|
||||
me.carrier.getNode(c_heading).
|
||||
setValue(master_course);
|
||||
me.carrier.getNode(c_pitch).
|
||||
setValue(me.rplayer.getNode(mp_pitch).getValue());
|
||||
me.carrier.getNode(c_roll).
|
||||
setValue(me.rplayer.getNode(mp_roll).getValue());
|
||||
|
||||
# Accelerate the AI carrier to the right speed.
|
||||
me.carrier.getNode(c_control_speed).
|
||||
setValue(master_speed);
|
||||
} else {
|
||||
# Player on deck. Use the speed controller.
|
||||
me.carrier.getNode(c_control_speed).
|
||||
setValue(set_speed);
|
||||
}
|
||||
|
||||
# Always set these commands.
|
||||
me.carrier.getNode(c_control_course).
|
||||
setValue(set_course);
|
||||
|
||||
# Switch off AI control for the carrier if available.
|
||||
if (me.carrier.getNode(c_control_mp_ctrl) != nil)
|
||||
me.carrier.getNode(c_control_mp_ctrl).setBoolValue(1);
|
||||
}
|
||||
##################################################
|
||||
Manager.stop = func {
|
||||
me.loopid += 1;
|
||||
printf("Manager.stop() me.carrier_name=%s me.rplayer.getPath()=%s",
|
||||
me.carrier_name, me.rplayer.getPath());
|
||||
# Reenable AI control.
|
||||
if (me.carrier.getNode(c_control_mp_ctrl) != nil)
|
||||
me.carrier.getNode(c_control_mp_ctrl).setBoolValue(0);
|
||||
}
|
||||
##################################################
|
||||
Manager.die = func {
|
||||
if (me.callsign_listener == nil) return;
|
||||
|
||||
delete(MPCarriersNW.Manager_instances, me.rplayer.getIndex());
|
||||
me.loopid += 1;
|
||||
|
||||
# Delay the reactivation of AI control.
|
||||
settimer(func {
|
||||
if (me.carrier.getNode(c_control_mp_ctrl) != nil)
|
||||
me.carrier.getNode(c_control_mp_ctrl).setBoolValue(0);
|
||||
}, 5.0);
|
||||
|
||||
removelistener(me.callsign_listener);
|
||||
me.callsign_listener = nil;
|
||||
printf("Manager.die(): me.carrier_name=%s me.rplayer.getPath()=%s",
|
||||
me.carrier_name, me.rplayer.getPath());
|
||||
}
|
||||
##################################################
|
||||
Manager.start = func {
|
||||
me.loopid += 1;
|
||||
printf("Manager.start(): me.carrier_name=%s me.rplayer.getPath()=%s",
|
||||
me.carrier_name, me.rplayer.getPath());
|
||||
me._loop_(me.loopid);
|
||||
}
|
||||
##################################################
|
||||
Manager._loop_ = func(id) {
|
||||
id == me.loopid or return;
|
||||
me.update();
|
||||
settimer(func { me._loop_(id); }, 0);
|
||||
}
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
|
||||
#################################################################
|
||||
var normalize_course = func(c) {
|
||||
while (c < 0) c += 360;
|
||||
while (c >= 360) c -= 360;
|
||||
return c;
|
||||
}
|
||||
|
||||
#################################################################
|
||||
# Return a hash containing all nearby carrier players
|
||||
# indexed on MP-carrier type
|
||||
var find_carrier_players = func {
|
||||
var res = {};
|
||||
foreach (var c; keys(MPCarriersNW.Manager_instances)) {
|
||||
if (MPCarriersNW.Manager_instances[c].is_valid()) {
|
||||
var type = MPCarriersNW.Manager_instances[c].carrier_name;
|
||||
var pilot = MPCarriersNW.Manager_instances[c].rplayer;
|
||||
|
||||
if (!contains(res, type)) {
|
||||
res[type] = [pilot.getNode("callsign").getValue()];
|
||||
} else {
|
||||
append(res[type], pilot.getNode("callsign").getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
# debug.dump(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# MPCarrier selection dialog.
|
||||
var CARRIER_DLG = 0;
|
||||
var carrier_dialog = {};
|
||||
############################################################
|
||||
carrier_dialog.init = func (x = nil, y = nil) {
|
||||
me.x = x;
|
||||
me.y = y;
|
||||
me.bg = [0, 0, 0, 0.3]; # background color
|
||||
me.fg = [[1.0, 1.0, 1.0, 1.0]];
|
||||
#
|
||||
# "private"
|
||||
me.title = "MPCarrier";
|
||||
me.basenode = props.globals.getNode("/sim/mp-carriers", 1);
|
||||
me.dialog = nil;
|
||||
me.namenode = props.Node.new({"dialog-name" : me.title });
|
||||
me.listeners = [];
|
||||
me.players = {};
|
||||
me.carriers = { "Nimitz" : "nimitz-callsign",
|
||||
"Eisenhower" : "eisenhower-callsign",
|
||||
"Truman" : "truman-callsign",
|
||||
"Foch" : "foch-callsign",
|
||||
"Clemenceau" : "clemenceau-callsign",
|
||||
"Vinson" : "vinson-callsign"
|
||||
"Kuznetsov" : "kuznetsov-callsign",
|
||||
"Liaoning" : "liaoning-callsign",
|
||||
"Sanantonio" : "sanantonio-callsign"};
|
||||
}
|
||||
############################################################
|
||||
carrier_dialog.create = func {
|
||||
if (me.dialog != nil)
|
||||
me.close();
|
||||
|
||||
me.dialog = gui.Widget.new();
|
||||
gui.dialog[me.title] = me.dialog;
|
||||
me.dialog.set("name", me.title);
|
||||
if (me.x != nil)
|
||||
me.dialog.set("x", me.x);
|
||||
if (me.y != nil)
|
||||
me.dialog.set("y", me.y);
|
||||
|
||||
me.dialog.set("layout", "vbox");
|
||||
me.dialog.set("default-padding", 0);
|
||||
var titlebar = me.dialog.addChild("group");
|
||||
titlebar.set("layout", "hbox");
|
||||
titlebar.addChild("empty").set("stretch", 1);
|
||||
titlebar.addChild("text").set("label", "MPCarriers online");
|
||||
var w = titlebar.addChild("button");
|
||||
w.set("pref-width", 16);
|
||||
w.set("pref-height", 16);
|
||||
w.set("legend", "");
|
||||
w.set("default", 0);
|
||||
w.set("key", "esc");
|
||||
w.setBinding("nasal", "MPCarriers.carrier_dialog.destroy(); ");
|
||||
w.setBinding("dialog-close");
|
||||
me.dialog.addChild("hrule");
|
||||
|
||||
var content = me.dialog.addChild("group");
|
||||
content.set("layout", "vbox");
|
||||
content.set("halign", "center");
|
||||
content.set("default-padding", 5);
|
||||
|
||||
# Generate the dialog contents.
|
||||
var players_old = me.players;
|
||||
me.players = find_carrier_players();
|
||||
foreach (var type; keys(me.carriers)) {
|
||||
var selected = me.basenode.getNode(me.carriers[type], 1).getValue();
|
||||
var tmpbase = me.basenode.getNode(type, 1);
|
||||
|
||||
if (contains(me.players, type)) {
|
||||
var i = 0;
|
||||
foreach (var p; me.players[type]) {
|
||||
var tmp = tmpbase.getNode("b[" ~ i ~ "]", 1);
|
||||
tmp.setBoolValue(streq(selected, p));
|
||||
var w = content.addChild("checkbox");
|
||||
w.node.setValues({"label" : p ~ " (" ~ type ~ ")",
|
||||
"halign" : "left",
|
||||
"property" : tmp.getPath()});
|
||||
w.setBinding
|
||||
("nasal",
|
||||
"MPCarriers.carrier_dialog.select_action(" ~
|
||||
"\"" ~ type ~ "\", " ~ i ~ ");");
|
||||
i = i + 1;
|
||||
}
|
||||
if (size(me.players[type]) == 1
|
||||
and (
|
||||
!contains(players_old, type)
|
||||
or size(players_old[type]) == 0
|
||||
or g_auto_attach.getValue()
|
||||
)) {
|
||||
# Carrier has just appeared, and there is no other carrier of
|
||||
# the same type, so attach our AI carrier to it.
|
||||
printf("carrier_dialog.create(): auto-selecting type=%s", type);
|
||||
me.select_action(type, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
me.dialog.addChild("hrule");
|
||||
|
||||
# Display the dialog.
|
||||
fgcommand("dialog-new", me.dialog.prop());
|
||||
fgcommand("dialog-show", me.namenode);
|
||||
}
|
||||
############################################################
|
||||
carrier_dialog.close = func {
|
||||
if (me.dialog != nil) {
|
||||
me.x = me.dialog.prop().getNode("x", 1).getValue();
|
||||
me.y = me.dialog.prop().getNode("y", 1).getValue();
|
||||
}
|
||||
fgcommand("dialog-close", me.namenode);
|
||||
}
|
||||
############################################################
|
||||
carrier_dialog.destroy = func {
|
||||
CARRIER_DLG = 0;
|
||||
me.close();
|
||||
foreach(var l; me.listeners)
|
||||
removelistener(l);
|
||||
delete(gui.dialog, "\"" ~ me.title ~ "\"");
|
||||
}
|
||||
############################################################
|
||||
carrier_dialog.show = func {
|
||||
# print("Showing MPCarriers dialog!");
|
||||
if (!CARRIER_DLG) {
|
||||
CARRIER_DLG = int(getprop("/sim/time/elapsed-sec"));
|
||||
me.init();
|
||||
me.create();
|
||||
me._update_(CARRIER_DLG);
|
||||
}
|
||||
}
|
||||
############################################################
|
||||
carrier_dialog._redraw_ = func {
|
||||
if (me.dialog != nil) {
|
||||
me.close();
|
||||
me.create();
|
||||
}
|
||||
}
|
||||
############################################################
|
||||
carrier_dialog._update_ = func (id) {
|
||||
if (CARRIER_DLG != id) return;
|
||||
me._redraw_();
|
||||
settimer(func { me._update_(id); }, 4.1);
|
||||
}
|
||||
############################################################
|
||||
carrier_dialog.select_action = func (type, n) {
|
||||
var base = me.basenode.getNode(type);
|
||||
var selected = me.basenode.getNode(me.carriers[type]).getValue();
|
||||
var bs = base.getChildren();
|
||||
# Assumption: There are two true b:s or none. The one not matching selected
|
||||
# is the new selection.
|
||||
var i = 0;
|
||||
me.basenode.getNode(me.carriers[type], 1).setValue("");
|
||||
foreach (var b; bs) {
|
||||
if (!b.getValue() and (i == n)) {
|
||||
b.setValue(1);
|
||||
me.basenode.getNode(me.carriers[type]).setValue
|
||||
(me.players[type][i]);
|
||||
} else {
|
||||
b.setValue(0);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
me._redraw_();
|
||||
}
|
||||
###############################################################################
|
||||
|
||||
var as_num = func (val, default=0.0) {
|
||||
return (typeof(val) == "scalar") ? val : default;
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Overall initialization. Should only take place when the MPCarrier module is
|
||||
# being loaded.
|
||||
|
||||
# Load the MPCarrier MP network.
|
||||
if (!contains(globals, "MPCarriersNW")) {
|
||||
var base = "Aircraft/MPCarrier/Systems/mp-network.nas";
|
||||
io.load_nasal(resolvepath(base), "MPCarriersNW");
|
||||
MPCarriersNW.mp_network_init(0);
|
||||
|
||||
}
|
Loading…
Reference in a new issue