| Config/script.js | "use strict";
this.name        = "FTZ_Core";
this.author      = "Disembodied and phkb";
this.copyright   = "2016 Disembodied and phkb";
this.description = "Populator and dock checking routines for FTZ";
this.licence     = "CC BY-NC-SA 3.0";
/*
Other ideas:
- post some FTZ-keyed missions to the BB
	- transfer some docs/data files/docking list/etc to the main station	
		- have player hounded by police on way?
	- (at main station) offer player the chance to install some monitoring software at ftz to enable galcop to collect trading data
		- player could have chance to sell the software at the FTZ, rather than install it.
			- if they do, the failure of this mission will lead to bounty *and* assassins
			
Ideas for future releases (from Disembodied):
- visits from nice pirates
- trips between main station and ftz by "clean" ships
- unofficial "aegis" patrolled by specialised pirates
- if player is a known bounty hunter
	- forbid entry/have ships launch to ward off player
	- kill player on dock?
	- remove equipment on dock?
Political situation is tense so...
- have viper ships tag ships outside the station as offenders, rather than attack
- keep vipers from attacking anything but fugitives outside a FTZ, keep pirates from attacking patrolling police 
*/
this.local_freetradezone_marked = false;
this._doDockingPenalty = false;
this._penaltyAmount = 1000;
this._destroyed = [];
this._dockFrequency = 0;
this._daysUntilNewStation = 60;
this._trueValues = ["yes", "1", 1, "true", true];
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function() {
	// load our mission variables
	if (missionVariables.FTZ_Marked) this.local_freetradezone_marked = (this._trueValues.indexOf(missionVariables.FTZ_Marked) >= 0 ? true : false);
	if (missionVariables.FTZ_Destroyed) this._destroyed = JSON.parse(missionVariables.FTZ_Destroyed);
	if (missionVariables.FTZ_DockCount) this._dockFrequency = parseInt(missionVariables.FTZ_DockCount);
}
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function() {
	// save our mission variables
	missionVariables.FTZ_Marked = this.local_freetradezone_marked;
	missionVariables.FTZ_Destroyed = JSON.stringify(this._destroyed);
	missionVariables.FTZ_DockCount = this._dockFrequency;
}
//-------------------------------------------------------------------------------------------------------------
this.shipExitedWitchspace = function() {
	// reset our docking flag
	this.local_freetradezone_marked = false;
	this._doDockingPenalty = false;
}
//-------------------------------------------------------------------------------------------------------------
this.systemWillPopulate = function() {
	// will we be creating a FTZ in this system?
	// only in a normal system (not interstellar space), and only in multi-giv systems (gov = 2), and only when tl is > = 6, and only if it hasn't been previously destroyed
	if (system.ID >= 0 && system.info.government == 2 && system.info.techlevel >= 6 && this.$checkForDestroyedFTZ(system.ID) == false) {
		// create the FTZ
		var posFTZ = Vector3D(0, 0, -0.3).fromCoordinateSystem("wpu");
		system.setPopulator("ftz", {
			callback: function(pos) {
					if (system.countShipsWithRole("free_trade_zone") == 0) {
						var ftz = system.addShips("free_trade_zone", 1, pos, 1)[0];
						if (ftz.script.shipDied) ftz.script.$ftz_ovr_shipDied = ftz.script.shipDied;
						ftz.script.shipDied = worldScripts.FTZ_Core.$ftz_shipDied;
					}
				},
			location:"COORDINATES",
			coordinates:posFTZ,
			deterministic:true
		});
		// add a lurking pirate 
		var posFTZPirates1 = Vector3D(0, 0, -0.25).fromCoordinateSystem("wpu");
		system.setPopulator("ftzpirates1", {
			callback: function(pos) {
					var ftzp1 = system.addShips("ftzpirate", 1, pos, 1);
				},
			location:"COORDINATES",
			coordinates:posFTZPirates1
		});
		
		// 25% chance of adding some additional lurking pirates
		if (Math.random() > 0.75) {
			var posPirates2 = Vector3D(0, 0, -0.25).fromCoordinateSystem("wpu");
			system.setPopulator("pirates1", {
				callback: function(pos) {
						var ftzp2 = system.addShips("ftzpirate", 2, pos, 1);
					},
				location:"COORDINATES",
				coordinates:posPirates2
			});
		}
		// 70% of some more pirates a bit closer to the witchpoint
		if (Math.random() > 0.3) {
			var posFTZPirates3 = Vector3D(0, 0, -0.2).fromCoordinateSystem("wpu");
			system.setPopulator("ftzpirates2", {
				callback: function(pos) {
						var ftzp3 = system.addShips("ftzpirate", 2, pos, 1);
					},
				location:"COORDINATES",
				coordinates:posFTZPirates3
			});
		}
		// 70% chance of creating some more pirates halfway between witchpoint and the FTZ
		if (Math.random() > 0.7) {
			var posFTZPirates4 = Vector3D(0, 0, -0.15).fromCoordinateSystem("wpu");
			system.setPopulator("ftzpirates3", {
				callback: function(pos) {
						var ftzp4 = system.addShips("ftzpirate", 4, pos, 1);
					},
				location:"COORDINATES",
				coordinates:posFTZPirates4
			});
		}
		// 50% chance of creating a pirate trader
		if (Math.random() > 0.5) {
			var posHauler1 = Vector3D(0, 0, -0.2).fromCoordinateSystem("wpu");
			system.setPopulator("ftzhauler1", {
				callback: function(pos) {
						var ftzh1 = system.addShips("ftzhauler", 1, pos, 5000);
					},
				location:"COORDINATES",
				coordinates:posHauler1
			});
		}
		// 25% chance of creating another pirate trader
		if (Math.random() > 0.75) {
			var posHauler2 = Vector3D(0, 0, -0.25).fromCoordinateSystem("wpu");
			system.setPopulator("ftzhauler2", {
				callback: function(pos) {
						var ftzh2 = system.addShips("ftzhauler", 1, pos, 5000);
					},
				location:"COORDINATES",
				coordinates:posHauler2
			});
		}
		// 10% chance of adding some police around the FTZ
		if (Math.random() > 0.9) {
			var posPolice = Vector3D(0, 0, -0.3).fromCoordinateSystem("wpu");
			system.setPopulator("ftzPolice", {
				callback: function(pos) {
						var ftzPol = system.addShips("police", 6, pos, 5000);
					},
				location:"COORDINATES",
				coordinates:posPolice
			});
		}
	}
}
//-------------------------------------------------------------------------------------------------------------
// Original concept
/*this.shipWillDockWithStation = function(station) {
	if (station.name == "Free Trade Zone" && this.local_freetradezone_marked == false) {
		this.local_freetradezone_marked = true;
		player.ship.setBounty(player.bounty + 5, "illegal activity");
		player.addMessageToArrivalReport("As per the stringent GalCop law, you have been given a small bounty for docking at this Free Trade Zone.");
	}
}*/
//-------------------------------------------------------------------------------------------------------------
this.shipWillDockWithStation = function(station) {
	this._doDockingPenalty = false;
	// if this station is a FTZ, and we haven't docked at it since arriving insystem....
	if (station.name === "Free Trade Zone" && this.local_freetradezone_marked === false) {
		this.local_freetradezone_marked = true;
		// check if the player has enough cash to cover the cash penalty
		var finalamt = (this._dockFrequency > 0 ? parseInt(Math.pow((this._penaltyAmount * 0.75) / 1000, this._dockFrequency) * 100) * 10 : this._penaltyAmount);
		if (finalamt < 100) finalamt = 100;
		
		if (player.credits > finalamt) {
			// if so, we can run the mission screen where we ask the player which one they want
			this._doDockingPenalty = true;
		} else {
			// if we don't have enough cash, just add the bounty
			player.ship.setBounty(player.bounty + 5, "illegal activity");
			player.addMessageToArrivalReport("As per the stringent GalCop law, you have been given a small bounty for docking at this Free Trade Zone.");
			this._dockFrequency += 1;
		}
	}
}
//-------------------------------------------------------------------------------------------------------------
// displays the mission screen where the player can select their penalty
this.missionScreenOpportunity = function() {
	if (this._doDockingPenalty == true) {
		this._doDockingPenalty = false;
		// ask player what they want to do
		var finalamt = (this._dockFrequency > 0 ? parseInt(Math.pow((this._penaltyAmount * 0.75) / 1000, this._dockFrequency) * 100) * 10 : this._penaltyAmount);
		if (finalamt < 100) finalamt = 100;
		var curChoices = {};
		var text = "";
		var def = "";
		text += "Welcome to the " + expandDescription("%I") + " Free Trade Zone. We hope you enjoy your visit.\n\n" + 
			"By GalCop law, and to prevent GalCop reprisals, we are required to penalise you on arrival at the station. " + 
			"The penalty can come in one of two ways. You can select to either have a small bounty amount added to your legal status, " + 
			"or to pay a fine of " + formatCredits(finalamt, false, true) + ". You may choose which penalty to accept.";
		
		curChoices["01_BOUNTY"] = {text:"Accept bounty", color:this._menuColor};
		curChoices["02_FINE"] = {text:"Accept fine", color:this._menuColor};
		def = "01_BOUNTY";
		var opts = {
			screenID: "oolite-ftz-penalty-map",
			title: "Free Trade Zone",
			overlay: {name:"ftz_logo.png", height:546},
			allowInterrupt: false,
			exitScreen: "GUI_SCREEN_STATUS",
			choices: curChoices,
			initialChoicesKey: def,
			message: text
		};
		mission.runScreen(opts, this.$screenHandler, this);
		opts = null;
		curChoices = null;
	}
}
//-------------------------------------------------------------------------------------------------------------
// processes the option selected by the player
this.$screenHandler = function(choice) {
	if (choice == null) return;
	
	this.local_freetradezone_marked = true;
	switch (choice) {
		case "01_BOUNTY":
			player.ship.setBounty(player.bounty + 5, "illegal activity");
			player.consoleMessage("Your bounty has been increased.");
			break;
		case "02_FINE":
			var finalamt = (this._dockFrequency > 0 ? parseInt(Math.pow((this._penaltyAmount * 0.75) / 1000, this._dockFrequency) * 100) * 10 : this._penaltyAmount);
			if (finalamt < 100) finalamt = 100;
			player.credits -= finalamt;
			player.consoleMessage(formatCredits(finalamt, false, true) + " has been deducted from your account.");
			break;
	}
	this._dockFrequency += 1;
}
//-------------------------------------------------------------------------------------------------------------
// returns true if the FTZ has been destroyed in the selected system, otherwise false
this.$checkForDestroyedFTZ = function(sysID) {
	if (worldScripts.station_validator)  {
		if (worldScripts.station_validator.$deaths("free_trade_zone", this._daysUntilNewStation).length === 0) {
			return false;
		} else {
			return true;
		}
	}
	if (this._destroyed && this._destroyed.length > 0) {
		for (var i = 0; i < this._destroyed.length; i++) {
			// check if the elapsed time since being destroyed is less than 60 days - if so, we return true
			if (this._destroyed[i].system == sysID && (clock.adjustedSeconds - this._destroyed[i].destroyedDate) < (86400 * this._daysUntilNewStation)) return true;
		}
	}
	return false;
}
//-------------------------------------------------------------------------------------------------------------
// removes any historic records from the destroyed array for the selected system
this.$clearDestroyedInfo = function(sysID) {
	if (this._destroyed && this._destroyed.length > 0) {
		for (var i = this._destroyed.length - 1; i >= 0; i--) {
			if (this._destroyed[i].system == sysID) this._destroyed.splice(i, 1);
		}
	}
}
//-------------------------------------------------------------------------------------------------------------
// script attached to shipDied event of the FTZ
this.$ftz_shipDied = function(whom, why) {
	if (this.ship.script.$ftz_ovr_shipDied) this.ship.script.$ftz_ovr_shipDied(whom, why);
	// clear out any historic data for this system
	worldScripts.FTZ_Core.$clearDestroyedInfo(system.ID);
	// add this system to the data array
	worldScripts.FTZ_Core._destroyed.push({system:system.ID, destroyedDate:clock.adjustedSeconds});
}
 | 
                
                    | Scripts/ftz_market.js | "use strict";
