MagicLib

From Starsector Wiki
Jump to navigation Jump to search

The goal of MagicLib is to create a community-built library of useful (and well documented) scripts and plugins that can be leveraged and contributed to by every modder.

It can be found at its forum page.

View MagicLib's javadoc here: https://magiclibstarsector.github.io/MagicLib/.

MagicSettings

MagicSettings offers tools to easily manage a unified cross-mods settings file, making mods inter-compatibility a much easier task to implement. Every mod can add their own externalized settings to the data/config/modSettings.json file, and use a single line of code to get them when needed. It also offer functions to merge lists and maps to easily make whitelists and blacklists that can be added to by each individual mod.

Settings that can be fetched:

boolean getBoolean(String modId, String id)
String getString(String modId, String id)
float getFloat(String modId, String id)
Integer getInteger(String modId, String id)
Color getColorRGB(String modId, String id)
Color getColorRGBA(String modId, String id)
List<String> getList(String modId, String id)
Map<String,Float> getFloatMap(String modId, String id)
Map<String,String> getStringMap(String modId, String id)
Map<String,Color> getColorMap(String modId, String id)

JSON formatting:

Json is a file format that can be a bit finicky. Make sure you use a proper formatting and avoid typos. A mod's section of modSettings.json should look like this:

{
    "modId":{
        "setting_A" : "value_A",
        "setting_list": [
            "list_element_A",
            "list_element_B",
        ],
        "setting_map": {
            "map_element_A":"map_value_A",
            "map_element_B":"map_value_B",
        },
    },
    "other_mod_compatibility":{
        "other_mod_whitelist":[
            "whitelist_element_A",
        ],
    },
}

It is important to remember that all parameter use quotes " ", as well as values except for numbers and boolean.

Lists use brackets [ ]

Maps use paragraphs { }

All lines break with a comma ,

Values are always separated from parameters with double dots :

modId should be your mod ID to ensure there is no name clash.

As of 0.95, the script loads the settings file on game launch then access that copy in memory when asked, making the script an order of magnitude faster. The settings can then be refreshed in dev mode using F8 like the other vanilla files.


Code example:

public class DAModPlugin extends BaseModPlugin {
    public static List<String> DERECHO_RESIST = new ArrayList<>();
    public static List<String> DERECHO_IMMUNE = new ArrayList<>();
    public static List<String> WANZERS = new ArrayList<>();
    public static float GANTRY_TIME_MULT = 1, GANTRY_DEPLETION_PERCENT = 0;
    
    @Override
	public void onApplicationLoad() throws ClassNotFoundException {  
        //modSettings loading:
        DERECHO_RESIST = MagicSettings.getList("diableavionics", "missile_resist_derecho");        
        DERECHO_IMMUNE = MagicSettings.getList("diableavionics", "missile_immune_derecho");                
        WANZERS = MagicSettings.getList("diableavionics", "wanzers");
        GANTRY_TIME_MULT = MagicSettings.getFloat("diableavionics", "gantry_refitMult");
        GANTRY_DEPLETION_PERCENT = MagicSettings.getFloat("diableavionics", "gantry_depletionPercent");      
    }
}

Go to the mod inter-compatibility page to see some use cases.

MagicBounty

MagicBounty is a versatile yet simple to use framework to implement unique bounties with little to no code. To some extends it merges the best of Ship and Weapon Pack's IBBs, and Vayra's Sector's HVBs. It features:

One custom bounty using the MagicBounty framework to establish context and motivations.
  • Plain text setup (no code required)
  • Choose where and when the bounty will show up. You can setup anything for time threshold, player level, specific market, faction, relationship threshold, finished a previous bounty and more.
  • The bounty will appear on the board when the player is within Hyperwave range of the bounty offer.
  • Write all the text you want to setup the situation, the characters involved and everyone's motivation.
  • Rely on procedural generation or precisely define your target's character, their Flagship and their fleet, or anything in-between.
  • Define if and how much the bounty should get scaled to the player level and fleet.
  • Define as precisely as you want where the target will be located, and how it will behave.
  • Tons of other small things (Mod requirements for cross-mod bounties, guaranteed flagship recovery, automatically fire scripts when the bounty is taken/completed to add further consequences or rewards, define how much information is available to the player, etc)

This is a quick rundown of the functionallities, for a more in-depth guide on how to add MagicBounties to you mod, you can go to this tutorial.

MagicBounty_data.json is a pretty long JSON file but most parameters are optional and the framework will fill the blanks with procedural content. Please remember that JSON is a fairly finicky file type so do not hesitate to use a JSON validator to make sure you did not missed a comma somewhere if your bounty cannot get loaded.

Fields that are not included in a bounty will use the default specified in the associated code comment (eg "Default: no values.").

