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");
}*/
|