| 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();
} |