{
    "bountyID":{
    
        "required_mods_id": ["modA", "modB"], # Default: no values. List the required mods for this bounty
        #TRIGGERS (ALL OPTIONAL)

        "trigger_market_id": ["market_name"], # Default: no values. Can default to the other preferences if those are defined and the location doesn't exists due to Nexerelin random mode.
                                              # This beats all other conditions; a job will ALWAYS show in this market, even if other conditions fail.
        "trigger_marketFaction_any": ["faction"], # Default: no values. markets of these factions will show the bounty (if other conditions are met).
        "trigger_marketFaction_alliedWith": true, # Default: false. if true, markets of all factions whose relationship is at least FAVORABLE to ANY ONE of the factions above will show the bounty (if other conditions are met).
        "trigger_marketFaction_none": ["other_faction"], # Default: no values. markets of factions listed here will never carry the bounty, regardless of other conditions.
        "trigger_marketFaction_enemyWith": false, # Default: false. If true, markets of all factions whose relationship is HOSTILE to EVERY ONE (ALL) of the factions above. Beware when using this parameter with multiple excluded factions.
        "trigger_market_minSize": 3, # Default: 0. The minimum size of the market.
        "trigger_player_minLevel": 15, # Default: 0. The minimum level of the player.
        "trigger_min_fleet_size": 25, # Default: 0. The minimum player fleet "power" based on Fleet Points (not Deployment Points) with some multipliers for officers and player levels. Can be used to prevent exploits such as picking ships in storage to reduce the size of the bounty fleet.
        "trigger_min_days_elapsed": 360, # Default: 0. The minimum number of days that must have elapsed.
        "trigger_weight_mult": 0.25, # Default: -1. Simple frequency multiplier when several bounties compete for limited board slots. Weights are added together, then one is picked at random, with higher weights having a higher chance. Default bounty memKeys of note:
		"trigger_memKeys_all": { # Default: no values. The job will only show if ALL of the listed memKeys exist with the specified boolean value.
		    # $job_memKey_succeeded set to true if the job has been successfully completed
            # $job_memKey_failed set to true if the job required the destruction of a flagship and the player salvaged it instead
            # $job_memKey_expired set to true if the job deadline expired, ended without player involvment, or was permanently dissmissed
            # $job_memKey set to false when the job has been picked up, true once concluded regardless of the result
            "$triggerKey":true,
        },
        "trigger_memKeys_any": { # Default: no values. The job will show if ANY of the listed memKeys exist with the specified boolean value.
            "$triggerKey":true,
        },
        "trigger_playerRelationship_atLeast": { # Default: no values. This job will require the player to have the specified relationship or HIGHER with the specified faction(s).
            "factionLikedId":0.25,
        },
        "trigger_playerRelationship_atMost": { # Default: no values. This job will require the player to have the specified relationship or LOWER with the specified faction(s).
            "factionDislikedId":-0.5,
        },

        #BOUNTY DESCRIPTION

        "job_name": "job name", # Default: "Unnamed job". Job name shown in the dialog pick list
        "job_description": "Long form description of the job", # Default: blank. The description shown upon selecting the job.
                                                               # \n creates a line break, for example "Line one.\nLine two."
															   # \" adds quotation marks.
                                                               # == brackets create a highlight, for example "Text ==highlight== text."
                                                               # ^ uppercase the following letter of a text variable, for example "^$heIsSheIsTheyAre turning angry."
                                                               # %% allow the use of %, otherwise it will be interpreted as an escape character.
                                                               # $sonDaughterChild based on bounty commander gender.
                                                               # $fatherMotherParent
                                                               # $manWomanPerson
                                                               # $heSheThey
                                                               # $himHerThem
                                                               # $hisHerTheir
                                                               # $heIsSheIsTheyAre
                                                               # $himselfHerselfThemselves
                                                               # $system The star system that the bounty fleet is in.
                                                               # $location The body that the bounty fleet has been placed near.
                                                               # $shipName The name of the bounty flagship.
                                                               # $faction The name of the faction (with article) of the bounty fleet.
                                                               # $reward The amount of credits being given as a reward.
                                                               # $name The name of the bounty commander.
                                                               # $firstName The first name of the bounty commander.
                                                               # $lastName The last name of the bounty commander.
                                                               # $constellation The constellation that the bounty fleet is in.
                                                               # $shipFleet base on either the target being a ship alone, or a fleet.
        "job_comm_reply": "Reply of the enemy to your hail", # Default: none. The text shown if the player opens comms with the bounty fleet,
                                                             # If set as an empty string, displays "The other $shipOrFleet does not answer to your hails."
                                                             # If not set, defaults to the regular comm reply for the fleet's faction.
        "job_intel_success": "Short text displayed in the intel", # Default: not shown. Short conclusion text shown in the intel object after the job has been COMPLETED SUCCESSFULLY.
        "job_intel_failure": "Short text displayed in the intel", # Default: not shown. Short conclusion text shown in the intel object after the job has been failed through FLAGSHIP RECOVERY.
        "job_intel_expired": "Short text displayed in the intel", # Default: not shown. Short conclusion text shown in the intel object after the job has EXPIRED.
        "job_forFaction": "faction_offering_the_job", # Default: no faction. Note that unless "job_reputation_reward" is set to 0, successfully completing a bounty will improve relations by 5 points.
        "job_deadline": 360, # Default: no limit. The number of days to complete the bounty.
        "job_credit_reward": 9000, # Default: no credit reward. Number of credits to award the player on successful completion.
        "job_reward_scaling": 1.0, # Default: no scaling/bonus. Bonus credits based on FP. Bonus is the specified number multiplied by how many FP the bounty fleet was over their base FP.
        "job_reputation_reward":5, # Default: 5 rep points. Reputation benefit with the faction posting the bounty, if any, in case of success. Set to 0 to disable, does not scale
        "job_item_reward": { # Default: no item rewards. Lists special items that will be added to the post-battle loot. First value is the item id, second is the number to give the player.
            # Using the same syntax as Console Commands, blueprints may be added. ["fighter_bp", "industry_bp", "modspec", "ship_bp", "weapon_bp"]
            "item_A":1,
            "ship_bp shipId": 1
        },
        "job_type":"assassination", # Default: assassination.
                # assassination: required only to disable the flagship, may recover it.
                # destruction: requires the complete destruction of the flagship without recovery.
                # obliteration: requires the complete destruction or disabling of the enemy fleet, may recover.
                # neutralisation: requires the destruction or disabling of 2/3rd of the enemy fleet, may recover.
        "job_show_type": true, # Default: true. Make sure to explain the mission objective in the bounty description if you choose to not use the default display.
        "job_show_captain": false, # Default: true. Whether to show the bounty fleet captain on the job board. If false, shows the flag of the giving faction.
        "job_show_fleet": "preset", # Default: "vanilla".
                # How much of the fleet to show on the bounty board.
				# none
                # text: "The intel assessment notes the target fleet may contain upwards of %s ships."
                # flagship: only shows an image of the flagship
                # flagshipText: shows an image of the flagships and a text with the number of other ships
                # preset: only show an image of the Flagship and the preset fleet
                # presetText: show an image of the Flagship and the preset fleet, plus a text with the number of other ships
                # vanilla: shows the Flagship and the 9 biggest ships of the fleet, plus a text with the number of other ships
                # all: show an image of all the ships in the fleet.
        "job_show_distance": "vague", # Default: "vanillaDistance".
                # How precisely the distance to the target is shown on the bounty board.
                # none: Do not show the distance.
                # vague: "The target is located somewhere in the vicinity of the core worlds."
                # distance: "It is located roughly %s LY away from your current position."
                # system: "The target is located in the <system> system."
				# vanilla: "The target is located near a giant in a system with a yellow primary star, in the Nebulon constellation." Also shows a map during the bar dialog
                # vanillaDistance: "The target is located near a giant in a system with a yellow primary star, in the Nebulon constellation. It is located roughly %s LY away from your current position." Also shows a map during the bar dialog
				# exact: "The target is located near X in the Y system." Also shows a map during the bar dialog
		"job_show_arrow": false, # Default: false. Whether to show an arrow on the Intel map pointing from the start to the bounty target location. Should only be enabled when there is a good reason, to match vanilla.
        "job_difficultyDescription": "auto",  # Default: auto description shown. "none": no description, "auto": bounty board describes how dangerous the bounty is, any other text: bounty board displays the text.
        "job_pick_option": "Accept the job", # Default: "Accept the job". The text option that, when selected, accepts the bounty job.
        "job_pick_script": "data.script.FancyScriptThatDoStuff", # Default: no script. Triggered after accepting, can be used to trigger further scripts when the mission is taken, for example you may want to have competing bounty hunters
        "job_memKey":"$jobMemKey",	# Defaults to "$bountyId", memKeys always start with "$". The specified memkey will be set to false when the job is accepted, then true if it is completed.
        "job_conclusion_script":"data.script.FancyScriptThatDoStuff", # Default: no script. Can be used to give additional rewards or add further consequences in case of failure using memkeys to check the outcome

        #TARGET EXISTING FLEET

		"existing_target_memkey":"$memKey",

        #TARGET COMMANDER (OPTIONAL)

        "target_first_name":"Firstname", # Default: randomly selected based on faction.
        "target_last_name":"Lastname", # Default: randomly selected based on faction.
        "target_portrait":"portraitId", # Default: randomly selected based on faction. Id of the sprite in settings.json/graphics/characters or full file path.
        "target_gender":"ANY", # Default: ANY. [ANY, UNDEFINED, MALE, FEMALE] ANY will randomly pick between male and female to avoid oddities and issues with texts and portraits.
        "target_rank": "Captain", # Default: "citizen". Rank from campaign.ids.Ranks [https://jaghaimo.github.io/starsector-api/classcom_1_1fs_1_1starfarer_1_1api_1_1impl_1_1campaign_1_1ids_1_1Ranks.html]
        "target_post": "Fleet Commander", # Default: "spacer". Post from campaign.ids.Ranks (yes, Ranks, posts are the bottom half). [https://jaghaimo.github.io/starsector-api/classcom_1_1fs_1_1starfarer_1_1api_1_1impl_1_1campaign_1_1ids_1_1Ranks.html]
        "target_personality": "aggressive", # Default: Randomly selected. Personality from campaign.ids.Personalities ("timid", "cautious", "steady", "aggressive", "reckless")
        "target_aiCoreId": null, # Default: null (not an AI). The AI Core id of the bounty commander. Core will be dropped as loot. Options: [ null, "gamma_core", "beta_core", "alpha_core" ]
        "target_level": 1, # Default: 0. The level of the bounty commander
        "target_elite_skills":2, # Default: vanilla setting (2 by default). Overrides the regular number of elite skills, set to 0 to not use elite skills.
        "target_skill_preference": "ANY", # Default: "ANY".
		    # YES_ENERGY_YES_BALLISTIC_YES_MISSILE_YES_DEFENSE,
		    # YES_ENERGY_YES_BALLISTIC_NO_MISSILE_YES_DEFENSE,
		    # YES_ENERGY_YES_BALLISTIC_YES_MISSILE_NO_DEFENSE,
		    # YES_ENERGY_YES_BALLISTIC_NO_MISSILE_NO_DEFENSE,
		    # YES_ENERGY_NO_BALLISTIC_YES_MISSILE_YES_DEFENSE,
		    # YES_ENERGY_NO_BALLISTIC_NO_MISSILE_YES_DEFENSE,
		    # YES_ENERGY_NO_BALLISTIC_YES_MISSILE_NO_DEFENSE,
		    # YES_ENERGY_NO_BALLISTIC_NO_MISSILE_NO_DEFENSE,
		    # NO_ENERGY_YES_BALLISTIC_YES_MISSILE_YES_DEFENSE,
		    # NO_ENERGY_YES_BALLISTIC_NO_MISSILE_YES_DEFENSE,
		    # NO_ENERGY_YES_BALLISTIC_YES_MISSILE_NO_DEFENSE,
		    # NO_ENERGY_YES_BALLISTIC_NO_MISSILE_NO_DEFENSE,
		    # NO_ENERGY_NO_BALLISTIC_YES_MISSILE_YES_DEFENSE,
		    # NO_ENERGY_NO_BALLISTIC_NO_MISSILE_YES_DEFENSE,
		    # NO_ENERGY_NO_BALLISTIC_YES_MISSILE_NO_DEFENSE,
		    # NO_ENERGY_NO_BALLISTIC_NO_MISSILE_NO_DEFENSE,
		    # ANY (from OfficerManagerEvent.SkillPickPreference)
        "target_skills": { # Default: empty. REMOVES ALL RANDOM SKILLS, set level 1 for normal skill, level 2 for elite.
            "skillnameA":1,
            "skillnameB":2,
            "skillnameC":1,
        },


        #TARGET FLEET

        "fleet_name":"Fleet Name", # Default: no name.
        "fleet_faction": "ML_bounty", # Required. The faction id from [https://jaghaimo.github.io/starsector-api/classcom_1_1fs_1_1starfarer_1_1api_1_1impl_1_1campaign_1_1ids_1_1Factions.html] or a custom faction id.
        # MagicLib includes a utility bounty faction that is forced to be neutral to everyone but the player under the id ["ML_bounty"].
        "fleet_flagship_variant":"buffalo2_FS", # Required. The variant ID to use for the Flagship. Can be a list of variants to choose randomly from: [variant1,variant2,variant3]
        # Variant files that use ships or weapons from third party mods that may or may not be installed can be put in [data\config\modFiles\magicBounty_variants\shipVariantId.variant] to avoid crashing on launch if said mods are absent. The bounty will need the proper mod requirements to be generated without issue.
        "fleet_flagship_name":"Flagship", # Default: Random.
        "fleet_flagship_alwaysRecoverable": true, # Default: false. Whether the flagship will be always recoverable. Allowing this will still let the player fail the bounty if they were not supposed to recover the flagship.
        "fleet_flagship_autofit": false, # Default: false. Whether the flagship will be autofitted. When false, the Flagship does not receive D-mods or S-mods from the quality override.
		"fleet_preset_ships": { # Default: no presets. Preset fleet generated with the flagship. First value is the variant id, second is the number of them in the fleet.
            "ship_variant1":1,
            "ship_variant2":3,
        },
        "fleet_preset_autofit": true, # Default: false. Whether the preset ships will be autofitted. When false, the preset ships do not receive D-mods or S-mods from the quality override.
        "fleet_scaling_multiplier": 1, # Default: no scaling. Dynamic reinforcements to match that amount of player fleet DP, set to 0 to ignore.
        "fleet_min_FP": 100, # Default: no minimum. Minimal total fleet size, set to -1 to ignore.
        "fleet_composition_faction": "pirates", # Default: bounty fleet faction. Used if the extra ships don't match the fleet's faction. For example a pirate fleet of Hegemony deserters. Required for min FP and player adjustment.
        "fleet_composition_quality": 1, # Default: 1, use 2 for no Dmods.
        "fleet_transponder": false, # Default: true.
		"fleet_no_retreat": false, #Default: false.
        "fleet_behavior": "PASSIVE", # Default:"GUARDED". The fleet's behavior on the campaign layer. Options: ["PASSIVE", "GUARDED", "AGGRESSIVE", "ROAMING"].
        # The musicSetId to use for the battle, defaults to no custom music.
        # IMPORTANT: This must be added to the mod's `sounds.json` file. See "music_combat" in the vanilla `sounds.json` for an example.
        "fleet_musicSetId": "music_combat",

        #LOCATION

        "location_entitiesID": [  # Default: no preset. Preset locations to spawn the bounty fleet, can default to the preferences if those are defined and the location doesn't exists due to Nexerelin random mode.
            "location1",
            "location2",
        ],
        "location_marketFactions": [  # Default: no faction specified. Markets of specified faction for the fleet to spawn at. Adding a faction market supersedes all other parameters except location_id.
            "faction"
        ],
        "location_distance": "CLOSE", # Default: no preference. How far from the center to spawn the bounty fleet. Options: "CORE", "CLOSE", "FAR" or just left empty to ignore.
        "location_themes": [ # Default: no preference. System themes that are valid to spawn the fleet at.
            "theme_core_unpopulated",
            "theme_core_populated",
            "theme_core",
            "theme_interesting",
            "theme_interesting_minor",
            "theme_ruins",
            "theme_ruins_main",
            "theme_ruins_secondary",
            "theme_derelict",
            "theme_derelict_mothership",
            "theme_derelict_cryosleeper",
            "theme_derelict_survey_ship",
            "theme_derelict_probes",
            "theme_unsafe",
            "theme_remnant",
            "theme_remnant_main",
            "theme_remnant_secondary",
            "theme_remnant_no_fleets",
            "theme_remnant_destroyed",
            "theme_remnant_suppressed",
            "theme_remnant_resurgent",

            "procgen_no_theme", #not so special bounties should add this attribute
            "procgen_no_theme_pulsar_blackhole", #or this one
        ],
        "location_themes_blacklist": [ # Default: none. System themes to never spawn the fleet at.
            "theme_already_occupied", #Will avoid systems with "hostile" themes taken from a merged list between mods. Includes all Remnant, Plague-Bearer, OCI, Blade-Breaker systems
            "theme_already_colonized", #Will explicitely exclude systems with active markets, kind of mandatory for pirate bounties given that faction colonize otherwise interesting systems with Nexerelin
            "theme_hidden", #Used by that one story system
			"no_pulsar_blackhole",
        ],
        "location_entities": [ # Default: PLANET + JUMP_POINT + STABLE_LOCATION. Possible entities to spawn the fleet around.
            "gate",
            "station",
            "wreck",
            "debris",
            "stable_location",
            "comm_relay",
            "nav_buoy",
            "sensor_array",
            "gas_giant",
            "planet",
            "jump_point",
        ],
        "location_prioritizeUnexplored": true, # Default: false. Will pick in priority systems that have not been visited by the player yet, but won't override the distance requirements.
        "location_defaultToAnyEntity": true, # Default: false. If true and no suitable entity is found in any systems with the required Theme and distance, a random entity will be picked instead. Otherwise the script will ignore the distance requirements.
    },
}

