Back to Index Page generated: Jun 26, 2025, 4:38:07 AM

Expansion Quick-Visa

Content

Warnings

  1. http://wiki.alioth.net/index.php/Quick-Visa -> 404 Not Found
  2. Required Expansions mismatch between OXP Manifest and Expansion Manager at character position 0058 (DIGIT ZERO vs LATIN SMALL LETTER N)
  3. Information URL mismatch between OXP Manifest and Expansion Manager string length at character position 0
  4. No version in dependency reference to oolite.oxp.Day.Diplomacy:null
  5. No version in dependency reference to oolite.oxp.phkb.BroadcastCommsMFD:null

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Adds Quick-Visa Service stations to witchpoints, and alerts the player, when arriving in a system, whether visa are required at system stations. Adds Quick-Visa Service stations to witchpoints, and alerts the player, when arriving in a system, whether visa are required at system stations.
Identifier oolite.oxp.phkb.QuickVisa oolite.oxp.phkb.QuickVisa
Title Quick-Visa Quick-Visa
Category Miscellaneous Miscellaneous
Author phkb phkb
Version 1.3 1.3
Tags
Required Oolite Version
Maximum Oolite Version
Required Expansions
  • oolite.oxp.Day.Diplomacy:0
  • oolite.oxp.phkb.BroadcastCommsMFD:0
  • oolite.oxp.Day.Diplomacy:
  • oolite.oxp.phkb.BroadcastCommsMFD:
  • Optional Expansions
    Conflict Expansions
    Information URL n/a
    Download URL https://wiki.alioth.net/img_auth.php/5/55/QuickVisa.oxz n/a
    License CC-BY-SA-NC 4.0 CC-BY-SA-NC 4.0
    File Size n/a
    Upload date 1749031693

    Documentation

    readme.txt

    Quick-Visa
    by phkb
    
    Overview
    ========
    This mod does two things. Firstly, if the player doesn't have a citizenship or a valid visa when they arrive in a new system, it will warn the player that a visa is required for docking at system stations.
    
    Additionally, it adds "Quick-Visa Self-Service" stations near the witchpoint, which allow the player to purchase 24h, 48h or 72h visas for the current system, at a substantially inflated price.
    
    Operation
    =========
    To use the Quick-View Self-Service station, approach the station until you are within 1km of it. At that point, Broadcast Comms options will become available, allowing you to select 1 of three different options: Purchase a 24h visa, purchase a 48h visa, or purchase a 72h visa. Select the desired option using the Broadcast Comms MFD, and transmit. After a few seconds, you should see a response that your visa was approved and the credits have been deducted.
    
    Backstory
    =========
    It's the bane of many a pilot's life. In a hurry to reach a destination, they launch and jump into a new system, completely forgetting that a visa is required. They jet along the spacelane to the main station, only to discover, to their horror, that they would be denied entry.
    
    Into this dilemma came Quick-Visa, a startup conceived with this one issue in mind. Based in the Galaxy 4 system of Edorqu, the trio of entrepreneurs who funded the initial investment, discovered there could be a solution that was both beneficial to the systems requiring visas, and lucrative enough to fund the massive outlays envisaged. Initial tests confirmed their analysis that pilots would be willing to pay a significant amount over the normal visa cost to avoid the other hassles of not having one.
    
    They began by reaching out, through diplomatic channels, to many of the communist and dictatorship systems in their own corner of the galaxy. Would they be interested in getting additional income, at almost no cost to them, while providing a benefit to incoming traders? Understandably, given those terms, many were willing to participate in a trial.
    
    And so the rollout began. Old communication stations were repurposed, chosen largely because they were so cheap and had enough existing technology on board, given a shiny new coat of paint, and deposited near the witchpoint of some carefully selected systems.
    
    No one could have predicted just how effective they were. Within just a few days, not only had they been able to pay for the stations already purchased and issue massive payments to the governments they were deployed in, they were scrambling to answer all the diplomatic calls they were receiving. Could they deploy the system there? How quickly could they get it set up? 
    
    Money was being thrown at them from a variety of directions, and in a short amount of time the system was rolled out across all the charts. The start-up out-grew it's original offices and moved to a private station of their own design in a far off (and secret) corner of the galaxy, and the money just continued to roll in.
    
    Everyone was happy - the governments, the investors, and, to a certain degree, the pilots who kept paying for the over-priced visas. It was certainly cheaper than getting a fine at the station, and quicker than doing a fuel-scooping run to the sun. 
    
    Requirements
    ============
    The Diplomacy OXP is required, as it is the mod which controls visas and citizenships.
    The Broadcast Comms OXP is required to communicate with the Quick-Visa Self-Service stations.
    
    Licence
    =======
    This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 4.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
    
    Parts of the code were borrowed from Thargoids Fuel Stations OXP.
    The station model is taken from Ramirez's Iron Raven OXP.
    
    Version History
    ===============
    1.3
    - Fixed issue where moving away from the station would remove the BCC links, but not put them back if the player approaches for a second time.
    - Quick-Visa stations no longer mass lock the player.
    - Made station rotate for more visual interest.
    
    1.2
    - Turned of station naming for the Quick-Visa stations.
    - Fixed issue where visas purchased through Quick-Visa stations were not being recognised by PlanetFall2 locations.
    
    1.1
    - Tweaks to the Quick-Visa Self-Service station model.
    - Fixed invalid filename in shipdata.
    
    1.0
    - Initial release

    Equipment

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

    Ships

    Name
    Quick-Visa Self-Service
    Visa Station Box

    Models

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

    Scripts

    Path
    Config/script.js
    "use strict";
    this.name = "QuickVisa";
    this.author = "phkb";
    this.description = "Adds Quick-Visa Self Service stations and alerts player when visas are required at system stations.";
    this.copyright = "2025 phkb";
    this.license = "CC BY-NC-SA 4.0";
    
    this._settings = {
        _visaGov3PriceFactor: 50,
        _visaGov4PriceFactor: 50,
        _visaGov7PriceFactor: 50,
        _spawnGov3Stations: true,
        _spawnGov4Stations: true,
        _spawnGov7Stations: true,
        _enableWPMessages: true
    };
    
    this._visaConfig = {
        Name: this.name,
        Display: expandMissionText("visa_config_display"),
        Alias: expandMissionText("visa_config_alias"),
        Alive: "_visaConfig",
        Bool: {
            B0: { Name: "_settings._spawnGov3Stations", Def: true, Desc: expandMissionText("visa_config_spawn_gov3") },
            B1: { Name: "_settings._spawnGov4Stations", Def: true, Desc: expandMissionText("visa_config_spawn_gov4") },
            B2: { Name: "_settings._spawnGov7Stations", Def: true, Desc: expandMissionText("visa_config_spawn_gov7") },
            B3: { Name: "_settings._enableWPMessages", Def: true, Desc: expandMissionText("visa_config_wpmessages") }, 
            Info: expandMissionText("visa_config_bool_info")
        },
        SInt: {
            S0: { Name: "_settings._visaGov3PriceFactor", Def: 50, Min: 1, Max: 100, Desc: expandMissionText("visa_config_factor_gov3") },
            S1: { Name: "_settings._visaGov4PriceFactor", Def: 50, Min: 1, Max: 100, Desc: expandMissionText("visa_config_factor_gov4") },
            S2: { Name: "_settings._visaGov7PriceFactor", Def: 50, Min: 1, Max: 100, Desc: expandMissionText("visa_config_factor_gov7") },
            Info: expandMissionText("visa_config_sint_info")
        },
    };
    
    //----------------------------------------------------------------------------------------
    this.startUpComplete = function() {
        if (worldScripts.WireframeShipImages) {
            if (!worldScripts.WireframeShipImages._gameShips["Quick-Visa Self-Service"]) {
                worldScripts.WireframeShipImages._gameShips["Quick-Visa Self-Service"] = "fuel_station_ir";
            }
        }
        // register our settings, if Lib_Config is present
        if (worldScripts.Lib_Config) {
            worldScripts.Lib_Config._registerSet(this._visaConfig);
        }
        if (missionVariables.QuickView_Settings) {
            this._settings = JSON.parse(missionVariables.QuickView_Settings);
        }
    }
    
    //----------------------------------------------------------------------------------------
    this.playerWillSaveGame = function() {
        missionVariables.QuickView_Settings = JSON.stringify(this._settings);
    }
    
    //----------------------------------------------------------------------------------------
    this.systemWillPopulate = function() {
        var gov = system.government;
        if ((gov === 3 && this._settings._spawnGov3Stations) || 
            (gov === 4 && this._settings._spawnGov4Stations) || 
            (gov === 7 && this._settings._spawnGov7Stations)) { // dictator, communist, corporate
    		if (system.countShipsWithRole("visa-station") == 0) {
                // numbers between -1 and 1;
                var xf = (system.scrambledPseudoRandomNumber(277) * 2) - 1;
                var yf = (system.scrambledPseudoRandomNumber(377) * 2) - 1;
    			var stnPos = Vector3D(5000 * xf, 5000 * yf, 5000); 
    			system.setPopulator("visa-station", {
    				priority: 200,
    				location: "COORDINATES",
    				coordinates: stnPos,
    				groupCount: 1,
    				callback: function (pos) {
    					system.addShips("visa-station", 1, pos, 0);
    				},
    				deterministic: true
    			});
    		}
        }
    }
    
    //----------------------------------------------------------------------------------------
    this.shipExitedWitchspace = function() {
        if (!this._settings._enableWPMessages) return;
        function getWPBuoy(entity) {
            return (entity.isShip && (entity.hasRole("buoy-witchpoint") || (entity.isStation && entity.allegiance === "galcop")));
        }
        var dip = worldScripts.DayDiplomacy_060_Citizenships;
        if (!dip) return;
        var gov = system.government;
        if (gov === 3 || gov === 4 || gov === 7) { // dictator, communist, corporate
            if (!dip.$hasPlayerVisa(system.ID) && !dip.$hasPlayerCitizenship(galaxyNumber, system.ID)) {
                var targets = system.filteredEntities(this, getWPBuoy);
                if (targets.length > 0) {
                    for (var i = 0; i < targets.length; i++) {
                        targets[i].commsMessage(expandMissionText("visa_missing_alert"), player.ship);
                    }
                }
            }
        }
    }
    
    //----------------------------------------------------------------------------------------
    this.$updatePF2Docks = function() {
        var pf2 = system.shipsWithRole("planetFall2_surface");
        if (!pf2 || pf2.length == 0) return;
        for (var i = 0; i < pf2.length; i++) {
            var land = pf2[i];
            land.performedDockRequest = false;
        }
    }
    Scripts/visa-station.js
    "use strict";
    this.name = "VisaStation";
    this.author = "Thargoid, phkb";
    this.copyright = "Creative Commons: attribution, non-commercial, sharealike with clauses - see readme.txt";
    this.description = "Visa Station";
    this.version = "1.0";
    
    this._linksAdded = false;
    
    //----------------------------------------------------------------------------------------
    this.shipSpawned = function () { //  line the station up with the route one. Code borrowed from Anarchies for convenience.
    	this.ship.scannerDisplayColor1 = "greenColor";
    	this.ship.scannerDisplayColor2 = "darkGrayColor";
    
    	if (system.isInterstellarSpace || !system.mainPlanet) { return; }
    	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()
    	this.ship.orientation = this.ship.orientation.rotate(cross, -angle);
    	this.setPrice();
    }
    
    //----------------------------------------------------------------------------------------
    this.addBCCLinks = function() {
        this._linksAdded = true;
        // set up broadcast comms interface
        var bcc = worldScripts.BroadcastCommsMFD;
        if (bcc.$checkMessageExists("visa_24") === false) {
            bcc.$createMessage({
                messageName: "visa_24",
                callbackFunction: this.ship.script.doPurchase.bind(this, 24),
                displayText: "[" + expandMissionText("visa_bcc_item", {time: "24", price: formatCredits(this.visaPrice, false, true)}) + "]",
                messageText: "",
                ship: this.ship,
                transmissionType: "target",
                deleteOnTransmit: false,
                delayCallback: 0,
                hideOnConditionRed: true
            });
        }
        if (bcc.$checkMessageExists("visa_48") === false) {
            bcc.$createMessage({
                messageName: "visa_48",
                callbackFunction: this.ship.script.doPurchase.bind(this, 48),
                displayText: "[" + expandMissionText("visa_bcc_item", {time: "48", price: formatCredits(this.visaPrice * 2, false, true)}) + "]",
                messageText: "",
                ship: this.ship,
                transmissionType: "target",
                deleteOnTransmit: false,
                delayCallback: 0,
                hideOnConditionRed: true
            });
        }
        if (bcc.$checkMessageExists("visa_72") === false) {
            bcc.$createMessage({
                messageName: "visa_72",
                callbackFunction: this.ship.script.doPurchase.bind(this, 72),
                displayText: "[" + expandMissionText("visa_bcc_item", {time: "72", price: formatCredits(this.visaPrice * 3, false, true)}) + "]",
                messageText: "",
                ship: this.ship,
                transmissionType: "target",
                deleteOnTransmit: false,
                delayCallback: 0,
                hideOnConditionRed: true
            });
        }
    }
    
    //----------------------------------------------------------------------------------------
    this.removeBCCLinks = function() {
        this._linksAdded = false;
        var bcc = worldScripts.BroadcastCommsMFD;
        bcc.$removeMessage("visa_24");
        bcc.$removeMessage("visa_48");
        bcc.$removeMessage("visa_72");
    }
    
    //----------------------------------------------------------------------------------------
    this.doPurchase = function(time) {
        // don't let the player accidentally do it twice
        if (this._payTimer && this._payTimer.isRunning) return;
        this.$playSound();
        player.consoleMessage(expandMissionText("visa_bcc_initiated", {time: time.toString()}), 4);
        switch (time) {
            case 24: this._payTimer = new Timer(this, this.purchase.bind(this, 24), 4, 0); break;
            case 48: this._payTimer = new Timer(this, this.purchase.bind(this, 48), 4, 0); break;
            case 72: this._payTimer = new Timer(this, this.purchase.bind(this, 72), 4, 0); break;
        }
    }
    
    //----------------------------------------------------------------------------------------
    this.purchase = function(length) {
        if (player.credits > this.visaPrice) {
            var dip = worldScripts.DayDiplomacy_060_Citizenships;
            player.credits -= this.visaPrice;
            for (var i = 0; i < length / 24; i++) {
                dip._add1DayVisa(system.ID);
            }
            worldScripts.QuickVisa.$updatePF2Docks();
            player.consoleMessage(expandMissionText("visa_bcc_complete", {time: length.toString(), price: formatCredits(this.visaPrice, false, true)}), 6);
        } else {
            player.consoleMessage(expandMissionText("visa_bcc_low_credits"), 6);
        }
        this._payTimer = null;
    }
    
    //----------------------------------------------------------------------------------------
    this.setPrice = function () {
        this.visaPrice = worldScripts["DayDiplomacy_060_Citizenships"].$getVisaPrice(system.info);
        switch (system.government) {
            case 3: this.visaPrice *= worldScripts.QuickVisa._settings._visaGov3PriceFactor; break
            case 4: this.visaPrice *= worldScripts.QuickVisa._settings._visaGov4PriceFactor; break
            case 7: this.visaPrice *= worldScripts.QuickVisa._settings._visaGov7PriceFactor; break
        }
        this.visaPrice = parseInt(this.visaPrice);
    }
    
    //----------------------------------------------------------------------------------------
    this.playerDetected = function () {
        if (this.scanTimer && this.scanTimer.isRunning) this.scanTimer.stop();
    	if (!this.firstMessage) {
            this.firstMessage = true;
            this.messageTimer = new Timer(this, this.sendInitialMessage.bind(this), 5, 0);
        }
    	if (this.scanTimer) {
    		this.scanTimer.start();
    	} else {
    		this.scanTimer = new Timer(this, this.locatePlayer, 0, 0.50);
    	}
    }
    
    //----------------------------------------------------------------------------------------
    this.sendInitialMessage = function() {
        var dip = worldScripts.DayDiplomacy_060_Citizenships;
        if (dip.$hasPlayerCitizenship(galaxyNumber, system.ID)) return;
    
    	var msg = expandMissionText("visa_station_greeting", {price: formatCredits(this.visaPrice, false, true)});
    	this.ship.commsMessage(msg, player.ship);
    }
    
    //----------------------------------------------------------------------------------------
    this.locatePlayer = function () {
    	if (!this.ship || !this.ship.isValid || !this.ship.position || !player.ship.isValid) { // if the ship no longer exists but timer is running, e.g. if player has jumped whilst near a satellite into a system without one
    		this.playerGone();
    		return;
    	}
    
    	if (this.ship.position.distanceTo(player.ship.position) < 1000) { // player ship within 1000m of the centre of the satellite
    		if (this.firstMessage) {
                this.firstMessage = false;
                // only allow visas to be purchased if the player is not a citizen
                var dip = worldScripts.DayDiplomacy_060_Citizenships;
                if (dip.$hasPlayerCitizenship(galaxyNumber, system.ID)) return;
    
                player.consoleMessage(expandMissionText("visa_station_helper"), 10);
            }
            this.addBCCLinks();
    	} else {
            if (this._linksAdded) this.removeBCCLinks();
        }
    }
    
    //----------------------------------------------------------------------------------------
    this.playerWillEnterWitchspace = this.playerGone = function () {
    	if (this.scanTimer) {
            this.removeBCCLinks();
    		this.scanTimer.stop();
    		delete this.scanTimer;
    	}
    }
    
    //----------------------------------------------------------------------------------------
    this.shipDied = function (whom, why) {
    	this.playerGone();
    
    	if (whom && whom.isPlayer) {
    		player.consoleMessage(expandMissionText("visa_died_message"), 6);
    		player.score -= 1; // don't condone vandalism!
    		player.bounty += 20;
    	}
    }
    
    //----------------------------------------------------------------------------------------
    this.attackedMessage = function () {
    	this.ship.commsMessage(expandMissionText("visa_station_attacked"));
    }
    
    //----------------------------------------------------------------------------------------
    this.$playSound = function() {
    	var mySound = new SoundSource;
        mySound.sound = "[@click]";
    	mySound.loop = false;
    	mySound.volume = 0.5;
    	mySound.play();
    }