Fractal Softworks Forum

Please login or register.

Login with username, password and session length
Advanced search  

News:

Starsector 0.97a is out! (02/02/24); New blog post: Simulator Enhancements (03/13/24)

Pages: 1 ... 653 654 [655] 656 657 ... 706

Author Topic: Misc modding questions that are too minor to warrant their own thread  (Read 1700799 times)

Ruddygreat

  • Admiral
  • *****
  • Posts: 524
  • Seals :^)
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9810 on: April 20, 2023, 12:51:46 PM »

Absolutely. Get the ship's hull JSON and read the offsets directly from there.

huh, never thought that the .getShipFilePath() method would ever turn out to be useful, ty!

EDIT: and for anyone who cares, this is what my final code ended up looking like, just a tad shorter than xeno's reccomendation :p
code
Code
        try {
            JSONArray coords = Global.getSettings().loadJSON(ship.getHullSpec().getShipFilePath().replaceAll("\\\\", "/")).getJSONArray("center");

            float spriteXoffset = sprite.getWidth() / 2f - coords.getInt(0);
            float spriteYoffset = sprite.getHeight() / 2f - coords.getInt(1);

            /*
            * todo will need to make this account for x offset as well, rn the center of the ship needs to be down the centerline of the ship
            */
           
            offset = (float) Math.sqrt((spriteXoffset * spriteXoffset) + (spriteYoffset * spriteYoffset));

        } catch (JSONException | IOException ignored) {}
[close]
« Last Edit: April 21, 2023, 08:03:04 PM by Ruddygreat »
Logged

basileus

  • Commander
  • ***
  • Posts: 133
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9811 on: April 20, 2023, 01:21:04 PM »

Code
public void advanceInCombat(ShipAPI ship, float amount) {

        Map<String, Object> customCombatData = Global.getCombatEngine().getCustomData();

        final String key = "ZDA_Test" + ship.getId();
        float shieldTest = customCombatData.get(key) instanceof Float
        ? (float) customCombatData.get(key)
        : 0f;
       
        if (ship.getSystem().isOn()) {
            shieldTest += 0.0175f;
        } else if (ship.getShield().isOn()) {
            shieldTest -= 0.0175f;
        } else {
            shieldTest = 0f;
        }

        shieldTest = Math.min(Math.max(shieldTest, 0f), 5f);

        customCombatData.put(key, shieldTest);

        ship.getMutableStats().getBallisticWeaponRangeBonus().modifyFlat("test", shieldTest * 80f);

    }

I'm not a Java guy, so I am a little curious if the explicit typecasting to (float) is necessary in the immediate aftermath of the instanceof Float check.
Logged

AtlanticAccent

  • Lieutenant
  • **
  • Posts: 73
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9812 on: April 20, 2023, 03:16:50 PM »

Code
public void advanceInCombat(ShipAPI ship, float amount) {

        Map<String, Object> customCombatData = Global.getCombatEngine().getCustomData();

        final String key = "ZDA_Test" + ship.getId();
        float shieldTest = customCombatData.get(key) instanceof Float
        ? (float) customCombatData.get(key)
        : 0f;
       
        if (ship.getSystem().isOn()) {
            shieldTest += 0.0175f;
        } else if (ship.getShield().isOn()) {
            shieldTest -= 0.0175f;
        } else {
            shieldTest = 0f;
        }

        shieldTest = Math.min(Math.max(shieldTest, 0f), 5f);

        customCombatData.put(key, shieldTest);

        ship.getMutableStats().getBallisticWeaponRangeBonus().modifyFlat("test", shieldTest * 80f);

    }

I'm not a Java guy, so I am a little curious if the explicit typecasting to (float) is necessary in the immediate aftermath of the instanceof Float check.

I assume that key is for data only your mod ever reads and writes? In which case I wouldn't bother doing any type checks at all and do a naked cast, ie:
Code
float shieldTest = (float) customCombatData.get(key);
Otherwise, if you really want to do type checking you can try using a try/catch and catch the (potential but highly unlikely) ClassCastException
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 23988
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9813 on: April 20, 2023, 03:58:45 PM »

I assume that key is for data only your mod ever reads and writes? In which case I wouldn't bother doing any type checks at all and do a naked cast, ie:
Code
float shieldTest = (float) customCombatData.get(key);
Otherwise, if you really want to do type checking you can try using a try/catch and catch the (potential but highly unlikely) ClassCastException

One thing worth noting is that this:
float shieldTest = (float) customCombatData.get(key);

Will throw a NullPointerException if the key is not present in the map, so you still want to check to make sure it's present before casting.

