Back to Index Page generated: May 8, 2024, 6:16:03 AM

Expansion Carriers

Content

Warnings

  1. Syntax Error Config/effectdata.plist[494:58] extraneous input '.0' expecting {')', ','}
  2. Found 1 issues in Config/effectdata.plist

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Build up your personal fleet and take with you on your Carrier. Requires EscortDeck OXP and Ship Storage Helper OXP. Build up your personal fleet and take with you on your Carrier. Requires EscortDeck OXP and Ship Storage Helper OXP.
Identifier oolite.oxp.Norby.Carriers oolite.oxp.Norby.Carriers
Title Carriers Carriers
Category Ships Ships
Author Norby Norby
Version 0.10 0.10
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
  • oolite.oxp.Norby.EscortDeck:1.1
  • oolite.oxp.CaptMurphy.ShipStorageHelper:0.22
  • oolite.oxp.Norby.EscortDeck:1.1
  • oolite.oxp.CaptMurphy.ShipStorageHelper:0.22
  • Optional Expansions
  • oolite.oxp.Norby.EscortPack:1.0
  • oolite.oxp.Norby.EscortPack:1.0
  • Conflict Expansions
    Information URL http://wiki.alioth.net/index.php/Carriers n/a
    Download URL https://wiki.alioth.net/img_auth.php/d/d0/Carriers_0.10.oxz n/a
    License CC BY-NC-SA 4.0 CC BY-NC-SA 4.0
    File Size n/a
    Upload date 1630137493

    Documentation

    Also read http://wiki.alioth.net/index.php/Carriers

    Carriers_readme.txt

    Carriers OXP
    
    Requires EscortDeck and Ship Storage Helper, recommends EscortPack OXP.
    
    When this addon will be finished then you can build up your escort fleet on the decks of a Carrier and you can sit into any escort ship to fight within a much faster and agile ship if needed.
    
    The hull of a Carrier can hold up to 10 escort ships and barely fit into a standard 64m x 192m x 250m dock together with the carried ships. You can check your escorts in external views by pressing the "v" key.
    
    Please select the configuration of your Escort Deck by purchasing either the default (for trading and salvaging) or the XL equipment (for combat).
    
    
    Escort Deck equipment
    
    Prime this equipment to launch and call back your escorts.
    
    The default configuration allow 9 ships on board: 2 big traders (Anaconda), 2 ships up to Cobra Mark III and 5 escort ships: 1 heavy (Asp), 2 small (Gecko) and 2 mini (Adder). Practical for salvaging more derelict ships in the same time: if you like to earn money with a Towbar then a Carrier is especially useful for you.
    
    Top decks (1.-2.): a large space on the front and another over the middle engine. Can hold ships with less than 130m width, 35m height, 95m length and 800t mass up to Cobra Mark III.
    
    Center deck (3.): on the neck for a heavy escort up to Asp (65x29x95m and 130t), so Krait and Cobra Mark III can't fit. This deck is lifted over the others a bit to avoid collisions with big Anacondas in main decks or long Fer-De-Lances in front or aft top decks.
    
    Aft side decks (4.-5.): hold small escorts over side engines (65x17x65m and 40t): Adder, Gecko or Sidewinder.
    
    Main decks (6.-7.):  the largest space on the sides can hold a pair of large trader ships up to 90x64x170m and 800t mass: Anaconda, Boa or Python. Anaconda and larger ships will not launch automatically at red alert - not so good fighters, better if not send them into the combat if not forced by hand.
    Heavy escorts (Asp) can fit also but if you want more escorts than all other decks can hold then you can change your configutation to the traderless XL Deck (see below).
    
    Good trader ships which can fit into the main decks: D.T.T. Atlas, D.T.T. Cyclops, Python Class Cruiser, Python ET Special.
    Large fighter-traders fit here: Granite Python from EscortPack and the very fast and agile Vector.
    
    Forward decks (8-9): on front for two Adders and other mini ships up to 39x15x65m and 30t mass.
    You can use these as additional shields on your Carrier if not launched.
    
    
    For more details please read the documentation of Escort Deck OXP: http://wiki.alioth.net/index.php/EscortDeck
    
    
    Escort Deck XL equipment
    
    The combat configuration of Carriers can hold 10 fighters: 2 ships up to Cobra Mark III on the top and 8 escorts: 4 heavy (Asp) within the main decks, 2 wide (Krait) over the engines and 2 mini (Adder) on front to give fearsome firepower into your hands. Most pirate groups will flee insantly after you released your fleet.
    
    
    Sit into an escort ship
    
    You can sit into and launch within a carried escort ship if you change the mode of Escort Deck from "avoid to sit into a selected escort" to "allow" the same option. First prime the deck with 'Shift+N', then press mode key (b) until this message will be displayed after step over your escorts. Press activate (n) to show "allow" instead of "avoid", then select an usable (non-salvage) escort ship landed on your deck with 'b' and use the 'n' key to launch yourself within the selected ship.
    
    You can launch in playable ships only (has player role and view positions in shipdata.plist and defined in shipyard.plist at least with chance=0), otherwise the ship will be launched without you. EscortDeck will try to replace the -trader and -pirate suffixes in dataKeys and use the -player variant if available, but in other cases you must make playable by hand in the ship's OXP.
    
    When you are not in the Carrier you still can check your wingmans on MFD and command them to attack a target by locking it and delivering a laser hit.
    
    For landing you must hold your ident lock (using 'r') on your Carrier to get landing clearance, then approach within 500m and less than 100m/s speed difference to start the landing sequence. You will be transferred into the bridge of Carrier after the docking tunnel.
    
    Unfortunately you can not sit into a ship with 0 max.missiles like standard Krait, Mamba and Sidewinder due to a core bug. Buyable Sidewinder Escorts has 1 max.missiles just to avoid this and allow sit into.
    
    == FLYING ESCORTS CURRENTLY EXPERIMENTAL! For example do not dock into a station while you are in an escort, nor enter into a wormhole, go back into your Carrier first. ==
    
    
    
    == Warning: informations below this point are unfinished, if there are scripted parts of these then in alpha state so probably contain bugs and missing features. ==
    
    
    Instant launch
    
    The top front landing position will acts as a command bridge: if your ship is landed on the first pad then you will be able to steer the Carrier and launch yourself immediately without going through the undocking tunnel. In this case the Carrier is a very large detachable escort deck under the Commander's ship.
    
    
    Trading
    
    You will be able to use the cargo capacity of traders on your deck. If you have 6 Cobra Mark I on board then your total cargo capacity is 110t, but you will not see this in one piece. You will be able to switch between your ships when you are in a dock but you will see one cargo bay only at a time.
    
    If you want a really big trader ship then collect a pair of Anacondas into your carrier.
    
    
    Fuel
    
    Carriers has normal tanks only but will transfer fuel from the carried ships to keep over 6 ly, and will refuel the ship selected by the Commander before launch until there are any fuel in other ships on board.
    
    The Commander can open a wormhole if he want to travel into another system and all ships in the fleet will jump into.
    
    
    
    Have fun, Fleet Commander! :)
    
    
    
    Instructions:
    
    Do not unzip the .oxz file, just move into the AddOns folder of your Oolite installation.
    
    Correct landed escort positions need Oolite 1.81. In 1.80 all escorts moved well over the hull to avoid collisions.
    
    There is a savegame in the package, copy into your oolite-saves directory if you want an instant test flight.
    
    
    License:
    
    The 3D model of all Carriers is derived from HammerHead in Aquatics OXP, thanks to Thargoid and P.A. Groove.
    Carriers_escortAI.plist is based on hiredGuns_escortAI.plist in Hired Guns OXP by Thargoid which is based on upsPrivateEscortAI.plist in UPS-Courier OXP by Eric Walch.
    The carriers-escort.js is based on hiredGuns_escort.js in Hired Guns OXP by Thargoid.
    
    This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License version 4.0.
    If you are re-using any piece of this OXP, please let me know by sending an e-mail to norbylite@gmail.com.
    
    
    Changelog:
     2021.08.21. v0.10 Fixed a couple of errors in the shipdata.plist file.
     2015.01.20. v0.9  Sit into feature is fixed and enabled by default.
     2015.01.11. v0.8  Use Escort Deck equipment to launch and call back escorts.
                       XL deck can hold 10 escorts.
                       Test version of the "sit into an escort ship" feature.
                       Pitch and yaw rates of Carriers are changed from 0.3 to 0.5.
     2014.06.20. v0.7  Center deck is lifted over others to fit more ship types up to Asp.
     2014.06.19. v0.6  Moray is fit into the center deck due to the narrow aft.
                       Fixed shader filename, thanks to Stormrider.
     2014.06.19. v0.5  Front Adder decks added.
     2014.06.18. v0.4  Top front deck is upgraded to hold a large ship.
     2014.06.17. v0.3  Narrower head on Carriers to fit Anaconda in straight.
     2014.06.16. v0.2  Anaconda and Fer-De-Lance Carrier models added.
     2014.06.15. v0.1  First ship models.
    

    Equipment

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

    Ships

    Name
    Anaconda Carrier
    anaconda-carrier-pirate
    anaconda-carrier-player
    Carriers alloy
    Carriers dock
    Carrier
    Carriers vdock
    Cobra Mark I Carrier
    cobra1-carrier-pirate
    cobra1-carrier-player
    Cobra Mark III Carrier
    cobra3-carrier-pirate
    cobra3-carrier-player
    Carrier
    Fer-De-Lance Carrier
    empty-carrier-player
    Viper Carrier
    Fer-De-Lance Carrier
    ferdelance-carrier-pirate
    ferdelance-carrier-player
    Viper Carrier
    viper-carrier-player
    viper-carrier-police

    Models

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

    Scripts

    Path
    Scripts/carriers.js
    "use strict";
    this.name        = "carriers";
    this.author      = "Norby";
    this.copyright   = "2015 Norbert Nagy";
    this.licence     = "CC BY-NC-SA 4.0";
    this.description = "Carriers with open decks.";
    
    this.$Debug = false; //verbose log
    this.$CarriersSitInto = true; //turn on the "sit into the ecort during flight"
    this.$CarriersSitIntoWithMode = true; //show the mode menu item on primed EscortDeck to enable sit into
    
    //internal properties, should not touch
    this.$CarriersBG = ""; //backgroung image for missionscreens of Carriers
    this.$CarriersCarrier = null; //the carrier ship object, used in carriers-escort.js ship script
    this.$CarriersDocked = false; //flag if the player is the current ship is a carrier when player is docked
    this.$CarriersED = null; //store a pointer to escortdeck worldscript
    this.$CarriersEDEQ = null; //which deck player have: normal or XL
    this.$CarriersEscortData = null; //temporary storage of selected escort's data when sit into
    this.$CarriersEDCarrierPad = -1; //this pad on Escort Deck store the Carrier when player sit into an escort
    this.$CarriersFCB = null; //FrameCallBack for calling event handlers after launch
    this.$CarriersFCBArray = []; //store event handlers for FrameCallBack
    this.$CarriersLastShip = null; //store the last player ship which is docked into a station for detect restore
    this.$CarriersPirate = null; //store a created pirate carrier
    this.$CarriersPlayerInEscort = false; //flag for EscortDeck FCB
    this.$CarriersPrevCarrier = null; //save last name to avoid repeated landing clearance message
    this.$CarriersS = null; //store the created trader ship to prevent recreates
    this.$CarriersShip = null; //store the created trader ship to prevent recreates
    this.$CarriersShipStorage = []; //store the carried escort ships, the 0. position store the carrier itself
    this.$CarriersSH = null; //store a pointer to Ship_Storage_Helper.js worldscript
    this.$CarriersSV = null; //store a pointer to shipversion worldscript
    this.$CarriersSVB = null; //store the whole playerBoughtNewShip() code of shipversion
    this.$CarriersT = null; //store a pointer to telescope worldscript
    this.$CarriersTimer = null; //general timer for landing back on Carrier
    //this.$CarriersTimerL = null; //delay timer for PS.launch()
    //this.$CarriersTimerV = null; //delay timer for vdock remove
    this.$CarriersVDock = null; //Virtual dock for ship change during launch an escort from the carrier
    this.$EscortDeckLandingDist = 500; //landing distance, will be overwritten if EscortDeck OXP present
    
    //world script events
    this.startUp = function() {
    	if(worldScripts["BGS-M"]) this.$CarriersBG = "bgs-i_equipship.png";
    	else if(worldScripts["Better Screens"]) this.$CarriersBG = "bs-base-bg.png";
    	else if(worldScripts["Gallery"]) this.$CarriersBG = "gallery_bg.png";
    	
    	this.$CarriersTimer = new Timer(this, this.$Carriers_Timed.bind(this), 2, 2);
    	this.$CarriersED = worldScripts.escortdeck;
    	if(!this.$CarriersED) log("Carriers", "Error: Carriers can not handle escorts without EscortDeck OXP");
    	else {
    		this.$EscortDeckLandingDist = this.$CarriersED.$EscortDeckLandingDist;
    		this.$CarriersED.$EscortDeckSitInto = this.$CarriersSitInto;
    		this.$CarriersED.$EscortDeckSitIntoWithMode = this.$CarriersSitIntoWithMode;
    	}
    	
    	this.$CarriersSH = worldScripts["Ship_Storage_Helper.js"];
    	if(!this.$CarriersSH) log("Carriers", "Error: Carriers can not change ship without Ship Storage Helper OXP");
    	else {
    //		player.credits += 1000000;//debug ;)
    	}
    	this.$CarriersSV = worldScripts.shipversion;
    	this.$CarriersT = worldScripts.telescope;
    
    	var s = missionVariables.$CarriersShipStorage;
    	if( s && s.length > 0 )	this.$CarriersShipStorage = JSON.parse(s);
    
    	this.$CarriersVDock = null; //Virtual dock for ship change during launch an escort from the carrier
    	this.$CarriersEDCarrierPad = -1; //this pad store the Carrier when player sit into an escort
    	this.$CarriersPlayerInEscort = false;
    
    	this.$Carriers_CheckCarrier();
    }
    
    this.guiScreenChanged = function(to, from) {
    	var ps = player.ship;
    	var w = this.$CarriersED;
    	if( to != "GUI_SCREEN_STATUS" || !ps.docked ) return;
    	if(this.$Debug) log("Carriers", "guiScreenChanged "+to+" docked:"+ps.docked+" "+ps.dockedStation+" "
    		+this.$CarriersSitInto+" vdock:"+this.$CarriersVDock);
    	if( !w || !this.$CarriersVDock ) return;
    
    	var h = worldScripts.hudselector;
    	if( h ) h.$HUDSelectorRestoreHUD(); //give back the actual HUD - must if restoreShipData breaks
    
    //5. step: Call launch() to do not stay within the virtual dock.
    	ps.launch();
    //call in timer if do not work well here
    //	this.$CarriersTimerL = new Timer(this, this.$Carriers_TimedL.bind(this), 0.001, 0);
    //	if(this.$Debug) log(this.name,"TimerL started: "+this.$CarriersTimerL);
    //	var f = this.$Carriers_TimedL.bind(this); f("aha"); //skip timer delay and call instantly
    	
    	if( ps != this.$CarriersCarrier ) { //restore escort equipments
    		w.$EscortDeck_RestoreShipData(ps, this.$CarriersEscortData, w);
    		//Escort Deck or XL deck for using MFD and primable functions
    		ps.awardEquipment(this.$CarriersEDEQ);//again for sure
    		if( h ) h.$HUDSelectorRestoreHUD(); //give back the actual HUD again for sure
    	}
    }
    
    this.playerWillSaveGame = function(message) {
           missionVariables.$CarriersShipStorage = JSON.stringify(this.$CarriersShipStorage);
    }
    
    this.shipAttackedOther = function(other) { //player hits other
    	if( !other.script ) other.script = "oolite-default-ship-script.js"; //for sure
    	if( other.script ) other.script.$Carriers_Target = 1; //flag for carrier AI
    }
    
    this.shipCollided = function( pt ) {
    	if( pt && pt.isValid && pt == this.$CarriersCarrier //exclude carriers in exhibitions of Gallery OXP
    		&& player.ship && player.ship.isValid && player.ship.target == pt ) {
    		this.$Carriers_DockPlayer( pt );
    	}
    }
    
    this.shipDockedWithStation = function(station) {
    	var ps = player.ship;
    	var w = this.$CarriersED;
    	if(this.$Debug) log("Carriers", "sDWS station.dataKey:"+station.dataKey
    		+" pad:"+w.$EscortDeckSelectedPad+" cpad:"+this.$CarriersEDCarrierPad
    		+" ps.dockedStation:"+ps.dockedStation+" inEscort:"+this.$CarriersPlayerInEscort
    		+" vdock:"+this.$CarriersVDock);
    	if( !w || !this.$CarriersVDock ) return;
    
    	if( this.$CarriersPlayerInEscort ) { //sit into the carrier
    		this.$CarriersPlayerInEscort = false;
    		player.consoleMessage("Welcome home, Commander "+player.name+"!", 5);
    		this.$Carriers_SitIntoTheCarrier();
    		this.$CarriersEDCarrierPad = -1;
    		if( ps.equipmentStatus("EQ_ESCORTDECKXL") == "EQUIPMENT_OK" )
    			ps.removeEquipment("EQ_ESCORTDECK"); //bugfix
    		return;
    	} else { //launch player in an escort
    //3. step: Replace player ship to the escort using Ship Storage Helper.
    		//this pad on Escort Deck store the Carrier when player sit into an escort
    		var pad = this.$CarriersEDCarrierPad;
    
    		this.$CarriersEDEQ = "EQ_ESCORTDECK";
    		if( ps.equipmentStatus("EQ_ESCORTDECKXL") == "EQUIPMENT_OK" )
    			this.$CarriersEDEQ = "EQ_ESCORTDECKXL"; //save the current deck equipment
    
    		this.$CarriersEscortData = w.$EscortDeckShipData[pad];
    		var s = JSON.stringify(this.$CarriersEscortData);
    		if(this.$Debug) log("Carriers", "pad "+pad+": "+s);
    		if( s && s.length > 0 ) {
    			this.$CarriersCarrier = ps;
    			if(ps.script) ps.script.$EscortDeckUsable = 1; //carrier is always usable
    			this.$CarriersShipStorage[0] = this.$Carriers_StoreShip(); //save the carrier
    //4. step: Remove the old escort and spawn a Carrier.
    			if( w.$EscortDeckShip[pad] && w.$EscortDeckShip[pad].isValid
    				&& w.$EscortDeckShip[pad] != ps )
    				w.$EscortDeckShip[pad].remove(true);//remove NPC escort
    			w.$EscortDeckShipData[pad] = null; //prevent recreation in dock
    			w.$EscortDeckShipPos[pad] = null; //do not update position in FCB
    			if(this.$Debug) log("Carriers","Stored: "+this.$CarriersShipStorage[0]);
    			this.$CarriersPlayerInEscort = true; //set it before RestoreShip to avoid salvaging
    			if( !this.$Carriers_RestoreShip(s, true) ) {
    				this.$CarriersPlayerInEscort = false;//set back if restore failed
    				log("Carriers","Error: can not sit into "+s);
    				return; //failed to sit into the escort
    			}
    		} else return;
    		if(this.$Debug) log("Carriers", "Player ship changed to pad "+pad+": "+s);
    
    		var c = null; //spawn the carrier behind the player after takeoff
    		var pos = this.$CarriersVDock.position.add(this.$CarriersVDock.heading
    			.multiply(-(this.$EscortDeckLandingDist-100)));
    		var b = JSON.parse(this.$CarriersShipStorage[0]); // destringify the carrier
    		if( b.length > 1 && b[1].length > 0 ) //b[1] is the stored dataKey of carrier
    			c = system.addShips("["+b[1]+"]", 1, pos, 10);
    		if( c && c[0] && c[0].isValid ) {
    			w.$EscortDeck_RestoreShipData(c[0], b, w);
    			if(c[0].addCollisionException) { //from v1.81
    				for(var i = 0; i < w.$EscortDeckPadPos.length; i++ ) {
    					if( w.$EscortDeckShip && w.$EscortDeckShip[i] )
    						c[0].addCollisionException(w.$EscortDeckShip[i]);
    				}
    			}
    			w.$EscortDeckShip[pad] = c[0]; //replace the escort with the Carrier in MFD
    			this.$Carriers_EscortSetup(c[0], 0); //give AI to the npc carrier
    			this.$CarriersCarrier = c[0];
    			
    		} else log("Carriers","Error: can not create Carrier at escort takeoff");
    		if(this.$Debug) {
    			log("Carriers","b:"+b);
    			log("Carriers","c:"+c);
    		}
    		
    		w.$EscortDeck_RestoreShipData(ps, this.$CarriersEscortData, w);
    		//Escort Deck or XL deck for using MFD and primable functions
    		ps.awardEquipment(this.$CarriersEDEQ);
    //5. step: Call launch() to do not stay within the virtual dock.
    //		ps.launch(); - drop player.ship.dockedStation is null error in Commander's Log
    	}
    }
    
    this.shipLaunchedFromStation = function() {
    //6. step: Remove the virtual dock - need allow_launching=true; of vdock in shipdata.plist
    	if(this.$Debug) log(this.name,this.name+".shipLaunchedFromStation called");
    	this.$Carriers_RemoveVDock();
    }
    
    this.shipTargetAcquired = function(target) {
    	this.$CarriersPrevCarrier = null; //to get landing clearance message a bit later
    }
    
    this.shipWillDockWithStation = function() {
    	this.$Carriers_CheckCarrier();
    }
    
    this.shipWillLaunchFromStation = function() {
    	if(this.$Debug) log(this.name,this.name+".shipWillLaunchFromStation called");
    /*	if( this.$CarriersVDock ) {
    		this.$CarriersTimerV = new Timer(this, this.$Carriers_TimedV.bind(this), 4, 0);
    		if(this.$Debug) log(this.name,"TimerV started: "+this.$CarriersTimerV);
    	}*/
    }
    
    //Carriers functions
    this.$Carriers_CheckCarrier = function() {
    	var ws = worldScripts["carriers"];
    	var ps = player.ship;
    	if( ps && ps.isValid && ps.dataKey && ps.dataKey.indexOf("carrier-player") > -1 ) { //current ship is a carrier
    		ws.$CarriersDocked = true;
    		ws.$CarriersCarrier = ps;
    		ws.$CarriersShipStorage[0] = ws.$Carriers_StoreShip(); //save the carrier
    	} else ws.$CarriersDocked = false;
    }
    
    this.$Carriers_DockPlayer = function( pt ) {
    	var ws = worldScripts.carriers;
    	//check speed difference
    	var diff = player.ship.velocity.subtract( pt.velocity ).magnitude();
    	if( diff > 100 ) {
    		player.consoleMessage(Math.round(diff)+" m/s speed difference deny landing on "
    			+ws.$CarriersPrevCarrier, 5);
    	} else {
    		var ps = player.ship;
    		var w = ws.$CarriersED;
    		var pos = pt.position.add(pt.vectorForward.multiply(1000));
    		ws.$CarriersVDock = system.addShips("[carriers-vdock]", 1, pos, 100)[0];
    		if( w && ws.$CarriersVDock ) {
    			ws.$CarriersVDock.orientation = pt.orientation; //the direction of launch
    			if(ps.addCollisionException)  //from v1.81
    				ps.addCollisionException(ws.$CarriersVDock);
    			ws.$CarriersVDock.dockPlayer();
    		} else log("Carriers", "Error: can not create virtual dock for sit into the carrier");
    	}
    }
    
    this.$Carriers_EscortSetup = function( e, id ) {
    	var ws = worldScripts.carriers;
    	var w = ws.$CarriersED;
    	var ai = "interceptAI.plist"; //fallback ai if no escortdeck oxp present
    	if( w ) ai = "EscortDeck_AI.plist";
    
    	var ps = player.ship;
    	if( e && e.isValid ) {
    		if(!ps.group) ps.group = new ShipGroup("CarriersEscorts", ps); //player ship is the leader
    		ps.group.addShip(e);
    		e.switchAI(ai);
    		if( w ) e.AIState = ("GOTO");
    		e.scannerDisplayColor1 = [0.3, 1, 0.3]; //lightgreen
    		var usable = 0;
    		var sl = 0;
    		if(e.script) {
    			usable = e.script.$EscortDeckUsable; //must set again after setScript
    			sl = e.script.$SSH_serviceLevel; //must set again after setScript
    		}
    		if( w ) e.setScript("escortdeck_escort.js");
    		if(e.script) {
    			e.script.$CarriersEscortHome = ws.$CarriersCarrier; //set the owner carrier
    			e.script.$CarriersShipStorageID = id; //position in $CarriersShipStorage array
    			e.script.$EscortDeckUsable = usable;
    			e.script.$SSH_serviceLevel = sl;
    		}
    		e.orientation = ps.orientation;
    	} else log("Carriers","Error: can not setup escort #"+id+" "+e);
    }
    			
    this.$Carriers_FCB = function( delta ) { //FrameCallBack for calling event handlers after sit into an escort
    	var ws = worldScripts.carriers;
    	var f = null;
    	if( ws.$CarriersFCBArray ) f = ws.$CarriersFCBArray.pop();
    	if( f ) {
    		//if(ws.$Debug) log(ws.name,(ws.$CarriersFCBArray.length+1)+". call "+f);
    		f( ws.$CarriersVDock );
    	}
    }
    
    this.$Carriers_RemoveVDock = function() {
    	var ws = worldScripts.carriers;
    	if( ws.$CarriersVDock ) {
    		ws.$CarriersVDock.remove(true);
    		ws.$CarriersVDock = null;
    		if(ws.$Debug) log(ws.name,"VDock removed");
    	}
    	if( isValidFrameCallback( ws.$CarriersFCB ) )
    		removeFrameCallback( ws.$CarriersFCB );
    	if( ws.$CarriersTimerV ) {
    		ws.$CarriersTimerV.stop();
    		delete ws.$CarriersTimerV;
    	}
    }
    
    this.$Carriers_RestoreShip = function(storedShipString, escort) {
    	var ws = worldScripts.carriers;
    	if(ws.$CarriersSH) {
    		var h = worldScripts.hudselector;
    		if( h ) h.$HUDSelectorRestoreHUD(); //give back the actual HUD
    		if( escort ) {
    			var d = JSON.parse(storedShipString);
    			if(ws.$Debug) log("Carriers", "d1:"+d[1]+" d13:"+d[13]+" d:"+d);
    			if( !player.replaceShip(d[1],d[13]) ) return false;
    			var w = ws.$CarriersED;
    			if( w ) w.$EscortDeck_RestoreShipData(player.ship, d, w);
    			if(ws.$Debug) log("Carriers", "new player.ship: "+player.ship);
    		} else {
    			var e = ws.$CarriersSH.restoreStoredShip(storedShipString); //carrier
    			if(ws.$Debug) log("Carriers", "player.ship: "+player.ship+" e:"+e);
    			if( e && e.length > 1 ) return false;
    		}
    //		if(ws.$Debug) log("Carriers", "player.ship.maxEscorts: "+player.ship.maxEscorts);
    		//player.ship.maxEscorts= 16; //16 is the maximum allowed by the core game - but read only
    		return true;
    	} else log("Carriers", "Error: Carriers can not restore ship without Ship Storage Helper OXP");
    	return false;
    }
    
    this.$Carriers_SitIntoAnEscort = function(ship) { //called from EscortDeck's EQActivated
    	var ps = player.ship;
    	this.$CarriersCarrier = ps;
    	var ws = worldScripts.carriers;
    	
    //1. step: Spawn a virtual dock (a ship with a dock subentity) near the player ship.
    	var pos = ps.position.add(ps.vectorForward.multiply(1000));
    	ws.$CarriersVDock = system.addShips("[carriers-vdock]", 1, pos, 100)[0];
    	if( ws.$CarriersVDock && ws.$CarriersED ) {
    		ws.$CarriersEDCarrierPad = ws.$CarriersED.$EscortDeckSelectedPad;
    		player.consoleMessage( ship.name+" takeoff from "+ps.displayName, 10 );
    		ws.$CarriersVDock.orientation = ps.orientation; //the direction of launch
    		if(ps.addCollisionException)  //from v1.81
    			ps.addCollisionException(ws.$CarriersVDock);
    //2. step: Call dockPlayer() into vdock which show the docking tunnel.
    		ws.$CarriersVDock.dockPlayer();
    		//continued in this.guiScreenChanged
    	} else log("Carriers", "Error: can not create virtual dock for launch an escort");
    }
    
    this.$Carriers_SitIntoTheCarrier = function() {
    	//add the current escort ship into the first empty item of ship storage
    	var ws = worldScripts.carriers;
    	var w = ws.$CarriersED;
    	if( w ) {
    		w.$EscortDeckSelectedPad = -1;
    		var b = w.$EscortDeck_MakeShipData(player.ship);//need to be docked
    		var c = null; //spawn the escort behind the player
    		var pad = ws.$CarriersEDCarrierPad;
    		var pos = player.ship.position.add(player.ship.heading
    			.multiply(-(w.$EscortDeckLandingDist-100)));
    		if( b.length > 1 && b[1].length > 0 ) //b[1] is the stored dataKey of escort
    			c = system.addShips("["+b[1]+"]", 1, pos, 1000);
    		if( c && c[0] && c[0].isValid ) {
    			if(c[0].addCollisionException) { //from v1.81
    				c[0].addCollisionException(player.ship);
    			}
    			w.$CarriersLastShip = c[0];
    			w.$EscortDeck_RestoreShipData(c[0], b, w);
    			w.$EscortDeck_PutShip(c[0], pad, player.ship, w, false, true );
    		} else log("Carriers","Error: can not create escort in"
    			+"$Carriers_SitIntoTheCarrier b[1]:"+b[1]+" c:"+c+" pos:"+pos);
    		if( ws.$CarriersCarrier != player.ship ) ws.$CarriersCarrier.remove(true); //remove the npc carrier
    		ws.$Carriers_RestoreShip(ws.$CarriersShipStorage[0]);
    		ws.$CarriersCarrier = player.ship;
    	}
    	if(ws.$Debug) log("Carriers", "CSITC Player ship:"+player.ship.dataKey
    		+" "+player.ship.name+"/"+player.ship.displayName);//debug
    }
    
    this.$Carriers_StoreShip = function() {
    	var ws = worldScripts.carriers;
    	var sh = ws.$CarriersSH;
    	if( sh ) {
    		var storedShipString = sh.storeCurrentShip();
    		sh.disableVortexPBNSFunc("delete");
    		sh.disableMaelstromPBNSFunc("delete");
    		sh.disableTCATPBNSFunc();
    		return(storedShipString);
    	} else log("Carriers", "Error: Carriers can not store ship without Ship Storage Helper OXP");
    }
    
    this.$Carriers_Timed = function() {
    	var ps = player.ship;
    	if( !ps || !ps.isValid ) return; //player died
    
    	if( this.$CarriersPlayerInEscort ) {
    		var c = this.$CarriersCarrier;
    		if( !c || !c.isValid ) {
    			this.$CarriersPlayerInEscort = false; //if carrier died
    			var w = this.$CarriersED;
    			if( w ) {
    				w.$EscortDeck_ControlAll( true, false, w ); //launch all
    				var pad = w.$CarriersEDCarrierPad;
    				w.$EscortDeckShip[pad] = null;
    				w.$EscortDeckShipData[pad] = null;
    				w.$CarriersEDCarrierPad = -1;
    			}
    		}
    	}
    
    	var m = system.mainStation; //add some NPC carriers
    	if( m && m.isValid && ( !this.$CarriersShip || !this.$CarriersShip.isValid ) ) { //delayed create
    		if( system.government < 5 )
    			this.$CarriersPirate = system.addShipsToRoute("carriers-pirate", 1, Math.random(), "wp")[0];
    		this.$CarriersShip = system.addShips("carriers-trader", 1, m.position, 150000)[0];
    //		this.$CarriersShip = system.addShips("anaconda-carrier", 1, m.position, 15000)[0];//debug
    //		this.$CarriersShip = system.addShips("cobra1-carrier", 1, m.position, 15000)[0];//debug
    //		this.$CarriersShipRH = system.addShips("rockhermit", 1, this.$CarriersShip.position, 15000)[0];//debug
    //		this.$CarriersShipRH.target = this.$CarriersShip;
    //		this.$CarriersShip.target = this.$CarriersShipRH;
    //		this.$CarriersShip.setAI("dockingAI.plist");
    //		this.$CarriersShip = system.addShips("empty-carrier", 1, m.position, 5000)[0];//debug
    //		this.$CarriersShip.setAI("nullAI.plist");//debug
    		if(this.$Debug) log("Carriers", "Added "+this.$CarriersShip);//debug
    	}
    	
    	var pt = ps.target; //player is landing on carrier
    	if( pt && pt.isValid && pt.dataKey && pt.dataKey.indexOf("carrier") > -1
    		&& pt == this.$CarriersCarrier ) { //exclude carriers in exhibitions of Gallery OXP
    		var d = ps.position.distanceTo(pt) - pt.collisionRadius;
    		if( d < 25000 && pt.displayName != this.$CarriersPrevCarrier ) { //carrier within 25km
    			pt.switchAI("EscortDeck_AI.plist"); //leave waypoint AI
    			pt.AIState = "LANDING"; //do not run from the player
    			player.consoleMessage( "Landing approved on "+pt.displayName, 10 );
    			this.$CarriersPrevCarrier = pt.displayName; //save last name to avoid repeated message
    		} else if( d < this.$EscortDeckLandingDist ) { //carrier within 500m
    			this.$Carriers_DockPlayer( pt );
    		}
    	}
    	
    	if( this.$CarriersT && ps.viewPositionForward ) { //fix telescope visual target pos.(need 1.79)
    		this.$CarriersT.$TelescopeVPos =
    			ps.viewPositionForward.add(this.$CarriersT.$TelescopeVPosHUD);
    	}
    }
    /*
    this.$Carriers_TimedL = function(a) {
    	var ps = player.ship;
    	if( !ps || !ps.isValid ) return; //player died
    	var ws = worldScripts.carriers;
    
    	var h = worldScripts.hudselector;
    	if( h ) h.$HUDSelectorRestoreHUD(); //give back the actual HUD
    	
    //5. step: Call willLaunch handlers  - not needed if allow_launching=true; in the vdock
    //then launch() to do not stay within the virtual dock.
    	if( !isValidFrameCallback( ws.$CarriersFCB ) )
    		ws.$CarriersFCB = addFrameCallback( ws.$Carriers_FCB );
    
    	ws.$CarriersFCBArray = [];
    	ws.$CarriersFCBArray.push( function() {player.ship.launch();} );
    	for(var i in worldScripts) {
    		var f = worldScripts[i].shipWillLaunchFromStation;
    		if( f ) {
    			ws.$CarriersFCBArray.push( f.bind( worldScripts[i] ) );
    			if(ws.$Debug) log(ws.name, ws.$CarriersFCBArray.length+". "+i
    				+".shipWillLaunchFromStation added to FCBArray");
    		}
    	}
    	ps.launch();
    	if( ws.$CarriersTimerL ) {
    		ws.$CarriersTimerL.stop();
    		delete ws.$CarriersTimerL;
    	}
    	if(ws.$Debug) log(ws.name,"TimerL executed, a:"+a+" this:"+this);
    }
    
    this.$Carriers_TimedV = function() {
    	var ps = player.ship;
    	if( !ps || !ps.isValid ) return; //player died
    	var ws = worldScripts.carriers;
    
    //6. step: call launched events - not needed if allow_launching=true; in the vdock
    // then remove the virtual dock
    	ws.$CarriersFCBArray = [];
    	ws.$CarriersFCBArray.push( ws.$Carriers_RemoveVDock.bind(ws) );
    	for(var i in worldScripts) {
    		var f = worldScripts[i].shipLaunchedFromStation;
    		if( f && i != ws.name ) {
    			ws.$CarriersFCBArray.push( f.bind( worldScripts[i] ) );
    			if(ws.$Debug) log(ws.name, ws.$CarriersFCBArray.length+". "+i
    				+".shipLaunchedFromStation added to FCBArray");
    		}
    	}
    
    	if( ws.$CarriersTimerV ) {
    		ws.$CarriersTimerV.stop();
    		delete ws.$CarriersTimerV;
    	}
    	if(ws.$Debug) log(ws.name,"TimerV executed");
    }*/