Back to Index Page generated: Dec 20, 2024, 7:22:09 AM

Expansion Pirate Cove

Content

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Adds pirate bases to the system that are situated in rock hermits. Adds pirate bases to the system that are situated in rock hermits.
Identifier oolite.oxp.EricWalch.PirateCove oolite.oxp.EricWalch.PirateCove
Title Pirate Cove Pirate Cove
Category Ambience Ambience
Author Lazy Gun & Eric Walch Lazy Gun & Eric Walch
Version 2.0.1 2.0.1
Tags Hermits, Pirates Hermits, Pirates
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
Conflict Expansions
Information URL http://wiki.alioth.net/index.php/Pirate_Coves_OXP n/a
Download URL https://wiki.alioth.net/img_auth.php/e/ec/PirateCoves_2.0.oxz n/a
License CC-BY-NC-SA 3.0 CC-BY-NC-SA 3.0
File Size n/a
Upload date 1716768630

Documentation

Also read http://wiki.alioth.net/index.php/Pirate%20Cove

Equipment

This expansion declares no equipment.

Ships

Name
pirate-cove
pirate-cove-chaotic
pirate-cove-pirate
pirate-cove-single

Models

This expansion declares no models.

Scripts

Path
Scripts/pirateCove.js
"use strict";
this.name = "Pirate_Coves";
this.author = "lazygun (JS adaption by EW)";
this.copyright = "lazygun";
this.description = "Adds pirate coves to the system.";
this.version = "2.0";

this._spawning = {
    neutral: {replace:true, chance:0.25}, // should be equivalent to roles = "rockhermit(0.25)";
    chaotic: {replace:false, chance:0.25},
    pirate: {replace:false, chance:0.25},
    single: {
        allowed: true,
        sampleAtDiso: true,
        // max min range calculate
        // if max = 0.3 and min = 0.1, range will be from -0.3 to -0.1 or from +0.1 to +0.3
        xRange: {max: 0.3, min: 0.1},
        yRange: {max: 0.3, min: 0.1},
        zRange: {max: 0.4, min: 0.1}
    }
}

// configuration settings for use in Lib_Config
this._pcConfig = {
	Name: this.name,
	Alias: "Pirate Coves",
	Display: "RH replace spawning options",
	Alive: "_pcConfig",
	Bool: {
		B0: {Name: "_spawning.neutral.replace", Def: true, Desc: "Allow neutral RH replacement"},
		B1: {Name: "_spawning.chaotic.replace", Def: false, Desc: "Allow chaotic RH replacement"},
		B2: {Name: "_spawning.pirate.replace", Def: false, Desc: "Allow pirate RH replacement"},
        Info: "0 - Allows pirate coves to replace neutral Rock Hermits\n" + 
            "1 - Allows pirate coves to replace chaotic Rock Hermits\n" + 
            "2 - Allows pirate coves to replace pirate Rock Hermits"
	},
	SInt: {
		S0: {Name: "_spawning.neutral.chance", Def: 0.25, Min: 0.0, Max: 100, Desc: "Neutral RH replace chance", Float:true},
		S1: {Name: "_spawning.chaotic.chance", Def: 0.25, Min: 0.0, Max: 100, Desc: "Chaotic RH replace chance", Float:true},
		S2: {Name: "_spawning.pirate.chance", Def: 0.25, Min: 0.0, Max: 100, Desc: "Pirate RH replace chance", Float:true},
		Info: "0 - Chance of replacing neutral Rock Hermits (eg 0.25 = 25% chance)\n" +
            "1 - Chance of replacing chaotic Rock Hermits\n" + 
            "2 - Chance of replacing pirate Rock Hermits"
	}
};