So will this:
float shieldTest = (Float) customCombatData.get(key);

However, this will not (note the capital-case Float on both sides:
Float shieldTest = (Float) customCombatData.get(key);

And instead, if the key is not in the map, then shieldTest will be null. So you'd get your NPE when trying to use it in an expression that tries to convert it to a regular float :)

Main point being that you don't strictly speaking need a type check, but you probably want a null check somewhere unless you're very, very careful about how you structure your code and make sure a null is impossible. But probably even then.
Logged

basileus

  • Commander
  • ***
  • Posts: 133
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9814 on: April 20, 2023, 06:02:41 PM »

That was insightful.  Thanks to both of you.
Logged

jujuteux

  • Ensign
  • *
  • Posts: 43
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9815 on: April 21, 2023, 12:53:08 AM »

Hi, alex.

i'm currently checking the whole Personality.csv file and trying to add new ones (mainly for changing descriptions and names)
and i bumped on the fact that there's not actually any difference between reckless and aggressive in the csv

is the whole AI mechanic handled by checking for the name or ID?
that might actually cause some problems since i'm basically duplicating those personalities and just changing names, ID and desc

if it can't be fixed, can you consider making something so you can create your own personalities outside of the csv? like unobfuscating the personality code.

thanks in advance!
Logged

rogerbacon

  • Commander
  • ***
  • Posts: 142
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9816 on: April 21, 2023, 05:18:54 PM »

How do I add a listener to a projectile?

I want to create a projectile that, if shot down by pd, will spawn an emp arc to the nearest target within range. I've added listeners to ships but I don't see a similar method for projectiles.
Logged

Ruddygreat

  • Admiral
  • *****
  • Posts: 524
  • Seals :^)
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9817 on: April 21, 2023, 07:40:32 PM »

How do I add a listener to a projectile?

I want to create a projectile that, if shot down by pd, will spawn an emp arc to the nearest target within range. I've added listeners to ships but I don't see a similar method for projectiles.

you can't add a listener directly to a projectile, but I've got a similar thing that I do this (see below) for.

code
here's the onFire effect that adds the fired projectile to a list of projectiles that a "manager" class iterates over
getFirstListenerofClass is a lil method I made that's effectively just Ship().getListeners(classname.class).get(0);, but a little fancified.
Code
public class lightspikeDriverOnFire implements OnFireEffectPlugin {

    @Override
    public void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {

        lightspikeDriverEFS.lsdActualEfs listener = getFirstListenerOfClass(weapon.getShip(), lightspikeDriverEFS.lsdActualEfs.class);

        if (listener == null) return;

        listener.addProj(projectile);

    }
}
and here's the actual manager class, in the form of an EveryFrameWeaponEffect that adds an advanceableListener to the ship (though tbh that could probably just be done in the onfire, check if it's null, if yes add one, if no use the existing one)
Code
public class lightspikeDriverEFS implements EveryFrameWeaponEffectPlugin {

    @Override
    public void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon) {
        if (!weapon.getShip().hasListenerOfClass(lsdActualEfs.class)) {
            weapon.getShip().addListener(new lsdActualEfs(weapon.getShip()));
        }
    }

    public static class lsdActualEfs implements AdvanceableListener, DamageDealtModifier {

        protected final ShipAPI ship;
        private final ArrayList<DamagingProjectileAPI> projs = new ArrayList<>();

        public lsdActualEfs(ShipAPI ship) {
            this.ship = ship;
        }

        public void addProj(DamagingProjectileAPI proj) {
            projs.add(proj);
        }

        @Override
        public void advance(float amount) {

            for (DamagingProjectileAPI proj : new ArrayList<>(projs)) {

               /*
               * do your checking here, probably just a CombatEngineAPI.isEntityInPlay(); check on the projectile before spawning the arcs or so
               * also, that for loop creates a new arrayList to prevent concurrentModificationExceptions when removing projectiles from the list so that you don't need to do a second loop over the list
               */
           
            }
        }
    }
}
[close]
this method technically has a few pitfalls (particularly if the projectile is spawned using spawnProjectile() without manually calling the onFire for it), but it works well enoughtm for me to not be bothered by it

rogerbacon

  • Commander
  • ***
  • Posts: 142
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9818 on: April 22, 2023, 05:29:14 PM »

How do I add a listener to a projectile?

I want to create a projectile that, if shot down by pd, will spawn an emp arc to the nearest target within range. I've added listeners to ships but I don't see a similar method for projectiles.

