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

Expansion Curse of the Black Sunspot

Content

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description An informal mission for experienced players set in Chart 3 An informal mission for experienced players set in Chart 3
Identifier oolite.oxp.cim.cotbs oolite.oxp.cim.cotbs
Title Curse of the Black Sunspot Curse of the Black Sunspot
Category Missions Missions
Author cim cim
Version 1.0.2 1.0.2
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Information URL http://wiki.alioth.net/index.php/Curse_of_the_Black_Sunspot n/a
Download URL https://cim.sotl.org.uk/games/files/oolite/Curse_of_the_Black_Sunspot_1.0.2.oxz n/a
License CC-BY-SA 3.0 CC-BY-SA 3.0
File Size n/a
Upload date 1397678091

Documentation

Also read http://wiki.alioth.net/index.php/Curse%20of%20the%20Black%20Sunspot

Equipment

Name Visible Cost [deci-credits] Tech-Level
Restore to factory settings yes 10000 9+

Ships

Name
cotbs-escort1
cotbs-escort2
cotbs-escort3
cotbs-escort4
Vengeance
cotbs-guard
cotbs-leader
cotbs-loot
cotbs-misjumper
Asteroid
Transmitter
cotbs-turret

Models

This expansion declares no models.

Scripts

Path
Scripts/cotbs-conditions.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS condition script";

/** How this works...
 * What we want is for the pirate leader to have the four unique
 * escorts defined in shipdata - specifically, one of each.
 * So, each escort has a common escort role, which the leader uses
 * Then, we keep a counter in the worldscript.
 * This is used to ensure that only cotbs-escort1 can be spawned to start with
 * Once it is spawned, its ship script event (and we have to use
 * spawnedAsEscort, as shipSpawned occurs too late) increments the
 * counter, so the next escort spawned must be cotbs-escort2, and so
 * on.
 */

this.allowSpawnShip = function(shipkey) {
		var rv = false;
		var counter = 1 + worldScripts["COTBS"]._escortSetupCounter;

		if (shipkey == "cotbs-escort"+counter) {
				rv = true;
		}
		return rv;
}

/* Cleaner than messing around with TL 99 */

this.allowAwardEquipment = function(eqkey) {
		// eqkey is always EQ_COTBS_RESTORE
		if (missionVariables.COTBS_stage == "DESTROYED") {
				if (missionVariables.COTBS_substage != "UNKNOWN" && missionVariables.COTBS_substage != "THATSODD" && missionVariables.COTBS_substage != "NEEDTL9" && missionVariables.COTBS_delay < 3) {
						return true;
				}
		}
		return false;
}
Scripts/cotbs-error.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS: display error";

this.effectSpawned = function() {
		this.$fcb = addFrameCallback(this._update.bind(this));
		this.visualEffect.shaderFloat1 = Math.random();
		this.visualEffect.shaderFloat2 = -1;
		player.consoleMessage("Camera feed malfunction. Attempting recalibration",10);
		this.visualEffect.scale(1000);
}

this.effectRemoved = function() {
		removeFrameCallback(this.$fcb);
}

this._update = function(delta) {
		this.visualEffect.shaderFloat1 += delta;
		this.visualEffect.shaderFloat2 += delta/7;
		this.visualEffect.position = player.ship.position;
		if (this.visualEffect.shaderFloat2 > 1) {
				this.visualEffect.remove();
		}
}
Scripts/cotbs-escort.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS pirate escort script";

this.shipSpawned = function() {
		// only get a name if ships in general get names
		if (worldScripts["randomshipnames"]) {
				this.ship.displayName += ": " + this.ship.scriptInfo.cotbsname;
		}
		// correct for ship models with weapon on subent
		for (var i=0; i<this.ship.subEntities.length;i++) {
				if (this.ship.subEntities[i].forwardWeapon != EquipmentInfo.infoForKey("EQ_WEAPON_NONE")) {
						this.ship.subEntities[i].forwardWeapon = this.ship.forwardWeapon;
						this.ship.forwardWeapon = "EQ_WEAPON_NONE";
				}
		}

		this.ship.bounty = 64+Math.floor(Math.random()*64);
}

this.spawnedAsEscort = function(ship) {
		worldScripts["COTBS"]._escortSetupCounter++;
}

