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

Expansion Sothis Trade Center

Content

Warnings

  1. Conflict Expansions mismatch between OXP Manifest and Expansion Manager at character position 0059 (DIGIT ZERO vs LATIN SMALL LETTER N)
  2. Wiki check failed: org.apache.http.conn.ConnectTimeoutException: Connect to wiki.alioth.net:443 [wiki.alioth.net/109.70.41.29] failed: Connection timed out
  3. Wiki check failed: org.apache.http.conn.ConnectTimeoutException: Connect to wiki.alioth.net:443 [wiki.alioth.net/109.70.41.29] failed: Connection timed out

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description A large space station often used for corporate offices, a six-star hotel, a huge orbital shopping mall, as well as numerous high class luxury accommodations for the rich and famous. A large space station often used for corporate offices, a six-star hotel, a huge orbital shopping mall, as well as numerous high class luxury accommodations for the rich and famous.
Identifier oolite.oxp.KillerWolf.SothisTC oolite.oxp.KillerWolf.SothisTC
Title Sothis Trade Center Sothis Trade Center
Category Dockables Dockables
Author Killer Wolf, spara, phkb Killer Wolf, spara, phkb
Version 2.1 2.1
Tags station, buoy station, buoy
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
  • oolite.oxp.Spara.SothisTC:0
  • oolite.oxp.KillerWolf.Sothis_station:0
  • oolite.oxp.Spara.SothisTC:
  • oolite.oxp.KillerWolf.Sothis_station:
  • Information URL https://wiki.alioth.net/index.php/Sothis n/a
    Download URL https://wiki.alioth.net/img_auth.php/8/85/SothisTC_2.1.oxz n/a
    License Killer Wolf special Killer Wolf special
    File Size n/a
    Upload date 1780527566

    Relationships Diagram

    Documentation

    Also read http://wiki.alioth.net/index.php/Sothis%20Trade%20Center

    SothisTC_readme_&_license.txt

    SothisTC OXP ver 1.0.4 (16.5.2013)
    
    Author: spara (Mika Spåra)
    
    _The_story,_sort_of_
    
    Long ago a business magnate Donald Troomp built Sothis stations to high tech corporate systems to act as trade centers. To the big public Troomp is better remembered by his intergalactic competition, which he called "The Apprentice." The idea was to find the most suitable person to run one of his companies. Mr Troomp is long gone, but his Sothis Trade Centers are live and kicking.
    
    _What_it_does_
    
    All Sothises (from Sothis OXP by KillerWolf) are converted into trading stations and relocated to high TL corporate systems.
    
    If you have New Cargoes OXP by cim installed, you can read TradeNet when visiting a Sothis station. You will also find that there are more special cargo opportunities than there are in the main station.
    
    _Work_used_by_others_
    
    * Backgrounds are made from vectormaps by G. Presti & C. Angus.
    
    _Installing_and_requirements_
    
    * Sothis station is required
    * New Cargoes is recommended
    * Station Validator is supported
    
    Install the OXP by copying SothisTC.oxp to your AddOns-folder.
    (Now combined into one OXP)
    ------
    
    This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
    
    ------
    
    v.1.0.4
    Tweaked to work on AppleMac by Cholmondeley
    
    This version also makes Killer Wolf's station saveable at.

    read me.txt

    Sothis Stations
    
    To install, unzip the OXP and place in your AddOns folder.
    some unzippers split the enclosed folders up ~ if this happens simply 
    create a folder called "Sothis.OXP", drag/drop the folders into it, then
    place the folder into the AddOns.
    
    Thanks go out to Thargoid and Eric Walch for scripty help. Thanks as ever to Griff 
    for the shadery things.
    
    KW
    8-8-2010
    v1.0
    
    Station markets added by Diziet Sma, using Spara's "Basic market fix for old oxps"
    http://aegidian.org/bb/viewtopic.php?f=4&t=17621#p239979
    
    29/10/2017
    
    Market Inquirer compatibility & Ship's Library presence added by Cholmondely. "Wasp Buoy" renamed to Sothis Buoy. Spara reckons that KW based this on his Wasps.oxp and forgot to rename everything.
    23/3/2022
    
    Updated by phkb.
    Merged SothisTC into main Sothis Station.
    Add Library Config options for controlling market and spawn conditions.
    Reverted to using default shaders.
    Updated diffuse and normal textures.
    Cleaned up code and data.
    Centred station on z-axis.
    Move all text to descriptions.plist for easier localisation.
    Updated vector maps, increased resolution so images are clearer.
    16/05/2026
    
    Fixed an issue with the spawning of the station nav beacon.
    Removed some debug code.
    04/06/2026

    Equipment

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

    Ships

    Name
    Sothis Dock
    Buoy
    Sothis Buoy
    Buoy
    Buoy
    Sothis Decorations
    Sothis Main Hull
    Sothis Trade Center

    Models

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

    Scripts

    Path
    Scripts/.DS_Store
    Bud1% @� @� @� @E%DSDB`� @� @� @
    Scripts/sothis_main.js
    "use strict";
    this.name = "Spawn-sothis";
    this.author = "phkb";
    this.copyright = "This script is hereby placed in the public domain.";
    this.version = "1.1";
    this.description = "Sothis Trade Center main script";
    
    this._config = {
        marketType: 3, // 0 = no market; 1 = original custom market; 2 = similar to main station; 3 = oolite-business goods
        minTL: 8,
    	maxTL: 14,
    	minEco: 0,
    	maxEco: 7,
    	minGov: 7,
    	maxGov: 7,
    	minProd: 0,
    	maxProd: 60000,
    };
    
    this._STCConfig = {
        Name: this.name,
        Display: expandDescription("[STC_config_display]"),
        Alias: expandDescription("[STC_config_alias]"),
        Alive: "_STCConfig",
        SInt: {
            S0: { Name: "_config.marketType", Def: 2, Min: 0, Max: 3, Desc: expandDescription("[STC_markettype]") },
            S1: { Name: "_config.minTL", Def: 8, Min: 0, Max: 14, Desc: expandDescription("[STC_minTL]") },
            S2: { Name: "_config.maxTL", Def: 14, Min: 0, Max: 14, Desc: expandDescription("[STC_maxTL]") },
            S3: { Name: "_config.minEco", Def: 0, Min: 0, Max: 7, Desc: expandDescription("[STC_minEco]") },
            S4: { Name: "_config.maxEco", Def: 7, Min: 0, Max: 7, Desc: expandDescription("[STC_maxEco]") },
            S5: { Name: "_config.minGov", Def: 7, Min: 0, Max: 7, Desc: expandDescription("[STC_minGov]") },
            S6: { Name: "_config.maxGov", Def: 7, Min: 0, Max: 7, Desc: expandDescription("[STC_maxGov]") },
            S7: { Name: "_config.minProd", Def: 0, Min: 0, Max: 60000, Desc: expandDescription("[STC_minProd]") },
            S8: { Name: "_config.maxProd", Def: 60000, Min: 0, Max: 60000, Desc: expandDescription("[STC_maxProd]") },
            Info: expandDescription("[STC_config_sint_info]")
        },
    };
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUp = function () {
        if (missionVariables.Sothis_Config) this._config = JSON.parse(missionVariables.Sothis_Config);
    	// make sure everything is a number
    	for (var prop in this._config) {
    		this._config[prop] = parseInt(this._config[prop]);
    	}
    
        worldScripts.XenonUI.$addMissionScreenException("sothis");
    	if (!worldScripts.CargoTypeExtension) { //check for new cargoes oxp
    		this.$new_cargoes = false;
    		delete this.playerBoughtEquipment;
    		delete this.shipLaunchedFromStation;
    	} else {
    		this.$tc_eqTradenet = false;
    		this.$new_cargoes = true;
    	}
    	this.$showWelcome = false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.startUpComplete = function () {
        // register our settings, if Lib_Config is present
        if (worldScripts.Lib_Config) {
            worldScripts.Lib_Config._registerSet(this._STCConfig);
        }
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerWillSaveGame = function() {
        if (worldScripts.Lib_Config) {
    	    missionVariables.Sothis_Config = JSON.stringify(this._config);
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.systemWillPopulate = function () {
    	this.$addSothis();
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.$addSothis = function () { 
    	//add sothis to corporate states
    	//Ask spawn permission from Station Validator oxp
    	if (worldScripts.station_validator && (worldScripts.station_validator.$deaths("sothis").length !== 0))
    		return;
    
    	if ((system.government >= this._config.minGov && system.government <= this._config.maxGov) &&
    		(system.techLevel >= this._config.minTL && system.techLevel <= this._config.maxTL) && 
    		(system.economy >= this._config.minEco && system.economy <= this._config.maxEco) && 
    		(system.productivity >= this._config.minProd && system.productivity <= this._config.maxProd) && 
    		system.mainStation) {
    		var a = system.mainStation.position.x;
    		var b = system.mainStation.position.y;
    		var c = 1.5 * system.mainStation.position.distanceTo(system.mainPlanet);
    		var x = - b * c / Math.sqrt(b * b + a * a);
    		var y = a * c / Math.sqrt(b * b + a * a);
    		var z = system.mainStation.position.z;
    		var exactPosition = [x, y, z];
    		system.setPopulator("sothis_tc", {
    			callback: function (pos) {
    				system.addShips("sothis", 1, pos, 0);
    			}.bind(this),
    			location: "COORDINATES",
    			coordinates: exactPosition,
    			deterministic: true
    		})
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipDockedWithStation = function (station) { 
    	//give special welcome screen when docking at sothis
    	if (station.hasRole("sothis")) {
    		this.$showWelcome = true;
    		if (this.$new_cargoes) { 
    			//give access to tradenet when visiting sothis
    			if (player.ship.equipmentStatus("EQ_CTE_TRADERNET") != "EQUIPMENT_OK") {
    				this.$tc_eqTradenet = false;
    				player.ship.awardEquipment("EQ_CTE_TRADERNET");
    				missionVariables.cargotypeextension_tradernet = clock.days + 30;
    			} else
    				this.$tc_eqTradenet = true;
    		}
    	}
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.missionScreenOpportunity = function () {
    	if (!this.$showWelcome) return;
    	var messText = expandDescription("[STC_welcome]");
    	if (this.$new_cargoes)
    		messText = messText + expandDescription("[STC_new_cargoes]");
    	var tcbgpic = "OOmap_G" + (galaxyNumber + 1) + ".png";
    	mission.runScreen({
    		screenID: "sothis",
    		title: "Sothis Trade Center",
    		message: messText,
    		background: {name: tcbgpic, height:546 }
    	});
    	this.$showWelcome = false;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.playerBoughtEquipment = function (equipment) { 
    	//check for tradernet
    	if (equipment == "EQ_CTE_TRADERNET")
    		this.$tc_eqTradenet = true;
    	else if (equipment == "EQ_CTE_TRADERNET_RENEWAL")
    		this.$tc_eqTradenet = true;
    }
    
    //-------------------------------------------------------------------------------------------------------------
    this.shipLaunchedFromStation = function (station) { 
    	//remove tradernet on launch from sothis if not bought
    	if (this.$new_cargoes && station.hasRole("sothis")) {
    		if (!this.$tc_eqTradenet) {
    			player.ship.removeEquipment("EQ_CTE_TRADERNET");
    			delete missionVariables.cargotypeextension_tradernet;
    		}
    	}
    }
    
    Scripts/sothis_market.js
    "use strict";
    this.name = "sothis-station-market";
    
    //put the original defs here. no def is handled later.
    this.$originalDefs = {
    	"food" : [0, 0, 25, -1, -1, 250, 5, 5, 0],
    	"textiles" : [0, 0, 18, -1, 0, 250, 5, 10, 0],
    	"radioactives" : [0, 0, 53, -2, -3, 0, 7, 15, 0],
    	"slaves" : [0, 0, 20, -2, -1, 5, 0, 3, 0],
    	"liquor_wines" : [0, 0, 130, -1, -1, 250, 15, 5, 0],
    	"luxuries" : [0, 0, 190, 8, -1, 250, 9, 21, 0],
    	"narcotics" : [0, 0, 36, -5, -9, 250, 5, 5, 0],
    	"computers" : [0, 0, 150, 14, -1, 250, 3, 21, 0],
    	"machinery" : [0, 0, 120, 6, 1, 250, 31, 10, 0],
    	"alloys" : [0, 0, 88, 3, 1, 250, 21, 10, 0],
    	"firearms" : [0, 0, 100, 13, 0, 0, 63, 0, 0],
    	"furs" : [0, 0, 170, -9, -1, 250, 63, 21, 0],
    	"minerals" : [0, 0, 16, -1, -2, 15, 3, 31, 0],
    	"gold" : [0, 0, 100, 0, 0, 0, 4, 0, 1],
    	"platinum" : [0, 0, 181, 0, 0, 0, 21, 0, 1],
    	"gem_stones" : [0, 0, 50, 0, 0, 0, 10, 0, 2],
    	"alien_items" : [0, 0, 125, 1, 0, 0, 31, 0, 0]
    };
    
    this.updateLocalCommodityDefinition = function (goodDefinition, station, sysID) {
    	var commodity = goodDefinition.key;
    	var oldDefs = this.$originalDefs[commodity];
    
    	if (!station || !station.hasRole("sothis")) return goodDefinition;
    
    	//define the market size for the station
    	goodDefinition.capacity = 63;
    	var soth = worldScripts["Spawn-sothis"];
    	if (!soth) return goodDefinition;
    	var conf = soth._config;
    	if (!conf) return goodDefinition;
    
    	//old style definition found for the good. calculate it the old way
    	if (conf.marketType == 1 && oldDefs) {
    		var market_base_price = oldDefs[2];
    		var market_eco_adjust_price = oldDefs[3];
    		var market_eco_adjust_quantity = oldDefs[4];
    		var market_base_quantity = oldDefs[5];
    		var market_mask_price = oldDefs[6];
    		var market_mask_quantity = oldDefs[7];
    		var market_rnd = Math.floor(Math.random() * 256);
    
    		var economy = system.economy;
    
    		var price = (market_base_price + (market_rnd & market_mask_price) + (economy * market_eco_adjust_price)) & 255;
    		price *= 0.4;
    
    		var quantity = (market_base_quantity + (market_rnd & market_mask_quantity) - (economy * market_eco_adjust_quantity)) & 255;
    		if (quantity > 127) quantity = 0;
    
    		quantity &= 63;
    
    		goodDefinition.quantity = quantity;
    		goodDefinition.price = price * 10;
    	}
    	//type 2: just add some variance to the system market (+/-5%)
    	else if (conf.marketType == 2) {
    		goodDefinition.price = goodDefinition.price * (1.05 - Math.random() * 0.1);
    		goodDefinition.quantity = Math.floor(goodDefinition.quantity * (1.05 - Math.random() * 0.1));
    	}
    	// type 3: oolite-business trade goods only
    	else if (conf.marketType == 3) {
    		if (goodDefinition.classes.indexOf("oolite-business") >= 0) {
    			// from the shipdata market_definition
    			//{ type = "class"; name = "oolite-business"; price_multiplier = 1.2; price_randomiser = 0.3; quantity_multiplier = 0.7; quantity_randomiser = 0.4; }, 			
    			goodDefinition.price *= (1.2 + (0.3 * (Math.random() * 2 - 1)));
    			goodDefinition.quantity *= (0.7 + (0.4 * (Math.random() * 2 - 1)));
    		} else {
    			goodDefinition.price = 0;
    			goodDefinition.quantity = 0;
    			goodDefinition.capacity = 0;
    		}
    	}
    	//type 0: no market 
    	else if (conf.marketType == 0) {
    		goodDefinition.price = 0;
    		goodDefinition.quantity = 0;
    		goodDefinition.capacity = 0;
    	}
    
    	//scale down if quantity too high
    	if (goodDefinition.quantity > goodDefinition.capacity)
    		goodDefinition.quantity = Math.floor(goodDefinition.quantity / 127 * goodDefinition.capacity);
    
    	return goodDefinition;
    };
    Scripts/sothis_stn_script.js
    "use strict";
    this.name = "sothis_stn_script.js";
    this.author = "Eric Walsh";
    this.copyright = "Do what you want with it";
    this.description = "Realigns station and adds buoy";
    this.version = "1.0";
    
    this.shipSpawned = function () {
        var targetVector = system.mainPlanet.position.subtract(this.ship.position).direction();
        var angle = this.ship.heading.angleTo(targetVector);
        var cross = this.ship.heading.cross(targetVector).direction();
        // align the heading to the targetVector
        this.ship.orientation = this.ship.orientation.rotate(cross, -angle);
    
        //system.legacy_addShipsAtPrecisely("sothisbuoy", 1, "abs", this.ship.position.add(this.ship.heading.multiply(10E3)));
        system.addShips("sothisbuoy", 1, this.ship.position.add(this.ship.heading.multiply(10E3)));
        delete this.shipSpawned;
    }
    
    Scripts/sothis_tc_new_cargoes.js
    "use strict";
    this.name = "sothis_tc_new_cargoes";
    this.author = "spara";
    this.copyright = "2013 Mika Spåra";
    this.licence = "CC-BY-SA 3.0";
    this.version = "1.0";
    this.description = "Sothis new cargoes market definition";
    
    this.startUp = function () {
    	if (!worldScripts.CargoTypeExtension || !worldScripts["Spawn-sothis"]) {
    		for (var prop in this) {
    			if (prop !== "name" && prop !== "version" && prop != "oolite_manifest_identifier") {
    				delete this[prop];
    			}
    		}
    		return;
    	} else {
    		worldScripts["CargoTypeExtension"].registerOXPStation(this.name, "sothis");
    	}
    }
    
    this.exportCargoAmount = function (good) {
    	return 2;
    }
    
    this.exportCargoPrice = function (good) {
    	return 1.05;
    }
    
    this.importCargoPrice = function (good) {
    	return 0.95;
    }
    
    this.randomCargoAmount = function (good) {
    	return 5;
    }
    
    this.randomCargoChance = function (good) {
    	return 2;
    }
    
    this.randomImportChance = function (good) {
    	return 0.01;
    }
    
    this.systemImportChance = function (good) {
    	return 1;
    }
    
    this.importPermitCheck = function () {
    	return true;
    }
    
    this.exportPermitCheck = function () {
    	return true;
    }
    
    this.stationGossip = function () {
    	var randomizeGossip = Math.floor((Math.random() * 2) + 1);
    	switch (randomizeGossip) {
    		case 2: return expandDescription("[STC_gossip]");
    	}
    }