TLDR

  • TRIGGERS refers to attributes deciding in which station bars the bounty will be available.
  • BOUNTY DESCRIPTION refers to the details of the offer itself, what players will read.
  • TARGET COMMANDER refers to the target captain (and can be ignored for a random captain although I would advise setting at least a level).
  • TARGET FLEET define the bounty fleet, with its flagship, name, support ships, faction, behavior and so on.
  • LOCATION sets where the bounty will be located, from a random place anywhere in the sector down to a specific entity you designate. I strongly suggest to set the blacklist, notably by adding "theme_hidden" to prevent your bounty to spawn in story-critical systems.

Please note that a lot of those fields do not have to be filled if the default value is acceptable, or if you want a random generation (such as random commander name and portrait, or random skills)

Fleet and reward scaling

Scaling in this framework is always tied to the minimum FP of the bounty. The amount of extra ships added correspond to the difference between the Player fleet effective power (that accounts for officers and levels) multiplied by the scaling value. For example if the player has a fleet "power" of 200, a bounty that has a min FP of 100 and a scaling of 0.5 will generate a fleet of 100 + (200-100)*0.5 = 150FP. The reward multiplier works the same way.

Mod-dependent variants and S-mods

If a bounty requires a ship or a weapon from another mod that may or may not be enabled, the variant file cannot be added to the regular folder otherwise the game will crash on startup when trying to load it. To prevent this, MagicLib now includes a "on demand" variant loader: you can add the cross-mod variant required for your bounty in the data\config\modFiles\magicBounty_variants folder, making sure that the file name and the variant ID are the same. The variant loader also allows for the use of S-mods on your ships. Ships created from variant files added to the regular folder will not keep their S-mods.

Running custom scripts

If you need to trigger a script after accepting a job or at its completion, you'll need to add one line to the dreaded data/campaign/rules.csv.

ruleID,"bounty_script_trigger",,"BountyScript",,,

bounty_script_trigger corresponds to "job_pick_script":"bounty_script_trigger" and/or "job_conclusion_script":"bounty_script_trigger" in the bounty json definition.
job_pick_script will be triggered after a bounty is accepted. The fleet will have been created and placed at this point.
job_conclusion_script will be triggered after a bounty is finished, either in success or failure.
BountyScript is the name of a script that has been defined like any other script used by rules.csv.

MagicCampaign

MagicCampaign offers shorthands to speedup systems creation, as well as a way to create custom fleets with simple orders.

hyperspaceCleanup()

void hyperspaceCleanup(StarSystemAPI system)

Removes hyperspace clouds around the system, up to the outer-most jump point radius.

createDerelict()

SectorEntityToken createDerelict(
            String variantId,
            ShipRecoverySpecial.ShipCondition condition,
            boolean discoverable,
            Integer discoveryXp,
            boolean recoverable,
            SectorEntityToken orbitCenter, 
            float orbitStartAngle,
            float orbitRadius,
            float orbitDays
    )

Creates a derelict ship at the desired emplacement.

  • variantId: spawned ship variant
  • condition: state of the derelict, better conditions means less D-mods but also more recoverable weapons from the original variant.
  • discoverable: awards XP when found
  • discoveryXp :XP awarded when found (<0 to use the default)
  • recoverable: forces the recoverability of the derelict
  • orbitCenter: entity orbited
  • orbitStartAngle: orbit starting angle
  • orbitRadius: orbit radius
  • orbitDays: orbit period

createDebrisField()