you can't add a listener directly to a projectile, but I've got a similar thing that I do this (see below) for.

this method technically has a few pitfalls (particularly if the projectile is spawned using spawnProjectile() without manually calling the onFire for it), but it works well enoughtm for me to not be bothered by it

Thank you. With your help I was able to make what I wanted. Code below.

Code
package data.scripts.weapons;
import com.fs.starfarer.api.combat.*;
import com.fs.starfarer.api.combat.WeaponAPI;
import com.fs.starfarer.api.combat.DamagingProjectileAPI;
import com.fs.starfarer.api.combat.EveryFrameCombatPlugin;
import com.fs.starfarer.api.combat.OnFireEffectPlugin;
import java.util.Random;
import java.lang.Math;
import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.combat.*;
import com.fs.starfarer.api.combat.CombatEngineAPI;
import com.fs.starfarer.api.combat.CombatEntityAPI;
import com.fs.starfarer.api.combat.DamageType;
import com.fs.starfarer.api.combat.ShipAPI;
import com.fs.starfarer.api.loading.WeaponSlotAPI;
import com.fs.starfarer.api.combat.GuidedMissileAI;
import com.fs.starfarer.api.util.IntervalUtil;
import org.lazywizard.lazylib.combat.CombatUtils;
import com.fs.starfarer.api.combat.listeners.AdvanceableListener;
import org.lazywizard.lazylib.VectorUtils;
import org.lazywizard.lazylib.MathUtils;
import org.lazywizard.console.Console;
import org.lazywizard.lazylib.CollisionUtils;
import com.fs.starfarer.api.combat.FluxTrackerAPI;
import com.fs.starfarer.api.loading.DamagingExplosionSpec;
import com.fs.starfarer.api.combat.listeners.AdvanceableListener;
// import com.fs.starfarer.api.combat.listeners.DamageDealtModifier;
import java.awt.Color;
import java.util.*;
import org.lwjgl.util.vector.Vector2f;
import static com.fs.starfarer.api.util.Misc.ZERO;

public class SFB_Nuclear_Torpedo_OnFireEffect implements OnFireEffectPlugin {

   
    public void onFire(final DamagingProjectileAPI projectile, final WeaponAPI weapon, final CombatEngineAPI engine) {

if (weapon.getShip() != null) {

if (!weapon.getShip().hasListenerOfClass(nuclearListener.class)) {
            weapon.getShip().addListener(new nuclearListener(weapon.getShip()));
}
SFB_Nuclear_Torpedo_OnFireEffect.nuclearListener listener = getFirstListenerOfClass(weapon.getShip(), SFB_Nuclear_Torpedo_OnFireEffect.nuclearListener.class);

listener.addProj(projectile);
}


    }

public static nuclearListener getFirstListenerOfClass(ShipAPI ship, Class listenerClass) {

        if (!ship.hasListenerOfClass(listenerClass)) {
            return null;
        }
        nuclearListener listener = (nuclearListener)ship.getListeners(listenerClass).get(0);
        return  listener;
    }


public static class nuclearListener implements AdvanceableListener /*, DamageDealtModifier */ {

        protected final ShipAPI ship;
        private final ArrayList<DamagingProjectileAPI> projs = new ArrayList<DamagingProjectileAPI>();
private final ArrayList<DamagingProjectileAPI> deadProjs = new ArrayList<DamagingProjectileAPI>();

private static final Color ARC_FRINGE_COLOR = new Color(85, 60, 205, 225);
private static final Color ARC_CORE_COLOR = new Color(235, 175, 235, 255);
private static final int NUM_ARCS = 3f;

        public nuclearListener(ShipAPI ship) {
            this.ship = ship;
        }

        public void addProj(DamagingProjectileAPI proj) {
            projs.add(proj);
        }

public boolean isHarmless(MissileAPI m) {
        return m.isFizzling() || m.isExpired() || m.isFading();
}

