Fractal Softworks Forum

Please login or register.

Login with username, password and session length
Pages: 1 ... 594 595 [596] 597 598 ... 709

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

Liral

  • Admiral
  • *****
  • Posts: 718
  • Realistic Combat Mod Author
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8925 on: July 13, 2022, 09:20:44 AM »

Hey Alex,

I have a problem with lead.  The lead calculation of the vanilla autofire AI uses the projectile speeds from weapon_data.csv rather than those of the relevant ProjectileSpecAPIs.  I know that the AI is using the .csv values because both the vanilla AutofireAIPlugin and Leading Pip by DarkRevenant estimate the same excessive lead at the thousands of SU of range and projectile speed and hundreds of SU per second of ship speed in Realistic Combat: debugging DarkRevenant's code, I found that it uses the method WeaponAPI.getProjectileSpeed(), which returns the value from weapon_data.csv although Realistic Combat has modified the projectile speed ProjectileSpecAPI of the WeaponSpecAPI of the relevant WeaponAPI.  Replacing that method call with with the following statement corrected the lead:

Code
((ProjectileSpecAPI) weapon.getSpec().getProjectileSpec()).getMoveSpeed(weapon.getShip().getMutableStats(), weapon)

I need the AI to use the value that this statement returns.  I suspect I would have to inject some AutofireAIPlugin, but then I would be at best duplicating your years of effort to write a good one.

If you want to see more code, here it is:

Deriving the relevant stats of the WeaponGroupAPI for which lead is to be calculated
Spoiler
Code
    private static class WeaponGroupDerivedStats {

        private final float averageWeaponSpeed;
        private final Vector2f center;

        private static boolean isActiveNonBeamWeapon(WeaponAPI weapon) {
            return (!weapon.isDisabled()
                    && !weapon.isBeam()
                    && !weapon.isBurstBeam()
                    && weapon.getProjectileSpeed() >= 50f);
        }

        private static boolean firesMissiles(WeaponAPI weapon) {
            return weapon.getSpec().getProjectileSpec() instanceof MissileSpecAPI;
        }

        private static float getMissileSpeed(WeaponAPI weapon) {
            return ((MissileSpecAPI) weapon.getSpec().getProjectileSpec()
            ).getHullSpec().getEngineSpec().getMaxSpeed();
        }

        /**
         * {@code WeaponAPI.getProjectileSpeed()} returns the speed
         * in weapon_data.csv rather than after RealisticCombat has
         * modified the weapon and projectile specs.
         *
         * @param weapon {@link WeaponAPI}
         *
         * @return {@code float} true speed of the projectile of
         *         a {@link WeaponAPI}
         */
        private static float getProjectileSpeed(WeaponAPI weapon) {
            return ((ProjectileSpecAPI) weapon.getSpec().getProjectileSpec()).getMoveSpeed(
                    weapon.getShip().getMutableStats(), weapon);
        }

        private static float getWeaponSpeed(WeaponAPI weapon) {
            return firesMissiles(weapon) ? getMissileSpeed(weapon) : getProjectileSpeed(weapon);
        }

        private WeaponGroupDerivedStats(WeaponGroupAPI weaponGroup) {
            float totalWeaponSpeed = 0.01f, activeNonBeamWeapons = 0;
            Vector2f center = new Vector2f(0, 0);
            for (WeaponAPI weapon : weaponGroup.getWeaponsCopy())
                if (isActiveNonBeamWeapon(weapon)) {
                    totalWeaponSpeed += getWeaponSpeed(weapon);
                    Vector2f.add(center, weapon.getLocation(), center);
                    activeNonBeamWeapons += 1f;
                }
            averageWeaponSpeed = totalWeaponSpeed / activeNonBeamWeapons;
            center.x /= activeNonBeamWeapons; center.y /= activeNonBeamWeapons;
            this.center = center;
        }

        private float getAverageWeaponSpeed() { return averageWeaponSpeed; }

        private Vector2f getWeaponsCenter() { return center; }
    }
[close]

