Back to Index Page generated: Nov 12, 2024, 11:02:04 PM

Expansion The Collector

Content

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Find the rich man who collect historical spaceships and do the jobs he offer. Choose wisely, your choices will form the story. Find the rich man who collect historical spaceships and do the jobs he offer. Choose wisely, your choices will form the story.
Identifier oolite.oxp.Norby.TheCollector oolite.oxp.Norby.TheCollector
Title The Collector The Collector
Category Missions Missions
Author mossfoot, Norby mossfoot, Norby
Version 0.4 0.4
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Information URL http://wiki.alioth.net/index.php/TheCollector n/a
Download URL https://wiki.alioth.net/img_auth.php/1/11/TheCollector.0.4.oxz n/a
License CC BY-NC-SA 4 CC BY-NC-SA 4
File Size n/a
Upload date 1610873231

Documentation

Also read http://wiki.alioth.net/index.php/The%20Collector

TheCollector_readme.txt

The Collector mission pack

Somewhere in the galaxy there is a rich man who love his collection of historical spaceships.

Your first mission is to find him, then do all the jobs what he offer from easy to hard and your reward will be higher than you think.

No more info here due to everything else is spoiler. You should not dig into the included files if you do not want to cheat but enjoy a great play within the game.


Instructions:

Do not unzip the .oxz file, just move into the AddOns folder of your Oolite installation.

License:

This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License version 4.0.
If you are re-using any piece of this OXP, please let me know by sending an e-mail to norbylite@gmail.com.

The station is borrowed from Shady Sungs OXP by Christoph Schmucker (aka Sung Mehta) and Michael Francis (aka Ancient Dwarven Chaos Knight - ADCK). Shader files from neolites by Simon B.
The gate near the station comes from Ring Racer OXP by Thargoid.
The experimental Cobra is made by Paradox.
The backround of mission screens is use images from BGS OXP.

Changelog:
 2014.11.02. v0.4  Some help in finding the station.
 2014.09.03. v0.3  Galaxy-independent start.
 2014.09.02. v0.2  Stage 1-7 done.
 2014.08.16. v0.1  First text files.

Equipment

This expansion declares no equipment.

Ships

Name
Arc Detail
The Collector's Station
Docking Slit (horizontal)
The Collector's target beacon
The Collector's Buoy
The Collector's Gate

Models

This expansion declares no models.

Scripts

Path
Scripts/thecollector.js
"use strict";
this.name	= "thecollector";
this.author	= "mossfoot, Norby";
this.copyright	= "2014 Norby";
this.description= "Missions from The Collector";
this.version	= "0.4";
this.licence	= "CC BY-NC-SA 4.0";

this.$TheCollectorBuoyDistance = 20000; //distance between two buoys before the collector's station
this.$TheCollectorMinBuoys = 5; //minimum how many buoys created

//internal properties, should not touch
this.$TheCollectorMissionStage = 0; //Where the player stay in the missions
this.$TheCollectorMissionSub = null; //Where the player stay within a MissionStage
this.$TheCollectorMSO = true; //flag for the first missionScreenOpportunity after landing
this.$TheCollectorStation = null; //store the station to detect if spawned
this.$TheCollectorStationKey = "thecollector_adck_coriolis-station"; //dataKey of collector's station
this.$TheCollectorTimes = []; //When the stages started

//worldscript events
this.startUp = function() {
	this.$TheCollectorMissionStage = missionVariables.$TheCollectorMissionStage;
	if(!(this.$TheCollectorMissionStage)) this.$TheCollectorMissionStage = 0;
	if(this.$TheCollectorMissionStage > 0) this.$TheCollectorInstructions(0); //set the F5F5 info only
	this.$TheCollectorTimes = JSON.parse(missionVariables.$TheCollectorTimes); //destringify
	if( !this.$TheCollectorTimes ) this.$TheCollectorTimes = []; //When the stages started

	this.$TheCollectorSound1 = new SoundSource;
	if( worldScripts["BGS-M"] ) this.$TheCollectorSound1.sound = "bgs-c_buy.ogg";
	else this.$TheCollectorSound1.sound = "buy.ogg";
	this.$TheCollectorSound1.loop = false;
	this.$TheCollectorSound1.repeatCount = 1;
}