this._singleConfig = {
    Name: this.name,
    Alias: "Pirate Coves",
    Display: "Single PC spawning options",
    Alive: "_singleConfig",
    Bool: {
        B0: {Name: "_spawning.single.allowed", Def: true, Desc: "Allow single Pirate Coves"},
        B1: {Name: "_spawning.single.sampleAtDiso", Def: true, Desc: "Ensure PC @ Diso (G1)"},
        Info: "0 - Allows pirate coves to created on their own\n1 - Ensures there's a Pirate Cove at Diso in G1."
    },
    SInt: {
        S0: {Name: "_spawning.single.xRange.max", Def:0.3, Min:0.01, Max: 1, Desc: "X-axis +/- max range for single", Float:true},
        S1: {Name: "_spawning.single.xRange.min", Def:0.0, Min:0.0, Max: 1, Desc: "X-axis +/- min range for single", Float:true},
        S2: {Name: "_spawning.single.yRange.max", Def:0.3, Min:0.01, Max: 1, Desc: "Y-axis +/- max range for single", Float:true},
        S3: {Name: "_spawning.single.yRange.min", Def:0.0, Min:0.0, Max: 1, Desc: "Y-axis +/- min range for single", Float:true},
        S4: {Name: "_spawning.single.zRange.max", Def:0.4, Min:0.1, Max: 0.8, Desc: "Z-axis max range for single", Float:true},
        S5: {Name: "_spawning.single.zRange.min", Def:0.1, Min:0.05, Max: 0.5, Desc: "Z-axis min range for single", Float:true},
        Info: "Range values when spawning single pirate cove.\nX and Y axis values could be + or -. Z axis is only +:\n" + 
            "Calculation is (when +) 'RND * (max - min) + min' or (when -) 'RND * (-max + min) - min'"
    }
};

//-------------------------------------------------------------------------------------------------------------
this.startUp = function () {
    if (missionVariables.pirate_cove_spawning) {
        this._spawning = JSON.parse(missionVariables.pirate_cove_spawning);
    }
    // restore the systems were a pirate cove is missing
    if (missionVariables.pirate_cove_systems) {
        this.pirateCoveSystems = JSON.parse(missionVariables.pirate_cove_systems);
    } else {
        this.pirateCoveSystems = new Array(256);
    }

    this.basicDefenders = Math.round(Math.log(1 + player.score));
};

//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function() {
	// register our settings, if Lib_Config is present
	if (worldScripts.Lib_Config) {
        worldScripts.Lib_Config._registerSet(this._pcConfig);
        worldScripts.Lib_Config._registerSet(this._singleConfig);
    }
}

//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function () {
    // encode the systems were a pirate cove is missing
    missionVariables.pirate_cove_systems = JSON.stringify(this.pirateCoveSystems);
    missionVariables.pirate_cove_spawning = JSON.stringify(this._spawning);
}

//-------------------------------------------------------------------------------------------------------------
this.playerEnteredNewGalaxy = function () {
    // reset the systems
    this.pirateCoveSystems = new Array(256);
}

//-------------------------------------------------------------------------------------------------------------
this.systemWillPopulate = function () {
    // Test for [System.countShipsWithRole("pirate-cove") == 0] because the populator might already have added them as rock hermit replacement.
    if (!system.isInterstellarSpace && system.countShipsWithRole("pirate-cove") === 0 && !system.sun.hasGoneNova && this._spawning.single.allowed) {
        this.$addRockHermit();
    }
};