Math and driver code that update the center of the leading indicator.  Note that intercept may return null to indicate that no lead is available.
Spoiler
Code
    /**
     * @param a {@code float} coefficient of x^2
     * @param b {@code float} coefficient of x
     * @param c {@code float} constant
     *
     * @return {@link Vector2f} solutions of a quadratic equation
     *          ax^2 + bx + c = 0
     */
    private static float[] quad(float a, float b, float c) {
        if (Float.compare(Math.abs(a), 0) == 0) {
            if (Float.compare(Math.abs(b), 0) == 0)
                return (Float.compare(Math.abs(c), 0) == 0) ? new float[] {0, 0} : null;
            return new float[] {-c / b, -c / b};
        } else {
            float d = b * b - 4 * a * c;
            if (d >= 0) {
                d = (float) Math.sqrt(d);
                float e = 2 * a;
                return new float[]{(-b - d) / e, (-b + d) / e};
            }
        } return null;
    }

    /**
     * @param point {@link Vector2f} average {@link WeaponAPI} location of a
     *                               {@link WeaponGroupAPI}
     * @param speed {@code float} average {@link DamagingProjectileAPI} speed
     *                            of the {@link WeaponAPI}s of a
     *                            {@link WeaponGroupAPI}
     * @param targetLoc {@link Vector2f} target location
     * @param targetVel {@link Vector2f} target velocity
     *
     * @return {@link Vector2f} at which a {@link DamagingProjectileAPI}
     *         fired from the average {@link Vector2f} location of the
     *         {@link WeaponAPI}s of the selected {@link WeaponGroupAPI} with
     *         the {@code float} average {@link DamagingProjectileAPI} speed of
     *         the same would intercept a target of known {@link Vector2f}
     *         location and anticipated constant {@link Vector2f} velocity
     */
    private static Vector2f intercept(Vector2f point,
                                      float speed,
                                      Vector2f targetLoc,
                                      Vector2f targetVel)
    {
        Vector2f difference = new Vector2f(targetLoc.x - point.x, targetLoc.y - point.y);
        float a = targetVel.x * targetVel.x + targetVel.y * targetVel.y - speed * speed;
        float b = 2 * (targetVel.x * difference.x + targetVel.y * difference.y);
        float c = difference.x * difference.x + difference.y * difference.y;
        float[] solutions = quad(a, b, c);

        if (solutions == null) return null;
        float bestFit = Math.min(solutions[0], solutions[1]);
        if (bestFit < 0) bestFit = Math.max(solutions[0], solutions[1]);
        if (bestFit > 0) return new Vector2f(targetLoc.x + targetVel.x * bestFit,
                                             targetLoc.y + targetVel.y * bestFit);
        return null;
    }

    /**
     * Set the {@link Vector2f} center of the indicator for its targeted
     * {@link ShipAPI}.
     */
    private void updateCenter() {
        ShipAPI playerShip = Global.getCombatEngine().getPlayerShip();
        WeaponGroupAPI weaponGroup = playerShip.getSelectedGroupAPI();
        WeaponGroupDerivedStats stats = new WeaponGroupDerivedStats(weaponGroup);
        Vector2f relativeVelocity = Vector2f.sub(target.getVelocity(), playerShip.getVelocity(),
                null);
        center = intercept(stats.getWeaponsCenter(), stats.getAverageWeaponSpeed(),
                target.getLocation(), relativeVelocity);
    }
Spoiler
[close]
[close]

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8926 on: July 13, 2022, 11:05:56 AM »

Let me add setProjectileSpeed() to WeaponSpecAPI.

I don't remember why the speed is kept in two places - it probably should not be - but there are many places in the game that assume the two values will always be the same; just changing that AI calculation wouldn't be the half of it. I'd suggest making sure to change both - is there a reason this isn't a good solution for you?
Logged

Liral

  • Admiral
  • *****
  • Posts: 718
  • Realistic Combat Mod Author
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8927 on: July 13, 2022, 11:27:43 AM »

Let me add setProjectileSpeed() to WeaponSpecAPI.

Oh, thanks!  I wasn't even expecting you to.  :)  So, would WeaponSpecAPI.setProjectileSpeed(float projectileSpeed) be syntactic sugar WeaponSpecAPI.getProjectileSpec().setMoveSpeed(float moveSpeed)?

Quote
I don't remember why the speed is kept in two places - it probably should not be - but there are many places in the game that assume the two values will always be the same; just changing that AI calculation wouldn't be the half of it.

Oh my.

Quote
I'd suggest making sure to change both - is there a reason this isn't a good solution for you?

