Back to Index Page generated: Dec 20, 2024, 7:22:09 AM

Expansion Free Trade Zones

Content

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Adds Free Trade Zones to Multi-Government systems (TL7+). Adds Free Trade Zones to Multi-Government systems (TL7+).
Identifier oolite.oxp.Disembodied.FreeTradeZone oolite.oxp.Disembodied.FreeTradeZone
Title Free Trade Zones Free Trade Zones
Category Dockables Dockables
Author Disembodied, Griff, phkb Disembodied, Griff, phkb
Version 0.31 0.31
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Information URL http://wiki.alioth.net/index.php/Free_Trade_Zone n/a
Download URL https://wiki.alioth.net/img_auth.php/3/34/FTZ.oxz n/a
License CC BY-NC-SA 3 CC BY-NC-SA 3
File Size n/a
Upload date 1626941722

Documentation

Also read http://wiki.alioth.net/index.php/Free%20Trade%20Zones

readme.txt

Oolite OXP

FTZ v0.31

Partick Enterprises, 18 August 2007
Updated 8 October 2010
Updated 20 May 2016 (v0.21)

Overview
========
This is a small flavour OXP that adds a "Free Trade Zone" to Multi-Government systems. These are mined-out rock-hermits, dragged beyond the witchpoint beacon, where various morally dyslexic ship captains can trade outside the official, GalCop-protected, network. There are some bargains to be found -- as you might expect, given how most of the goods are acquired -- but quantities are often low and there are often unscrupulous individuals in the area. It's really a buyer's market, unless you find it awkward to go near main stations. Fuel and basic equipment are available, at a premium. Their out-of-the-way location can make FTZs hard to find, but they are marked as "Z" on the Advanced Space Compass.

Free Trade Zones exist because of the highly complex legal nature of Multi-Government planets, their collective paranoia over perceived sovereignty infringements by GalCop, and their general inability to make collective decisions. Although FTZs are recognised as nation states by the planetary authorities, GalCop currently regard those who visit these stations as (minor) Offenders, and will garnish your legal status accordingly. As part of the deal with GalCop, the FTZs are obliged to provide information on all who enter and leave. Despite persistent GalCop requests, however, they still refuse to give details of those ships' cargo manifests, citing "commercial confidentiality".

New rules from GalCop have meant that FTZ's can, as an alternative to marking docking ships as offenders, pay GalCop a premium of 1000cr for each ship that visits the station. As the governing bodies of the FTZ's are in no position to subsidise this expenditure, they have instead given the captains the option. When a ship docks, they will be asked what their preferred option is: accept the bounty increase, or pay the 1000cr. Regular visitors to FTZ's will find that the 1000cr amount will reduce over time as a "frequent dockers" system has recently been implemented.

Also, visitors to FTZ's will now need to request docking clearance, as a series of accidents in the docking tunnel have had a serious impact on prices.

License
=======
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License version 3.0. For more information see the Oolite ReadMe or the Creative Commons' website.

Thanks to Disembodied for coming up with the original idea and OXP. Disembodied has very kindly allowed phkb to update and maintain it.

FTZ logo image from http://simpleicon.com/d_zone.html

Version History
===============
0.31
- Updates to shipdata to link into randomshipnames and Skilled NPC's (thanks to Rustum for the entries).
- Update the spawning mechanism to allow for games to be saved at FTZ's.

0.30
- Updated FTZ model to use the Griff shadered rock hermit.

0.22
- Frequent visitors to Free Trade Zones will now receive a discount on the fine amount.
- Increased destroyed station recreation wait period to 60 days.
- Added code to utilise Station Validator OXP, if installed.
- Tweaks to the market script to cater for non-core commodities.

0.21
* Converted model to be a variation of the new Rock Hermit.
* Added a customised docking tunnel texture for use by BGS.
* Turned on docking requests.
* Limited FTZ's to only appear in TL7 systems or higher.
* Converted plist-style script to Javascript.
* Updated the populator routine to use the new Oolite populator methods.
* Added routines to check if the FTZ was destroyed in a system, and only recreate the station after 30 days have passed.
* Updated the market script to use the new style.
* Added an option for commanders who dock at the station to either take the bounty increase, or pay a fine.

0.15:
* Changed "legalStatus_number" to "commanderLegalStatus_number" to conform with trunk changes. Docking with an FTZ once again *adds* 5 to your bounty, instead of *setting it* to 5 ...

0.14:
* Corrected error where FTZ escorts could get called up as ordinary escorts. Thanks to Eric Walch for the correction.

0.13:
* Pirates around the FTZ now carry some cargo.
* GalCop may, from time to time, put on a show of force in the vicinity of an FTZ -- cries of "restrictive trade practices" notwithstanding.

0.11:
* There is now an automatic 5-point fine to your legal record for visiting an FTZ (v0.1 just added 5 to your record if you were clean: now bad people get fined too). Thanks to Commander McLane on the Oolite BBS for the coding.

Equipment

This expansion declares no equipment.

Ships

Name
Free Trade Zone
FTZ (docking slit)
ftzcargo1
ftzcargo2
ftzcargo3
ftzcargo4
ftzescort1
ftzescort2
ftzescort3
ftzpirate1
ftzpirate10
ftzpirate11
ftzpirate12
ftzpirate13
ftzpirate2
ftzpirate3
ftzpirate4
ftzpirate5
ftzpirate6
ftzpirate7
ftzpirate8
ftzpirate9

Models

This expansion declares no models.

Scripts

Path
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_conditions.js
"use strict";
this.name        = "FTZ_Conditions";
this.author      = "phkb";
this.copyright   = "2016 phkb";
this.description = "Condition script for populating FTZ";
this.licence     = "CC BY-NC-SA 3.0";

this.allowSpawnShip = function(shipKey) {
	if (system.info.government != 2) {
		return false;
	} else {
		return true;
	}
}
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;
};