this.name = "ftz_market";
this.author = "spara";
this.copyright = "2014 spara";
this.license     = "CC BY-NC-SA 4.0";
this.$originalDefs = {
      "food" : [0, 0, 21, 1, 2, 0, 1, 1, 0],
      "textiles" : [0, 0, 16, 1, 3, -5, 3, 7, 0],
      "radioactives" : [0, 0, 52, 1, 3, -5, 3, 7, 0],
      "slaves" : [0, 0, 20, 0, 0, 10, 15, 0, 0],
      "liquor_wines" : [0, 0, 75, 1, 2, 4, 1, 1, 0],
      "luxuries" : [0, 0, 170, -3, -1, -5, 31, 3, 0],
      "narcotics" : [0, 0, 235, 29, 0, 0, 120, 0, 0],
      "computers" : [0, 0, 140, -7, -1, -3, 15, 7, 0],
      "machinery" : [0, 0, 105, -4, -1, 0, 7, 7, 0],
      "alloys" : [0, 0, 75, -1, -1, 10, 3, 31, 0],
      "firearms" : [0, 0, 124, -7, -1, -2, 15, 3, 0],
      "furs" : [0, 0, 135, 3, 2, 3, 7, 1, 0],
      "minerals" : [0, 0, 18, 3, 3, 9, 3, 7, 0],
      "gold" : [0, 0, 102, 1, 0, 0, 20, 0, 1],
      "platinum" : [0, 0, 181, 2, 0, 0, 21, 0, 1],
      "gem_stones" : [0, 0, 50, 1, 0, 0, 15, 0, 2],
      "alien_items" : [0, 0, 10, 1, 0, 0, 7, 0, 0]
};
this.updateLocalCommodityDefinition = function(goodDefinition) {
	var commodity = goodDefinition.key;
	var oldDefs = this.$originalDefs[commodity];
	//old style definition found for the good. calculate it the old way
	if (oldDefs) {
		var market_base_price = oldDefs[2];
		var market_eco_adjust_price = oldDefs[3];
		var market_eco_adjust_quantity = oldDefs[4];
		var market_base_quantity = oldDefs[5];
		var market_mask_price = oldDefs[6];
		var market_mask_quantity = oldDefs[7];
		var market_rnd = Math.floor(Math.random() * 256);
		var economy = system.economy;
		var price = (market_base_price + (market_rnd & market_mask_price) + (economy * market_eco_adjust_price)) & 255;
		price *= 0.4;
		var quantity = (market_base_quantity + (market_rnd & market_mask_quantity) - (economy * market_eco_adjust_quantity)) & 255;
		if (quantity > 127) quantity = 0;
		quantity &= 63;
		goodDefinition.price = price * 10;
		goodDefinition.quantity = quantity;
	} else {
		// hit or miss variation
		var price = goodDefinition.price * (1 + (system.scrambledPseudoRandomNumber(clock.days) * 0.6 - 0.3));
		// make sure there aren't lots of units to buy if the price is cheaper
		if (price < goodDefinition.price && goodDefinition.quantity > 0) {
			goodDefinition.quantity = parseInt(goodDefinition.quantity * 0.5);
		}
	}
	return goodDefinition;
};
 |