Changing weapon_data.csv was my original plan but entailed creating and maintaining a compatibility pack for any mod with which mine were to run, so I added code automatically rescaling all WeaponSpecAPIs.  Could I work further upstream to change what the game thinks is weapon_data.csv and then let it build the specs from these modified values?

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8928 on: July 13, 2022, 11:51:09 AM »

So, would WeaponSpecAPI.setProjectileSpeed(float projectileSpeed) be syntactic sugar WeaponSpecAPI.getProjectileSpec().setMoveSpeed(float moveSpeed)?

It's absolutely not! WeaponSpecAPI is what initially gets the data from weapon_data.csv (which is only read by the game once, barring devMode F8 (iirc) reload shenanigans). And ProjectileSpecAPI gets a copy of that value at some point - might even be at the same time as the data is being initially loaded. So what's happening is you're probably modifying ProjectileSpecAPI only, but not WeaponSpecAPI, so the values are out of sync.
Logged

Liral

  • Admiral
  • *****
  • Posts: 718
  • Realistic Combat Mod Author
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8929 on: July 13, 2022, 12:45:35 PM »

It's absolutely not! WeaponSpecAPI is what initially gets the data from weapon_data.csv (which is only read by the game once, barring devMode F8 (iirc) reload shenanigans). And ProjectileSpecAPI gets a copy of that value at some point - might even be at the same time as the data is being initially loaded. So what's happening is you're probably modifying ProjectileSpecAPI only, but not WeaponSpecAPI, so the values are out of sync.

You're right!  I did modify ProjectileSpecAPI without modifying ProjectileWeaponSpecProxy.  If I modify the former, then the projectile flies as fast as I intend, but the autofire is off; the latter, the autofire is where I would like if the projectile flew so fast, but it does not; both, the projectile flies fast and autofire is perfect.  Thank you, Alex!

Here's what I'm doing now, thanks to your advice: it's duplicative but necessary.  Note the last four lines.  :)

Code
    private static void modifyBallisticAutocannonSpec(WeaponSpecAPI weaponSpec) {
        WeaponCategory category = BALLISTIC_AUTOCANNON;
        float maxRange = getMaxRange(category, weaponSpec);
        WeaponAPI.WeaponSize weaponSize = weaponSpec.getSize();
        weaponSpec.setMaxRange(maxRange);
        weaponSpec.setMinSpread(getMinimumSpread());
        weaponSpec.setMaxSpread(getMaximumSpread());
        projectileWeaponSpecProxy.setWeaponSpec(weaponSpec);
        projectileWeaponSpecProxy.setRefireDelay(getRefireDelay(category, weaponSize)
                                                  / weaponSpec.getHardpointFireOffsets().size());
        projectileWeaponSpecProxy.setBurstDelay(0f);
        projectileWeaponSpecProxy.setBurstSize(1);
        projectileWeaponSpecProxy.setEnergyPerShot(0f);
        projectileWeaponSpecProxy.setMaxAmmo(getMaxAmmo(category, weaponSpec));
        projectileWeaponSpecProxy.setAmmoPerSecond(getAmmoPerSecond(category,
                weaponSize));
        projectileWeaponSpecProxy.setReloadSize(getReloadSize(category, weaponSize));
        projectileWeaponSpecProxy.setProjectileSpeed(maxRange);
        ProjectileSpecAPI projectileSpecAPI = (ProjectileSpecAPI) weaponSpec.getProjectileSpec();
        projectileSpecAPI.setMaxRange(maxRange);
        projectileSpecAPI.setMoveSpeed(maxRange);
    }

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8930 on: July 13, 2022, 12:46:42 PM »

That makes sense, yeah - glad you got it sorted out!
Logged

Liral

  • Admiral
  • *****
  • Posts: 718
  • Realistic Combat Mod Author
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8931 on: July 13, 2022, 12:59:25 PM »

That makes sense, yeah - glad you got it sorted out!

One other question: is there anything that responds to each tick of a BeamAPI hitting something?  My code applies it but only to the first one, causing big damage up front but little to no damage thereafter.  I can think of potential solutions (make all beams one-frame pulse beams, message passing, track all beams, add beam-specific listeners everywhere, etc.) but they all seem janky at best.

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8932 on: July 13, 2022, 01:01:41 PM »