this.shipDied = function() {
		if (worldScripts["COTBS"]._adversary) {
				worldScripts["COTBS"]._adversary.script._reactToEscortLoss();
		}
}
Scripts/cotbs-ghost.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS ghost ships";

this._fcb = null;
this._ve = null;

this.shipSpawned = function() {
		this._ve = system.addVisualEffect("cotbs-ghost-"+(1+Math.floor(Math.random()*6)),this.ship.position);
		this._ve.orientation = this.ship.orientation;
		this._fcb = addFrameCallback(this._veTrack.bind(this));
}

this._veTrack = function(delta) {
		if (this.ship) {
				this._ve.position = this.ship.position; 
				this._ve.orientation = this.ship.orientation;
		} else {
				this._ve.remove();
		}
}

this.shipDied = function() {
		if (this._fcb) {
				removeFrameCallback(this._fcb);
		}
		if (this._ve) {
				this._ve.remove();
		}
		if (player.alertLevel == 3) { // red alert
				// replace it 
				system.addShips("cotbs-ghost",1,player.ship.position,10E3);
		}
}

this._setTarget = function() {
		this.ship.target = player.ship;
}
Scripts/cotbs-guard.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS guard ships";

this.shipSpawned = function() {

		if (worldScripts["randomshipnames"]) {
				ship.displayName += ": " + worldScripts["randomshipnames"].$randomPirateName(ship);
		}

		for (var i=0; i<this.ship.subEntities.length;i++) {
				if (this.ship.subEntities[i].forwardWeapon != EquipmentInfo.infoForKey("EQ_WEAPON_NONE")) {
						this.ship.subEntities[i].forwardWeapon = this.ship.forwardWeapon;
						this.ship.forwardWeapon = "EQ_WEAPON_NONE";
				}
		}
		
		this.ship.bounty |= Math.floor(Math.random()*64);
		this.ship.primaryRole = "pirate";
}
Scripts/cotbs-leader.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS pirate leader ship script";

this._lostEscorts = 0;

this.shipSpawned = function() {
		// only get a name if ships in general get names
		if (worldScripts["randomshipnames"]) {
				this.ship.displayName += ": " + this.ship.scriptInfo.cotbsname;
		}
		// correct for ship models with weapon on subent
		for (var i=0; i<this.ship.subEntities.length;i++) {
				if (this.ship.subEntities[i].forwardWeapon != EquipmentInfo.infoForKey("EQ_WEAPON_NONE")) {
						this.ship.subEntities[i].forwardWeapon = this.ship.forwardWeapon;
						this.ship.forwardWeapon = "EQ_WEAPON_NONE";
				}
		}
		// set escort formation if supported
		if (worldScripts["Escort Formations Randomiser"]) {
				worldScripts["Escort Formations Randomiser"].$setupEscortFormation(this.ship,"arrowhead");
		}

		this.ship.bounty = 255;

		worldScripts["COTBS"]._adversary = this.ship;
}

this.shipDied = function(whom,why) {
		worldScripts["COTBS"]._adversary = null;
		this.ship.commsMessage("The curse of the black sunspot be upon you!");
		if (whom == player.ship) {
				missionVariables.COTBS_stage = "DESTROYED";
				missionVariables.COTBS_delay = 1;
				missionVariables.COTBS_substage = "UNKNOWN";

		} else {
				// they should be tough enough to flatten any NPC hunters or
				// traders in seconds, but...
				missionVariables.COTBS_stage = "COMPLETE"; // someone else's problem
				worldScripts.COTBS._cleanup();
		}
		worldScripts.COTBS._snoop("cotbs-story-destroyed");
		this.ship.spawn("cotbs_loot",20+Math.floor(Math.random()*10));
}

this._reactToEscortLoss = function() {
		this._lostEscorts++;
		if (this._lostEscorts == 2) {
				this.ship.commsMessage(expandDescription("[cotbs-comm-alert2]"));
		} else if (this._lostEscorts == 3) {
				this.ship.commsMessage(expandDescription("[cotbs-comm-alert3]"));
		} else if (this._lostEscorts == 4) {
				this.ship.commsMessage(expandDescription("[cotbs-comm-alert4]"));
		}
}
Scripts/cotbs-loot.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS loot ship script";

