Back to Index Page generated: Jun 13, 2026, 7:54:55 PM

Expansion Her Imperial Majesty's Space Navy

Content

Warnings

  1. Extreanous whitespace on key 'max_police '
  2. Unknown key 'upload_date' at https://wiki.alioth.net/img_auth.php/d/de/Himsn_0.9-alpha.oxz!manifest.plist

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description A more 'believable' Navy presence that sits more comfortably in the Ooniverse as many of us see it. The Navy is there if you go looking. If you do your normal trading, mining and bounty hunting you will never see them. They do not, under any circumstances, meddle in internal system politics. So, you will not be attacked by the Navy if you are an offender or even a fugitive for that matter. That is a police matter. A more 'believable' Navy presence that sits more comfortably in the Ooniverse as many of us see it. The Navy is there if you go looking. If you do your normal trading, mining and bounty hunting you will never see them. They do not, under any circumstances, meddle in internal system politics. So, you will not be attacked by the Navy if you are an offender or even a fugitive for that matter. That is a police matter.
Identifier oolite.oxp.tsoj.himsn oolite.oxp.tsoj.himsn
Title Her Imperial Majesty's Space Navy Her Imperial Majesty's Space Navy
Category Miscellaneous Miscellaneous
Author Gimi, Pleb, Keeper, Smivs, Cody, Disembodied, Cholmondely, cbr, Tsoj Gimi, Pleb, Keeper, Smivs, Cody, Disembodied, Cholmondely, cbr, Tsoj
Version 0.9 0.9
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Dependent Expansions
  • oolite.oxp.Cholmondeley.Lore_Collection_(Classic_Elite):1.2
  • Information URL http://wiki.alioth.net/index.php/Her_Imperial_Majesty%27s_Space_Navy n/a
    Download URL https://wiki.alioth.net/img_auth.php/d/de/Himsn_0.9-alpha.oxz http://wiki.alioth.net/index.php/File:Himsn_0.9-alpha.oxz
    License GPL v2+ / CC-BY-NC-SA 4.0 GPL v2+ / CC-BY-NC-SA 4.0
    File Size n/a
    Upload date 1642376758

    Relationships Diagram

    Documentation

    Also read http://wiki.alioth.net/index.php/Her%20Imperial%20Majesty's%20Space%20Navy

    README.md

    # Her Imperial Majesty's Space Navy
    
    ## An expansion pack for [Oolite](http://www.oolite.org/).
    
    "A more 'believable' Navy presence that sits more comfortably in the Ooniverse as many of us see it. The problem with GN is that it's too big. Based on canon and lore, the war against the Thargoids is played out mostly in InterGalactic space, and therefore you wouldn't expect to find a big naval presence in 'normal' space. There would not be navy ships all over the place (clogging up the spacelanes!) and the idea of numerous naval bases (SecComs) in each Galaxy also seems a bit silly. These stations also skew the game quite badly due to their market economics. Also, GN often focuses on pirates, and there is no justification for this within the game - that's what the GalCop Police are for.
    
    We are talking about an OXP which adds a much more discrete (and believable) naval presence, with a more appropriate range of ships. It may in time also offer missions similar to the two in-built missions involving HIMSN: small, covert special-ops type missions rather than the somewhat repetitive mass shoot-em-ups that GN offers.
    
    The Navy is there if you go looking. If you do your normal trading, mining and bounty hunting you will never see them. They do not, under any circumstances, meddle in internal system politics. So, you will not be attacked by the Navy if you are an offender or even a fugitive for that matter. That is a police matter."
    
    [Wiki](http://wiki.alioth.net/index.php/Her_Imperial_Majesty%27s_Space_Navy)
    
    
    ## License
    GPL v2+  
    CC-BY-NC-SA 4.0
    
    **Authors**:  
    *Gimi  
    Pleb  
    Keeper  
    Smivs  
    Cody  
    Disembodied  
    Cholmondely  
    Tsoj  
    cbr*
    
    ## Development plan
    
    **Stage 1 - Eye Candy only:**
    - [x] Navy units from the core ship-set.
    - [x] Navy stations. (HQ and Outpost)
    - [x] Basic scripting and and AI behaviour.
    
    **Stage 2 - Thargoid Interaction:**
    - [ ] War zones with the Thargoids
    - [x] Capital ships
    - [ ] Yearly Parade
    - [ ] Additional stations (Navy Shipyard and maybe some mission related type of station)
    - [ ] Intelligence/Special Operations type ships (e.g. production model of the Constrictor)
        - [ ] AI behaviour
    
    **Stage 3 - Missions:**
    - [ ] Player Missions
      
    

    Equipment

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

    Ships

    Name
    himsn_adv_patrol_asp
    himsn_adv_patrol_boa_mk2
    himsn_adv_patrol_constrictor
    Imperial Navy Anaconda
    Imperial Navy Asp Mark II
    Imperial Navy Boa Class Cruiser
    Imperial Navy Constrictor
    himsn_defender
    himsn_escort
    himsn_escort_anaconda
    himsn_escort_asp
    Imperial Navy Headquarters
    himsn_heavy_patrol_leader
    Imperial Navy Outpost
    Kiota Comms Array
    Kiota Disc
    Kiota Dock Ring (Hidden)
    Kiota Lift
    Kiota Small Ring
    Kiota Spur
    Kiota Strut
    Kiota Turret
    Imperial Navy Carrier (Komodo Class)
    Docking Slit (horizontal)
    himsn_light_patrol_leader
    himsn_logistics_transport
    himsn_misjumper
    himsn_missile_corvette
    Imperial Navy Sidewinder
    Navy Special Ops Asp Mark II
    Navy Intelligence Constrictor
    Imperial Navy Base

    Models

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

    Scripts

    Path
    Scripts/himsn_adv_patrol.js
    "use strict";
    
    this.name 			= "himsn_adv_patrol";
    this.author         = "Pleb";
    this.copyright      = "(C) 2014 Pleb.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.version 		= "0.9-alpha";
    
    this._generateDestination = function ()
    {
    	var thisSystem = system.info;
    	var targetSystems = SystemInfo.systemsInRange(7);
    	if (!targetSystems) return system.ID;
    	var count = targetSystems.length;
    	var targetSystem = targetSystems[Math.floor(Math.random()*count)];
    	var realDistance = System.infoForSystem(galaxyNumber, targetSystem.systemID).routeToSystem(thisSystem).distance;
    	var i = 0;
    	while ((!realDistance || realDistance > 7) && i<count)
    	{
    		targetSystem = targetSystems[i++];
    		realDistance = System.infoForSystem(galaxyNumber, targetSystem.systemID).routeToSystem(thisSystem).distance;
    	}
    	return targetSystem.systemID;
    }
    
    this.shipSpawned = function ()
    {
    	if (!missionVariables.himsn_adv_patrol_mission)
    	{
    		this.ship.destinationSystem = this._generateDestination();
    		missionVariables.himsn_adv_patrol_dest = this.ship.destinationSystem;
    		missionVariables.himsn_adv_patrol_home = this.ship.homeSystem;
    		if (Math.random() < 0.5)
    		{
    			missionVariables.himsn_adv_patrol_mission = 0;
    		}
    		else
    		{
    			missionVariables.himsn_adv_patrol_mission = 1;
    		}
    		this.ship.awardEquipment("EQ_FUEL_SCOOPS");
    		this.ship.awardEquipment("EQ_HEAT_SHIELD");
    	}
    	else
    	{
    		this.ship.destinationSystem = missionVariables.himsn_adv_patrol_dest;
    		this.ship.homeSystem = missionVariables.himsn_adv_patrol_home;
    	}
    	
    	// Use Escort Formations OXP if installed for random flight formations:
    	if (worldScripts["Escort Formations Randomiser"])
    	{
    		worldScripts["Escort Formations Randomiser"].$setupDefensiveEscorts(this.ship);
    	}
    }
    
    this.helpRequestReceived = function(ally, enemy)
    {
    	this.ship.destination = ally.position;
    	this.ship.target = enemy;
    	this.ship.performAttack();
    }
    
    this.shipBeingAttacked = function(whom)
    {
    	if (whom.scanClass != "CLASS_MILITARY")
    	{
    		this.ship.target = whom;
    		this.ship.requestHelpFromGroup();
    		system.filteredEntities(this, function (entity)
    		{
    			if (entity.scanClass == "CLASS_MILITARY")
    			{
    				entity.target = whom;
    				entity.performAttack();
    			}
    			if (entity.isStation && entity.hasRole("himsn_station"))
    			{
    				entity.alertCondition = 3;
    				entity.launchDefenseShip();
    			}
    		});
    	}
    }
    Scripts/himsn_carrier.js
    "use strict";
    
    this.name 			= "himsn_carrier";
    this.author         = "Pleb";
    this.copyright      = "(C) 2014 Pleb.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.version 		= "0.9-alpha";
    
    this.shipSpawned = function ()
    {
    	this.ship.awardEquipment("EQ_FUEL_SCOOPS");
    	this.ship.awardEquipment("EQ_HEAT_SHIELD");
    	
    	this.ship.shipUniqueName = "HIMSS "+expandDescription("[himsn_carrier_names]");
    	missionVariables.himsn_carrier_name = this.ship.shipUniqueName;
    	
    	// Use Escort Formations OXP if installed for random flight formations:
    	if (worldScripts["Escort Formations Randomiser"])
    	{
    		worldScripts["Escort Formations Randomiser"].$setupDefensiveEscorts(this.ship);
    	}
    }
    
    this.helpRequestReceived = function(ally, enemy)
    {
    	this.ship.destination = ally.position;
    	this.ship.target = enemy;
    	this.ship.performAttack();
    }
    
    this.shipBeingAttacked = function(whom)
    {
    	if (whom.scanClass != "CLASS_MILITARY")
    	{
    		this.ship.target = whom;
    		this.ship.requestHelpFromGroup();
    		system.filteredEntities(this, function (entity)
    		{
    			if (entity.scanClass == "CLASS_MILITARY")
    			{
    				entity.target = whom;
    				entity.performAttack();
    			}
    			if (entity.isStation && entity.hasRole("himsn_station"))
    			{
    				entity.alertCondition = 3;
    				entity.launchDefenseShip();
    			}
    		});
    	}
    }
    Scripts/himsn_carrier_dock.js
    "use strict";
    
    this.name 			= "himsn_carrier_dock";
    this.author         = "Pleb";
    this.copyright      = "(C) 2014 Pleb.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.version 		= "0.9-alpha";
    
    this.shipSpawned = function ()
    {
    	this.ship.allowsDocking = true;
    }
    
    this.acceptDockingRequestFrom = function(ship)
    {
    	if (ship.isPlayer)
    	{
    		return false;
    	}
    	else
    	{
    		return true;
    	}
    }
    Scripts/himsn_constrictor_conditions.js
    "use strict";
    
    this.name           = "himsn_constrictor_conditions";
    this.author         = "Pleb";
    this.copyright      = "(C) 2014 Pleb.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.description    = "This is the conditions script for the HIMSN Constrictor.";
    this.version        = "0.9-alpha";
    
    this.allowSpawnShip = function(shipKey)
    {
    	if (missionVariables.conhunt == "MISSION_COMPLETE" && missionVariables.thargplans == "MISSION_COMPLETE")
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    Scripts/himsn_main.js
    this.name           = "himsn_main";
    this.author         = "Pleb";
    this.copyright      = "(C) 2014 Pleb.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.description    = "This is the main worldscript for the HIMSN OXZ.";
    this.version        = "0.9-alpha";
    
    "use strict";
    
    // TODO add logging
    
    /**** Functions ****/
    
    this._addAdvPatrol = function()
    {
    	this._addAdvPatrolSwitch = true;
    }
    
    this._addAdvPatrolShips = function(pos)
    {
    	var advPatrol = system.addShips("himsn_adv_patrol",1,pos,0);
    	if (system.ID == missionVariables.himsn_adv_patrol_home) 
    	{
    		advPatrol.maxEscorts = Math.floor(Math.random() * (4 - 0 + 1) + 0);
    	}
    }
    
    //TODO why is this never used?
    this._addAdvEscort = function()
    {
    	var pos = system.locationFromCode("WITCHPOINT");
    	system.addGroup("himsn_logistics_transport", 1, pos, 0);
    }
    
    this._launchAdvPatrol = function()
    {
    	if (system.ID == -1) return;
    	var navyStat = null;
    	system.filteredEntities(this, function (entity)
    	{
    		if (entity.isStation)
    		{
    			if (entity.hasRole("himsn_station"))
    			{
    				navyStat = entity;
    			}
    		}
    	});
    	if (navyStat)
    	{
    		navyStat.launchShipWithRole("himsn_adv_patrol", [true]);
    		this._advPatrolTimer_3.stop();
    		this._advPatrolTimer_3 = new Timer(this,this._launchAdvPatrol,900);
    	}
    }
    
    //TODO why is this never used?
    this._addNavyBattleFleet = function(pos)
    {
    	// Add Navy Carrier and defending fleet:
    	var navyCarrier = system.addShips("himsn_komodo_carrier",1,pos,0)[0];
    	var targetVector = system.mainPlanet.position.subtract(navyCarrier.position).direction();
    	navyCarrier.orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrier.maxEscorts = 16;
    	var navyCarrierSidewinders = system.addShips("himsn_escort",8,pos,500);
    	var navyCarrierAsps = system.addShips("himsn_escort_asp",5,pos,500);
    	var navyCarrierAnacondas = system.addShips("himsn_escort_anaconda",3,pos,500);
    	navyCarrierSidewinders[0].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierSidewinders[0].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierSidewinders[0]);
    	navyCarrierSidewinders[0].switchAI("himsn_escort_ai.js");
    	navyCarrierSidewinders[1].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierSidewinders[1].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierSidewinders[1]);
    	navyCarrierSidewinders[1].switchAI("himsn_escort_ai.js");
    	navyCarrierSidewinders[2].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierSidewinders[2].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierSidewinders[2]);
    	navyCarrierSidewinders[2].switchAI("himsn_escort_ai.js");
    	navyCarrierSidewinders[3].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierSidewinders[3].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierSidewinders[3]);
    	navyCarrierSidewinders[3].switchAI("himsn_escort_ai.js");
    	navyCarrierSidewinders[4].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierSidewinders[4].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierSidewinders[4]);
    	navyCarrierSidewinders[4].switchAI("himsn_escort_ai.js");
    	navyCarrierSidewinders[5].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierSidewinders[5].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierSidewinders[5]);
    	navyCarrierSidewinders[5].switchAI("himsn_escort_ai.js");
    	navyCarrierSidewinders[6].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierSidewinders[6].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierSidewinders[6]);
    	navyCarrierSidewinders[6].switchAI("himsn_escort_ai.js");
    	navyCarrierSidewinders[7].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierSidewinders[7].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierSidewinders[7]);
    	navyCarrierSidewinders[7].switchAI("himsn_escort_ai.js");
    	navyCarrierAsps[0].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierAsps[0].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierAsps[0]);
    	navyCarrierAsps[0].switchAI("himsn_escort_ai.js");
    	navyCarrierAsps[1].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierAsps[1].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierAsps[1]);
    	navyCarrierAsps[1].switchAI("himsn_escort_ai.js");
    	navyCarrierAsps[2].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierAsps[2].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierAsps[2]);
    	navyCarrierAsps[2].switchAI("himsn_escort_ai.js");
    	navyCarrierAsps[3].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierAsps[3].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierAsps[3]);
    	navyCarrierAsps[3].switchAI("himsn_escort_ai.js");
    	navyCarrierAsps[4].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierAsps[4].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierAsps[4]);
    	navyCarrierAsps[4].switchAI("himsn_escort_ai.js");
    	navyCarrierAnacondas[0].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierAnacondas[0].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierAnacondas[0]);
    	navyCarrierAnacondas[0].switchAI("himsn_escort_ai.js");
    	navyCarrierAnacondas[1].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierAnacondas[1].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierAnacondas[1]);
    	navyCarrierAnacondas[1].switchAI("himsn_escort_ai.js");
    	navyCarrierAnacondas[2].orientation = targetVector.rotationTo([0,0,1]);
    	navyCarrierAnacondas[2].primaryRole = "escort";
    	navyCarrier.escortGroup.addShip(navyCarrierAnacondas[2]);
    	navyCarrierAnacondas[2].switchAI("himsn_escort_ai.js");
    }
    
    this._addNavyHeadquarters = function(pos)
    {
    	// Add Navy Headquaters and defending fleet:
    	navyStation = system.addShips("himsn_headquarters",1,pos,0)[0];
    	var navyStationGroup = system.addGroup("himsn_defender",5,pos,8000);
    	navyStationGroup.leader = navyStation;
    	navyStationGroup.addShip(navyStation);
    }
    
    this._addNavySystemBase = function(pos)
    {
    	// Add Navy Sysytem Base and defending fleet:
    	navyStation = system.addShips("himsn_system_base",1,pos,0)[0];
    	var targetVector = system.mainPlanet.position.subtract(navyStation.position).direction();
    	navyStation.orientation = targetVector.rotationTo([0,0,1]);
    	var navyStationGroup = system.addGroup("himsn_defender",3,pos,8000);
    	navyStationGroup.leader = navyStation;
    	navyStationGroup.addShip(navyStation);
    }
    
    this._addNavyInterstellarOutpost = function(pos)
    {
    	// Add Navy Interstellar Outpost and defending fleet:
    	navyStation = system.addShips("himsn_interstellar_outpost",1,pos,0)[0];
    	var navyStationGroup = system.addGroup("himsn_defender",3,pos,8000);
    	navyStationGroup.leader = navyStation;
    	navyStationGroup.addShip(navyStation);
    }
    
    this._addNavyPatrol = function (pos)
    {
    	// 50% chance patrol is heavy or light:
    	var patrol;
    	if (Math.random() < 0.5)
    	{
    		if (missionVariables.conhunt == "MISSION_COMPLETE" && missionVariables.thargplans == "MISSION_COMPLETE")
    		{
    			if (Math.random() < 0.5)
    			{
    				patrol = "himsn_heavy_patrol_leader";
    			}
    			else
    			{
    				patrol = "himsn_missile_corvette";
    			}
    		}
    		else
    		{
    			patrol = "himsn_light_patrol_leader";
    		}
    	}
    	else
    	{
            patrol = "himsn_light_patrol_leader";
    	}
    	// Add a Navy Patrol:
    	system.addGroup(patrol, 1, pos, 0);
    }
    
    //TODO why is this never used?
    this._addNavyLogisticsTransport = function (pos)
    {
    	// Add a Navy Logistics Transport:
    	system.addGroup("himsn_logistics_transport", 1, pos, 0);
    }
    
    //TODO why is this never used?
    this._addNavyMissileCorvette = function (pos)
    {
    	// Add a Navy Missile Corvette:
    	system.addGroup("himsn_missile_corvette", 1, pos, 0);
    }
    
    this._addNavySpecOpsRecon = function (pos)
    {
    	// Only add recon (constrictor) if 'Constrictor Hunt' and 'Thargoid Plans' missions are complete:
    	if (missionVariables.conhunt == "MISSION_COMPLETE" && missionVariables.thargplans == "MISSION_COMPLETE")
    	{
    		// Add a Navy Recon:
    		system.addGroup("himsn_specops_recon", 1, pos, 0);
    	}
    }
    
    this._addNavySpecOpsFighter = function (pos)
    {
    	// Add 3x Navy Spec Ops Fighter:
    	system.addGroup("himsn_specops_asp", 3, pos, 0);
    }
    
    this._checkIfHostilePeriodIsOver = function ()
    {
    	// Check if player is considered an enemy of HIMSN and 60 days have passed since being declared an enemy:
    	if (missionVariables.himsn_status == "HOSTILE" && clock.adjustedSeconds >= missionVariables.himsn_status_timer)
    	{
    		missionVariables.himsn_status = "NEUTRAL";
    	}
    }
    
    this._checkPlayerAngle = function() 
    {
    	// Check angle for galactic misjump:
    	this._oldPlayerAngle = player.ship.vectorForward.direction();
    }
    
    this._checkPlayerPitch = function() 
    {
    	// Check pitch for galactic misjump:
    	if (player.ship.pitch) 
    	{
    		if (player.ship.pitch >= 0.95 || player.ship.pitch <= -0.95) 
    		{
    			return true;
    		} 
    		else 
    		{
    			return false;
    		}
    	} 
    	else 
    	{
    		var angle = this._oldPlayerAngle.dot(player.ship.vectorForward.direction());
    		if (angle < 0.95) 
    		{
    			return true;
    		} 
    		else 
    		{
    			return false;
    		}
    	}
    }
    
    this._checkPlayerMisjump = function() 
    {
    	// Check pitch for galactic misjump:
    	if (this._checkPlayerPitch()) 
    	{
    		// If pitch okay for misjump then prepare to send player to intergalactic space:
    		var jumper = system.addShips("himsn_misjumper",1,[15E5,15E5,15E5],1)[0];
    		jumper.scriptedMisjump = true;
    		if (jumper.exitSystem()) {
    				player.ship.position = [15E5,15E5,15E5];
    				this._galacticMisjump = true;
    				player.ship.setEquipmentStatus("EQ_GAL_DRIVE","EQUIPMENT_DAMAGED");
    		}
    	} 
    	else 
    	{
    		// If pitch normal then perform normal galactic jump:
    		this._galacticMisjump = false;
    		player.ship.scriptedMisjump = false;
    	}
    }
    
    this._resetGalacticMisjump = this.shipWillEnterWitchspace = function() 
    {
    	// Reset galactic misjump:
    	if (!this._galacticMisjump && System.infoForSystem(galaxyNumber,player.ship.targetSystem).name == "Intergalactic space") 
    	{
    		System.infoForSystem(galaxyNumber,player.ship.targetSystem).name = null;
    	} 
    	else if (this._galacticMisjump) 
    	{
    		player.ship.scriptedMisjump = true;
    	}
    }
    
    this._repairGalacticHyperDrive = function() 
    {
    	// Repair galactic hyperdrive when 5 minutes are up:
    	player.ship.setEquipmentStatus("EQ_GAL_DRIVE","EQUIPMENT_OK");
    	player.consoleMessage("Galactic Hyperdrive recalibration complete. Remaining charge sufficient to complete jump.",10);
    }
    
    /**** Event handlers ****/
    
    this.startUp = function ()
    {
    	//Reset Galactic Misjump variable:
    	this._galacticMisjump = false;
    	// Check if HIMSN OXZ has run before:
    	if (missionVariables.himsn_status == null)
    	{
    		// Set up internal OXZ variables:
    		missionVariables.himsn_status = "NEUTRAL";
    		missionVariables.himsn_status_timer = clock.adjustedSeconds;
    	}
    }
    
    this.playerStartedJumpCountdown = function (type,delay)
    {
    	if (type == "galactic")
    	{
    		// Setup timers for Galactic Misjump:
    		this._galacticMisjumpTimer2 = new Timer(this,this._checkPlayerAngle,delay-0.5);
    		this._galacticMisjumpTimer = new Timer(this,this._checkPlayerMisjump,delay-0.1);
    	}
    	else if (this._galacticMisjump)
    	{
    		// Force player to misjump:
    		player.ship.scriptedMisjump = true;
    	}
    	else
    	{
    		// Reset Galactic Misjump variable:
    		this._galacticMisjump = false;
    	}
    }
    
    this.playerCancelledJumpCountdown = function() 
    {
    	// Stop and remove Galactic Misjump timers if jump is cancelled:
    	if (this._galacticMisjumpTimer) 
    	{
    		this._galacticMisjumpTimer.stop();
    		delete this._galacticMisjumpTimer;
    	}
    	if (this._galacticMisjumpTimer2) 
    	{
    		this._galacticMisjumpTimer2.stop();
    		delete this._galacticMisjumpTimer2;
    	}
    }
    
    this.shipWillEnterWitchspace = function (cause)
    {
    	this._interstellarBaseLocation = false;
    	this._headquartersLocation = false;
    	// Check if about to jump into interstellar space in between Tetiri and Orlaed in G5:
    	if(galaxyNumber == 4 && ((system.ID == 70 && player.ship.targetSystem == 161) || (system.ID == 161 && player.ship.targetSystem == 70)  || (system.ID == 70 && player.ship.targetSystem == 70) || (system.ID == 161 && player.ship.targetSystem == 161)))
    	{
    		this._headquartersLocation = true;
    	}
    	// Check if about to jump into interstellar space in between Legees and Laeden in G1:
    	if(galaxyNumber == 0 && ((system.ID == 26 && player.ship.targetSystem == 224) || (system.ID == 224 && player.ship.targetSystem == 26)  || (system.ID == 26 && player.ship.targetSystem == 26) || (system.ID == 224 && player.ship.targetSystem == 224)))
    	{
    		this._interstellarBaseLocation = true;
    	}
    	// Check if about to jump into interstellar space in between Raried and Maracece in G3:
    	if(galaxyNumber == 2 && ((system.ID == 4 && player.ship.targetSystem == 123) || (system.ID == 123 && player.ship.targetSystem == 4)  || (system.ID == 4 && player.ship.targetSystem == 4) || (system.ID == 123 && player.ship.targetSystem == 123)))
    	{
    		this._interstellarBaseLocation = true;
    	}
    	// Check if about to jump into interstellar space in between Riusbequ and Quzaarar in G4:
    	if(galaxyNumber == 3 && ((system.ID == 217 && player.ship.targetSystem == 221) || (system.ID == 221 && player.ship.targetSystem == 217)  || (system.ID == 217 && player.ship.targetSystem == 217) || (system.ID == 221 && player.ship.targetSystem == 221)))
    	{
    		this._interstellarBaseLocation = true;
    	}
    	// Check if about to jump into interstellar space in between Gexequon and Edtizabe in G8:
    	if(galaxyNumber == 7 && ((system.ID == 144 && player.ship.targetSystem == 247) || (system.ID == 247 && player.ship.targetSystem == 144)  || (system.ID == 144 && player.ship.targetSystem == 144) || (system.ID == 247 && player.ship.targetSystem == 247)))
    	{
    		this._interstellarBaseLocation = true;
    	}
    	if (this._advPatrolTimer_3)
    	{
    		this._advPatrolTimer_3.stop();
    		delete this._advPatrolTimer_3;
    	}
    }
    
    this.shipWillExitWitchspace = function ()
    {
    	// Check if player is considered an enemy of HIMSN and 60 days have passed since being declared an enemy:
    	this._checkIfHostilePeriodIsOver();
    	
    	// If player is not jumping into interstellar space make sure galactic misjump variable is reset:
    	if (!system.isInterstellarSpace) 
    	{
    		this._galacticMisjump = false;
    	}
    	
    	// Check if a Galactic Misjump is about to occur:
    	if (this._galacticMisjump) 
    	{
    		// Delete oolite populator scripts:
    		delete worldScripts["oolite-populator"].interstellarSpaceWillPopulate;
    		delete worldScripts["oolite-populator"].interstellarSpaceWillRepopulate;
    		// Set a timer for 2 minutes to recharge galactic hyperdrive:
    		this._galacticMisjumpTimer.stop();
    		this._galacticMisjumpTimer = new Timer(this,this._repairGalacticHyperDrive,120);
    		// Set name for area:
    		System.infoForSystem(galaxyNumber,player.ship.targetSystem).name = "Intergalactic space";
    		// Adjust player's position to new area of interstellar space:
    		player.ship.position = [0,0,1E6];
    		// 80% chance of 2x light patrols vs 4-6 thargoids:
    		if (Math.random() < 0.8)
    		{
    			system.addShips("himsn_light_patrol_leader",2,[0,0,1E6],5000);
    			system.addShips("thargoid",4+Math.floor(Math.random() * (2 - 0 + 1) + 10),[0,0,1E6],5000);
    		}
    		// Else 70% chance of 2x heavy patrols vs 6-8 thargoids:
    		else if (Math.random() < 0.7)
    		{
    			if (missionVariables.conhunt == "MISSION_COMPLETE" && missionVariables.thargplans == "MISSION_COMPLETE")
    			{
    				if (Math.random() < 0.5)
    				{
    					system.addShips("himsn_heavy_patrol_leader",2,[0,0,1E6],5000);
    				}
    				else
    				{
    					system.addShips("himsn_missile_corvette",2,[0,0,1E6],5000);
    				}
    			}
    			else
    			{
    				system.addShips("himsn_light_patrol_leader",2,[0,0,1E6],5000);
    			}
    			system.addShips("thargoid",6+Math.floor(Math.random() * (2 - 0 + 1) + 10),[0,0,1E6],5000);
    		}
    		// If none of the above then just player vs 2-4 thargoids:
    		else
    		{
    			system.addShips("thargoid",2+Math.floor(Math.random() * (2 - 0 + 1) + 10),[0,0,1E6],5000);
    		}
    		// 30% chance a rogue planet will be spawned:
    		if (Math.random() < 0.3)
    		{
    			// Choose one of eight planets to spawn: 
    			var planetchance = Math.random();
    			var igPlanet;
    			if ((planetchance <= 1) && (planetchance > 0.875)) igPlanet = system.addMoon("himsn_rogue_planet_1");
    			if ((planetchance <= 0.875) && (planetchance > 0.75)) igPlanet = system.addMoon("himsn_rogue_planet_2");
    			if ((planetchance <= 0.75) && (planetchance > 0.625)) igPlanet = system.addMoon("himsn_rogue_planet_3");
    			if ((planetchance <= 0.625) && (planetchance > 0.5)) igPlanet = system.addMoon("himsn_rogue_planet_4");
    			if ((planetchance <= 0.5) && (planetchance > 0.375)) igPlanet = system.addMoon("himsn_rogue_planet_5");
    			if ((planetchance <= 0.375) && (planetchance > 0.25)) igPlanet = system.addMoon("himsn_rogue_planet_6");
    			if ((planetchance <= 0.25) && (planetchance > 0.125)) igPlanet = system.addMoon("himsn_rogue_planet_7");
    			if (planetchance <= 0.125) igPlanet = system.addMoon("himsn_rogue_planet_8");
    			// 10% chance a navy outpost will be spawned in orbit around planet:
    			if (Math.random() < 0.1)
    			{
    				var planetToStation = Vector3D.randomDirection(2 * igPlanet.radius);
    				var igNavyStat = system.addShips("himsn_interstellar_outpost", 1, igPlanet.position.add(planetToStation))[0];
    				targetVector = igPlanet.position.subtract(igNavyStat.position).direction();
    				angle = igNavyStat.heading.angleTo(targetVector);
    				cross = igNavyStat.heading.cross(targetVector).direction();
    				igNavyStat.orientation = igNavyStat.orientation.rotate(cross, -angle);
    			}
    		}
    	}
    }
    
    this.shipExitedWitchspace = function() 
    {
    	if (missionVariables.himsn_adv_patrol_dest && system.ID == missionVariables.himsn_adv_patrol_dest && system.countShipsWithRole("himsn_adv_patrol") == 0)
    	{
    		this._advPatrolTimer_1 = new Timer(this,this._addAdvPatrol,30);
    	}
    	
    	if (this._galacticMisjump) 
    	{
    		if (!system.isInterstellarSpace) 
    		{
    			// If player has managed to escape Intergalactic Space the reset galactic misjump variables:
    			this._galacticMisjump = false;
    			this._resetGalacticMisjump();
    		} 
    		else 
    		{
    			// Warn player that Galactic Hyperdrive has malfunctioned:
    			if (player.ship.equipmentStatus("EQ_GAL_DRIVE") == "EQUIPMENT_DAMAGED")
    			{
    				player.consoleMessage("WARNING! Galactic Hyperdrive Malfunction!",10);
    				player.consoleMessage("Attempting recalibration with remaining charge...",5);
    			}
    			player.ship.scriptedMisjump = true;
    		}
    	}
    }
    
    this.guiScreenChanged = function(from,to) 
    {
    	// Disable short & long range charts and planet info screens:
    	if (this._galacticMisjump) 
    	{
    		if (guiScreen == "GUI_SCREEN_SYSTEM_DATA" || guiScreen == "GUI_SCREEN_SHORT_RANGE_CHART" || guiScreen == "GUI_SCREEN_LONG_RANGE_CHART") 
    		{
    			mission.runScreen({
    				title: "Critical Error",
    				message: "Unable to determine location - Cannot load Galactic Chart data."
    			});
    		}
    	}
    }
    
    this.shipWillLaunchFromStation = function (station)
    {
    	// Check if player is considered an enemy of HIMSN and 60 days have passed since being declared an enemy:
    	this._checkIfHostilePeriodIsOver();
    }
    
    this.interstellarSpaceWillPopulate = function () 
    {
    	// 15% chance of light patrol encounter:
    	var lightpatrolchance = 0.15;
    	// 10% chance of heavy patrol encounter:
    	var heavypatrolchance = 0.1;
    	
    	// Add Navy Outpost at designated zero distance locations:
    	if (system.ID == -1 && this._interstellarBaseLocation)
    	{
    		delete worldScripts["oolite-populator"].interstellarSpaceWillPopulate;
    		delete worldScripts["oolite-populator"].interstellarSpaceWillRepopulate;
    		system.setPopulator("himsn-interstellar-base",
    		{
    			priority: 200,
    			location: "WITCHPOINT",
    			groupCount: 1,
    			callback: this._addNavyInterstellarOutpost,
    			deterministic: true
    		});
    	}
    	else if (system.ID == -1 && this._headquartersLocation)
    	{
    		delete worldScripts["oolite-populator"].interstellarSpaceWillPopulate;
    		delete worldScripts["oolite-populator"].interstellarSpaceWillRepopulate;
    		system.setPopulator("himsn-headquarters",
    		{
    			priority: 200,
    			location: "WITCHPOINT",
    			groupCount: 1,
    			callback: this._addNavyHeadquarters,
    			deterministic: true
    		});
    	}
    	// If in interstellar space with no outpost:
    	else 
    	{
    		// 2x heavy patrols vs 6x thargoids:
    		if(Math.random() < heavypatrolchance)
    		{
    			var heavy_patrol;
    			if (Math.random() < 0.5)
    			{
    				heavy_patrol = "himsn_light_patrol_leader";
    			}
    			else
    			{
    				heavy_patrol = "himsn_missile_corvette";
    				if (missionVariables.conhunt == "MISSION_COMPLETE" && missionVariables.thargplans == "MISSION_COMPLETE")
    				{
    					if (Math.random() < 0.5)
    					{
    						heavy_patrol = "himsn_heavy_patrol_leader";
    					}
    				}
    			}
    			system.setPopulator("himsn-interstellar-heavy-escort",
    			{
    				priority: 210,
    				location: "WITCHPOINT",
    				groupCount: 2,
    				callback: function(pos) {
    					system.addShips(heavy_patrol,2,pos,0);
    				}
    			});
    			system.setPopulator("himsn-interstellar-heavy-escort-thargoids",
    			{
    				priority: 210,
    				location: "WITCHPOINT",
    				groupCount: 6,
    				callback: function(pos) {
    					system.addShips("thargoid",1,pos,0);
    				}
    			});
    		}
    		// 2x light patrols vs 4x thargoids:
    		else if(Math.random() < lightpatrolchance)
    		{
    			system.setPopulator("himsn-interstellar-light-escort",
    			{
    				priority: 210,
    				location: "WITCHPOINT",
    				groupCount: 2,
    				callback: function(pos) {
    					system.addShips("himsn_light_patrol_leader",1,pos,0);
    				}
    			});
    			system.setPopulator("himsn-interstellar-light-escort-thargoids",
    			{
    				priority: 210,
    				location: "WITCHPOINT",
    				groupCount: 4,
    				callback: function(pos) {
    					system.addShips("thargoid",1,pos,0);
    				}
    			});
    		}
    	}
    }
    
    this.systemWillPopulate = function () 
    {
    	// 3% chance of patrol appearing:
    	var patrolchance = 0.03;
    	// 0.2% chance of recon appearing:
    	var reconchance = 0.002;
    	
    	// Check if player is hostile to navy:
    	if (missionVariables.himsn_status == "HOSTILE")
    	{
    		// 30% chance special ops fighters waiting for player at witchpoint & station aegis:
    		if (Math.random() < 0.3)
    		{
    			system.setPopulator("himsn-specops-fighter-witchpoint",
    			{
    				priority: 200,
    				location: "WITCHPOINT",
    				groupCount: 1,
    				callback: this._addNavySpecOpsFighter,
    				deterministic: true
    			});
    			system.setPopulator("himsn-specops-fighter-station",
    			{
    				priority: 200,
    				location: "STATION_AEGIS",
    				groupCount: 1,
    				callback: this._addNavySpecOpsFighter,
    				deterministic: true
    			});
    		}
    	}
    	
    	// Add Navy Base to Birera (G3) and Xeer (G1):
    	if ((galaxyNumber == 0 && system.ID == 150) || (galaxyNumber == 2 && system.ID == 36))
    	{
    		system.setPopulator("himsn-system-base",
    		{
    			priority: 200,
    			location: "STAR_ORBIT",
    			locationSeed: 67812,
    			groupCount: 1,
    			callback: this._addNavySystemBase,
    			deterministic: true
    		});
    		// 5% chance of patrol appearing:
    		patrolchance = 0.05;
    		// 0.5% chance of recon appearing:
    		reconchance = 0.005;
    		// 3% chance of another patrol appearing on any lane:
    		if (Math.random() < 0.03)
    		{
    			system.setPopulator("himsn-extra-patrol-2",
    			{
    				priority: 210,
    				location: "LANE_WPS",
    				groupCount: 1,
    				callback: this._addNavyPatrol
    			});
    		}
    	}
    	
    	// Add patrol on witchpoint-sun lane:
    	if (Math.random() < patrolchance)
    	{
    		system.setPopulator("himsn-patrol",
    		{
    			priority: 210,
    			location: "LANE_WS",
    			groupCount: 1,
    			callback: this._addNavyPatrol
    		});
    	}
    	
    	// Add recon on any lane:
    	if (Math.random() < reconchance)
    	{
    		system.setPopulator("himsn-specops-recon",
    		{
    			priority: 210,
    			location: "LANE_WPS",
    			groupCount: 1,
    			callback: this._addNavySpecOpsRecon
    		});
    	}
    }
    
    this.systemWillRepopulate = function()
    {
    	if (missionVariables.himsn_adv_patrol_dest && missionVariables.himsn_adv_patrol_dest == system.ID && this._addAdvPatrolSwitch == true)
    	{
    		delete this._addAdvPatrolSwitch;
    		missionVariables.himsn_adv_patrol_dest = null;
    		this._advPatrolTimer_1.stop();
    		delete this._advPatrolTimer_1;
    		this._addAdvPatrolShips(system.locationFromCode("WITCHPOINT"));
    	}
    	if (missionVariables.himsn_adv_patrol_home && missionVariables.himsn_adv_patrol_home == system.ID && this._addAdvPatrolSwitch == true)
    	{
    		delete this._addAdvPatrolSwitch;
    		missionVariables.himsn_adv_patrol_home = null;
    		missionVariables.himsn_adv_patrol_mission = null;
    		this._advPatrolTimer_2.stop();
    		delete this._advPatrolTimer_2;
    		this._addAdvPatrolShips(system.locationFromCode("WITCHPOINT"));
    	}
    }
    Scripts/himsn_ship.js
    "use strict";
    
    this.name 			= "himsn_ship";
    this.author         = "Pleb";
    this.copyright      = "(C) 2014 Pleb.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.version 		= "0.9-alpha";
    
    this.shipSpawned = function ()
    {
    	this.ship.awardEquipment("EQ_FUEL_SCOOPS");
    	this.ship.awardEquipment("EQ_HEAT_SHIELD");
    	
    	// Use Escort Formations OXP if installed for random flight formations:
    	if (worldScripts["Escort Formations Randomiser"])
    	{
    		worldScripts["Escort Formations Randomiser"].$setupDefensiveEscorts(this.ship);
    	}
    }
    
    this.helpRequestReceived = function(ally, enemy)
    {
    	this.ship.destination = ally.position;
    	this.ship.target = enemy;
    	this.ship.performAttack();
    }
    
    this.shipBeingAttacked = function(whom)
    {
    	if (whom.scanClass != "CLASS_MILITARY")
    	{
    		this.ship.target = whom;
    		this.ship.requestHelpFromGroup();
    		system.filteredEntities(this, function (entity)
    		{
    			if (entity.scanClass == "CLASS_MILITARY")
    			{
    				entity.target = whom;
    				entity.performAttack();
    			}
    			if (entity.isStation && entity.hasRole("himsn_station"))
    			{
    				entity.alertCondition = 3;
    				entity.launchDefenseShip();
    			}
    		});
    	}
    }
    Scripts/himsn_station.js
    "use strict";
    
    this.name 			= "himsn_station";
    this.author         = "Pleb";
    this.copyright      = "(C) 2014 Pleb.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.version 		= "0.9-alpha";
    
    this.shipSpawned = function ()
    {
    	if (system.ID == -1) return;
    	this.ship.launchShipWithRole("himsn_adv_patrol", [true]);
    	worldScripts["himsn_main"]._advPatrolTimer_2 = new Timer(this,worldScripts["himsn_main"]._addAdvPatrol,1800);
    	worldScripts["himsn_main"]._advPatrolTimer_3 = new Timer(this,worldScripts["himsn_main"]._launchAdvPatrol,900);
    	
    	this.liftArray = [];
    	this.liftHomeArray = [];
    	this.liftStatusArray = [];
    	this.subArray = this.ship.subEntities;
    	if (this.subArray.length > 0)
    	{
    		var listCounter = 0 ; // reset the counter
    		for(listCounter = 0;listCounter<this.subArray.length;listCounter++)
    		{
    			if (this.subArray[listCounter].hasRole("himsn_kiotaLift"))
    			{
    				this.liftArray.push(this.subArray[listCounter]);
    				this.liftHomeArray.push(this.subArray[listCounter].position);
    				this.liftStatusArray.push("down");				
    			}
    		}
    
    		this.distanceTimer = new Timer(this, this.distanceCheck, 0, 10);
    	}
    }
    
    this.shipBeingAttacked = function(whom)
    {
    	if (whom.scanClass != "CLASS_MILITARY")
    	{
    		this.ship.target = whom;
    		this.ship.requestHelpFromGroup();
    		system.filteredEntities(this, function (entity)
    		{
    			if (entity.scanClass == "CLASS_MILITARY")
    			{
    				entity.target = whom;
    				entity.performAttack();
    			}
    		});
    	}
    }
    
    this.stationReceivedDockingRequest = function(whom)
    {
    	system.filteredEntities(this, function (entity)
    	{
    		if (entity.scanClass == "CLASS_MILITARY")
    		{
    			entity.target = whom;
    			entity.destination = entity.target.position;
    			entity.desiredRange = 2500;
    			entity.performFlyToRangeFromDestination();
    		}
    	});
    }
    
    this.distanceCheck = function()
    {
    	if(this.checkDistance())
    	{
    		if(!this.callbackID) { this.callbackID = addFrameCallback(this.moveLifts.bind(this)); }
    		if(!this.liftTimer) { this.liftTimer = new Timer(this, this.triggerLifts, 0, 10); }
    		if(!this.missileTimer) { this.missileTimer = new Timer(this, this.awardMissile, 0, 30); }
    		return;
    	}
    	else
    	{ 
    		this.stopTimers(); 
    	}	
    }
    
    this.checkDistance = function () 
    {
    	if(!this.ship || ! player.ship || !this.ship.isValid || !player.ship.isValid)
    	{ 
    		return false; 
    	}
    	return (this.ship.position.distanceTo(player.ship) < 256E3);
    }	
    	
    this.rotateStation = function (targetVector)
    {
    	var angle = this.ship.heading.angleTo(targetVector);
    	var cross = this.ship.heading.cross(targetVector).direction();
    	this.ship.orientation = this.ship.orientation.rotate(cross,-angle);
    }
    
    this.awardMissile = function()
    {
    	if(this.ship.missiles.length < this.ship.missileCapacity)
    	{ 
    		this.ship.awardEquipment(this.ship.selectNewMissile()); 
    	}
    }
    	
    this.triggerLifts = function()
    {
    	var listCounter = 0 ; // reset the counter
    	for(listCounter = 0;listCounter<this.liftArray.length;listCounter++)
    	{
    		if(this.liftStatusArray[listCounter] === "down" && Math.random() < (0.1 * Math.random()))
    		{ 
    			this.liftStatusArray[listCounter] = "rising"; 
    		}
    		if (this.liftStatusArray[listCounter] === "up" && Math.random() < (0.1 * Math.random()))
    		{ 
    			this.liftStatusArray[listCounter] = "falling"; 
    		}	
    	}
    }
    
    this.moveLifts = function(delta)
    {
    	if(!this.ship.isValid || !this.ship.status)
    	{
    		this.shipDied();
    		return;
    	}
       
    	var listCounter = 0 ; // reset the counter
    	var distance = delta * 60; // 60 meter per second
    	for(listCounter = 0;listCounter<this.liftArray.length;listCounter++)
    	{
    		if(this.liftStatusArray[listCounter] === "rising")
    		{
    			this.liftArray[listCounter].position = this.liftArray[listCounter].position.add(this.liftArray[listCounter].vectorUp.multiply(distance));
    			if(this.liftArray[listCounter].position.distanceTo(this.liftHomeArray[listCounter]) >= 1145)
    			{
    				this.liftArray[listCounter].position = this.liftHomeArray[listCounter].add(this.liftArray[listCounter].vectorUp.multiply(1150));
    				this.liftStatusArray[listCounter] = "up";
    			}
    		}
             
    		if(this.liftStatusArray[listCounter] === "falling")
    		{
    			this.liftArray[listCounter].position = this.liftArray[listCounter].position.subtract(this.liftArray[listCounter].vectorUp.multiply(distance));
    			if((this.liftArray[listCounter].position.distanceTo(this.liftHomeArray[listCounter]) <= 5) || (this.liftArray[listCounter].position.subtract(this.liftHomeArray[listCounter]).direction().angleTo(this.liftArray[listCounter].vectorUp) < 0.1))
    			{
    				this.liftArray[listCounter].position = this.liftHomeArray[listCounter];
    				this.liftStatusArray[listCounter] = "down";
    			}
    		}	
    	}
    }
    	
    this.playerWillEnterWitchspace = this.entityDestroyed = this.stopTimers = function()
    {
    	if(this.callbackID)
    	{
    		removeFrameCallback(this.callbackID); 
    		delete this.callbackID;
    	}
    		
    	if(this.missileTimer && this.missileTimer.isRunning)
    	{
    		this.missileTimer.stop();
    		delete this.missileTimer;
    	}
    		
    	if(this.liftTimer && this.liftTimer.isRunning)
    	{
    		this.liftTimer.stop();
    		delete this.liftTimer;
    	}
    }
    
    this.shipFiredMissile = function(missile, target)
    {
    	if(missile && target && this.ship.heading.angleTo(target.position.subtract(this.ship.position).direction()) > (Math.PI / 2))
    	{
    		missile.orientation = missile.orientation.rotate(missile.vectorUp, Math.PI); 
    		missile.position = this.ship.position.subtract(this.ship.vectorForward.multiply(this.ship.position.distanceTo(missile.position)));
    	}
    }
    Scripts/himsn_station_dock.js
    "use strict";
    
    this.name 			= "himsn_station_dock";
    this.author         = "Pleb";
    this.copyright      = "(C) 2014 Pleb.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.version 		= "0.9-alpha";
    
    this.acceptDockingRequestFrom = function(ship)
    {
    	if (ship.isPlayer)
    	{
    		if (missionVariables.conhunt == "MISSION_COMPLETE" && missionVariables.thargplans == "MISSION_COMPLETE")
    		{
    			return true;
    		}
    		else
    		{
    			return false;
    		}
    	}
    	else
    	{
    		return true;
    	}
    }
    Scripts/himsn_station_interface.js
    "use strict";
    
    this.name           = "himsn_station_interface";
    this.author         = "Tsoj";
    this.copyright      = "(C) 2021 Tsoj.";
    this.licence        = "CC-NC-by-SA 4.0";
    this.description    = "This is the script for station interfaces for the HIMSN OXZ.";
    this.version        = "0.9-alpha";
    
    this._timeToFirstWarning = 120; // seconds
    this._timeToForcedLaunch = 180; // seconds
    
    this._leaveTimer = null;
    
    this._assert = function(condition, message) {
    	if(!condition)
        	log("HIMSN", "ERROR, condition failed: " + message);
    }
    
    this._stopLeaveTimer = function(){
    	if(this._leaveTimer){
    		this._leaveTimer.stop();
    		delete this._leaveTimer;
    	}
    }
    
    this._startLeaveTimer = function(f, t){
    	this._stopLeaveTimer();
    	this._leaveTimer = new Timer(this, f, t);
    }
    
    this._isAtHIMSNStation = function(){
        return player.ship.docked && (
            player.ship.dockedStation.hasRole("himsn_komodo_carrier") ||
            player.ship.dockedStation.hasRole("himsn_station")
        );
    }
    
    this._forcedStationLaunch = function() {
    	player.bounty += 40;
    	mission.runScreen({
    		titleKey: "HIMSN_forced_launch_title",
    		messageKey: "HIMSN_forced_launch_message",
    	}, function(){
    		player.ship.launch();
    	});
    }
    
    this._warningLeaveStation = function(){
    	mission.runScreen({
    		titleKey: "HIMSN_warning_title",
    		messageKey: "HIMSN_warning_message",
    		choicesKey: "HIMSN_stay_or_leave"
    	}, function (choice){
    		if(choice === "HIMSN_stay"){
    			this._startLeaveTimer(this._forcedStationLaunch.bind(this), this._timeToForcedLaunch);
    		}
    		if(choice === "HIMSN_leave"){
    			player.ship.launch();
    		}
    	});
    }
    
    this._generateAlienItemPrice = function() {
    	let result = {
    		price: 100.0,
    		isSpecial: false
    	};
    
    	if(Math.random() <= 0.05) {
    		result.price += (500 + Math.round(4500 * Math.random()))/10;
    		result.isSpecial = true;
    	}
    
    	return result;
    }
    
    this._runMarketScreen = function() {
    
    	const numAlienItems = player.ship.manifest.alien_items;
    
    	const optionPrefix = "HIMSN_option_";
    
    	let options = {};
    	for(let i = 1; i < Math.min(10000, numAlienItems); i*=10) {
    		options[optionPrefix + i] = "Sell " + i + " alien items";
    	}
    	if(numAlienItems > 0 && !options[optionPrefix + numAlienItems])
    		options[optionPrefix + numAlienItems] = "Sell " + numAlienItems + " alien items";
    
    	mission.runScreen({
    		titleKey: "HIMSN_market_title",
    		message: expandMissionText("HIMSN_market_message", {num_alien_items: numAlienItems}),
    		choices: options,
    		allowInterrupt: true
    	}, function (text){
    		this._assert(text.indexOf(optionPrefix) !== -1, "Options keys all should begin with the option prefix.")
    		let x = text.replace(optionPrefix, "");
    		
    		this._assert(!isNaN(x), "Should be a number: " + x);
    		this._assert(x > 0, "Should be only possible to sell positive amounts of alien items.");
    
    		this._startLeaveTimer(this._warningLeaveStation.bind(this), this._timeToFirstWarning);
    
    		const soldAlienItems = Math.min(Math.floor(x), numAlienItems);
    
    		let earnedCredits = 0;
    		let numSoldSpecialItems = 0;
    		for(let i = 0; i<soldAlienItems; i++){
    			const p = this._generateAlienItemPrice();
    			earnedCredits += p.price;
    			if(p.isSpecial)
    				numSoldSpecialItems += 1;
    		}
    		this._assert(earnedCredits >= 0, "Player shouldn't lose credits by selling alien items.");
    
    		player.ship.manifest.alien_items -= soldAlienItems;
    		player.credits += earnedCredits;
    		
    		mission.runScreen({
    			titleKey: "HIMSN_market_title",
    			message: expandMissionText("HIMSN_sold_alien_items_message", {
    				sold_alien_items: soldAlienItems,
    				num_sold_special_items: numSoldSpecialItems,
    				earned_credits: earnedCredits
    			}),
    			allowInterrupt: true
    		}, function(){
    			this._runMarketScreen();
    		});
    	});
    }
    
    this._runShipyardScreen = function(){
    	mission.runScreen({
    		titleKey: "HIMSN_shipyard_title",
    		messageKey: "HIMSN_shipyard_restricted_message",
    		allowInterrupt: true
    	});
    }
    
    this._runSystemScreen = function(){
    	mission.runScreen({
    		titleKey: "HIMSN_interfaces_title",
    		messageKey: "HIMSN_interfaces_restricted_message",
    		allowInterrupt: true
    	});
    }
    
    this.guiScreenChanged = function () {
        if(this._isAtHIMSNStation()) {
            if (guiScreen === "GUI_SCREEN_MARKET" || guiScreen == "GUI_SCREEN_MARKETINFO")
                this._runMarketScreen();
            if (guiScreen === "GUI_SCREEN_SHIPYARD" || guiScreen === "GUI_SCREEN_EQUIP_SHIP")
                this._runShipyardScreen();
            if (guiScreen === "GUI_SCREEN_INTERFACES")
                this._runSystemScreen();
        }
    }
    
    this.shipWillLaunchFromStation = function() {
        if(this._isAtHIMSNStation()) {
            this._startLeaveTimer();
        }
    }
    
    this.shipDockedWithStation = function () {
        if(this._isAtHIMSNStation()) {
            mission.runScreen({
                titleKey: "HIMSN_welcome_title",
                messageKey: "HIMSN_welcome_message",
                choicesKey: "HIMSN_stay_or_leave",
            }, function (choice){
                if(choice === "HIMSN_stay"){
                    this._startLeaveTimer(this._warningLeaveStation.bind(this), this._timeToFirstWarning);
                }
                if(choice === "HIMSN_leave"){
                    player.ship.launch();
                }
            });
        }
    }
    
    this.startUpComplete = function() {
        if(this._isAtHIMSNStation()) {
    	    this._startLeaveTimer(this._warningLeaveStation.bind(this), this._timeToFirstWarning);
        }
    }