Back to Index Page generated: Jun 13, 2026, 7:54:50 PM

Expansion Asteroid Storm

Content

Warnings

  1. License not specified
  2. Unknown key 'licence' at https://wiki.alioth.net/img_auth.php/2/2a/AsteroidStorm_4.3.oxz!manifest.plist

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description This OXP adds more models and textures for asteroids to the game and as bonus one mission. This OXP adds more models and textures for asteroids to the game and as bonus one mission.
Identifier oolite.oxp.LittleBear.AsteroidStorm oolite.oxp.LittleBear.AsteroidStorm
Title Asteroid Storm Asteroid Storm
Category Ambience Ambience
Author Little Bear, Eric Walch Little Bear, Eric Walch
Version 4.3 4.3
Tags Asteroids, Mission Asteroids, Mission
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Dependent Expansions
  • oolite.oxp.Norby.Ambience_Collection:1.3
  • Information URL http://wiki.alioth.net/index.php/Asteroid_Storm n/a
    Download URL https://wiki.alioth.net/img_auth.php/2/2a/AsteroidStorm_4.3.oxz n/a
    License
    File Size n/a
    Upload date 1610873257

    Relationships Diagram

    Documentation

    Also read http://wiki.alioth.net/index.php/Asteroid%20Storm

    asteroidstorm_readme.txt

    			    	  Asteroid Storm OXP - V4.03
    			        -----------------------------
    
    			(New Asteroid Models and Textures by "Charlie")
    			         (Scripting by "LittleBear")
    			    (Further scripting for 3.4+  by "Kaks")
    				(Original JS script by "Dajt")
    			     (Galatic Police Image by "Wombat")
                                (Retextured all asteroids by "Eric")
    
    
    With this version all of Charlies asteroids now appear, but in a much improved mesh and with normalmapping.
    
    ------------------------------------------------------------------------------------------------
    
    An addon for Oolite by Giles Williams.
    
    Based on "Elite" by Ian Bell and David Braben.
    
    Version 4.03 - compatible with Oolite 1.74 and higher. 
    
    
    -------------------------------------------------------------------------------------------------
    
    Overview
    --------
    
    This OXP adds more models and textures for Asteroids to the game. All the new asteroids were
    modeled and textured by "Charlie", based upon asteroids in the Real Life Sol System. Some are
    really big and will be marked by your ID computer as a "Large Asteroid"!
    
    In the native game there are only two types of asteroid. If you play with this OXP installed then
    there is more variety to the shapes and sizes of the asteroids you encounter as they have 15
    different shapes and sizes. The chance and number of boulders formed when an asteroid is
    destroyed also varies for each type of asteroid.
    
    The OXP also adds an asteroid related mission, well suited to a novice commander in Galaxy 1.
    
    You are docked at a station near Lave, in a system well known to suffer from asteroid storms.
    Sure enough, as you drop off your cargo, you hear the sound of small asteroids glancing off
    the Station's shields. Suddenly all hell breaks loose, Commanders running for their ships,
    leaving their cargo behind!
    
    A Large Asteroid has been detected approaching the Station. It is so massive that if it strikes,
    destruction of the mighty Dodec is certain. Will you stay and help or get out of Dodge?
    
    The mission has three possible endings depending on your actions.
    
    The mission will trigger when you are docked at a certain system within 7 light years of Lave
    and are ranked at least "Above Average". I won't tell you the name of the system, but you may
    find that checking your F7 screen gives a clue!
    
    This is intended to be a fairly easy mission, but a bit of fun!
    
    Updates from V1.0
    -----------------
    
    1) Version 2.0 adds the models and textures for Charlie's asteroids to the game generally.
    
    2) A code optimisation to remove the System's station permanently, if it is destroyed.
       (The station is now removed by setting the System's station to "none".)
    
    Updates from V2.0
    -----------------
    
    1) Texture case names fixed. No problem on Windows or Mac, but the old version had case
    sensitivity bugs, which caused a problem on Unix.
    
    2) Eric's mission clash prevention code added, to ensure this OXP doesn't clash with any other
    OXPs that display mission briefing screens.
    
    3) The "Large Asteroids" added to the Universe generally have a higher energy value, making
    them more resilient to laser fire than a small asteroid.
    
    4) The system which "suffers from deadly asteroid storms" now has a higher than average number of
    asteroids in the space lanes, and a small (non-dangerous) storm occurs near the station whenever
    the system is visited. Displaced asteroids can also be seen whizzing through the spacelanes.
    
    Updates from v.3.0
    ------------------ 
    
    1) 	Legacy script: reduced number of tests done by the script to 3, improving overall system performance.
    
    2) 	Made the mission slightly tougher.
    
    3) 	Added alternative mission ending: in some cases, the station will be partially hit by the asteroid, with irreversible damage to the station's main reactor.
    
    4) 	Further cleanup of asteroids, including solving more upper/lower case problems with linux & case sensitive macs.
    
    5) 	In case of cowardice, legal status now worsens by 25 points, as opposed to being set at 25.
    
    6) 	1.68 and 1.69: message screen - after loading savegame - explaining how to enable the 1.65 version on their computer.
    
    7) 	1.70: If the player score is 50% higher than the minimum required for the mission, the asteroid will be tougher still.
    
    8) 	1.70: If the main station is destroyed, stations added by other OXPs will also be removed from the system.
    
    9) 	1.70: Workaround for 'indestructible stations', With nice station explosion, 30-60 seconds after partial asteroid hit.
    
    10)	1.70: Once mission finishes, run only 1 event handler, improving overall system performance.
    
    11)	1.70: Mission records who destroyed the asteroid, and gives a smaller reward to player if NPCs did it.
    
    12)	1.70: If the player had an energy bomb before the mission and can get back to the station, they get their bomb back.
    
    13)	1.71: The further the asteroid is from the station, the more hits will be needed to destroy it.
    
    
    v.3.45
    ------
    - Cleanup script bugfixed, large asteroids labelled properly.
    
    v.3.46
    ------
    
    A role key is added to all asteroids added by this OXP. In the previous version only the Large Asteroids had a role. This
    meant that only these appeared in game (oops)! On the old version, only 1 new type of asteroid was added even though the
    OXP has the graphics and models to add 12 different types. The new versions now works as intended and you will see a greater
    variety to the shapes and sizes of all asteroids in the Ooniverse. Only the graphics are changed, rocks are still rocks!
    
    v.3.50
    ------
    Because of the large scripting changes since Oolite 1.70, some of the special stuff to make it work with 1.70 is removed again and instead code is added to make it work with 1.71+. (1.72.0 has a bug but will generate a warning on screen. You need than to update to at least 1.72.1)
    All normal big asteroids now have a script that let them generate additional boulders throughout the asteroid and not just in the centre. 
    
    v.3.51
    ------
    Added ships to "help" the player killing the asteroids.
    Several minor bug fixes on 3.50.  
    
    v.3.52
    ------
    Changed role of station-alloy. Anything with station in the role is handled as such. Even as part of a name.
    
    v.3.53
    ------
    Added code so it won't run with Oolite 1.74+. It needs rewriting to work with that Oolite version.
    
    v.3.54
    ------
    Removed the warning.ogg sound from this oxp because it was already part of Oolite since at least Oolite 1.40.
    Repaired the meshes of all asteroids (Griff). This gave much z-fighting of the texture. Completely retextured all asteroids with the original textures but now free of defects.
    
    v3.55
    ------
    Added low resolution normal maps to the asteroids for better experience on computers with shader capability.
    
    v.4.00
    ------
    Added the new mission offering for Oolite 1.74. Raised minimum version to 1.74.
    Changed the asteroid behaviour in the mission system during the "storm". They now fly a more logical path heading for the planet as centre of gravity.
    Recompiled the asteroid models to the new .dat structure with explicit normals.
    Added better resolution normal maps to the asteroids to simulate a surface texture on computers with shaders. (256x256 textures)
    Randomised textures, so that any asteroid can get any texture so we now have 120 different combinations of asteroids and surface structure.
    Disabled Oolite's own asteroids and boulders from appearing. (like_ship copies of them created by other oxp's will still appear)
    Made the texture selection less random for asteroids added close to the previous one, resulting in areas of similar textured asteroids.
    Added new boulders.
    
    v.4.01
    ------
    Fixed a casing bug that will give errors after Oolite 1.74
    
    v.4.02
    ------
    Changed the texture mapping on the asteroids. Now the same texture repeats a few times around the asteroids to create an effective higher resolution for the texture as seen in play.
    
    v.4.02
    ------
    Updated for Oolite 1.77+ were the energy bomb can be missing.
    
    Known Performance Issues (for old systems like mine!)
    ----------------------------------------------------
    
    When you launch into the Storm during the mission, Oolite will freeze for a few seconds whilst
    it adds all the Asteroids to the Ooniverse. Once the Asteroids are added, the game runs normally.
    
    If the Station is destroyed, Oolite will freeze for a few seconds whilst it adds all the
    wreackage that the destroyed station throws out! 
    Much of this slowdown is fixed in Oolite versions after Oolite 1.65
    
    
    LittleBear && Others
    

    Equipment

    This expansion declares no equipment. This may be related to warnings.

    Ships

    Name
    ASBoulder
    ASBoulder1
    ASBoulder10
    ASBoulder11
    ASBoulder2
    ASBoulder3
    ASBoulder4
    ASBoulder5
    ASBoulder6
    ASBoulder7
    ASBoulder8
    ASBoulder9
    Asteroid
    Casteroid1-demo
    Casteroid10
    Casteroid10-demo
    Casteroid11
    Casteroid11-demo
    Casteroid12
    Casteroid12-demo
    Casteroid2
    Casteroid2-demo
    Casteroid3
    Casteroid3-demo
    Casteroid4
    Casteroid4-demo
    Casteroid5
    Casteroid5-demo
    Casteroid6
    Casteroid6-demo
    Casteroid7
    Casteroid7-demo
    Casteroid8
    Casteroid8-demo
    Casteroid9
    Casteroid9-demo
    Asteroid
    LBasteroid10
    LBasteroid2
    LBasteroid3
    LBasteroid4
    LBasteroid5
    LBasteroid6
    LBasteroid7
    LBasteroid8
    LBasteroid9
    Doomsday Asteroid
    LBbadrockI
    LBbadrockII
    LBbadrockIII
    Debris
    Leesti High

    Models

    This expansion declares no models. This may be related to warnings.

    Scripts

    Path
    Scripts/AsteroidStorm.js
    "use strict";
    this.name			= "AsteroidStorm";
    this.author			= "Dajt, Kaks, LittleBear";
    this.copyright		= "Creative Commons: attribution, non-commercial, sharealike.";
    this.description	= "A mission to save a space station, original script.js (Oolite 1.65-js) by Dajt, updated & expanded by Kaks & adapted to Oolite 1.73+ by Eric.";
    this.version		= "4.03";
    
    // declare working variables
    this.badrocks=["badrockI","badrockII","badrockIII"];
    this.badrock="";
    this.lasthit="";
    this.lastPosition = 0;
    /*
    Materials from the following list are randomly used by the asteroids. You can add your own materials to the list by putting
    your new textures in the texture folder and adding the definition to the list below.
    Some materials use a seperate specular file, other materials use the diffuse texture as specular and have the
    shininess map in the alpha chanel of this file.
    */
    this.materials = [
    {"asteroid.png":{diffuse_map: {name:"astorm01.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm01_normal.png", "repeat_s":true, "repeat_t":true}, 
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm02.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm06_normal.png", "repeat_s":true, "repeat_t":true}, 
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm02.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm02_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm03.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm03_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm05.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm05_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm05_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm05.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm03_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm07.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm07_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm08.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm04_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm08.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm08_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm09.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm09_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm09.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm03_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm09.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm07_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm10.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm10_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm11.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm11_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm11.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm13.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm02_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm_specular.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm13.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm13_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm13.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm14.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm14_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm14.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}},
    {"asteroid.png":{diffuse_map: {name:"astorm15.png", "repeat_s":true, "repeat_t":true},
                    normal_map: {name:"astorm15_normal.png", "repeat_s":true, "repeat_t":true},
                    specular_map: {name:"astorm15.png", "repeat_s":true, "repeat_t":true},
                    shininess: 30}}
    ];
    this.lastMaterial = this.boulderMaterial = this.materials[0];
    this.materialCount = this.materials.length;
    
    this.startUp = function (){
    	if (missionVariables.asteroids === "asteroids_FINISHED") this.cleanup();
    };
    
    this.cleanup = function (){
        //disable the events - tell them why!
        delete this.shipWillLaunchFromStation;
        delete this.shipWillEnterWitchspace;
        delete this.missionScreenOpportunity;
    };
    
    this.anyInt = function (n1,n2){
        return Math.round(Math.random()*(n2-n1)+n1);
    };
    
    this.changeInfo = function (){
        var d="The planet Leesti is reasonably fabled for Zero-G cricket and Leestiian evil juice, but cursed by deadly asteroid storms. Leesti's orbital station was recently destroyed by a large asteroid strike. Ships without planet landing capabilities are therefore advised to avoid this system.";
        System.infoForSystem(0, 55).description = d;
        System.infoForSystem(0, 55).productivity /= 100;
    };
    
    this.wipeStationReally = function (){
    	this.wipeStation(true);
    };
    
    this.wipeStation = function (really) {
    	missionVariables.asteroids = "asteroids_OVER";
    	missionVariables.asteroids_statdead =1;
    	this.byeStation=true;
    	if (system.mainStation){
    		system.mainStation.displayName="Damaged Leesti High";
        }
    	if (system.countShipsWithRole("aststat")>0){
    		this.changeInfo();
            if (Math.random()<.25||really){
    			var pos=system.mainStation.position;
    			system.mainStation.explode();
                system.addShips("alloy", 50, pos, 250);
                this.removeAllStations(); //(make sure no other station becomes mainStation)
    		} else{
    			system.description=system.description.replace(/was recently destroyed by/,"is currently being evacuated after");
    			system.mainStation.commsMessage("MAIN REACTOR BREACH, EXPLOSION IMMINENT!");
                system.mainStation.energy = 100;
    			for (var i=0; i<5; i++) system.mainStation.launchShuttle();
    			this.setBadrockMiner(system.mainStation.launchShipWithRole("miner", true)); // true cancels all dockings.
    			this.timer=new Timer(this, this.wipeStationReally, this.anyInt(18, 38));
    		}
    	} else{
    		system.legacy_addSystemShips("alloy", 50, 1); //should work even with a missing station.
        }
    };
    
    this.missionScreenOpportunity = function (){
        if (player.ship.docked){
            this.missionOffers();
        }
    };
    
    this.missionOffers = function (){
    	// Don't offer the missions when showing a mission screen  or mission.choice needs processing
    	// wait until called again via missionScreenEnded, next docking, or missionChoiceWasReset
    	if (this.myMissionShown) return;
    	{
    		if (!player.ship.dockedStation.isMainStation) return;
    		if (system.ID===55 && galaxyNumber===0){
    			if ((!missionVariables.asteroids && player.score>63) || 
                                (missionVariables.asteroids === "asteroids_BRIEFED")){
    				missionVariables.asteroids = "asteroids_BRIEFED";
    				this.asteroids_bombremoved =
    				this.asteroids_rockdead = 0;
    				mission.runScreen({title: "Asteroid Storm", messageKey: "asteroidsbrief_1",
                                overlay: "GalCop.png", model: this.badrocks[0], music: "astormSiren.ogg"}) // "son et lumiere" :)
                    this.hullbang = new Timer(this, this.playHit, 4, 1); // add some ambiance.
    				this.badrock="";
                    this.myMissionShown= true;
    			}
    			if (missionVariables.asteroids==="asteroids_RUNNING"){
    				// do we still have a doomsday asteroid?
    				if (system.shipsWithRole(this.badrock).length>0){
    					mission.runScreen({title: "Asteroid Storm", messageKey: "asteroidsbrief_2",
                                overlay: "GalCop.png", music: "astormSiren.ogg"});  //get back out!
                        this.hullbang = new Timer(this, this.playHit, 4, 1); // add some ambiance.
                    } else { // inside the station, mission running, but no asteroid. this should never happen 
    					missionVariables.asteroids = "asteroids_OVER";
    					this.asteroids_rockdead=1;
    				}
                    this.myMissionShown= true;
    			}
    		} 
    		
    		if (missionVariables.asteroids && missionVariables.asteroids != "asteroids_FINISHED") {
    			if (missionVariables.asteroids === "asteroids_COWARD"){
    				player.credits -= 200;
    				player.bounty += 25;
    				missionVariables.asteroids = "asteroids_FINISHED";
    				mission.runScreen({title: "Asteroid Storm", messageKey: "asteroidsbrief_3", overlay: "GalCop.png"});
    				this.myMissionShown= true;
    			}
    			if (missionVariables.asteroids === "asteroids_OVER"){
    				if (missionVariables.asteroids_statdead===1){ //0 or 1
    					if (this.byeStation && system.ID==55){ //"damaged leesti"
    						//inside the damaged station.
    						if (this.timer) this.timer.stop();
    						if (this.asteroids_bombremoved>0){
    							this.addEnergyBomb();
    						}
    						mission.runScreen({title: "Asteroid Storm", messageKey: "asteroidsbrief_7", overlay: "GalCop.png"}); //we're doomed!
    					}else{
                            // failed. Must be docking in an other system.
    						mission.runScreen({title: "Asteroid Storm", messageKey: "asteroidsbrief_4", overlay: "GalCop.png"}); //you tried!
                        }
    					player.credits += 200;
    					if (system.ID!=55 || galaxyNumber!=0) //we saw the doomed station, didn't bother to go in
    						this.changeInfo();
    				} else if (this.asteroids_rockdead===1){
    					if (this.badRockKiller==="PLAYER"){
    						player.credits += 1000;
    						player.bounty=0;
                            var addedBomb = this.addEnergyBomb(); // do it always here.
    						if (addedBomb)
                                mission.runScreen({title: "Asteroid Storm", messageKey: "asteroidsbrief_5", overlay: "GalCop.png"});//you did it!
                            else
                                mission.runScreen({title: "Asteroid Storm", messageKey: "asteroidsbrief_5b", overlay: "GalCop.png"});//you did it!
    					} else {
    						player.credits += 350;
    						mission.runScreen({title: "Asteroid Storm", messageKey: "asteroidsbrief_6", overlay: "GalCop.png"});//you helped doing it!
    						if (this.asteroids_bombremoved>0){
    							this.addEnergyBomb();
    						}
    					}
    				}
    				missionVariables.asteroids = "asteroids_FINISHED";
    				this.myMissionShown= true;
    			}
    		}
    	}
    };
    
    this.addEnergyBomb = function () {
        // equipment can be unknown after Oolite 1.76
        if (player.ship.equipmentStatus("EQ_ENERGY_BOMB") !== "EQUIPMENT_UNKNOWN")
        {
            player.ship.awardEquipment("EQ_ENERGY_BOMB");
            return true;
        }
        return false;
    }
    
    
    /*
    Credits to Kaks. Below Kaks uses a very complicated method to set properties of the badrock from
    within this worldScript. In current Oolite versions one can do this much easier, but Kaks had to use
    this complex way to let it work with Oolite 1.70. Part of the complexity I wrote out of it and part I 
    let in as a tribute to Kaks who left some very nice sample code with it.
    All b.xxx become properties of the rock itself and can be used in that ship script.
    Without this the objects "missionVariables" and "System" could not be used reliable in oolite 1.70 ship scripts.
    Eric Walch
    */
    this.doomRocks = function (){
        if (!this.trajectory) this.setAsteroidTrajectory();
    	var rockPosition;
    	var rockDistance = this.anyInt(4000,20000);  // addition range relative to station.
    	rockPosition = system.mainStation.position.add(this.trajectory.multiply(rockDistance));
    	missionVariables.asteroids = "asteroids_RUNNING";
        var badrock = system.addShips(this.badrock, 1, rockPosition, 10)[0];
        if (badrock){
            badrock.recharge=(rockDistance/7000)-1; //rough estimate
            badrock.scannerDisplayColor1 = [0.0, 0.8, 0.8, 1.0]; // cyan-like
            var miner = system.addShips("miner", 4, rockPosition, 10E3);
            for (var i=0; i<miner.length; i++) if (miner[i]) this.setBadrockMiner(miner[i]);
            log(this.name, "Adding doomsday asteroid at: "+rockDistance+" meters");
        }
        system.addShips("ast1", 27, rockPosition, 15E3);
    };
    
    this.setBadrockMiner = function (ship){
        ship.switchAI("LBbadrockMinerAI.plist");
        ship.primaryRole = "LBbadrockMiner"; // role needed to interact with badrock.
    };
    
    this.shipWillLaunchFromStation = function (){
    	if (system.ID===55 && galaxyNumber===0){
            this.myMissionShown=false;
    		if (this.byeStation){
    			this.timer=new Timer(this, this.wipeStationReally, this.anyInt(3,19));
    			return;
    		}
    		var asteroids = system.countShipsWithPrimaryRole("ast1")
    		if (asteroids<3)
                for (var i=0; i<4; i++) this.addAsteroid(3);
    		if (missionVariables.asteroids === "asteroids_RUNNING"|| missionVariables.asteroids === "asteroids_BRIEFED"){
    			if (player.ship.equipmentStatus("EQ_ENERGY_BOMB") === "EQUIPMENT_OK"){
    				player.ship.removeEquipment("EQ_ENERGY_BOMB");
    				this.asteroids_bombremoved=1;
    			}
    			if (this.badrock===""){ // choose once.
    				if (player.score<96) this.badrock=this.badrocks[0]  // weak, easy with 2x beam laser.
    				else if (player.score<180) this.badrock=this.badrocks[1] // strong
    				else this.badrock=this.badrocks[2]; // very strong, needs 2x military laser.
    			}
    			if (system.countShipsWithRole(this.badrock)===0)
    				this.doomRocks();
    		}
    	}
    };
    
    this.shipWillEnterWitchspace = function (){
    	if (missionVariables.asteroids === "asteroids_RUNNING"){
    		if (system.countShipsWithRole(this.badrock)===0)
    			missionVariables.asteroids = "asteroids_OVER";
    		else{
    			missionVariables.asteroids = "asteroids_COWARD";
    			missionVariables.asteroids_statdead=1;
    			this.changeInfo();
    		}
    	}
    };
    
    this.shipWillExitWitchspace = function (){
    	if (system.ID===55 && galaxyNumber===0){
            for (var i=0; i<4; i++) this.addAsteroid(3);
    		system.addShips("asteroid", 3);
    		if (missionVariables.asteroids_statdead===1){
                this.timer = new Timer(this, this.removeAllStations, 0); // make sure it runs after all other oxps.
                this.timer2 = new Timer(this, this.removeAllStations, 5); // also remove delayed added ones.
                for (var i=0; i<5; i++) this.addAsteroid(4); // add some more rocks during mission
    		}
    	}
    };
    
    this.removeAllStations = function (){
        // Find all stations and dockable items in the system.
        var stations = system.filteredEntities(this, function (entity) { return entity.isStation; });
        // Blow them all up.
        stations.forEach(function (entity) { entity.remove(true); });
    };
    
    this.setAsteroidTrajectory = function (){
        if (system.mainStation) this.trajectory = system.mainStation.position.subtract(system.mainPlanet.position).direction()
        else this.trajectory = new Vector3D(-0.95569, 0.131987, -0.263126);
    };
    
    this.addAsteroid = function (count){
        if (!this.trajectory) this.setAsteroidTrajectory();
        var multiplier = 3 + 10 * Math.random();
        var distance = system.mainPlanet.radius * multiplier; // at least 3 radii away (station is at 2 radii)
        var pos = system.mainPlanet.position.add(this.trajectory.multiply(distance));
        
        if (Math.random() < 0.3) system.addShips("ast1", 1, pos, 1E3) // on very likely ramming course.
        else system.addShips("ast1", 1, pos, 10E3 * multiplier); // spread more widely
        
        // asteroids focus themself at one point on their journey to the planet, so spread them
        // furter appart when adding them further away.
        if (count > 1) system.addShips("ast1", count-1, pos, 15E3 * multiplier);
    };
    
    // function is called by timer.
    this.playHit = function (){
        if (!player.ship.docked){
            this.hullbang.stop();
            delete this.hullbang;
            return;
        }
        if (Math.random() < 0.9) return;
        this.mySound = new SoundSource;
        this.mySound.sound = "hullbang.ogg";
        this.mySound.play(1);
    };
    
    this.getMaterial = function (pos){
        var dif = pos - this.lastPosition;
        dif *= dif;
        if (dif > 400E6){
            // Only switch material for distant asteroids so that we obtain asteroid clusters of similar type.
            // for effectifines we only compare the z component of the position.
            this.lastPosition = pos;
            this.lastMaterial = this.materials[Math.floor(Math.random()*this.materialCount)];
            //log(this.name, "Made new material selection. Difference = "+Math.round(Math.sqrt(dif))+" m");
        }
        return this.lastMaterial;
    };
    
    Scripts/AsteroidStormAsteroid.js
    "use strict";
    this.name      = "AsteroidStormAsteroid"; 
    this.author    = "eric walch"; 
    this.copyright = "� 2008 eric walch."; 
    this.description = "Code for an self colouring asteroid"; 
    this.version   = "1.2";
    
    this.shipSpawned = function(){ 
        this.ship.primaryRole = "asteroid";
        if (this.ship.isBoulder){ // created by one of the very big asteroids.
            this.ship.displayName = "Big boulder";
            this.ship.isBoulder = false;
        }
        this.material = worldScripts.AsteroidStorm.getMaterial(this.ship.position.z); // remember this.
        this.ship.setMaterials(this.material);
    };
    
    this.shipDied = function (){
        // store the used material in the worldScript, so the created boulders can
        // retreive it there. We have no direct reference to the created boulders.
        worldScripts.AsteroidStorm.boulderMaterial = this.material;
    };
    Scripts/AsteroidStormBoulder.js
    "use strict";
    this.name      = "AsteroidStormBoulder"; 
    this.author    = "eric walch"; 
    this.copyright = "� 2008 eric walch."; 
    this.description = "Code for an self colouring boulder"; 
    this.version   = "1.2";
    
    this.shipSpawned = function (miner){ 
        this.ship.setMaterials(worldScripts.AsteroidStorm.boulderMaterial);
    };
    
    Scripts/LBasteroid.js
    "use strict";
    this.name      = "LBAsteroid"; 
    this.author    = "eric walch"; 
    this.copyright = "� 2008 eric walch."; 
    this.description = "Code for regeneration of special asteroid"; 
    this.version   = "1.00";
    
    this.shipSpawned = function (){
        this.ship.savedCoordinates = system.mainPlanet.position;
        delete this.shipSpawned;
    }
    
    this.shipDied = function(ship){ 
        worldScripts.AsteroidStorm.addAsteroid(1);
        if (ship && ship.isStation && this.ship.position.distanceTo(player.ship) < 7E3) this.playHit();
    
    	delete this.shipDied; // make sure it is not called again.
    }
    
    this.playHit = function (){
        this.mySound = new SoundSource;
        this.mySound.sound = player.ship.docked ? "hullbang.ogg" : "hit.ogg";
        this.mySound.play(1);
    };
    Scripts/LBbadrock.js
    "use strict";
    this.name = "LBbadrock";
    this.author = "LittleBear,Kaks";
    this.copyright = "Jan/Feb 2008 - But do what you like with it in your OXPs!";
    this.description = "who shot the asteroid last?"
    this.version = "1.18";
    
    this.lastEnergy = this.ship.energy;
    this.lasthit = "";
    
    this.shipDied = function (who, why){
    	log(this.name, "Rock killed by: "+who+", by means of "+why)
    	missionVariables.asteroids = 'asteroids_OVER';
    	worldScripts["AsteroidStorm"].asteroids_rockdead = 1;
        var bigExplosion = (this.lastEnergy > this.ship.maxEnergy * 0.5); // player cheats with super weapon.
        var stationPosition = system.mainStation.position;
    	if (who && who.isStation || bigExplosion || why === "cascade weapon") worldScripts["AsteroidStorm"].wipeStation(false);
        if (bigExplosion){
            var rocks = this.ship.spawn("ast1", 20);
            var vel = stationPosition.subtract(this.ship.position).direction();
            for (var i=0; i < 13; i++) rocks[i].velocity = vel.multiply(500 + Math.random()*1000); // throw some rocks in direction of station.
        }
    	// Collided with station or player used Q-bomb or similar super weapon.
    	if ((who && who.isPlayer) || this.lasthit === "PLAYER")
    		worldScripts["AsteroidStorm"].badRockKiller = "PLAYER"
        else
    		worldScripts["AsteroidStorm"].badRockKiller = "NPC"; // this line only happens when the 2 last shots were not the plaer!
    	delete this.shipDied; // make sure it is not called again.
    	// in 1.72 becomeExplosion is not triggering the shipDied event. 1.71 and probably 1.73 will. (Edit: only fixed since 1.75.4)
    }
    
    this.shipBeingAttacked = function (who){
    
        this.lasthit = (who && who.isPlayer) ? "PLAYER" : "NPC";
    	if (who && who.primaryRole === "LBbadrockMiner") this.ship.energy = this.lastEnergy; // don't count the mining hits
    	if (this.ship.recharge>=0){
    		this.ship.recharge-=(this.ship.maxEnergy-this.ship.energy)/this.ship.maxEnergy;
    		this.ship.energy=this.ship.maxEnergy;
    		}
    	this.lastEnergy = this.ship.energy;
    }
    
    this.wipeStation = function (){
    	this.shipDied(system.mainStation, "scriptMessage")  //In oolite 1.72 the shipDied() is not executed for ships dying with an AI "becomeExplosion" command.
    }