SectorEntityToken createDebrisField(
            String id,
            float radius,
            float density,
            float duration,
            float glowDuration,
            Integer salvageXp,
            float defenderProbability,
            @Nullable String defenderFaction,
            Integer defenderFP,
            float detectionMult,
            boolean discoverable,
            @Nullable Integer discoveryXp,
            SectorEntityToken orbitCenter,
            float orbitStartAngle,
            float orbitRadius,
            float orbitDays
    )

Creates a debris field with generic commodity loot to salvage .

  • id: field ID
  • radius: field radius in su (clamped to 1000 for performance reasons)
  • density: field visual density
  • duration: field lifetime in days (set to a negative value for a permanent field)
  • glowDuration: time in days with glowing debris
  • salvageXp: XP awarded for salvaging (<0 to use the default)
  • defenderProbability: chance of an enemy fleet guarding the debris field when attempting to salvage (<0 to ignore)
  • defenderFaction: defender's faction
  • defenderFP: defender fleet's size in Fleet Points
  • detectionMult: detection distance multiplier (<0 to use the default)
  • discoverable: awards XP when found
  • discoveryXp: XP awarded when found (<0 to use the default)
  • orbitCenter
  • orbitStartAngle
  • orbitRadius
  • orbitDays

addSalvage()

void addSalvageItem (
    @Nullable CargoAPI cargo,
    SectorEntityToken carrier,
    lootType type,
    @Nullable String lootID,
    int amount
    )

Adds items to a salvageable entity such as a debris field, a recoverable ship or a wreck.

  • cargo: cargo to add salvage to, creates a new cargo if NULL
  • carrier: entity with the loot
  • type: type of loot added using MagicSystem.lootType.
  • lootID: specific ID of the loot found, use NULL for supplies, fuel, crew and marines. Trade commodities can use campaign.ids.Commodities
  • amount: amount recovered, unaffected by skills

CODE EXAMPLE:

//create the cargo and put 4 vulcans in it
CargoAPI cargo = MagicCampaign.addSalvage(null, wreck1, MagicCampaign.lootType.WEAPON, "vulcan", 4 );
//add 5 marines to the existing cargo
cargo = MagicCampaign.addSalvage(cargo, wreck1, MagicCampaign.lootType.MARINES, null, 5 );
//lastly add a few ai cores because why not. No need to get the cargo any further.
MagicCampaign.addSalvage(cargo, wreck1, MagicCampaign.lootType.COMMODITY, Commodities.BETA_CORE, 5 );

addJumpPoint()

SectorEntityToken addJumpPoint(
            String id,
            String name,
            @Nullable SectorEntityToken linkedPlanet,
            SectorEntityToken orbitCenter,
            float orbitStartAngle,
            float orbitRadius,
            float orbitDays
    )

Shorthand to add a specific jump-point.

  • id: jump point's internal ID
  • name: jump point's displayed name
  • linkedPlanet: planet entity displayed from hyperspace, can be NULL
  • orbitCenter
  • orbitStartAngle
  • orbitRadius
  • orbitDays

addSimpleMarket()

MarketAPI addSimpleMarket(
            SectorEntityToken entity,
            String id,
            String name,
            Integer size,
            String faction,
            boolean isFreeport,
            boolean isHidden,            
            List <String> conditions,
            List <String> industries,            
            boolean hasStorage,
            boolean paidForStorage,
            boolean hasBlackmarket,
            boolean hasOpenmarket,
            boolean hasMilitarymarket,
            boolean isAbandonedStation
    )

Adds a simple custom market to a system entity.

  • entity
  • id
  • name
  • size
  • faction
  • isFreeport
  • isHidden
  • conditions: list of conditions that can be fetched from campaign.ids.Conditions
  • industries: list of industries that can be fetched from campaign.ids.Industries
  • hasStorage
  • paidForStorage: is storage already freely available or has to be unlocked
  • hasBlackmarket
  • hasOpenmarket
  • hasMilitarymarket
  • isAbandonedStation

Please note that for that market to be active in the global economy, you will need to add

Global.getSector().getEconomy().addMarket(market);

addCustomPerson()

PersonAPI addCustomPerson(
            MarketAPI market,
            String firstName,
            String lastName,
            String portraitId,
            FullName.Gender gender,
            String factionId,
            String rankId,
            String postId,
            boolean isMarketAdmin,
            Integer industrialPlanning_level,
            Integer fleetLogistic_level,
            Integer planetaryOperations_level,
            Integer commScreenPosition
    )

Adds a custom character to a given market.

  • market: MarketAPI the person is added to
  • firstName: person's first name
  • lastName: person's last name
  • portraitId: id of the sprite in settings.json/graphics/characters
  • gender: FullName.Gender value
  • factionId: person's faction
  • rankId: rank from campaign.ids.Ranks
  • postId: post from campaign.ids.Ranks
  • isMarketAdmin
  • industrialPlanning_level: skill level for market admin
  • fleetLogistic_level: skill level for market admin
  • planetaryOperations_level: skill level for market admin
  • commScreenPosition: position order in the comm screen, 0 being the admin position

createFleetBuilder()

SectorEntityToken createFleetBuilder()
  .setFleetName(String fleetName)
  .setFleetFaction(String fleetFaction)
  .setFleetType(@Nullable String fleetType)
  .setFlagshipName(@Nullable String flagshipName)
  .setFlagshipVariant(String flagshipVariant)
  .setFlagshipAlwaysRecoverable(boolean flagshipAlwaysRecoverable)
  .setFlagshipAutofit(boolean flagshipAutofit)
  .setCaptain(@Nullable PersonAPI captain)
  .setSupportFleet(@Nullable Map<String, Integer> supportFleet)
  .setSupportAutofit(boolean supportAutofit)
  .setMinFP(int minFP)
  .setReinforcementFaction(String reinforcementFaction)
  .setQualityOverride(@Nullable Float qualityOverride)
  .setSpawnLocation(@Nullable SectorEntityToken spawnLocation)
  .setAssignment(@Nullable FleetAssignment assignment)
  .setAssignmentTarget(@Nullable SectorEntityToken assignmentTarget)
  .setIsImportant(boolean isImportant)
  .setTransponderOn(boolean transponderOn)
  .setVariantsPath(@Nullable String variantsPath)
  .create();

Creates a fleet with a defined flagship and optionally a preset captain, a preset escort fleet and/or a random escort.

Everything is optional.

  • fleetName: Default: "<faction name> Fleet".
  • fleetFaction: Default: MagicVariables.BOUNTY_FACTION ("ML_bounty").
  • fleetType: campaign.ids.FleetTypes, defaults to FleetTypes.PERSON_BOUNTY_FLEET.
  • flagshipName: Default: automatically picked by the game.
  • flagshipVariant: Default: picks the first ship in the fleet after it has been sorted.
  • flagshipAlwaysRecoverable: Default: false.
  • flagshipAutofit: Whether the flagship will be autofitted. When false, the Flagship does not receive D-mods or S-mods from the quality override. Default: false.
  • captain: PersonAPI, can be NULL for random captain, otherwise use MagicCampaign.createCaptainBuilder() .
  • supportFleet: Optional escort fleet, map with key=ships variants, values=number of ships with that variant. Default: no preset support fleet.
  • supportAutofit: Whether the preset ships will be autofitted. When false, the preset ships do not receive D-mods or S-mods from the quality override. Default: false.
  • minFP: Minimal fleet size, can be used to adjust to the player's power or simply add a random escort fleet. Set to 0 to ignore. Default: 0.
  • reinforcementFaction: if the fleet faction is a "neutral" one without ships in its doctrine, ships from a different faction can be picked as reinforcements . Default: fleetFaction.
  • qualityOverride: Optional ship quality override, default to 2 (no D-mods) if NULL or <0.
  • spawnLocation: Where the fleet will spawn, default to assignmentTarget if NULL.
  • assignment: campaign.FleetAssignment order, default to orbit_aggressive.
  • assignmentTarget: Where the fleet will go to execute its order. Default: spawnLocation. If spawnLocation is also not set, the fleet will not be spawned.
  • isImportant: will the fleet be tagged with a "!" in the campaign map, also prevents despawning. Default: false.
  • transponderOn: Default: false.

createCaptainBuilder()

PersonAPI MagicCampaign.createCaptainBuilder()
  .setIsAI(boolean isAI)
  .setAICoreType(@Nullable String aiCoreType)
  .setFirstName(@Nullable String firstName)
  .setLastName(@Nullable String lastName)
  .setPortraitId(@Nullable String portraitId)
  .setGender(@Nullable FullName.Gender gender)
  .setFactionId(@NotNull String factionId)
  .setRankId(@Nullable String rankId)
  .setPostId(@Nullable String postId)
  .setPersonality(@Nullable String personality)
  .setLevel(@Nullable Integer level)
  .setEliteSkillsOverride(@Nullable Integer eliteSkillsOverride)
  .setSkillPreference(@Nullable OfficerManagerEvent.SkillPickPreference skillPreference)
  .setSkillLevels(@Nullable Map<String, Integer> skillLevels)
  .create();