        @Override
        public void advance(float amount) {

            Iterator<DamagingProjectileAPI> iter = projs.iterator();
while (iter.hasNext()) {
CombatEngineAPI engine = Global.getCombatEngine();
if (engine.isPaused() ) {
return;
}

DamagingProjectileAPI proj = (DamagingProjectileAPI)iter.next();

if ( isHarmless((MissileAPI)proj) || proj.didDamage() ) {
//projs.remove(proj);
continue;
}


if (proj.getHitpoints() > 300 ) {
continue;
}


java.lang.Object missileAI = proj.getAI();
if (missileAI == null ) {
continue;
}

CombatEntityAPI target = ((GuidedMissileAI)missileAI).getTarget();

//CombatEntityAPI target = proj.getDamageTarget(); // wrong. This is what it damaged
if (target == null) {
continue;
}


Vector2f projPos = proj.getLocation();
Vector2f targetPos = target.getLocation();
float distance = MathUtils.getDistanceSquared(projPos, targetPos) ;
if (distance > 250000f) { // range 500 = 250000
continue;
}

// At this point the projectile should have zero hp, not have done damage, and be within range.

SpawnEMP(target, proj);
Console.showMessage("proj in arraylist " + projs.size());
// clear out dead missles. Need a better way.
if (!deadProjs.contains(proj)){
deadProjs.add(proj);
}

             
           
            }

for (DamagingProjectileAPI deadProjectile : deadProjs) {
if (projs.contains(deadProjectile)) {
projs.remove(deadProjectile);
}
}

deadProjs.clear();

        }

public void SpawnEMP(CombatEntityAPI target, DamagingProjectileAPI proj) {
//Console.showMessage( proj.getHitpoints() + " hp" + " Boom!");
CombatEngineAPI engine = Global.getCombatEngine();
for (int x = 0 ; x < NUM_ARCS; x++) {
engine.spawnEmpArcPierceShields(proj.getSource(),
proj.getLocation(),
proj,
target,
DamageType.ENERGY,
0f, // damage
750f, // emp damage
500f, // range
"shock_repeater_emp_impact", // sound
8f, // thickness
ARC_FRINGE_COLOR, // fringe
ARC_CORE_COLOR // core color
);
}

proj.setHitpoints(0f);
}
    }

}

One difference from yours is that I iterate through the original arraylist instead  of creating a copy inside the advance() method. Isn't creating a copy of the arraylist expensive? Sinec advance runs every frame I'm concerned about performance.

I want to remove the dead projectiles but, like you said, doing so causes an error within the loop. The sources say it should work this way but it gave an error. Anyway, since I don't expect to spam thousands of missiles in a given battle I can live with this. Thanks again.
Logged

ctuncks

  • Commander
  • ***
  • Posts: 117
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9819 on: April 22, 2023, 07:53:12 PM »

As a more general question is there any noticeable technical disadvantages of running several mods that would otherwise be in a single amalgamation? I'm contemplating whether I should roll my cosmetic shield hullmods into my current WIP mod or create a separate one just for them.
Logged

SafariJohn

  • Admiral
  • *****
  • Posts: 3010
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9820 on: April 23, 2023, 05:12:28 AM »

Not really. AFAIK only the UI replacement mods have to be separate. It is mainly a choice on how you want to present your content to the user.
Logged

rogerbacon

  • Commander
  • ***
  • Posts: 142
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9821 on: April 23, 2023, 12:24:33 PM »

Is there any way to programmatically change the burst size of a weapon during combat?
Logged

Big Bee

  • Commander
  • ***
  • Posts: 153
  • bugs are cool
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9822 on: April 23, 2023, 02:55:05 PM »

Hey, I'm sure this has been asked before (though I had a quick look and couldn't find it), but how do I make a ship available to use in NPC fleets?

I just got started on trying to make a ship pack mod cause I decided to try kitbashing and found it quite fun, but the first ship I made refuses to appear in my faction's fleets even though I had it prioritized. It doesn't work even if it's the only non-default blueprint I got and it doesn't work if I use console commands to learn all blueprints to ensure that all weapons its variants use can be produced by my faction. I used the ship editor and made sure all variants have goalVariant set to true but the ship still refused to appear in the 'typical heavy patrol' window, no matter how often I pressed 'regenerate'.

I tried setting the rarity in the csv to 1, leaving it blank or setting it to a different number as well.
Logged

Ruddygreat

  • Admiral
  • *****
  • Posts: 524
  • Seals :^)
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9823 on: April 23, 2023, 02:59:17 PM »

you'll need at least an entry in default_ship_roles.json as well (look at vanilla for an example), without them the game doesn't know when to spawn the ship so it simply won't.

Ruddygreat

  • Admiral
  • *****
  • Posts: 524
  • Seals :^)
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #9824 on: April 24, 2023, 11:23:44 AM »

is there any function that gets called / boolean that I can check right on the final frame of combat?
I'm generating some textures for shader stufftm & I don't want to eat everyone's vram, I know there's CombatEngineAPI.isCombatOver(), but for some reason I've got it in my head that it gets set to true as soon as the "you can claim victory" popup appears & idrk a good way to test that.
Pages: 1 ... 653 654 [655] 656 657 ... 706