Config/script.js |
"use strict";
this.name = "spacecrowds";
this.author = "Astrobe";
this.copyright = "2017 Creative Commons: attribution, non-commercial, sharealike.";
this.description = "Creates random encounters when the Torus drive has been in use for a long time.";
this.version = "1.2.0";
// Configurability contributed by PHKB.
// Additionnal options to preserve derelicts and asteroids contributed by Dybal.
/* How to add your own encounter scenarios:
* Create a function that spawns all the necessary stuff.
* This function will be called by Space Crowds (SC):
* - with one parameter which is around where to spawn the ships (typically you pass it to system.addGroup().
* This is a suggested position that is a few scanner ranges ahead of the player. But you can spawn your ships
* behind the player if you want. Just make sure the player has good chances to be masslocked as a result.
* The masslock doesn't have to be certain, for the player to be able to avoid trouble by careful eyeballing
* is considered "fair game" (let other OXPs like Bullet Drive deal with that if that's too easy for some players).
* - this is bound to SC's script object, so you can use its facilities like $spawnRandomRoles
* Then, call $pushScenario or $pushRareScenario with your name of the symbol of your function.
* There are two scenario lists. The former is used 99% of the times, the latter 1% of the times.
* Among those two lists the probabilities are even.
* If you really want to give your scenario relatively more weight, just push it multiple times.
*
* $spawnRandomRoles(n, role, pos, radius)
* $spawnRandomRoles is a utility function that let you spawn easily a group of ships in one role.
* n is the maximum number of ships. The function performs n-1 times a coinflip to determine how many
* ships to spawn. As a result, we get a bell curve-like distribution centered on n/2, meaning that
* the function will spawn most often n/2 ships, and more rarely 1 or n. The function will spawn at least
* one ship.
* roles is a string indicating the role of the ships ("pirate" or "police" or "trader" etc.)
* pos is the spawning position; typically you pass the suggested position you've received from SC.
* radius is the radius of the spawning sphere. The bigger, the more the ships will be spread-out.
* This parameter is optional and will default to 5Km if not given (scanner range is 25Km).
*
* How to test your scenarios
* The main problem with testing is that scenarios are chosent randomly, so it can take a while
* until you get your scenario.
* Use $flushScenarios() to remove the other scenarios and then add your scenario, so your scenario
* will be the only available one besides the rare scenarios. When you're done testing, remove the
* the $flushScenarios() line and move your scenario to the $pushRareScenario() if needed.
* You can use the $report() function to log whatever you need to.
*
* Possible errors:
* Javascript exception "group is null" : role doesn't exist; could be a typo in the name (eg "hunters" instead of "hunter")
* Javascript exception "commonEvents is undefined": scenario list is empty. Maybe you flushed (for testing purposes)
* the scenarion list after you added your scenario? Can also be a typo in scenario name.
*/
this.$commonEvents=[];
this.$rareEvents=[];
this.$spawnedShips=[];
this.$chance = 0.02;
this.$rare_chance = 0.01;
this.preserve_derelicts = false;
this.preserve_asteroids = false;
this.libSettings = {Name:this.name, Display:"Config", Alias:"Space Crowds", Alive:"libSettings",
Bool:{
B0:{Name:"$preserve_derelicts", Def:false, Desc:"Preserve derelicts"},
B1:{Name:"$preserve_asteroids", Def:false, Desc:"Perserve asteroids"},
Info:"true:Preserve, false:Remove when out of player's sight"},
SInt:{
S0:{Name:"$chance", Def:0.02, Min:0.0001, Max:1, Desc:"Chance of encounter", Float:true},
S1:{Name:"$rare_chance", Def:0.01, Min:0.0001, Max:1, Desc:"Rare chance", Float:true},
Info:"0 - Chance of having an encounter\n1 - Chance of encounter being a rare one"},
};
// utilities
this.$spawnRandomRoles=function(n, roles, pos, radius)
{
radius = (typeof radius !== 'undefined') ? radius : 8E3;
var random=Math.random;
var count=1; // at least one
for(var i=0; i<n-1; i++)
{
if(random()<0.5) continue;
count++;
}
var group=system.addGroup(roles, count, pos, radius);
group.ships.forEach(function(ship) {ship.fuel=random()*7; this.$spawnedShips.push(ship); }, this);
this.$report("Adding " + count + " " + roles);
return group;
}
// basic scenarios
this.$small_pirate_pack=function(pos) {this.$spawnRandomRoles(5, "pirate", pos);}
this.$small_hunter_pack=function(pos) {this.$spawnRandomRoles(5, "hunter", pos);}
this.$small_police_patrol=function(pos) {this.$spawnRandomRoles(5, "police", pos);}
this.$small_traders_pack=function(pos) {this.$spawnRandomRoles(5, "trader", pos);}
this.$adaptative=function(pos)
{
this.$report("Adaptative");
var s=system.government;
if(s<=4) this.$spawnRandomRoles(7-s, "pirate", pos);
else this.$spawnRandomRoles(s, "police", pos);
}
this.$pirates_vs_police=function(pos)
{
this.$report("Pirates vs Police");
this.$small_pirate_pack(pos);
this.$small_police_patrol(pos);
}
this.$pirates_vs_hunters=function(pos)
{
this.$report("Pirates vs Hunters");
this.$small_pirate_pack(pos);
this.$small_hunter_pack(pos);
}
this.$pirates_vs_traders=function(pos)
{
this.$report("Pirates vs Traders");
this.$small_pirate_pack(pos);
this.$small_traders_pack(pos);
}
this.$boulder_field=function(pos)
{
// The "popping" with asteroids is too obvious, so we use boulders.
// However, they seem to have a low "visibility range", so typically
// some of them are almost immediately removed.
// We should give those boulder some speed so as to deter miner-players
// from setting a way point here in order to come back later; they won't find
// anything because those boulders will be removed as soon as they get out
// of sight.
this.$report("Boulders");
var g=this.$spawnRandomRoles(20, "boulder", pos, 2E3);
g.ships.forEach(function(ship) { ship.temperature=0; }, this);
}
this.$empty=function(pos)
{
this.$report("Empty");
}
this.$cargo=function(pos)
{
this.$report("Cargo");
if(Math.random()<0.5) this.$spawnRandomRoles(1, "cargopod", pos);
}
this.$traders_vs_thargoids=function(pos) // rare
{
this.$report("Traders vs Thargoids");
this.$small_traders_pack(pos);
this.$spawnRandomRoles(5, "thargoid", pos);
}
this.$police_vs_thargoids=function(pos) // rare
{
this.$report("Police vs Thargoids");
this.$small_police_patrol(pos);
this.$spawnRandomRoles(6, "thargoid", pos);
}
this.$thargoid_fleet=function(pos) // rare
{
// Around 5 Thargoid ships, expect no support.
this.$report("Tharmageddon!");
this.$spawnRandomRoles(10, "thargoid", pos);
}
this.$pirateNet=function(pos) // rare
{
// A large group of pirates widely spread in order to catch lone ships
this.$report("Pirate net");
this.$spawnRandomRoles(10, "pirate", pos, 15E3);
}
this.$pushScenario = function (proc)
{
this.$commonEvents.push(proc);
}
this.$pushRareScenario = function (proc)
{
this.$rareEvents.push(proc);
}
this.$flushScenarios = function (proc)
{
this.$commonEvents.length=0;
}
this.$report = function (msg)
{
log(this.name, msg);
}
this.startUp = function ()
{
this.dsGroup = new ShipGroup("DeepSpaceShips"); // start with an empty group
//this.$pushScenario(this.$small_pirate_pack);
//this.$pushScenario(this.$small_police_patrol);
this.$pushScenario(this.$small_traders_pack);
this.$pushScenario(this.$small_hunter_pack);
this.$pushScenario(this.$empty);
this.$pushScenario(this.$pirates_vs_police);
this.$pushScenario(this.$pirates_vs_hunters);
this.$pushScenario(this.$pirates_vs_traders);
this.$pushScenario(this.$boulder_field);
this.$pushScenario(this.$cargo);
this.$pushScenario(this.$adaptative);
this.$pushRareScenario(this.$traders_vs_thargoids);
this.$pushRareScenario(this.$police_vs_thargoids);
this.$pushRareScenario(this.$thargoid_fleet);
this.$pushRareScenario(this.$pirateNet);
}
this.startUpComplete = function() {
if (missionVariables.SpaceCrowds_Chance) this.$chance = parseFloat(missionVariables.SpaceCrowds_Chance);
if (missionVariables.SpaceCrowds_Rare) this.$rare_chance = parseFloat(missionVariables.SpaceCrowds_Rare);
if (missionVariables.SpaceCrowds_Preserve_Derelicts && missionVariables.SpaceCrowds_Preserve_Derelicts == 1)
this.$preserve_derelicts = true;
else
this.$preserve_derelicts = false;
if (missionVariables.SpaceCrowds_Preserve_Asteroids && missionVariables.SpaceCrowds_Preserve_Asteroids == 1)
this.$preserve_asteroids = true;
else
this.$preserve_asteroids = false;
// register our settings, if Lib_Config is present
if (worldScripts.Lib_Config) worldScripts.Lib_Config._registerSet(this.libSettings);
}
this.playerWillSaveGame = function() {
missionVariables.SpaceCrowds_Chance = this.$chance;
missionVariables.SpaceCrowds_Rare = this.$rare_chance;
if (this.$preserve_derelicts)
missionVariables.SpaceCrowds_Preserve_Derelicts = 1;
else
missionVariables.SpaceCrowds_Preserve_Derelicts = 0;
if (this.$preserve_asteroids)
missionVariables.SpaceCrowds_Preserve_Asteroids = 1;
else
missionVariables.SpaceCrowds_Preserve_Asteroids = 0;
}
this.shipLaunchedFromStation = function ()
{
if (this.checkTimer)
this.checkTimer.start()
else
this.checkTimer = new Timer(this, this.$check, 5, 1000/(player.ship.maxSpeed*3)); // about every 1.3 second for Adder (maxSpeed=240).
}
this.$check = function ()
{
if(player.ship.torusEngaged
&& Math.random()>(1 - this.$chance)
&& !system.isInterstellarSpace)
{
this.$report("Chance!");
this.$createEncounter();
}
else
{
this.$removeFarShips();
}
}
this.$createEncounter = function ()
{
var ourShip=player.ship;
if(system.countShipsWithRole("station", ourShip, 240E3) > 0)
{
this.$report("Station nearby");
return;
}
var pos = ourShip.position.add(ourShip.heading.multiply(48E3)).add(Vector3D.random(15E3));
if(Math.random()<this.$rare_chance)
{
var n=Math.floor(Math.random()*this.$rareEvents.length);
this.$rareEvents[n].call(this, pos);
}
else
{
var n=Math.floor(Math.random()*this.$commonEvents.length);
this.$commonEvents[n].call(this, pos);
}
}
this.$removeFarShips=function()
{
var spawnedShips=this.$spawnedShips;
var count=0;
var e;
for(var i=0; i<spawnedShips.length; i++)
{
// ship might actually be long dead, but Oolite seems to handle that case well.
try
{
if(!spawnedShips[i].position.distanceTo(player.ship.position)>100E3)
{
if(spawnedShips[i].isShip &&
!(this.preserve_derelicts && spawnedShips[i].isDerelict) &&
!(this.preserve_asteroids && spawnedShips[i].isBoulder) )
{
spawnedShips[i].remove();
spawnedShips[i]=null; // for cleanup
count++;
}
}
}
catch(e)
{
spawnedShips[i]=null;
}
}
//cleanup
if(count)
{
this.$spawnedShips=spawnedShips.filter(function(e) { return e!=null; });
this.$report("Removed "+count+" ships");
}
}
|