this.shipSpawned = function() {
		var amount = 20+Math.floor(Math.random()*40);
		var type = "Gold";
		if (Math.random() < 0.5) {
				type = "Gem-stones";
		}
		if (Math.random() < 0.25) {
				type = "Platinum";
		}
		this.ship.setCargo(type,amount);
		this.ship.velocity = Vector3D.randomDirection().multiply(30);
}
Scripts/cotbs-main.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS";
this.description = "Curse of the Black Sunspot";

this._escortSetupCounter = 0;

this.startUp = function() {
		if (!missionVariables.COTBS_stage) {
				missionVariables.COTBS_stage = "FUTURE";
		}
		if (missionVariables.COTBS_stage == "COMPLETE") {
				return;
		}
		this._init();
		this._systemPopulator();
}

// if the mission is complete, for efficiency this is never called
this._init = function() {

		this._soundSource = new SoundSource;
		this._soundSource.loop = false;

		this._curseTimer = null;
		this._curseSubTimer = null;
		this._curseWSTimer = null;
		this._curseFC = null;
		this._teususdiOutlands = [1,14,21,72,103,222];

		if (worldScripts["System Features: Sunspots"]) {
				// no random sunspots in this system
				if (worldScripts["System Features: Sunspots"].startUp) {
						worldScripts["System Features: Sunspots"].startUp();
				}
				worldScripts["System Features: Sunspots"].$overrides[2].push(72);
		}

		if (worldScripts.CargoTypeExtension) {
				worldScripts.CargoTypeExtension.registerPriceChange(this.name);

				this.priceChange = function(good, context) {
						if (missionVariables.COTBS_stage != "PRESENT") { return 1; }
						if (this._teususdiOutlands.indexOf(system.ID) < 0) { return 1; }
						var gtype = worldScripts.CargoTypeExtension.cargoDefinition(good,"genericType");
						if (gtype == "computers" || gtype == "machinery" || gtype == "firearms" || gtype == "luxuries") {
								return 1.2;
						}
						return 1;
				}

				this.priceGossip = function() {
						if (missionVariables.COTBS_stage != "PRESENT") { return false; }
						if (system.ID % 3 != 0) { return false; }
						return "* Piracy in the Teususdi Outland is increasing the price of industrial goods.";
				}
		}

		this.shipWillEnterWitchspace = function() {
				this._escortSetupCounter = 0;
				if (this._curseTimer) {
						this._curseTimer.stop();
						delete this._curseTimer;
				}
				if (this._curseWSTimer) {
						this._curseWSTimer.stop();
						delete this._curseWSTimer;
				}
		}

		this.shipWillExitWitchspace = function() {
				if (missionVariables.COTBS_stage == "FUTURE" && galaxyNumber == 2 && player.score >= 512 && Math.random() < 0.2) {
						missionVariables.COTBS_stage = "PRESENT";
						this._snoop("cotbs-story-begin");
				}	else if (missionVariables.COTBS_substage == "PERSIST")	{
						missionVariables.COTBS_substage = "SEARCHED";
				}

				this._systemPopulator();
		}

		this._systemPopulator = function() {
				if (galaxyNumber == 2 && missionVariables.COTBS_stage == "PRESENT") { 
						if (this._teususdiOutlands.indexOf(system.ID) >= 0) { // outlands
								var pirates = Math.floor(system.countShipsWithPrimaryRole("pirate") * 0.25+(Math.random()*0.25));
//								log("cotbs.populator","Adding "+pirates+" extra pirates");
								while (pirates > 0) {
										var gsize = 2+Math.floor(Math.random()*3);
										pirates -= gsize;
										system.addGroup("pirate",gsize,system.mainPlanet.position.multiply(0.1+(0.8*Math.random())));
//										log("cotbs.populator","Adding group of "+gsize);
								}
								var pirateships = system.shipsWithPrimaryRole("pirate");
//								log("cotbs.populator","Now has "+pirateships.length+" pirates.");
								for (var i=0;i<pirateships.length;i++) {
//										log("cotbs.populator","...upgrading "+i);
										var pship = pirateships[i];
										pship.accuracy += Math.random()*7;
										pship.bounty |= Math.floor(Math.random()*64);
										if (Math.random() < 0.8) {
												pship.aftWeapon = pship.forwardWeapon;
												if (Math.random() < 0.5) {
														if (pship.forwardWeapon == EquipmentInfo.infoForKey("EQ_WEAPON_PULSE_LASER")) {
																pship.forwardWeapon = "EQ_WEAPON_BEAM_LASER";
														}
												}
												for (var j=0; j<pship.subEntities.length;j++) {
														if (pship.subEntities[j].forwardWeapon != EquipmentInfo.infoForKey("EQ_WEAPON_NONE")) {
																pship.aftWeapon = pship.subEntities[j].forwardWeapon;
														} 
														if (Math.random() < 0.5) {
																if (pship.subEntities[j].forwardWeapon == EquipmentInfo.infoForKey("EQ_WEAPON_PULSE_LASER")) {
																		pship.subEntities[j].forwardWeapon = "EQ_WEAPON_BEAM_LASER";
																}
														}
												}
										}
								}
						}
						if (system.ID == 72) { // Enanen
								system.addShips("cotbs_leader",1,system.mainPlanet.position.multiply(0.5),10E3); // half-way along spacelane
						}
				}
				if (galaxyNumber == 2 && system.ID == 72 && missionVariables.COTBS_stage != "FUTURE") {
						var planar = system.sun.position.direction()
						var normal = planar.cross(system.mainPlanet.position.direction());
						var spotpos = system.sun.position.subtract(planar.multiply(0.5).add(normal.multiply(0.87)).direction().multiply(system.sun.radius*0.999));
						var sunspot = system.addVisualEffect("cotbs-sunspot",spotpos);

						var facing = sunspot.position.subtract(system.sun.position).direction().rotationTo(new Vector3D([0,0,1]));
						sunspot.orientation = facing;
						// add asteroid
						if (missionVariables.COTBS_stage == "PRESENT" || (missionVariables.COTBS_stage == "DESTROYED" && missionVariables.COTBS_substage != "SCOOPED" && missionVariables.COTBS_substage != "SEARCHED")) {
								var apos = spotpos.subtract(system.sun.position).direction().multiply(system.sun.radius*10).add(system.sun.position);
								system.addShips("cotbs-rock",1,apos,1);
								var guards = system.addGroup("cotbs-guard",4,apos,10E3);
						}
				} else if (missionVariables.COTBS_stage == "DESTROYED" && missionVariables.COTBS_delay == 0) {
						var spotpos = system.sun.position.add(Vector3D.randomDirection(system.sun.radius*0.999));
						var sunspot = system.addVisualEffect("cotbs-sunspot2",spotpos);

						var facing = sunspot.position.subtract(system.sun.position).direction().rotationTo(new Vector3D([0,0,1]));
						sunspot.orientation = facing;

				}
		}

		this.dayChanged = function(day) {
				if (missionVariables.COTBS_stage == "DESTROYED") {
						if (missionVariables.COTBS_delay && missionVariables.COTBS_delay > 0) {
								missionVariables.COTBS_delay--;
						}
				}
		}

		this.shipLaunchedFromStation = this.shipExitedWitchspace = function() {
				if (missionVariables.COTBS_stage == "DESTROYED") {
						if (this._curseTimer) {
								this._curseTimer.stop();
								delete this._curseTimer;
						}
						if (missionVariables.COTBS_delay <= 0) {
								var delay = 80+(Math.random()*40);
								if (player.ship.equipmentStatus("EQ_DCN") == "EQUIPMENT_OK" || player.ship.equipmentStatus("EQ_REPAIRBOTS_CONTROLLER") == "EQUIPMENT_OK") {
										delay /= 3;
								}
								this._curseTimer = new Timer(this,this._applyCurseDamage,30+(Math.random()*10),delay);
								if (missionVariables.COTBS_sneaky) {
										delete missionVariables.COTBS_sneaky;
										this._taunt("[cotbs-sneaky-taunt]");
								}
						} 
				}
		}

		this._knowCurse = function() {
				if (missionVariables.COTBS_substage == "UNKNOWN" && Math.random() < 0.25) {
						missionVariables.COTBS_substage = "THATSODD";
				}
		}

		this._forceKnowCurse = function() {
				missionVariables.COTBS_substage = "THATSODD";
		}


		this._applyCurseDamage = function() {
				if (player.ship.dockedStation || missionVariables.COTBS_delay > 0) {
						return;
				}
				this._forceApplyCurseDamage();
		}

		this._forceApplyCurseDamage = function() {
				var choice = Math.random();
				if (choice < 0.33) { // 1/3 system damage
						do {
								var damaged = player.ship.takeInternalDamage();
						} while (!damaged);
						this._soundSource.sound = "[player-direct-hit]";
						this._soundSource.play();
						this._knowCurse();
				} else if (choice < 0.5) { // 1/6 display trouble
						this._soundSource.sound = "[@warning]";
						this._soundSource.play();
						system.addVisualEffect("cotbs-error",player.ship.position);
						this._knowCurse();
				} else if (choice < 0.66) { // 1/6 HUD trouble
						this._soundSource.sound = "[@warning]";
						this._soundSource.play();
						player.ship.hudHidden = true;
						this._curseSubTimer = new Timer(this,this._restoreHud,Math.random()*15);
						this._knowCurse();
				} else if (choice < 0.70 && player.ship.fireMissile()) { // ~1/20 missile fire, if locked on
						this._knowCurse();
				} else if (choice < 0.75) { // 1/20 shield drain (~1/10 if no missile lock)
						this._soundSource.sound = "[@warning]";
						this._soundSource.play();
						player.consoleMessage("Warning: shield charge imbalance! Emergency restart of shield system in progress.",5);
						if (this._curseFC) {
								removeFrameCallback(this._curseFC);
								delete this._curseFC;
						}
						this._curseFC = addFrameCallback(this._shieldImbalance);
						this._knowCurse();

				} else if (choice < 0.9) { // 3/20 taunt
						this._soundSource.sound = "[@beep]";
						this._soundSource.play();
						this._taunt("[cotbs-taunt]");
				} else if (player.ship.fuel > 0) { // 1/10 fuel leak
						this._soundSource.sound = "[fuel-leak]";
						this._soundSource.play();
						player.consoleMessage("Warning: fuel leak!");
						player.ship.fuelLeakRate = 1;
						this._knowCurse();

				}
		}

		this._taunt = function(msg) {
				if (worldScripts["randomshipnames"]) {
						player.commsMessage(expandDescription("Python: Adversarial:\n  "+msg));
				} else {
						player.commsMessage(expandDescription("Python:\n  "+msg));
				}
		}

		this._restoreHud = function() {
				player.ship.hudHidden = false;
		}

		this._shieldImbalance = function(delta) {
				var rate = delta*32;
				player.ship.aftShield -= rate;
				player.ship.forwardShield -= rate;
				if ((player.ship.forwardShield < 1 && player.ship.aftShield < 1) || player.ship.dockedStation) {
						// shields drained
						removeFrameCallback(worldScripts.COTBS._curseFC);
						delete worldScripts.COTBS._curseFC;
				}
		}

		this.playerStartedJumpCountdown = function(type, seconds)	{
				if (missionVariables.COTBS_stage != "DESTROYED") { return; }
				if (type == "galactic") {
						this._knowCurse();
						player.ship.setEquipmentStatus("EQ_GAL_DRIVE","EQUIPMENT_DAMAGED");
						this._soundSource.sound = "[player-direct-hit]";
						this._soundSource.play();
						player.consoleMessage("Warning! Galactic hyperdrive miscalibration detected. Disabling device until it can be serviced.",8);
				} else if (system.ID != 72 && missionVariables.COTBS_delay <= 0) {
						if (this._curseWSTimer) {
								this._curseWSTimer.stop();
								delete this._curseWSTimer;
						}
						var curdist = System.infoForSystem(galaxyNumber,72).distanceToSystem(System.infoForSystem(galaxyNumber,system.ID));
						var newdist = System.infoForSystem(galaxyNumber,72).distanceToSystem(System.infoForSystem(galaxyNumber,player.ship.targetSystem));
						if (newdist > curdist) {
								// trying to get away, are you?
								this._curseWSTimer = new Timer(this,this._interruptJump,seconds-0.1);
								player.consoleMessage("The power of the black sunspot compels you, Commander...");
						}
				}
		}

		this.playerCancelledJumpCountdown = this.playerJumpFailed = function() {
				if (this._curseWSTimer) {
						this._curseWSTimer.stop();
						delete this._curseWSTimer;
				}
		}

		this._interruptJump = function() {
				var route = System.infoForSystem(galaxyNumber,system.ID).routeToSystem(System.infoForSystem(galaxyNumber,72));
				if (route && route.route) {
						var newdest = route.route[1];
						var cpf = player.ship.fuel;
						cpf -= System.infoForSystem(galaxyNumber,system.ID).distanceToSystem(System.infoForSystem(galaxyNumber,newdest));
						if (cpf >= 0) {
								var jumper = system.addShips("cotbs_misjumper",1,player.ship.position.add(player.ship.vectorForward.multiply(player.ship.collisionRadius+100)),0)[0];
								if (jumper.exitSystem(newdest)) {
										this._soundSource.sound = "[witchdrive-malfunction]";
										this._soundSource.play();
										this._forceKnowCurse();
										player.ship.fuel = cpf;
										player.ship.position = jumper.position;
										player.ship.velocity = [0,0,0];
								}
								jumper.remove(true);
						}
				}						

		}

		this.alertConditionChanged = function(newc,oldc) {
				if (missionVariables.COTBS_stage != "DESTROYED" || missionVariables.COTBS_delay > 0) { return; }
				if (newc != 3) {
						var objs = system.shipsWithPrimaryRole("cotbs-ghost");
						for (var i=0; i<objs.length; i++) {
								objs[i].remove();
						}
				} else {
						this._knowCurse();
						system.addShips("cotbs-ghost",2+Math.floor(Math.random()*3),player.ship.position,10E3);
				}
		}

		this._snoop = function(key) {
				if (!worldScripts.snoopers) {
						return;
				}
				var obj = {
						ID: this.name,
						Message: expandDescription("["+key+"]"),
						Agency: 1,
						Model: "[python-blackdog]",
						Priority: 3
				};

				worldScripts.snoopers.insertNews(obj);
		}

		this.playerBoughtNewShip = this.shipLaunchedEscapePod = function() {
				if (missionVariables.COTBS_stage == "DESTROYED") {
						missionVariables.COTBS_delay += 3;
						missionVariables.COTBS_sneaky = 1;
				}
		}

		this.missionScreenOpportunity = function() {
				if (missionVariables.COTBS_stage != "DESTROYED") { return; }
				if (player.ship.dockedStation != system.mainStation) { return; }
				if (system.info.techlevel < 8) { // region except Teususdi
						if (missionVariables.COTBS_substage == "THATSODD") {
								missionVariables.COTBS_substage = "NEEDTL9";
								this._shipyardAnnouncement1();
						}
				} else if (system.info.techlevel < 12) { // not Cedile or Bixein
						if (missionVariables.COTBS_substage == "THATSODD" || missionVariables.COTBS_substage == "NEEDTL9") {
								missionVariables.COTBS_substage = "NEEDTL13";
								this._shipyardAnnouncement2();
						}
				} else { // Cedile or Bixein, probably
						if (missionVariables.COTBS_substage == "THATSODD" || missionVariables.COTBS_substage == "NEEDTL9" || missionVariables.COTBS_substage == "NEEDTL13" || missionVariables.COTBS_substage == "SEARCHED") {
								missionVariables.COTBS_cost = Math.floor(player.ship.price / 5);
								this._shipyardAnnouncement3();
						} else if (missionVariables.COTBS_substage == "SCOOPED") {
								this._shipyardAnnouncement4();
						}
				}
		}

		this._shipyardAnnouncementTemplate = function() {
				return {
						title: "%H shipyard",
						model: "["+player.ship.shipKey+"]"
				}
		}
		
		this._shipyardAnnouncement1 = function() {
				var param = this._shipyardAnnouncementTemplate;
				param.messageKey = "cotbs-sya1";
				mission.runScreen(param);
		}

		this._shipyardAnnouncement2 = function() {
				var param = this._shipyardAnnouncementTemplate;
				param.messageKey = "cotbs-sya2";
				mission.runScreen(param);
		}

		this._shipyardAnnouncement3 = function() {
				var param = this._shipyardAnnouncementTemplate;
				param.messageKey = "cotbs-sya3";
				param.choicesKey = "cotbs-sya3-choices";
				mission.runScreen(param, this._shipyardAnnouncement3a);
		}

		this._shipyardAnnouncement3a = function(choice) {
				if (choice == "01_TRANS") {
						if (missionVariables.COTBS_substage == "SEARCHED") {
								missionVariables.COTBS_substage = "PERSIST";
						} else {
								missionVariables.COTBS_substage = "SEARCHING";
								mission.setInstructionsKey("cotbs-sya3-mission");
								mission.markSystem({system:72,name:this.name,markerColor:"cyanColor"},
																	 {system:22,name:this.name,markerColor:"cyanColor",markerShape:"MARKER_DIAMOND"},
																	 {system:79,name:this.name,markerColor:"cyanColor",markerShape:"MARKER_DIAMOND"});
						}

				} else {
						missionVariables.COTBS_stage = "COMPLETED";
						if (missionVariables.COTBS_cost > player.credits)
						{
								missionVariables.COTBS_cost = player.credits;
								clock.addSeconds(86400*2);
								player.ship.removeEquipment("EQ_NAVAL_ENERGY_UNIT");
								player.ship.removeEquipment("EQ_NAVAL_SHIELD_BOOSTER");
								player.ship.removeEquipment("EQ_SHIELD_BOOSTER");
								var param = this._shipyardAnnouncementTemplate;
								param.message = "\"You didn't have enough money in your account to pay for all the new electronics, so we've had to remove some of the more expensive kit entirely. We can put it back in when you've got some cash again.\"";
								mission.runScreen(param);
						}
						player.credits -= missionVariables.COTBS_cost;

						this._cleanup();
				}
		}

		this._shipyardAnnouncement4 = function() {
				var param = this._shipyardAnnouncementTemplate;
				param.messageKey = "cotbs-sya4";
				mission.runScreen(param);
				player.credits += 2500;
				clock.addSeconds(3600*5);
				missionVariables.COTBS_stage = "COMPLETED";
			
				this._cleanup();
		}


		this.playerBoughtEquipment = function(eq) {
				if (eq == "EQ_COTBS_RESTORE") {
						missionVariables.COTBS_delay = 3;
						player.ship.removeEquipment("EQ_COTBS_RESTORE");
				}
		}

		this.guiScreenChanged = function(to,from) {
				if (missionVariables.COTBS_stage != "DESTROYED" || missionVariables.COTBS_delay > 0 || !player.ship.dockedStation) {
						return;
				}
				var choice = Math.random();
				if (choice < 0.03) {
						while (player.ship.cargoSpaceAvailable > 0 && player.ship.dockedStation.market.narcotics.quantity > 0 && player.credits > player.ship.dockedStation.market.narcotics.price / 10) {
								player.credits -= player.ship.dockedStation.market.narcotics.price / 10;
								player.ship.manifest.narcotics++;
								player.ship.dockedStation.setMarketQuantity("narcotics",player.ship.dockedStation.market.narcotics.quantity-1);
						}
				} else if (choice < 0.06) {
						player.ship.awardEquipment("EQ_MISSILE_REMOVAL");
						player.credits -= 20;
				}
		}

		this.shipWillDockWithStation = function(station) {
				if (station.isMainStation && clock.days % 10 == system.ID % 10 && galaxyNumber == 2)	{
//						log(this.name,"Interface addition?");
						station.setInterface(this.name,{
								title: "Piracy Warning",
								category: expandDescription("[interfaces-category-news]"),
								summary: "Galcop Level 3 Warning: A large and well-equipped pirate band is attacking shipping in the Teususdi Outland. Caution is advised. More details are available.",
								callback: function() {
										mission.runScreen({"titleKey": "cotbs-news1-title",
																			 "messageKey": "cotbs-news1-message",
																			 "model": "cotbs_leader",
																			 "allowInterrupt": true,
																			 "exitScreen": "GUI_SCREEN_INTERFACES"});
								}});
				}
				
		}


		this._cleanup = function() {
				mission.unmarkSystem({system:72,name:this.name},
														 {system:22,name:this.name},
														 {system:79,name:this.name});
				mission.setInstructions(null);

				delete missionVariables.COTBS_substage;
				delete missionVariables.COTBS_delay;
				delete missionVariables.COTBS_sneaky;
				delete missionVariables.COTBS_cost;
				if (this._curseTimer) {
						this._curseTimer.stop();
						delete this._curseTimer;
				}
		}


		// call this on startup to add the news, if needed
		this.shipWillDockWithStation(player.ship.dockedStation);
		

} // end this._init
Scripts/cotbs-rock.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS asteroid";