this.systemWillPopulate = function() { //for Oolite 1.79 and above
	this.$TheCollectorCreateStation(true);
}

this.missionScreenOpportunity = function() {
	var p = player.ship;
//	log(this.name, p.dockedStation);//debug
	if( p && p.docked && this.$TheCollectorMSO && system ) {
		this.$TheCollectorMSO = false; //only in the first missionScreenOpportunity after landing

		if( this.$TheCollectorMissionStage < 2 && Math.random() < 0.1 ) { //10% chance
			this.$TheCollectorInstructions( 1 ); //galaxy hint talk until stage 2
			return;
		} else if( galaxyNumber > 0 ) return; //nothing more in other galaxies

		if( p.dockedStation == system.mainStation ) {
			if( system.ID == 119 && this.$TheCollectorMissionStage < 4 //Rarere
				&& p.dockedStation.dataKey != this.$TheCollectorStationKey ) {
				this.$TheCollectorInstructions( 3 ); //local rumor until stage 4
			} else if( system.ID == 160 && ( this.$TheCollectorMissionStage == 5  //Leritean
				|| this.$TheCollectorMissionStage == 6 ) ) {
				var h = 0; //elapsed time in hours
				var s = this.$TheCollectorTimes[5];
				if( s > 0 ) h = ( clock.seconds - s ) / 3600;
				var tt = Math.ceil( h * 10 ) / 10 + " hours";
//				log(this.name, tct+" "+h+" "+s);//debug
				if( s && h < 63 ) { //arrived in time (63h)
					this.$TheCollectorInstructions( 7, tt );
				} else this.$TheCollectorInstructions( 6, tt ); //too late
			} else if( system.ID == 65 && this.$TheCollectorMissionStage < -1 ) { //Sori
				this.$TheCollectorInstructions( -1 ); //todo: a ship is delivered
			} else if( system.ID == 66 && this.$TheCollectorMissionStage < -1 ) { //Aate
				this.$TheCollectorInstructions( -1 ); //todo: a ship is delivered
			}
		} else if( p.dockedStation.dataKey == this.$TheCollectorStationKey ) {
			if( this.$TheCollectorMissionStage < 5 ) { //offer Leritean mission
				this.$TheCollectorInstructions( 4 );
			} else if( this.$TheCollectorMissionStage == 6 ) { //Leritean mission failed
				this.$TheCollectorInstructions( 4 ); //back to stage 4
			} else if( this.$TheCollectorMissionStage == 7 ) { //Leritean mission done
				this.$TheCollectorInstructions( 8 );
			}
		}
	}
}

this.playerWillSaveGame = function( message ) {
	missionVariables.$TheCollectorMissionStage = this.$TheCollectorMissionStage;
	missionVariables.$TheCollectorTimes = JSON.stringify(this.$TheCollectorTimes);
}

this.shipWillDockWithStation = function( station ) {
	this.$TheCollectorMSO = true; //flag for the first missionScreenOpportunity after landing
}

this.shipWillEnterWitchspace = function() {
	this.$TheCollectorStation = null; //clear the station storage
}

this.shipWillExitWitchspace = function() { //use this event due to shipExitedWitchspace is not called for player ship
	this.$TheCollectorCreateStation();
	if( galaxyNumber == 0 && system ) {
		if( this.$TheCollectorMissionStage > 3 //trap setup after met Mr. Smith
			&& ( system.ID == 122 || system.ID == 181 ) ) { //in Bibe and Bioris
			var n = Math.floor( 1 + 3 * Math.random() ); //1-3 attackers
			var s = system.addShips("pirate", n, player.ship.position, 25000);
			if( s ) for(var i=0; i < s.length; i++ ) {
				if( s[i] ) {
					s[i].setAI("thecollector_trapAI.plist");
					s[i].awardEquipment("EQ_FUEL_INJECTION");
					s[i].fuel = 7;
					s[i].target = player.ship;
				}
			}
		}
	}
}

this.shipWillLaunchFromStation = function( station ) {
	this.$TheCollectorCreateStation(false); //for Oolite v1.77
}

