| Scripts/gates_gateTrader.js | this.name					= "gates_gateTrader";
this.author					= "Thargoid";
this.copyright				= "Creative Commons: attribution, non-commercial, sharealike with clauses - see readme.txt.";
this.description				= "Script for traders using jumpgates";
this.version				= "1.00";
this.shipSpawned = function()
	{ 
	if(system.isInterstellarSpace || system.sun.isGoingNova || system.sun.hasGoneNova || system.countShipsWithRole("gates_jumpGate") < 2)
		{
		return;
		}
	
	
	function jumpGates(entity) {return entity.isShip && entity.hasRole("gates_jumpGate")}; // all gates except this one
	var gates = system.filteredEntities(this, jumpGates, this.ship); // find the gates in the system
	
	if(this.ship.position.distanceTo(gates[0].position) < 51200 && (this.ship.AIState == "HEAD_FOR_PLANET" || this.ship.AIState == "HEAD_AWAY_FROM_PLANET"))
		{
		this.ship.target = gates[0];
		this.ship.setAI("gates_useGateAI.plist");
		}
	}
this.checkGateDistance = function()
	{	
	if(this.ship.position.distanceTo(this.ship.target.position) > 51200)
		{
		this.ship.reactToAIMessage("NEXT_GATE")
		}
	}
 | 
                
                    | Scripts/gates_jumpGate.js | this.name					= "gates_jumpGate";
this.author					= "Thargoid";
this.copyright				= "Creative Commons: attribution, non-commercial, sharealike with clauses - see readme.txt";
this.description			= "Script for Thargoid jumpgates";
this.version				= "1.12";
function gates_allGates(entity) {return entity.isShip && entity != this.ship && entity.hasRole("gates_jumpGate")}; // all gates except this one
function gates_clients(entity) {return entity.isShip && entity.primaryRole != "gates_gateGuard" && !entity.isCloaked && !entity.isWeapon && !entity.isRock && !entity.isCargo && (!entity.hasOwnProperty("gates_receivingGate")|| entity.gates_receivingGate == null)}; // ships that can use jumpgates (exclude spawned defenders, missiles, mines, asteroids and cargo pods
function gates_oldClients(entity) {return entity.isShip && entity.hasOwnProperty("gates_receivingGate") && entity.gates_receivingGate != null && entity.position.distanceTo(this.ship.position) > 500 && entity.position.distanceTo(this.ship.position) < 5000}; // ships which have come through this gate and are now between 500m and 5km from it
function gates_outboundNPCs(entity) {return entity.isShip && entity.AI == "exitingTraderAI.plist" && entity.AIState == "HEAD_AWAY_FROM_PLANET" && (!entity.escorts || entity.escorts.length == 0) && system.mainStation && entity.position.distanceTo(system.mainStation.position) < 51200};
function gates_inboundNPCs(entity) {return entity.isShip && entity.AI == "route1traderAI.plist" && entity.AIState == "HEAD_FOR_PLANET" && (!entity.escorts || entity.escorts.length == 0) && entity.position.distanceTo([0,0,0]) < 51200};
this.shipSpawned = function()
	{
	this.ship.scannerDisplayColor1 = "greenColor";
	this.ship.scannerDisplayColor2 = "whiteColor";
	this.playerGreeted = null;
	this.allowGreeting = true;
	this.gatesOnline = true;
	this.ship.orientation = system.mainStation.orientation; // point them all in the same direction, along universal Z.
	this.defenderCount = 10; // max number of defenders that can be launched overall by the gate if attacked
	
	if(this.scanTimer)
		{
		this.scanTimer.start();
		}
	else
		{
		this.scanTimer = new Timer(this, this.shipApproach, 0, 1.0); // scan for jumping ships every 1 second - too long/short?
		}
	if(this.npcTimer)
		{
		this.npcTimer.start();
		}
	else
		{
		this.npcTimer = new Timer(this, this.npcTraders, 0, 180); // scan for NPC traders who may want to use the gates every 3 minutes
		}
	}
this.playerWillEnterWitchspace = this.shipDied = function()
	{
	if(this.scanTimer)
		{
		this.scanTimer.stop();
		}
	if(this.npcTimer)
		{
		this.npcTimer.stop();
		}
	}