this._transmitter = true;
this._transmitterEntity = null;
this._selfDestruct = 0;

this._triangulation = 0;

this._doSelfDestruct = function() {
		// shutdown
		this._selfDestruct++;
		if (this._selfDestruct == 1) {
				player.consoleMessage("Warning! Energy surge detected!",10);
				this.ship.scannerDisplayColor1 = "redColor";
				this.ship.scannerDisplayColor2 = "yellowColor";
		}
		if (this._selfDestruct == 15) { // ~75 seconds
				this.ship.dealEnergyDamage(255,5000,0);
				this.ship.explode();
		}
}

this._transmitCurse = function() {
		if (!this._transmitter) {
				if (this.ship.subEntities.length == 0) {
						this._doSelfDestruct();
						this._doSelfDestruct();
						this._doSelfDestruct();
				}
				return;
		}
		if (!player.ship.position) {
				return;
		}
		var distance = this.ship.position.subtract(player.ship.position).magnitude();
		if (distance < 51200 && Math.random() < 0.3 && missionVariables.COTBS_stage == "DESTROYED") {
				worldScripts["COTBS"]._forceApplyCurseDamage();
		} else if (missionVariables.COTBS_delay == 0 && missionVariables.COTBS_stage == "DESTROYED" && Math.random() < 0.02) {
				worldScripts["COTBS"]._applyCurseDamage();
				this._triangulation++;
				if (this._triangulation > 10) {
						this._transmitterEntity.beaconCode = "Transmission Source";
				}
		}
		
		if (distance > 30000) {
				this._transmitterEntity.position = this._transmitterPosition();
				this._transmitterEntity.orientation = this.ship.orientation;
		}

		if (this.ship.subEntities.length == 0) {
				this._doSelfDestruct();
		}

}