//-------------------------------------------------------------------------------------------------------------
this.$initialiseSystem = function () {
    // initialise
    if (system.countShipsWithPrimaryRole("pirate") > 9) {
        this.pirateCoveSystems[system.ID] = false; // allow stations until killed.
    } else {
        this.pirateCoveSystems[system.ID] = clock.days; // don't allow a station for the next 20 days.
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$addRockHermit = function () {
    var coordinateSystem = (this.$randomZ() < 0.1) ? "psu" : "wpu";
    
    // get the x axis range
    var xRangeMax = this._spawning.single.xRange.max;
    // ensure range will be valid
    if (this._spawning.single.xRange.min > xRangeMax) this._spawning.single.xRange.min = 0;
    var xRangeMin = this._spawning.single.xRange.min;
    
    // get the y-axis range
    var yRangeMax = this._spawning.single.yRange.max;
    // ensure range will be valid
    if (this._spawning.single.yRange.min > yRangeMax) this._spawning.single.yRange.min = 0;
    var yRangeMin = this._spawning.single.yRange.min;
    
    // get the z-axis range
    var zRangeMax = this._spawning.single.zRange.max;
    // ensure range will be valid
    if (this._spawning.single.zRange.min > zRangeMax) this._spawning.single.zRange.min = 0.1;
    var zRangeMin = this._spawning.single.zRange.min;
    
    // 50% chance or either a positive or negative range
    var x = (this.$randomX() > 0.5 ? this.$randomX() * (xRangeMax - xRangeMin) + xRangeMin : this.$randomX() * ((xRangeMax * -1) - (xRangeMin * -1)) - xRangeMin);
    var y = (this.$randomY() > 0.5 ? this.$randomY() * (yRangeMax - yRangeMin) + yRangeMin : this.$randomY() * ((yRangeMax * -1) - (yRangeMin * -1)) - yRangeMin);
    // z range is always positive
    var z = this.$randomZ() * (zRangeMax - zRangeMin) + zRangeMin;
    
    var stnPos = Vector3D(x, y, z).fromCoordinateSystem(coordinateSystem);

    system.setPopulator("piratecove", {
        callback: function(pos) {
            var ws = worldScripts["Pirate_Coves"];
            var isDead = ws.pirateCoveSystems[system.ID];
            if (isDead == undefined || (isDead && (isDead + 20 < clock.days))) {
                ws.$initialiseSystem();
            }
            // make sure diso has a separate pirate cove
            if (galaxyNumber == 0 && system.ID == 147 && ws._spawning.single.sampleAtDiso == true) {
                ws.pirateCoveSystems[system.ID] = false;
            }

            if (!ws.pirateCoveSystems[system.ID]) {
                log("piratecove-populator", "adding pirate cove to system");
                var station = system.addShips("[pirate-cove-single]", 1, pos, 0)[0];
                station.orientation = [1, 0, 0, 0]; // orientate it along the z-axis like oolite hermits.
                var asteroidCount = Math.ceil(3 + ws.$randomZ() * 8);
                system.addShips("asteroid", asteroidCount, pos, 15000);
            }
        },
        location:"COORDINATES",
        coordinates: stnPos,
        deterministic: true 
    });
};

//-------------------------------------------------------------------------------------------------------------
this.$randomZ = function () {
    // return mostly the same value, but change over time.
    var salt = (clock.days & 0xE0) + 15; // change once every 32 days
    return system.scrambledPseudoRandomNumber(salt);
};

//-------------------------------------------------------------------------------------------------------------
this.$randomX = function () {
    var salt = (clock.days & 0xE0) + 20; // change once every 32 days
    return system.scrambledPseudoRandomNumber(salt);
}

//-------------------------------------------------------------------------------------------------------------
this.$randomY = function () {
    var salt = (clock.days & 0xE0) + 25; // change once every 32 days
    return system.scrambledPseudoRandomNumber(salt);
}
Scripts/pirateCoveConditions.js
"use strict";
this.name = "pirate_cove_conditions";
this.author = "phkb";
this.copyright = "2023 phkb";
this.license = "CC BY-NC-SA 4.0";

//-------------------------------------------------------------------------------------------------------------
this.allowSpawnShip = function(shipkey) {
    var typ = "";
    switch (shipkey) {
        case "pirate-cove":
            typ = "neutral";
            break;
        case "pirate-cove-chaotic":
            typ = "chaotic";
            break;
        case "pirate-cove-pirate":
            typ = "pirate";
            break;
        default:
            return false;
    }
    var pc = worldScripts.Pirate_Coves;
    if (!pc._spawning[typ].replace) return false;
    var chance = pc._spawning[typ].chance;
    // if the following returns true, it will be true for a whole month
    // so if you jump back into the system inside of a month, the same RH should be switched to a pirate cove
    if (system.scrambledPseudoRandomNumber((clock.daysComponent / 30) % 12 + this.$rockHermitSeedVariation(typ)) < chance) return true;
    return false;
}

//----------------------------------------------------------------------------------------
// get a different seed value for each type, so they will be checked independently of each other
this.$rockHermitSeedVariation = function(typ) {
    switch (typ) {
        case "neutral": return system.countShipsWithRole("rockhermit");
        case "chaotic": return system.countShipsWithRole("rockhermit-chaotic") + 10;
        case "pirate": return system.countShipsWithRole("rockhermit-pirate") + 20;
    }
    return 0;
}
Scripts/pirateCoveMarket.js
"use strict";
this.name = "pirate_cove_market";
this.author = "phkb";
this.copyright = "2023 phkb";
this.license = "CC BY-NC-SA 4.0";

this.$originalDefs = {
	"food": [0, 0, 20, -1, 0, 0, 1, 0, 0],
	"textiles": [0, 0, 20, -1, 0, 0, 3, 0, 0],
	"radioactives": [0, 0, 42, -3, -3, 1, 7, 3, 0],
	"slaves": [0, 0, 40, -5, 0, 0, 15, 0, 0],
	"liquor_wines": [0, 0, 105, -5, 0, 0, 15, 0, 0],
	"luxuries": [0, 0, 236, 8, 0, 0, 3, 0, 0],
	"narcotics": [0, 0, 235, 29, 0, 0, 120, 0, 0],
	"computers": [0, 0, 150, 14, 0, 0, 3, 0, 0],
	"machinery": [0, 0, 120, 6, 0, 0, 7, 0, 0],
	"alloys": [0, 0, 70, 1, 0, 0, 31, 2, 0],
	"firearms": [0, 0, 130, 13, 0, 29, 7, 0, 0],
	"furs": [0, 0, 160, -9, 0, 0, 63, 0, 0],
	"minerals": [0, 0, 16, -1, -1, 85, 3, 3, 0],
	"gold": [0, 0, 73, -1, -1, 5, 7, 3, 1],
	"platinum": [0, 0, 145, -2, -2, 6, 31, 7, 1],
	"gem_stones": [0, 0, 25, -1, -1, 250, 15, 15, 2],
	"alien_items": [0, 0, 140, 1, 0, 0, 3, 0, 0]
};

//-------------------------------------------------------------------------------------------------------------
this.updateLocalCommodityDefinition = function (goodDefinition) {
	var commodity = goodDefinition.key;
	var oldDefs = this.$originalDefs[commodity];
	//old style definition found for the good. calculate it the old way
	if (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.price = price * 10;
		goodDefinition.quantity = quantity;
	}
	//no definition found. nullify the goods.
	else {
		goodDefinition.price = 0;
		goodDefinition.quantity = 0;
	}
	return goodDefinition;
};
Scripts/pirateCoveRock.js
"use strict";
this.name = "Pirate Cove Rock";
this.author = "eric walch";
this.description = "Script for the Pirate_Cove Rock by Lazy Gun";
this.version = "1.5";

this.defenderCount = worldScripts["Pirate_Coves"].basicDefenders + Math.floor(Math.random() * 3);  // defenderCount is redefined by the main script.

//-------------------------------------------------------------------------------------------------------------
this.shipSpawned = function () {
    if (this.ship.dataKey !== "pirate-cove-single") log(this.name, "pirate cove replacing rock hermit for role " + this.ship.primaryRole);
    //this.ship.primaryRole = "pirate-cove"; // needed to set the market correct. << not needed now
    this.maxAirbornDefenders = 3 + Math.floor(Math.random() * 4);
    if (player.score > 512) this.maxAirbornDefenders++;
    if (player.score > 6400) this.maxAirbornDefenders++;
}

//-------------------------------------------------------------------------------------------------------------
// Correct clean hits.
this.shipBeingAttacked = function (attacker) {
    if (attacker && attacker.owner === this.ship && attacker.target === this.ship) {
        attacker.reactToAIMessage("TARGET_LOST");
        log(this.name, "Pirate cove was friendly hit by: " + attacker.displayName);
    }
}

//-------------------------------------------------------------------------------------------------------------
this.stationLaunchedShip = function (ship) {
    if (ship.primaryRole === "defense_ship") ship.switchAI("pirateCovePirateAI.plist");
    if (ship.primaryRole === "scavenger" && !ship.bounty) ship.bounty = 5 + Math.random() * 25;
    if (ship.primaryRole === "escort" && !ship.bounty) ship.bounty = 5 + Math.random() * 15;
}

//-------------------------------------------------------------------------------------------------------------
this.otherShipDocked = function (ship) {
    if (ship.isPlayer) {
        // we are spotted!
        this.ship.displayName.replace("Rock Hermit", "Pirate Cove"); 
    }
    if (ship.primaryRole == "pirate") this.defenderCount++;
}

//-------------------------------------------------------------------------------------------------------------
/*
In addition to the below launched pirates, the AI can also launch pirates as defense ships
when directly attacked.
*/
this.$launchDefender = function () {
    if (this.defenderCount > 0 && this.ship.target
        && this.ship.position.distanceTo(this.ship.target.position) < 15000
        && this.ship.group.count < this.maxAirbornDefenders) {
        var defender = this.ship.launchShipWithRole("pirate");
        if (defender) {
            defender.switchAI("pirateCovePirateAI.plist");
            defender.target = this.ship.target;
            this.ship.group.addShip(defender);
            defender.group = this.ship.group;
            if (!this.ship.bounty && this.ship.target.isPlayer) {
                this.ship.bounty = (this.ship.scanClass == "CLASS_NEUTRAL") ? 100 : 1000; // the cove is no longer clean now.
            }
            this.defenderCount--;
        }
    }
};

//-------------------------------------------------------------------------------------------------------------
this.shipDied = function () {
    // store the time of death
    worldScripts.Pirate_Coves.pirateCoveSystems[system.ID] = clock.days;
};