this.shipApproach = function()
	{	
	if(!player.ship || !player.ship.isValid)
		{
		this.shipDied();
		return;
		}
	
	if(this.ship.position.distanceTo(player.ship.position) > 25600 && this.allowGreeting == null)
		{
		this.allowGreeting = true;
		}
	
	var pastClients = system.filteredEntities(this, gates_oldClients, this.ship, 5000) // if any old clients are around, strip their client status
	if(pastClients.length > 0)
		{
		for(var i = 0; i < pastClients.length; i++)
			{
			pastClients[i].gates_receivingGate = null;
			if(pastClients[i].isPlayer) 	
				{
				player.consoleMessage("Jump gate cleared.", 6);
				this.allowGreeting = null;
				}
			}
		}
	
	var queue = system.filteredEntities(this, gates_clients, this.ship, 250); // if there is no-one wanting to jump, end the test
	if(queue.length == 0)
		{
		return;
		}
	
	var gates = system.filteredEntities(this, gates_allGates, this.ship); // check whether there is a second gate to receive the jumper
	if(gates.length == 0) 
		{
		if(queue[0].isPlayer && this.gatesOnline == true) 
			{
			player.consoleMessage("Jump gate off-line.", 6);
			this.gatesOnline = null;
			}
		return;
		}
	else
		{
		this.gatesOnline = true;
		}
	
	if(queue[0].hasOwnProperty("gates_receivingGate") && queue[0].gates_receivingGate == this.ship) // if the jumper has just arrived, end the test
		{
		return;
		}
	if(queue[0].AI == "gates_useGateAI.plist")
		{
		queue[0].reactToAIMessage("JUMPED");
		queue[0].gates_receivingGate = gates[0]; // note the gate that is about to receive the jumper
		queue[0].position = gates[0].position; // move the jumper to the receiving gate
		queue[0].orientation = gates[0].orientation; // re-orient the jumper to point out of the gate
		return;
		}
	
	if(queue[0].isPlayer)
		{
		if(player.credits < 251)
			{
			player.consoleMessage("Insufficient credits to perform jump.", 6);
			return;
			}
		else
			{
			player.consoleMessage("Jump gate activated.", 6);
			player.credits -=250;
			this.playerGreeted = null;
			queue[0].gates_receivingGate = gates[0]; // note the gate that is about to receive the player
			queue[0].position = gates[0].position; // move the player to the receiving gate
			queue[0].orientation = gates[0].orientation; // re-orient the player to point out of the gate
			}
		}
	}
this.greetPlayer = function()
	{
	if(!player.ship.isCloaked && (!player.ship.hasOwnProperty("gates_receivingGate") || player.ship.gates_receivingGate == null) && this.playerGreeted != true && this.allowGreeting == true)
		{
		player.consoleMessage("Welcome Commander, only 250Cr to use the jump gate system.", 6);
		this.playerGreeted = true;
		}
	}
this.findGates = function()
	{
	var gates = system.filteredEntities(this, gates_allGates, this.ship);	
	if(gates.length == 0)
		{
		this.ship.reactToAIMessage("NO_GATE");
		this.ship.scannerDisplayColor1 = "greenColor";
		this.ship.scannerDisplayColor2 = "orangeColor";
		}
	else
		{
		this.ship.reactToAIMessage("GATE_FOUND");
		this.ship.scannerDisplayColor1 = "greenColor";
		this.ship.scannerDisplayColor2 = "whiteColor";
		}
	};
	
this.underAttack = function()
	{
	if(this.defenderCount > 0 && worldScripts["gates_masterScript"] && worldScripts["gates_masterScript"].defenderAllowed())
		{
		var defender = this.ship.spawnOne("police");
		defender.position = this.ship.position;
		defender.orientation = this.ship.orientation;
		this.defenderCount -= 1;
		}
	}