this._transmitterPosition = function() {
		return position = this.ship.position.add(
				this.ship.vectorForward.multiply(632)).add(
						this.ship.vectorUp.multiply(-240)).add(
								this.ship.vectorRight.multiply(240));
}

this.shipSpawned = function() {
		this._transmitterEntity = system.addShips("cotbs-transmitter",1,this._transmitterPosition(),0)[0];
		this._transmitterEntity.script._owner = this.ship;
		this._transmitterEntity.orientation = this.ship.orientation;
}

this.shipTakingDamage = function(amount,whom,type) {
		if (type == "scrape damage") {
				this.ship.energy += amount;
				this.ship.velocity = new Vector3D([0,0,0]);
				if (this._transmitter) {
						this._transmitterEntity.position = this._transmitterPosition();
						this._transmitterEntity.orientation = this.ship.orientation;
				}
		}
}

this.shipDied = function() {
		if (this._transmitter) {
				this._transmitterEntity.explode();
		}
		var fragments = this.ship.spawn("asteroid",15);
		for (var i=0;i<fragments.length;i++) {
				fragments[i].explode();
		}
}
Scripts/cotbs-transmitter.js
this.author      = "cim"; 
this.copyright   = "� 2011-2014 cim."; 
this.licence = "CC-BY-SA 3.0";
this.version     = "1.0.2"; 
this.name = "COTBS transmitter script";

this.shipTakingDamage = function(amount,whom,type) {
		if (type == "scrape damage") {
				this.ship.energy += amount;
				this.ship.velocity = new Vector3D([0,0,0]);
		}
}

this.shipDied = function() {
		this._owner.script._transmitter = false;
		player.consoleMessage("Transmitter is no longer detectable",10);
		worldScripts.COTBS._taunt("[cotbs-oops-taunt]");
		if (missionVariables.COTBS_stage == "DESTROYED") {
				missionVariables.COTBS_substage = "SEARCHED";
		}
}

this.shipWasScooped = function(scooper) {
		this._owner.script._transmitter = false;
		if (missionVariables.COTBS_stage == "DESTROYED") {
				if (scooper != player.ship) {
						missionVariables.COTBS_substage = "SEARCHED";
				} else {
						missionVariables.COTBS_substage = "SCOOPED";
				}
		}
}