//TheCollector methods
this.$TheCollectorCreateStation = function( populator ) {
	if( galaxyNumber == 0 && system && system.ID == 119 && !this.$TheCollectorStation ) {
		var dist = 1656000; //how far is the collector's station in the main station to sun lane
		var mpos = system.mainStation.position;
		var msvector = system.sun.position.subtract(mpos); //mainStation to current sun vector
		var mlen = (this.$TheCollectorMinBuoys+1) * this.$TheCollectorBuoyDistance; //min. length of the buoy line
		var apos = mpos.add( msvector.direction().multiply( dist - mlen ) ); //asteroids position
//		var p = system.sun.position; log(this.name, "Sunpos:"+p.x+" "+p.y+" "+p.z);//get orig. sunpos
//		var osp = Vector3D(-1679104.3673211336, -1513520.786781907, -43617.31031984091);//original sun
//		var movector = osp.subtract(mpos); //mainStation to original sun vector
//		var spos = mpos.add( movector.direction().multiply( dist ) ) //station position
//			.add( mpos.direction().multiply( 40000 ) );
//		log(this.name, "spos:"+spos.x+" "+spos.y+" "+spos.z);//get the following coordinates
		var spos = Vector3D(-1219441.8670473576, -1134372.290313594, 113154.84710425357); //fix for sure

		if(populator) { //for Oolite 1.79 and above
			system.setPopulator("thecollector_station", {
				callback: function(pos) {
					this.$TheCollectorCreateSGB( apos, spos );
				}.bind(this),
				location: "COORDINATES",
				coordinates: spos,
				deterministic: true
			});
			system.setPopulator("thecollector_asteroids", {
				callback: function(pos) {
					this.$TheCollectorCreateAF( apos, spos );
				}.bind(this),
				location: "COORDINATES",
				coordinates: spos
			});
		} else { //for Oolite v1.77
			this.$TheCollectorCreateSGB( apos, spos ); //create station, gate and buoys
			//create asteroid fields after(!) buoys to do not prevent an aseroid the creation of buoys
			this.$TheCollectorCreateAF( apos, spos );
		}
	}
}

this.$TheCollectorCreateAF = function( apos, spos ) {//create asteroid fields
	//call after buoys to do not prevent an aseroid the creation of a buoy
	system.addShips("asteroid", 32, apos, 30000);
	var v = apos.subtract(spos);
	system.addShips("asteroid", 64, spos.add(v.direction().multiply(v.magnitude()/2)), 40000);
	system.addShips("asteroid", 32, spos, 30000);
}

this.$TheCollectorCreateSGB = function( apos, spos ) { //create station, gate and buoys
	var s = system.addShips("[" + this.$TheCollectorStationKey + "]", 1, spos, 0);
	var v = apos.subtract(spos); //targetVector from the collector's station to the asteroids
	var bd = this.$TheCollectorBuoyDistance; //buoy distance
	var d = v.direction(); //targetVector from the collector's station to the asteroids
	if(s) this.$TheCollectorStation = s[0];
	if( this.$TheCollectorStation ) { //rotate to the asteroids
		var a = this.$TheCollectorStation.heading.angleTo(d); //angle
		var c = this.$TheCollectorStation.heading.cross(d).direction(); //cross
		this.$TheCollectorStation.orientation = this.$TheCollectorStation.orientation.rotate(c, -a);

		var gpos = spos.add( d.multiply( this.$TheCollectorBuoyDistance ) ); //gate position
		var r = system.addShips("thecollector_gate", 1, gpos, 0);
		if(r && r[0]) r[0].orientation = this.$TheCollectorStation.orientation;
		else  log(this.name, "Warning: The Collector's Gate is not created");
	} else log(this.name, "Error: The Collector's Station is not created!");

	//the trick of the buoy line is if the sun is in an unortodox position then make a very long guide line
	var l = Math.round((v.magnitude())/this.$TheCollectorBuoyDistance); //length of the buoy line
	for( var i = 2; i <= l; i++ ) { //create buoys along the line except the nearest to the station (the gate)
		var p = spos.add( d.multiply( this.$TheCollectorBuoyDistance * i ) ); //buoy position
		var b = system.addShips("thecollector_buoy", 1, p, 0);
		if(b && b[0]) b[0].displayName += " "+(i-1);
		if( l > 500 && i == 496 ) i = l - 5; //do not make too much buoys
	}
	if( l > 500 ) {
		if( r && r[0] ) {
			r[0].beaconCode = r[0].name; //last resort: the gate is a beacon
			log(this.name, "Warning: The Collector's Station is too far so the gate is the beacon");
		} else log(this.name, "Error: The Collector's Station is too far and the gate is not created");
	}
}