Creates a fleet commander PersonAPI.

  • isAI: Default: false
  • AICoreType: AI core from campaign.ids.Commodities. Default: none.
  • firstName: Default: randomly chosen from faction names.
  • lastName: Default: randomly chosen from faction names.
  • portraitId: id of the sprite in settings.json/graphics/characters. Default: randomly chosen from faction.
  • gender: Default: Randomly chosen between male and female if non-AI. Gender.ANY if AI.
  • factionId: Captain's faction id. Default: set in constructor.
  • rankId: rank from campaign.ids.Ranks. Default: Ranks.SPACE_COMMANDER'.
  • postId: post from campaign.ids.Ranks. Default:Ranks.POST_FLEET_COMMANDER.
  • personality: personality from campaign.ids.Personalities. Default: randomly chosen.
  • level: Captain's level, will pick random skills according to the faction's doctrine. Default: Set from skillLevels if present. If skillLevels is not set, 1 is used.
  • eliteSkillsOverride: Overrides the regular number of elite skills, set to -1 to ignore. Default: none.
  • skillPreference: GENERIC, PHASE, CARRIER, ANY from OfficerManagerEvent.SkillPickPreference. Default: OfficerManagerEvent.SkillPickPreference.ANY.
  • skillLevels: Map <skill, level> Optional Skills from campaign.ids.Skills and their appropriate levels, OVERRIDES ALL RANDOM SKILLS PREVIOUSLY PICKED! Default: none.


MagicIncompatibleHullmods

void MagicIncompatibleHullmods.removeHullmodWithWarning(
    ShipVariantAPI variant,
    String toRemove,
    String removeCause
    )

Proposes a universal solution for hullmod incompatibilities when they can't be avoided through isApplicableToShip. When called, it will remove the offending hullmod, and add a "WARNING" hullmod detailing which hullmod was removed and why. Please note that it is best practice to remove the hullmod that was just added due to the presence of a previously installed one rather than the opposite.

  • Variant
  • toRemove: hullmod ID that must be removed to solve the incompatibility
  • removeCause: hullmod ID that caused the removal

CODE EXAMPLE:

if(stats.getVariant().getHullMods().contains("heavyarmor")){
    //if someone tries to install heavy armor, remove it
    MagicIncompatibleHullmods.removeHullmodWithWarning(
        stats.getVariant(),
        "heavyarmor",
        "SKR_ancientArmor"
        );
}


MagicInterference

Weapons with the Interference trait reduce the ship's flux dissipation for every other weapon with that trait also installed. If an interference is detected, a hullmod will be added to the ship detailing the effect and its cause.

Weapons must be added to data/config/modSetting.json in the MagicLib.interferences_weapons section.

  • id: weapon id from weapon_data.csv
  • intensity: defines the amount of interference generated. By default it can be "WEAK", "MILD" or "STRONG, but mods can add new ratings in modSettings.json, although those will not be mentioned in the hullmod description.

By default, weak = -20 flux dissipation for each other interference weapon installed, mild = -40 and strong = -80

Then the weapon must have an everyframeWeaponScript to trigger the interference check:

if(weapon.getShip().getOriginalOwner()<0 && !weapon.getSlot().isBuiltIn()){
    MagicInterference.ApplyInterference(weapon.getShip().getVariant());
}

A default script is provided:

org.magiclib.weapons.MagicBasicInterferenceEffect

Please note that the interference trait should be mentioned in the weapon extra effect part of the tooltip card.


MagicAnim

A collection of functions to make smooth animations.

MagicAnim OFFSET.png

normalizeRange()

float MagicAnim.normalizeRange (float x, float start, float end)

Translates a value in a (start,end) range into a (0,1) range. Similar to smoothNormalizeRange without ease in and ease out.

MagicAnim range.png

offsetToRange()

float MagicAnim.offsetToRange (float x, float min, float max)

Translates a (0,1) value into a different (min,max) range.



MagicAnim smooth.png

smooth()

float MagicAnim.smooth(float x)

Translates a value in a (0,1) range into a value in the same range with smooth ease-in and ease-out.

0, 0.5 and 1 returns the same value, but 0.25 returns 0.11 and 0.75 return 0.89.

MagicAnim ARBITRARYSMOOTH.png

arbitrarySmooth()

float MagicAnim.arbitrarySmooth (float x, float min, float max)

Translates a value in a (min,max) range into a value within the same range that has smooth ease in and ease out.

MagicAnim SMOOTHOFFSET.png

smoothNormalizeRange()

float MagicAnim.smoothNormalizeRange (float x, float start, float end)

Translates a value in a (start,end) range into a (0,1) range with smooth ease in and ease out. Allows to segment the value of a timer or an effect level into different shorter (0,1) sliders.


smoothToRange()

float MagicAnim.smoothToRange (float x, float fromMin, float fromMax, float toMin, float toMax)

Translates a value from a (fromMin,fromMax) range into a value in a (toMin,toMax) range with smooth ease in and ease out. It pretty much does everything in one declaration.


MagicAnim RETURNSMOOTHOFFSET.png

smoothReturnNormalizeRange()

float MagicAnim.smoothReturnNormalizeRange (float x, float start, float end)

Translates a value in a (start,end) range into a "back and forth" value in a (0,1) range with smooth ease in and ease out.



smoothReturnToRange()

float MagicAnim.smoothReturnToRange (float x, float fromMin, float fromMax, float toMin, float toMax)

Translates a value in a (fromMin,fromMax) range into a "back-and-forth" value in a (toMin,toMax) range with smooth ease in and ease out.


cycle()

float MagicAnim.cycle (float x, float min, float max)

Restricts a value to a cycling range, produces a seesaw.

smoothNormalizeRange is the most useful function: if you have a "timer" source, say a weapon charge, you can add animation at specific points of the charge level. For example;

float doorX = MagicAnim.smoothNormalizeRange(weapon.getChargeLevel(),0.2f,0.7f)*4;
float doorY = MagicAnim.smoothNormalizeRange(weapon.getChargeLevel(),0.4f,1f)*11;

Means the value doorY will go from 0 to 11 between charge levels of 0.4 to 1, while the value doorX will move from 0 to 4 between charge levels of 0.2 to 0.7. Meaning the door will first move sideways then to the front with with a smooth arc.

MagicAnim SMOOTHplusOFFSET.gif


Smooth+Range+Return can be used with "locks" that open and close or to add staggers.


MagicFakeBeam

Creates convincing ponctual beams from arbitrary coordinates.

MagicFakeBeam.spawnFakeBeam ( 
    CombatEngineAPI engine, 
    Vector2f from, 
    float range, 
    float angle, 
    float width, 
    float full, 
    float fading, 
    float impactSize, 
    Color core, 
    Color fringe, 
    float normalDamage, 
    DamageType type, 
    float emp, 
    ShipAPI source 
    )

It however has several limitation:

  • - It deals damage instantly and is therefore only meant to be used for burst beams.
  • - It cannot be "cut" by another object passing between the two ends, thus a very short duration is preferable.
  • - Unlike vanilla, it deals full damage to armor, be careful when using HIGH_EXPLOSIVE damage type.
  • - While the colors can be set, the texture is smooth.

It's usage is recommended for short snappy beams or for VFXs

CODE EXAMPLE:

 MagicFakeBeam.spawnFakeBeam(
        engine,                         //combat engine
        missile.getLocation(),          //start point
        500,                            //beam range
        missile.getFacing(),            //aim
        8,                              //beam width
        0.1f,                           //beam duration
        0.2f+(float)Math.random()*0.2f, //beam fading
        100,                            //impact size
        Color.WHITE,                    //core color
        Color.BLUE,                     //impact color
        missile.getDamageAmount(),      //damage amount
        missile.getDamageType(),        //damage type
        missile.getEmpAmount(),         //emp amount
        missile.getSource()             //damage source
        );

Spawns a beam from a missile, used from a custom missile AI, to make laser torpedoes.
MagicFakeBeam spawnFakeBeam.gif

MagicLensFlare

Creates "cinematic" lens-flares

ShartLensflare.jpg

createSharpFlare()

MagicLensFlare.createSharpFlare(
    CombatEngineAPI engine,
    ShipAPI origin,
    Vector2f point,
    float thickness,
    float length,
    float angle,
    Color fringeColor,
    Color coreColor
    )

Creates sharp lens-flares, more suited to very thin short lived flares. Not CPU intensive.


CODE EXAMPLE:

MagicLensFlare.createSharpFlare(
        engine,
        ship,
        MathUtils.getRandomPointInCircle(
                ship.getLocation(),
                ship.getCollisionRadius()
                ),
        5,
        250,
        0,
        new Color(50,175,255),
        new Color(200,200,255)
        );
SmoothLensflare.jpg

createSmoothFlare() !!!TEMPORARILY DEPRECATED (until 0.95.1)!!!

