| Scripts/riskybusiness.js | "use strict";
this.author = "phkb";
this.copyright = "2021 phkb";
this.licence = "CC-BY-SA-NC 4.0";
this.name = "RiskyBusiness_Main";
this.description = "Adjusts prices according to system danger level - so dangerous systems have more reward for traders";
this._trueValues = ["yes", "1", 1, "true", true];
this._riskBasedEconomy = true;
this._riskyBusiness = true;
this._logging = false;
this.$tvols = [[],[],[],[],[],[],[],[]]; // cache variable for risk-based-economy
this._rbConfig = {Name:this.name, Alias:"Risky Business", Display:"Config", Alive:"_rbConfig",
	Bool:{
		B0:{Name:"_riskBasedEconomy", Def:true, Desc:"Include 'Risk Based Economy'"},
		B1:{Name:"_riskyBusiness", Def:true, Desc:"Include 'Risky Business'"},
		B2:{Name:"_logging", Def:false, Desc:"Output info to log"},
		Info:"0 - Includes logic from 'Risk Based Economy'.\n1 - Includes logic from 'Risky Business'.\n2 - Output extra info to log file."}
};
//-------------------------------------------------------------------------------------------------------------
this.startUp = function() {
	var msi = worldScripts.MarketScriptInterface_Main;
	msi.$addMarketInterface("system_local", "$updateLocalCommodityDefinition", this.name);
	if (missionVariables.RiskyBusiness_RBE) this._riskBasedEconomy = (this._trueValues.indexOf(missionVariables.RiskyBusiness_RBE) >= 0 ? true : false);
    if (missionVariables.RiskyBusiness_Risky) this._riskyBusiness = (this._trueValues.indexOf(missionVariables.RiskyBusiness_Risky) >= 0 ? true : false);
    if (missionVariables.RiskyBusiness_Logging) this._logging = (this._trueValues.indexOf(missionVariables.RiskyBusiness_logging) >= 0 ? true : false);
}
//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function () {
    // register our settings, if Lib_Config is present
    if (worldScripts.Lib_Config) {
        worldScripts.Lib_Config._registerSet(this._rbConfig);
    }
}
//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function() {
    missionVariables.RiskyBusiness_RBE = this._riskBasedEconomy;
    missionVariables.RiskyBusiness_Risky = this._riskyBusiness;
    missionVariables.RiskyBusiness_Logging = this._logging;
}
/*
    Other factors to consider:
        system economy - increase or decrease bias
        number of local systems - more neighbours means more traffic, increase or decrease traffic
*/
//-------------------------------------------------------------------------------------------------------------
this.$updateLocalCommodityDefinition = function (good, station, systemID) {
	if (station) return good; // shouldn't be necessary
	if (!worldScripts.RiskyBusiness_Control || worldScripts.RiskyBusiness_Control._riskBasedEconomy) good = this.rbe_updateLocalCommodityDefinition(good, station, systemID);
	if (!worldScripts.RiskyBusiness_Control || worldScripts.RiskyBusiness_Control._riskyBusiness) good = this.rb_updateLocalCommodityDefinition(good, station, systemID);
	return good;
}
//-------------------------------------------------------------------------------------------------------------
this.rb_updateLocalCommodityDefinition = function (good, station, systemID) {
	var info = System.infoForSystem(galaxyNumber, systemID);
	var sys = info.government; // 0 = anarchy, 7 = corporate
	// if we're in a system we're not adjusting, just return the good with no change
	if (sys >= 3) return good;
	// not all goods will be impacted
	// we're using sort_order for a seed, so that for any system, the same goods will be adjusted, 
	// because the sort order shouldn't change and is unique for each good
	// this adds some predictability to the changes, but also means there is benefit to searching out the best locations
	if (this.$customPseudoRandomNumber(galaxyNumber, systemID, good.sort_order) > 0.25) return good; // only 25% chance a good will be changed
	var old_price = good.price;
	// the random factor will be the same on any given day
	var bias = ((7 - sys) + 3) / 7 + ((this.$customPseudoRandomNumber(galaxyNumber, systemID, clock.days) * 0.2) - 0.1);
	var diff = good.price - good.price_average;
	// apply the bias to the difference
	// if the price is lower than the average, make it a super-special
	if (diff < 0) bias = 1 - (bias - 1);
	// check for an edge case where the applied change would make the price less than 0.
	// this could happen if the average price is much greater than or less than the normal price
	if (Math.floor(good.price + (diff * bias)) < 0) return good;
	// ok, we should be good to go now
	good.price = Math.floor(good.price + (diff * bias));
	if (worldScripts.RiskyBusiness_Control && worldScripts.RiskyBusiness_Control._logging) log(this.name, "Adjusted " + good.key + " from " + old_price + " to " + good.price + " (avr_price=" + good.price_average + ",bias=" + bias + ",diff=" + diff + ",sys=" + systemID + ")");
	return good;
}
//-------------------------------------------------------------------------------------------------------------
this.$customPseudoRandomNumber = function (galid, sysid, salt) {
	// because we can't use scrambledPseudoRandomNumber for systems we aren't in
	var n = (sysid + (galid * 256)) * (salt * 512) + salt;
	n = (214013 * n + 2531011) & 0xFFFFFFFF;
	n = (214013 * n + 2531011) & 0xFFFFFFFF;
	n = (214013 * n + 2531011) & 0xFFFFFFFF;
	return n / 4294967296.0 + 0.5;
}
//-------------------------------------------------------------------------------------------------------------
/*
    Risk-Based Economy
    Adjusts prices according to trade volume - so safer systems have more 'centred' prices, and hub systems have more 'centred' prices.
    Author: cim
    Copyright 2011-2014 cim.
    Licence: CC-BY-SA 3.0
    Version: 2.0
*/
this.rbe_updateLocalCommodityDefinition = function (good, station, system) {
	var info = System.infoForSystem(galaxyNumber, system);
	//	var tvol = worldScripts["oolite-populator"].$repopulatorFrequencyIncoming.traderFreighters; // generally in 0.025 .. 0.1 range with 0.05 being reasonably typical
	// tvol hasn't actually been generated at this point, though, so
	// must calculate it separately here
	if (!this.$tvols[galaxyNumber][system.ID]) {
		var freighters = 0;
		var locals = info.systemsInRange();
		for (var i = 0; i < locals.length; i++) {
			// standard freighter traffic is mirrored
			var local = locals[i];
			// traffic is higher between systems on opposite side of economy
			var ecomatch = -(info.economy - 3.5) * (local.economy - 3.5);
			var trdanger = 0;
			var rate = 0;
			// if either local or remote end is more dangerous than
			// Communist, reduce trader frequency
			if (local.government < 4) {
				trdanger = (4 - local.government) * 2.5;
			}
			if (info.government < 4) {
				trdanger += (4 - info.government) * 2.5;
			}
			// good economic match: one every 30 minutes if safe
			if (ecomatch > 0) {
				rate = 60 / (30 + trdanger);
			}
			// bad economic match: one every 2 hours if safe
			else {
				rate = 60 / (120 + (trdanger * 2));
			}
			freighters += rate;
		}
		this.$tvols[galaxyNumber][system.ID] = freighters / 180;
	}
	var tvol = this.$tvols[galaxyNumber][system.ID];
	// this has already been counted a bit above, but count it again
	// because that doesn't allow for how many actually get through
	var sys = info.government; // 0 = anarchy, 7 = corporate
	var bias = ((tvol + sys * 0.01) - 0.07) * 10;
	// approximate range -0.5 ..0.8 
	bias = bias * (0.75 + Math.random() / 2);
	if (bias > 0.9) {
		bias = 0.9;
	}
	// adjusted range -0.625 .. 1.0
	// positive means "centre this more"
	var oldprice = good.price;
	good.price = Math.floor(good.price + ((good.price_average - good.price) * bias));
	if (worldScripts.RiskyBusiness_Control && worldScripts.RiskyBusiness_Control._logging) log(this.name, "Adjusted " + good.key + " from " + oldprice + " to " + good.price + " (bias=" + bias + " => " + tvol + "," + sys + ")");
	return good;
} |