this.$TheCollectorInstructions = function( stage, tt ) {
	var t = worldScripts.thecollector;
	if( stage > 0 ) { //step to the new stage and display missionscreen
		t.$TheCollectorMissionStage = stage;
		t.$TheCollectorMissionSub = "_"; //start
		t.$TheCollectorMissionScreen(t, tt);
		if(msg) player.commsMessage(msg, 10);
	} //if stage is 0 then set the F5F5 message to the current missionstage and do not change it
	var msg = expandMissionText(t.name+t.$TheCollectorMissionStage);
	if( msg ) {
		mission.setInstructions( msg+" (#"+t.$TheCollectorMissionStage+")", t.name);//show in F5-F5 screen
		t.$TheCollectorTimes[t.$TheCollectorMissionStage] = clock.seconds; //save the start of the stage
	}
}

this.$TheCollectorMissionScreen = function( t, tt ) {
	var mt = t.$TheCollectorMissionStage+t.$TheCollectorMissionSub;
	var todo = expandMissionText(t.name+t.$TheCollectorMissionStage);
	var m = expandMissionText(t.name+mt, {thecollectortime: tt, thecollectortodo: todo});
	if( !m || !(m.length>0) ) return;
	var c = [];
	var cr = 0;
	for( var j = 1; j < 10; j++ ) {
		var mj = t.name+mt+j;
		var txt = null;
		cr = expandMissionText(mj+"cr"); //must pay for this choice?
		if( !cr || !(cr>0) || player.credits >= cr ) //do not show if not enough money
			txt = expandMissionText(mj);
		if( txt && txt.length > 0 ) c[ j ] = txt;
	}
	if( c.length < 1 ) c[0] = "OK"; //default choice if none is defined
//	log(t.name, "Stage #"+mt+" c.length: "+c.length+" "+c[0]);//debug
	mission.runScreen({
			title: "The Collector (#"+t.$TheCollectorMissionStage+")",
			message: m,
			background: "thecollector_background.png",
			exitScreen: "GUI_SCREEN_MANIFEST",
			choices: { "_0" : c[0],
				"_1" : c[1],
				"_2" : c[2],
				"_3" : c[3],
				"_4" : c[4],
				"_5" : c[5],
				"_6" : c[6],
				"_7" : c[7],
				"_8" : c[8],
				"_9" : c[9]
			}
	},function( choice ) {
			var o = 0;
			if( choice ) o = choice.substr(1); //cut starting "_"
			var cr = expandMissionText(t.name+mt+o+"cr"); //must pay for this choice?
			var r = expandMissionText(t.name+mt+o+"redir");
			var redir = false;
			if( r && r.length > 0 ) {
				redir = true;
				if( 1*r == r ) { //redir to a single number mean new stage
					t.$TheCollectorMissionStage = r;
					t.$TheCollectorInstructions(0);
					t.$TheCollectorMissionSub = "_"; //begin of a new stage
				} else if( r.indexOf("_") == 0 ) { //redir begin with underscore mean new sub within this stage
					t.$TheCollectorMissionSub = r + "_";
				} else { //redir into a new stage lower than the first subpage
					var i = r.indexOf("_");
					t.$TheCollectorMissionStage = r.substr(0, i);
					t.$TheCollectorInstructions(0);
					t.$TheCollectorMissionSub = r.substr(i) + "_";
//		   			log(t.name, r+" "+t.$TheCollectorMissionStage+" "+t.$TheCollectorMissionSub);//debug
				}
			}
   			log(t.name, "Stage:"+mt+" choice:"+o+" "+c[o]+" cr:"+cr+" redir:"+r);//debug
			if( o > 0 ) {
				if( cr > 0 ) { //must pay for this choice!
					player.credits -= cr;
					t.$TheCollectorSound1.play();
				}
				if( !redir ) t.$TheCollectorMissionSub += o + "_";
				t.$TheCollectorMissionScreen(t); //recursive, so do not use too much level
			} else return; //exit
//			if( !isValidFrameCallback( h.$HUDSelectorFCB2 ) )
//				h.$HUDSelectorFCB2 = addFrameCallback( h.$HUDSelector_FCB2 );
 	});
}