MagicLensFlare.createSmoothFlare( 
    CombatEngineAPI engine,
    ShipAPI origin,
    Vector2f point, 
    float thickness, 
    float length, 
    float angle, 
    Color fringeColor, 
    Color coreColor 
    )

Creates smooth lens-flares, more suited to thick and wide flares. Can be CPU intensive for larger flares.


CODE EXAMPLE:

MagicLensFlare.createSmoothFlare(
        engine,
        ship,
        MathUtils.getRandomPointInCircle(
                ship.getLocation(),
                ship.getCollisionRadius()
                ),
        50,
        400,
        0,
        new Color(50,175,255),
        new Color(200,200,255)
        );


MagicRender

Draw arbitrary sprites on screen with constraints to entities/camera when needed. Most drawing functions come with three optional declarations: A simple declaration that should cover most use cases, an advanced declaration that adds jitter/flicker controls plus render layer overrides, and an advance declaration that also includes OpenGL blending options.

screenCheck()

(boolean) MagicRender.screenCheck (float distance, Vector2f point)

Checks if a point is within a certain distance of the screen's edges.

  • distance: cuttoff distance away from the edge of the viewport, in screen width.
  • point: position checked

It is used to avoid spawning particles or other effects that will not be seen by the player while still impacting performances. Obviously the longer lived the effect is, the farther should be the cut-off distance. The distance is expressed in "screen", so that it is independent of zoom levels. A good default distance is 0.5f, or half a screen away from the edge, but it can be shorter for short lived particles and such.

singleframe()

void MagicRender.singleframe(
            SpriteAPI sprite,
            Vector2f loc,
            Vector2f size,
            float angle,
            Color color,
            boolean additive
    )

Single frame render in absolute combat engine coordinates, can be used for animations.

  • sprite: SpriteAPI to render, use Global.getSettings().getSprite(settings category, settings id)
  • loc: center in world coordinates
  • size: Vector2f(width, height) in pixels
  • angle: float of the sprite's azimuth. 0 is pointing top
  • color: Color() override, also used for fading
  • additive: boolean for additive blending
MagicRender worldspace.jpg

battlespace()

void MagicRender.battlespace(
            SpriteAPI sprite,
            Vector2f loc,
            Vector2f vel,
            Vector2f size,
            Vector2f growth,
            float angle,
            float spin,
            Color color, 
            boolean additive,
            float fadein,
            float full,
            float fadeout
    )

Draws a sprite in absolute combat engine coordinates for a duration. Perfect for effects.

  • sprite: SpriteAPI to render. Use Global.getSettings().getSprite(settings category, settings id)
  • loc: Vector2f, center in world coordinates.
  • vel: Vector2f() velocity of the sprite.
  • size: Vector2f(width, height) in pixels.
  • growth: Vector2f() change of size along each axis over time in pixels/sec. Can be negative, a sprite that completely shrunk will be removed.
  • angle: float of the sprite's azimuth. 0 is pointing top.
  • spin: float of the sprite's rotation, in degree/sec.
  • color: Color() override, also used for dimming.
  • additive: boolean for additive blending.
  • fadein: time in sec for fading in.
  • full: time in sec at maximum opacity (clamped by color)
  • fadeout: time in sec for fading out

USE CASE EXAMPLE:
MagicRender battlespace2.gif

MagicRender objectspace1.jpg

objectspace()

void MagicRender.objectspace(
            SpriteAPI sprite,
            CombatEntityAPI anchor,
            Vector2f offset,
            Vector2f vel,
            Vector2f size,
            Vector2f growth,
            float angle,
            float spin,
            boolean parent,
            Color color,
            boolean additive,
            float fadein,
            float full,
            float fadeout,
            boolean fadeOnDeath
    )

Draws a sprite attached to an entity for a duration. When "parent" is true, the sprite will also be constrained by the anchor's orientation instead of only following the position. If "fadeOnDeath" is true, the sprite will fade out when the anchor dies or is removed, otherwise it will be instantly removed.

  • sprite: SpriteAPI to render. Use Global.getSettings().getSprite(settings category, settings id)
  • anchor: CombatEntityAPI the sprite will follow.
  • offset: Vector2f, offset from the anchor's center in world coordinates. If "parent" is true, it will be kept relative to the anchor's orientation.
  • vel: Vector2f() velocity of the sprite relative to the anchor. If "parent" is true, it will be relative to the anchor's orientation.
  • size: Vector2f(width, height) in pixels.
  • growth: Vector2f() change of size over time in pixels/sec. Can be negative, a sprite that completely shrunk will be removed.
  • angle: float of the sprite's azimuth. 0 is pointing front. If "parent" is true, 0 will match the anchor's orientation.
  • spin: float of the sprite's rotation, in degree/sec. If "parent" is true, it will be relative to the anchor's orientation.
  • parent: boolean, if true the sprite will also follow the anchor's orientation in addition to the position.
  • color: Color() override, also used for fading.
  • additive: boolean for additive blending.
  • fadein: time in sec for fading in.
  • full: time in sec at maximum opacity (clamped by color). If attached to a projectile that value can be longer than the maximum flight time, for example 99s.
  • fadeout: time in sec for fading out. If attached to a projectile, the sprite will immediately start to fade if the anchor hit or fade.
  • fadeOnDeath: if true the sprite will fadeout in case the anchor is removed, if false it will be instantly removed. Mostly useful if you want to put effects on missiles or projectiles.
MagicLib screenspace.png

screenspace()

void MagicRender.screenspace(
            SpriteAPI sprite,
            positioning pos,
            Vector2f loc,
            Vector2f vel, 
            Vector2f size,
            Vector2f growth, 
            float angle,
            float spin,
            Color color,
            boolean additive,
            float fadein,
            float full, 
            float fadeout
    )

Draws a sprite attached to the camera for a duration. Can be used to create UI elements.

  • sprite: SpriteAPI to render. Use Global.getSettings().getSprite(settings category, settings id)
  • pos: Positioning mode, set the point of reference, useful for UI elements. Use MagicRender.positioning
  • loc: Vector2f, center in world coordinates. Ignore for fullscreen.
  • vel: Vector2f() velocity of the sprite. Ignore for fullscreen.
  • size: Vector2f(width, height) in pixels.
  • growth: Vector2f() change of size over time in pixels/sec. Can be negative, a sprite that completely shrunk will be removed. Ignore for fullscreen.
  • angle: float of the sprite's azimuth. 0 is pointing top. Ignore for fullscreen.
  • spin: float of the sprite's rotation, in degree/sec. Ignore for fullscreen.
  • color: Color() override, also used for fading.
  • additive: boolean for additive blending.
  • fadein: time in sec for fading in. Set to -1 for single frame render.
  • full: time in sec at maximum opacity (clamped by color). Set to -1 for single frame render.
  • fadeout: time in sec for fading out. Set to -1 for single frame render.

There are several positioning options:

CENTER: The sprite will be drawn relative to the center of the screen.

LOW_LEFT, LOW_RIGHT, UP_LEFT, UP_RIGHT: The sprite will be drawn relative to the relevant screen corner regardless of the user's resolution or zoom level.

STRETCH_TO_FULLSCREEN: The sprite will be stretched to full screen. Ignores loc, vel, size, growth, angle and spin.

FULLSCREEN_MAINTAIN_RATIO: The sprite will be stretched to fill the screen while keeping the ratio of the "size" parameter. Ignores loc, vel, growth, angle and spin.

Advanced Parameters

JITTER and FLICKER attributes:

MagicRender supports sprite flickering and jittering in all modes except singleFrame(). The parameter are as follow:

  • jitterRange : max jitter offset from base position in pixels
  • jitterTilt : max jitter rotation from base orientation in degrees
  • flickerRange : flickering range, can be >1 to maintain the sprite on or off
  • flickerMedian : default opacity before flickering, can be > or < 0
  • maxDelay : base frequency is 60 update per second, delay can be randomly increased up to this value

One subtlety to note is how the flickering work. The flickering range is a multiplier applied to the base opacity derived from the RGBA color input, therefore it is clamped to a [0,1] range. The formula is opacity = RandomNumberInRange( flickerMedian - flickerRange, flickerMedian + flickerRange ); In layman terms, the flickerMedian is your target opacity, and the flickerRange is the amount of deviation from that target on either side.

Since the random values are clamped however, you can deliberately use values outside the [0,1] range to get interesting effects. For example to make a flickering display that stays on most of the time but occasionally fades off you can use flickerMedian=4, flickerRange=5. The random values will be uniformly spread in a [-1,9] range, which means that once clamped to [0,1], the sprite will be fully opaque 8/10th of the time, completely off 1/10th of the time, and faded 1/10th of the time.

LAYER OVERRIDE attribute:

By default sprites are rendered above all battle elements but bellow the UI. However the render layer can be changed if the effect needs to be under the ships for example.

  • layer: intended render layer taken from CombatEngineLayers

