Back to Index Page generated: Dec 20, 2024, 7:22:10 AM

Expansion XenonHUD

Content

Warnings

  1. http://wiki.alioth.net/index.php/XenonHUD -> 404 Not Found
  2. Low hanging fuit: Information URL exists...
  3. Required Expansions mismatch between OXP Manifest and Expansion Manager at character position 0061 (DIGIT ZERO vs LATIN SMALL LETTER N)
  4. No version in dependency reference to oolite.oxp.Svengali.Library:null

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description This HUD puts most of the important scales (fuel, speed, laser temp, fore/aft shields and energy) around the crosshairs, but with a low alpha and a uniform colour to avoid distractions when fighting. It also moves other HUD elements to the edges of the screen, rather than grouping them around the scanner. Feature summary: - Centralised gauges around the crosshairs and giving them a uniform color. - Fixes bug with witchspace destination label - shows next jump dest. - Docked and inflight GUI huds. - New crosshair images for each weapon type. - Works with 16:10, 16:9 and 4:3 format displays. - Allows 3rd party laser OXP's to configure the crosshairs. - Automatic 40% glare reduction on all views. - Automatically hides the HUD when an external view is selected. - Implements the \"allow_big_gui\" option. - Primable equipment allows HUD to be switched to \"hi-contrast\" mode, which is useful when sun-skimming. - Amber color option This HUD puts most of the important scales (fuel, speed, laser temp, fore/aft shields and energy) around the crosshairs, but with a low alpha and a uniform colour to avoid distractions when fighting. It also moves other HUD elements to the edges of the screen, rather than grouping them around the scanner. Feature summary: - Centralised gauges around the crosshairs and giving them a uniform color. - Fixes bug with witchspace destination label - shows next jump dest. - Docked and inflight GUI huds. - New crosshair images for each weapon type. - Works with 16:10, 16:9 and 4:3 format displays. - Allows 3rd party laser OXP's to configure the crosshairs. - Automatic 40% glare reduction on all views. - Automatically hides the HUD when an external view is selected. - Implements the \"allow_big_gui\" option. - Primable equipment allows HUD to be switched to \"hi-contrast\" mode, which is useful when sun-skimming. - Amber color option
Identifier oolite.oxp.phkb.XenonHUD oolite.oxp.phkb.XenonHUD
Title XenonHUD XenonHUD
Category HUDs HUDs
Author phkb phkb
Version 3.8.10 3.8.10
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
  • oolite.oxp.Svengali.Library:0
  • oolite.oxp.Svengali.Library:
  • Optional Expansions
    Conflict Expansions
    Information URL http://wiki.alioth.net/index.php/Xenon_HUD n/a
    Download URL https://wiki.alioth.net/img_auth.php/4/42/XenonHUD.oxz n/a
    License CC-BY-NC-SA 4.0 CC-BY-NC-SA 4.0
    File Size n/a
    Upload date 1657691372

    Documentation

    readme.txt

    Xenon HUD
    By Nick Rogers
    
    Overview
    ========
    This HUD puts most of the important scales (fuel, speed, laser temp, fore/aft shields and energy) around the crosshairs, but with a low alpha and a uniform colour to avoid distractions when fighting. It also moves other HUD elements to the edges of the screen, rather than grouping them around the scanner. 
    
    There are three different HUD files which are used during flight. The main HUD is the standard one containing all the crosshair information. The second one is used when a GUI screen is brought up during flight. This secondary HUD gathers all the gauges and displays them in the bottom left while the GUI is open. The third HUD is a hi-contrast version of the main HUD (see below).
    
    This OXP requires Oolite version 1.82 or higher.
    
    Feature Summary
    ===============
    - Centralised gauges around the crosshairs and giving them a uniform colour (except in alert conditions).
    - Fixes bug with witchspace destination labels - next jump destination is now shown, not the final destination.
    - Docked and inflight GUI huds.
    - New crosshair images for each weapon type.
    - Works with 16:10 and 16:9 format displays.
    - Also works with 4:3 ratio screens automatically (1 MFD slot is dropped in this configuration).
    - Allows 3rd party laser OXP's to configure the crosshairs (see below).
    - Automatic 40% glare reduction on all views.
    - Automatically hides the HUD when an external view is selected, and unhides it when a standard view is selected.
    - Implements the "allow_big_gui" option to maximise GUI interface screen real-estate when docked.
    - Prime-able equipment allows HUD to be switched to "hi-contrast" mode, which is useful when sun-skimming. Can be automatically engaged with options via Library Config.
    - Incoming missile warning indicator on HUD.
    - Mass-lock indicator on HUD.
    
    Mode Selector
    =============
    Hi-Contrast mode
    ----------------
    The Xenon HUD comes with two operation modes: normal and hi-contrast. The hi-contrast mode can be useful when sun-skimming, when the glare from the sun can otherwise obscure instrumentation. To switch between the modes, first prime the "Xenon HUD Mode Selector" by pressing "Shift-N" until it appears as the primed equipment. Then, press the "N" key to activate first the hi-contrast mode, then again to revert back to normal mode.
    
    Hi-contrast mode will automatically be turned off when you dock.
    
    If the prime-able equipment is removed via Library Config, Hi-Contrast mode will be automatically engaged when the screen glare reaches a point where the mode would be useful.
    
    Crosshair modes
    ---------------
    The crosshairs can also be configured to operate in different conditions. With the "Xenon HUD Mode Selector" primed, press the "B" key to cycle through these options:
    	"Crosshairs on in all conditions" (this is the default mode)
    	"Crosshairs on in condition red only"
    	"Crosshairs on in condition yellow and red only"
    When the crosshairs are off, all gauges around the crosshairs will also be turned off, giving the pilot an completely unobstructed view of space.
    
    The mode selected for the crosshairs will be stored and will remain in place after docking and launching, and will be saved in mission variables.
    
    A special mode exists for when the player has requested docking clearance at a station. All gauges will be turned off, leaving only a simple crosshair image and the speed gauge to provide a clear view and aid in the docking process.
    
    Glare Filter Compatibility
    ==========================
    If the Glare Filter OXP is installed it will be set to its maximum setting ("High") whenever it is turned on. Attempting to set a low or medium level will be overridden, as both of these levels are at or below the default filter level provided by this OXP.
    
    Glare Clarifier Compatibility
    =============================
    This OXP will detect when the Glare Clarifier OXP is installed, and will allow it to do its work of providing 100% glare filtering.
    
    3rd Party Laser Crosshairs
    ==========================
    Other laser OXP's can configure the Xenon HUD to use a particular image file for their crosshairs. The image file can be one of the ones supplied with the Xenon HUD, or included in their own OXP. To configure a crosshair image file for a particular laser you will need to do the following:
      
    	var xh = worldScripts.XenonHUD;
    	xh.$customCrosshairs({laser:"EQ_WEAPON_MYLASER", filename:"crosshairs.png"});
     
    Example: You have the "LaserCannons.oxz" installed, and you want to use the military laser crosshairs for the "Lance & Ferman Military Cannon". You would need to do this:
    
    	var xh = worldScripts.XenonHUD;
    	xh.$customCrosshairs({laser:"EQ_WEAPON_CANNON_4", filename:"xenon_crosshairs_military.png"});
    
    The crosshairs for the built-in lasers are set up using this same mechanism, so you can also override the crosshair file for those lasers by doing the following:
    
    	var xh = worldScripts.XenonHUD;
    	xh.$customCrosshairs({laser:"EQ_WEAPON_BEAM_LASER", filename:"xenon_crosshairs_alt3.png"});
    
    The crosshair files included in the OXP are:
    	xenon_crosshairs_none.png
    	xenon_crosshairs_pulse.png
    	xenon_crosshairs_beam.png
    	xenon_crosshairs_mining.png
    	xenon_crosshairs_military.png
    	xenon_crosshairs_other.png
    	xenon_crosshairs_alt1.png
    	xenon_crosshairs_alt2.png
    	xenon_crosshairs_alt3.png
    	xenon_crosshairs_alt4.png
    	xenon_crosshairs_alt5.png
    	
    You don't have to use these images. If your OXP has a particular image file you want to use for the crosshairs, you can insert the name of that file instead. Note that the image will be scaled to fit into a 50x50 window - smaller images will be scaled up (potentially making them look pixelated), and larger images will be scaled down (potentially losing fine detail). 
    
    For more information and screenshots, please visit the wiki page at http://wiki.alioth.net/index.php/Xenon_HUD
    
    Requirements
    ============
    The Library OXP is a requirement for this pack.
    
    Licence
    =======
    This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 4.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
    
    Some images courtesy of the Coluber HUD by Captain Beatnik.
    Crosshair images based on work by Kay Pisarowitz. Released under GNU General Public License, version 2 (http://www.gnu.org/licenses/gpl-2.0.html).
    
    Big thanks to Astrobe for suggesting and helping to implement the mass-lock indicator, and for tidying up my code.
    Thanks also to Milo who has made a lot of suggestions to greatly improve the user experience for the HUD.
    
    Version History
    ===============
    3.8.10
    - Fixes issue introduced in 3.8.9 that was preventing the FCB from doing anything.
    
    3.8.9
    - Protection for FCB against player not being in space.
    
    3.8.8
    - Protection for invalid sun references in frame callback.
    
    3.8.7
    - Removed joystick sensitivity indicator.
    - Improved calculations to determine when to auto-switch to Hi-Contrast mode.
    
    3.8.6 (beta)
    - HUD warning elements will now switch off correctly when threat/event is gone.
    - Auto-switch anti-flickering time set to 1 second (down from 2 seconds).
    - Combat MFD speed value no longer visible on docking HUD.
    - Better alignment of space compass elements.
    - Added current status text (GREEN, YELLOW, RED) to HUD.
    
    3.8.5 (beta)
    - Moved script.js to xenonhud.js (to reduce clutter in Config folder).
    - Added code to prevent flickering when in auto-Hi-Contrast mode.
    - Improved calculations to determine when to auto-switch to Hi-Contrast mode.
    - Added some interfaces for Combat MFD values (speed, distance to space compass target).
    
    3.8.4 (beta)
    - Added selected missile name to area under missile display (Oolite 1.89 required).
    - Cleaned up warning/indicators around crosshairs.
    
    3.8.3 (beta)
    - Fixed issue that was stopping the auto-Hi-Contrast mode from engaging correctly.
    - Rearranged the warning indicators around the central HUD, and changed the masslock light into a similar label.
    - Re-worked method for adding warning and indicator texts to the HUD.
    
    3.8.2 (beta)
    - Better alignment of MFD underlays with MFD frames.
    - Further increased the distance at which checking for Hi-Contrast mode begins.
    - Attempt to correct issue where MFD underlay was shown even when no MFD was in the slot.
    
    3.8.1 (beta)
    - Improved visibility of MFD's when in Hi-Contrast mode.
    - Fixed issue with jump fuel required marker disappearing from fuel gauge when in Hi-Contrast mode.
    - Reduced font size in comms log and message GUI panels.
    - Slightly increased the distance at which checking for Hi-Contrast mode begins.
    
    3.8 (beta)
    - Added 2 additional MFD slots, making 9 in total.
    - When prime-able equipment is removed (via Library Config), the Hi-Contrast mode will be automatically engaged when glare increases (Oolite 1.89 required).
    - Changing the setting for removing the prime-able equipment is now being saved correctly.
    - Made Library OXP a requirement for the OXP.
    
    3.7
    - Improved integration with Ship Configuration F3 HUD selection process.
    
    3.6
    - Temperature bar wasn't switching to alert mode correctly in all situations.
    
    3.5
    - Temperature bar vanished when changing mode to "Crosshairs in yellow/red".
    
    3.4
    - Added "Simplified crosshairs" switch (available via Library Config), which turns off the circular brackets around the crosshairs.
    - Mini crosshairs (used when crosshairs are off in red/yellow status) were not reappearing after a witchspace jump.
    - Temperature change from low to medium was showing the temp bar even when crosshairs were off.
    - Incorrect default crosshair image selected for unrecognised lasers when amber mode is on.
    - Switched crosshair list to a dictionary for performance improvements.
    - Scanner ultra zoom and non-linear settings were being overridden by HUD Selector in a new game.
    
    3.3
    - Wrong HUD color used on F3 screen when Ship Configuration in use.
    
    3.2
    - Some elements on the docked HUD were not being switched to amber color correctly.
    - Some elements on the alternate HUD (used when viewing F5-F8 screens) were not being switched to amber color correctly.
    - Target reticle now matches selected color scheme (blue or amber).
    - Switched all white/grey elements to be the appropriate screen color (blue or amber), including scanner and MFD's.
    - Crosshair information was not being correctly transferred to a new ship (standard purchase or via Ship Respray OXP).
    
    3.1
    - Ship Config armour values were not displaying correctly when they reached 0%.
    - Added code to switch color of Manual Witchspace Alignment nav beacon (version 2.0 required).
    
    3.0
    - Added "Amber" color mode, which switches all standard blue-toned HUD elements to an amber color (selectable via Library Config).
    - Added some missing centre points to some crosshair images.
    - Compressed PNG images.
    - Bug fixes.
    
    2.1.1
    - Cleanup of Ship Configuration interface when HUDs are switched with HUD Selector.
    - Added some missing functions to the HUD Selector integration routine.
    
    2.1.0
    - Added equipment space and cargo space dials to the docked HUD, for improved integration with Ship Configuration.
    - Added ability to turn off fuel leak warning and cloaking device indicator via Library Config.
    - Added waypoint dial.
    
    2.0.2
    - Improved handling of player ship death scenarios.
    - Improved startup scenario handling.
    
    2.0.1
    - Fixed background alpha colour of message gui on narrow mode HUD.
    - Made narrow mode ratio trigger slightly wider to better avoid overlapping screen elements.
    
    2.0.0
    - Added a "narrow" HUD variant which will engage if the game window ratio becomes too narrow for the widescreen display. In narrow mode, the seventh MFD is dropped, and the comms log and message log are moved so they don't overlap other screen elements.
    - Added a cloaking indicator to the central HUD.
    - Really changed medium level cabin temp color to orange, returned medium laser temp back to blue.
    
    1.5.12
    - Changed medium level cabin temp color to orange.
    - Restored the $xenonHUDActive function for backwards compatibility with other OXP's.
    
    1.5.11
    - Potential fix for issue where docking crosshairs are shown on top of normal HUD.
    - Fixes for issues in interstellar space.
    - Bug fixes.
    
    1.5.10
    - Better handling of situation when buying a new ship replaces the player's ship script object.
    - Small tweaks for performance.
    - Better handling of player ship destruction.
    - Bug fixes.
    
    1.5.9
    - Fixed issue where scanner zoom setting was not being restored from a save game immediately after the game is launched. Note: the fix involves updating the default HUD to use the non-linear scanner with ultra zoom.
    - Performance tweaks.
    
    1.5.8
    - Added fuel leak warning to HUD.
    - Bug fixes.
    - More code cleanup.
    
    1.5.7
    - Better armour integration for forthcoming Ship Configuration release.
    - Stopped the "View Mode" equipment item from being removed unnecessarily.
    - Made use of the new "weaponsSystemsOnline" event to improve timer code performance.
    - Made use of the "playerDockingClearanceExpired" event to avoid the use of a timer, for better performance.
    - Fixed issue where the sun glare filter was being reset even though the "Glare Clarifier" was installed.
    - More code cleanup.
    
    1.5.6
    - Better handling of player launching an escape pod.
    - Code cleanup (thanks to gsagostinho and cag for the suggestions).
    
    1.5.5
    - Fixed issue where switching HUD's during flight may not award all required Xenon HUD equipment.
    - Improved HUDSelector integration.
    - Some attempts at performance improvements.
    
    1.5.4
    - Moved positions of comm log and message gui when docked.
    - Corrected some rgb_color values in the HUD plist files.
    - Added "background_automatic" to the message_gui so it will fade out in hi-contrast mode (Oolite 1.85/86 only).
    - Fixed script error that could occur when player ejects.
    - Updates for new events in Oolite v1.85/6.
    - Added central "dot" to a couple of the crosshairs to help with aiming.
    - Code refactoring.
    
    1.5.3
    - Updated method for determining player's next target system, to use new property "nextSystem".
    - Improved integration with Glare Clarifier and Glare Filter.
    - Removed hard-coded scanner range value.
    
    1.5.2 (With thanks to Astrobe)
    - Mass-lock indicator moved to be near the bottom of the scanner, rather than in the central HUD area.
    - Improvements to mass-lock calculation process.
    - Removed option to disable mass-lock indicator, as its position and constant presence shouldn't annoy anyone.
    - Removed "viewscreen_only" setting on mass-lock element in the HUD plist files.
    
    1.5.0
    - Added a mass-lock indicator to the HUD.
    - Added flag into Library Config to disable the mass-lock indicator.
    - Fixed Library Config default setting for missile warning indicator.
    
    1.4.1
    - Added very small crosshairs to appear when standard crosshairs are turned off during green or yellow conditions.
    - Added flags into Library Config to disable the docking HUD and the missile warning indicator.
    - Added flags into Library Config to manually set the crosshair mode, and to disable the Mode selector prime-able equipment item.
    - Fixed issue with hyperspace destination system being linked to the space compass, and not considering the presence of the ANA.
    
    1.4.0
    - Changed "==" comparisons to "===" for performance improvements.
    - Added an incoming missile warning indicator.
    - Code improvements and better integration with HUD Selector.
    - Fixed issue with mission screens that use the short range or long range special backgrounds and overirde the player's target system. The player's real destination was being reset if the player went from the mission screen displaying the map directly to the F6 screen. It now waits a moment to allow mission screens to do their own cleanup before checking and reseting the destination.
    - Better handling of scenario in interstellar space when player selects their originating system as their jump destination. Destination will now appear in HUD.
    - Sound effects added for mode/activate functions of HUD.
    
    1.3.9
    - Added scanner_non_linear and scanner_ultra_zoom to HUD.
    - Fixes to the message gui and comm log gui sections in hi-contrast mode.
    - Fixes to the position of the message gui and comm log gui when switching between an in-flight view and a ship system view.
    - Tweaks to the hi-contrast mode background colors for some elements.
    - plist tidying.
    
    1.3.8
    - Fixed issue with the "show HUD on red alert only" option not engaging during red alert. The "alertHostiles" property was being incorrectly referenced against the player ship, not the player.
    
    1.3.7
    - Hi-contrast mode now automatically turns off after a witchspace jump.
    - Added a check for when the player is in the middle of a jump countdown when attempting to change to/from hi-contrast mode. The HUD cannot be changed during a jump countdown.
    - Destination system was not being correctly updated when player's destination was set via an OXP mission screen.
    
    1.3.6
    - Current docked station was not being updated upon docking.
    
    1.3.5
    - Added armour values (from IronHide or Ship Configuration) to the HUD.
    - Added a "docked station" label to the docked HUD. 
    - Improvements to the hi-contrast mode, making MFD's more visible.
    - If you launch using another HUD, then use HUD Selector to change to the Xenon HUD, the HUD should now be displayed correctly.
    - Trimmed some fat out of the equipment.plist file.
    - Crosshair red alert mode now only triggers in combat red alert.
    - Clock position on main display will now be more centred based on the font being used.
    - Code cleanup.
    
    1.3.4
    - Fixed Javascript bug.
    
    1.3.3
    - Fixed issue where the wrong HUD was being shown after docking clearance is extended.
    
    1.3.2
    - Fixed issue where the check for weapons being online was being switched off after a witchspace jump.
    - Small tweaks to positions of text labels.
    - Code refactoring.
    
    1.3.1
    - Added a "current system" label to the docked HUD.
    - Fixed issue where Xenon HUD would override other HUD's when docking.
    
    1.3.0
    - Crosshairs change when weapon systems are disabled.
    - Better pause-screen handling with "viewscreen_only = 1" on all HUD applicable elements.
    - Moved docking speed bar away from crosshairs.
    - Added guidelines to docking HUD to aid with docking.
    - Fixed Javascript error if player doesn't dock before time expires.
    
    1.2.2
    - Fixed issue where the mode was not being restored correctly when restoring the game.
    
    1.2.1
    - Fixed issue where docking crosshairs would remain visible if the alert condition changed while attempting to dock.
    
    1.2.0
    - Added a special HUD mode for docking, where most gauges are hidden, leaving only a simple crosshair and the speed gauge to aid in the docking process.
    - Fixed issue where pausing and then resuming the game would not select the correct crosshair mode.
    - Removed debug message.
    - Removed redundant code from plist files.
    - Made more compatible with HUD Vanisher.
    - Added additional crosshair type (alt5).
    
    1.1.1
    - Fixed issue with Javascript error when in interstellar space.
    
    1.1
    - Fixed issue where HUD elements were shown on the paused/F2 screen.
    - Converted crosshair-drawn guidelines into an image so it can be turned on/off with the rest of the HUD elements when paused.
    - Added ability to turn off crosshair gauges in different conditions.
    
    1.0
    - Initial release
    

    Equipment

    Name Visible Cost [deci-credits] Tech-Level
    Xenon HUD Centre Element Controller no 0 1+
    Xenon HUD Centre Element Controller no 0 1+
    Xenon HUD Clock Position 1 no 0 1+
    Xenon HUD Clock Position 2 no 0 1+
    Xenon HUD Clock Position 3 no 0 1+
    Xenon HUD Docking Centre Element Controller no 0 1+
    Xenon HUD MFD 1 underlay no 0 1+
    Xenon HUD MFD 2 underlay no 0 1+
    Xenon HUD MFD 3 underlay no 0 1+
    Xenon HUD MFD 4 underlay no 0 1+
    Xenon HUD MFD 5 underlay no 0 1+
    Xenon HUD MFD 6 underlay no 0 1+
    Xenon HUD MFD 7 underlay no 0 1+
    Xenon HUD MFD 8 underlay no 0 1+
    Xenon HUD MFD 9 underlay no 0 1+
    Xenon HUD Low Temp Bar Control no 0 1+
    Xenon HUD Medium Temp Bar Controller no 0 1+
    Xenon HUD Mode Selector no 0 1+

    Ships

    This expansion declares no ships. This may be related to warnings.

    Models

    This expansion declares no models. This may be related to warnings.

    Scripts

    Path
    Scripts/xenonhud.js
    "use strict";
    this.name = "XenonHUD";
    this.author = "phkb";
    this.copyright = "2018 phkb";
    this.description = "Controls HUD selector compatibility and inflight GUI screen changes";
    this.licence = "CC BY-NC-SA 4.0";
    
    this._wc_fcb = null;
    this._hc_fcb = null;
    this._lastSwitch = 0;
    this._dockingCrosshairs = "xenon_crosshairs_alt5.png";
    this._holdFilter = 0; // hold spot for the sunGlareFilter value for the ship
    this._destination = -1; // current witchspace destination
    this._lastSource = -1; // used to establish the start point for destination system calculations
    this._glareFilterInstalled = false; // flag to indicate whether the glare filter OXP is installed
    this._glareClarifiedInstalled = false; // flag to indicate whether the glare clarifier OXP is installed
    this._glareTimer = null; // timer used to check when the glare filter is turned on
    this._doChecks = false; // flag to indicated that the glare filter has been turned on and therefore checks need to be made
    this._defaultGlareFilter = 0.4; // default glare filter value provided by this OXP
    this._hudVanisherInstalled = false; // flag to indicate whether the HUD Vanisher OXP is installed
    this._mode = ""; // HUD mode, either blank for standard, or "_hicontrast" for hicontrast mode
    this._amber = false; // controls whether blue (false) or amber (true) display is used
    this._crosshairMode = 0; // Crosshair mode: 0 = normal, 1 = off in green/yellow, on in red, 2 = off in green, on in red/yellow
    this._simplified = false;
    this._dockTimer = null; // timer used when docking to determine if the player has exceeded the allotted time
    this._ironHideArmour = false; // flag to indicate that IronHide armour is installed
    this._shipConfigArmour = false; // flag to indicate that Ship Configuration armour is installed
    this._holdTarget = 0;
    this._jumpCountdownStarted = false; // flag used to monitor when a jump countdown has started
    this._mapScreenChangeTimer = null;
    this._mapScreen = "";
    this._disableDockingHUD = false;
    this._disableMissileWarning = false;
    this._disableCloakIndicator = false;
    this._disableFuelLeakWarning = false;
    this._removePrimableEquip = false;
    this._trueValues = ["yes", "1", 1, "true", true];
    this._crosshairList = {
    	"EQ_WEAPON_NONE": "xenon_crosshairs_none.png",
    	"EQ_WEAPON_PULSE_LASER": "xenon_crosshairs_pulse.png",
    	"EQ_WEAPON_BEAM_LASER": "xenon_crosshairs_beam.png",
    	"EQ_WEAPON_MINING_LASER": "xenon_crosshairs_mining.png",
    	"EQ_WEAPON_MILITARY_LASER": "xenon_crosshairs_military.png"
    };
    
    // configuration settings for use in Lib_Config
    this._xenonHUDConfig = {
    	Name: this.name,
    	Alias: "Xenon HUD",
    	Display: "Config",
    	Alive: "_xenonHUDConfig",
    	Notify: "$changeSettings",
    	Bool: {
    		B0: {
    			Name: "_disableDockingHUD",
    			Def: false,
    			Desc: "Disable docking HUD"
    		},
    		B1: {
    			Name: "_disableMissileWarning",
    			Def: false,
    			Desc: "Disable missile warning"
    		},
    		B2: {
    			Name: "_disableCloakIndicator",
    			Def: false,
    			Desc: "Disable cloak indicator"
    		},
    		B3: {
    			Name: "_disableFuelLeakWarning",
    			Def: false,
    			Desc: "Disable fuel leak warning"
    		},
    		B4: {
    			Name: "_removePrimableEquip",
    			Def: false,
    			Desc: "Removes primable equipment"
    		},
    		B5: {
    			Name: "_amber",
    			Def: false,
    			Desc: "Amber color"
    		},
    		B6: {
    			Name: "_simplified",
    			Def: false,
    			Desc: "Simplified crosshairs"
    		},
    		Info: "0 - Disable docking HUD; 1 - Disable missile warning; 2 - Disable cloak indicator;\n3 - Disable fuel leak warning; 4 - Remove HUD Mode selector primable equipment;\n5 - Switch amber color on; 6 - Simplified crosshairs;"
    	},
    	SInt: {
    		S0: {
    			Name: "_crosshairMode",
    			Def: 0,
    			Min: 0,
    			Max: 2,
    			Desc: "HUD Crosshairs mode"
    		},
    		Info: "0 - Setting 0 = On in all conditions, 1 = On in Red condition only, 2 = On in Red/Yellow condtions"
    	}
    };
    
    //-------------------------------------------------------------------------------------------------------------
    // Allows OXP lasers to use a different crosshair png file
    // usage: lcobject is an object containing two properties:
    //		laser: 		the name of the equipment key of the laser
    //		filename:	the filename of the crosshairs file to use
    this.$customCrosshairs = function $customCrosshairs(lcobject) {
    	if (!lcobject.laser || lcobject.laser === "") {
    		throw "Invalid laser equipment object specified. Make sure the passed object has a 'laser:\"EQ_WEAPON_MYLASER\"' specified.";
    	}
    	if (!lcobject.filename || lcobject.filename === "") {
    		throw "Invalid crosshair filename specified. Make sure the passed object has a 'filename:\"specific_crosshairs.png\"' specified. See readme.txt file for possible filenames.";
    	}
    	var ch = this._crosshairList;
    	ch[lcobject.laser] = lcobject.filename;
    }
    
    //=============================================================================================================
    // ship interfaces
    
    //-------------------------------------------------------------------------------------------------------------
    // for compatibility with HUD selector
    this.startUp = function () {
    	var p = player.ship;
    	var ps = p.script;
    	p.hud = this.name + "_docked" + (this._amber === false ? "" : "_amber") + ".plist";
    
    	var h = worldScripts.hudselector;
    	if (h) h.$HUDSelectorAddHUD("Xenon HUD", this.name);
    
    	ps._currentCrosshairs = "";
    	ps._missiles = [];
    	ps._lastCheck = true;
    	ps._missileWarning = false;
    	ps._missileWarningChanged = false;
    	ps._fuelLeakWarning = false;
    	ps._playerIsDocking = false;
    	ps._mediumTemp = false;
    	ps._redoUnderlays = false;
    	//ps._wc_fcb = null;
    
    	//ps._previousCrosshairs = null;
    	ps.$selectCrosshairs = this.$selectCrosshairs;
    	//ps.$weaponsOnlineCheck = this.$weaponsOnlineCheck;
    	ps.$checkForIncomingMissiles = this.$checkForIncomingMissiles;
    
    	var sr = worldScripts.ShipRespray;
    	if (sr) {
    		//sr.$addPreSprayCall(this.name, "$preRespray");
    		//sr.$addPostSprayCall(this.name, "$postRespray");
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function () {
    	var p = player.ship;
    	if (this.playerBoughtNewShip) this.playerBoughtNewShip(p, 0);
    	if (worldScripts.GlareClarifier) {
    		this._glareClarifiedInstalled = true;
    		this._glareFilterInstalled = false;
    	}
    	if (worldScripts["HUD Vanisher"]) this._hudVanisherInstalled = true;
    	// restore the crosshair mode from mission variables
    	if (missionVariables.XenonHUD_CrosshairMode) this._crosshairMode = parseInt(missionVariables.XenonHUD_CrosshairMode);
    	this._lastSource = system.ID;
    	this.$setCurrentSystem();
    
    	// read flags from saved game
    	if (missionVariables.XenonHUD_DisableDockHUD) this._disableDockingHUD = (this._trueValues.indexOf(missionVariables.XenonHUD_DisableDockHUD) >= 0 ? true : false);
    	if (missionVariables.XenonHUD_DisableMissWarn) this._disableMissileWarning = (this._trueValues.indexOf(missionVariables.XenonHUD_DisableMissWarn) >= 0 ? true : false);
    	if (missionVariables.XenonHUD_DisableFuelLeakWarn) this._disableFuelLeakWarning = (this._trueValues.indexOf(missionVariables.XenonHUD_DisableFuelLeakWarn) >= 0 ? true : false);
    	if (missionVariables.XenonHUD_DisableCloakInd) this._disableCloakIndicator = (this._trueValues.indexOf(missionVariables.XenonHUD_DisableCloakInd) >= 0 ? true : false);
    	if (missionVariables.XenonHUD_RemoveEquip) this._removePrimableEquip = (this._trueValues.indexOf(missionVariables.XenonHUD_RemoveEquip) >= 0 ? true : false);
    	if (missionVariables.XenonHUD_Simplified) this._simplified = (this._trueValues.indexOf(missionVariables.XenonHUD_Simplified) >= 0 ? true : false);
    	// remove old flag, if it's still there
    	if (missionVariables.XenonHUD_DisableMassLock) delete missionVariables.XenonHUD_DisableMassLock;
    	// register our settings, if Lib_Config is present
    	if (worldScripts.Lib_Config) {
    		worldScripts.Lib_Config._registerSet(this._xenonHUDConfig);
    		if (missionVariables.XenonHUD_Amber) this._amber = (this._trueValues.indexOf(missionVariables.XenonHUD_Amber) >= 0 ? true : false);
    	}
    	if (worldScripts.ShipConfiguration_F3HUDControl) {
    		if (player.ship.hud.indexOf(this.name) >= 0) this.$updateShipConfigHUD();
    	}
    	this.$removeHUDEquipment();
    	// small fix for hudselector
    	var h = worldScripts.hudselector;
    	if (h && h.$BG === "") h.$BG = null;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillSaveGame = function () {
    	missionVariables.XenonHUD_CrosshairMode = this._crosshairMode;
    	missionVariables.XenonHUD_DisableDockHUD = this._disableDockingHUD;
    	missionVariables.XenonHUD_DisableMissWarn = this._disableMissileWarning;
    	missionVariables.XenonHUD_DisableFuelLeakWarn = this._disableFuelLeakWarning;
    	missionVariables.XenonHUD_DisableCloakInd = this._disableCloakIndicator;
    	missionVariables.XenonHUD_RemoveEquip = this._removePrimableEquip;
    	missionVariables.XenonHUD_Amber = this._amber;
    	missionVariables.XenonHUD_Simplified = this._simplified;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.guiScreenChanged = function (to, from) {
    	var p = player.ship;
    
    	this._mapScreen = from;
    	if (from !== "GUI_SCREEN_MAIN") {
    		if (this._mapScreenChangeTimer == null || this._mapScreenChangeTimer.isRunning === false) this._mapScreenChangeTimer = new Timer(this, this.$checkForNewDestination, 0.3, 0);
    	}
    
    	if (p.status === "STATUS_IN_FLIGHT") {
    		// when in flight, switch to the alt hud if the player selects anything other that the main screen
    		if (guiScreen === "GUI_SCREEN_MAIN") {
    			p.hud = this.name + this._mode + (this._amber === false ? "" : "_amber") + ".plist";
    			if (p.script._playerIsDocking === true) p.crosshairs = "crosshairs_docking.plist";
    		} else {
    			// the alt hud moves the speed, energy and shield bars to the bottom left, with all the other gauges
    			// to keep them from getting in the way of the Xenon backgrounds
    			p.hud = this.name + "_alt" + (this._amber === false ? "" : "_amber") + ".plist";
    		}
    	} else {
    		if ((guiScreen === "GUI_SCREEN_MARKET" || guiScreen === "GUI_SCREEN_MARKETINFO") && worldScripts["market_observer3"]) {
    			// do nothing - allow Market Observer to change the hud
    		} else {
    			p.hud = this.name + "_docked" + (this._amber === false ? "" : "_amber") + ".plist";
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillLaunchFromStation = function (station) {
    	var p = player.ship;
    	var ps = p.script;
    	// reset the missile monitoring array
    	if (!ps._missiles) ps._missiles = [];
    	ps._missiles.length = 0;
    	ps._massLockOn = false;
    	ps._missileWarning = false;
    	ps._missileWarningChanged = false;
    	ps._fuelLeakWarning = false;
    	ps._selectedMissile = "";
    	if (p.hasOwnProperty("activeMissile") == false) ps._selectedMissile = "N/A";
    	if (p.missiles && p.missiles.length > 0 && p.activeMissile < p.missiles.length && p.hasOwnProperty("activeMissile")) {
    		ps._selectedMissile = p.missiles[p.activeMissile].name;
    	}
    
    	this.$switchAmberCrosshairs();
    
    	if (!ps.$selectCrosshairs) ps.$selectCrosshairs = this.$selectCrosshairs;
    	//if (!ps.$weaponsOnlineCheck) ps.$weaponsOnlineCheck = this.$weaponsOnlineCheck;
    	if (!ps.$checkForIncomingMissiles) ps.$checkForIncomingMissiles = this.$checkForIncomingMissiles;
    
    	// oolite 1.85 has a new event to handle the change in weapons online status, so this code only applies to earlier versions
    	if (oolite.compareVersion("1.85") > 0) {
    		ps._checkForWeaponsOnline = true;
    	} else {
    		ps._checkForWeaponsOnline = false;
    	}
    	ps._disableMissileWarning = this._disableMissileWarning;
    	ps._disableFuelLeakWarning = this._disableFuelLeakWarning;
    
    	if (this._glareClarifiedInstalled === false && worldScripts["glare filter"] && p.equipmentStatus("EQ_GLARE_FILTER") === "EQUIPMENT_OK") {
    		this._glareFilterInstalled = true;
    		// force the default glare filter level to be the maximum
    		worldScripts["glare filter"].filterPointer = 2;
    	}
    
    	// add the viewmode selector and centre equipment items regardless of whether this is the current HUD or not.
    	// that way, if HUD selector changes to/from this HUD mid-flight, the right equipment is already installed and the HUD should work as normal
    	if (this._removePrimableEquip === false) p.awardEquipment("EQ_XENONHUD_VIEWMODE");
    	else p.removeEquipment("EQ_XENONHUD_VIEWMODE");
    
    	if (this._simplified == true) p.removeEquipment("EQ_XENONHUD_CENTRE_CROSSHAIR");
    	this.$displayCrosshairs();
    
    	// because there's no way of centring items, we'll move the centred position of the clock based on the width of the font
    	var test = defaultFont.measureString("000");
    	if (test >= 1.7) {
    		p.awardEquipment("EQ_XENONHUD_CLOCK_1")
    	} else if (test > 1.4 && test < 1.7) {
    		p.awardEquipment("EQ_XENONHUD_CLOCK_2");
    	} else {
    		p.awardEquipment("EQ_XENONHUD_CLOCK_3");
    	}
    
    	var ratio = oolite.gameSettings.gameWindow.width / oolite.gameSettings.gameWindow.height;
    	if (ratio < 1.5418) this._mode = "_narrow";
    
    	p.hud = this.name + this._mode + (this._amber === false ? "" : "_amber") + ".plist";
    
    	if (this._glareClarifiedInstalled === false) {
    		// make a note of the player's ship filter value
    		this._holdFilter = p.sunGlareFilter;
    		// only set the filter if the ship's filter level is less than 50%.
    		if (this._holdFilter < this._defaultGlareFilter) {
    			p.sunGlareFilter = this._defaultGlareFilter;
    		}
    	}
    
    	// preset the crosshairs
    	ps._currentCrosshairs = this.$selectCrosshairs(p.viewDirection);
    	this.$setCrosshairs();
    
    	// set up the glare filter check timer
    	if (this._glareFilterInstalled) {
    		// if the glare filter is installed, start a timer to monitor when it's turned on
    		this._glareTimer = new Timer(this, this.$checkGlareFilter, 5, 5);
    	}
    
    	this._lastSource = system.ID;
    	ps._mediumTemp = false;
    	ps._playerIsDocking = false;
    
    	if (p.equipmentStatus("EQ_IRONHIDE") === "EQUIPMENT_OK") this._ironHideArmour = true;
    	var sc = worldScripts.ShipConfiguration_Core;
    	if (sc) {
    		var a = sc._armour;
    		if (a && a.length > 0) {
    			for (var i = 0; i <= a.length; i++) {
    				if (a[i] && p.equipmentStatus(a[i]) === "EQUIPMENT_OK") {
    					this._shipConfigArmour = true;
    					break;
    				}
    			}
    		}
    	}
    	// force an update to the HUD so initial armour value can be displayed
    	this.shipTakingDamage(0, null, "");
    
    	// tell manual witchspace alignment which color to use for the nav frame
    	if (worldScripts.ManualWitchspaceAlignment) {
    		var mwa = worldScripts.ManualWitchspaceAlignment;
    		if (mwa._userOverride === false) {
    			mwa._color = 0;
    			if (this._amber === true) mwa._color = 1;
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipLaunchedFromStation = function(station) {
    	/*var ps = player.ship.script;
    	if (!ps._weaponsOnlineTimer || ps._weaponsOnlineTimer.isRunning === false) {
    		ps._weaponsOnlineTimer = new Timer(ps, ps.$weaponsOnlineCheck, 0.25, 0.25);
    	}*/
    	this.$setUpWCFCB();
    	this.$setUpHCFCB();
    	this.$setMFDUnderlays();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDockedWithStation = function (station) {
    	var p = player.ship;
    	// remove the xenon hud equipment items
    	this.$removeHUDEquipment();
    	this.$setCurrentSystem();
    
    	// make sure the normal mode is switched back
    	if (this._mode != "") this._mode = "";
    	p.hud = this.name + "_docked" + (this._amber === false ? "" : "_amber") + ".plist";
    
    	if (this._glareClarifiedInstalled === false) {
    		if (this._holdFilter < this._defaultGlareFilter) {
    			// restore the filter level to the stored value, just in case the player switches HUD while docked.
    			p.sunGlareFilter = this._holdFilter;
    		}
    	}
    	this.$stopTimers();
    	this.$stopFCB();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipWillDockWithStation = function (station) {
    	var p = player.ship;
    	var eqList = ["EQ_XENONHUD_CENTRE", "EQ_XENONHUD_CENTRE_CROSSHAIR", "EQ_XENONHUD_TEMP_LOW", "EQ_XENONHUD_TEMP_MEDIUM",
    		"EQ_XENONHUD_MFD1", "EQ_XENONHUD_MFD2", "EQ_XENONHUD_MFD3", "EQ_XENONHUD_MFD4", "EQ_XENONHUD_MFD5",
    		"EQ_XENONHUD_MFD6", "EQ_XENONHUD_MFD7", "EQ_XENONHUD_MFD8", "EQ_XENONHUD_MFD9", "EQ_XENONHUD_DOCKING", 
    		"EQ_XENONHUD_CLOCK_1", "EQ_XENONHUD_CLOCK_2", "EQ_XENONHUD_CLOCK_3"];
    	for (var i = 0; i < eqList.length; i++) {
    		p.removeEquipment(eqList[i]);
    	}
    	// reset the missile monitoring array
    	p.script._missiles.length = 0;
    
    	// reset the hud back to the normal one (ie. not the hi-contrast one)
    	p.hud = this.name + "_docked" + (this._amber === false ? "" : "_amber") + ".plist";
    
    	this.$stopTimers();
    	this.$stopFCB();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerStartedJumpCountdown = function (type, seconds) {
    	this._jumpCountdownStarted = true;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerCancelledJumpCountdown = function () {
    	this._jumpCountdownStarted = false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerJumpFailed = function (reason) {
    	this._jumpCountdownStarted = false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDied = function (whom, why) {
    	this.$stopTimers();
    	this.$stopFCB();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipTakingDamage = function (amount, whom, type) {
    	var p = player.ship;
    	var ps = p.script;
    	if (!p || !ps) return;
    	// work out how much armour is left in front and aft positions
    	var armourFront = 0;
    	var armourAft = 0;
    
    	// ironhide only keeps one value for armour, so we'll put that value into both positions
    	if (this._ironHideArmour === true) {
    		armourFront = missionVariables.ironHide_percentage;
    		armourAft = armourFront;
    	}
    	// ship config has independent front and aft armour values, so we can use those directly
    	if (this._shipConfigArmour === true) {
    		var arm = worldScripts.ShipConfiguration_Armour;
    		if (ps._armourFront >= 0) {
    			armourFront = ps._armourFront;
    			armourAft = ps._armourAft;
    		} else {
    			armourFront = arm._armourFront;
    			armourAft = arm._armourAft;
    		}
    	}
    
    	// set the custom dials to the values
    	// if no armour is installed, these values will be zero, effectively turning off the hud elements
    	p.setCustomHUDDial("armour_forward", armourFront / 100);
    	p.setCustomHUDDial("armour_aft", armourAft / 100);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipAttackedWithMissile = function (missile, whom) {
    	if (this._disableMissileWarning === true) return; // don't add missiles if the indicator is disabled
    	// add the missile to our array for checking
    	var ps = player.ship.script;
    	if (ps) ps._missiles.push(missile);
    }
    
    //--------------------------------------------------------------------------------------------------------------
    this.alertConditionChanged = function (newCondition, oldCondition) {
    	// only update the crosshairs when the condition is something other than docked (0)
    	if (newCondition > 0) this.$displayCrosshairs();
    	if (player.ship && player.ship.script) {
    		player.ship.script._redoUnderlays = true;
    	}
    }
    
    //--------------------------------------------------------------------------------------------------------------
    this.viewDirectionChanged = function (viewString) {
    	var p = player.ship;
    	var ps = p.script;
    	this._lastSwitch = 0;
    	// no need to do this if the hud vanisher is installed
    	if (this._hudVanisherInstalled === false) {
    		if (viewString === "VIEW_CUSTOM") {
    			p.hudHidden = true;
    		} else {
    			p.hudHidden = false;
    		}
    	}
    	ps._currentCrosshairs = this.$selectCrosshairs(viewString);
    	p.setCustomHUDDial("crosshairs", ps._currentCrosshairs);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipExitedWitchspace = function () {
    	if (player.ship.script._missiles) {
    		player.ship.script._missiles.length = 0;
    	} else {
    		player.ship.script._missiles = [];
    	}
    	if (system.ID != -1) this._lastSource = system.ID;
    
    	this._jumpCountdownStarted = false;
    	// reset the hi-contrast mode after exiting witchspace
    	this._mode = this._mode.replace("_hicontrast", "");
    	this.guiScreenChanged("", "");
    
    	this._destination = this.$playerTargetSystem();
    	this.$setDestination();
    	this.$setCurrentSystem();
    
    	if (this._dockTimer && this._dockTimer.isRunning) this._dockTimer.stop();
    	this.$displayCrosshairs();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerBoughtNewShip = function (ship, price) {
    	if (!this.$hudSelector && player.ship.hud === "hud.plist") {
    		player.ship.hud = this.name + "_docked" + (this._amber === false ? "" : "_amber") + ".plist";
    		this.$setDestination();
    		this.$setCurrentSystem();
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipCloakActivated = function () {
    	if (this._disableCloakIndicator === true) return;
    	player.ship.setCustomHUDDial("local_cloakIndicator", "CLOAKED");
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipCloakDeactivated = function () {
    	if (this._disableCloakIndicator === true) return;
    	player.ship.setCustomHUDDial("local_cloakIndicator", "");
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerRequestedDockingClearance = function (message) {
    	if (this._disableDockingHUD === false) {
    		var p = player.ship;
    		var ps = p.script;
    		if (message === "DOCKING_CLEARANCE_GRANTED" || message === "DOCKING_CLEARANCE_EXTENDED" || message === "DOCKING_CLEARANCE_DENIED_TRAFFIC_INBOUND" || message === "DOCKING_CLEARANCE_DENIED_TRAFFIC_OUTBOUND") {
    			ps._playerIsDocking = true;
    			//ps._previousCrosshairs = p.crosshairs;
    			p.removeEquipment("EQ_XENONHUD_CENTRE");
    			p.removeEquipment("EQ_XENONHUD_CENTRE_CROSSHAIR");
    			p.removeEquipment("EQ_XENONHUD_TEMP_LOW");
    			p.removeEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    			p.awardEquipment("EQ_XENONHUD_DOCKING");
    			p.crosshairs = "crosshairs_docking.plist";
    			if (message === "DOCKING_CLEARANCE_GRANTED" || message === "DOCKING_CLEARANCE_EXTENDED") {
    				// start a timer so we can track when the clearance expires
    				if (oolite.compareVersion("1.83") > 0) {
    					if (this._dockTimer && this._dockTimer.isRunning) this._dockTimer.stop();
    					this._dockTimer = new Timer(this, this.$dockingExpired, 121, 0);
    				}
    			}
    		} else {
    			ps._playerIsDocking = false;
    			this.$displayCrosshairs();
    			//p.crosshairs = ps._previousCrosshairs;
    			if (this._dockTimer && this._dockTimer.isRunning) this._dockTimer.stop();
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // for oolite 1.85++
    this.playerDockingClearanceCancelled = function () {
    	var p = player.ship;
    	var ps = p.script;
    	ps._playerIsDocking = false;
    	this.$displayCrosshairs();
    	//p.crosshairs = ps._previousCrosshairs;
    	if (this._dockTimer && this._dockTimer.isRunning) this._dockTimer.stop();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // for oolite 1.83++
    this.playerDockingClearanceExpired = function () {
    	this.playerDockingClearanceCancelled();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.weaponsSystemsToggled = function (state) {
    	var p = player.ship;
    	var ps = p.script;
    	if (ps) {
    		ps._currentCrosshairs = this.$selectCrosshairs(p.viewDirection);
    		p.setCustomHUDDial("crosshairs", ps._currentCrosshairs);
    		if (!state && ps._selectedMissile != "N/A") {
    			p.setCustomHUDDial("local_selectedMissile", "");
    			ps._selectedMissile = "";
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.mfdKeyChanged = function(index, key) {
    	this.$setMFDUnderlays();
    }
    
    //=============================================================================================================
    // helper functions
    
    //-------------------------------------------------------------------------------------------------------------
    // HUD selector callback to turn things on/off with the currently selected HUD
    this.$HUDSelectorCallBack = function $HUDSelectorCallBack(off) {
    	var w = worldScripts.XenonHUD;
    	if (off) {
    		w.$stopTimers();
    		w.$stopFCB();
    		// do things to disable HUD like rename functions
    		if (w.guiScreenChanged) {
    			w.$save_guiScreenChanged = w.guiScreenChanged;
    			delete w.guiScreenChanged;
    		}
    		if (w.shipWillLaunchFromStation) {
    			w.$save_shipWillLaunchFromStation = w.shipWillLaunchFromStation;
    			delete w.shipWillLaunchFromStation;
    		}
    		if (w.shipLaunchedFromStation) {
    			w.$save_shipLaunchedFromStation = w.shipLaunchedFromStation;
    			delete w.shipLaunchedFromStation;
    		}
    		if (w.shipDockedWithStation) {
    			w.$save_shipDockedWithStation = w.shipDockedWithStation;
    			delete w.shipDockedWithStation;
    		}
    		if (w.shipWillDockWithStation) {
    			w.$save_shipWillDockWithStation = w.shipWillDockWithStation;
    			delete w.shipWillDockWithStation;
    		}
    		if (w.shipDied) {
    			w.$save_shipDied = w.shipDied;
    			delete w.shipDied;
    		}
    		if (w.shipTakingDamage) {
    			w.$save_shipTakingDamage = w.shipTakingDamage;
    			delete w.shipTakingDamage;
    		}
    		if (w.shipAttackedWithMissile) {
    			w.$save_shipAttackedWithMissile = w.shipAttackedWithMissile;
    			delete w.shipAttackedWithMissile;
    		}
    		if (w.alertConditionChanged) {
    			w.$save_alertConditionChanged = w.alertConditionChanged;
    			delete w.alertConditionChanged;
    		}
    		if (w.viewDirectionChanged) {
    			w.$save_viewDirectionChanged = w.viewDirectionChanged;
    			delete w.viewDirectionChanged;
    		}
    		if (w.shipExitedWitchspace) {
    			w.$save_shipExitedWitchspace = w.shipExitedWitchspace;
    			delete w.shipExitedWitchspace;
    		}
    		if (w.playerJumpFailed) {
    			w.$save_playerJumpFailed = w.playerJumpFailed;
    			delete w.playerJumpFailed;
    		}
    		if (w.playerStartedJumpCountdown) {
    			w.$save_playerStartedJumpCountdown = w.playerStartedJumpCountdown;
    			delete w.playerStartedJumpCountdown;
    		}
    		if (w.playerCancelledJumpCountdown) {
    			w.$save_playerCancelledJumpCountdown = w.playerCancelledJumpCountdown;
    			delete w.playerCancelledJumpCountdown;
    		}
    		if (w.playerBoughtNewShip) {
    			w.$save_playerBoughtNewShip = w.playerBoughtNewShip;
    			delete w.playerBoughtNewShip;
    		}
    		if (w.playerRequestedDockingClearance) {
    			w.$save_playerRequestedDockingClearance = w.playerRequestedDockingClearance;
    			delete w.playerRequestedDockingClearance;
    		}
    		if (w.playerDockingClearanceCancelled) {
    			w.$save_playerDockingClearanceCancelled = w.playerDockingClearanceCancelled;
    			delete w.playerDockingClearanceCancelled;
    		}
    		if (w.playerDockingClearanceExpired) {
    			w.$save_playerDockingClearanceExpired = w.playerDockingClearanceExpired;
    			delete w.playerDockingClearanceExpired;
    		}
    		if (w.weaponsSystemsToggled) {
    			w.$save_weaponsSystemsToggled = w.weaponsSystemsToggled;
    			delete w.weaponsSystemsToggled;
    		}
    		if (w.shipCloakActivated) {
    			w.$save_shipCloakActivated = w.shipCloakActivated;
    			delete w.shipCloakActivated;
    		}
    		if (w.shipCloakDeactivated) {
    			w.$save_shipCloakDeactivated = w.shipCloakDeactivated;
    			delete w.shipCloakDeactivated;
    		}
    		if (w.mfdKeyChanged) {
    			w.$save_mfdKeyChanged = w.mfdKeyChanged;
    			delete w.mfdKeyChanged;
    		}
    		player.ship.removeEquipment("EQ_XENONHUD_VIEWMODE");
    		w.$revertShipConfigHUD();
    		
    	} else {
    		// do things to activate HUD like restore disabled functions
    		if (!w.guiScreenChanged) eval("w.guiScreenChanged = " + w.$save_guiScreenChanged);
    		if (!w.shipWillLaunchFromStation) eval("w.shipWillLaunchFromStation = " + w.$save_shipWillLaunchFromStation);
    		if (!w.shipLaunchedFromStation) eval("w.shipLaunchedFromStation = " + w.$save_shipLaunchedFromStation);
    		if (!w.shipDockedWithStation) eval("w.shipDockedWithStation = " + w.$save_shipDockedWithStation);
    		if (!w.shipWillDockWithStation) eval("w.shipWillDockWithStation = " + w.$save_shipWillDockWithStation);
    		if (!w.shipDied) eval("w.shipDied = " + w.$save_shipDied);
    		if (!w.shipTakingDamage) eval("w.shipTakingDamage = " + w.$save_shipTakingDamage);
    		if (!w.shipAttackedWithMissile) eval("w.shipAttackedWithMissile = " + w.$save_shipAttackedWithMissile);
    		if (!w.alertConditionChanged) eval("w.alertConditionChanged = " + w.$save_alertConditionChanged);
    		if (!w.viewDirectionChanged) eval("w.viewDirectionChanged = " + w.$save_viewDirectionChanged);
    		if (!w.shipExitedWitchspace) eval("w.shipExitedWitchspace = " + w.$save_shipExitedWitchspace);
    		if (!w.playerJumpFailed) eval("w.playerJumpFailed = " + w.$save_playerJumpFailed);
    		if (!w.playerStartedJumpCountdown) eval("w.playerStartedJumpCountdown = " + w.$save_playerStartedJumpCountdown);
    		if (!w.playerCancelledJumpCountdown) eval("w.playerCancelledJumpCountdown = " + w.$save_playerCancelledJumpCountdown);
    		if (!w.playerBoughtNewShip) eval("w.playerBoughtNewShip = " + w.$save_playerBoughtNewShip);
    		if (!w.playerRequestedDockingClearance) eval("w.playerRequestedDockingClearance = " + w.$save_playerRequestedDockingClearance);
    		if (!w.playerDockingClearanceCancelled) eval("w.playerDockingClearanceCancelled = " + w.$save_playerDockingClearanceCancelled);
    		if (!w.playerDockingClearanceExpired) eval("w.playerDockingClearanceExpired = " + w.$save_playerDockingClearanceExpired);
    		if (!w.weaponsSystemsToggled) eval("w.weaponsSystemsToggled = " + w.$save_weaponsSystemsToggled);
    		if (!w.shipCloakActivated) eval("w.shipCloakActivated = " + w.$save_shipCloakActivated);
    		if (!w.shipCloakDeactivated) eval("w.shipCloakDeactivated = " + w.$save_shipCloakDeactivated);
    		if (!w.mfdKeyChanged) eval("w.mfdKeyChanged = " + w.$save_mfdKeyChanged);
    		// force an update
    		w.shipExitedWitchspace();
    		w.shipWillLaunchFromStation();
    		w.viewDirectionChanged(player.ship.viewDirection);
    		w.$setMFDUnderlays();
    		w.$setUpHCFCB();
    		w.$setUpWCFCB();
    		w.$updateShipConfigHUD();
    		var h = worldScripts.hudselector;
    		if (h) {
    			h.$HUDSelectorScanner = 3;
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$checkForNewDestination = function $checkForNewDestination() {
    	// check if our destination hasn't been set yet (-1) or if our targetSystem has changed, or we've just left the long/short range chart
    	if (this._destination === -1 || this._holdTarget != player.ship.targetSystem || (this._mapScreen === "GUI_SCREEN_SHORT_RANGE_CHART" || this._mapScreen === "GUI_SCREEN_LONG_RANGE_CHART")) {
    		this._destination = this.$playerTargetSystem();
    		this.$setDestination();
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // work out whether to show crosshair controls
    this.$displayCrosshairs = function $displayCrosshairs() {
    	var p = player.ship;
    	if (!p || !p.script) return;
    	
    	p.removeEquipment("EQ_XENONHUD_DOCKING");
    	p.crosshairs = null; //if (p.script) p.script._previousCrosshairs;
    
    	switch (this._crosshairMode) {
    		case 0: // on in all conditions
    			if (this._simplified === false) p.awardEquipment("EQ_XENONHUD_CENTRE_CROSSHAIR");
    			p.awardEquipment("EQ_XENONHUD_CENTRE");
    			if (p.temperature < 0.5) {
    				p.awardEquipment("EQ_XENONHUD_TEMP_LOW");
    				p.removeEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    				p.script._mediumTemp = false;
    			} else {
    				p.awardEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    				p.removeEquipment("EQ_XENONHUD_TEMP_LOW");
    				p.script._mediumTemp = true;
    			}
    			break;
    		case 1: // on in combat red alert only
    			if (p.alertCondition === 3 && player.alertHostiles) {
    				if (this._simplified === false) p.awardEquipment("EQ_XENONHUD_CENTRE_CROSSHAIR");
    				p.awardEquipment("EQ_XENONHUD_CENTRE");
    				if (p.temperature < 0.5) {
    					p.awardEquipment("EQ_XENONHUD_TEMP_LOW");
    					p.removeEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    					p.script._mediumTemp = false;
    				} else {
    					p.awardEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    					p.removeEquipment("EQ_XENONHUD_TEMP_LOW");
    					p.script._mediumTemp = true;
    				}
    			} else {
    				p.removeEquipment("EQ_XENONHUD_CENTRE");
    				p.removeEquipment("EQ_XENONHUD_CENTRE_CROSSHAIR");
    				p.removeEquipment("EQ_XENONHUD_TEMP_LOW");
    				p.removeEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    				p.crosshairs = "crosshairs_mini.plist";
    			}
    			break;
    		case 2: // on in yellow and red only
    			if (p.alertCondition >= 2) {
    				if (this._simplified === false) p.awardEquipment("EQ_XENONHUD_CENTRE_CROSSHAIR");
    				p.awardEquipment("EQ_XENONHUD_CENTRE");
    				if (p.temperature < 0.5) {
    					p.awardEquipment("EQ_XENONHUD_TEMP_LOW");
    					p.removeEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    					p.script._mediumTemp = false;
    				} else {
    					p.awardEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    					p.removeEquipment("EQ_XENONHUD_TEMP_LOW");
    					p.script._mediumTemp = true;
    				}
    			} else {
    				p.script._mediumTemp = false;
    				p.removeEquipment("EQ_XENONHUD_CENTRE");
    				p.removeEquipment("EQ_XENONHUD_CENTRE_CROSSHAIR");
    				p.removeEquipment("EQ_XENONHUD_TEMP_LOW");
    				p.removeEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    				p.crosshairs = "crosshairs_mini.plist";
    			}
    			break;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks to see if the glare filter is ever turned on, and if so, monitors the glare filter level so it stays at the default level
    this.$checkGlareFilter = function $checkForGlareFilter() {
    	var w = worldScripts["glare filter"];
    	var p = player.ship;
    	// check to see if the filter ever gets turned on
    	if (w.$filterOn) this._doChecks = true;
    	// once it's been turned on, monitor the glare filter and reset it to the default
    	if (this._doChecks) {
    		// if the filter is on, but it's set to a low level, force it to the max level
    		if (w.$filterPointer < 2) {
    			w.$filterPointer = 2;
    			w.$adjustFilter();
    		}
    		if (p.sunGlareFilter < this._defaultGlareFilter) p.sunGlareFilter = this._defaultGlareFilter;
    	}
    	// if the filter has been turned of, we can stop doing the checks
    	if (!w.$fiterOn) this._doChecks = false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // sets the HUD dials to the current crosshair images
    this.$setCrosshairs = function $setCrosshairs() {
    	var p = player.ship;
    	if (p.hud != this.name + "_alt" + (this._amber === false ? "" : "_amber") + ".plist") {
    		p.setCustomHUDDial("crosshairs", p.script._currentCrosshairs);
    		p.setCustomHUDDial("crosshairsDocking", this._dockingCrosshairs);
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // sets the witchspace destination labels to the next destination (to fix bug in 1.82 with the builtin dial that only shows the final destination)
    this.$setDestination = function $setDestination() {
    	var p = player.ship;
    	var planet = "";
    	if (this._destination >= 0 && this._destination != system.ID) planet = System.systemNameForID(this._destination);
    	p.setCustomHUDDial("witchspace_destination", planet);
    	this._holdTarget = p.targetSystem;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // sets the current location label
    this.$setCurrentSystem = function $setCurrentSystem() {
    	var p = player.ship;
    	var sys = "";
    	if (system.ID === -1) {
    		sys = "Interstellar space";
    	} else {
    		sys = system.name;
    	}
    	var stn = "";
    	if (p.dockedStation) {
    		stn = p.dockedStation.displayName;
    		if (stn === "") stn = p.dockedStation.name;
    	}
    	p.setCustomHUDDial("current_system", sys);
    	p.setCustomHUDDial("current_station", stn);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // select the appropriate crosshairs based on the weapon in the selected view
    this.$selectCrosshairs = function $selectCrosshairs(view) {
    	var ws = worldScripts.XenonHUD;
    	var p = player.ship;
    	if (p.weaponsOnline === false) return ws.$weaponCrosshairs("EQ_WEAPON_NONE");
    
    	var imageFile = "";
    	switch (view) {
    		case "VIEW_FORWARD":
    			imageFile = ws.$weaponCrosshairs(p.forwardWeapon.equipmentKey);
    			break;
    		case "VIEW_AFT":
    			imageFile = ws.$weaponCrosshairs(p.aftWeapon.equipmentKey);
    			break;
    		case "VIEW_PORT":
    			imageFile = ws.$weaponCrosshairs(p.portWeapon.equipmentKey);
    			break;
    		case "VIEW_STARBOARD":
    			imageFile = ws.$weaponCrosshairs(p.starboardWeapon.equipmentKey);
    			break;
    	}
    	return imageFile;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // select the correct crosshairs image based on the weapon
    this.$weaponCrosshairs = function $weaponCrosshairs(weapon) {
    	var ch = this._crosshairList;
    	var file = (this._amber === false ? "xenon_crosshairs_other.png" : "xenon_crosshairs_other_amber.png");
    	if (ch && ch[weapon]) {
    		file = ch[weapon];
    	}
    	return file;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks whether the player has turned off weapons, and resets the crosshairs
    this.$setUpWCFCB = function $setUpWCFCB() {
    	this._wc_fcb = addFrameCallback(function (delta) {
    		var p = player.ship;
    		var ps = p.script;
    		var x = worldScripts.XenonHUD;
    		if (p && p.isInSpace) {
    			if (p.weaponsOnline == true) {
    				// only do the missile name if the property is available (Oolite 1.89ff)
    				if (ps._selectedMissile != "N/A") {
    					if (p.missilesOnline == false || !p.missiles || p.missiles.length == 0 && ps._selectedMissile != "") {
    						ps._selectedMissile = "";
    						p.setCustomHUDDial("local_selectedMissile", "");
    					}
    					if (p.missilesOnline == true && p.missiles && p.missiles.length > 0 && p.activeMissile < p.missiles.length && ps._selectedMissile != p.missiles[p.activeMissile].equipmentKey) {
    						ps._selectedMissile = p.missiles[p.activeMissile].equipmentKey;
    						p.setCustomHUDDial("local_selectedMissile", "Selected missile: " + p.missiles[p.activeMissile].name);
    					}
    				}
    			}
    		
    			var showTemp = false;
    			switch (x._crosshairMode) {
    				case 0: // on in all conditions
    					showTemp = true;
    					break;
    				case 1:
    					if (p.alertCondition === 3 && player.alertHostiles) showTemp = true;
    					break;
    				case 2:
    					if (p.alertCondition >= 2) showTemp = true;
    					break;
    			}
    			if (p.temperature >= 0.5 && ps._mediumTemp === false) {
    				if (showTemp === true) {
    					p.removeEquipment("EQ_XENONHUD_TEMP_LOW");
    					p.awardEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    				}
    				ps._mediumTemp = true;
    			} else if (p.temperature < 0.5 && ps._mediumTemp === true) {
    				if (showTemp === true) {
    					p.awardEquipment("EQ_XENONHUD_TEMP_LOW");
    					p.removeEquipment("EQ_XENONHUD_TEMP_MEDIUM");
    				}
    				ps._mediumTemp = false;
    			}
    
    			if (ps._checkForWeaponsOnline === true) {
    				if (p.weaponsOnline != ps._lastCheck) {
    					ps._lastCheck = p.weaponsOnline;
    					ps._currentCrosshairs = ps.$selectCrosshairs(p.viewDirection);
    					p.setCustomHUDDial("crosshairs", ps._currentCrosshairs);
    				}
    			}
    			if (ps._disableMissileWarning === false) {
    				ps.$checkForIncomingMissiles();
    				if (ps._missileWarning === true && ps._missileWarningChanged === true) {
    					p.setCustomHUDDial("local_missileWarning", "MISSILE");
    					ps._missileWarningChanged = false;
    				}
    				if (ps._missileWarning === false && ps._missileWarningChanged === true) {
    					p.setCustomHUDDial("local_missileWarning", "");
    					ps._missileWarningChanged = false;
    				}
    			}
    			if (ps._disableFuelLeakWarning === false) {
    				if (p.fuelLeakRate > 0 && p.fuel > 0) {
    					if (ps._fuelLeakWarning === false) {
    						ps._fuelLeakWarning = true;
    						p.setCustomHUDDial("local_fuelLeakWarning", "LEAK");
    					}
    				} else {
    					if (ps._fuelLeakWarning === true) {
    						ps._fuelLeakWarning = false;
    						p.setCustomHUDDial("local_fuelLeakWarning", "");
    					}
    				}
    			}
    
    			if (ps._playerIsDocking === false && (player.alertCondition > 1 || player.alertMassLocked === true)) {
    				// we're keeping track of the mass lock state via a flag, so we don't have to keep updating the HUD with the same value each second.
    				if (ps._massLockOn === false) {
    					p.setCustomHUDDial("local_masslockIndicator", "MASS LOCK");
    				}
    				ps._massLockOn = true;
    			} else {
    				if (ps._massLockOn === true) {
    					p.setCustomHUDDial("local_masslockIndicator", "");
    				}
    				ps._massLockOn = false;
    			}
    
    			// check for change of screen size
    			var o = oolite.gameSettings.gameWindow
    			var ratio = o.width / o.height;
    			if (!ps._xenon_lastRatio) ps._xenon_lastRatio = ratio;
    			if (ratio != ps._xenon_lastRatio) {
    				ps._xenon_lastRatio = ratio;
    				if (ratio < 1.5418 && x._mode.indexOf("_narrow") === -1) {
    					x._mode = "_narrow" + x._mode;
    					player.ship.hud = x.name + x._mode + (x._amber === false ? "" : "_amber") + ".plist";
    				} else if (x._mode.indexOf("_narrow") >= 0) {
    					x._mode = x._mode.replace("_narrow", "");
    					player.ship.hud = x.name + x._mode + (x._amber === false ? "" : "_amber") + ".plist";
    				}
    			}
    			
    			if (ps._redoUnderlays === true) {
    				ps._redoUnderlays = false;
    				x.$setMFDUnderlays();
    			}
    		}
    	});
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // returns the player's target system (1.80) or the next jump to their target system (1.82)
    this.$playerTargetSystem = function $playerTargetSystem() {
    	var p = player.ship;
    	if (p.hasOwnProperty("nextSystem")) return p.nextSystem;
    
    	// need to check for the ANA when route checking - if no ANA it's just the targetSystem - no routing available
    	var target = p.targetSystem;
    	if (oolite.compareVersion("1.81") < 0 && p.hasEquipmentProviding("EQ_ADVANCED_NAVIGATIONAL_ARRAY") === true) {
    		// in 1.81 or greater, the target system could be more than 7 ly away. It becomes, essentially, the final destination.
    		// there could be multiple interim stop points between the current system and the target system.
    		// the only way to get this info is to recreate a route using the same logic as entered on the ANA, and pick item 1
    		// from the list. That should be the next destination in the list.
    		if (target != this._lastSource) {
    			var myRoute = System.infoForSystem(galaxyNumber, this._lastSource).routeToSystem(System.infoForSystem(galaxyNumber, target), p.routeMode);
    			if (myRoute && myRoute.route.length > 1) {
    				target = myRoute.route[1];
    			}
    		}
    	}
    	return target;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // stops the dock timer
    this.$stopTimers = function $stopTimers() {
    	var p = player.ship;
    	var ps = p.script;
    	// stop the glare filter check timer if it's running
    	if (this._glareTimer && this._glareTimer.isRunning) this._glareTimer.stop();
    	// stop the dock timer check timer if it's running
    	if (this._dockTimer && this._dockTimer.isRunning) this._dockTimer.stop();
    	// stop the weapons online check timer if it's running
    	//if (ps && ps._weaponsOnlineTimer && ps._weaponsOnlineTimer.isRunning) ps._weaponsOnlineTimer.stop();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // checks for an expired docking request
    this.$dockingExpired = function $dockingExpired() {
    	var p = player.ship;
    	var ps = p.script;
    	if (ps._playerIsDocking === true) {
    		this.$displayCrosshairs();
    		//p.crosshairs = null; ps._previousCrosshairs;
    		ps._playerIsDocking = false;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // performs a scan of the missile array to see if any are still tracking the player
    this.$checkForIncomingMissiles = function $checkForIncomingMissiles() {
    	if (!this.ship || !this.ship.position) return;
    	var found = false;
    	var p = this.ship;
    	var ps = p.script;
    	// do we have any missiles in the queue?
    	if (ps._missiles.length === 0) {
    		if (ps._missileWarning === true) ps._missileWarningChanged = true;
    		ps._missileWarning = false;
    		return;
    	}
    	// are they in range and valid?
    	var ml = ps._missiles.length;
    	for (var i = 0; i < ml; i++) {
    		var m = ps._missiles[i];
    		if (m.isValid && m.isInSpace && m.position.distanceTo(p) < p.scannerRange) {
    			if (ps._missileWarning === false) ps._missileWarningChanged = true;
    			ps._missileWarning = true;
    			found = true;
    			break;
    		}
    	}
    	// has the flag state changed
    	if (found === false && ps._missileWarning === true) {
    		if (ps._missileWarning === true) ps._missileWarningChanged = true;
    		ps._missileWarning = false;
    		ps._missileWarningChanged = true;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$preRespray = function $preRespray() {
    	var sch = worldScripts.ShipConfiguration_F3HUDControl;
    	if (sch) this._holdHUD = sch._holdHUD;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$postRespray = function $postRespray() {
    	var sch = worldScripts.ShipConfiguration_F3HUDControl;
    	if (sch) sch._holdHUD = this._holdHUD;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$xenonHUDActive = function $xenonHUDActive() {
    	return (player.ship.hud.indexOf("XenonHUD") >= 0);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$switchAmberCrosshairs = function $switchAmberCrosshairs() {
    	var defList = ["xenon_crosshairs_alt1", "xenon_crosshairs_alt2", "xenon_crosshairs_alt3", "xenon_crosshairs_alt4", "xenon_crosshairs_alt5",
    		"xenon_crosshairs_beam", "xenon_crosshairs_military", "xenon_crosshairs_mining", "xenon_crosshairs_none", "xenon_crosshairs_other", "xenon_crosshairs_pulse"
    	];
    	var ch = this._crosshairList;
    	var extra = "";
    	if (this._amber === true) extra = "_amber";
    
    	this._dockingCrosshairs = "xenon_crosshairs_alt5" + extra + ".png";
    
    	// look for an existing entry and update the filename if found
    	var list = Object.keys(ch);
    	for (var i = 0; i < list.length; i++) {
    		var laser = list[i];
    		for (var j = 0; j < defList.length; j++) {
    			if (ch[laser].indexOf(defList[j]) >= 0) {
    				ch[laser] = defList[j] + extra + ".png";
    			}
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$updateShipConfigHUD = function $updateShipConfigHUD() {
    	// tell ShipConfig to use our HUD on the F3 Equip Ship screen
    	var sch = worldScripts.ShipConfiguration_F3HUDControl;
    	var p = player.ship;
    	if (sch && p.hud.indexOf(this.name) >= 0) {
    		if (!sch._holdHUD) sch._holdHUD = sch._equipSpaceHUD;
    		sch._equipSpaceHUD = this.name + "_docked" + (this._amber === false ? "" : "_amber") + ".plist";
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$revertShipConfigHUD = function $revertShipConfigHUD() {
    	// tell ShipConfig to go back to it's former HUD on the F3 Equip Ship screen
    	var sch = worldScripts.ShipConfiguration_F3HUDControl;
    	var p = player.ship;
    	if (sch && sch._holdHUD) {
    		sch._equipSpaceHUD = sch._holdHUD;
    		delete sch._holdHUD;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$removeHUDEquipment = function $removeHUDEquipment() {
    	var p = player.ship;
    	var remove = ["EQ_XENONHUD_CLOCK_1", "EQ_XENONHUD_CLOCK_2", "EQ_XENONHUD_CLOCK_3"];
    	for (var i = 0; i < remove.length; i++) p.removeEquipment(remove[i]);
    	// reset other elements
    	p.setCustomHUDDial("local_missileWarning", "");
    	p.setCustomHUDDial("local_selectedMissile", "");
    	p.setCustomHUDDial("local_fuelLeakWarning", "");
    	p.setCustomHUDDial("local_masslockIndicator", "");
    	p.setCustomHUDDial("local_cloakIndicator", "");
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$changeSettings = function $changeSettings() {
    	this.$updateShipConfigHUD();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // setup a FCB to monitor when hicontrast mode should be turned on/off
    this.$setUpHCFCB = function $setUpHCFCB() {
    	// isSunlit is a feature only in the latest release
    	if (!("isSunlit" in player.ship)) return;
    	// if the primable equipment is still active, don't start the FCB - player wants manual control
    	if (this._removePrimableEquip == false) return;
    	this._hc_fcb = addFrameCallback(this.$hiContrastFCB);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$hiContrastFCB = function (delta) {
    	// only do anything if we're on the main display
    	if (guiScreen != "GUI_SCREEN_MAIN") return;
    	var that = $hiContrastFCB;
    	var w = (that.w = that.w || worldScripts.XenonHUD);
    	var p = (that.p = that.p || player.ship);
    	if (!p || !p.position) return; // probably player has died
    	var mode = w._mode;
    	var switchHi = false;
    	var switchNrml = false;
    	// auto switch if we're in shadow but the mode is hicontrast
    	if (p.isSunlit == false && mode == "_hicontrast") {
    		switchNrml = true;
    	// don't need hi-contrast in interstellar space
    	} else if (mode == "_hicontrast" && system.isInterstellarSpace) {
    		switchNrml = true;
    	} else {
    		// no sun in interstellar space, so no need to switch
    		if (system.isInterstellarSpace) return;
    		var s = (that.s = that.s || system.sun);
    		var cf = (that.cf = that.cf || system.info.corona_flare);
    		if (!s || !s.position) {
    			s = system.sun;
    			cf = system.info.corona_flare;
    		}
    		var sgf = p.sunGlareFilter;
    		// point at which sun glare will become a problem
    		var dst_rng = [1900000, 1800000, 1700000, 1600000, 1500000, 1400000, 1270000, 1120000, 1120000, 1120000, 1120000];
    		var rng = dst_rng[parseInt(sgf * 10)];
    
    		// only check for the requirements if we're at a point where glare becomes a problem.
    		var dist = p.position.distanceTo(s);
    		var radius = s.radius * (1 + (8.0 * cf));
    		//log("fcb", "dist " + dist + ", radius " + radius + ", rng " + rng + ", cf " + cf + ", sgf " + sgf);
    		if (dist < rng) {
    			var deviation = 0;
    			switch (p.viewDirection) {
    				case "VIEW_FORWARD":
    					deviation = p.vectorForward.angleTo(s.position.subtract(p.position));
    					break;
    				case "VIEW_AFT":
    					deviation = p.vectorForward.angleTo(p.position.subtract(s.position));
    					break;
    				case "VIEW_PORT":
    					deviation = p.vectorRight.angleTo(p.position.subtract(s.position));
    					break;
    				case "VIEW_STARBOARD":
    					deviation = p.vectorRight.angleTo(s.position.subtract(p.position));
    					break;
    			}
    			deviation *= sgf; 
    			var calc = radius / dist;
    			// by this point, we should be ignoring heading
    			if (calc > (0.90 - cf)) deviation = 0; 
    			//log("fcb", "dist " + dist + ", rad " + radius + ", cf " + cf + ", calc " + calc + ", dev " + deviation + ", curr mode " + w._mode);
    			// pointing at main part of sun
    			if (mode == "" && deviation < calc) switchHi = true;
    			// pointing away from main part of sun
    			if (mode == "_hicontrast" && deviation > calc) switchNrml = true;
    		} else {
    			if (mode == "_hicontrast") switchNrml = true;
    		}
    	}
    	if (switchHi == true && clock.absoluteSeconds > w._lastSwitch + 1) {
    		w._mode = "_hicontrast";
    		p.hud = "XenonHUD_hicontrast" + (w._amber === false ? "" : "_amber") + ".plist";
    		if (p.script._playerIsDocking === true) p.crosshairs = "crosshairs_docking.plist";
    		w._lastSwitch = clock.absoluteSeconds;
    		return;
    	}
    	if (switchNrml == true && clock.absoluteSeconds > w._lastSwitch + 1) {
    		w._mode = "";
    		p.hud = "XenonHUD" + (w._amber === false ? "" : "_amber") + ".plist";
    		if (p.script._playerIsDocking === true) p.crosshairs = "crosshairs_docking.plist";
    		w._lastSwitch = clock.absoluteSeconds;
    		return;
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // turn off the FCB
    this.$stopFCB = function() {
    	if (isValidFrameCallback(this._hc_fcb)) removeFrameCallback(this._hc_fcb);
    	if (isValidFrameCallback(this._wc_fcb)) removeFrameCallback(this._wc_fcb);
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // adds/removes equipment items for controlling the mfd underlays (used in hi-contrast mode)
    this.$setMFDUnderlays = function $setMFDUnderlays() {
    	var p = player.ship;
    	var mfd = p.multiFunctionDisplayList;
    	for (var i = 0; i < mfd.length; i++) {
    		if (mfd[i] != null && mfd[i] != "" && this.$confirmMFDEquipment(mfd[i]) == true) {
    			p.awardEquipment("EQ_XENONHUD_MFD" + (i + 1).toString());
    		} else {
    			p.removeEquipment("EQ_XENONHUD_MFD" + (i + 1).toString());
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // because there is no direct connection between equipment items and MFD ID's we're doing a translation here
    this.$confirmMFDEquipment = function $confirmMFDEquipment(mfdID) {
    	var list = null;
    	switch (mfdID) {
    		case "combat_MFD": list = ["EQ_COMBATMFD"]; break;
    		case "telescope": list = ["EQ_TELESCOPE"]; break;
    		case "escortdeck": list = ["EQ_ESCORTDECK", "EQ_ESCORTDECKXL"]; break;
    		case "CommsLogMFD": list = ["EQ_COMMSLOGMFD", "EQ_COMMSLOGMFD_PASSIVE"]; break;
    		case "BroadcastCommsMFD": list = ["EQ_BROADCASTCOMMSMFD"]; break;
    		case "trophy_mfd": list = ["EQ_TROPHY_MFD"]; break;
    		case "navi_mfd": list = ["EQ_NAVIGATION_MFD"]; break;
    		case "market_inquirer": list = ["EQ_MARKET_INQUIRER_MFD"]; break;
    		case "manifest_mfd": list = ["EQ_MANIFEST_MFD"]; break;
    		case "useful_MFD_general_info": list = null; break; // no equip for this one
    		case "Waypoint_Here_MFD": list = ["EQ_WPH_ASC_UPGRADE"]; break;
    		case "DamageReportMFD": list = ["EQ_DAMAGE_REPORT_MFD", "EQ_DAMAGE_REPORT_MFD_PASSIVE"]; break;
    		case "RangeFinderMFD": list = ["EQ_GCM_RANGE_FINDER_MFD"]; break;
    		case "LaunchQueueMFD": list = null; break; // no equip for this one
    		case "BountySystem_WarrantScanner": list = ["EQ_WARRANT_SCANNER"]; break;
    	}
    	if (list == null) return true;
    	var p = player.ship;
    	for (var i = 0; i < list.length; i++) {
    		if (p.equipmentStatus(list[i]) == "EQUIPMENT_OK") return true;
    	}
    	return false;
    }
    Scripts/xenonhud_conditions.js
    "use strict";
    this.name        = "XenonHUD_Equipment";
    this.author      = "phkb";
    this.copyright   = "2018 phkb";
    this.description = "Condition script for Xenon HUD equipment";
    this.licence     = "CC BY-NC-SA 4.0";
    
    this.allowAwardEquipment = function(equipment, ship, context) {
    	if (context != "scripted") return false;
    	return true;
    }
    Scripts/xenonhud_equip.js
    "use strict";
    this.name        = "XenonHUD_Equipment";
    this.author      = "phkb";
    this.copyright   = "2018 phkb";
    this.description = "Controls switching of XenonHUD to hi-contrast mode";
    this.licence     = "CC BY-NC-SA 4.0";
    
    //======================================================================================================================
    // N key - used to turn hi-contrast mode on/off
    this.activated = function() {
    	var w = worldScripts.XenonHUD;
    	// can't change the HUD during a jump countdown
    	if (w._jumpCountdownStarted === true) {
    		player.consoleMessage("Unable to switch modes during jump countdown.");
    		return;
    	}
    
    	if (w._mode == "") {
    		player.consoleMessage("Hi-contrast mode activated");
    		w._mode = "_hicontrast";
    	} else {
    		player.consoleMessage("Normal mode activated");
    		w._mode = "";
    	}
    	w.guiScreenChanged("", "");
    	this.$playSound("mode"); // we'll use the same sound for mode and activate
    }
    
    //======================================================================================================================
    // B key - used to cycle through the different crosshair modes
    this.mode = function() {
    	var w = worldScripts.XenonHUD;
    	w._crosshairMode += 1;
    	if (w._crosshairMode == 3) w._crosshairMode = 0;
    	switch (w._crosshairMode) {
    		case 0:
    			player.consoleMessage("Crosshairs on in all conditions");
    			break;
    		case 1:
    			player.consoleMessage("Crosshairs on in condition red only");
    			break;
    		case 2:
    			player.consoleMessage("Crosshairs on in condition yellow and red only");
    			break;
    	}
    	w.$displayCrosshairs();
    	this.$playSound("mode");
    }
    
    //-------------------------------------------------------------------------------------------------------------
    // play sound effects
    this.$playSound = function(soundtype) {
    	var mySound = new SoundSource;
    
    	switch (soundtype) {
    		case "mode":
    			mySound.sound = "[@click]";
    			break;
    		case "activate":
    			mySound.sound = "[@beep]";
    			break;
    		case "stop":
    			mySound.sound = "[@boop]";
    			break;
    	}
    	mySound.loop = false;
    	mySound.play();
    }