Hmm, it seems like DamageListener should get called for every beam tick.
Logged

Liral

  • Admiral
  • *****
  • Posts: 718
  • Realistic Combat Mod Author
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8933 on: July 13, 2022, 01:02:30 PM »

Hmm, it seems like DamageListener should get called for every beam tick.

Ahhhh, there it is!  Thanks.

bananana

  • Commander
  • ***
  • Posts: 228
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8934 on: July 14, 2022, 01:50:20 AM »

is it still impossible to have a non-circular(oval) orbit for planets? and a non-circular ringBand?
i mean, ringBand can be spiral...
Logged
Any and ALL sprites i ever posted on this forum are FREE to use. even if i'm using them myself. Don't ever, EVER ask for permission, or i will come to your home and EAT YOUR DOG!!!
i do NOT want to see my name appear in the credits section of any published mod and will consider it a personal insult.

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8935 on: July 14, 2022, 07:34:59 AM »

You could do it - either by providing a custom implementation of OrbitAPI (which *might* run into some problems, potentially, if some vanilla code makes some assumptions that are broken by this) or by just having a script move the entity around however you choose. You could even have a rectangular orbit if you like :)

Whether that works well will depend on the specifics of your use case - with non-circular orbits you'd generally have a harder time making sure that the object doesn't occasionally overlap some of its neighbors in a visually awkward way.

(The spiral ringband doesn't have anything to do with orbits, iirc; it's just a visual for filling in the inside of a circular band, more or less.)
Logged

Liral

  • Admiral
  • *****
  • Posts: 718
  • Realistic Combat Mod Author
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8936 on: July 14, 2022, 08:08:02 AM »

You could do it - either by providing a custom implementation of OrbitAPI (which *might* run into some problems, potentially, if some vanilla code makes some assumptions that are broken by this) or by just having a script move the entity around however you choose. You could even have a rectangular orbit if you like :)

Waaaaaait a minute.  You mean that planet orbits are circular, but that orbits could be elliptical instead?  You could even give them tilt by shrinking and growing the planet sprite over the orbit, right?  In principle, you could even simulate real orbits!
« Last Edit: July 14, 2022, 08:10:31 AM by Liral »
Logged

Ruddygreat

  • Admiral
  • *****
  • Posts: 524
  • Seals :^)
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8937 on: July 14, 2022, 12:55:53 PM »

how does using spawnShipOrWing() work for wings specifically?
say that I wanted a fighter to spawn a copy of itself (and for those copies to be able to spawn copies, with a limit), would spawning the extras as individual ships & adding them to the first ship's wing work (and go over the 6 fighter-per-wing limit), or would I have to do something else?

I've tried looking at the shardSpawner code but it's franky incomprehensible to me, I can't really tell where the aspects actually get spawned / get anything assigned to them

Timid

  • Admiral
  • *****
  • Posts: 640
  • Personal Text
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8938 on: July 14, 2022, 07:40:35 PM »

I'm not looking hard enough or something but...

I would like a hullmod to be droppable from raiding faction, but not droppable in research stations or random derelicts scattered across the sector. Is there any tag?

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #8939 on: July 15, 2022, 01:04:35 PM »

how does using spawnShipOrWing() work for wings specifically?
say that I wanted a fighter to spawn a copy of itself (and for those copies to be able to spawn copies, with a limit), would spawning the extras as individual ships & adding them to the first ship's wing work (and go over the 6 fighter-per-wing limit), or would I have to do something else?

I've tried looking at the shardSpawner code but it's franky incomprehensible to me, I can't really tell where the aspects actually get spawned / get anything assigned to them

It spawns a full wing. I think your best bet might be to spawn those fighters as "ships", but I'm not sure if it's actually possible to add them to an existing wing - wing.getWingMembers().add() wouldn't work because getWingMembers() returns a copy of the list. Someone with more experience modding this stuff might have a better idea, though.


I'm not looking hard enough or something but...

I would like a hullmod to be droppable from raiding faction, but not droppable in research stations or random derelicts scattered across the sector. Is there any tag?

The "no_drop_salvage" tag should do it.

Edit: at least, assuming a mod hasn't changed or added drop groups that don't respect that.
Logged
Pages: 1 ... 594 595 [596] 597 598 ... 709