OPENGL BLENDING attributes:

Normal and additive blending cover 99.9% of the use cases, however if you have a very specific effect you want to create, you can directly change the OpenGl blending settings.

  • srcBlendFunc: openGL source blend function
  • destBlendFunc: openGL destination blend function

More information about OpenGL blending is available on the Internet.

CODE EXAMPLE:

MagicRender.objectspace(
        Global.getSettings().getSprite("fx",zapSprite+chooser),
        ship,
        new Vector2f(point),
        vel,
        new Vector2f(36*rand,36*rand),
        new Vector2f((float)Math.random()*20,(float)Math.random()*20),
        (float)Math.random()*360,
        (float)(Math.random()-0.5f)*10,
        false,
        new Color(255,175,255),
        true,
        0,
        0.2f+(float)Math.random()*0.5f,
        0.2f,
        false
        );

Draws random "zap" sprites around a ship moving towards the back, without fadein, a random duration and a fadeout.
MagicRender code.gif

MagicTargeting

Allows "smart" target selection for systems and missiles within distance and search cone parameters, plus it can use ship-class preferences.

(ShipAPI) MagicTargeting.pickTarget(
 CombatEntityAPI seeker,
 targetSeeking seeks,
 Integer maxRange,
 Integer searchCone,
 Integer fighterWeight,
 Integer frigateWeight,
 Integer destroyerWeight,
 Integer cruiserWeight,
 Integer capitalWeight,
 boolean failsafe
)

This script selects a suitable ShipAPI target for either a ship or a missile.

The possible seeking modes are:

NO_RANDOM:     

  • If the ship/source has a valid target, the script will pick it.    
  • If there is no target, the script will check for an unselected cursor target.    
  • If there is none, the script will pick the closest valid threat within the search zone.    

Note that if the seeking entity is a missile, the script will also check for an auto-fire target selected by their weapon group.

LOCAL_RANDOM:

  • If the ship/source has a selected target, the script will pick a random valid threat around that selected target.
  • If there are none, the script will pick a random valid threat around the cursor.
  • If there are none, the script will pick a random valid threat around the ship/missile.

Warning: this behavior can produce strange results if used with a limited search cone.

FULL_RANDOM:

  • The script will always pick a random valid threat around the ship/missile.

IGNORE_SOURCE:

  • The script will pick the closest target of interest. Useful for MIRVs.

CODE EXAMPLE:

(ShipAPI) target = MagicTargeting.pickTarget(
        missile,
        MagicTargeting.targetSeeking..NO_RANDOM,
        (int)missile.getWeapon().getRange(),
        360,
        0,
        1,
        2,
        4,
        4,
        false
        );

This will first aim for the ship target, if none is selected it will look for a possible cursor target, if none are found it will then aim for the closest cruiser or capital and ignore fighters.

(MissileAPI) MagicTargeting.randomMissile(
 CombatEntityAPI source,
 missilePriority priority,
 Vector2f lookAround,
 float direction,
 Integer searchCone,
 Integer maxRange
)

Unlike the other two, this script is targeting MissileAPI. The possible priorities are:    

RANDOM:

  •      Pure random pick within search zone.    

DAMAGE_PRIORITY:

  •      Picks high damage missiles within the search zone first but still has some randomness.    

HIGHEST_DAMAGE:

  •      Picks the highest damage missile within the search zone.

CODE EXAMPLE:

target = MagicTargeting.randomMissile(
        weapon.getShip(),
        MagicTargeting.missilePriority.DAMAGE_PRIORITY,
        weapon.getLocation(),
        weapon.getCurrAngle(),
        90,
        (int)weapon.getRange()
        );

Selects a random missile within 90 degrees in front of a weapon, with high damage priority.

MagicUI

MagicUI.drawSystemBar(
 ShipAPI ship,
 Color intendedColor,
 float fill,
 float blendTime
)
MagicUI.drawSystemBox(
 ShipAPI ship,
 Color intendedColor,
 float blendTime
)

Draws a small UI charge-bar/tick box next to the normal ship-system for special systems.
> ship: Ship concerned (the element will only be drawn if that ship is the player ship)
> intendedColor: Color of the filling. If null, the filling will be UI-green
> fill: Filling level
> blendTime: time taken to switch between colors, can be 0.

CODE EXAMPLE:

MagicUI.drawSystemBar(
        ship,
        new Color(255,0,0),
        shieldTime/MAX_SHIELD_TIME,
        0
);

Create a bar that fills up as long as the shield is kept online.
MagicLib UI.gif


MagicUI.drawInterfaceStatusBar(
 ShipAPI ship, float fill,
 Color innerColor,
 Color borderColor,
 float secondfill,
 String text,
 int number
)

Draw a third status bar above the Flux and Hull ones on the User Interface. With a text of the left and the number on the right.
> ship: Player ship.
> fill Filling: level of the bar. 0 to 1
> innerColor: Color of the bar. If null, the vanilla green UI color will be used.
> borderColor: Color of the border. If null, the vanilla green UI color will be used.
> secondfill: Wider filling like the soft/hard-flux. 0 to 1.
> text: The text written to the left, automatically cut if too large.
> number: The number displayed on the right. Can go from 0 to 999 999.

Interfacebar.png



MagicUI.drawHUDStatusBar(
 ShipAPI ship, float fill,
 Color innerColor,
 Color borderColor,
 float secondfill,
String bottext,
String toptext,
boolean offset
)

Draw a status bar next to the player ship on the top left corner of the hud. Can write two bits of text on its left side.
> bottext: Write a text just on the left of the bar. Example: 'flux'
> toptext: Write a text just above the bar. Example: 'player' or 'target'
> Offsets: the bar a few pixels upward. Can be used for example to display the targeted enemy special status bar.

Screenshot668.png




MagicCombatUI

Allows for easily creating button-based GUIs that are usable anywhere, most notably in combat.

For more details, please refer to the readme and example code in the example repository.

MagicMissileAI

A very customizable and lightweight missile AI script usable without any java knowledge. All the actionable parameters are fully commented within the script.

MagicVectorThruster

Manages vectoring or vernier-style attitude thrusters.

"everyFrameEffect":"org.magiclib.weapons.MagicVectorThruster",   

Just needs to be assigned to a deco weapon with a "flame" animation or a "cover" sprite in their weapon file. Supports both moving vectoring-style thrusters and fixed vernier-style ones.


vectoring-style thruster example image

MagicVectorThruster fixedVernierExample.gif
WARNING, this script may have a negative performance impact, use it sparingly.

MagicTrailPlugin

Allows custom QUAD_STRIP-style trails to be drawn freely, with a bunch of customization available. The trails are made by spawning "trail pieces", which if they have the same ID links together to form a smooth trail (the trail will not render without having at least 2 pieces link together).

These are the main functions included in MagicTrailPlugin

MagicTrailPlugin.addTrailMemberSimple(CombatEntityAPI linkedEntity, float ID, SpriteAPI sprite, Vector2f position, float speed, float angle, float startSize, float endSize, Color color, float opacity, float duration, boolean additive, Vector2f offsetVelocity)

Spawns a trail piece, which links up with other pieces with the same ID to form a smooth trail. This function has most of the functionality you need; should you want more configurability, use addTrailMemberAdvanced instead.

Parameters:

linkedEntity : The entity this trail is attached to (this is used for cutting trails). Can be null to make a trail un-cuttable, but this should generally never be done

ID : The ID for this specific trail, any other trail pieces with the same ID links up to form a trail. This should preferably be gotten from MagicTrailPlugin.getUniqueID().

sprite : Which sprite to use when drawing this trail. Do not change this mid-trail; make another trail instead or use MagicTrailPlugin.addTrailMemberAnimated() (see below).

position : Starting position for this piece of trail.

speed : The trail piece's speed, in SU/s.

angle : The angle the trail piece has when spawned, in degrees. This determines both it travel direction and which direction its width is calculated across.

startAngularVelocity : The angular velocity this trail piece has when spawned. The actual angular velocity will go from startAngularVelocity to endAngularVelocity over the trail's lifetime.

endAngularVelocity : See "startAngularVelocity" above.

startSize : The starting width of a trail piece (measured in SU). The actual width will go from startSize to endSize over the trail's life.

endSize : See "startSize" above.

color : The color of this piece of trail. Can be changed mid-trail, and will smoothly blend between trail pieces.

opacity : The starting opacity of this trail (defined between 1f and 0f); the trail's actual opacity will go from this value to 0f over its lifetime.

duration : How long the trail piece lasts, in seconds

additive : Whether the trail uses additive blending or not. Can not be changed mid-trail.

offsetVelocity : The offset velocity of the trail; this is an additional velocity that is unaffected by rotation and facing, and will never change over the trail's lifetime.

