Back to Index Page generated: Jun 13, 2026, 7:54:51 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
Dependent Expansions
  • oolite.oxp.Norby.Addons_for_Beginners:1.5
  • 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

    Relationships Diagram

    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 );
     	});
    }