/*
========================================================================
extraThargoids_populator.js

This file is part of the ExtraThargoids expansion pack.
Author: UK_Eliter
License: 2017 Creative Commons: attribution, non-commercial, sharealike.
========================================================================
*/


/*
-------------------
JSLINT: set options
-------------------
*/

/*jshint esversion: 6*/
/*jshint sub:true*/

this.name = "extraThargoids_populator";
this.author = "UK_Eliter";
this.copyright = "2014 Creative Commons: attribution, non-commercial, sharealike.";
this.licence = "CC-NC-SA 3";
this.description = "This script adds some of the 'Extra Thargoids' to the game";


/*
--------
SWITCHES
--------
*/

this.logging = false; // NB: Most log lines are commented out at present.


/*
----------------
GLOBAL VARIABLES
----------------
*/

this.invasionChance = 0.003;
// 0.003. Increased somewhat by player score . . - see this.startUp.


/*
------------------------
JSHINT: start of wrapper
------------------------
*/

(function() {
	"use strict";


	/*
	---------
	MAIN CODE
	---------
	*/

	this.startUp = function() {
		this.threeG_Installed = (worldScripts.ferdelance3G_populator !== undefined);
		var score = player.score;
		if (score > 7000) {
			if (score > 19200) {
				this.invasionChance += 0.0035;
			} else {
				this.invasionChance += 0.0025;
			} // 'Elite' score is 6400.
		}
		this.invasionExtantInCurrentSystem = false;
		// log("Extra Thargoids", "Initialised OK");
	};

	this.playerWillEnterWitchspace = function() {
		if (this.invasionExtantInCurrentSystem || this.invasionChance === 0 || player.score < 1500 || Math.random() > this.invasionChance) {
			this.invasionExtantInCurrentSystem = false;
		} else {
			this.repopulationsCounter = 0;
			this.invasionExtantInCurrentSystem = true; // well, will occur in the NEXT system.
			this.maxRepopulations = 40 + Math.ceil(Math.random() * 100);
			this.repopulationsCounter = 0;
		}
		// this.invasionExtantInCurrentSystem = true; // TEST
	};

	this.entityDestroyed = function() {
		this.invasionExtantInCurrentSystem = false;
	};

	this.interstellarSpaceWillPopulate = function() {
		// INTERSTELLAR POPULATOR
		// Use 'callback: this._myFunction.bind(this)' not callback: this._myFunction' in order to use global variables and functions.
		// if two populator entries have same 'priority', Oolite will randomly determine their order.
		// if (Math.random() > 0.86) {return;}
		// ADD THARGOIDS
		system.setPopulator("extraThargs-interstellarThargoids", {
			priority: 101,
			callback: this._perhapsAddInterstellarThargoids.bind(this)
		});
	};

	this._perhapsAddInterstellarThargoids = function(pos) {
		//
		// log("extraThargoids_populator.js", "One or more Thargoid(s) added to interstellar space by populator script.");
		var n;
		if (player.score > 3750) {
			n = 36;
		} else {
			n = 40;
		}
		var c = Math.ceil(Math.random() * n);
		var s;
		switch (c) {
			case 1:
				s = system.addShips("extraThargoid", 1, pos, 27000);
				break;
			case 2:
				s = system.addShips("extraThargoid", 1, pos, 27000);
				break;
			case 3:
				s = system.addShips("extraThargoid", 2, pos, 27000);
				break;
			case 4:
				s = system.addShips("extraThargoid", 3, pos, 30000);
				break;
			case 5:
				s = system.addShips("extraThargoids_buggly3", 3, pos, 15000);
				break;
			case 6:
				s = system.addShips("extraThargoid", 2, pos, 60000);
				break;
			case 7:
				s = system.addShips("extraThargoid", 2, pos, 27000); /* falls through */
			case 8:
				s = system.addShips("extraThargoids_buggly2", 1, pos, 27000);
				break;
			case 9:
				s = system.addShips("extraThargoids_sweeper", 1, pos, 20000);
				break;
			case 10:
				s = system.addShips("extraThargoids_sweeper", 1, pos, 25000);
				break;
			case 11:
				s = system.addShips("extraThargoids_sweeper", 1, pos, 28000);
				break;
			case 12:
				s = system.addShips("extraThargoids_sweeper", 2, pos, 40000);
				break;
			default:
		}
	};

	// INTERSTELLAR REPOPULATOR - NONE
	/*
	this.interstellarSpaceWillRepopulate = function()
	{
	}
	*/

	this.systemWillPopulate = function() {
		// STELLAR POPULATOR

		// LANE_PS, LANE_WP, LANE_WS, STATION_AEGIS, PLANET_ORBIT, OUTER_SYSTEM, OUTER_SYSTEM_OFFPLANE

		// INVASION stuff
		// Use 'callback: this._myFunction.bind(this)' not callback: this._myFunction' in order to use global variables and functions
		if (this.invasionExtantInCurrentSystem === false) {
			return;
		} // Else - INVASION
		// Add thargoids and other ships
		system.setPopulator("extraThargs-invasionShips", {
			groupCount: 1,
			priority: 100,
			location: "LANE_WP",
			callback: this._addInvasionEntities.bind(this)
		});
		if (Math.random() > 0.8) {
			return;
		}
		var gc = 1;
		if (Math.random() < 0.3) {
			gc += 1;
		}
		system.setPopulator("extraThargs-invasionShips_More", {
			groupCount: gc,
			priority: 101,
			location: "LANE_WPS",
			callback: this._addInvasionEntities.bind(this)
		});
	};

	this.shipWillExitWitchspace = function() {
		if (!this.invasionExtantInCurrentSystem) {
			return;
		}
		// Under certain conditions, cancel it. (And can't do this earlier, i.e. not initiate in the first place, because of technical problems. .
		// Or, rather, because cannot cancel in sense of undo the population function, just try to make sure all ships I've added leave.
		if (system.isInterstellarSpace) {
			this.invasionExtantInCurrentSystem = false;
			return;
			// This will not actually cancel anything, because interstellar - rather than stellar - populator will have been called.
		}
		// Else
		if (system.sun.isGoingNova || system.sun.hasGoneNova) {
			system.sendAllShipsAway();
			this.invasionExtantInCurrentSystem = false;
			return;
		}
		// Else
		//
		// Remove some existing ships - try to do this as late as possible
		this.$removeShipsEtcForInvasion();
	};

	this.shipExitedWitchspace = function() {
		if (this.invasionExtantInCurrentSystem) {
			// this.invasionExtantInCurrentSystem will have been set to false if we are in interstellar space.
			player.consoleMessage("** POLICE ALERT **: Thargoid invasion!", 300);
		}
		// var s = system.addShips("extraThargoids_uberBuggly", 1, [0,0,0], 22000); // TEST
	};

	this.$is_a_targettedNonMainStation = function(e) {
		return e.isStation && e.scanClass === "CLASS_STATION" && (e.position.distanceTo(system.mainPlanet.position) < system.mainPlanet.radius * 13);
	};

	this.$isWitchpointBuoy = function(e) {
		return e.isShip && e.scanClass === "CLASS_BUOY" && e.hasRole("buoy-witchpoint") && (e.position.distanceTo(system.mainPlanet.position) < system.mainPlanet.radius * 50);
	};

	this.$removeShipsEtcForInvasion = function() {
		// Some populators might add stuff *after* this, so err on removing too much
		var i, l, f, r, s;

		// Stations
		s = system.filteredEntities(this, this.$is_a_targettedNonMainStation, system.mainStation);
		for (i = 0; i < s.length; i++) {
			r = Math.random();
			if (r < 0.5) {
				if (r < 0.4) {
					s[i].explode();
				} else {
					s[i].remove(true); // no death action
				}
			}
		}
		// Buoys
		s = system.filteredEntities(this, this.$isWitchpointBuoy);
		l = s.length;
		if (l > 0) {
			i = s.length;
			while (i--) {
				if (Math.random() < 0.6) {
					s[i].remove(true);
				}
			}
		}
		// Neutral ships
		s = system.entitiesWithScanClass("CLASS_NEUTRAL");
		l = s.length;
		if (l > 9) {
			if (Math.random() < 0.6) {
				f = 0.9;
			} else {
				f = 0.75;
			}
			// NB: The following will run before various (old-style) OXP populators
			l = Math.ceil(s.length * f);
			i = l;
			while (l--) {
				if (
					(s[i].isValid) &&
					s[i].isShip &&
					!s[i].isPlayer &&
					s[i].primaryRole !== "hunter-medium" &&
					s[i].primaryRole !== "hunter-heavy" &&
					!s[i].hasRole("ecl_escape_pod_beacon") &&
					!s[i].hasRole("escape-capsule") &&
					!s[i].hasRole("hiredGuns_escort")
				) {
					if ((i % 3 === 0) && (s[i].distanceToPlayer > 30000) && (s[i].distanceToPlayer < 3072000)) {
						if (s[i].abandonShip === true) {
							s[i].energy = (s[i].energy * f) - 100 - i;
						} else if (i % 6 === 0) {
							s[i].explode();
						} else {
							s[i].remove(true);
						}
					}
				}
			}
		}
		// Remove some rocks
		s = system.entitiesWithScanClass("CLASS_ROCK", player.ship, 3072000);
		if (s.length < 1) {
			return;
		}
		l = Math.ceil(s.length * 0.35);
		i = l;
		while (i--) {
			if (s[i].isValid) {
				if ((i % 2 === 0) && (s[i].distanceToPlayer > 30000)) {
					s[i].explode();
				} else {
					s[i].remove(true); // no death action
				}
			}
		}
	};

	this._addInvasionEntities = function(pos) {
		var baseThargoidNum, basePoliceNum, i, n, n2, r, s;

		// THARGOIDS
		if (player.score < 5000) {
			baseThargoidNum = 18;
		} else {
			baseThargoidNum = 23;
		}

		// log("ET TESTING", "OK");

		// Main action - carriers and other ships
		if (this.$roleExists("thargoidCarrier") !== undefined && system.mainStation && Math.random() < 0.9) {
			n = 1 + Math.ceil(Math.random() * 2);
			if (n === 1 && Math.random() < 0.5) {
				n++;
			}
			i = n;
			while (i--) {
				s = system.addShips("thargoid_carrier", 1, pos, 26000);
				s[0].script.targetStation = system.mainStation;
				s[0].script.destinationCoordinates = system.mainStation.position;
				if (Math.random() < 0.6) {
					s = system.addShips("extraThargoids_sweeper", 1, pos, 15000);
				}
			}
			baseThargoidNum -= 5; // if (baseThargoidNum < 10) {baseThargoidNum = 10;}
			if (Math.random() < 0.7) {
				s = system.addShips("extraThargoids_uberBuggly", 1, pos, 20000); // has sweeper escorts
				baseThargoidNum -= 1;
			}
		} else if (Math.random() < 0.92) {
			s = system.addShips("extraThargoids_uberBuggly", 1, pos, 17000); // has sweeper escorts
			baseThargoidNum -= 2;
			if (Math.random() < 0.57) {
				s = system.addShips("extraThargoids_uberBuggly", 1, pos, 20000); // has sweeper escorts
				baseThargoidNum -= 1;
			}
		}
		s = system.addShips("thargoid", baseThargoidNum, pos, 20000);
		// Witchspace - planet
		n = Math.ceil(Math.random() * baseThargoidNum);
		s = system.addShipsToRoute("thargoid", baseThargoidNum, Math.random(), "wp");
		// POLICE
		// Main action - normal ships and carriers
		basePoliceNum = baseThargoidNum + 2 + Math.ceil(Math.random() * 4);
		if (Math.random() < 0.7) {
			n = 1 + Math.ceil(Math.random() * 5);
			s = system.addShips("interceptor", n, pos, 23000);
			if (s[0] && s[0].isValid) {
				basePoliceNum--;
			}
		}
		r = Math.random();
		if (r < 0.7) {
			s = system.addShips("behemoth", 1, pos, 23000);
			if (r < 0.35) {
				s = system.addShips("behemoth", 1, pos, 32000);
			}
			if (s[0] && s[0].isValid) {
				basePoliceNum -= 2;
			} // have done no check actually are these ships installed
		}
		if (Math.random() < 0.5) {
			s = system.addShips("leviathan", 1, pos, 23000);
			basePoliceNum -= 2;
			if (s[0] && s[0].isValid) {
				basePoliceNum -= 2;
			} // have done no check actually are these ships installed
		}
		if (basePoliceNum > 0) {
			s = system.addShips("police", basePoliceNum, pos, 20000);
		}
		// Witchpoint - planet
		if (Math.random() < 0.5) {
			n = 1 + Math.ceil(Math.random() * basePoliceNum);
			s = system.addShipsToRoute("police", n, Math.random(), "wp");
		}
		// HUNTERS
		r = Math.random();
		if (r < 0.25) {
			n = 1 + Math.ceil(Math.random() * 2);
			s = system.addShips("hunter-medium", n, pos, 35000);
		}
		if (r < 0.2) {
			n = 1 + Math.ceil(Math.random() * 3);
			s = system.addShips("hunter-heavy", n, pos, 30000);
		}
		// WRECKAGE. Note that removal of entities via removeShipsEtcForInvasion will tend to generate some wreckage.
		// At the site of the main action
		n = 1 + Math.ceil(Math.random() * 4);
		s = system.addShips("alloy", n, pos, 45000);
		n = 1 + Math.ceil(Math.random() * 9);
		s = system.addShips("extraThargoids_tharglet", n, pos, 40000);
		// Witchpoint
		r = Math.random();
		if (r < 0.6) {
			n = 1 + Math.ceil(r * 3);
			s = system.addShips("alloy", n, [0, 0, 0], 45000);
			n = 1 + Math.ceil(r * 13);
			s = system.addShips("extraThargoids_tharglet", n, [0, 0, 0], 40000);
			if (Math.random() < 0.5) {
				n2 = 1 + Math.ceil(Math.random() * 4);
				s = system.addShips("cargopod", n2, [0, 0, 0], 4000);
			}
		}
		// Witchpoint - planet
		n = 1 + Math.ceil(Math.random() * 7);
		i = n;
		while (i--) {
			n2 = 1 + Math.ceil(Math.random() * 4);
			s = system.addShipsToRoute("cargopod", n2, Math.random(), "wp");
		}
		n = 1 + Math.ceil(Math.random() * 4);
		i = n;
		while (i--) {
			n2 = 1 + Math.ceil(Math.random() * 4);
			s = system.addShipsToRoute("extraThargoids_tharglet", n2, Math.random(), "wp");
			if (Math.random() < 0.3) {
				s = system.addShipsToRoute("alloy", 1, r, "wp");
			}
		}
		s = system.addShipsToRoute("extraThargoids_tharglet", n, Math.random(), "wp");
	};

	this.systemWillRepopulate = function() {
		// It is important for smooth gameplay that this function runs very quickly. If calculations are needed, run as many as possible in the populator function to save the result.
		// 'systemWillRepopulate' does *not* use system.setPopulator 

		if (this.invasionExtantInCurrentSystem === false) {
			return;
		}
		// THE FOLLOWING ONLY RUNS *WHEN IS AN INVASION*
		if (this.repopulationsCounter > this.maxRepopulations) {
			return;
		}
		// Else
		this.repopulationsCounter++;
		if (Math.random() > 0.04) {
			return;
		}
		// Else
		var i, g, n, s, s2;
		// Perhaps add police
		if (Math.random() < 0.45) {
			n = system.countShipsWithRole("police");
			if (n > 50) {
				return;
			}
			// Else
			n = 3 + Math.ceil(Math.random() * 8);
			if (this.threeG_Installed && r < 0.015) {
				s = system.addShips("ferdelance3G_interstellar", n);
				i = s.length;
				while (i--) {
					s[i].ai.switchAI("route1patrolAI.plist");
					// Need to set AI to stop them trying to go interstellar
				}
			} else {
				s = system.addShips("police", n);
			}
			return;
		}
		// perhaps add thargoids
		if (Math.random() < 0.35) {
			n = system.countShipsWithRole("thargoid");
			if (n > 150) {
				return;
			}
			n = 2 + Math.ceil(Math.random() * 30);
			s = system.addShips("thargoid", n);
			return;
		}
		// Else, add hunters
		s = system.addShips("hunter-heavy", 1);
		if (s[0]) {
			g = new ShipGroup("hunter group vs invasion", s[0]);
			s[0].group = g;
			log("ET TESTING", "add hunter-heavy(" + g.name + ") to ...");
			// TODO: Set weapons, skill, AI
			if (s[0].autoAI) {
				s[0].switchAI("oolite-bountyHunterLeaderAI.js");
			}
			n = 2 + Math.ceil(Math.random() * 5);
			s2 = system.addShips("hunter", n);
			for (i = 0; i < n; i++) {
				s2[i].group = g;
				g.addShip(s2[i]);
				// s2[i].setAI("oolite-bountyHunterAI.js"); // autoAI
			}
			// log("ET TESTING", "added "+n+" hunters("+g.name+") to ...");
		}
	};

	this.$roleExists = function(roleString) {
		var dummyShips = system.addShips(roleString, 1, [100000, 100000, 100000]);
		if (dummyShips == null) {
			return false;
		}
		var exists = (dummyShips.length == 1);
		if (exists) dummyShips[0].remove(true);
		return exists;
	};


	/*
	----------------------
	JSHINT: end of wrapper
	----------------------
	*/

}).call(this);

// EOF