MagicTrailPlugin.addTrailMemberAdvanced(CombatEntityAPI linkedEntity, float ID, SpriteAPI sprite, Vector2f position, float startSpeed, float endSpeed, float angle, float startAngularVelocity, float endAngularVelocity, float startSize, float endSize, Color startColor, Color endColor, float opacity, float inDuration, float mainDuration, float outDuration, int blendModeSRC, int blendModeDEST, float textureLoopLength, float textureScrollSpeed, Vector2f offsetVelocity, float aggressiveCulling, @Nullable Map<String,Object> advancedOptions)

Spawns a trail piece, which links up with other pieces with the same ID to form a smooth trail. This function has all available functions; if you just want to spawn a normal trail without all the extra configuration involved, use addTrailMemberSimple instead.

Parameters:

linkedEntity : The entity this trail is attached to (this is used for cutting trails). Can be null to make a trail un-cuttable, but this should generally never be done

ID : The ID for this specific trail, any other trail pieces with the same ID links up to form a trail. This should preferably be gotten from MagicTrailPlugin.getUniqueID().

sprite : Which sprite to use when drawing this trail. Do not change this mid-trail; make another trail instead or use MagicTrailPlugin.addTrailMemberAnimated() (see below).

position : Starting position for this piece of trail.

startSpeed : The trail piece's starting speed. The actual speed will gradually go from startSpeed to endSpeed over the trail piece's lifetime.

endSpeed : See "startSpeed" above.

angle : The angle the trail piece has when spawned, in degrees. This determines both it travel direction and which direction its width is calculated across.

startAngularVelocity : The angular velocity this trail piece has when spawned. The actual angular velocity will go from startAngularVelocity to endAngularVelocity over the trail's lifetime.

endAngularVelocity : See "startAngularVelocity" above.

startSize : The starting width of a trail piece (measured in SU). The actual width will go from startSize to endSize over the trail's life.

endSize : See "startSize" above.

---PAGE WIP: MORE STUFF WILL BE ADDED---

MagicTrailPlugin.addTrailMemberAnimated(CombatEntityAPI linkedEntity, float ID, SpriteAPI sprite, Vector2f position, float startSpeed, float endSpeed, float angle, float startAngularVelocity, float endAngularVelocity, float startSize, float endSize, Color startColor, Color endColor, float opacity, float inDuration, float mainDuration, float outDuration, int blendModeSRC, int blendModeDEST, float textureLoopLength, float textureScrollSpeed, Vector2f offsetVelocity, float aggressiveCulling, @Nullable Map<String,Object> advancedOptions)

Spawns a trail piece, which links up with other pieces with the same ID to form a smooth trail. This function is identical to the Advanced function, but allows the trail to change its texture each time a new member is added. It will always use the texture of the most recently-added member. If the texture is not supposed to be animated, do NOT use this function: it runs notably slower.

Parameters:

Same as AddTrailAdvanced, except for:

sprite : The sprite for the trail; if this is changed mid-trail, the entire trail changes sprite to the newest-added sprite.

MagicTrailPlugin.getUniqueID()

Gets a unique Float ID for the purpose of generating trails. Should ideally not be used for non-trail IDs since it is very simplistic.

MagicTrailPlugin.cutTrailsOnEntity(CombatEntityAPI entity)

"Cuts" all trails on a designated entity, forcing new trail pieces to not link up with old ones. Should be used before teleporting any entity, since it may have trails attached to it which will otherwise stretch in unintended ways.

This can also be called (with a potential 1-frame delay) by adding an entity to any CustomData in the CombatEngineAPI with a key containing the phrase "MagicTrailPlugin_LIB_FREE_TRAIL_CUT" (note: *containing*; there must be more to the key than this, as it should be unique [optimally, add your modID and the ID of the ship trying to cut the trails]). This alternate  calling method does not require MagicLib, and may thus be optimal for smaller mods or mods that don't want any  other MagicLib features but still needs trail-cutting support

Parameters:

entity : The entity you want to cut all trails on. Cannot be null.

MagicAchievements

Achievements work very similarly to Steam achievements. Once unlocked, they are unlocked forever across all saves (unless the user changes computers, reinstalls the OS, etc). Progress is stored in `saves/common`. If you unlock an achievement, then reload to before you unlocked it, it's still unlocked - just like Steam. New saves will have any previous save's achievements unlocked and you can keep working to unlock them. Most achievements have no extrinsic reward (achievements added by other mods may have other rewards). The intent is to avoid player power creep. Some achievements unlock paintjobs, which are purely cosmetic.

MagicLib achievements.png

To create your own achievement, you need two things: a Java class and a csv entry.

Step 1: Java class

There is no way around writing code to create an achievement. How would one make an achievement for destroying an enemy ship using your own ship's explosion without writing code?

Create a new class for your achievement and extend MagicAchievement. This gives you a great deal of control and freedom - use your IDE to look at the methods available to you. Each has a description. There are many example implementations available here (some in Java, some in Kotlin): https://github.com/MagicLibStarsector/MagicAchievementsVanillaPack/tree/main/src/org/wisp/magicachievements

To mark your achievement as complete, simply call completeAchievement().

/**
 * Completed when the player abandons a colony.
 */
public class AbandonedAchievement extends MagicAchievement implements PlayerColonizationListener {
    @Override
    public void onSaveGameLoaded(boolean isComplete) {
        super.onSaveGameLoaded(isComplete);
        if (isComplete) return;
        Global.getSector().getListenerManager().addListener(this, true);
    }

    @Override
    public void onDestroyed() {
        super.onDestroyed();
        Global.getSector().getListenerManager().removeListener(this);
    }

    @Override
    public void reportPlayerAbandonedColony(MarketAPI colony) {
        completeAchievement();
    }

    @Override
    public void reportPlayerColonizedPlanet(PlanetAPI planet) {

    }
}

Step 2: data/config/magic_achievements.csv

Create or copy magic_achievements.csv into your mod's data/config folder. You may find a template here: https://github.com/MagicLibStarsector/MagicLib/blob/master/data/config/magic_achievements.csv. Add an entry for your own achievement, including the path to the class. For information on each column, please refer to the template linked above.

MagicPaintjobs

MagicPaintjobs are cosmetic-only sprite swaps for ships your fleet. They are unlocked per-game-install, not per-save. If you unlock a paintjob, then reload to before you unlocked it, it's still unlocked - just like Steam. New saves will have the same paintjobs unlocked as previous ones.

Paintjobs use additional VRAM, but are loaded after the rest of the game, so if you have a GPU with limited VRAM, consider disabling MagicPaintjobs using LunaLib's settings to reduce VRAM usage.

MagicLib pjs.png

To create your own paintjob, all you need is a .csv entry and a sprite!

Step 1: data/config/magic_paintjobs.csv

Create or copy magic_paintjobs.csv into your mod's data/config folder. You may find a template here: https://github.com/MagicLibStarsector/MagicLib/blob/master/data/config/magic_paintjobs.csv.

The file must be data/config/magic_paintjobs.csv.

There is a sample implementation of the csv here: https://github.com/MagicLibStarsector/MagicAchievementsVanillaPack/blob/main/data/config/magic_paintjobs.csv

Add an entry for your paintjob, following the instructions at the top of the template csv.

Optional: Unlock Paintjob After Meeting A Condition

If you want the player to have to *earn* your paintjob, you may, in your mod's code, call MagicPaintjobManager.unlockPaintjob(paintjobId) at any point.

There are example implementations for unlocking a paintjob from an Achievement here: https://github.com/MagicLibStarsector/MagicAchievementsVanillaPack/blob/main/src/org/wisp/magicachievements/BuiltInsAchievement.kt#L12

MagicSubsystems

A subsystem is like a ship system. MagicSubsystems lets you add up to five additional subsystems to a ship, giving the ship up to six systems in total, including the default vanilla system.

Each may be activated with its own hotkey.

MagicLib-MagicSubsystems-UI.png

To add a subsystem, use MagicSubsystemsManager.

MagicSubsystemsManager.addSubsystemToShip(ship, subsystem);

There are a number of examples of subsystem implementations at https://github.com/MagicLibStarsector/MagicLib/tree/master/src/org/magiclib/subsystems/examples.

Combat Activators to MagicSubsystems Migration

  • Rename from Activators to MagicSubsystems.
    • Change your imports from activators to org.magiclib.subsystems.
    • Change ActivatorManager to MagicSubsystemsManager.
    • Change CombatActivator to MagicSubsystem.
    • (etc)
  • advance(float amount) and advanceEveryFrame() are now a single method, advance(float amount, boolean isPaused).
    • All logic that was in advanceEveryFrame before should move to advance, which is now called even when paused.
    • All logic that was in advance before should have if (!isPaused) added around it.
  • ActivatorManager.addActivator has been renamed to MagicSubsystemsManager.addSubsystemToShip.
    • Same with similar methods.

Bonus: Kotlin extension methods for adding/removing subsystems have been added on ShipAPI.



Return to: Modding