Scripts/Deep_Horizon_Adv_Nav_Comp_World.js |
"use strict";
this.name = "Deep_Horizon_Adv_Nav_Comp";
this.authors = "Cmd. Cheyd (Blake Deakins) and PhantorGorth (Paul Cooper)";
this.contributors = "Svengali, Nick Rogers";
this.description = "Adds a prime-able piece of equipment that improves interstellar navigation in the form of fuel savings.";
this.copyright = "� Creative Commons Attribution-Noncommercial-ShareAlike 3.0 Unported license (Modified)";
/*
***************************************************************************************************************
** A significant portion of the code contained herein was based on code originally written and contributed by
** Svengali. Without his contribution, this OXP would not have been possible. Thanks Olli!
***************************************************************************************************************
*/
//*************************************************************************************************************
//************************************ Variable Declaration ************************************
//*************************************************************************************************************
this.$jumpDistance = 0;
this.usedANC = false;
this.$lastSource = -1;
//*************************************************************************************************************
//************************************ Event Functions ************************************
//*************************************************************************************************************
this.startUp = function() {
// get instance
this.myFCB = new CheydsReorient();
this.systemDone = false;
this.loopHere = false;
}
this.shipWillLaunchFromStation = function () {
this._systemSetup();
if (this.systemDone) return;
this.loopHere = false;
this.entryVectorCorrect = false;
this.$lastSource = system.ID;
}
this.shipWillEnterWitchspace = function(cause) {
this.systemDone = false;
this.myFCB.fcbRemove(1);
if (cause == "wormhole") {
this.playerCancelledJumpCountdown();
return;
} else if (cause =="standard jump" && this.usedANC) {
// Calculate distance about to be jumped. Use this after the jump for fuel waste calculations
var playerTarget = this._playerTargetSystem();
this.$jumpDistance = Number(System.infoForSystem(galaxyNumber,system.ID).distanceToSystem(System.infoForSystem(galaxyNumber,playerTarget)).toFixed(1));
this.entryVector = player.ship.heading.angleTo(this.$jumpMarker.position.subtract(player.ship.position).direction());
}
}
this.shipExitedWitchspace = function() {
if (system.ID != -1) this.$lastSource = system.ID;
// If the ANC was used, calculate distance travelled and reward fuel savings.
this._systemSetup();
this.loopHere = false;
if (!this.usedANC) return;
this.usedANC = false;
if ((this.$jumpDistance > 1.0) && this.entryVectorCorrect) {
var fuelSaved = Number((this.$jumpDistance*0.1).toFixed(1));
player.ship.fuel += fuelSaved;
player.consoleMessage("Fuel savings due to optimized routing: " + fuelSaved, 4);
this.entryVectorCorrect = false;
} else if (this.$jumpDistance < 1.0) {
player.consoleMessage("Jump distance was too short to achieve appreciable fuel savings.",4);
} else {
player.consoleMessage("Entry vector across witchspace event horizon meniscus too far off calculated. Fuel savings negated.",4);
}
}
this.shipWillExitWitchspace = function () {
if (this.entryVector < 0.010) this.entryVectorCorrect = true;
this._stopNavFrameCallback();
if (this.$navFrameVE) this.$navFrameVE.remove();
if (this.$navStarVE) this.$navStarVE.remove();
if (this.navigationTimer) {
this.navigationTimer.stop();
delete this.navigationTimer;
}
}
this.shipWillDockWithStation = this.shipDied = function() {
// cleaning up to avoid trouble
this.usedANC = false;
this._stopNavFrameCallback();
delete this.navFrameCallbackID;
if (this.$navFrameVE) this.$navFrameVE.remove();
if (this.$navStarVE) this.$navStarVE.remove();
if (this.myFCB) this.myFCB.fcbRemove(1);
if (this.navigationTimer) {
this.navigationTimer.stop();
delete this.navigationTimer;
}
this.loopHere = false;
}
this.playerStartedJumpCountdown = function(type, seconds) {
if (!this.usedANC) {
if (type === "standard") {
if (worldScripts["Deep_Horizon_Emer_Jump_Initiator"]) {
if (worldScripts["Deep_Horizon_Emer_Jump_Initiator"].$usedEWI) return;
else {
this._spawnDHINavVEs();
this._reorientPlayer();
}
} else {
this._spawnDHINavVEs();
this._reorientPlayer();
}
}
} else {
if (this.navigationTimer && this.loopHere) {
this._cancelANC(false);
this.loopHere = false;
}
if (type == "standard" && seconds == player.ship.hyperspaceSpinTime*2) this.loopHere = true;
else if (type == "standard" && seconds != player.ship.hyperspaceSpinTime*2) {
this._cancelANC(false);
this._reorientPlayer();
}
}
}
this.playerCancelledJumpCountdown = this.playerStartedAutoPilot = function() {
//If the ANC is running, kill it.
if (this.usedANC) this._cancelANC(true);
else {
this.usedANC = false;
this._stopNavFrameCallback();
if (this.$navFrameVE) this.$navFrameVE.remove();
if (this.$navStarVE) this.$navStarVE.remove();
if (this.myFCB) this.myFCB.fcbRemove(1);
if (this.navigationTimer) {
this.navigationTimer.stop();
delete this.navigationTimer;
}
this.loopHere = false;
}
}
this.playerJumpFailed = function(reason) {
//If the ANC is running, kill it.
this.usedANC = false;
this._stopNavFrameCallback();
delete this.navFrameCallbackID;
if (this.$navFrameVE) this.$navFrameVE.remove();
if (this.$navStarVE) this.$navStarVE.remove();
if (this.myFCB) this.myFCB.fcbRemove(1);
if (this.navigationTimer) {
this.navigationTimer.stop();
delete this.navigationTimer;
}
this.loopHere = false;
}
//*************************************************************************************************************
//************************************ OXP Functions ************************************
//*************************************************************************************************************
//-------------------------------------------------------------------------------------------------------------
// returns the player's target system (1.80) or the next jump to their target system (1.82)
this._playerTargetSystem = function() {
if (player.ship.hasOwnProperty("nextSystem")) return player.ship.nextSystem;
var p = player.ship;
var target = p.targetSystem;
var last = system.ID;
if (system.ID == -1) {
last = this.$lastSource;
}
if (oolite.compareVersion("1.81") < 0) {
// 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.
var myRoute = System.infoForSystem(global.galaxyNumber, last).routeToSystem(System.infoForSystem(global.galaxyNumber, target), p.routeMode);
if (myRoute) {
target = myRoute.route[1];
}
}
return target;
}
this._ancActivated = function () {
var playerTarget = this._playerTargetSystem();
if (!playerTarget || playerTarget == system.ID) {
// Local system is selected. Halt.
player.consoleMessage("Local system selected. Navigation calculations unnecessary. Shutting down.", 4);
return;
}
if (System.infoForSystem(galaxyNumber,system.ID).distanceToSystem(System.infoForSystem(galaxyNumber,playerTarget)) > player.ship.fuel) {
// Insufficient Fuel. Halt.
player.consoleMessage("Insufficient fuel to reach destination system. Navigation calculations unnecessary. Shutting down.", 4);
return;
}
if (!this.navigationTimer) {
// Proceed with ANC-style long-count jump.
this._spawnDHINavVEs();
//Pause to simulate calculations...
var delay = Math.floor((system.scrambledPseudoRandomNumber (24784 + playerTarget)*100)/33);
this.navigationTimer = new Timer(this, this._reorientPlayer, 3+delay);
} else {
// Cancel the ANC.
this._cancelANC(false);
}
return;
}
this._initiateJump = function () {
var self = worldScripts["Deep_Horizon_Adv_Nav_Comp"];
if (player.ship.status === "STATUS_IN_FLIGHT") {
self.usedANC = true;
player.ship.beginHyperspaceCountdown(player.ship.hyperspaceSpinTime*2);
} else self.usedANC = false;
}
this._spawnDHINavVEs = function () {
// Select farpointMarker that matches the destination system.
var playerTarget = this._playerTargetSystem();
for (var i = this.$farpointMarkers.length; i > 0; i--) {
if (playerTarget == this.$farpointMarkers[i-1].systemID) {
this.$jumpMarker = this.$farpointMarkers[i-1]
}
}
player.consoleMessage("Locking onto " + System.systemNameForID(playerTarget) + " system witchpoint nav beacon.", 4);
// Spawn Visual Effect and store reference to it
this.$navFrameVE = system.addVisualEffect("deephorizon_navframe",this._vectoredPositionToTarget(this.$jumpMarker.position,player.ship.collisionRadius + 5000));
this.$navStarVE = system.addVisualEffect("deephorizon_navstar",this._vectoredPositionToTarget(this.$jumpMarker.position,player.ship.collisionRadius + 50000));
// Orient the VE toward the player ship
this.$navFrameVE.scale(0.66);
this.$navStarVE.scale(3.30-this.$jumpMarker.distanceToSystem*.27);
var tex = this.$jumpMarker.systemID%4;
switch (tex) {
case 1:
this.$navStarVE.setMaterials({"dhi_navstar.png":{"textures":["dhi_navstar2.png"],"fragment_shader":"dhi_anc_jumpstar.fragment","emission_map":"dhi_navstar2.png","uniforms":{"uColorMap":{"type":"texture","value":"0"},"uSpecIntensity":"shaderFloat1","uSpecColor":"shaderVector1"},"vertex_shader":"dhi_anc_jumpstar.vertex"}});
break;
case 2:
this.$navStarVE.setMaterials({"dhi_navstar.png":{"textures":["dhi_navstar3.png"],"fragment_shader":"dhi_anc_jumpstar.fragment","emission_map":"dhi_navstar3.png","uniforms":{"uColorMap":{"type":"texture","value":"0"},"uSpecIntensity":"shaderFloat1","uSpecColor":"shaderVector1"},"vertex_shader":"dhi_anc_jumpstar.vertex"}});
break;
case 3:
this.$navStarVE.setMaterials({"dhi_navstar.png":{"textures":["dhi_navstar4.png"],"fragment_shader":"dhi_anc_jumpstar.fragment","emission_map":"dhi_navstar4.png","uniforms":{"uColorMap":{"type":"texture","value":"0"},"uSpecIntensity":"shaderFloat1","uSpecColor":"shaderVector1"},"vertex_shader":"dhi_anc_jumpstar.vertex"}});
break;
}
this._reorientVEToPlayer (this.$navFrameVE);
this._reorientVEToPlayer (this.$navStarVE);
this.navFrameCallbackID = addFrameCallback(this._positionNavVisualEffects.bind(this));
}
this._positionNavVisualEffects = function () {
this._reorientVEToPlayer (this.$navFrameVE);
this._reorientVEToPlayer (this.$navStarVE);
this.$navFrameVE.position = this._vectoredPositionToTarget(this.$jumpMarker.position,player.ship.collisionRadius + 5000);
this.$navStarVE.position = this._vectoredPositionToTarget(this.$jumpMarker.position,player.ship.collisionRadius + 10000 );
this.$navStarVE.shaderVector1 = this.$jumpMarker.uSpecColor;
this.$navStarVE.shaderFloat1 = this.$jumpMarker.uSpecIntensity;
return;
}
this._stopNavFrameCallback = function() {
if(!this.navFrameCallbackID) return;
removeFrameCallback(this.navFrameCallbackID);
delete this.navFrameCallbackID;
return;
};
this._reorientPlayer = function _reorientPlayer() {
//Calculation of the roll and Pitch accelerations and decelerations based on variations from a Cobra Mk3.
var rollAcc = (0.2) * (player.ship.maxThrust / 30) / (player.ship.mass / 185580.015625) / ((player.ship.boundingBox.x + player.ship.boundingBox.y) / 160);
if (rollAcc > 1) rollAcc = 1;
else if (rollAcc < 0.28) rollAcc = 0.28;
var pitchAcc = rollAcc * (160/95) * ((player.ship.boundingBox.x + player.ship.boundingBox.y) / 160) / ((player.ship.boundingBox.y + player.ship.boundingBox.z) / 95);
if (pitchAcc > 1) pitchAcc = 1;
else if (pitchAcc < 0.255) pitchAcc = 0.255;
var rollDec = rollAcc / 2;
var pitchDec = pitchAcc / 2;
//Turn the player to the appropriate buoy for the selected system.ID
this.myFCB.fcbFace(player.ship,[[1,this.$jumpMarker],[0,this.$jumpMarker]],0,[rollAcc,pitchAcc],[rollDec,pitchDec],this._initiateJump);
player.consoleMessage (System.systemNameForID(this._playerTargetSystem()) + " system beacon acquired. Reorienting ship for vectored system departure\n",4);
return;
}
this._reorientVEToPlayer = function (navVE) {
var orient = this._lookAtRotate (player.ship.position.subtract(navVE.position),player.ship.orientation.vectorUp());
if (orient === null) orient = this._lookAtRotate(player.ship.position.subtract(navVE.position),player.ship.orientation.vectorForward().multiply(-1));
navVE.orientation = orient;
}
this._orthoNormalise = function(a, b)
{
//Returns a normalised vector that is in the plane of "ab" and is at 90� to "a" in the same half plane as "b".
var a2 = a.direction();
var b2 = b.direction();
var c = a.cross(b).cross(a);
return c.direction();
}
this._lookAtRotateEuler = function(theta, phi, psi)
{
//Returns a Quaternion that matches a rotational transformation that is described by the Euler angles.
//Uses Y axis at the basis axis for theta and the Z axis is used to measure phi from.
var q = new Quaternion(1, 0, 0, 0);
var theta2 = (Math.PI/2) - theta;
q = q.rotateZ(psi);
q = q.rotateX(theta2);
q = q.rotateY(phi);
return q;
}
this._lookAtRotate = function(forward, up)
{
//returns an orientation quaternion given a Forward vector and an Up vector (the Forward and Up do not need to be
//orthonormal but they can not be parallel or anti-parallel.)
if (forward.direction().cross(up.direction()).magnitude() < 0.01) return null; // Return null if Forward and Up are parallel or anti-parallel or nearly so.
var f = forward.direction();
var u = this._orthoNormalise(f, up);
var v = new Vector3D(0,1,0); //Uses Y axis at the basis axis for theta and the Z axis is used to measure phi from for finding the Euler angles.
var u2 = this._orthoNormalise(f, v);
var sign = -u2.cross(u).dot(f);
var sign = sign && sign / Math.abs(sign);
var psi = sign * u2.angleTo(u);
var z = new Vector3D(0,0,1);
var h = new Vector3D(f.x,0,f.z);
sign = -z.cross(h).y;
sign = sign && sign / Math.abs(sign);
var phi = sign * z.angleTo(h);
sign = f.y;
sign = sign && sign / Math.abs(sign);
var theta = (Math.PI/2) - (sign * h.angleTo(f));
return this._lookAtRotateEuler(theta, phi, psi);
}
this._vectoredPositionToTarget = function (targetPosVector, distance) {
var v = targetPosVector.subtract(player.ship.position).direction();
v = v.multiply(distance);
v = v.add(player.ship.position);
return v;
}
this._cancelANC = function(silent) {
if (!silent) player.consoleMessage("Advanced Navigation calculations cancelled.", 4);
this._stopNavFrameCallback();
if (this.$navFrameVE) this.$navFrameVE.remove();
if (this.$navStarVE) this.$navStarVE.remove();
if (this.navigationTimer) {
this.navigationTimer.stop();
delete this.navigationTimer;
}
player.ship.cancelHyperspaceCountdown();
if (this.myFCB) this.myFCB.fcbRemove(1);
this.loopHere = false;
this.usedANC = false;
return;
}
this._ancDamaged = function() {
if ((equipment == "EQ_ADV_NAV_COMP" || equipment == "EQ_ADVANCED_NAVIGATIONAL_ARRAY") && this.navigationTimer) {
this._cancelANC(false);
}
return;
}
this._systemSetup = function () {
this.$farpointMarkers = new Array();
// Determine how many farpoint markers are needed
this.$localSystems = System.infoForSystem(galaxyNumber,system.ID).systemsInRange(7);
this.$spawnCount = this.$localSystems.length;
// For each in-range system spawn a farpoint marker
this.$farpointMarkers = system.addShips("DHI_farpoint_marker",this.$spawnCount,player.ship.position,5000000);
//Assign a matching system.ID as an additional value to each buoy
for (var i = this.$farpointMarkers.length; i > 0; i--) {
var fpm = this.$farpointMarkers[i-1];
fpm.systemID = this.$localSystems[i-1].systemID;
fpm.galCoordinates = this.$localSystems[i-1].coordinates;
fpm.name = this.$localSystems[i-1].name;
fpm.distanceToSystem = System.infoForSystem(galaxyNumber,system.ID).distanceToSystem(this.$localSystems[i-1]);
fpm.uSpecColor = this._selectColor(this.$localSystems[i-1].systemID,i);
fpm.uSpecIntensity = 0.5;
fpm.position = this.positionFarpointMarker(fpm,50000000);
}
this.systemDone = true;
return;
}
//-------------------------------------------------------------------------------------------------------------
this.$anc_shipLaunchedEscapePod = function $anc_shipLaunchedEscapePod(pod, passengers) {
pod.remove(true);
}
this._selectColor = function (sysID,i) {
var color = System.infoForSystem(galaxyNumber,sysID).sun_color;
if (typeof(color) === 'undefined') {
var c = Math.floor(system.scrambledPseudoRandomNumber(785331-i)*7);
switch (c) {
case 0: color = "magentaColor"; break;
case 1: color = "redColor"; break;
case 2: color = "orangeColor"; break;
case 3: color = "yellowColor"; break;
case 4: color = "whiteColor"; break;
case 5: color = "cyanColor"; break;
default: color = "blueColor"; break;
}
}
switch (color) {
case "magentaColor": var colorVec = [1,0,1]; break;
case "redColor": var colorVec = [1,0,0]; break;
case "orangeColor": var colorVec = [1,0.5,0]; break;
case "yellowColor": var colorVec = [1,1,0]; break;
case "whiteColor": var colorVec = [1,1,1]; break;
case "cyanColor": var colorVec = [0,1,1]; break;
case "blueColor": var colorVec = [0,0,1]; break;
default: colorVec = [1,1,1];
}
return colorVec;
}
this.positionFarpointMarker = function positionFarpointMarker(marker,distance)
{
if (marker.galCoordinates == null) return null;
var t = marker.galCoordinates;
var s = System.infoForSystem(galaxyNumber, system.ID).coordinates;
var tV = t.subtract(s);
var u = system.scrambledPseudoRandomNumber(34567346);
var v = system.scrambledPseudoRandomNumber(431976567);
var w = system.scrambledPseudoRandomNumber(9834674);
var theta = Math.acos(2 * u - 1);
var phi = 2 * Math.PI * v;
var psi = 2 * Math.PI * w;
var v1 = new Vector3D(Math.sin(theta) * Math.sin(phi), Math.sin(theta) * Math.cos(phi), Math.cos(theta));
var v2 = new Vector3D(0, 0, 1); //straight up
var v3 = v2.cross(v1);
v3 = v3.direction(); // normalize (should be normalized anyway)
var q1 = new Quaternion(1,0,0,0);
q1 = q1.rotate(v3, theta).normalize();
var v4 = tV.rotateBy(q1).direction(); // rotate target vector tV so that the coordinate space has pole moved from straight up to v1 (theta, phi) (spherical coords)
var q2 = new Quaternion(1,0,0,0);
q2 = q2.rotate(v1, psi).normalize();
v4 = v4.rotateBy(q2).direction(); // rotate about the new pole v1 by psi
return v4.multiply(distance).add(player.ship.position);
}
this._anc_sum = function(arr) {
var total = 0;
for(var a = 0; a < arr.length; a++) { total += arr[a]; };
return total
}
this._anc_time_taken = function(angle, max_ang_vel, dampa, dampb)
{
var ret_val = [0, 0, 0];
ret_val[0] = (angle / max_ang_vel) + ((dampa + dampb) * 0.5);
ret_val[1] = dampa;
ret_val[2] = dampb;
if (ret_val[0] < (dampa + dampb))
{
var m = Math.sqrt((2 * angle)/(max_ang_vel * (dampa + dampb)));
ret_val[0] = m * (dampa + dampb);
ret_val[1] *= m;
ret_val[2] *= m;
}
return ret_val;
}
//*************************************************************************************************************
//************************************ Lib Functions ************************************
//*************************************************************************************************************
this.CheydsReorient = function CheydsReorient(){this._root = null;}
CheydsReorient.prototype = {
constructor: CheydsReorient,
cheyds_fcb: 0,
cheyds_fcbs: [],
cheyds_doAutoRemove: true,
cheyds_autoRemove: function(mode){
if(mode){
if(!this.cheyds_autoRemoveTimer) this.cheyds_autoRemoveTimer = new Timer(this,this.fcbRemove,0,3);
else if(!this.cheyds_autoRemoveTimer.isRunning) this.cheyds_autoRemoveTimer.start();
} else if(this.cheyds_autoRemoveTimer) this.cheyds_autoRemoveTimer.stop();
},
// Face target
// ent Entity. Required. To be reoriented.
// tar Entity. Required. Target entity.
// recall Boolean. Recall settings. If set ignores dampb and starts over when duration over.
// angAccA Number. Angular acceleration array
// angDecA Number. Angular deceleration array
fcbFace: function(ent,tarVA,recall,angAccA,angDecA,call_back){
if(!ent || !ent.isValid) return;
var croStep = 0,ccl_sum = 0,ccl_ent = ent,ccl_tarVA = tarVA,ccl_tar = tarVA[0],ccl_recall = recall,ccl_angAccA = angAccA,ccl_angDecA = angDecA,ccl_angAcc,ccl_angDec,ccl_dampa,ccl_dampb;
var ccl_last, initialAngle, aimAngle, alpha, reset = 0, max_ang_vel = 0, targetVector;
var cheyds_fcbs_ref, absSecs, totalSecs = 0;
var finalCallbackCalled = false, ccl_callback = call_back;
var lastOrientation, lastUpAngle;
this.cheyds_fcb = addFrameCallback(function(delta){
if(!delta || !ccl_ent || !ccl_ent.isValid) return;
if (ccl_sum == 0) {
lastOrientation = ccl_ent.orientation;
lastUpAngle = ccl_ent.orientation.vectorUp().angleTo(worldScripts["Deep_Horizon_Adv_Nav_Comp"]._orthoNormalise(ccl_ent.heading, ccl_tar[1].position.subtract(ccl_ent.position)));
if ((!ccl_recall) && (ccl_tarVA.length > 0) && (croStep < ccl_tarVA.length)) {
ccl_tar = ccl_tarVA[croStep];
}
if (ccl_tar[0] == 0) {
max_ang_vel = ccl_ent.maxPitch;
targetVector = ccl_tar[1].position.subtract(ccl_ent.position).direction();
if (reset == 0) initialAngle = ccl_ent.heading.angleTo(targetVector);
}
else {
max_ang_vel = ccl_ent.maxRoll;
targetVector = worldScripts["Deep_Horizon_Adv_Nav_Comp"]._orthoNormalise(ccl_ent.heading, ccl_tar[1].position.subtract(ccl_ent.position));
if (reset == 0) initialAngle = ccl_ent.orientation.vectorUp().angleTo(targetVector);
}
if(ccl_angAccA.length > 0) if (croStep < ccl_angAccA.length) { ccl_angAcc = ccl_angAccA[croStep]; } else { ccl_angAcc = ccl_angAccA[ccl_angAccA.length - 1]; }
if(ccl_angDecA.length > 0) if (croStep < ccl_angDecA.length) { ccl_angDec = ccl_angDecA[croStep]; } else { ccl_angDec = ccl_angDecA[ccl_angDecA.length - 1]; }
ccl_dampa = max_ang_vel / ccl_angAcc;
ccl_dampb = max_ang_vel / ccl_angDec;
let ret_val = worldScripts["Deep_Horizon_Adv_Nav_Comp"]._anc_time_taken(initialAngle, max_ang_vel, ccl_dampa, ccl_dampb);
ccl_last = ret_val[0];
log ("Reorient Function", "ccl_last = " + ccl_last + ".");
ccl_dampa = ret_val[1];
ccl_dampb = ret_val[2];
totalSecs += ccl_last;
if (croStep == (ccl_tarVA.length -1)) cheyds_fcbs_ref[1] = absSecs + totalSecs;
alpha = ccl_last/(ccl_last - (ccl_dampa + ccl_dampb) / 2);
}
ccl_sum += delta;
if(ccl_sum>=ccl_last){
if(ccl_recall) ccl_sum = 0;
else if (croStep < (ccl_tarVA.length-1)) {
croStep += 1;
ccl_sum = 0;
reset = 0;
return;
}
else if ((croStep == (ccl_tarVA.length - 1)) && (!finalCallbackCalled)) {
finalCallbackCalled = true;
ccl_callback();
}
else return;
}
if (ccl_tar[0] == 0) {
let currentForward = ccl_ent.heading;
let currentForwardAngle = currentForward.angleTo(targetVector);
let currentUpAngle = ccl_ent.orientation.vectorUp().angleTo(targetVector);
if (ccl_sum < ccl_dampa) aimAngle = (1 - (alpha*(ccl_last/ccl_dampa)*(ccl_sum/ccl_last)*(ccl_sum/ccl_last)/2))*initialAngle;
else if (ccl_sum < (ccl_last - ccl_dampb)) aimAngle = (1 - ((alpha*ccl_dampa/ccl_last/2) + alpha*(ccl_sum-ccl_dampa)/ccl_last))*initialAngle;
else if (ccl_sum < ccl_last) aimAngle = (alpha*(ccl_last/ccl_dampb)*(ccl_last-ccl_sum)/ccl_last*(ccl_last-ccl_sum)/ccl_last/2)*initialAngle;
else aimAngle = 0;
let angle = currentForwardAngle - aimAngle;
let cross = lastOrientation.vectorForward().cross(targetVector).direction();
ccl_ent.orientation = worldScripts["Deep_Horizon_Adv_Nav_Comp"]._lookAtRotate(ccl_ent.orientation.rotate(cross,-angle).vectorForward(), lastOrientation.vectorUp());
lastOrientation = ccl_ent.orientation;
lastUpAngle = currentUpAngle;
}
else {
let currentForward = ccl_ent.heading;
let currentForwardAngle = currentForward.angleTo(targetVector);
let currentUpAngle = ccl_ent.orientation.vectorUp().angleTo(targetVector);
if (ccl_sum < ccl_dampa) aimAngle = (1 - (alpha*(ccl_last/ccl_dampa)*(ccl_sum/ccl_last)*(ccl_sum/ccl_last)/2))*initialAngle;
else if (ccl_sum < (ccl_last - ccl_dampb)) aimAngle = (1 - ((alpha*ccl_dampa/ccl_last/2) + alpha*(ccl_sum-ccl_dampa)/ccl_last))*initialAngle;
else if (ccl_sum < ccl_last) aimAngle = (alpha*(ccl_last/ccl_dampb)*(ccl_last-ccl_sum)/ccl_last*(ccl_last-ccl_sum)/ccl_last/2)*initialAngle;
else aimAngle = 0;
let angle = currentUpAngle - aimAngle;
let cross = lastOrientation.vectorUp().cross(targetVector).direction();
ccl_ent.orientation = worldScripts["Deep_Horizon_Adv_Nav_Comp"]._lookAtRotate(lastOrientation.vectorForward(), ccl_ent.orientation.rotate(cross,-angle).vectorUp());
lastOrientation = ccl_ent.orientation;
lastUpAngle = currentUpAngle;
}
reset = 1;
return;
});
absSecs = clock.absoluteSeconds;
if(ccl_recall) this.cheyds_fcbs.push([this.cheyds_fcb,absSecs + 0xFFFFFF]);
else {
this.cheyds_fcbs.push([this.cheyds_fcb,absSecs + 0xFFFFFF]);
cheyds_fcbs_ref = this.cheyds_fcbs[this.cheyds_fcbs.length - 1];
if(this.cheyds_doAutoRemove) this.cheyds_autoRemove(1);
}
return;
},
// Check fcbs and log them.
fcbCheckAll: function(){
if(!this.cheyds_fcbs.length) return(false);
for(let i=0;i<this.cheyds_fcbs.length;i++){
if(isValidFrameCallback(this.cheyds_fcbs[i][0])) log("fcbCheck","valid i:"+i+" fcb:"+this.cheyds_fcbs[i][0]+" typeof:"+typeof(this.cheyds_fcbs[i][0])+" lasts:"+(clock.absoluteSeconds-this.cheyds_fcbs[i][1]));
else log("fcbCheck","invalid i:"+i);
}
return(true);
},
// Clean fcbs.
// all Boolean. Clean all fcbs.
fcbRemove: function fcbRemove(all){
if(!this.cheyds_fcbs.length) return(false);
var checked=0;
for(let i=0;i<this.cheyds_fcbs.length;i++){
if(isValidFrameCallback(this.cheyds_fcbs[i][0])){
if(all) removeFrameCallback(this.cheyds_fcbs[i][0]);
else if(this.cheyds_doAutoRemove && clock.absoluteSeconds>this.cheyds_fcbs[i][1]){
removeFrameCallback(this.cheyds_fcbs[i][0]);
checked++;
}
} else checked++;
}
if(all || this.cheyds_fcbs.length===checked){
this.cheyds_fcb = 0;
this.cheyds_fcbs = [];
this.cheyds_autoRemove();
}
return(true);
}
};
|