this.npcTraders = function()
	{
	var outTraders = system.filteredEntities(this, gates_outboundNPCs); // list of outbound traders
	var inTraders = system.filteredEntities(this, gates_inboundNPCs); // list of inbound traders
	var gates = system.shipsWithRole("gates_jumpGate");
	if(gates.length < 2)
		{
		return;
		}
	if(inTraders.length > 0)
		{
		for(var i = 0; i < inTraders.length; i++)
			{
			if(Math.random() < 0.2 && gates.length > 0)
				{
				inTraders[i].target = gates[0];
				inTraders[i].script.checkGateDistance = this.checkGateDistance;
				inTraders[i].setAI("gates_useGateAI.plist");
				}
			}
		}
	if(outTraders.length > 0)
		{
		for(var i = 0; i < outTraders.length; i++)
			{
			if(Math.random() < 0.2 && gates.length > 0)
				{
				outTraders[i].target = gates[0];
				outTraders[i].script.checkGateDistance = this.checkGateDistance;
				outTraders[i].setAI("gates_useGateAI.plist");
				}
			}
		}
	}
// The function below is assigned to NPC ships using the jump gates
this.checkGateDistance = function()
	{	
	if(this.ship.position.distanceTo(this.ship.target.position) > 51200)
		{
		this.ship.reactToAIMessage("NEXT_GATE")
		}
	}
 | 
                
                    | Scripts/gates_masterScript.js | this.name					= "gates_masterScript";
this.author					= "Thargoid";
this.copyright				= "Creative Commons: attribution, non-commercial, sharealike with clauses - see readme.txt";
this.description			= "WorldScript for Gates OXP.";
this.version				= "1.13";
this.startUp = function()
	{
	this.defenderTime = clock.absoluteSeconds; 
	}
	
this.shipWillExitWitchspace = function()
	{
	if(system.isInterstellarSpace || system.sun.isGoingNova || system.sun.hasGoneNova) 
		{ // stop the script if interstellar space, or system is going Nova(to allow Nova mission unhindered) or indeed if it has gone nova already.
		return;
		}
	this.setUpGates();
	}
this.shipWillLaunchFromStation = function(station)
	{
	if(station.isMainStation)
		{
		this.setUpGates();
		delete this.shipWillLaunchFromStation;
		}
	}
this.setUpGates = function()
	{
	if(system.countShipsWithRole("gates_jumpGate") > 0 || system.techLevel < 7 || system.government < 4 || this.scrambledPseudoRandom(34.12) < 0.25)
		{
		return;
		}
	log("Adding jump gates to the " + system.name + " system");
	system.legacy_addShipsAt("gates_jumpGate", 1, "wpu", [0,0,0.02]);
      
    this.xOffset = (Math.random() * 10000); // x offset between 0 and 10km
	this.yOffset = (Math.random() * 10000); // y offset between 0 and 10km
	this.zOffset = (Math.random() * 25000) + 15000; // z offset between 15 and 40km
      if(Math.random() > 0.5) // 50:50 chance of offsetting in the other direction
         {
         this.xOffset = -this.xOffset;
         }
      if(Math.random() > 0.5) // 50:50 chance of offsetting in the other direction
         {
         this.yOffset = -this.yOffset;
         }
	
	if(system.mainStation)
		{ system.legacy_addShipsAtPrecisely("gates_jumpGate", 1, "abs", system.mainStation.position.subtract([this.xOffset, this.yOffset, this.zOffset]));}
	}
this.scrambledPseudoRandom = function(salt) // Ahruman's random number generator.
	{
    // Convert from float in [0..1) with 24 bits of precision to integer.
    var n = Math.floor(system.pseudoRandomNumber * 16777216.0);
   
    // Add salt to enable generation of different sequences.
    n += salt;
   
    // Scramble with basic LCG psuedo-random number generator.
    n = (214013 * n + 2531011) & 0xFFFFFFFF;
    n = (214013 * n + 2531011) & 0xFFFFFFFF;
    n = (214013 * n + 2531011) & 0xFFFFFFFF;
   
    // Convert from (effectively) 32-bit signed integer to float in [0..1).
    return n / 4294967296.0 + 0.5;
	};	
	
// the function below is referenced by the gates themselves via their own script, or are assigned to NPC ships using the gates.
this.defenderAllowed = function() 
	{ 
	if(this.defenderTime && (clock.absoluteSeconds - this.defenderTime) > 20) 
		{ 
		this.defenderTime = clock.absoluteSeconds; 
		return true; 
		} 
	else 
		{
		return false; 
		}
	}
 |